5 // Duco Fijma (duco@lorentz.xs4all.nl)
6 // Sebastien Pouliot (sebastien@ximian.com)
7 // Jb Evain (jbevain@novell.com)
8 // Marek Safar (marek.safar@gmail.com)
10 // (C) 2002 Duco Fijma
11 // Copyright (C) 2004-2010 Novell, Inc (http://www.novell.com)
12 // Copyright 2012 Xamarin, Inc (http://www.xamarin.com)
15 // 1. UUIDs and GUIDs (DRAFT), Section 3.4
16 // http://www.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01.txt
18 // Permission is hereby granted, free of charge, to any person obtaining
19 // a copy of this software and associated documentation files (the
20 // "Software"), to deal in the Software without restriction, including
21 // without limitation the rights to use, copy, modify, merge, publish,
22 // distribute, sublicense, and/or sell copies of the Software, and to
23 // permit persons to whom the Software is furnished to do so, subject to
24 // the following conditions:
26 // The above copyright notice and this permission notice shall be
27 // included in all copies or substantial portions of the Software.
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System.Runtime.InteropServices;
39 using System.Security.Cryptography;
45 [StructLayout (LayoutKind.Sequential)]
47 public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
50 if (MonoTouchAOTHelper.FalseFlag) {
51 var comparer = new System.Collections.Generic.GenericComparer <Guid> ();
52 var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <Guid> ();
56 private int _a; //_timeLow;
57 private short _b; //_timeMid;
58 private short _c; //_timeHighAndVersion;
59 private byte _d; //_clockSeqHiAndReserved;
60 private byte _e; //_clockSeqLow;
61 private byte _f; //_node0;
62 private byte _g; //_node1;
63 private byte _h; //_node2;
64 private byte _i; //_node3;
65 private byte _j; //_node4;
66 private byte _k; //_node5;
69 N, // 00000000000000000000000000000000
70 D, // 00000000-0000-0000-0000-000000000000
71 B, // {00000000-0000-0000-0000-000000000000}
72 P, // (00000000-0000-0000-0000-000000000000)
73 X, // {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
82 public GuidParser (string src)
91 _length = _src.Length;
95 get { return _cur >= _length; }
98 public static bool HasHyphen (Format format)
110 bool TryParseNDBP (Format format, out Guid guid)
115 if (format == Format.B && !ParseChar ('{'))
118 if (format == Format.P && !ParseChar ('('))
121 if (!ParseHex (8, true, out a))
124 var has_hyphen = HasHyphen (format);
126 if (has_hyphen && !ParseChar ('-'))
129 if (!ParseHex (4, true, out b))
132 if (has_hyphen && !ParseChar ('-'))
135 if (!ParseHex (4, true, out c))
138 if (has_hyphen && !ParseChar ('-'))
141 var d = new byte [8];
142 for (int i = 0; i < d.Length; i++) {
144 if (!ParseHex (2, true, out dd))
147 if (i == 1 && has_hyphen && !ParseChar ('-'))
153 if (format == Format.B && !ParseChar ('}'))
156 if (format == Format.P && !ParseChar (')'))
162 guid = new Guid ((int) a, (short) b, (short) c, d);
166 bool TryParseX (out Guid guid)
171 if (!(ParseChar ('{')
173 && ParseHex (8, false, out a)
176 && ParseHex (4, false, out b)
179 && ParseHex (4, false, out c)
181 && ParseChar ('{'))) {
186 var d = new byte [8];
187 for (int i = 0; i < d.Length; ++i) {
190 if (!(ParseHexPrefix () && ParseHex (2, false, out dd)))
195 if (i != 7 && !ParseChar (','))
199 if (!(ParseChar ('}') && ParseChar ('}')))
205 guid = new Guid ((int) a, (short) b, (short) c, d);
209 bool ParseHexPrefix ()
211 if (!ParseChar ('0'))
214 return ParseChar ('x');
217 bool ParseChar (char c)
219 if (!Eof && _src [_cur] == c) {
227 bool ParseHex (int length, bool strict, out ulong res)
231 for (int i = 0; i < length; i++) {
233 return !(strict && (i + 1 != length));
235 char c = Char.ToLowerInvariant (_src[_cur]);
236 if (Char.IsDigit (c)) {
237 res = res * 16 + c - '0';
239 } else if (c >= 'a' && c <= 'f') {
240 res = res * 16 + c - 'a' + 10;
246 return !(strict && (i + 1 != length));
253 public bool Parse (Format format, out Guid guid)
255 if (format == Format.X)
256 return TryParseX (out guid);
258 return TryParseNDBP (format, out guid);
261 public bool Parse (out Guid guid)
263 if (TryParseNDBP (Format.N, out guid))
267 if (TryParseNDBP (Format.D, out guid))
271 if (TryParseNDBP (Format.B, out guid))
275 if (TryParseNDBP (Format.P, out guid))
279 return TryParseX (out guid);
283 private static void CheckNull (object o)
286 throw new ArgumentNullException (Locale.GetText ("Value cannot be null."));
290 private static void CheckLength (byte[] o, int l)
292 if (o . Length != l) {
293 throw new ArgumentException (String.Format (Locale.GetText ("Array should be exactly {0} bytes long."), l));
297 private static void CheckArray (byte[] o, int l)
303 public Guid (byte[] b)
306 _a = Mono.Security.BitConverterLE.ToInt32 (b, 0);
307 _b = Mono.Security.BitConverterLE.ToInt16 (b, 4);
308 _c = Mono.Security.BitConverterLE.ToInt16 (b, 6);
319 public Guid (string g)
323 var parser = new GuidParser (g);
325 if (!parser.Parse (out guid))
326 throw CreateFormatException (g);
331 static Exception CreateFormatException (string s)
333 return new FormatException (string.Format ("Invalid Guid format: {0}", s));
336 public Guid (int a, short b, short c, byte[] d)
352 public Guid (int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
367 [CLSCompliant (false)]
368 public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
369 : this((int) a, (short) b, (short) c, d, e, f, g, h, i, j, k)
373 public static readonly Guid Empty = new Guid (0,0,0,0,0,0,0,0,0,0,0);
375 private static int Compare (int x, int y)
377 return ((uint)x < (uint)y) ? -1 : 1;
380 public int CompareTo (object value)
385 if (!(value is Guid)) {
386 throw new ArgumentException ("value", Locale.GetText (
387 "Argument of System.Guid.CompareTo should be a Guid."));
390 return CompareTo ((Guid)value);
393 public override bool Equals (object o)
396 return CompareTo ((Guid)o) == 0;
400 public int CompareTo (Guid value)
402 if (_a != value._a) {
403 return Compare (_a, value._a);
405 if (_b != value._b) {
406 return Compare (_b, value._b);
408 if (_c != value._c) {
409 return Compare (_c, value._c);
411 if (_d != value._d) {
412 return Compare (_d, value._d);
414 if (_e != value._e) {
415 return Compare (_e, value._e);
417 if (_f != value._f) {
418 return Compare (_f, value._f);
420 if (_g != value._g) {
421 return Compare (_g, value._g);
423 if (_h != value._h) {
424 return Compare (_h, value._h);
426 if (_i != value._i) {
427 return Compare (_i, value._i);
429 if (_j != value._j) {
430 return Compare (_j, value._j);
432 if (_k != value._k) {
433 return Compare (_k, value._k);
438 public bool Equals (Guid g)
440 return CompareTo (g) == 0;
443 public override int GetHashCode ()
448 res = res ^ ((int) _b << 16 | _c);
449 res = res ^ ((int) _d << 24);
450 res = res ^ ((int) _e << 16);
451 res = res ^ ((int) _f << 8);
452 res = res ^ ((int) _g);
453 res = res ^ ((int) _h << 24);
454 res = res ^ ((int) _i << 16);
455 res = res ^ ((int) _j << 8);
456 res = res ^ ((int) _k);
461 private static char ToHex (int b)
463 return (char)((b<0xA)?('0' + b):('a' + b - 0xA));
466 private static object _rngAccess = new object ();
467 #if !FULL_AOT_RUNTIME
468 private static RandomNumberGenerator _rng;
469 private static RandomNumberGenerator _fastRng;
471 private static object _fastRng;
474 // generated as per section 3.4 of the specification
475 public static Guid NewGuid ()
477 #if !FULL_AOT_RUNTIME
478 byte[] b = new byte [16];
480 // thread-safe access to the prng
483 _rng = RandomNumberGenerator.Create ();
487 byte[] b = FastNewGuidArray ();
491 Guid res = new Guid (b);
492 // Mask in Variant 1-0 in Bit[7..6]
493 res._d = (byte) ((res._d & 0x3fu) | 0x80u);
494 // Mask in Version 4 (random based Guid) in Bits[15..13]
495 res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
500 // used in ModuleBuilder so mcs doesn't need to invoke
501 // CryptoConfig for simple assemblies.
502 internal static byte[] FastNewGuidArray ()
504 byte[] guid = new byte [16];
506 // thread-safe access to the prng
508 // if known, use preferred RNG
510 if (_fastRng == null)
511 _fastRng = new RNGCryptoServiceProvider ();
512 (_fastRng as RNGCryptoServiceProvider).GetBytes (guid);
516 // else use hardcoded default RNG (bypassing CryptoConfig)
517 if (_fastRng == null)
518 _fastRng = new RNGCryptoServiceProvider ();
519 _fastRng.GetBytes (guid);
523 // Mask in Variant 1-0 in Bit[7..6]
524 guid [8] = (byte) ((guid [8] & 0x3f) | 0x80);
525 // Mask in Version 4 (random based Guid) in Bits[15..13]
526 guid [7] = (byte) ((guid [7] & 0x0f) | 0x40);
531 public byte[] ToByteArray ()
533 byte[] res = new byte[16];
538 tmp = Mono.Security.BitConverterLE.GetBytes(_a);
539 for (s=0; s<4; ++s) {
543 tmp = Mono.Security.BitConverterLE.GetBytes(_b);
544 for (s=0; s<2; ++s) {
548 tmp = Mono.Security.BitConverterLE.GetBytes(_c);
549 for (s=0; s<2; ++s) {
565 static void AppendInt (StringBuilder builder, int value) {
566 builder.Append (ToHex ((value >> 28) & 0xf));
567 builder.Append (ToHex ((value >> 24) & 0xf));
568 builder.Append (ToHex ((value >> 20) & 0xf));
569 builder.Append (ToHex ((value >> 16) & 0xf));
570 builder.Append (ToHex ((value >> 12) & 0xf));
571 builder.Append (ToHex ((value >> 8) & 0xf));
572 builder.Append (ToHex ((value >> 4) & 0xf));
573 builder.Append (ToHex (value & 0xf));
576 static void AppendShort (StringBuilder builder, short value) {
577 builder.Append (ToHex ((value >> 12) & 0xf));
578 builder.Append (ToHex ((value >> 8) & 0xf));
579 builder.Append (ToHex ((value >> 4) & 0xf));
580 builder.Append (ToHex (value & 0xf));
583 static void AppendByte (StringBuilder builder, byte value) {
584 builder.Append (ToHex ((value >> 4) & 0xf));
585 builder.Append (ToHex (value & 0xf));
588 string ToString (Format format)
606 throw new NotImplementedException (format.ToString ());
609 StringBuilder res = new StringBuilder (length);
610 bool has_hyphen = GuidParser.HasHyphen (format);
612 if (format == Format.P) {
614 } else if (format == Format.B) {
616 } else if (format == Format.X) {
617 res.Append ('{').Append ('0').Append ('x');
623 } else if (format == Format.X) {
624 res.Append (',').Append ('0').Append ('x');
627 AppendShort (res, _b);
630 } else if (format == Format.X) {
631 res.Append (',').Append ('0').Append ('x');
634 AppendShort (res, _c);
639 if (format == Format.X) {
640 res.Append (',').Append ('{').Append ('0').Append ('x');
641 AppendByte (res, _d);
642 res.Append (',').Append ('0').Append ('x');
643 AppendByte (res, _e);
644 res.Append (',').Append ('0').Append ('x');
645 AppendByte (res, _f);
646 res.Append (',').Append ('0').Append ('x');
647 AppendByte (res, _g);
648 res.Append (',').Append ('0').Append ('x');
649 AppendByte (res, _h);
650 res.Append (',').Append ('0').Append ('x');
651 AppendByte (res, _i);
652 res.Append (',').Append ('0').Append ('x');
653 AppendByte (res, _j);
654 res.Append (',').Append ('0').Append ('x');
655 AppendByte (res, _k);
656 res.Append ('}').Append ('}');;
658 AppendByte (res, _d);
659 AppendByte (res, _e);
665 AppendByte (res, _f);
666 AppendByte (res, _g);
667 AppendByte (res, _h);
668 AppendByte (res, _i);
669 AppendByte (res, _j);
670 AppendByte (res, _k);
672 if (format == Format.P) {
674 } else if (format == Format.B) {
679 return res.ToString ();
682 public override string ToString ()
684 return ToString (Format.D);
687 public string ToString (string format)
689 return ToString (ParseFormat (format));
692 // provider value is never used
693 public string ToString (string format, IFormatProvider provider)
695 return ToString (format);
698 public static bool operator == (Guid a, Guid b)
703 public static bool operator != (Guid a, Guid b)
705 return !( a.Equals (b) );
708 #if NET_4_0 || MOONLIGHT || MOBILE
709 public static Guid Parse (string input)
712 throw new ArgumentNullException ("input");
715 if (!TryParse (input, out guid))
716 throw CreateFormatException (input);
721 public static Guid ParseExact (string input, string format)
724 throw new ArgumentNullException ("input");
726 throw new ArgumentNullException ("format");
729 if (!TryParseExact (input, format, out guid))
730 throw CreateFormatException (input);
735 public static bool TryParse (string input, out Guid result)
742 var parser = new GuidParser (input);
743 return parser.Parse (out result);
746 public static bool TryParseExact (string input, string format, out Guid result)
748 if (input == null || format == null) {
753 var parser = new GuidParser (input);
754 return parser.Parse (ParseFormat (format), out result);
758 static Format ParseFormat (string format)
760 if (string.IsNullOrEmpty (format))
763 switch (format [0]) {
776 #if NET_4_0 || MOONLIGHT || MOBILE
783 throw new FormatException (
784 #if NET_4_0 || MOONLIGHT || MOBILE
785 "Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\""
787 "Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\" or \"b\""