//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ // PERF, [....], [....]: Make LookupNamespace do something smarter when lots of names // PERF, [....], [....]: Make Attribute lookup smarter when lots of attributes // PERF: [....], [....]: Compare safe/unsafe versions namespace System.Xml { using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime; using System.Runtime.Serialization; using System.Security; using System.Text; static class XmlConverter { public const int MaxDateTimeChars = 64; public const int MaxInt32Chars = 16; public const int MaxInt64Chars = 32; public const int MaxBoolChars = 5; public const int MaxFloatChars = 16; public const int MaxDoubleChars = 32; public const int MaxDecimalChars = 40; public const int MaxUInt64Chars = 32; public const int MaxPrimitiveChars = MaxDateTimeChars; static char[] whiteSpaceChars = new char[] { ' ', '\t', '\n', '\r' }; static UTF8Encoding utf8Encoding; static UnicodeEncoding unicodeEncoding; static Base64Encoding base64Encoding; static public Base64Encoding Base64Encoding { get { if (base64Encoding == null) base64Encoding = new Base64Encoding(); return base64Encoding; } } static UTF8Encoding UTF8Encoding { get { if (utf8Encoding == null) utf8Encoding = new UTF8Encoding(false, true); return utf8Encoding; } } static UnicodeEncoding UnicodeEncoding { get { if (unicodeEncoding == null) unicodeEncoding = new UnicodeEncoding(false, false, true); return unicodeEncoding; } } static public bool ToBoolean(string value) { try { return XmlConvert.ToBoolean(value); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Boolean", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Boolean", exception)); } } static public bool ToBoolean(byte[] buffer, int offset, int count) { if (count == 1) { byte ch = buffer[offset]; if (ch == (byte)'1') return true; else if (ch == (byte)'0') return false; } return ToBoolean(ToString(buffer, offset, count)); } static public int ToInt32(string value) { try { return XmlConvert.ToInt32(value); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); } } static public int ToInt32(byte[] buffer, int offset, int count) { int value; if (TryParseInt32(buffer, offset, count, out value)) return value; return ToInt32(ToString(buffer, offset, count)); } static public Int64 ToInt64(string value) { try { return XmlConvert.ToInt64(value); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); } } static public Int64 ToInt64(byte[] buffer, int offset, int count) { long value; if (TryParseInt64(buffer, offset, count, out value)) return value; return ToInt64(ToString(buffer, offset, count)); } static public float ToSingle(string value) { try { return XmlConvert.ToSingle(value); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception)); } } static public float ToSingle(byte[] buffer, int offset, int count) { float value; if (TryParseSingle(buffer, offset, count, out value)) return value; return ToSingle(ToString(buffer, offset, count)); } static public double ToDouble(string value) { try { return XmlConvert.ToDouble(value); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception)); } } static public double ToDouble(byte[] buffer, int offset, int count) { double value; if (TryParseDouble(buffer, offset, count, out value)) return value; return ToDouble(ToString(buffer, offset, count)); } static public decimal ToDecimal(string value) { try { return XmlConvert.ToDecimal(value); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); } } static public decimal ToDecimal(byte[] buffer, int offset, int count) { return ToDecimal(ToString(buffer, offset, count)); } static public DateTime ToDateTime(Int64 value) { try { return DateTime.FromBinary(value); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(ToString(value), "DateTime", exception)); } } static public DateTime ToDateTime(string value) { try { return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "DateTime", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "DateTime", exception)); } } static public DateTime ToDateTime(byte[] buffer, int offset, int count) { DateTime value; if (TryParseDateTime(buffer, offset, count, out value)) return value; return ToDateTime(ToString(buffer, offset, count)); } static public UniqueId ToUniqueId(string value) { try { return new UniqueId(Trim(value)); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UniqueId", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UniqueId", exception)); } } static public UniqueId ToUniqueId(byte[] buffer, int offset, int count) { return ToUniqueId(ToString(buffer, offset, count)); } static public TimeSpan ToTimeSpan(string value) { try { return XmlConvert.ToTimeSpan(value); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception)); } } static public TimeSpan ToTimeSpan(byte[] buffer, int offset, int count) { return ToTimeSpan(ToString(buffer, offset, count)); } [SuppressMessage("Reliability", "Reliability113", Justification = "Catching expected exceptions inline instead of calling Fx.CreateGuid to minimize code change")] static public Guid ToGuid(string value) { try { return Guid.Parse(Trim(value)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception)); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception)); } } static public Guid ToGuid(byte[] buffer, int offset, int count) { return ToGuid(ToString(buffer, offset, count)); } static public UInt64 ToUInt64(string value) { try { return ulong.Parse(value, NumberFormatInfo.InvariantInfo); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception)); } } static public UInt64 ToUInt64(byte[] buffer, int offset, int count) { return ToUInt64(ToString(buffer, offset, count)); } static public string ToString(byte[] buffer, int offset, int count) { try { return UTF8Encoding.GetString(buffer, offset, count); } catch (DecoderFallbackException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception)); } } static public string ToStringUnicode(byte[] buffer, int offset, int count) { try { return UnicodeEncoding.GetString(buffer, offset, count); } catch (DecoderFallbackException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception)); } } static public byte[] ToBytes(string value) { try { return UTF8Encoding.GetBytes(value); } catch (DecoderFallbackException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(value, exception)); } } static public int ToChars(byte[] buffer, int offset, int count, char[] chars, int charOffset) { try { return UTF8Encoding.GetChars(buffer, offset, count, chars, charOffset); } catch (DecoderFallbackException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception)); } } static public string ToString(bool value) { return value ? "true" : "false"; } static public string ToString(int value) { return XmlConvert.ToString(value); } static public string ToString(Int64 value) { return XmlConvert.ToString(value); } static public string ToString(float value) { return XmlConvert.ToString(value); } static public string ToString(double value) { return XmlConvert.ToString(value); } static public string ToString(decimal value) { return XmlConvert.ToString(value); } static public string ToString(TimeSpan value) { return XmlConvert.ToString(value); } static public string ToString(UniqueId value) { return value.ToString(); } static public string ToString(Guid value) { return value.ToString(); } static public string ToString(UInt64 value) { return value.ToString(NumberFormatInfo.InvariantInfo); } static public string ToString(DateTime value) { byte[] dateChars = new byte[MaxDateTimeChars]; int count = ToChars(value, dateChars, 0); return ToString(dateChars, 0, count); } static string ToString(object value) { if (value is int) return ToString((int)value); else if (value is Int64) return ToString((Int64)value); else if (value is float) return ToString((float)value); else if (value is double) return ToString((double)value); else if (value is decimal) return ToString((decimal)value); else if (value is TimeSpan) return ToString((TimeSpan)value); else if (value is UniqueId) return ToString((UniqueId)value); else if (value is Guid) return ToString((Guid)value); else if (value is UInt64) return ToString((UInt64)value); else if (value is DateTime) return ToString((DateTime)value); else if (value is bool) return ToString((bool)value); else return value.ToString(); } static public string ToString(object[] objects) { if (objects.Length == 0) return string.Empty; string value = ToString(objects[0]); if (objects.Length > 1) { StringBuilder sb = new StringBuilder(value); for (int i = 1; i < objects.Length; i++) { sb.Append(' '); sb.Append(ToString(objects[i])); } value = sb.ToString(); } return value; } static public void ToQualifiedName(string qname, out string prefix, out string localName) { int index = qname.IndexOf(':'); if (index < 0) { prefix = string.Empty; localName = Trim(qname); } else { if (index == qname.Length - 1) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.XmlInvalidQualifiedName, qname))); prefix = Trim(qname.Substring(0, index)); localName = Trim(qname.Substring(index + 1)); } } static bool TryParseInt32(byte[] chars, int offset, int count, out int result) { result = 0; if (count == 0) return false; int value = 0; int offsetMax = offset + count; if (chars[offset] == '-') { if (count == 1) return false; for (int i = offset + 1; i < offsetMax; i++) { int digit = (chars[i] - '0'); if ((uint)digit > 9) return false; if (value < int.MinValue / 10) return false; value *= 10; if (value < int.MinValue + digit) return false; value -= digit; } } else { for (int i = offset; i < offsetMax; i++) { int digit = (chars[i] - '0'); if ((uint)digit > 9) return false; if (value > int.MaxValue / 10) return false; value *= 10; if (value > int.MaxValue - digit) return false; value += digit; } } result = value; return true; } static bool TryParseInt64(byte[] chars, int offset, int count, out long result) { result = 0; if (count < 11) { int value; if (!TryParseInt32(chars, offset, count, out value)) return false; result = value; return true; } else { long value = 0; int offsetMax = offset + count; if (chars[offset] == '-') { if (count == 1) return false; for (int i = offset + 1; i < offsetMax; i++) { int digit = (chars[i] - '0'); if ((uint)digit > 9) return false; if (value < long.MinValue / 10) return false; value *= 10; if (value < long.MinValue + digit) return false; value -= digit; } } else { for (int i = offset; i < offsetMax; i++) { int digit = (chars[i] - '0'); if ((uint)digit > 9) return false; if (value > long.MaxValue / 10) return false; value *= 10; if (value > long.MaxValue - digit) return false; value += digit; } } result = value; return true; } } static bool TryParseSingle(byte[] chars, int offset, int count, out float result) { result = 0; int offsetMax = offset + count; bool negative = false; if (offset < offsetMax && chars[offset] == '-') { negative = true; offset++; count--; } if (count < 1 || count > 10) return false; int value = 0; int ch; while (offset < offsetMax) { ch = (chars[offset] - '0'); if (ch == ('.' - '0')) { offset++; int pow10 = 1; while (offset < offsetMax) { ch = chars[offset] - '0'; if (((uint)ch) >= 10) return false; pow10 *= 10; value = value * 10 + ch; offset++; } // More than 8 characters (7 sig figs and a decimal) and int -> float conversion is lossy, so use double if (count > 8) { result = (float)((double)value / (double)pow10); } else { result = (float)value / (float)pow10; } if (negative) result = -result; return true; } else if (((uint)ch) >= 10) return false; value = value * 10 + ch; offset++; } // Ten digits w/out a decimal point might've overflowed the int if (count == 10) return false; if (negative) result = -value; else result = value; return true; } static bool TryParseDouble(byte[] chars, int offset, int count, out double result) { result = 0; int offsetMax = offset + count; bool negative = false; if (offset < offsetMax && chars[offset] == '-') { negative = true; offset++; count--; } if (count < 1 || count > 10) return false; int value = 0; int ch; while (offset < offsetMax) { ch = (chars[offset] - '0'); if (ch == ('.' - '0')) { offset++; int pow10 = 1; while (offset < offsetMax) { ch = chars[offset] - '0'; if (((uint)ch) >= 10) return false; pow10 *= 10; value = value * 10 + ch; offset++; } if (negative) result = -(double)value / pow10; else result = (double)value / pow10; return true; } else if (((uint)ch) >= 10) return false; value = value * 10 + ch; offset++; } // Ten digits w/out a decimal point might've overflowed the int if (count == 10) return false; if (negative) result = -value; else result = value; return true; } static int ToInt32D2(byte[] chars, int offset) { byte ch1 = (byte)(chars[offset + 0] - '0'); byte ch2 = (byte)(chars[offset + 1] - '0'); if (ch1 > 9 || ch2 > 9) return -1; return 10 * ch1 + ch2; } static int ToInt32D4(byte[] chars, int offset, int count) { return ToInt32D7(chars, offset, count); } static int ToInt32D7(byte[] chars, int offset, int count) { int value = 0; for (int i = 0; i < count; i++) { byte ch = (byte)(chars[offset + i] - '0'); if (ch > 9) return -1; value = value * 10 + ch; } return value; } static bool TryParseDateTime(byte[] chars, int offset, int count, out DateTime result) { int offsetMax = offset + count; result = DateTime.MaxValue; if (count < 19) return false; // 1 2 3 // 012345678901234567890123456789012 // "yyyy-MM-ddTHH:mm:ss" // "yyyy-MM-ddTHH:mm:ss.fffffff" // "yyyy-MM-ddTHH:mm:ss.fffffffZ" // "yyyy-MM-ddTHH:mm:ss.fffffff+xx:yy" // "yyyy-MM-ddTHH:mm:ss.fffffff-xx:yy" if (chars[offset + 4] != '-' || chars[offset + 7] != '-' || chars[offset + 10] != 'T' || chars[offset + 13] != ':' || chars[offset + 16] != ':') return false; int year = ToInt32D4(chars, offset + 0, 4); int month = ToInt32D2(chars, offset + 5); int day = ToInt32D2(chars, offset + 8); int hour = ToInt32D2(chars, offset + 11); int minute = ToInt32D2(chars, offset + 14); int second = ToInt32D2(chars, offset + 17); if ((year | month | day | hour | minute | second) < 0) return false; DateTimeKind kind = DateTimeKind.Unspecified; offset += 19; int ticks = 0; if (offset < offsetMax && chars[offset] == '.') { offset++; int digitOffset = offset; while (offset < offsetMax) { byte ch = chars[offset]; if (ch < '0' || ch > '9') break; offset++; } int digitCount = offset - digitOffset; if (digitCount < 1 || digitCount > 7) return false; ticks = ToInt32D7(chars, digitOffset, digitCount); if (ticks < 0) return false; for (int i = digitCount; i < 7; ++i) ticks *= 10; } bool isLocal = false; int hourDelta = 0; int minuteDelta = 0; if (offset < offsetMax) { byte ch = chars[offset]; if (ch == 'Z') { offset++; kind = DateTimeKind.Utc; } else if (ch == '+' || ch == '-') { offset++; if (offset + 5 > offsetMax || chars[offset + 2] != ':') return false; kind = DateTimeKind.Utc; isLocal = true; hourDelta = ToInt32D2(chars, offset); minuteDelta = ToInt32D2(chars, offset + 3); if ((hourDelta | minuteDelta) < 0) return false; if (ch == '+') { hourDelta = -hourDelta; minuteDelta = -minuteDelta; } offset += 5; } } if (offset < offsetMax) return false; DateTime value; try { value = new DateTime(year, month, day, hour, minute, second, kind); } catch (ArgumentException) { return false; } if (ticks > 0) { value = value.AddTicks(ticks); } if (isLocal) { try { TimeSpan ts = new TimeSpan(hourDelta, minuteDelta, 0); if (hourDelta >= 0 && (value < DateTime.MaxValue - ts) || hourDelta < 0 && (value > DateTime.MinValue - ts)) { value = value.Add(ts).ToLocalTime(); } else { value = value.ToLocalTime().Add(ts); } } catch (ArgumentOutOfRangeException) // Overflow { return false; } } result = value; return true; } static public int ToChars(bool value, byte[] buffer, int offset) { if (value) { buffer[offset + 0] = (byte)'t'; buffer[offset + 1] = (byte)'r'; buffer[offset + 2] = (byte)'u'; buffer[offset + 3] = (byte)'e'; return 4; } else { buffer[offset + 0] = (byte)'f'; buffer[offset + 1] = (byte)'a'; buffer[offset + 2] = (byte)'l'; buffer[offset + 3] = (byte)'s'; buffer[offset + 4] = (byte)'e'; return 5; } } // Works left from offset static public int ToCharsR(int value, byte[] chars, int offset) { int count = 0; if (value >= 0) { while (value >= 10) { int valueDiv10 = value / 10; count++; chars[--offset] = (byte)('0' + (value - valueDiv10 * 10)); value = valueDiv10; } chars[--offset] = (byte)('0' + value); count++; } else { while (value <= -10) { int valueDiv10 = value / 10; count++; chars[--offset] = (byte)('0' - (value - valueDiv10 * 10)); value = valueDiv10; } chars[--offset] = (byte)('0' - value); chars[--offset] = (byte)'-'; count += 2; } return count; } static public int ToChars(int value, byte[] chars, int offset) { int count = ToCharsR(value, chars, offset + MaxInt32Chars); Buffer.BlockCopy(chars, offset + MaxInt32Chars - count, chars, offset, count); return count; } static public int ToCharsR(long value, byte[] chars, int offset) { int count = 0; if (value >= 0) { while (value > int.MaxValue) { long valueDiv10 = value / 10; count++; chars[--offset] = (byte)('0' + (int)(value - valueDiv10 * 10)); value = valueDiv10; } } else { while (value < int.MinValue) { long valueDiv10 = value / 10; count++; chars[--offset] = (byte)('0' - (int)(value - valueDiv10 * 10)); value = valueDiv10; } } Fx.Assert(value >= int.MinValue && value <= int.MaxValue, ""); return count + ToCharsR((int)value, chars, offset); } static public int ToChars(long value, byte[] chars, int offset) { int count = ToCharsR(value, chars, offset + MaxInt64Chars); Buffer.BlockCopy(chars, offset + MaxInt64Chars - count, chars, offset, count); return count; } [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] static unsafe bool IsNegativeZero(float value) { // Simple equals function will report that -0 is equal to +0, so compare bits instead float negativeZero = -0e0F; return (*(Int32*)&value == *(Int32*)&negativeZero); } [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] static unsafe bool IsNegativeZero(double value) { // Simple equals function will report that -0 is equal to +0, so compare bits instead double negativeZero = -0e0; return (*(Int64*)&value == *(Int64*)&negativeZero); } static int ToInfinity(bool isNegative, byte[] buffer, int offset) { if (isNegative) { buffer[offset + 0] = (byte)'-'; buffer[offset + 1] = (byte)'I'; buffer[offset + 2] = (byte)'N'; buffer[offset + 3] = (byte)'F'; return 4; } else { buffer[offset + 0] = (byte)'I'; buffer[offset + 1] = (byte)'N'; buffer[offset + 2] = (byte)'F'; return 3; } } static int ToZero(bool isNegative, byte[] buffer, int offset) { if (isNegative) { buffer[offset + 0] = (byte)'-'; buffer[offset + 1] = (byte)'0'; return 2; } else { buffer[offset] = (byte)'0'; return 1; } } static public int ToChars(double value, byte[] buffer, int offset) { if (double.IsInfinity(value)) return ToInfinity(double.IsNegativeInfinity(value), buffer, offset); if (value == 0.0) return ToZero(IsNegativeZero(value), buffer, offset); return ToAsciiChars(value.ToString("R", NumberFormatInfo.InvariantInfo), buffer, offset); } static public int ToChars(float value, byte[] buffer, int offset) { if (float.IsInfinity(value)) return ToInfinity(float.IsNegativeInfinity(value), buffer, offset); if (value == 0.0) return ToZero(IsNegativeZero(value), buffer, offset); return ToAsciiChars(value.ToString("R", NumberFormatInfo.InvariantInfo), buffer, offset); } static public int ToChars(decimal value, byte[] buffer, int offset) { return ToAsciiChars(value.ToString(null, NumberFormatInfo.InvariantInfo), buffer, offset); } static public int ToChars(UInt64 value, byte[] buffer, int offset) { return ToAsciiChars(value.ToString(null, NumberFormatInfo.InvariantInfo), buffer, offset); } static int ToAsciiChars(string s, byte[] buffer, int offset) { for (int i = 0; i < s.Length; i++) { Fx.Assert(s[i] < 128, ""); buffer[offset++] = (byte)s[i]; } return s.Length; } static int ToCharsD2(int value, byte[] chars, int offset) { Fx.Assert(value >= 0 && value < 100, ""); if (value < 10) { chars[offset + 0] = (byte)'0'; chars[offset + 1] = (byte)('0' + value); } else { int valueDiv10 = value / 10; chars[offset + 0] = (byte)('0' + valueDiv10); chars[offset + 1] = (byte)('0' + value - valueDiv10 * 10); } return 2; } static int ToCharsD4(int value, byte[] chars, int offset) { Fx.Assert(value >= 0 && value < 10000, ""); ToCharsD2(value / 100, chars, offset + 0); ToCharsD2(value % 100, chars, offset + 2); return 4; } static int ToCharsD7(int value, byte[] chars, int offset) { Fx.Assert(value >= 0 && value < 10000000, ""); int zeroCount = 7 - ToCharsR(value, chars, offset + 7); for (int i = 0; i < zeroCount; i++) chars[offset + i] = (byte)'0'; int count = 7; while (count > 0 && chars[offset + count - 1] == '0') count--; return count; } static public int ToChars(DateTime value, byte[] chars, int offset) { const long TicksPerMillisecond = 10000; const long TicksPerSecond = TicksPerMillisecond * 1000; int offsetMin = offset; // "yyyy-MM-ddTHH:mm:ss.fffffff"; offset += ToCharsD4(value.Year, chars, offset); chars[offset++] = (byte)'-'; offset += ToCharsD2(value.Month, chars, offset); chars[offset++] = (byte)'-'; offset += ToCharsD2(value.Day, chars, offset); chars[offset++] = (byte)'T'; offset += ToCharsD2(value.Hour, chars, offset); chars[offset++] = (byte)':'; offset += ToCharsD2(value.Minute, chars, offset); chars[offset++] = (byte)':'; offset += ToCharsD2(value.Second, chars, offset); int ms = (int)(value.Ticks % TicksPerSecond); if (ms != 0) { chars[offset++] = (byte)'.'; offset += ToCharsD7(ms, chars, offset); } switch (value.Kind) { case DateTimeKind.Unspecified: break; case DateTimeKind.Local: // +"zzzzzz"; TimeSpan ts = TimeZoneInfo.Local.GetUtcOffset(value); if (ts.Ticks < 0) chars[offset++] = (byte)'-'; else chars[offset++] = (byte)'+'; offset += ToCharsD2(Math.Abs(ts.Hours), chars, offset); chars[offset++] = (byte)':'; offset += ToCharsD2(Math.Abs(ts.Minutes), chars, offset); break; case DateTimeKind.Utc: // +"Z" chars[offset++] = (byte)'Z'; break; default: throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); } return offset - offsetMin; } static public bool IsWhitespace(string s) { for (int i = 0; i < s.Length; i++) { if (!IsWhitespace(s[i])) return false; } return true; } static public bool IsWhitespace(char ch) { return (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')); } static public string StripWhitespace(string s) { int count = s.Length; for (int i = 0; i < s.Length; i++) { if (IsWhitespace(s[i])) { count--; } } if (count == s.Length) return s; char[] chars = new char[count]; count = 0; for (int i = 0; i < s.Length; i++) { char ch = s[i]; if (!IsWhitespace(ch)) { chars[count++] = ch; } } return new string(chars); } static string Trim(string s) { int i; for (i = 0; i < s.Length && IsWhitespace(s[i]); i++); int j; for (j = s.Length; j > 0 && IsWhitespace(s[j - 1]); j--); if (i == 0 && j == s.Length) return s; else if (j == 0) return string.Empty; else return s.Substring(i, j - i); } } }