Updates referencesource to .NET 4.7
[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">Microsoft</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             if (!LocalAppContextSwitches.IgnoreKindInUtcTimeSerialization && value.Kind == DateTimeKind.Utc)
81             {
82                 return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffZ");
83             }
84             else
85             {
86                 return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffzzzzzz");
87             }
88         }
89
90         internal static string FromDateTime(DateTime value) {
91 #if CONFIGURATION_DEP
92             if (Mode == DateTimeSerializationSection.DateTimeSerializationMode.Local) {
93                 return XmlConvert.ToString(value, "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz");
94             }
95 #endif
96                 // for mode DateTimeSerializationMode.Roundtrip and DateTimeSerializationMode.Default
97                 return XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind);
98         }
99
100         internal static string FromChar(char value) {
101             return XmlConvert.ToString((UInt16)value);
102         }
103
104         internal static string FromXmlName(string name) {
105             return XmlConvert.EncodeName(name);
106         }
107
108         internal static string FromXmlNCName(string ncName) {
109             return XmlConvert.EncodeLocalName(ncName);
110         }
111
112         internal static string FromXmlNmToken(string nmToken) {
113             return XmlConvert.EncodeNmToken(nmToken);
114         }
115
116         internal static string FromXmlNmTokens(string nmTokens) {
117             if (nmTokens == null)
118                 return null;
119             if (nmTokens.IndexOf(' ') < 0) 
120                 return FromXmlNmToken(nmTokens);
121             else {
122                 string[] toks = nmTokens.Split(new char[] { ' ' });
123                 StringBuilder sb = new StringBuilder();
124                 for (int i = 0; i < toks.Length; i++) {
125                     if (i > 0) sb.Append(' ');
126                     sb.Append(FromXmlNmToken(toks[i]));
127                 }
128                 return sb.ToString();
129             }
130         }
131
132         internal static void WriteArrayBase64(XmlWriter writer, byte[] inData, int start, int count) {
133             if (inData == null || count == 0) {
134                 return;
135             }
136             writer.WriteBase64(inData, start, count);
137         }
138
139         internal static string FromByteArrayHex(byte[] value) {
140             if (value == null)
141                 return null;
142             if (value.Length == 0)
143                 return "";
144             return XmlConvert.ToBinHexString(value);
145         }
146
147         internal static string FromEnum(long val, string[] vals, long[] ids, string typeName) {
148 #if DEBUG
149                 // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
150                 if (ids.Length != vals.Length) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Invalid enum"));
151 #endif
152
153             long originalValue = val;
154             StringBuilder sb = new StringBuilder();
155             int iZero = -1;
156
157             for (int i = 0; i < ids.Length; i++) {
158                 if (ids[i] == 0) {
159                     iZero = i;
160                     continue;
161                 }
162                 if (val == 0) {
163                     break;
164                 }
165                 if ((ids[i] & originalValue) == ids[i]) {
166                     if (sb.Length != 0)
167                         sb.Append(" ");
168                     sb.Append(vals[i]);
169                     val &= ~ids[i];
170                 }
171             }
172             if (val != 0) {
173                 // failed to parse the enum value
174                 throw new InvalidOperationException(Res.GetString(Res.XmlUnknownConstant, originalValue, typeName == null ? "enum" : typeName));
175             }
176             if (sb.Length == 0 && iZero >= 0) {
177                 sb.Append(vals[iZero]);
178             }
179             return sb.ToString();
180         }
181
182         internal static object ToDefaultValue(string value, string formatter) {
183             if (formatter == "DateTime") {
184                 return ToDateTime(value);
185             }
186             if (formatter == "Date") {
187                 return ToDate(value);
188             }
189             if (formatter == "Time") {
190                 return ToTime(value);
191             }
192             if (formatter == "XmlName") {
193                 return ToXmlName(value);
194             }
195             if (formatter == "XmlNCName") {
196                 return ToXmlNCName(value);
197             }
198             if (formatter == "XmlNmToken") {
199                 return ToXmlNmToken(value);
200             }
201             if (formatter == "XmlNmTokens") {
202                 return ToXmlNmTokens(value);
203             }
204             throw new Exception(Res.GetString(Res.XmlUnsupportedDefaultValue, formatter));
205             //            Debug.WriteLineIf(CompModSwitches.XmlSerialization.TraceVerbose, "XmlSerialization::Unhandled default value " + value + " formatter " + formatter);
206             //            return DBNull.Value;
207         }
208
209         static string[] allDateTimeFormats = new string[] {
210             "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz",
211             "yyyy",
212             "---dd",
213             "---ddZ",
214             "---ddzzzzzz",
215             "--MM-dd",
216             "--MM-ddZ",
217             "--MM-ddzzzzzz",
218             "--MM--",
219             "--MM--Z",
220             "--MM--zzzzzz",
221             "yyyy-MM",
222             "yyyy-MMZ",
223             "yyyy-MMzzzzzz",
224             "yyyyzzzzzz",
225             "yyyy-MM-dd",
226             "yyyy-MM-ddZ",
227             "yyyy-MM-ddzzzzzz",
228
229             "HH:mm:ss",
230             "HH:mm:ss.f",
231             "HH:mm:ss.ff",
232             "HH:mm:ss.fff",
233             "HH:mm:ss.ffff",
234             "HH:mm:ss.fffff",
235             "HH:mm:ss.ffffff",
236             "HH:mm:ss.fffffff",
237             "HH:mm:ssZ",
238             "HH:mm:ss.fZ",
239             "HH:mm:ss.ffZ",
240             "HH:mm:ss.fffZ",
241             "HH:mm:ss.ffffZ",
242             "HH:mm:ss.fffffZ",
243             "HH:mm:ss.ffffffZ",
244             "HH:mm:ss.fffffffZ",
245             "HH:mm:sszzzzzz",
246             "HH:mm:ss.fzzzzzz",
247             "HH:mm:ss.ffzzzzzz",
248             "HH:mm:ss.fffzzzzzz",
249             "HH:mm:ss.ffffzzzzzz",
250             "HH:mm:ss.fffffzzzzzz",
251             "HH:mm:ss.ffffffzzzzzz",
252             "HH:mm:ss.fffffffzzzzzz",
253             "yyyy-MM-ddTHH:mm:ss",
254             "yyyy-MM-ddTHH:mm:ss.f",
255             "yyyy-MM-ddTHH:mm:ss.ff",
256             "yyyy-MM-ddTHH:mm:ss.fff",
257             "yyyy-MM-ddTHH:mm:ss.ffff",
258             "yyyy-MM-ddTHH:mm:ss.fffff",
259             "yyyy-MM-ddTHH:mm:ss.ffffff",
260             "yyyy-MM-ddTHH:mm:ss.fffffff",
261             "yyyy-MM-ddTHH:mm:ssZ",
262             "yyyy-MM-ddTHH:mm:ss.fZ",
263             "yyyy-MM-ddTHH:mm:ss.ffZ",
264             "yyyy-MM-ddTHH:mm:ss.fffZ",
265             "yyyy-MM-ddTHH:mm:ss.ffffZ",
266             "yyyy-MM-ddTHH:mm:ss.fffffZ",
267             "yyyy-MM-ddTHH:mm:ss.ffffffZ",
268             "yyyy-MM-ddTHH:mm:ss.fffffffZ",
269             "yyyy-MM-ddTHH:mm:sszzzzzz",
270             "yyyy-MM-ddTHH:mm:ss.fzzzzzz",
271             "yyyy-MM-ddTHH:mm:ss.ffzzzzzz",
272             "yyyy-MM-ddTHH:mm:ss.fffzzzzzz",
273             "yyyy-MM-ddTHH:mm:ss.ffffzzzzzz",
274             "yyyy-MM-ddTHH:mm:ss.fffffzzzzzz",
275             "yyyy-MM-ddTHH:mm:ss.ffffffzzzzzz",
276         };
277
278         static string[] allDateFormats = new string[] {
279             "yyyy-MM-ddzzzzzz",
280             "yyyy-MM-dd",
281             "yyyy-MM-ddZ",
282             "yyyy",
283             "---dd",
284             "---ddZ",
285             "---ddzzzzzz",
286             "--MM-dd",
287             "--MM-ddZ",
288             "--MM-ddzzzzzz",
289             "--MM--",
290             "--MM--Z",
291             "--MM--zzzzzz",
292             "yyyy-MM",
293             "yyyy-MMZ",
294             "yyyy-MMzzzzzz",
295             "yyyyzzzzzz",
296         };
297
298         static string[] allTimeFormats = new string[] {
299             "HH:mm:ss.fffffffzzzzzz",
300             "HH:mm:ss",
301             "HH:mm:ss.f",
302             "HH:mm:ss.ff",
303             "HH:mm:ss.fff",
304             "HH:mm:ss.ffff",
305             "HH:mm:ss.fffff",
306             "HH:mm:ss.ffffff",
307             "HH:mm:ss.fffffff",
308             "HH:mm:ssZ",
309             "HH:mm:ss.fZ",
310             "HH:mm:ss.ffZ",
311             "HH:mm:ss.fffZ",
312             "HH:mm:ss.ffffZ",
313             "HH:mm:ss.fffffZ",
314             "HH:mm:ss.ffffffZ",
315             "HH:mm:ss.fffffffZ",
316             "HH:mm:sszzzzzz",
317             "HH:mm:ss.fzzzzzz",
318             "HH:mm:ss.ffzzzzzz",
319             "HH:mm:ss.fffzzzzzz",
320             "HH:mm:ss.ffffzzzzzz",
321             "HH:mm:ss.fffffzzzzzz",
322             "HH:mm:ss.ffffffzzzzzz",
323         };
324
325         internal static DateTime ToDateTime(string value) {
326 #if CONFIGURATION_DEP
327             if (Mode == DateTimeSerializationSection.DateTimeSerializationMode.Local) {
328                 return ToDateTime(value, allDateTimeFormats);
329             }
330             else
331 #endif
332             {
333                 // for mode DateTimeSerializationMode.Roundtrip and DateTimeSerializationMode.Default
334                 return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind);
335             }
336         }
337
338         internal static DateTime ToDateTime(string value, string[] formats) {
339             return XmlConvert.ToDateTime(value, formats);
340         }
341
342         internal static DateTime ToDate(string value) {
343             return ToDateTime(value, allDateFormats);
344         }
345
346         internal static DateTime ToTime(string value) {
347             if (!LocalAppContextSwitches.IgnoreKindInUtcTimeSerialization)
348             {
349                 return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.RoundtripKind);
350             }
351             else
352             {
353                 return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.NoCurrentDateDefault);
354             }
355         }
356
357         internal static char ToChar(string value) {
358             return (char)XmlConvert.ToUInt16(value);
359         }
360
361         internal static string ToXmlName(string value) {
362             return XmlConvert.DecodeName(CollapseWhitespace(value));
363         }
364
365         internal static string ToXmlNCName(string value) {
366             return XmlConvert.DecodeName(CollapseWhitespace(value));
367         }
368         
369         internal static string ToXmlNmToken(string value) {
370             return XmlConvert.DecodeName(CollapseWhitespace(value));
371         }
372         
373         internal static string ToXmlNmTokens(string value) {
374             return XmlConvert.DecodeName(CollapseWhitespace(value));
375         }
376         
377         internal static byte[] ToByteArrayBase64(string value) {
378             if (value == null) return null;
379             value = value.Trim();
380             if (value.Length == 0)
381                 return new byte[0];           
382             return Convert.FromBase64String(value);
383         }
384         internal static byte[] ToByteArrayHex(string value) {
385             if (value == null) return null;
386             value = value.Trim();
387             return XmlConvert.FromBinHexString(value);
388         }
389
390         internal static long ToEnum(string val, Hashtable vals, string typeName, bool validate)     {
391             long value = 0;
392             string[] parts = val.Split(null);
393             for (int i = 0; i < parts.Length; i++) {
394                 object id = vals[parts[i]];
395                 if (id != null)
396                     value |= (long)id;
397                 else if (validate && parts[i].Length > 0)
398                     throw new InvalidOperationException(Res.GetString(Res.XmlUnknownConstant, parts[i], typeName));
399             }
400             return value;
401         }
402
403         static string CollapseWhitespace(string value) {
404             if (value == null)
405                 return null;
406             return value.Trim();
407         }
408     }
409 }