Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Runtime.Serialization / System / Xml / XmlConverter.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 // PERF, [....], [....]: Make LookupNamespace do something smarter when lots of names
5 // PERF, [....], [....]: Make Attribute lookup smarter when lots of attributes
6 // PERF: [....], [....]: Compare safe/unsafe versions
7
8 namespace System.Xml
9 {
10     using System;
11     using System.Diagnostics.CodeAnalysis;
12     using System.Globalization;
13     using System.Runtime;
14     using System.Runtime.Serialization;
15     using System.Security;
16     using System.Text;
17
18     static class XmlConverter
19     {
20         public const int MaxDateTimeChars = 64;
21         public const int MaxInt32Chars = 16;
22         public const int MaxInt64Chars = 32;
23         public const int MaxBoolChars = 5;
24         public const int MaxFloatChars = 16;
25         public const int MaxDoubleChars = 32;
26         public const int MaxDecimalChars = 40;
27         public const int MaxUInt64Chars = 32;
28         public const int MaxPrimitiveChars = MaxDateTimeChars;
29
30         static char[] whiteSpaceChars = new char[] { ' ', '\t', '\n', '\r' };
31         static UTF8Encoding utf8Encoding;
32         static UnicodeEncoding unicodeEncoding;
33         static Base64Encoding base64Encoding;
34
35         static public Base64Encoding Base64Encoding
36         {
37             get
38             {
39                 if (base64Encoding == null)
40                     base64Encoding = new Base64Encoding();
41                 return base64Encoding;
42             }
43         }
44
45         static UTF8Encoding UTF8Encoding
46         {
47             get
48             {
49                 if (utf8Encoding == null)
50                     utf8Encoding = new UTF8Encoding(false, true);
51                 return utf8Encoding;
52             }
53         }
54
55         static UnicodeEncoding UnicodeEncoding
56         {
57             get
58             {
59                 if (unicodeEncoding == null)
60                     unicodeEncoding = new UnicodeEncoding(false, false, true);
61                 return unicodeEncoding;
62             }
63         }
64
65         static public bool ToBoolean(string value)
66         {
67             try
68             {
69                 return XmlConvert.ToBoolean(value);
70             }
71             catch (ArgumentException exception)
72             {
73                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Boolean", exception));
74             }
75             catch (FormatException exception)
76             {
77                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Boolean", exception));
78             }
79         }
80
81         static public bool ToBoolean(byte[] buffer, int offset, int count)
82         {
83             if (count == 1)
84             {
85                 byte ch = buffer[offset];
86                 if (ch == (byte)'1')
87                     return true;
88                 else if (ch == (byte)'0')
89                     return false;
90             }
91             return ToBoolean(ToString(buffer, offset, count));
92         }
93
94         static public int ToInt32(string value)
95         {
96             try
97             {
98                 return XmlConvert.ToInt32(value);
99             }
100             catch (ArgumentException exception)
101             {
102                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception));
103             }
104             catch (FormatException exception)
105             {
106                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception));
107             }
108             catch (OverflowException exception)
109             {
110                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception));
111             }
112         }
113
114         static public int ToInt32(byte[] buffer, int offset, int count)
115         {
116             int value;
117             if (TryParseInt32(buffer, offset, count, out value))
118                 return value;
119             return ToInt32(ToString(buffer, offset, count));
120         }
121
122         static public Int64 ToInt64(string value)
123         {
124             try
125             {
126                 return XmlConvert.ToInt64(value);
127             }
128             catch (ArgumentException exception)
129             {
130                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception));
131             }
132             catch (FormatException exception)
133             {
134                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception));
135             }
136             catch (OverflowException exception)
137             {
138                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception));
139             }
140         }
141
142         static public Int64 ToInt64(byte[] buffer, int offset, int count)
143         {
144             long value;
145             if (TryParseInt64(buffer, offset, count, out value))
146                 return value;
147             return ToInt64(ToString(buffer, offset, count));
148         }
149
150         static public float ToSingle(string value)
151         {
152             try
153             {
154                 return XmlConvert.ToSingle(value);
155             }
156             catch (ArgumentException exception)
157             {
158                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception));
159             }
160             catch (FormatException exception)
161             {
162                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception));
163             }
164             catch (OverflowException exception)
165             {
166                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception));
167             }
168         }
169
170         static public float ToSingle(byte[] buffer, int offset, int count)
171         {
172             float value;
173             if (TryParseSingle(buffer, offset, count, out value))
174                 return value;
175             return ToSingle(ToString(buffer, offset, count));
176         }
177
178         static public double ToDouble(string value)
179         {
180             try
181             {
182                 return XmlConvert.ToDouble(value);
183             }
184             catch (ArgumentException exception)
185             {
186                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception));
187             }
188             catch (FormatException exception)
189             {
190                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception));
191             }
192             catch (OverflowException exception)
193             {
194                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception));
195             }
196         }
197
198         static public double ToDouble(byte[] buffer, int offset, int count)
199         {
200             double value;
201             if (TryParseDouble(buffer, offset, count, out value))
202                 return value;
203             return ToDouble(ToString(buffer, offset, count));
204         }
205
206         static public decimal ToDecimal(string value)
207         {
208             try
209             {
210                 return XmlConvert.ToDecimal(value);
211             }
212             catch (ArgumentException exception)
213             {
214                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception));
215             }
216             catch (FormatException exception)
217             {
218                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception));
219             }
220             catch (OverflowException exception)
221             {
222                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception));
223             }
224         }
225
226         static public decimal ToDecimal(byte[] buffer, int offset, int count)
227         {
228             return ToDecimal(ToString(buffer, offset, count));
229         }
230
231         static public DateTime ToDateTime(Int64 value)
232         {
233             try
234             {
235                 return DateTime.FromBinary(value);
236             }
237             catch (ArgumentException exception)
238             {
239                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(ToString(value), "DateTime", exception));
240             }
241         }
242
243         static public DateTime ToDateTime(string value)
244         {
245             try
246             {
247                 return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind);
248             }
249             catch (ArgumentException exception)
250             {
251                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "DateTime", exception));
252             }
253             catch (FormatException exception)
254             {
255                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "DateTime", exception));
256             }
257         }
258
259         static public DateTime ToDateTime(byte[] buffer, int offset, int count)
260         {
261             DateTime value;
262             if (TryParseDateTime(buffer, offset, count, out value))
263                 return value;
264             return ToDateTime(ToString(buffer, offset, count));
265         }
266
267         static public UniqueId ToUniqueId(string value)
268         {
269             try
270             {
271                 return new UniqueId(Trim(value));
272             }
273             catch (ArgumentException exception)
274             {
275                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UniqueId", exception));
276             }
277             catch (FormatException exception)
278             {
279                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UniqueId", exception));
280             }
281         }
282
283         static public UniqueId ToUniqueId(byte[] buffer, int offset, int count)
284         {
285             return ToUniqueId(ToString(buffer, offset, count));
286         }
287
288         static public TimeSpan ToTimeSpan(string value)
289         {
290             try
291             {
292                 return XmlConvert.ToTimeSpan(value);
293             }
294             catch (ArgumentException exception)
295             {
296                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception));
297             }
298             catch (FormatException exception)
299             {
300                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception));
301             }
302             catch (OverflowException exception)
303             {
304                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception));
305             }
306         }
307
308         static public TimeSpan ToTimeSpan(byte[] buffer, int offset, int count)
309         {
310             return ToTimeSpan(ToString(buffer, offset, count));
311         }
312
313         [SuppressMessage("Reliability", "Reliability113", Justification = "Catching expected exceptions inline instead of calling Fx.CreateGuid to minimize code change")]
314         static public Guid ToGuid(string value)
315         {
316             try
317             {
318                 return Guid.Parse(Trim(value));
319             }
320             catch (FormatException exception)
321             {
322                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception));
323             }
324             catch (ArgumentException exception)
325             {
326                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception));
327             }
328             catch (OverflowException exception)
329             {
330                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception));
331             }
332         }
333
334         static public Guid ToGuid(byte[] buffer, int offset, int count)
335         {
336             return ToGuid(ToString(buffer, offset, count));
337         }
338
339         static public UInt64 ToUInt64(string value)
340         {
341             try
342             {
343                 return ulong.Parse(value, NumberFormatInfo.InvariantInfo);
344             }
345             catch (ArgumentException exception)
346             {
347                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception));
348             }
349             catch (FormatException exception)
350             {
351                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception));
352             }
353             catch (OverflowException exception)
354             {
355                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception));
356             }
357         }
358
359         static public UInt64 ToUInt64(byte[] buffer, int offset, int count)
360         {
361             return ToUInt64(ToString(buffer, offset, count));
362         }
363
364         static public string ToString(byte[] buffer, int offset, int count)
365         {
366             try
367             {
368                 return UTF8Encoding.GetString(buffer, offset, count);
369             }
370             catch (DecoderFallbackException exception)
371             {
372                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception));
373             }
374         }
375
376         static public string ToStringUnicode(byte[] buffer, int offset, int count)
377         {
378             try
379             {
380                 return UnicodeEncoding.GetString(buffer, offset, count);
381             }
382             catch (DecoderFallbackException exception)
383             {
384                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception));
385             }
386         }
387
388
389         static public byte[] ToBytes(string value)
390         {
391             try
392             {
393                 return UTF8Encoding.GetBytes(value);
394             }
395             catch (DecoderFallbackException exception)
396             {
397                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(value, exception));
398             }
399         }
400
401         static public int ToChars(byte[] buffer, int offset, int count, char[] chars, int charOffset)
402         {
403             try
404             {
405                 return UTF8Encoding.GetChars(buffer, offset, count, chars, charOffset);
406             }
407             catch (DecoderFallbackException exception)
408             {
409                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception));
410             }
411         }
412
413         static public string ToString(bool value) { return value ? "true" : "false"; }
414         static public string ToString(int value) { return XmlConvert.ToString(value); }
415         static public string ToString(Int64 value) { return XmlConvert.ToString(value); }
416         static public string ToString(float value) { return XmlConvert.ToString(value); }
417         static public string ToString(double value) { return XmlConvert.ToString(value); }
418         static public string ToString(decimal value) { return XmlConvert.ToString(value); }
419         static public string ToString(TimeSpan value) { return XmlConvert.ToString(value); }
420         static public string ToString(UniqueId value) { return value.ToString(); }
421         static public string ToString(Guid value) { return value.ToString(); }
422         static public string ToString(UInt64 value) { return value.ToString(NumberFormatInfo.InvariantInfo); }
423
424         static public string ToString(DateTime value)
425         {
426             byte[] dateChars = new byte[MaxDateTimeChars];
427             int count = ToChars(value, dateChars, 0);
428             return ToString(dateChars, 0, count);
429         }
430
431         static string ToString(object value)
432         {
433             if (value is int)
434                 return ToString((int)value);
435             else if (value is Int64)
436                 return ToString((Int64)value);
437             else if (value is float)
438                 return ToString((float)value);
439             else if (value is double)
440                 return ToString((double)value);
441             else if (value is decimal)
442                 return ToString((decimal)value);
443             else if (value is TimeSpan)
444                 return ToString((TimeSpan)value);
445             else if (value is UniqueId)
446                 return ToString((UniqueId)value);
447             else if (value is Guid)
448                 return ToString((Guid)value);
449             else if (value is UInt64)
450                 return ToString((UInt64)value);
451             else if (value is DateTime)
452                 return ToString((DateTime)value);
453             else if (value is bool)
454                 return ToString((bool)value);
455             else
456                 return value.ToString();
457         }
458
459         static public string ToString(object[] objects)
460         {
461             if (objects.Length == 0)
462                 return string.Empty;
463             string value = ToString(objects[0]);
464             if (objects.Length > 1)
465             {
466                 StringBuilder sb = new StringBuilder(value);
467                 for (int i = 1; i < objects.Length; i++)
468                 {
469                     sb.Append(' ');
470                     sb.Append(ToString(objects[i]));
471                 }
472                 value = sb.ToString();
473             }
474             return value;
475         }
476
477         static public void ToQualifiedName(string qname, out string prefix, out string localName)
478         {
479             int index = qname.IndexOf(':');
480             if (index < 0)
481             {
482                 prefix = string.Empty;
483                 localName = Trim(qname);
484             }
485             else
486             {
487                 if (index == qname.Length - 1)
488                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.XmlInvalidQualifiedName, qname)));
489                 prefix = Trim(qname.Substring(0, index));
490                 localName = Trim(qname.Substring(index + 1));
491             }
492         }
493
494         static bool TryParseInt32(byte[] chars, int offset, int count, out int result)
495         {
496             result = 0;
497             if (count == 0)
498                 return false;
499             int value = 0;
500             int offsetMax = offset + count;
501             if (chars[offset] == '-')
502             {
503                 if (count == 1)
504                     return false;
505                 for (int i = offset + 1; i < offsetMax; i++)
506                 {
507                     int digit = (chars[i] - '0');
508                     if ((uint)digit > 9)
509                         return false;
510                     if (value < int.MinValue / 10)
511                         return false;
512                     value *= 10;
513                     if (value < int.MinValue + digit)
514                         return false;
515                     value -= digit;
516                 }
517             }
518             else
519             {
520                 for (int i = offset; i < offsetMax; i++)
521                 {
522                     int digit = (chars[i] - '0');
523                     if ((uint)digit > 9)
524                         return false;
525                     if (value > int.MaxValue / 10)
526                         return false;
527                     value *= 10;
528                     if (value > int.MaxValue - digit)
529                         return false;
530                     value += digit;
531                 }
532             }
533             result = value;
534             return true;
535         }
536
537         static bool TryParseInt64(byte[] chars, int offset, int count, out long result)
538         {
539             result = 0;
540             if (count < 11)
541             {
542                 int value;
543                 if (!TryParseInt32(chars, offset, count, out value))
544                     return false;
545                 result = value;
546                 return true;
547             }
548             else
549             {
550                 long value = 0;
551                 int offsetMax = offset + count;
552                 if (chars[offset] == '-')
553                 {
554                     if (count == 1)
555                         return false;
556                     for (int i = offset + 1; i < offsetMax; i++)
557                     {
558                         int digit = (chars[i] - '0');
559                         if ((uint)digit > 9)
560                             return false;
561                         if (value < long.MinValue / 10)
562                             return false;
563                         value *= 10;
564                         if (value < long.MinValue + digit)
565                             return false;
566                         value -= digit;
567                     }
568                 }
569                 else
570                 {
571                     for (int i = offset; i < offsetMax; i++)
572                     {
573                         int digit = (chars[i] - '0');
574                         if ((uint)digit > 9)
575                             return false;
576                         if (value > long.MaxValue / 10)
577                             return false;
578                         value *= 10;
579                         if (value > long.MaxValue - digit)
580                             return false;
581                         value += digit;
582                     }
583                 }
584                 result = value;
585                 return true;
586             }
587         }
588
589         static bool TryParseSingle(byte[] chars, int offset, int count, out float result)
590         {
591             result = 0;
592             int offsetMax = offset + count;
593             bool negative = false;
594             if (offset < offsetMax && chars[offset] == '-')
595             {
596                 negative = true;
597                 offset++;
598                 count--;
599             }
600             if (count < 1 || count > 10)
601                 return false;
602             int value = 0;
603             int ch;
604             while (offset < offsetMax)
605             {
606                 ch = (chars[offset] - '0');
607                 if (ch == ('.' - '0'))
608                 {
609                     offset++;
610                     int pow10 = 1;
611                     while (offset < offsetMax)
612                     {
613                         ch = chars[offset] - '0';
614                         if (((uint)ch) >= 10)
615                             return false;
616                         pow10 *= 10;
617                         value = value * 10 + ch;
618                         offset++;
619                     }
620                     // More than 8 characters (7 sig figs and a decimal) and int -> float conversion is lossy, so use double
621                     if (count > 8)
622                     {
623                         result = (float)((double)value / (double)pow10);
624                     }
625                     else
626                     {
627                         result = (float)value / (float)pow10;
628                     }
629                     if (negative)
630                         result = -result;
631                     return true;
632                 }
633                 else if (((uint)ch) >= 10)
634                     return false;
635                 value = value * 10 + ch;
636                 offset++;
637             }
638             // Ten digits w/out a decimal point might've overflowed the int
639             if (count == 10)
640                 return false;
641             if (negative)
642                 result = -value;
643             else
644                 result = value;
645             return true;
646         }
647
648         static bool TryParseDouble(byte[] chars, int offset, int count, out double result)
649         {
650             result = 0;
651             int offsetMax = offset + count;
652             bool negative = false;
653             if (offset < offsetMax && chars[offset] == '-')
654             {
655                 negative = true;
656                 offset++;
657                 count--;
658             }
659             if (count < 1 || count > 10)
660                 return false;
661             int value = 0;
662             int ch;
663             while (offset < offsetMax)
664             {
665                 ch = (chars[offset] - '0');
666                 if (ch == ('.' - '0'))
667                 {
668                     offset++;
669                     int pow10 = 1;
670                     while (offset < offsetMax)
671                     {
672                         ch = chars[offset] - '0';
673                         if (((uint)ch) >= 10)
674                             return false;
675                         pow10 *= 10;
676                         value = value * 10 + ch;
677                         offset++;
678                     }
679                     if (negative)
680                         result = -(double)value / pow10;
681                     else
682                         result = (double)value / pow10;
683                     return true;
684                 }
685                 else if (((uint)ch) >= 10)
686                     return false;
687                 value = value * 10 + ch;
688                 offset++;
689             }
690             // Ten digits w/out a decimal point might've overflowed the int
691             if (count == 10)
692                 return false;
693             if (negative)
694                 result = -value;
695             else
696                 result = value;
697             return true;
698         }
699
700         static int ToInt32D2(byte[] chars, int offset)
701         {
702             byte ch1 = (byte)(chars[offset + 0] - '0');
703             byte ch2 = (byte)(chars[offset + 1] - '0');
704             if (ch1 > 9 || ch2 > 9)
705                 return -1;
706             return 10 * ch1 + ch2;
707         }
708
709         static int ToInt32D4(byte[] chars, int offset, int count)
710         {
711             return ToInt32D7(chars, offset, count);
712         }
713
714         static int ToInt32D7(byte[] chars, int offset, int count)
715         {
716             int value = 0;
717             for (int i = 0; i < count; i++)
718             {
719                 byte ch = (byte)(chars[offset + i] - '0');
720                 if (ch > 9)
721                     return -1;
722                 value = value * 10 + ch;
723             }
724             return value;
725         }
726
727         static bool TryParseDateTime(byte[] chars, int offset, int count, out DateTime result)
728         {
729             int offsetMax = offset + count;
730             result = DateTime.MaxValue;
731
732             if (count < 19)
733                 return false;
734
735             //            1         2         3
736             //  012345678901234567890123456789012
737             // "yyyy-MM-ddTHH:mm:ss"
738             // "yyyy-MM-ddTHH:mm:ss.fffffff"
739             // "yyyy-MM-ddTHH:mm:ss.fffffffZ"
740             // "yyyy-MM-ddTHH:mm:ss.fffffff+xx:yy"
741             // "yyyy-MM-ddTHH:mm:ss.fffffff-xx:yy"
742             if (chars[offset + 4] != '-' || chars[offset + 7] != '-' || chars[offset + 10] != 'T' ||
743                 chars[offset + 13] != ':' || chars[offset + 16] != ':')
744                 return false;
745
746             int year = ToInt32D4(chars, offset + 0, 4);
747             int month = ToInt32D2(chars, offset + 5);
748             int day = ToInt32D2(chars, offset + 8);
749             int hour = ToInt32D2(chars, offset + 11);
750             int minute = ToInt32D2(chars, offset + 14);
751             int second = ToInt32D2(chars, offset + 17);
752
753             if ((year | month | day | hour | minute | second) < 0)
754                 return false;
755
756             DateTimeKind kind = DateTimeKind.Unspecified;
757             offset += 19;
758
759             int ticks = 0;
760             if (offset < offsetMax && chars[offset] == '.')
761             {
762                 offset++;
763                 int digitOffset = offset;
764                 while (offset < offsetMax)
765                 {
766                     byte ch = chars[offset];
767                     if (ch < '0' || ch > '9')
768                         break;
769                     offset++;
770                 }
771                 int digitCount = offset - digitOffset;
772                 if (digitCount < 1 || digitCount > 7)
773                     return false;
774                 ticks = ToInt32D7(chars, digitOffset, digitCount);
775                 if (ticks < 0)
776                     return false;
777                 for (int i = digitCount; i < 7; ++i)
778                     ticks *= 10;
779             }
780
781             bool isLocal = false;
782             int hourDelta = 0;
783             int minuteDelta = 0;
784             if (offset < offsetMax)
785             {
786                 byte ch = chars[offset];
787                 if (ch == 'Z')
788                 {
789                     offset++;
790                     kind = DateTimeKind.Utc;
791                 }
792                 else if (ch == '+' || ch == '-')
793                 {
794                     offset++;
795                     if (offset + 5 > offsetMax || chars[offset + 2] != ':')
796                         return false;
797                     kind = DateTimeKind.Utc;
798                     isLocal = true;
799                     hourDelta = ToInt32D2(chars, offset);
800                     minuteDelta = ToInt32D2(chars, offset + 3);
801                     if ((hourDelta | minuteDelta) < 0)
802                         return false;
803                     if (ch == '+')
804                     {
805                         hourDelta = -hourDelta;
806                         minuteDelta = -minuteDelta;
807                     }
808                     offset += 5;
809                 }
810             }
811             if (offset < offsetMax)
812                 return false;
813
814             DateTime value;
815             try
816             {
817                 value = new DateTime(year, month, day, hour, minute, second, kind);
818             }
819             catch (ArgumentException)
820             {
821                 return false;
822             }
823
824             if (ticks > 0)
825             {
826                 value = value.AddTicks(ticks);
827             }
828             if (isLocal)
829             {
830                 try
831                 {
832                     TimeSpan ts = new TimeSpan(hourDelta, minuteDelta, 0);
833                     if (hourDelta >= 0 && (value < DateTime.MaxValue - ts) ||
834                         hourDelta < 0 && (value > DateTime.MinValue - ts))
835                     {
836                         value = value.Add(ts).ToLocalTime();
837                     }
838                     else
839                     {
840                         value = value.ToLocalTime().Add(ts);
841                     }
842                 }
843                 catch (ArgumentOutOfRangeException) // Overflow
844                 {
845                     return false;
846                 }
847             }
848
849             result = value;
850             return true;
851         }
852
853         static public int ToChars(bool value, byte[] buffer, int offset)
854         {
855             if (value)
856             {
857                 buffer[offset + 0] = (byte)'t';
858                 buffer[offset + 1] = (byte)'r';
859                 buffer[offset + 2] = (byte)'u';
860                 buffer[offset + 3] = (byte)'e';
861                 return 4;
862             }
863             else
864             {
865                 buffer[offset + 0] = (byte)'f';
866                 buffer[offset + 1] = (byte)'a';
867                 buffer[offset + 2] = (byte)'l';
868                 buffer[offset + 3] = (byte)'s';
869                 buffer[offset + 4] = (byte)'e';
870                 return 5;
871             }
872         }
873
874         // Works left from offset
875         static public int ToCharsR(int value, byte[] chars, int offset)
876         {
877             int count = 0;
878             if (value >= 0)
879             {
880                 while (value >= 10)
881                 {
882                     int valueDiv10 = value / 10;
883                     count++;
884                     chars[--offset] = (byte)('0' + (value - valueDiv10 * 10));
885                     value = valueDiv10;
886                 }
887                 chars[--offset] = (byte)('0' + value);
888                 count++;
889             }
890             else
891             {
892                 while (value <= -10)
893                 {
894                     int valueDiv10 = value / 10;
895                     count++;
896                     chars[--offset] = (byte)('0' - (value - valueDiv10 * 10));
897                     value = valueDiv10;
898                 }
899                 chars[--offset] = (byte)('0' - value);
900                 chars[--offset] = (byte)'-';
901                 count += 2;
902             }
903             return count;
904         }
905
906         static public int ToChars(int value, byte[] chars, int offset)
907         {
908             int count = ToCharsR(value, chars, offset + MaxInt32Chars);
909             Buffer.BlockCopy(chars, offset + MaxInt32Chars - count, chars, offset, count);
910             return count;
911         }
912
913         static public int ToCharsR(long value, byte[] chars, int offset)
914         {
915             int count = 0;
916             if (value >= 0)
917             {
918                 while (value > int.MaxValue)
919                 {
920                     long valueDiv10 = value / 10;
921                     count++;
922                     chars[--offset] = (byte)('0' + (int)(value - valueDiv10 * 10));
923                     value = valueDiv10;
924                 }
925             }
926             else
927             {
928                 while (value < int.MinValue)
929                 {
930                     long valueDiv10 = value / 10;
931                     count++;
932                     chars[--offset] = (byte)('0' - (int)(value - valueDiv10 * 10));
933                     value = valueDiv10;
934                 }
935             }
936             Fx.Assert(value >= int.MinValue && value <= int.MaxValue, "");
937             return count + ToCharsR((int)value, chars, offset);
938         }
939
940         static public int ToChars(long value, byte[] chars, int offset)
941         {
942             int count = ToCharsR(value, chars, offset + MaxInt64Chars);
943             Buffer.BlockCopy(chars, offset + MaxInt64Chars - count, chars, offset, count);
944             return count;
945         }
946
947         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
948             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
949         [SecuritySafeCritical]
950         static unsafe bool IsNegativeZero(float value)
951         {
952             // Simple equals function will report that -0 is equal to +0, so compare bits instead
953             float negativeZero = -0e0F;
954             return (*(Int32*)&value == *(Int32*)&negativeZero);
955         }
956
957         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
958             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
959         [SecuritySafeCritical]
960         static unsafe bool IsNegativeZero(double value)
961         {
962             // Simple equals function will report that -0 is equal to +0, so compare bits instead
963             double negativeZero = -0e0;
964             return (*(Int64*)&value == *(Int64*)&negativeZero);
965         }
966
967         static int ToInfinity(bool isNegative, byte[] buffer, int offset)
968         {
969             if (isNegative)
970             {
971                 buffer[offset + 0] = (byte)'-';
972                 buffer[offset + 1] = (byte)'I';
973                 buffer[offset + 2] = (byte)'N';
974                 buffer[offset + 3] = (byte)'F';
975                 return 4;
976             }
977             else
978             {
979                 buffer[offset + 0] = (byte)'I';
980                 buffer[offset + 1] = (byte)'N';
981                 buffer[offset + 2] = (byte)'F';
982                 return 3;
983             }
984         }
985
986         static int ToZero(bool isNegative, byte[] buffer, int offset)
987         {
988             if (isNegative)
989             {
990                 buffer[offset + 0] = (byte)'-';
991                 buffer[offset + 1] = (byte)'0';
992                 return 2;
993             }
994             else
995             {
996                 buffer[offset] = (byte)'0';
997                 return 1;
998             }
999         }
1000
1001         static public int ToChars(double value, byte[] buffer, int offset)
1002         {
1003             if (double.IsInfinity(value))
1004                 return ToInfinity(double.IsNegativeInfinity(value), buffer, offset);
1005             if (value == 0.0)
1006                 return ToZero(IsNegativeZero(value), buffer, offset);
1007             return ToAsciiChars(value.ToString("R", NumberFormatInfo.InvariantInfo), buffer, offset);
1008         }
1009
1010         static public int ToChars(float value, byte[] buffer, int offset)
1011         {
1012             if (float.IsInfinity(value))
1013                 return ToInfinity(float.IsNegativeInfinity(value), buffer, offset);
1014             if (value == 0.0)
1015                 return ToZero(IsNegativeZero(value), buffer, offset);
1016             return ToAsciiChars(value.ToString("R", NumberFormatInfo.InvariantInfo), buffer, offset);
1017         }
1018
1019         static public int ToChars(decimal value, byte[] buffer, int offset)
1020         {
1021             return ToAsciiChars(value.ToString(null, NumberFormatInfo.InvariantInfo), buffer, offset);
1022         }
1023
1024         static public int ToChars(UInt64 value, byte[] buffer, int offset)
1025         {
1026             return ToAsciiChars(value.ToString(null, NumberFormatInfo.InvariantInfo), buffer, offset);
1027         }
1028
1029         static int ToAsciiChars(string s, byte[] buffer, int offset)
1030         {
1031             for (int i = 0; i < s.Length; i++)
1032             {
1033                 Fx.Assert(s[i] < 128, "");
1034                 buffer[offset++] = (byte)s[i];
1035             }
1036             return s.Length;
1037         }
1038
1039         static int ToCharsD2(int value, byte[] chars, int offset)
1040         {
1041             Fx.Assert(value >= 0 && value < 100, "");
1042             if (value < 10)
1043             {
1044                 chars[offset + 0] = (byte)'0';
1045                 chars[offset + 1] = (byte)('0' + value);
1046             }
1047             else
1048             {
1049                 int valueDiv10 = value / 10;
1050                 chars[offset + 0] = (byte)('0' + valueDiv10);
1051                 chars[offset + 1] = (byte)('0' + value - valueDiv10 * 10);
1052             }
1053             return 2;
1054         }
1055
1056         static int ToCharsD4(int value, byte[] chars, int offset)
1057         {
1058             Fx.Assert(value >= 0 && value < 10000, "");
1059             ToCharsD2(value / 100, chars, offset + 0);
1060             ToCharsD2(value % 100, chars, offset + 2);
1061             return 4;
1062         }
1063
1064         static int ToCharsD7(int value, byte[] chars, int offset)
1065         {
1066             Fx.Assert(value >= 0 && value < 10000000, "");
1067             int zeroCount = 7 - ToCharsR(value, chars, offset + 7);
1068             for (int i = 0; i < zeroCount; i++)
1069                 chars[offset + i] = (byte)'0';
1070             int count = 7;
1071             while (count > 0 && chars[offset + count - 1] == '0')
1072                 count--;
1073             return count;
1074         }
1075
1076         static public int ToChars(DateTime value, byte[] chars, int offset)
1077         {
1078             const long TicksPerMillisecond = 10000;
1079             const long TicksPerSecond = TicksPerMillisecond * 1000;
1080             int offsetMin = offset;
1081             // "yyyy-MM-ddTHH:mm:ss.fffffff";
1082             offset += ToCharsD4(value.Year, chars, offset);
1083             chars[offset++] = (byte)'-';
1084             offset += ToCharsD2(value.Month, chars, offset);
1085             chars[offset++] = (byte)'-';
1086             offset += ToCharsD2(value.Day, chars, offset);
1087             chars[offset++] = (byte)'T';
1088             offset += ToCharsD2(value.Hour, chars, offset);
1089             chars[offset++] = (byte)':';
1090             offset += ToCharsD2(value.Minute, chars, offset);
1091             chars[offset++] = (byte)':';
1092             offset += ToCharsD2(value.Second, chars, offset);
1093             int ms = (int)(value.Ticks % TicksPerSecond);
1094             if (ms != 0)
1095             {
1096                 chars[offset++] = (byte)'.';
1097                 offset += ToCharsD7(ms, chars, offset);
1098             }
1099             switch (value.Kind)
1100             {
1101                 case DateTimeKind.Unspecified:
1102                     break;
1103                 case DateTimeKind.Local:
1104                     // +"zzzzzz";
1105                     TimeSpan ts = TimeZoneInfo.Local.GetUtcOffset(value);
1106                     if (ts.Ticks < 0)
1107                         chars[offset++] = (byte)'-';
1108                     else
1109                         chars[offset++] = (byte)'+';
1110                     offset += ToCharsD2(Math.Abs(ts.Hours), chars, offset);
1111                     chars[offset++] = (byte)':';
1112                     offset += ToCharsD2(Math.Abs(ts.Minutes), chars, offset);
1113                     break;
1114                 case DateTimeKind.Utc:
1115                     // +"Z"
1116                     chars[offset++] = (byte)'Z';
1117                     break;
1118                 default:
1119                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
1120             }
1121             return offset - offsetMin;
1122         }
1123
1124         static public bool IsWhitespace(string s)
1125         {
1126             for (int i = 0; i < s.Length; i++)
1127             {
1128                 if (!IsWhitespace(s[i]))
1129                     return false;
1130             }
1131             return true;
1132         }
1133
1134         static public bool IsWhitespace(char ch)
1135         {
1136             return (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'));
1137         }
1138
1139         static public string StripWhitespace(string s)
1140         {
1141             int count = s.Length;
1142             for (int i = 0; i < s.Length; i++)
1143             {
1144                 if (IsWhitespace(s[i]))
1145                 {
1146                     count--;
1147                 }
1148             }
1149             if (count == s.Length)
1150                 return s;
1151             char[] chars = new char[count];
1152             count = 0;
1153             for (int i = 0; i < s.Length; i++)
1154             {
1155                 char ch = s[i];
1156                 if (!IsWhitespace(ch))
1157                 {
1158                     chars[count++] = ch;
1159                 }
1160             }
1161             return new string(chars);
1162         }
1163
1164         static string Trim(string s)
1165         {
1166             int i;
1167             for (i = 0; i < s.Length && IsWhitespace(s[i]); i++);
1168
1169             int j;
1170             for (j = s.Length; j > 0 && IsWhitespace(s[j - 1]); j--);
1171
1172             if (i == 0 && j == s.Length)
1173                 return s;
1174             else if (j == 0)
1175                 return string.Empty;
1176             else
1177                 return s.Substring(i, j - i);
1178         }
1179     }
1180 }