const NumberStyles floatStyle = NumberStyles.AllowCurrencySymbol |
NumberStyles.AllowExponent |
NumberStyles.AllowDecimalPoint |
- NumberStyles.AllowLeadingSign;
+ NumberStyles.AllowLeadingSign |
+ NumberStyles.AllowLeadingWhite |
+ NumberStyles.AllowTrailingWhite;
+ const NumberStyles integerStyle = NumberStyles.Integer |
+ NumberStyles.AllowLeadingWhite |
+ NumberStyles.AllowTrailingWhite;
+
static readonly string [] datetimeFormats = {
// dateTime
+#if NET_2_0
+ "yyyy-MM-ddTHH:mm:sszzz",
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",
"yyyy-MM-ddTHH:mm:ss",
- "yyyy-MM-ddTHH:mm:ss.f",
- "yyyy-MM-ddTHH:mm:ss.ff",
- "yyyy-MM-ddTHH:mm:ss.fff",
- "yyyy-MM-ddTHH:mm:ss.ffff",
- "yyyy-MM-ddTHH:mm:ss.fffff",
- "yyyy-MM-ddTHH:mm:ss.ffffff",
- "yyyy-MM-ddTHH:mm:ss.fffffff",
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
+ "HH:mm:ss",
+ "HH:mm:ss.FFFFFFF",
+ "HH:mm:sszzz",
+ "HH:mm:ss.FFFFFFFzzz",
+ "HH:mm:ssZ",
+ "HH:mm:ss.FFFFFFFZ",
+#else // it is not required in trunk but should make it easy to backport...
"yyyy-MM-ddTHH:mm:sszzz",
"yyyy-MM-ddTHH:mm:ss.fzzz",
"yyyy-MM-ddTHH:mm:ss.ffzzz",
"yyyy-MM-ddTHH:mm:ss.fffffZ",
"yyyy-MM-ddTHH:mm:ss.ffffffZ",
"yyyy-MM-ddTHH:mm:ss.fffffffZ",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mm:ss.f",
+ "yyyy-MM-ddTHH:mm:ss.ff",
+ "yyyy-MM-ddTHH:mm:ss.fff",
+ "yyyy-MM-ddTHH:mm:ss.ffff",
+ "yyyy-MM-ddTHH:mm:ss.fffff",
+ "yyyy-MM-ddTHH:mm:ss.ffffff",
+ "yyyy-MM-ddTHH:mm:ss.fffffff",
// time
"HH:mm:ss",
"HH:mm:ss.f",
"HH:mm:ss.fffffZ",
"HH:mm:ss.ffffffZ",
"HH:mm:ss.fffffffZ",
+#endif
// date
"yyyy-MM-dd",
"yyyy-MM-ddzzz",
"---ddzzz",
"---ddZ",
};
+
+#if NET_2_0
+ static readonly string [] defaultDateTimeFormats = new string [] {
+ "yyyy-MM-ddTHH:mm:ss", // dateTime(1)
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFF", // dateTime(2)
+ "yyyy-MM-dd", // date
+ "HH:mm:ss", // time
+ "yyyy-MM", // gYearMonth
+ "yyyy", // gYear
+ "--MM-dd", // gMonthDay
+ "---dd", // gDay
+ };
+
+ static readonly string [] roundtripDateTimeFormats;
+ static readonly string [] localDateTimeFormats;
+ static readonly string [] utcDateTimeFormats;
+ static readonly string [] unspecifiedDateTimeFormats;
+
+ static XmlConvert ()
+ {
+ int l = defaultDateTimeFormats.Length;
+ roundtripDateTimeFormats = new string [l * 2];
+ localDateTimeFormats = new string [l * 2];
+ utcDateTimeFormats = new string [l * 3];
+ unspecifiedDateTimeFormats = new string [l * 5];
+ for (int i = 0; i < l; i++) {
+ string s = defaultDateTimeFormats [i];
+ var z = s + 'Z';
+ localDateTimeFormats [i * 2] = s + (s [s.Length - 1] == 's' || s [s.Length - 1] == 'F' ? "zzz" : String.Empty);
+ localDateTimeFormats [i * 2 + 1] = z;
+ roundtripDateTimeFormats [i * 2] = s + 'K';
+ roundtripDateTimeFormats [i * 2 + 1] = z;
+ utcDateTimeFormats [i * 3] = s;
+ utcDateTimeFormats [i * 3 + 1] = z;
+ utcDateTimeFormats [i * 3 + 2] = s + "zzz";
+ unspecifiedDateTimeFormats [i * 5] = s;
+ unspecifiedDateTimeFormats [i * 5 + 1] = z;
+ unspecifiedDateTimeFormats [i * 5 + 2] = localDateTimeFormats [i];
+ unspecifiedDateTimeFormats [i * 5 + 3] = roundtripDateTimeFormats [i];
+ unspecifiedDateTimeFormats [i * 5 + 4] = utcDateTimeFormats [i];
+ }
+ }
+#endif
+ static DateTimeStyles _defaultStyle = DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite;
public XmlConvert()
{}
{
if (buffer == null)
throw new ArgumentNullException ("buffer");
- if (index < 0)
- throw new ArgumentOutOfRangeException ("index", index, "index must be non negative integer.");
- if (count < 0)
- throw new ArgumentOutOfRangeException ("count", count, "count must be non negative integer.");
+ if (index < 0) {
+ throw new ArgumentOutOfRangeException (
+#if !NET_2_1
+ "index", index,
+#endif
+ "index must be non negative integer.");
+ }
+ if (count < 0) {
+ throw new ArgumentOutOfRangeException (
+#if !NET_2_1
+ "count", count,
+#endif
+ "count must be non negative integer.");
+ }
if (buffer.Length < index + count)
throw new ArgumentOutOfRangeException ("index and count must be smaller than the length of the buffer.");
public static byte ToByte(string s)
{
- return Byte.Parse(s, CultureInfo.InvariantCulture);
+ return Byte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
}
public static char ToChar(string s)
{
+#if !NET_2_1
return Char.Parse(s);
+#else
+ if (s == null)
+ throw new ArgumentNullException ("s");
+
+ if (s.Length != 1)
+ throw new FormatException ("String contain more than one char");
+
+ return s [0];
+#endif
}
#if NET_2_0
}
#if NET_2_0
- public static DateTime ToDateTime (string value, XmlDateTimeSerializationMode mode)
+ public static DateTime ToDateTime (string s, XmlDateTimeSerializationMode dateTimeOption)
{
- string modestr = null;
- switch (mode) {
+ DateTime dt;
+ switch (dateTimeOption) {
case XmlDateTimeSerializationMode.Local:
+ dt = ToDateTime (s, localDateTimeFormats);
+ return new DateTime (dt.Ticks, DateTimeKind.Local);
case XmlDateTimeSerializationMode.RoundtripKind:
- default:
- return ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.fffffffzzz");
+ return ToDateTime (s, roundtripDateTimeFormats, _defaultStyle | DateTimeStyles.RoundtripKind);
case XmlDateTimeSerializationMode.Utc:
- return ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.fffffffZ").ToUniversalTime ();
+ dt = ToDateTime (s, utcDateTimeFormats);
+ return new DateTime (dt.Ticks, DateTimeKind.Utc);
case XmlDateTimeSerializationMode.Unspecified:
- return ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.fffffff");
+ return ToDateTime (s, unspecifiedDateTimeFormats);
+ default:
+ return ToDateTime (s, defaultDateTimeFormats);
}
}
#endif
public static DateTime ToDateTime(string s, string format)
{
- DateTimeFormatInfo d = new DateTimeFormatInfo();
- d.FullDateTimePattern = format;
- return DateTime.Parse(s, d);
+ //DateTimeFormatInfo d = new DateTimeFormatInfo();
+ //d.FullDateTimePattern = format;
+ //return DateTime.Parse(s, d);
+ DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
+ DateTimeStyles.AllowTrailingWhite;
+ return DateTime.ParseExact (s, format, DateTimeFormatInfo.InvariantInfo, style);
}
public static DateTime ToDateTime(string s, string[] formats)
{
- DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
- DateTimeStyles.AllowTrailingWhite;
- return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
+ return ToDateTime (s, formats, _defaultStyle);
+ }
+
+ private static DateTime ToDateTime (string s, string [] formats, DateTimeStyles style)
+ {
+ try {
+ return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
+ } catch (ArgumentOutOfRangeException) {
+ return DateTime.MinValue;
+ }
}
public static Decimal ToDecimal(string s)
{
if (s == null)
throw new ArgumentNullException();
- if (s == "INF")
- return Double.PositiveInfinity;
- if (s == "-INF")
- return Double.NegativeInfinity;
- if (s == "NaN")
- return Double.NaN;
+
+ float f = TryParseStringFloatConstants (s);
+ if (f != 0)
+ return f;
+
return Double.Parse (s, floatStyle, CultureInfo.InvariantCulture);
}
- public static Guid ToGuid(string s)
+ static float TryParseStringFloatConstants (string s)
{
- return new Guid(s);
+ int sidx = 0;
+ while (sidx < s.Length && Char.IsWhiteSpace (s [sidx]))
+ sidx++;
+ if (sidx == s.Length)
+ throw new FormatException ();
+ int sEndPos = s.Length - 1;
+ while (Char.IsWhiteSpace (s [sEndPos]))
+ sEndPos--;
+
+ if (TryParseStringConstant ("NaN", s, sidx, sEndPos))
+ return Single.NaN;
+ if (TryParseStringConstant ("INF", s, sidx, sEndPos))
+ return Single.PositiveInfinity;
+ if (TryParseStringConstant ("-INF", s, sidx, sEndPos))
+ return Single.NegativeInfinity;
+ // Handle these here because Single.Parse("Infinity") is invalid while XmlConvert.ToSingle("Infinity") is valid.
+ if (TryParseStringConstant ("Infinity", s, sidx, sEndPos))
+ return Single.PositiveInfinity;
+ if (TryParseStringConstant ("-Infinity", s, sidx, sEndPos))
+ return Single.NegativeInfinity;
+ return 0;
+ }
+
+ static bool TryParseStringConstant (string format, string s, int start, int end)
+ {
+ return end - start + 1 == format.Length && String.CompareOrdinal (format, 0, s, start, format.Length) == 0;
+ }
+
+ public static Guid ToGuid (string s)
+ {
+ try {
+ return new Guid(s);
+ } catch (FormatException ex) {
+ throw new FormatException (String.Format ("Invalid Guid input '{0}'", ex.InnerException));
+ }
}
public static short ToInt16(string s)
{
- return Int16.Parse(s, CultureInfo.InvariantCulture);
+ return Int16.Parse (s, integerStyle, CultureInfo.InvariantCulture);
}
public static int ToInt32(string s)
{
- return Int32.Parse(s, CultureInfo.InvariantCulture);
+ return Int32.Parse (s, integerStyle, CultureInfo.InvariantCulture);
}
public static long ToInt64(string s)
{
- return Int64.Parse(s, CultureInfo.InvariantCulture);
+ return Int64.Parse (s, integerStyle, CultureInfo.InvariantCulture);
}
[CLSCompliant (false)]
public static SByte ToSByte(string s)
{
- return SByte.Parse(s, CultureInfo.InvariantCulture);
+ return SByte.Parse(s, integerStyle, CultureInfo.InvariantCulture);
}
public static float ToSingle(string s)
{
if (s == null)
throw new ArgumentNullException();
- if (s == "INF")
- return Single.PositiveInfinity;
- if (s == "-INF")
- return Single.NegativeInfinity;
- if (s == "NaN")
- return Single.NaN;
+
+ float f = TryParseStringFloatConstants (s);
+ if (f != 0)
+ return f;
+
return Single.Parse(s, floatStyle, CultureInfo.InvariantCulture);
}
StringBuilder builder = new StringBuilder ();
if (value.Ticks < 0) {
+ if (value == TimeSpan.MinValue)
+ return "-P10675199DT2H48M5.4775808S"; // There's one fewer tick on the positive side, so we cannot Negate this value; just hard-code it
builder.Append ('-');
value = value.Negate ();
}
builder.Append ('P');
if (value.Days > 0)
builder.Append (value.Days).Append ('D');
- if (value.Days > 0 || value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
+ long ticks = value.Ticks % TimeSpan.TicksPerMillisecond;
+ if (value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0 || ticks > 0) {
builder.Append('T');
if (value.Hours > 0)
builder.Append (value.Hours).Append ('H');
if (value.Minutes > 0)
builder.Append (value.Minutes).Append ('M');
- if (value.Seconds > 0 || value.Milliseconds > 0) {
+ if (value.Seconds > 0 || value.Milliseconds > 0 || ticks > 0) {
builder.Append (value.Seconds);
- long ticks = value.Ticks % TimeSpan.TicksPerMillisecond;
+ bool trimZero = true;
if (ticks > 0)
builder.Append ('.').AppendFormat ("{0:0000000}", value.Ticks % TimeSpan.TicksPerSecond);
else if (value.Milliseconds > 0)
builder.Append ('.').AppendFormat ("{0:000}", value.Milliseconds);
+ else
+ trimZero = false;
+ if (trimZero)
+ while (builder [builder.Length - 1] == '0')
+ builder.Remove (builder.Length - 1, 1);
builder.Append ('S');
}
if (Double.IsNegativeInfinity(value)) return "-INF";
if (Double.IsPositiveInfinity(value)) return "INF";
if (Double.IsNaN(value)) return "NaN";
-#if TARGET_JVM
- return value.ToString("R", NumberFormatInfo.InvariantInfo);
-#else
- return value.ToString(CultureInfo.InvariantCulture);
-#endif
+ return value.ToString("R", CultureInfo.InvariantCulture);
}
public static string ToString(float value)
if (Single.IsNegativeInfinity(value)) return "-INF";
if (Single.IsPositiveInfinity(value)) return "INF";
if (Single.IsNaN(value)) return "NaN";
-#if TARGET_JVM
- return value.ToString("R", NumberFormatInfo.InvariantInfo);
-#else
- return value.ToString(CultureInfo.InvariantCulture);
-#endif
+ return value.ToString("R", CultureInfo.InvariantCulture);
}
[CLSCompliant (false)]
}
#if NET_2_0
- public static string ToString (DateTime value, XmlDateTimeSerializationMode mode)
+ public static string ToString (DateTime value, XmlDateTimeSerializationMode dateTimeOption)
{
- string modestr = null;
- switch (mode) {
+ // Unlike usual DateTime formatting, it preserves
+ // MaxValue/MinValue as is.
+ switch (dateTimeOption) {
case XmlDateTimeSerializationMode.Local:
+ return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToLocalTime ()).ToString (
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
+ CultureInfo.InvariantCulture);
case XmlDateTimeSerializationMode.RoundtripKind:
+ return value.ToString (
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
+ CultureInfo.InvariantCulture);
default:
return value.ToString (
- "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
CultureInfo.InvariantCulture);
- break;
case XmlDateTimeSerializationMode.Utc:
- return value.ToUniversalTime ().ToString (
- "yyyy-MM-ddTHH:mm:ss.fffffffZ",
+ return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToUniversalTime ()).ToString (
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",
CultureInfo.InvariantCulture);
- break;
case XmlDateTimeSerializationMode.Unspecified:
return value.ToString (
- "yyyy-MM-ddTHH:mm:ss.fffffff",
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
CultureInfo.InvariantCulture);
- break;
}
}
#endif
public static TimeSpan ToTimeSpan(string s)
{
+ s = s.Trim (XmlChar.WhitespaceChars);
if (s.Length == 0)
- throw new ArgumentException ("Invalid format string for duration schema datatype.");
+ throw new FormatException ("Invalid format string for duration schema datatype.");
int start = 0;
if (s [0] == '-')
bool minusValue = (start == 1);
if (s [start] != 'P')
- throw new ArgumentException ("Invalid format string for duration schema datatype.");
+ throw new FormatException ("Invalid format string for duration schema datatype.");
start++;
int parseStep = 0;
start = i;
}
if (error)
- throw new ArgumentException ("Invalid format string for duration schema datatype.");
+ throw new FormatException ("Invalid format string for duration schema datatype.");
TimeSpan ts = new TimeSpan (days, hours, minutes, seconds);
if (minusValue)
return TimeSpan.FromTicks (- (ts.Ticks + ticks));
[CLSCompliant (false)]
public static UInt16 ToUInt16(string s)
{
- return UInt16.Parse(s, CultureInfo.InvariantCulture);
+ return UInt16.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
}
[CLSCompliant (false)]
public static UInt32 ToUInt32(string s)
{
- return UInt32.Parse(s, CultureInfo.InvariantCulture);
+ return UInt32.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
}
[CLSCompliant (false)]
public static UInt64 ToUInt64(string s)
{
- return UInt64.Parse(s, CultureInfo.InvariantCulture);
+ return UInt64.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
}
public static string VerifyName (string name)
}
- public static string VerifyNCName (string ncname)
+ public static string VerifyNCName (string name)
{
- if (ncname == null || ncname.Length == 0)
- throw new ArgumentNullException("ncname");
+ if (name == null || name.Length == 0)
+ throw new ArgumentNullException("name");
- if (!XmlChar.IsNCName (ncname))
- throw new XmlException ("'" + ncname + "' is not a valid XML NCName");
- return ncname;
+ if (!XmlChar.IsNCName (name))
+ throw new XmlException ("'" + name + "' is not a valid XML NCName");
+ return name;
}
-#if NET_2_0
- public static string VerifyTOKEN (string name)
-#else
- internal static string VerifyTOKEN (string name)
-#endif
+ public static string VerifyTOKEN (string token)
{
- if (name == null)
- throw new ArgumentNullException("name");
+ if (token == null)
+ throw new ArgumentNullException("token");
- if (name.Length == 0)
- return name;
+ if (token.Length == 0)
+ return token;
- if (XmlChar.IsWhitespace (name [0]) ||
- XmlChar.IsWhitespace (name [name.Length - 1]))
+ if (XmlChar.IsWhitespace (token [0]) ||
+ XmlChar.IsWhitespace (token [token.Length - 1]))
throw new XmlException ("Whitespace characters (#xA, #xD, #x9, #x20) are not allowed as leading or trailing whitespaces of xs:token.");
- for (int i = 0; i < name.Length; i++)
- if (XmlChar.IsWhitespace (name [i]) && name [i] != ' ')
- throw new XmlException ("Either #xA, #xD or #x9 are not allowed inside xs:token.");
+ for (int i = 0; i < token.Length; i++)
+ if (XmlChar.IsWhitespace (token [i]) && token [i] != ' ')
+ throw new XmlException ("Either #xA, #xD or #x9 are not allowed inside xs:token.");
- return name;
+ return token;
}
#if NET_2_0
return bufIndex - offset;
}
+
+#if NET_2_0 // actually NET_3_5
+#if !TARGET_JVM
+
+ public static DateTimeOffset ToDateTimeOffset (string s)
+ {
+ return ToDateTimeOffset (s, datetimeFormats);
+ }
+
+ public static DateTimeOffset ToDateTimeOffset (string s, string format)
+ {
+ return DateTimeOffset.ParseExact (s, format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
+ }
+
+ public static DateTimeOffset ToDateTimeOffset (string s, string [] formats)
+ {
+ DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
+ DateTimeStyles.AllowTrailingWhite |
+ DateTimeStyles.AssumeUniversal;
+ return DateTimeOffset.ParseExact (s, formats, CultureInfo.InvariantCulture, style);
+ }
+
+ public static string ToString (DateTimeOffset value)
+ {
+ return ToString (value, "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz");
+ }
+
+ public static string ToString (DateTimeOffset value, string format)
+ {
+ return value.ToString (format, CultureInfo.InvariantCulture);
+ }
+#endif
+
+ // it is used only from 2.1 System.Xml.Serialization.dll from
+ // MS Silverlight SDK. We don't use it so far.
+ internal static Uri ToUri (string s)
+ {
+ return new Uri (s, UriKind.RelativeOrAbsolute);
+ }
+
+#endif
+
+#if NET_4_0 || NET_2_1
+ public static bool IsNCNameChar (char ch)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static bool IsPublicIdChar (char ch)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static bool IsStartNCNameChar (char ch)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static bool IsWhitespaceChar (char ch)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static bool IsXmlChar (char ch)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static bool IsXmlSurrogatePair (char lowChar, char highChar)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static string VerifyPublicId (string publicId)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static string VerifyWhitespace (string content)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static string VerifyXmlChars (string content)
+ {
+ throw new NotImplementedException ();
+ }
+#endif
}
}