Moving BSTR conv to native code in SecureStringToBSTR.
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Serialization / Xmlcustomformatter.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlCustomFormatter.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>                                                                
6 //------------------------------------------------------------------------------
7 namespace System.Xml.Serialization {
8
9     using System;
10     using System.Xml;
11     using System.Globalization;
12     using System.ComponentModel;
13     using System.Diagnostics;
14     using System.Diagnostics.CodeAnalysis;
15     using System.Text;
16     using System.Collections;
17     using System.Configuration;
18     using System.Xml.Serialization.Configuration;
19
20     /// <summary>
21     ///   The <see cref="XmlCustomFormatter"/> class provides a set of static methods for converting
22     ///   primitive type values to and from their XML string representations.</summary>
23     internal class XmlCustomFormatter {
24 #if CONFIGURATION_DEP
25         private static DateTimeSerializationSection.DateTimeSerializationMode mode;
26
27         static DateTimeSerializationSection.DateTimeSerializationMode Mode {
28             [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety")]
29             get {
30                 if (mode == DateTimeSerializationSection.DateTimeSerializationMode.Default) {
31                     DateTimeSerializationSection section = PrivilegedConfigurationManager.GetSection(ConfigurationStrings.DateTimeSerializationSectionPath) as DateTimeSerializationSection;
32                     if (section != null) {
33                         mode = section.Mode;
34                     }
35                     else {
36                         mode = DateTimeSerializationSection.DateTimeSerializationMode.Roundtrip;
37                     }
38                 }
39                 return mode;
40             }
41         }
42 #endif
43         private XmlCustomFormatter() {}
44         internal static string FromDefaultValue(object value, string formatter) {
45             if (value == null) return null;
46             Type type = value.GetType();
47             if (type == typeof(DateTime)) {
48                 if (formatter == "DateTime") {
49                     return FromDateTime((DateTime)value);
50                 }
51                 if (formatter == "Date") {
52                     return FromDate((DateTime)value);
53                 }
54                 if (formatter == "Time") {
55                     return FromTime((DateTime)value);
56                 }
57             }
58             else if (type == typeof(string)) {
59                 if (formatter == "XmlName") {
60                     return FromXmlName((string)value);
61                 }
62                 if (formatter == "XmlNCName") {
63                     return FromXmlNCName((string)value);
64                 }
65                 if (formatter == "XmlNmToken") {
66                     return FromXmlNmToken((string)value);
67                 }
68                 if (formatter == "XmlNmTokens") {
69                     return FromXmlNmTokens((string)value);
70                 }
71             }
72             throw new Exception(Res.GetString(Res.XmlUnsupportedDefaultType, type.FullName));
73         }
74
75         internal static string FromDate(DateTime value) {
76             return XmlConvert.ToString(value, "yyyy-MM-dd");
77         }
78
79         internal static string FromTime(DateTime value) {
80             return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffzzzzzz");
81         }
82
83         internal static string FromDateTime(DateTime value) {
84 #if CONFIGURATION_DEP
85             if (Mode == DateTimeSerializationSection.DateTimeSerializationMode.Local) {
86                 return XmlConvert.ToString(value, "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz");
87             }
88 #endif
89                 // for mode DateTimeSerializationMode.Roundtrip and DateTimeSerializationMode.Default
90                 return XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind);
91         }
92
93         internal static string FromChar(char value) {
94             return XmlConvert.ToString((UInt16)value);
95         }
96
97         internal static string FromXmlName(string name) {
98             return XmlConvert.EncodeName(name);
99         }
100
101         internal static string FromXmlNCName(string ncName) {
102             return XmlConvert.EncodeLocalName(ncName);
103         }
104
105         internal static string FromXmlNmToken(string nmToken) {
106             return XmlConvert.EncodeNmToken(nmToken);
107         }
108
109         internal static string FromXmlNmTokens(string nmTokens) {
110             if (nmTokens == null)
111                 return null;
112             if (nmTokens.IndexOf(' ') < 0) 
113                 return FromXmlNmToken(nmTokens);
114             else {
115                 string[] toks = nmTokens.Split(new char[] { ' ' });
116                 StringBuilder sb = new StringBuilder();
117                 for (int i = 0; i < toks.Length; i++) {
118                     if (i > 0) sb.Append(' ');
119                     sb.Append(FromXmlNmToken(toks[i]));
120                 }
121                 return sb.ToString();
122             }
123         }
124
125         internal static void WriteArrayBase64(XmlWriter writer, byte[] inData, int start, int count) {
126             if (inData == null || count == 0) {
127                 return;
128             }
129             writer.WriteBase64(inData, start, count);
130         }
131
132         internal static string FromByteArrayHex(byte[] value) {
133             if (value == null)
134                 return null;
135             if (value.Length == 0)
136                 return "";
137             return XmlConvert.ToBinHexString(value);
138         }
139
140         internal static string FromEnum(long val, string[] vals, long[] ids, string typeName) {
141 #if DEBUG
142                 // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
143                 if (ids.Length != vals.Length) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Invalid enum"));
144 #endif
145
146             long originalValue = val;
147             StringBuilder sb = new StringBuilder();
148             int iZero = -1;
149
150             for (int i = 0; i < ids.Length; i++) {
151                 if (ids[i] == 0) {
152                     iZero = i;
153                     continue;
154                 }
155                 if (val == 0) {
156                     break;
157                 }
158                 if ((ids[i] & originalValue) == ids[i]) {
159                     if (sb.Length != 0)
160                         sb.Append(" ");
161                     sb.Append(vals[i]);
162                     val &= ~ids[i];
163                 }
164             }
165             if (val != 0) {
166                 // failed to parse the enum value
167                 throw new InvalidOperationException(Res.GetString(Res.XmlUnknownConstant, originalValue, typeName == null ? "enum" : typeName));
168             }
169             if (sb.Length == 0 && iZero >= 0) {
170                 sb.Append(vals[iZero]);
171             }
172             return sb.ToString();
173         }
174
175         internal static object ToDefaultValue(string value, string formatter) {
176             if (formatter == "DateTime") {
177                 return ToDateTime(value);
178             }
179             if (formatter == "Date") {
180                 return ToDate(value);
181             }
182             if (formatter == "Time") {
183                 return ToTime(value);
184             }
185             if (formatter == "XmlName") {
186                 return ToXmlName(value);
187             }
188             if (formatter == "XmlNCName") {
189                 return ToXmlNCName(value);
190             }
191             if (formatter == "XmlNmToken") {
192                 return ToXmlNmToken(value);
193             }
194             if (formatter == "XmlNmTokens") {
195                 return ToXmlNmTokens(value);
196             }
197             throw new Exception(Res.GetString(Res.XmlUnsupportedDefaultValue, formatter));
198             //            Debug.WriteLineIf(CompModSwitches.XmlSerialization.TraceVerbose, "XmlSerialization::Unhandled default value " + value + " formatter " + formatter);
199             //            return DBNull.Value;
200         }
201
202         static string[] allDateTimeFormats = new string[] {
203             "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz",
204             "yyyy",
205             "---dd",
206             "---ddZ",
207             "---ddzzzzzz",
208             "--MM-dd",
209             "--MM-ddZ",
210             "--MM-ddzzzzzz",
211             "--MM--",
212             "--MM--Z",
213             "--MM--zzzzzz",
214             "yyyy-MM",
215             "yyyy-MMZ",
216             "yyyy-MMzzzzzz",
217             "yyyyzzzzzz",
218             "yyyy-MM-dd",
219             "yyyy-MM-ddZ",
220             "yyyy-MM-ddzzzzzz",
221
222             "HH:mm:ss",
223             "HH:mm:ss.f",
224             "HH:mm:ss.ff",
225             "HH:mm:ss.fff",
226             "HH:mm:ss.ffff",
227             "HH:mm:ss.fffff",
228             "HH:mm:ss.ffffff",
229             "HH:mm:ss.fffffff",
230             "HH:mm:ssZ",
231             "HH:mm:ss.fZ",
232             "HH:mm:ss.ffZ",
233             "HH:mm:ss.fffZ",
234             "HH:mm:ss.ffffZ",
235             "HH:mm:ss.fffffZ",
236             "HH:mm:ss.ffffffZ",
237             "HH:mm:ss.fffffffZ",
238             "HH:mm:sszzzzzz",
239             "HH:mm:ss.fzzzzzz",
240             "HH:mm:ss.ffzzzzzz",
241             "HH:mm:ss.fffzzzzzz",
242             "HH:mm:ss.ffffzzzzzz",
243             "HH:mm:ss.fffffzzzzzz",
244             "HH:mm:ss.ffffffzzzzzz",
245             "HH:mm:ss.fffffffzzzzzz",
246             "yyyy-MM-ddTHH:mm:ss",
247             "yyyy-MM-ddTHH:mm:ss.f",
248             "yyyy-MM-ddTHH:mm:ss.ff",
249             "yyyy-MM-ddTHH:mm:ss.fff",
250             "yyyy-MM-ddTHH:mm:ss.ffff",
251             "yyyy-MM-ddTHH:mm:ss.fffff",
252             "yyyy-MM-ddTHH:mm:ss.ffffff",
253             "yyyy-MM-ddTHH:mm:ss.fffffff",
254             "yyyy-MM-ddTHH:mm:ssZ",
255             "yyyy-MM-ddTHH:mm:ss.fZ",
256             "yyyy-MM-ddTHH:mm:ss.ffZ",
257             "yyyy-MM-ddTHH:mm:ss.fffZ",
258             "yyyy-MM-ddTHH:mm:ss.ffffZ",
259             "yyyy-MM-ddTHH:mm:ss.fffffZ",
260             "yyyy-MM-ddTHH:mm:ss.ffffffZ",
261             "yyyy-MM-ddTHH:mm:ss.fffffffZ",
262             "yyyy-MM-ddTHH:mm:sszzzzzz",
263             "yyyy-MM-ddTHH:mm:ss.fzzzzzz",
264             "yyyy-MM-ddTHH:mm:ss.ffzzzzzz",
265             "yyyy-MM-ddTHH:mm:ss.fffzzzzzz",
266             "yyyy-MM-ddTHH:mm:ss.ffffzzzzzz",
267             "yyyy-MM-ddTHH:mm:ss.fffffzzzzzz",
268             "yyyy-MM-ddTHH:mm:ss.ffffffzzzzzz",
269         };
270
271         static string[] allDateFormats = new string[] {
272             "yyyy-MM-ddzzzzzz",
273             "yyyy-MM-dd",
274             "yyyy-MM-ddZ",
275             "yyyy",
276             "---dd",
277             "---ddZ",
278             "---ddzzzzzz",
279             "--MM-dd",
280             "--MM-ddZ",
281             "--MM-ddzzzzzz",
282             "--MM--",
283             "--MM--Z",
284             "--MM--zzzzzz",
285             "yyyy-MM",
286             "yyyy-MMZ",
287             "yyyy-MMzzzzzz",
288             "yyyyzzzzzz",
289         };
290
291         static string[] allTimeFormats = new string[] {
292             "HH:mm:ss.fffffffzzzzzz",
293             "HH:mm:ss",
294             "HH:mm:ss.f",
295             "HH:mm:ss.ff",
296             "HH:mm:ss.fff",
297             "HH:mm:ss.ffff",
298             "HH:mm:ss.fffff",
299             "HH:mm:ss.ffffff",
300             "HH:mm:ss.fffffff",
301             "HH:mm:ssZ",
302             "HH:mm:ss.fZ",
303             "HH:mm:ss.ffZ",
304             "HH:mm:ss.fffZ",
305             "HH:mm:ss.ffffZ",
306             "HH:mm:ss.fffffZ",
307             "HH:mm:ss.ffffffZ",
308             "HH:mm:ss.fffffffZ",
309             "HH:mm:sszzzzzz",
310             "HH:mm:ss.fzzzzzz",
311             "HH:mm:ss.ffzzzzzz",
312             "HH:mm:ss.fffzzzzzz",
313             "HH:mm:ss.ffffzzzzzz",
314             "HH:mm:ss.fffffzzzzzz",
315             "HH:mm:ss.ffffffzzzzzz",
316         };
317
318         internal static DateTime ToDateTime(string value) {
319 #if CONFIGURATION_DEP
320             if (Mode == DateTimeSerializationSection.DateTimeSerializationMode.Local) {
321                 return ToDateTime(value, allDateTimeFormats);
322             }
323             else
324 #endif
325             {
326                 // for mode DateTimeSerializationMode.Roundtrip and DateTimeSerializationMode.Default
327                 return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind);
328             }
329         }
330
331         internal static DateTime ToDateTime(string value, string[] formats) {
332             return XmlConvert.ToDateTime(value, formats);
333         }
334
335         internal static DateTime ToDate(string value) {
336             return ToDateTime(value, allDateFormats);
337         }
338
339         internal static DateTime ToTime(string value) {
340             return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite|DateTimeStyles.AllowTrailingWhite|DateTimeStyles.NoCurrentDateDefault);
341         }
342
343         internal static char ToChar(string value) {
344             return (char)XmlConvert.ToUInt16(value);
345         }
346
347         internal static string ToXmlName(string value) {
348             return XmlConvert.DecodeName(CollapseWhitespace(value));
349         }
350
351         internal static string ToXmlNCName(string value) {
352             return XmlConvert.DecodeName(CollapseWhitespace(value));
353         }
354         
355         internal static string ToXmlNmToken(string value) {
356             return XmlConvert.DecodeName(CollapseWhitespace(value));
357         }
358         
359         internal static string ToXmlNmTokens(string value) {
360             return XmlConvert.DecodeName(CollapseWhitespace(value));
361         }
362         
363         internal static byte[] ToByteArrayBase64(string value) {
364             if (value == null) return null;
365             value = value.Trim();
366             if (value.Length == 0)
367                 return new byte[0];           
368             return Convert.FromBase64String(value);
369         }
370         internal static byte[] ToByteArrayHex(string value) {
371             if (value == null) return null;
372             value = value.Trim();
373             return XmlConvert.FromBinHexString(value);
374         }
375
376         internal static long ToEnum(string val, Hashtable vals, string typeName, bool validate)     {
377             long value = 0;
378             string[] parts = val.Split(null);
379             for (int i = 0; i < parts.Length; i++) {
380                 object id = vals[parts[i]];
381                 if (id != null)
382                     value |= (long)id;
383                 else if (validate && parts[i].Length > 0)
384                     throw new InvalidOperationException(Res.GetString(Res.XmlUnknownConstant, parts[i], typeName));
385             }
386             return value;
387         }
388
389         static string CollapseWhitespace(string value) {
390             if (value == null)
391                 return null;
392             return value.Trim();
393         }
394     }
395 }