|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.Runtime;
using Microsoft.Xml;
using Microsoft.Xml.Schema;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Globalization;
using System.Runtime.Serialization;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Microsoft.Xml
{
internal 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;
private static UTF8Encoding s_utf8Encoding;
private static UnicodeEncoding s_unicodeEncoding;
private static Base64Encoding s_base64Encoding;
static public Base64Encoding Base64Encoding
{
get
{
if (s_base64Encoding == null)
s_base64Encoding = new Base64Encoding();
return s_base64Encoding;
}
}
private static UTF8Encoding UTF8Encoding
{
get
{
if (s_utf8Encoding == null)
s_utf8Encoding = new UTF8Encoding(false, true);
return s_utf8Encoding;
}
}
private static UnicodeEncoding UnicodeEncoding
{
get
{
if (s_unicodeEncoding == null)
s_unicodeEncoding = new UnicodeEncoding(false, false, true);
return s_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));
}
static public Guid ToGuid(string value)
{
try
{
return new Guid(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, NumberStyles.Any, 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);
}
private 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(string.Format(SRSerialization.XmlInvalidQualifiedName, qname)));
prefix = Trim(qname.Substring(0, index));
localName = Trim(qname.Substring(index + 1));
}
}
private 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;
}
private 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;
}
}
private 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;
}
private 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 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 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;
}
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);
}
[SecuritySafeCritical]
private 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);
}
[SecuritySafeCritical]
private 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);
}
private 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;
}
}
private 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);
}
private 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 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;
}
}
private 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;
}
private static int ToInt32D4(byte[] chars, int offset, int count)
{
return ToInt32D7(chars, offset, count);
}
private 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;
}
private 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;
}
// 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;
}
private static int ToCharsD2(int value, byte[] chars, int offset)
{
DiagnosticUtility.DebugAssert(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;
}
private static int ToCharsD4(int value, byte[] chars, int offset)
{
DiagnosticUtility.DebugAssert(value >= 0 && value < 10000, "");
ToCharsD2(value / 100, chars, offset + 0);
ToCharsD2(value % 100, chars, offset + 2);
return 4;
}
private static int ToCharsD7(int value, byte[] chars, int offset)
{
DiagnosticUtility.DebugAssert(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);
}
private 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);
}
}
}
|