5 // Duco Fijma (duco@lorentz.xs4all.nl)
6 // Sebastien Pouliot (sebastien@ximian.com)
7 // Jb Evain (jbevain@novell.com)
10 // Copyright (C) 2004-2010 Novell, Inc (http://www.novell.com)
13 // 1. UUIDs and GUIDs (DRAFT), Section 3.4
14 // http://www.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01.txt
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Runtime.InteropServices;
37 using System.Security.Cryptography;
43 [StructLayout (LayoutKind.Sequential)]
45 public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
48 if (MonoTouchAOTHelper.FalseFlag) {
49 var comparer = new System.Collections.Generic.GenericComparer <Guid> ();
50 var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <Guid> ();
54 private int _a; //_timeLow;
55 private short _b; //_timeMid;
56 private short _c; //_timeHighAndVersion;
57 private byte _d; //_clockSeqHiAndReserved;
58 private byte _e; //_clockSeqLow;
59 private byte _f; //_node0;
60 private byte _g; //_node1;
61 private byte _h; //_node2;
62 private byte _i; //_node3;
63 private byte _j; //_node4;
64 private byte _k; //_node5;
67 N, // 00000000000000000000000000000000
68 D, // 00000000-0000-0000-0000-000000000000
69 B, // {00000000-0000-0000-0000-000000000000}
70 P, // (00000000-0000-0000-0000-000000000000)
71 X, // {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
80 public GuidParser (string src)
89 _length = _src.Length;
93 get { return _cur >= _length; }
96 static bool HasHyphen (Format format)
108 bool TryParseNDBP (Format format, out Guid guid)
113 if (format == Format.B && !ParseChar ('{'))
116 if (format == Format.P && !ParseChar ('('))
119 if (!ParseHex (8, true, out a))
122 var has_hyphen = HasHyphen (format);
124 if (has_hyphen && !ParseChar ('-'))
127 if (!ParseHex (4, true, out b))
130 if (has_hyphen && !ParseChar ('-'))
133 if (!ParseHex (4, true, out c))
136 if (has_hyphen && !ParseChar ('-'))
139 var d = new byte [8];
140 for (int i = 0; i < d.Length; i++) {
142 if (!ParseHex (2, true, out dd))
145 if (i == 1 && has_hyphen && !ParseChar ('-'))
151 if (format == Format.B && !ParseChar ('}'))
154 if (format == Format.P && !ParseChar (')'))
160 guid = new Guid ((int) a, (short) b, (short) c, d);
164 bool TryParseX (out Guid guid)
169 if (!(ParseChar ('{')
171 && ParseHex (8, false, out a)
174 && ParseHex (4, false, out b)
177 && ParseHex (4, false, out c)
179 && ParseChar ('{'))) {
184 var d = new byte [8];
185 for (int i = 0; i < d.Length; ++i) {
188 if (!(ParseHexPrefix () && ParseHex (2, false, out dd)))
193 if (i != 7 && !ParseChar (','))
197 if (!(ParseChar ('}') && ParseChar ('}')))
203 guid = new Guid ((int) a, (short) b, (short) c, d);
207 bool ParseHexPrefix ()
209 if (!ParseChar ('0'))
212 return ParseChar ('x');
215 bool ParseChar (char c)
217 if (!Eof && _src [_cur] == c) {
225 bool ParseHex (int length, bool strict, out ulong res)
229 for (int i = 0; i < length; i++) {
231 return !(strict && (i + 1 != length));
233 char c = Char.ToLowerInvariant (_src[_cur]);
234 if (Char.IsDigit (c)) {
235 res = res * 16 + c - '0';
237 } else if (c >= 'a' && c <= 'f') {
238 res = res * 16 + c - 'a' + 10;
244 return !(strict && (i + 1 != length));
251 public bool Parse (Format format, out Guid guid)
253 if (format == Format.X)
254 return TryParseX (out guid);
256 return TryParseNDBP (format, out guid);
259 public bool Parse (out Guid guid)
261 if (TryParseNDBP (Format.N, out guid))
265 if (TryParseNDBP (Format.D, out guid))
269 if (TryParseNDBP (Format.B, out guid))
273 if (TryParseNDBP (Format.P, out guid))
277 return TryParseX (out guid);
281 private static void CheckNull (object o)
284 throw new ArgumentNullException (Locale.GetText ("Value cannot be null."));
288 private static void CheckLength (byte[] o, int l)
290 if (o . Length != l) {
291 throw new ArgumentException (String.Format (Locale.GetText ("Array should be exactly {0} bytes long."), l));
295 private static void CheckArray (byte[] o, int l)
301 public Guid (byte[] b)
304 _a = Mono.Security.BitConverterLE.ToInt32 (b, 0);
305 _b = Mono.Security.BitConverterLE.ToInt16 (b, 4);
306 _c = Mono.Security.BitConverterLE.ToInt16 (b, 6);
317 public Guid (string g)
321 var parser = new GuidParser (g);
323 if (!parser.Parse (out guid))
324 throw CreateFormatException (g);
329 static Exception CreateFormatException (string s)
331 return new FormatException (string.Format ("Invalid Guid format: {0}", s));
334 public Guid (int a, short b, short c, byte[] d)
350 public Guid (int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
365 [CLSCompliant (false)]
366 public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
367 : this((int) a, (short) b, (short) c, d, e, f, g, h, i, j, k)
371 public static readonly Guid Empty = new Guid (0,0,0,0,0,0,0,0,0,0,0);
373 private static int Compare (int x, int y)
383 public int CompareTo (object value)
388 if (!(value is Guid)) {
389 throw new ArgumentException ("value", Locale.GetText (
390 "Argument of System.Guid.CompareTo should be a Guid."));
393 return CompareTo ((Guid)value);
396 public override bool Equals (object o)
399 return CompareTo ((Guid)o) == 0;
403 public int CompareTo (Guid value)
405 if (_a != value._a) {
406 return Compare (_a, value._a);
408 else if (_b != value._b) {
409 return Compare (_b, value._b);
411 else if (_c != value._c) {
412 return Compare (_c, value._c);
414 else if (_d != value._d) {
415 return Compare (_d, value._d);
417 else if (_e != value._e) {
418 return Compare (_e, value._e);
420 else if (_f != value._f) {
421 return Compare (_f, value._f);
423 else if (_g != value._g) {
424 return Compare (_g, value._g);
426 else if (_h != value._h) {
427 return Compare (_h, value._h);
429 else if (_i != value._i) {
430 return Compare (_i, value._i);
432 else if (_j != value._j) {
433 return Compare (_j, value._j);
435 else if (_k != value._k) {
436 return Compare (_k, value._k);
441 public bool Equals (Guid g)
443 return CompareTo (g) == 0;
446 public override int GetHashCode ()
451 res = res ^ ((int) _b << 16 | _c);
452 res = res ^ ((int) _d << 24);
453 res = res ^ ((int) _e << 16);
454 res = res ^ ((int) _f << 8);
455 res = res ^ ((int) _g);
456 res = res ^ ((int) _h << 24);
457 res = res ^ ((int) _i << 16);
458 res = res ^ ((int) _j << 8);
459 res = res ^ ((int) _k);
464 private static char ToHex (int b)
466 return (char)((b<0xA)?('0' + b):('a' + b - 0xA));
469 private static object _rngAccess = new object ();
470 private static RandomNumberGenerator _rng;
471 private static RandomNumberGenerator _fastRng;
473 // generated as per section 3.4 of the specification
474 public static Guid NewGuid ()
476 byte[] b = new byte [16];
478 // thread-safe access to the prng
481 _rng = RandomNumberGenerator.Create ();
485 Guid res = new Guid (b);
486 // Mask in Variant 1-0 in Bit[7..6]
487 res._d = (byte) ((res._d & 0x3fu) | 0x80u);
488 // Mask in Version 4 (random based Guid) in Bits[15..13]
489 res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
494 // used in ModuleBuilder so mcs doesn't need to invoke
495 // CryptoConfig for simple assemblies.
496 internal static byte[] FastNewGuidArray ()
498 byte[] guid = new byte [16];
500 // thread-safe access to the prng
502 // if known, use preferred RNG
505 // else use hardcoded default RNG (bypassing CryptoConfig)
506 if (_fastRng == null)
507 _fastRng = new RNGCryptoServiceProvider ();
508 _fastRng.GetBytes (guid);
511 // Mask in Variant 1-0 in Bit[7..6]
512 guid [8] = (byte) ((guid [8] & 0x3f) | 0x80);
513 // Mask in Version 4 (random based Guid) in Bits[15..13]
514 guid [7] = (byte) ((guid [7] & 0x0f) | 0x40);
519 public byte[] ToByteArray ()
521 byte[] res = new byte[16];
526 tmp = Mono.Security.BitConverterLE.GetBytes(_a);
527 for (s=0; s<4; ++s) {
531 tmp = Mono.Security.BitConverterLE.GetBytes(_b);
532 for (s=0; s<2; ++s) {
536 tmp = Mono.Security.BitConverterLE.GetBytes(_c);
537 for (s=0; s<2; ++s) {
553 static void AppendInt (StringBuilder builder, int value) {
554 builder.Append (ToHex ((value >> 28) & 0xf));
555 builder.Append (ToHex ((value >> 24) & 0xf));
556 builder.Append (ToHex ((value >> 20) & 0xf));
557 builder.Append (ToHex ((value >> 16) & 0xf));
558 builder.Append (ToHex ((value >> 12) & 0xf));
559 builder.Append (ToHex ((value >> 8) & 0xf));
560 builder.Append (ToHex ((value >> 4) & 0xf));
561 builder.Append (ToHex (value & 0xf));
564 static void AppendShort (StringBuilder builder, short value) {
565 builder.Append (ToHex ((value >> 12) & 0xf));
566 builder.Append (ToHex ((value >> 8) & 0xf));
567 builder.Append (ToHex ((value >> 4) & 0xf));
568 builder.Append (ToHex (value & 0xf));
571 static void AppendByte (StringBuilder builder, byte value) {
572 builder.Append (ToHex ((value >> 4) & 0xf));
573 builder.Append (ToHex (value & 0xf));
576 private string BaseToString (bool h, bool p, bool b)
578 StringBuilder res = new StringBuilder (40);
590 AppendShort (res, _b);
594 AppendShort (res, _c);
599 AppendByte (res, _d);
600 AppendByte (res, _e);
606 AppendByte (res, _f);
607 AppendByte (res, _g);
608 AppendByte (res, _h);
609 AppendByte (res, _i);
610 AppendByte (res, _j);
611 AppendByte (res, _k);
620 return res.ToString ();
623 public override string ToString ()
625 return BaseToString (true, false, false);
628 public string ToString (string format)
634 if (format != null) {
635 string f = format.ToLowerInvariant();
646 else if (f != "d" && f != String.Empty) {
647 throw new FormatException (Locale.GetText (
648 "Argument to Guid.ToString(string format) should be \"b\", \"B\", \"d\", \"D\", \"n\", \"N\", \"p\" or \"P\""));
652 return BaseToString (h, p, b);
655 public string ToString (string format, IFormatProvider provider)
657 return ToString (format);
660 public static bool operator == (Guid a, Guid b)
665 public static bool operator != (Guid a, Guid b)
667 return !( a.Equals (b) );
670 #if NET_4_0 || MOONLIGHT
671 public static Guid Parse (string input)
674 if (!TryParse (input, out guid))
675 throw CreateFormatException (input);
680 public static Guid ParseExact (string input, string format)
683 if (!TryParseExact (input, format, out guid))
684 throw CreateFormatException (input);
689 public static bool TryParse (string input, out Guid result)
692 throw new ArgumentNullException ("input");
694 var parser = new GuidParser (input);
695 return parser.Parse (out result);
698 public static bool TryParseExact (string input, string format, out Guid result)
701 throw new ArgumentNullException ("input");
703 throw new ArgumentNullException ("format");
705 var parser = new GuidParser (input);
706 return parser.Parse (ParseFormat (format), out result);
709 static Format ParseFormat (string format)
711 if (format.Length != 1)
712 throw new ArgumentException ("Wrong format");
714 switch (format [0]) {
727 throw new ArgumentException ("Wrong format");