Moving BSTR conv to native code in SecureStringToBSTR.
[mono.git] / mcs / class / referencesource / System.Runtime.Serialization / System / Runtime / Serialization / Json / XmlObjectSerializerReadContextComplexJson.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.Runtime.Serialization.Json
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.Runtime;
10     using System.Security;
11     using System.ServiceModel;
12     using System.Text;
13     using System.Xml;
14
15 #if USE_REFEMIT
16     public class XmlObjectSerializerReadContextComplexJson : XmlObjectSerializerReadContextComplex
17 #else
18     class XmlObjectSerializerReadContextComplexJson : XmlObjectSerializerReadContextComplex
19 #endif
20     {
21         string extensionDataValueType;
22         DateTimeFormat dateTimeFormat;
23         bool useSimpleDictionaryFormat;
24
25         public XmlObjectSerializerReadContextComplexJson(DataContractJsonSerializer serializer, DataContract rootTypeDataContract)
26             : base(serializer, serializer.MaxItemsInObjectGraph,
27                 new StreamingContext(StreamingContextStates.All),
28                 serializer.IgnoreExtensionDataObject)
29         {
30             this.rootTypeDataContract = rootTypeDataContract;
31             this.serializerKnownTypeList = serializer.knownTypeList;
32             this.dataContractSurrogate = serializer.DataContractSurrogate;
33             this.dateTimeFormat = serializer.DateTimeFormat;
34             this.useSimpleDictionaryFormat = serializer.UseSimpleDictionaryFormat;
35         }
36
37         internal IList<Type> SerializerKnownTypeList
38         {
39             get
40             {
41                 return this.serializerKnownTypeList;
42             }
43         }
44
45         public bool UseSimpleDictionaryFormat
46         {
47             get
48             {
49                 return this.useSimpleDictionaryFormat;
50             }
51         }
52
53         protected override void StartReadExtensionDataValue(XmlReaderDelegator xmlReader)
54         {
55             extensionDataValueType = xmlReader.GetAttribute(JsonGlobals.typeString);
56         }
57
58         protected override IDataNode ReadPrimitiveExtensionDataValue(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace)
59         {
60             IDataNode dataNode;
61
62             switch (extensionDataValueType)
63             {
64                 case null:
65                 case JsonGlobals.stringString:
66                     dataNode = new DataNode<string>(xmlReader.ReadContentAsString());
67                     break;
68                 case JsonGlobals.booleanString:
69                     dataNode = new DataNode<bool>(xmlReader.ReadContentAsBoolean());
70                     break;
71                 case JsonGlobals.numberString:
72                     dataNode = ReadNumericalPrimitiveExtensionDataValue(xmlReader);
73                     break;
74                 default:
75                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
76                         XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.JsonUnexpectedAttributeValue, extensionDataValueType)));
77             }
78
79             xmlReader.ReadEndElement();
80             return dataNode;
81         }
82
83         IDataNode ReadNumericalPrimitiveExtensionDataValue(XmlReaderDelegator xmlReader)
84         {
85             TypeCode type;
86             object numericalValue = JsonObjectDataContract.ParseJsonNumber(xmlReader.ReadContentAsString(), out type);
87             switch (type)
88             {
89                 case TypeCode.Byte:
90                     return new DataNode<byte>((byte)numericalValue);
91                 case TypeCode.SByte:
92                     return new DataNode<sbyte>((sbyte)numericalValue);
93                 case TypeCode.Int16:
94                     return new DataNode<short>((short)numericalValue);
95                 case TypeCode.Int32:
96                     return new DataNode<int>((int)numericalValue);
97                 case TypeCode.Int64:
98                     return new DataNode<long>((long)numericalValue);
99                 case TypeCode.UInt16:
100                     return new DataNode<ushort>((ushort)numericalValue);
101                 case TypeCode.UInt32:
102                     return new DataNode<uint>((uint)numericalValue);
103                 case TypeCode.UInt64:
104                     return new DataNode<ulong>((ulong)numericalValue);
105                 case TypeCode.Single:
106                     return new DataNode<float>((float)numericalValue);
107                 case TypeCode.Double:
108                     return new DataNode<double>((double)numericalValue);
109                 case TypeCode.Decimal:
110                     return new DataNode<decimal>((decimal)numericalValue);
111                 default:
112                     throw Fx.AssertAndThrow("JsonObjectDataContract.ParseJsonNumber shouldn't return a TypeCode that we're not expecting");
113             }
114         }
115
116         internal static XmlObjectSerializerReadContextComplexJson CreateContext(DataContractJsonSerializer serializer, DataContract rootTypeDataContract)
117         {
118             return new XmlObjectSerializerReadContextComplexJson(serializer, rootTypeDataContract);
119         }
120
121 #if USE_REFEMIT
122         public override int GetArraySize()
123 #else
124         internal override int GetArraySize()
125 #endif
126         {
127             return -1;
128         }
129
130         protected override object ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
131         {
132             return DataContractJsonSerializer.ReadJsonValue(dataContract, reader, this);
133         }
134
135 #if USE_REFEMIT
136         public override void ReadAttributes(XmlReaderDelegator xmlReader)
137 #else
138         internal override void ReadAttributes(XmlReaderDelegator xmlReader)
139 #endif
140         {
141             if (attributes == null)
142                 attributes = new Attributes();
143             attributes.Reset();
144
145             if (xmlReader.MoveToAttribute(JsonGlobals.typeString) && xmlReader.Value == JsonGlobals.nullString)
146             {
147                 attributes.XsiNil = true;
148             }
149             else if (xmlReader.MoveToAttribute(JsonGlobals.serverTypeString))
150             {
151                 XmlQualifiedName qualifiedTypeName = JsonReaderDelegator.ParseQualifiedName(xmlReader.Value);
152                 attributes.XsiTypeName = qualifiedTypeName.Name;
153
154                 string serverTypeNamespace = qualifiedTypeName.Namespace;
155
156                 if (!string.IsNullOrEmpty(serverTypeNamespace))
157                 {
158                     switch (serverTypeNamespace[0])
159                     {
160                         case '#':
161                             serverTypeNamespace = string.Concat(Globals.DataContractXsdBaseNamespace, serverTypeNamespace.Substring(1));
162                             break;
163                         case '\\':
164                             if (serverTypeNamespace.Length >= 2)
165                             {
166                                 switch (serverTypeNamespace[1])
167                                 {
168                                     case '#':
169                                     case '\\':
170                                         serverTypeNamespace = serverTypeNamespace.Substring(1);
171                                         break;
172                                     default:
173                                         break;
174                                 }
175                             }
176                             break;
177                         default:
178                             break;
179                     }
180                 }
181
182                 attributes.XsiTypeNamespace = serverTypeNamespace;
183             }
184             xmlReader.MoveToElement();
185         }
186
187         public int GetJsonMemberIndex(XmlReaderDelegator xmlReader, XmlDictionaryString[] memberNames, int memberIndex, ExtensionDataObject extensionData)
188         {
189             int length = memberNames.Length;
190             if (length != 0)
191             {
192                 for (int i = 0, index = (memberIndex + 1) % length; i < length; i++, index = (index + 1) % length)
193                 {
194                     if (xmlReader.IsStartElement(memberNames[index], XmlDictionaryString.Empty))
195                     {
196                         return index;
197                     }
198                 }
199                 string name;
200                 if (TryGetJsonLocalName(xmlReader, out name))
201                 {
202                     for (int i = 0, index = (memberIndex + 1) % length; i < length; i++, index = (index + 1) % length)
203                     {
204                         if (memberNames[index].Value == name)
205                         {
206                             return index;
207                         }
208                     }
209                 }
210             }
211             HandleMemberNotFound(xmlReader, extensionData, memberIndex);
212             return length;
213         }
214
215         internal static bool TryGetJsonLocalName(XmlReaderDelegator xmlReader, out string name)
216         {
217             if (xmlReader.IsStartElement(JsonGlobals.itemDictionaryString, JsonGlobals.itemDictionaryString))
218             {
219                 if (xmlReader.MoveToAttribute(JsonGlobals.itemString))
220                 {
221                     name = xmlReader.Value;
222                     return true;
223                 }
224             }
225             name = null;
226             return false;
227         }
228
229         public static string GetJsonMemberName(XmlReaderDelegator xmlReader)
230         {
231             string name;
232             if (!TryGetJsonLocalName(xmlReader, out name))
233             {
234                 name = xmlReader.LocalName;
235             }
236             return name;
237         }
238
239         public static void ThrowMissingRequiredMembers(object obj, XmlDictionaryString[] memberNames, byte[] expectedElements, byte[] requiredElements)
240         {
241             StringBuilder stringBuilder = new StringBuilder();
242             int missingMembersCount = 0;
243             for (int i = 0; i < memberNames.Length; i++)
244             {
245                 if (IsBitSet(expectedElements, i) && IsBitSet(requiredElements, i))
246                 {
247                     if (stringBuilder.Length != 0)
248                         stringBuilder.Append(", ");
249                     stringBuilder.Append(memberNames[i]);
250                     missingMembersCount++;
251                 }
252             }
253
254             if (missingMembersCount == 1)
255             {
256                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(
257                  SR.JsonOneRequiredMemberNotFound, DataContract.GetClrTypeFullName(obj.GetType()), stringBuilder.ToString())));
258             }
259             else
260             {
261                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(
262                     SR.JsonRequiredMembersNotFound, DataContract.GetClrTypeFullName(obj.GetType()), stringBuilder.ToString())));
263             }
264         }
265
266
267
268         public static void ThrowDuplicateMemberException(object obj, XmlDictionaryString[] memberNames, int memberIndex)
269         {
270             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(
271                 SR.GetString(SR.JsonDuplicateMemberInInput, DataContract.GetClrTypeFullName(obj.GetType()), memberNames[memberIndex])));
272         }
273
274         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'BitFlagsGenerator'.",
275             Safe = "This method is safe to call.")]
276         [SecuritySafeCritical]
277         static bool IsBitSet(byte[] bytes, int bitIndex)
278         {
279             return BitFlagsGenerator.IsBitSet(bytes, bitIndex);
280         }
281
282         protected override bool IsReadingCollectionExtensionData(XmlReaderDelegator xmlReader)
283         {
284             return xmlReader.GetAttribute(JsonGlobals.typeString) == JsonGlobals.arrayString;
285         }
286
287         protected override bool IsReadingClassExtensionData(XmlReaderDelegator xmlReader)
288         {
289             return xmlReader.GetAttribute(JsonGlobals.typeString) == JsonGlobals.objectString;
290         }
291
292         protected override XmlReaderDelegator CreateReaderDelegatorForReader(XmlReader xmlReader)
293         {
294             return new JsonReaderDelegator(xmlReader, this.dateTimeFormat);
295         }
296
297         internal override DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type)
298         {
299             DataContract dataContract = base.GetDataContract(typeHandle, type);
300             DataContractJsonSerializer.CheckIfTypeIsReference(dataContract);
301             return dataContract;
302         }
303
304         internal override DataContract GetDataContractSkipValidation(int typeId, RuntimeTypeHandle typeHandle, Type type)
305         {
306             DataContract dataContract = base.GetDataContractSkipValidation(typeId, typeHandle, type);
307             DataContractJsonSerializer.CheckIfTypeIsReference(dataContract);
308             return dataContract;
309         }
310
311         internal override DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle)
312         {
313             DataContract dataContract = base.GetDataContract(id, typeHandle);
314             DataContractJsonSerializer.CheckIfTypeIsReference(dataContract);
315             return dataContract;
316         }
317
318         protected override DataContract ResolveDataContractFromRootDataContract(XmlQualifiedName typeQName)
319         {
320             return XmlObjectSerializerWriteContextComplexJson.ResolveJsonDataContractFromRootDataContract(this, typeQName, rootTypeDataContract);
321         }
322     }
323 }