Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlCustomFormatter.cs
1 //
2 // System.Xml.Serialization.XmlCustomFormatter.cs
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //   Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // Copyright (C) Tim Coleman, 2002
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Collections;
34 using System.Text;
35 using System.Xml;
36 using System.Globalization;
37
38 namespace System.Xml.Serialization {
39         internal class XmlCustomFormatter {
40
41                 #region Methods
42
43                 internal static string FromByteArrayBase64 (byte[] value)
44                 {
45                         return value == null ? String.Empty : Convert.ToBase64String(value);
46                 }
47
48                 internal static string FromByteArrayHex (byte[] value)
49                 {
50                         if (value == null) return null;
51                         StringBuilder output = new StringBuilder ();
52                         foreach (byte val in value)
53                                 output.Append (val.ToString ("X2", CultureInfo.InvariantCulture));
54                         return output.ToString ();
55                 }
56
57                 internal static string FromChar (char value)
58                 {
59                         return ((int) value).ToString (CultureInfo.InvariantCulture);
60                 }
61
62                 internal static string FromDate (DateTime value)
63                 {
64                         return XmlConvert.ToString (value, "yyyy-MM-dd");
65                 }
66
67                 internal static string FromDateTime (DateTime value)
68                 {
69                         return XmlConvert.ToString (value, XmlDateTimeSerializationMode.RoundtripKind);
70                 }
71
72                 internal static string FromTime (DateTime value)
73                 {
74                         return XmlConvert.ToString (value, "HH:mm:ss.fffffffzzz");
75                 }
76
77                 internal static string FromEnum (long value, string[] values, long[] ids)
78                 {
79                         return FromEnum (value, values, ids, (string) null);
80                 }
81
82                 internal static string FromEnum (long value, string[] values, long[] ids, string typeName)
83                 {
84                         StringBuilder sb = new StringBuilder();
85                         int length = ids.Length;
86                         long valueToProcess = value;
87                         int zeroValue = -1;
88
89                         for (int i = 0; i < length; i ++) {
90                                 if (ids[i] == 0) {
91                                         zeroValue = i;
92                                 } else {
93                                         if (valueToProcess == 0) {
94                                                 break;
95                                         }
96
97                                         if ((ids[i] & value) == ids[i]) {
98                                                 if (sb.Length != 0)
99                                                         sb.Append (' ');
100                                                 sb.Append (values[i]);
101                                                 valueToProcess &= ~ids[i];
102                                         }
103                                 }
104                         }
105
106                         if (valueToProcess != 0) {
107                                 if (typeName != null)
108                                         throw new InvalidOperationException (string.Format (CultureInfo.CurrentCulture,
109                                                 "'{0}' is not a valid value for {1}.", value, typeName));
110                                 else
111                                         throw new InvalidOperationException (string.Format (CultureInfo.CurrentCulture,
112                                                 "'{0}' is not a valid value.", value));
113                         }
114                         if (sb.Length == 0 && zeroValue != -1) {
115                                 sb.Append (values[zeroValue]);
116                         }
117                         return sb.ToString ();
118                 }
119
120                 internal static string FromXmlName (string name)
121                 {
122                         return XmlConvert.EncodeName (name);
123                 }
124
125                 internal static string FromXmlNCName (string ncName)
126                 {
127                         return XmlConvert.EncodeLocalName (ncName);
128                 }
129
130                 internal static string FromXmlNmToken (string nmToken)
131                 {
132                         return XmlConvert.EncodeNmToken (nmToken);
133                 }
134
135                 internal static string FromXmlNmTokens (string nmTokens)
136                 {
137                         string [] tokens = nmTokens.Split (' ');
138                         for (int i=0; i<tokens.Length; i++)
139                                 tokens [i] = FromXmlNmToken (tokens [i]);
140                         return String.Join (" ", tokens);
141                 }
142
143                 internal static byte[] ToByteArrayBase64 (string value)
144                 {
145                         return Convert.FromBase64String(value);
146                 }
147
148                 internal static char ToChar (string value)
149                 {
150                         return (char) XmlConvert.ToUInt16 (value);
151                 }
152
153                 internal static DateTime ToDate (string value)
154                 {
155                         return ToDateTime (value);
156                 }
157
158                 internal static DateTime ToDateTime (string value)
159                 {
160                         return XmlConvert.ToDateTime (value, XmlDateTimeSerializationMode.RoundtripKind);
161                 }
162
163                 internal static DateTime ToTime (string value)
164                 {
165                         return ToDateTime (value);
166                 }
167
168                 internal static long ToEnum (string value, Hashtable values, string typeName, bool validate)
169                 {
170                         // Assuming that h contains map from value to Enumerated Name
171 /*
172                         You can try : 
173                                 return ToEnum ("One Two", h, "SomeType");
174                         where:
175                                 (1) no keys and values for h.
176                                 (2) string keys and long values.
177                         
178                         according to MSDN docs (for .NET 2.0) the hashtable "consists of the
179                         identifiers as keys and the constants as integral numbers"
180 */
181                         long enumValue = 0;
182                         string[] names = value.Split (' ');
183
184                         foreach (string name in names) {
185                                 object nameValue = values[name];
186                                 if (nameValue != null) {
187                                         enumValue |= (long) nameValue;
188                                 } else if (validate && name.Length != 0) {
189                                         throw new InvalidOperationException (String.Format ("'{0}' is not a valid member of type {1}.", name, typeName));
190                                 }
191                         }
192
193                         return enumValue;
194                 }
195
196                 internal static string ToXmlName (string value)
197                 {
198                         return XmlConvert.DecodeName (value);
199                 }
200
201                 internal static string ToXmlNCName (string value)
202                 {
203                         return ToXmlName (value);
204                 }
205
206                 internal static string ToXmlNmToken (string value)
207                 {
208                         return ToXmlName (value);
209                 }
210
211                 internal static string ToXmlNmTokens (string value)
212                 {
213                         return ToXmlName (value);
214                 }
215
216                 internal static string ToXmlString (TypeData type, object value)
217                 {
218                         if (value == null) return null;
219                         switch (type.XmlType)
220                         {
221                                 case "boolean": return XmlConvert.ToString ((bool)value);
222                                 case "unsignedByte": return XmlConvert.ToString ((byte)value);
223                                 case "char": return XmlConvert.ToString ((int)(char)value);
224                                 case "dateTime": return XmlConvert.ToString ((DateTime)value, XmlDateTimeSerializationMode.RoundtripKind);
225                                 case "date": return ((DateTime)value).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
226                                 case "time": return ((DateTime)value).ToString("HH:mm:ss.FFFFFFF", CultureInfo.InvariantCulture);
227                                 case "decimal": return XmlConvert.ToString ((decimal)value);
228                                 case "double": return XmlConvert.ToString ((double)value);
229                                 case "short": return XmlConvert.ToString ((Int16)value);
230                                 case "int": return XmlConvert.ToString ((Int32)value);
231                                 case "long": return XmlConvert.ToString ((Int64)value);
232                                 case "byte": return XmlConvert.ToString ((sbyte)value);
233                                 case "float": return XmlConvert.ToString ((Single)value);
234                                 case "unsignedShort": return XmlConvert.ToString ((UInt16)value);
235                                 case "unsignedInt": return XmlConvert.ToString ((UInt32)value);
236                                 case "unsignedLong": return XmlConvert.ToString ((UInt64)value);
237                                 case "guid": return XmlConvert.ToString ((Guid)value);
238                                 case "base64":
239                                 case "base64Binary": return value == null ? String.Empty : Convert.ToBase64String ((byte[])value);
240                                 case "hexBinary": return value == null ? String.Empty : XmlConvert.ToBinHexString ((byte[]) value);
241                                 case "duration": return (string) value;
242                         default: return value is IFormattable ? ((IFormattable) value).ToString (null, CultureInfo.InvariantCulture) : value.ToString ();
243                         }
244                 }
245
246                 static string[] allTimeFormats = new string[] {
247                         "HH:mm:ss.fffffffzzzzzz",
248                         "HH:mm:ss",
249                         "HH:mm:ss.f",
250                         "HH:mm:ss.ff",
251                         "HH:mm:ss.fff",
252                         "HH:mm:ss.ffff",
253                         "HH:mm:ss.fffff",
254                         "HH:mm:ss.ffffff",
255                         "HH:mm:ss.fffffff",
256                         "HH:mm:ssZ",
257                         "HH:mm:ss.fZ",
258                         "HH:mm:ss.ffZ",
259                         "HH:mm:ss.fffZ",
260                         "HH:mm:ss.ffffZ",
261                         "HH:mm:ss.fffffZ",
262                         "HH:mm:ss.ffffffZ",
263                         "HH:mm:ss.fffffffZ",
264                         "HH:mm:sszzzzzz",
265                         "HH:mm:ss.fzzzzzz",
266                         "HH:mm:ss.ffzzzzzz",
267                         "HH:mm:ss.fffzzzzzz",
268                         "HH:mm:ss.ffffzzzzzz",
269                         "HH:mm:ss.fffffzzzzzz",
270                         "HH:mm:ss.ffffffzzzzzz",
271                 };
272
273                 internal static object FromXmlString (TypeData type, string value)
274                 {
275                         if (value == null) return null;
276
277                         switch (type.XmlType)
278                         {
279                                 case "boolean": return XmlConvert.ToBoolean (value);
280                                 case "unsignedByte": return XmlConvert.ToByte (value);
281                                 case "char": return (char)XmlConvert.ToInt32 (value);
282                                 case "dateTime": return XmlConvert.ToDateTime (value, XmlDateTimeSerializationMode.RoundtripKind);
283                                 case "date": return XmlConvert.ToDateTime (value).Date;
284                                 case "time": return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.RoundtripKind);
285                                 case "decimal": return XmlConvert.ToDecimal (value);
286                                 case "double": return XmlConvert.ToDouble (value);
287                                 case "short": return XmlConvert.ToInt16 (value);
288                                 case "int": return XmlConvert.ToInt32 (value);
289                                 case "long": return XmlConvert.ToInt64 (value);
290                                 case "byte": return XmlConvert.ToSByte (value);
291                                 case "float": return XmlConvert.ToSingle (value);
292                                 case "unsignedShort": return XmlConvert.ToUInt16 (value);
293                                 case "unsignedInt": return XmlConvert.ToUInt32 (value);
294                                 case "unsignedLong": return XmlConvert.ToUInt64 (value);
295                                 case "guid": return XmlConvert.ToGuid (value);
296                                 case "base64":
297                                 case "base64Binary": return Convert.FromBase64String (value);
298                                 case "hexBinary": return XmlConvert.FromBinHexString (value);
299                                 case "duration": return value;
300                                 default: 
301                                         if (type.Type != null)
302                                                 return Convert.ChangeType (value, type.Type, null);
303                                         else
304                                                 return value;
305                         }
306                 }
307
308                 internal static string GenerateToXmlString (TypeData type, string value)
309                 {
310                         if (type.NullableOverride)
311                                 return "(" + value + " != null ? " + GenerateToXmlStringCore (type, value) + " : null)";
312                         else
313                                 return GenerateToXmlStringCore (type, value);
314                 }
315
316                 static string GenerateToXmlStringCore (TypeData type, string value)
317                 {
318                         if (type.NullableOverride)
319                                 value = value + ".Value";
320                         switch (type.XmlType)
321                         {
322                                 case "boolean": return "(" + value + "?\"true\":\"false\")";
323                                 case "unsignedByte": return value + ".ToString(CultureInfo.InvariantCulture)";
324                                 case "char": return "((int)(" + value + ")).ToString(CultureInfo.InvariantCulture)";
325                                 case "dateTime": return "XmlConvert.ToString (" + value + ", XmlDateTimeSerializationMode.RoundtripKind)";
326                                 case "date": return value + ".ToString(\"yyyy-MM-dd\", CultureInfo.InvariantCulture)";
327                                 case "time": return value + ".ToString(\"HH:mm:ss.FFFFFFF\", CultureInfo.InvariantCulture)";
328                                 case "decimal": return "XmlConvert.ToString (" + value + ")";
329                                 case "double": return "XmlConvert.ToString (" + value + ")";
330                                 case "short": return value + ".ToString(CultureInfo.InvariantCulture)";
331                                 case "int": return value + ".ToString(CultureInfo.InvariantCulture)";
332                                 case "long": return value + ".ToString(CultureInfo.InvariantCulture)";
333                                 case "byte": return value + ".ToString(CultureInfo.InvariantCulture)";
334                                 case "float": return "XmlConvert.ToString (" + value + ")";
335                                 case "unsignedShort": return value + ".ToString(CultureInfo.InvariantCulture)";
336                                 case "unsignedInt": return value + ".ToString(CultureInfo.InvariantCulture)";
337                                 case "unsignedLong": return value + ".ToString(CultureInfo.InvariantCulture)";
338                                 case "guid": return "XmlConvert.ToString (" + value + ")";
339                                 case "base64":
340                                 case "base64Binary": return value + " == null ? String.Empty : Convert.ToBase64String (" + value + ")";
341                                 case "hexBinary": return value + " == null ? String.Empty : ToBinHexString (" + value + ")";
342                                 case "duration": return value;
343                                 case "NMTOKEN":
344                                 case "Name":
345                                 case "NCName":
346                                 case "language":
347                                 case "ENTITY":
348                                 case "ID":
349                                 case "IDREF":
350                                 case "NOTATION":
351                                 case "token":
352                                 case "normalizedString":
353                                 case "string": return value;
354                                 default: return "((" + value + " != null) ? (" + value + ").ToString() : null)";
355                         }
356                 }
357
358                 internal static string GenerateFromXmlString (TypeData type, string value)
359                 {
360                         if (type.NullableOverride)
361                                 return String.Concat ("(", value, " != null ? (", type.CSharpName, "?)", GenerateFromXmlStringCore (type, value), " : null)");
362                         else
363                                 return GenerateFromXmlStringCore (type, value);
364                 }
365
366                 static string GenerateFromXmlStringCore (TypeData type, string value)
367                 {
368                         switch (type.XmlType)
369                         {
370                                 case "boolean": return "XmlConvert.ToBoolean (" + value + ")";
371                                 case "unsignedByte": return "byte.Parse (" + value + ", CultureInfo.InvariantCulture)";
372                                 case "char": return "(char)Int32.Parse (" + value + ", CultureInfo.InvariantCulture)";
373                                 case "dateTime": return "XmlConvert.ToDateTime (" + value + ", XmlDateTimeSerializationMode.RoundtripKind)";
374                                 case "date": return "XmlConvert.ToDateTime (" + value + ").Date";
375                                 case "time": return "DateTime.ParseExact (" + value + ", \"HH:mm:ss.FFFFFFF\", CultureInfo.InvariantCulture)";
376                                 case "decimal": return "Decimal.Parse (" + value + ", CultureInfo.InvariantCulture)";
377                                 case "double": return "XmlConvert.ToDouble (" + value + ")";
378                                 case "short": return "Int16.Parse (" + value + ", CultureInfo.InvariantCulture)";
379                                 case "int": return "Int32.Parse (" + value + ", CultureInfo.InvariantCulture)";
380                                 case "long": return "Int64.Parse (" + value + ", CultureInfo.InvariantCulture)";
381                                 case "byte": return "SByte.Parse (" + value + ", CultureInfo.InvariantCulture)";
382                                 case "float": return "XmlConvert.ToSingle (" + value + ")";
383                                 case "unsignedShort": return "UInt16.Parse (" + value + ", CultureInfo.InvariantCulture)";
384                                 case "unsignedInt": return "UInt32.Parse (" + value + ", CultureInfo.InvariantCulture)";
385                                 case "unsignedLong": return "UInt64.Parse (" + value + ", CultureInfo.InvariantCulture)";
386                                 case "guid": return "XmlConvert.ToGuid (" + value + ")";
387                                 case "base64:":
388                                 case "base64Binary": return "Convert.FromBase64String (" + value + ")";
389                                 case "hexBinary": return "FromBinHexString (" + value + ")";
390                                 case "duration": return value;
391                                 default: return value;
392                         }
393                 }
394
395                 #endregion // Methods
396         }
397 }