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 FromByteArrayBase64(byte[] value)43 internal static string FromByteArrayBase64 (byte[] value) 44 { 45 return value == null ? String.Empty : Convert.ToBase64String(value); 46 } 47 FromByteArrayHex(byte[] value)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 FromChar(char value)57 internal static string FromChar (char value) 58 { 59 return ((int) value).ToString (CultureInfo.InvariantCulture); 60 } 61 FromDate(DateTime value)62 internal static string FromDate (DateTime value) 63 { 64 return XmlConvert.ToString (value, "yyyy-MM-dd"); 65 } 66 FromDateTime(DateTime value)67 internal static string FromDateTime (DateTime value) 68 { 69 return XmlConvert.ToString (value, XmlDateTimeSerializationMode.RoundtripKind); 70 } 71 FromTime(DateTime value)72 internal static string FromTime (DateTime value) 73 { 74 return XmlConvert.ToString (value, "HH:mm:ss.fffffffzzz"); 75 } 76 FromEnum(long value, string[] values, long[] ids)77 internal static string FromEnum (long value, string[] values, long[] ids) 78 { 79 return FromEnum (value, values, ids, (string) null); 80 } 81 FromEnum(long value, string[] values, long[] ids, string typeName)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 FromXmlName(string name)120 internal static string FromXmlName (string name) 121 { 122 return XmlConvert.EncodeName (name); 123 } 124 FromXmlNCName(string ncName)125 internal static string FromXmlNCName (string ncName) 126 { 127 return XmlConvert.EncodeLocalName (ncName); 128 } 129 FromXmlNmToken(string nmToken)130 internal static string FromXmlNmToken (string nmToken) 131 { 132 return XmlConvert.EncodeNmToken (nmToken); 133 } 134 FromXmlNmTokens(string nmTokens)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 ToByteArrayBase64(string value)143 internal static byte[] ToByteArrayBase64 (string value) 144 { 145 return Convert.FromBase64String(value); 146 } 147 ToChar(string value)148 internal static char ToChar (string value) 149 { 150 return (char) XmlConvert.ToUInt16 (value); 151 } 152 ToDate(string value)153 internal static DateTime ToDate (string value) 154 { 155 return ToDateTime (value); 156 } 157 ToDateTime(string value)158 internal static DateTime ToDateTime (string value) 159 { 160 return XmlConvert.ToDateTime (value, XmlDateTimeSerializationMode.RoundtripKind); 161 } 162 ToTime(string value)163 internal static DateTime ToTime (string value) 164 { 165 return ToDateTime (value); 166 } 167 ToEnum(string value, Hashtable values, string typeName, bool validate)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 ToXmlName(string value)196 internal static string ToXmlName (string value) 197 { 198 return XmlConvert.DecodeName (value); 199 } 200 ToXmlNCName(string value)201 internal static string ToXmlNCName (string value) 202 { 203 return ToXmlName (value); 204 } 205 ToXmlNmToken(string value)206 internal static string ToXmlNmToken (string value) 207 { 208 return ToXmlName (value); 209 } 210 ToXmlNmTokens(string value)211 internal static string ToXmlNmTokens (string value) 212 { 213 return ToXmlName (value); 214 } 215 ToXmlString(TypeData type, object value)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 FromXmlString(TypeData type, string value)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 GenerateToXmlString(TypeData type, string value)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 GenerateToXmlStringCore(TypeData type, string value)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 GenerateFromXmlString(TypeData type, string value)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 GenerateFromXmlStringCore(TypeData type, string value)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 } 398