// Authors:
// Duco Fijma (duco@lorentz.xs4all.nl)
// Sebastien Pouliot (sebastien@ximian.com)
+// Jb Evain (jbevain@novell.com)
+// Marek Safar (marek.safar@gmail.com)
//
// (C) 2002 Duco Fijma
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2010 Novell, Inc (http://www.novell.com)
+// Copyright 2012 Xamarin, Inc (http://www.xamarin.com)
//
// References
// 1. UUIDs and GUIDs (DRAFT), Section 3.4
[Serializable]
[StructLayout (LayoutKind.Sequential)]
-#if NET_2_0
[ComVisible (true)]
public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
-#else
- public struct Guid : IFormattable, IComparable {
+#if MONOTOUCH
+ static Guid () {
+ if (MonoTouchAOTHelper.FalseFlag) {
+ var comparer = new System.Collections.Generic.GenericComparer <Guid> ();
+ var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <Guid> ();
+ }
+ }
#endif
private int _a; //_timeLow;
private short _b; //_timeMid;
private byte _j; //_node4;
private byte _k; //_node5;
- internal class GuidParser
- {
+ enum Format {
+ N, // 00000000000000000000000000000000
+ D, // 00000000-0000-0000-0000-000000000000
+ B, // {00000000-0000-0000-0000-000000000000}
+ P, // (00000000-0000-0000-0000-000000000000)
+ X, // {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+ }
+
+ class GuidParser {
+
private string _src;
private int _length;
private int _cur;
Reset ();
}
- private void Reset ()
+ void Reset ()
{
_cur = 0;
_length = _src.Length;
}
- private bool AtEnd ()
- {
- return _cur >= _length;
+ bool Eof {
+ get { return _cur >= _length; }
}
- private void ThrowFormatException ()
+ public static bool HasHyphen (Format format)
{
- throw new FormatException (Locale.GetText ("Invalid format for Guid.Guid(string)."));
+ switch (format) {
+ case Format.D:
+ case Format.B:
+ case Format.P:
+ return true;
+ default:
+ return false;
+ }
}
- private ulong ParseHex(int length, bool strictLength)
+ bool TryParseNDBP (Format format, out Guid guid)
{
- ulong res = 0;
- int i;
- bool end = false;
-
- for (i=0; (!end) && i<length; ++i) {
- if (AtEnd ()) {
- if (strictLength || i==0) {
- ThrowFormatException ();
- }
- else {
- end = true;
- }
- }
- else {
- char c = Char.ToLowerInvariant (_src[_cur]);
- if (Char.IsDigit (c)) {
- res = res * 16 + c - '0';
- _cur++;
- }
- else if (c >= 'a' && c <= 'f') {
- res = res * 16 + c - 'a' + 10;
- _cur++;
- }
- else {
- if (strictLength || i==0) {
- ThrowFormatException ();
- }
- else {
- end = true;
- }
- }
- }
+ ulong a, b, c;
+ guid = new Guid ();
+
+ if (format == Format.B && !ParseChar ('{'))
+ return false;
+
+ if (format == Format.P && !ParseChar ('('))
+ return false;
+
+ if (!ParseHex (8, true, out a))
+ return false;
+
+ var has_hyphen = HasHyphen (format);
+
+ if (has_hyphen && !ParseChar ('-'))
+ return false;
+
+ if (!ParseHex (4, true, out b))
+ return false;
+
+ if (has_hyphen && !ParseChar ('-'))
+ return false;
+
+ if (!ParseHex (4, true, out c))
+ return false;
+
+ if (has_hyphen && !ParseChar ('-'))
+ return false;
+
+ var d = new byte [8];
+ for (int i = 0; i < d.Length; i++) {
+ ulong dd;
+ if (!ParseHex (2, true, out dd))
+ return false;
+
+ if (i == 1 && has_hyphen && !ParseChar ('-'))
+ return false;
+
+ d [i] = (byte) dd;
}
- return res;
+
+ if (format == Format.B && !ParseChar ('}'))
+ return false;
+
+ if (format == Format.P && !ParseChar (')'))
+ return false;
+
+ if (!Eof)
+ return false;
+
+ guid = new Guid ((int) a, (short) b, (short) c, d);
+ return true;
}
- private bool ParseOptChar (char c)
+ bool TryParseX (out Guid guid)
{
- if (!AtEnd() && _src[_cur] == c) {
- _cur++;
- return true;
- }
- else {
+ ulong a, b, c;
+ guid = new Guid ();
+
+ if (!(ParseChar ('{')
+ && ParseHexPrefix ()
+ && ParseHex (8, false, out a)
+ && ParseChar (',')
+ && ParseHexPrefix ()
+ && ParseHex (4, false, out b)
+ && ParseChar (',')
+ && ParseHexPrefix ()
+ && ParseHex (4, false, out c)
+ && ParseChar (',')
+ && ParseChar ('{'))) {
+
return false;
}
- }
- private void ParseChar (char c)
- {
- bool b = ParseOptChar (c);
- if (!b) {
- ThrowFormatException ();
+ var d = new byte [8];
+ for (int i = 0; i < d.Length; ++i) {
+ ulong dd;
+
+ if (!(ParseHexPrefix () && ParseHex (2, false, out dd)))
+ return false;
+
+ d [i] = (byte) dd;
+
+ if (i != 7 && !ParseChar (','))
+ return false;
}
+
+ if (!(ParseChar ('}') && ParseChar ('}')))
+ return false;
+
+ if (!Eof)
+ return false;
+
+ guid = new Guid ((int) a, (short) b, (short) c, d);
+ return true;
}
- private Guid ParseGuid1 ()
+ bool ParseHexPrefix ()
{
- bool openBrace;
- bool groups = true;
- char endChar = '}';
- int a;
- short b;
- short c;
- byte[] d = new byte[8];
- int i;
-
- openBrace = ParseOptChar ('{');
- if (!openBrace) {
- openBrace = ParseOptChar ('(');
- if (openBrace) endChar = ')';
- }
-
- a = (int) ParseHex(8, true);
-
- if (openBrace) ParseChar('-');
- else groups = ParseOptChar('-');
-
- b = (short) ParseHex(4, true);
- if (groups) ParseChar('-');
-
- c = (short) ParseHex(4, true);
- if (groups) ParseChar('-');
-
- for (i=0; i<8; ++i) {
- d[i] = (byte) ParseHex(2, true);
- if (i == 1 && groups) {
- ParseChar('-');
- }
- }
-
- if (openBrace && !ParseOptChar(endChar)) {
- ThrowFormatException ();
- }
-
- return new Guid(a, b, c, d);
+ if (!ParseChar ('0'))
+ return false;
+
+ return ParseChar ('x');
}
- private void ParseHexPrefix ()
+ bool ParseChar (char c)
{
- ParseChar ('0');
- ParseChar ('x');
+ if (!Eof && _src [_cur] == c) {
+ _cur++;
+ return true;
+ }
+
+ return false;
}
- private Guid ParseGuid2 ()
+ bool ParseHex (int length, bool strict, out ulong res)
{
- int a;
- short b;
- short c;
- byte[] d = new byte [8];
- int i;
-
- ParseChar ('{');
- ParseHexPrefix ();
- a = (int) ParseHex (8, false);
- ParseChar (',');
- ParseHexPrefix ();
- b = (short) ParseHex (4, false);
- ParseChar (',');
- ParseHexPrefix ();
- c = (short) ParseHex (4, false);
- ParseChar (',');
- ParseChar ('{');
- for (i=0; i<8; ++i) {
- ParseHexPrefix ();
- d[i] = (byte) ParseHex (2, false);
- if (i != 7) {
- ParseChar (',');
+ res = 0;
+
+ for (int i = 0; i < length; i++) {
+ if (Eof)
+ return !(strict && (i + 1 != length));
+
+ char c = Char.ToLowerInvariant (_src[_cur]);
+ if (Char.IsDigit (c)) {
+ res = res * 16 + c - '0';
+ _cur++;
+ } else if (c >= 'a' && c <= 'f') {
+ res = res * 16 + c - 'a' + 10;
+ _cur++;
+ } else {
+ if (!strict)
+ return true;
+
+ return !(strict && (i + 1 != length));
}
}
- ParseChar ('}');
- ParseChar ('}');
- return new Guid (a,b,c,d);
-
+ return true;
}
- public Guid Parse ()
+ public bool Parse (Format format, out Guid guid)
{
- Guid g;
+ if (format == Format.X)
+ return TryParseX (out guid);
- try {
- g = ParseGuid1 ();
- }
- catch (FormatException) {
- Reset ();
- g = ParseGuid2 ();
- }
- if (!AtEnd () ) {
- ThrowFormatException ();
- }
- return g;
+ return TryParseNDBP (format, out guid);
+ }
+
+ public bool Parse (out Guid guid)
+ {
+ if (TryParseNDBP (Format.N, out guid))
+ return true;
+
+ Reset ();
+ if (TryParseNDBP (Format.D, out guid))
+ return true;
+
+ Reset ();
+ if (TryParseNDBP (Format.B, out guid))
+ return true;
+
+ Reset ();
+ if (TryParseNDBP (Format.P, out guid))
+ return true;
+
+ Reset ();
+ return TryParseX (out guid);
}
}
public Guid (string g)
{
CheckNull (g);
-
- GuidParser p = new GuidParser (g);
- Guid guid = p.Parse();
-
+ g = g.Trim();
+ var parser = new GuidParser (g);
+ Guid guid;
+ if (!parser.Parse (out guid))
+ throw CreateFormatException (g);
+
this = guid;
}
+ static Exception CreateFormatException (string s)
+ {
+ return new FormatException (string.Format ("Invalid Guid format: {0}", s));
+ }
+
public Guid (int a, short b, short c, byte[] d)
{
CheckArray (d, 8);
private static int Compare (int x, int y)
{
- if (x < y) {
- return -1;
- }
- else {
- return 1;
- }
+ return ((uint)x < (uint)y) ? -1 : 1;
}
public int CompareTo (object value)
return false;
}
-#if NET_2_0
public int CompareTo (Guid value)
-#else
- internal int CompareTo (Guid value)
-#endif
{
if (_a != value._a) {
return Compare (_a, value._a);
}
- else if (_b != value._b) {
+ if (_b != value._b) {
return Compare (_b, value._b);
}
- else if (_c != value._c) {
+ if (_c != value._c) {
return Compare (_c, value._c);
}
- else if (_d != value._d) {
+ if (_d != value._d) {
return Compare (_d, value._d);
}
- else if (_e != value._e) {
+ if (_e != value._e) {
return Compare (_e, value._e);
}
- else if (_f != value._f) {
+ if (_f != value._f) {
return Compare (_f, value._f);
}
- else if (_g != value._g) {
+ if (_g != value._g) {
return Compare (_g, value._g);
}
- else if (_h != value._h) {
+ if (_h != value._h) {
return Compare (_h, value._h);
}
- else if (_i != value._i) {
+ if (_i != value._i) {
return Compare (_i, value._i);
}
- else if (_j != value._j) {
+ if (_j != value._j) {
return Compare (_j, value._j);
}
- else if (_k != value._k) {
+ if (_k != value._k) {
return Compare (_k, value._k);
}
return 0;
}
-#if NET_2_0
public bool Equals (Guid g)
{
return CompareTo (g) == 0;
}
-#endif
public override int GetHashCode ()
{
}
private static object _rngAccess = new object ();
+#if !FULL_AOT_RUNTIME
private static RandomNumberGenerator _rng;
private static RandomNumberGenerator _fastRng;
+#else
+ private static object _fastRng;
+#endif
// generated as per section 3.4 of the specification
public static Guid NewGuid ()
{
+#if !FULL_AOT_RUNTIME
byte[] b = new byte [16];
// thread-safe access to the prng
_rng = RandomNumberGenerator.Create ();
_rng.GetBytes (b);
}
+#else
+ byte[] b = FastNewGuidArray ();
+#endif
+
Guid res = new Guid (b);
// Mask in Variant 1-0 in Bit[7..6]
// thread-safe access to the prng
lock (_rngAccess) {
// if known, use preferred RNG
+#if FULL_AOT_RUNTIME
+ if (_fastRng == null)
+ _fastRng = new RNGCryptoServiceProvider ();
+ (_fastRng as RNGCryptoServiceProvider).GetBytes (guid);
+#else
if (_rng != null)
_fastRng = _rng;
// else use hardcoded default RNG (bypassing CryptoConfig)
if (_fastRng == null)
_fastRng = new RNGCryptoServiceProvider ();
_fastRng.GetBytes (guid);
+#endif
}
// Mask in Variant 1-0 in Bit[7..6]
return res;
}
- private string BaseToString (bool h, bool p, bool b)
+ static void AppendInt (StringBuilder builder, int value) {
+ builder.Append (ToHex ((value >> 28) & 0xf));
+ builder.Append (ToHex ((value >> 24) & 0xf));
+ builder.Append (ToHex ((value >> 20) & 0xf));
+ builder.Append (ToHex ((value >> 16) & 0xf));
+ builder.Append (ToHex ((value >> 12) & 0xf));
+ builder.Append (ToHex ((value >> 8) & 0xf));
+ builder.Append (ToHex ((value >> 4) & 0xf));
+ builder.Append (ToHex (value & 0xf));
+ }
+
+ static void AppendShort (StringBuilder builder, short value) {
+ builder.Append (ToHex ((value >> 12) & 0xf));
+ builder.Append (ToHex ((value >> 8) & 0xf));
+ builder.Append (ToHex ((value >> 4) & 0xf));
+ builder.Append (ToHex (value & 0xf));
+ }
+
+ static void AppendByte (StringBuilder builder, byte value) {
+ builder.Append (ToHex ((value >> 4) & 0xf));
+ builder.Append (ToHex (value & 0xf));
+ }
+
+ string ToString (Format format)
{
- StringBuilder res = new StringBuilder (40);
+ int length;
+ switch (format) {
+ case Format.B:
+ case Format.P:
+ length = 38;
+ break;
+ case Format.D:
+ length = 36;
+ break;
+ case Format.N:
+ length = 32;
+ break;
+ case Format.X:
+ length = 68;
+ break;
+ default:
+ throw new NotImplementedException (format.ToString ());
+ }
+
+ StringBuilder res = new StringBuilder (length);
+ bool has_hyphen = GuidParser.HasHyphen (format);
- if (p) {
+ if (format == Format.P) {
res.Append ('(');
- } else if (b) {
+ } else if (format == Format.B) {
res.Append ('{');
+ } else if (format == Format.X) {
+ res.Append ('{').Append ('0').Append ('x');
}
- res.Append (_a.ToString ("x8"));
- if (h) {
+ AppendInt (res, _a);
+ if (has_hyphen) {
res.Append ('-');
+ } else if (format == Format.X) {
+ res.Append (',').Append ('0').Append ('x');
}
- res.Append (_b.ToString ("x4"));
- if (h) {
- res.Append ('-');
- }
- res.Append (_c.ToString ("x4"));
- if (h) {
+
+ AppendShort (res, _b);
+ if (has_hyphen) {
res.Append ('-');
+ } else if (format == Format.X) {
+ res.Append (',').Append ('0').Append ('x');
}
-
- char[] vals1 = {
- ToHex((_d >> 4) & 0xf),
- ToHex(_d & 0xf),
- ToHex((_e >> 4) & 0xf),
- ToHex(_e & 0xf)
- };
-
- res.Append (vals1);
- if (h) {
+ AppendShort (res, _c);
+ if (has_hyphen) {
res.Append ('-');
}
-
- char[] vals2 = {
- ToHex((_f >> 4) & 0xf),
- ToHex(_f & 0xf),
- ToHex((_g >> 4) & 0xf),
- ToHex(_g & 0xf),
- ToHex((_h >> 4) & 0xf),
- ToHex(_h & 0xf),
- ToHex((_i >> 4) & 0xf),
- ToHex(_i & 0xf),
- ToHex((_j >> 4) & 0xf),
- ToHex(_j & 0xf),
- ToHex((_k >> 4) & 0xf),
- ToHex(_k & 0xf)
- };
- res.Append (vals2);
+ if (format == Format.X) {
+ res.Append (',').Append ('{').Append ('0').Append ('x');
+ AppendByte (res, _d);
+ res.Append (',').Append ('0').Append ('x');
+ AppendByte (res, _e);
+ res.Append (',').Append ('0').Append ('x');
+ AppendByte (res, _f);
+ res.Append (',').Append ('0').Append ('x');
+ AppendByte (res, _g);
+ res.Append (',').Append ('0').Append ('x');
+ AppendByte (res, _h);
+ res.Append (',').Append ('0').Append ('x');
+ AppendByte (res, _i);
+ res.Append (',').Append ('0').Append ('x');
+ AppendByte (res, _j);
+ res.Append (',').Append ('0').Append ('x');
+ AppendByte (res, _k);
+ res.Append ('}').Append ('}');;
+ } else {
+ AppendByte (res, _d);
+ AppendByte (res, _e);
+
+ if (has_hyphen) {
+ res.Append ('-');
+ }
- if (p) {
- res.Append (')');
- } else if (b) {
- res.Append ('}');
+ AppendByte (res, _f);
+ AppendByte (res, _g);
+ AppendByte (res, _h);
+ AppendByte (res, _i);
+ AppendByte (res, _j);
+ AppendByte (res, _k);
+
+ if (format == Format.P) {
+ res.Append (')');
+ } else if (format == Format.B) {
+ res.Append ('}');
+ }
}
return res.ToString ();
public override string ToString ()
{
- return BaseToString (true, false, false);
+ return ToString (Format.D);
}
public string ToString (string format)
{
- bool h = true;
- bool p = false;
- bool b = false;
-
- if (format != null) {
- string f = format.ToLowerInvariant();
-
- if (f == "b") {
- b = true;
- }
- else if (f == "p") {
- p = true;
- }
- else if (f == "n") {
- h = false;
- }
- else if (f != "d" && f != String.Empty) {
- throw new FormatException (Locale.GetText (
- "Argument to Guid.ToString(string format) should be \"b\", \"B\", \"d\", \"D\", \"n\", \"N\", \"p\" or \"P\""));
- }
- }
-
- return BaseToString (h, p, b);
+ return ToString (ParseFormat (format));
}
+ // provider value is never used
public string ToString (string format, IFormatProvider provider)
{
return ToString (format);
{
return !( a.Equals (b) );
}
+
+#if NET_4_0 || MOONLIGHT || MOBILE
+ public static Guid Parse (string input)
+ {
+ if (input == null)
+ throw new ArgumentNullException ("input");
+
+ Guid guid;
+ if (!TryParse (input, out guid))
+ throw CreateFormatException (input);
+
+ return guid;
+ }
+
+ public static Guid ParseExact (string input, string format)
+ {
+ if (input == null)
+ throw new ArgumentNullException ("input");
+ if (format == null)
+ throw new ArgumentNullException ("format");
+
+ Guid guid;
+ if (!TryParseExact (input, format, out guid))
+ throw CreateFormatException (input);
+
+ return guid;
+ }
+
+ public static bool TryParse (string input, out Guid result)
+ {
+ if (input == null) {
+ result = Empty;
+ return false;
+ }
+
+ var parser = new GuidParser (input);
+ return parser.Parse (out result);
+ }
+
+ public static bool TryParseExact (string input, string format, out Guid result)
+ {
+ if (input == null || format == null) {
+ result = Empty;
+ return false;
+ }
+
+ var parser = new GuidParser (input);
+ return parser.Parse (ParseFormat (format), out result);
+ }
+#endif
+
+ static Format ParseFormat (string format)
+ {
+ if (string.IsNullOrEmpty (format))
+ return Format.D;
+
+ switch (format [0]) {
+ case 'N':
+ case 'n':
+ return Format.N;
+ case 'D':
+ case 'd':
+ return Format.D;
+ case 'B':
+ case 'b':
+ return Format.B;
+ case 'P':
+ case 'p':
+ return Format.P;
+#if NET_4_0 || MOONLIGHT || MOBILE
+ case 'X':
+ case 'x':
+ return Format.X;
+#endif
+ }
+
+ throw new FormatException (
+#if NET_4_0 || MOONLIGHT || MOBILE
+ "Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\""
+#else
+ "Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\" or \"b\""
+#endif
+ );
+ }
}
}