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;
41 #if MONOTOUCH && FULL_AOT_RUNTIME
42 using Crimson.CommonCrypto;
48 [StructLayout (LayoutKind.Sequential)]
50 public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
53 if (MonoTouchAOTHelper.FalseFlag) {
54 var comparer = new System.Collections.Generic.GenericComparer <Guid> ();
55 var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <Guid> ();
59 private int _a; //_timeLow;
60 private short _b; //_timeMid;
61 private short _c; //_timeHighAndVersion;
62 private byte _d; //_clockSeqHiAndReserved;
63 private byte _e; //_clockSeqLow;
64 private byte _f; //_node0;
65 private byte _g; //_node1;
66 private byte _h; //_node2;
67 private byte _i; //_node3;
68 private byte _j; //_node4;
69 private byte _k; //_node5;
72 N, // 00000000000000000000000000000000
73 D, // 00000000-0000-0000-0000-000000000000
74 B, // {00000000-0000-0000-0000-000000000000}
75 P, // (00000000-0000-0000-0000-000000000000)
76 X, // {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
85 public GuidParser (string src)
89 _length = _src.Length;
95 _length = _src.Length;
99 get { return _cur >= _length; }
102 public static bool HasHyphen (Format format)
114 bool TryParseNDBP (Format format, out Guid guid)
119 if (format == Format.B && !ParseChar ('{'))
122 if (format == Format.P && !ParseChar ('('))
125 if (!ParseHex (8, true, out a))
128 var has_hyphen = HasHyphen (format);
130 if (has_hyphen && !ParseChar ('-'))
133 if (!ParseHex (4, true, out b))
136 if (has_hyphen && !ParseChar ('-'))
139 if (!ParseHex (4, true, out c))
142 if (has_hyphen && !ParseChar ('-'))
145 var d = new byte [8];
146 for (int i = 0; i < d.Length; i++) {
148 if (!ParseHex (2, true, out dd))
151 if (i == 1 && has_hyphen && !ParseChar ('-'))
157 if (format == Format.B && !ParseChar ('}'))
160 if (format == Format.P && !ParseChar (')'))
166 guid = new Guid ((int) a, (short) b, (short) c, d);
170 bool TryParseX (out Guid guid)
175 if (!(ParseChar ('{')
177 && ParseHex (8, false, out a)
180 && ParseHex (4, false, out b)
183 && ParseHex (4, false, out c)
185 && ParseChar ('{'))) {
190 var d = new byte [8];
191 for (int i = 0; i < d.Length; ++i) {
194 if (!(ParseHexPrefix () && ParseHex (2, false, out dd)))
199 if (i != 7 && !ParseChar (','))
203 if (!(ParseChar ('}') && ParseChar ('}')))
209 guid = new Guid ((int) a, (short) b, (short) c, d);
213 bool ParseHexPrefix ()
215 if (!ParseChar ('0'))
218 return ParseChar ('x');
221 bool ParseChar (char c)
223 if (!Eof && _src [_cur] == c) {
231 bool ParseHex (int length, bool strict, out ulong res)
235 for (int i = 0; i < length; i++) {
237 return !(strict && (i + 1 != length));
239 char c = _src [_cur];
240 if (Char.IsDigit (c)) {
241 res = res * 16 + c - '0';
246 if (c >= 'a' && c <= 'f') {
247 res = res * 16 + c - 'a' + 10;
252 if (c >= 'A' && c <= 'F') {
253 res = res * 16 + c - 'A' + 10;
261 return false; //!(strict && (i + 1 != length));
267 public bool Parse (Format format, out Guid guid)
269 if (format == Format.X)
270 return TryParseX (out guid);
272 return TryParseNDBP (format, out guid);
275 public bool Parse (out Guid guid)
279 if (TryParseNDBP (Format.N, out guid))
283 if (TryParseNDBP (Format.D, out guid))
289 if (TryParseNDBP (Format.B, out guid))
293 if (TryParseNDBP (Format.P, out guid))
301 return TryParseX (out guid);
305 private static void CheckNull (object o)
308 throw new ArgumentNullException (Locale.GetText ("Value cannot be null."));
312 private static void CheckLength (byte[] o, int l)
314 if (o . Length != l) {
315 throw new ArgumentException (String.Format (Locale.GetText ("Array should be exactly {0} bytes long."), l));
319 private static void CheckArray (byte[] o, int l)
325 public Guid (byte[] b)
328 _a = Mono.Security.BitConverterLE.ToInt32 (b, 0);
329 _b = Mono.Security.BitConverterLE.ToInt16 (b, 4);
330 _c = Mono.Security.BitConverterLE.ToInt16 (b, 6);
341 public Guid (string g)
345 var parser = new GuidParser (g);
347 if (!parser.Parse (out guid))
348 throw CreateFormatException (g);
353 static Exception CreateFormatException (string s)
355 return new FormatException (string.Format ("Invalid Guid format: {0}", s));
358 public Guid (int a, short b, short c, byte[] d)
374 public Guid (int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
389 [CLSCompliant (false)]
390 public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
391 : this((int) a, (short) b, (short) c, d, e, f, g, h, i, j, k)
395 public static readonly Guid Empty = new Guid (0,0,0,0,0,0,0,0,0,0,0);
397 private static int Compare (int x, int y)
399 return ((uint)x < (uint)y) ? -1 : 1;
402 public int CompareTo (object value)
407 if (!(value is Guid)) {
408 throw new ArgumentException ("value", Locale.GetText (
409 "Argument of System.Guid.CompareTo should be a Guid."));
412 return CompareTo ((Guid)value);
415 public override bool Equals (object o)
418 return CompareTo ((Guid)o) == 0;
422 public int CompareTo (Guid value)
424 if (_a != value._a) {
425 return Compare (_a, value._a);
427 if (_b != value._b) {
428 return Compare (_b, value._b);
430 if (_c != value._c) {
431 return Compare (_c, value._c);
433 if (_d != value._d) {
434 return Compare (_d, value._d);
436 if (_e != value._e) {
437 return Compare (_e, value._e);
439 if (_f != value._f) {
440 return Compare (_f, value._f);
442 if (_g != value._g) {
443 return Compare (_g, value._g);
445 if (_h != value._h) {
446 return Compare (_h, value._h);
448 if (_i != value._i) {
449 return Compare (_i, value._i);
451 if (_j != value._j) {
452 return Compare (_j, value._j);
454 if (_k != value._k) {
455 return Compare (_k, value._k);
460 public bool Equals (Guid g)
462 return CompareTo (g) == 0;
465 public override int GetHashCode ()
470 res = res ^ ((int) _b << 16 | _c);
471 res = res ^ ((int) _d << 24);
472 res = res ^ ((int) _e << 16);
473 res = res ^ ((int) _f << 8);
474 res = res ^ ((int) _g);
475 res = res ^ ((int) _h << 24);
476 res = res ^ ((int) _i << 16);
477 res = res ^ ((int) _j << 8);
478 res = res ^ ((int) _k);
483 private static char ToHex (int b)
485 return (char)((b<0xA)?('0' + b):('a' + b - 0xA));
488 #if !FULL_AOT_RUNTIME
489 private static object _rngAccess = new object ();
490 private static RandomNumberGenerator _rng;
491 private static RandomNumberGenerator _fastRng;
494 #if FULL_AOT_RUNTIME && !MONOTOUCH
495 // NSA approved random generator.
496 static void LameRandom (byte [] b)
498 var r = new Random ();
503 // generated as per section 3.4 of the specification
504 public static Guid NewGuid ()
506 byte[] b = new byte [16];
507 #if !FULL_AOT_RUNTIME
508 // thread-safe access to the prng
511 _rng = RandomNumberGenerator.Create ();
515 Cryptor.GetRandom (b);
520 Guid res = new Guid (b);
521 // Mask in Variant 1-0 in Bit[7..6]
522 res._d = (byte) ((res._d & 0x3fu) | 0x80u);
523 // Mask in Version 4 (random based Guid) in Bits[15..13]
524 res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
529 #if !FULL_AOT_RUNTIME
530 // used in ModuleBuilder so mcs doesn't need to invoke
531 // CryptoConfig for simple assemblies.
532 internal static byte[] FastNewGuidArray ()
534 byte[] guid = new byte [16];
536 // thread-safe access to the prng
538 // if known, use preferred RNG
541 // else use hardcoded default RNG (bypassing CryptoConfig)
542 if (_fastRng == null)
543 _fastRng = new RNGCryptoServiceProvider ();
544 _fastRng.GetBytes (guid);
547 // Mask in Variant 1-0 in Bit[7..6]
548 guid [8] = (byte) ((guid [8] & 0x3f) | 0x80);
549 // Mask in Version 4 (random based Guid) in Bits[15..13]
550 guid [7] = (byte) ((guid [7] & 0x0f) | 0x40);
555 public byte[] ToByteArray ()
557 byte[] res = new byte[16];
562 tmp = Mono.Security.BitConverterLE.GetBytes(_a);
563 for (s=0; s<4; ++s) {
567 tmp = Mono.Security.BitConverterLE.GetBytes(_b);
568 for (s=0; s<2; ++s) {
572 tmp = Mono.Security.BitConverterLE.GetBytes(_c);
573 for (s=0; s<2; ++s) {
589 static void AppendInt (StringBuilder builder, int value) {
590 builder.Append (ToHex ((value >> 28) & 0xf));
591 builder.Append (ToHex ((value >> 24) & 0xf));
592 builder.Append (ToHex ((value >> 20) & 0xf));
593 builder.Append (ToHex ((value >> 16) & 0xf));
594 builder.Append (ToHex ((value >> 12) & 0xf));
595 builder.Append (ToHex ((value >> 8) & 0xf));
596 builder.Append (ToHex ((value >> 4) & 0xf));
597 builder.Append (ToHex (value & 0xf));
600 static void AppendShort (StringBuilder builder, short value) {
601 builder.Append (ToHex ((value >> 12) & 0xf));
602 builder.Append (ToHex ((value >> 8) & 0xf));
603 builder.Append (ToHex ((value >> 4) & 0xf));
604 builder.Append (ToHex (value & 0xf));
607 static void AppendByte (StringBuilder builder, byte value) {
608 builder.Append (ToHex ((value >> 4) & 0xf));
609 builder.Append (ToHex (value & 0xf));
612 string ToString (Format format)
630 throw new NotImplementedException (format.ToString ());
633 StringBuilder res = new StringBuilder (length);
634 bool has_hyphen = GuidParser.HasHyphen (format);
636 if (format == Format.P) {
638 } else if (format == Format.B) {
640 } else if (format == Format.X) {
641 res.Append ('{').Append ('0').Append ('x');
647 } else if (format == Format.X) {
648 res.Append (',').Append ('0').Append ('x');
651 AppendShort (res, _b);
654 } else if (format == Format.X) {
655 res.Append (',').Append ('0').Append ('x');
658 AppendShort (res, _c);
663 if (format == Format.X) {
664 res.Append (',').Append ('{').Append ('0').Append ('x');
665 AppendByte (res, _d);
666 res.Append (',').Append ('0').Append ('x');
667 AppendByte (res, _e);
668 res.Append (',').Append ('0').Append ('x');
669 AppendByte (res, _f);
670 res.Append (',').Append ('0').Append ('x');
671 AppendByte (res, _g);
672 res.Append (',').Append ('0').Append ('x');
673 AppendByte (res, _h);
674 res.Append (',').Append ('0').Append ('x');
675 AppendByte (res, _i);
676 res.Append (',').Append ('0').Append ('x');
677 AppendByte (res, _j);
678 res.Append (',').Append ('0').Append ('x');
679 AppendByte (res, _k);
680 res.Append ('}').Append ('}');;
682 AppendByte (res, _d);
683 AppendByte (res, _e);
689 AppendByte (res, _f);
690 AppendByte (res, _g);
691 AppendByte (res, _h);
692 AppendByte (res, _i);
693 AppendByte (res, _j);
694 AppendByte (res, _k);
696 if (format == Format.P) {
698 } else if (format == Format.B) {
703 return res.ToString ();
706 public override string ToString ()
708 return ToString (Format.D);
711 public string ToString (string format)
713 return ToString (ParseFormat (format));
716 // provider value is never used
717 public string ToString (string format, IFormatProvider provider)
719 return ToString (format);
722 public static bool operator == (Guid a, Guid b)
727 public static bool operator != (Guid a, Guid b)
729 return !( a.Equals (b) );
733 public static Guid Parse (string input)
736 throw new ArgumentNullException ("input");
739 if (!TryParse (input, out guid))
740 throw CreateFormatException (input);
745 public static Guid ParseExact (string input, string format)
748 throw new ArgumentNullException ("input");
750 throw new ArgumentNullException ("format");
753 if (!TryParseExact (input, format, out guid))
754 throw CreateFormatException (input);
759 public static bool TryParse (string input, out Guid result)
766 var parser = new GuidParser (input);
767 return parser.Parse (out result);
770 public static bool TryParseExact (string input, string format, out Guid result)
772 if (input == null || format == null) {
777 var parser = new GuidParser (input);
778 return parser.Parse (ParseFormat (format), out result);
782 static Format ParseFormat (string format)
784 if (string.IsNullOrEmpty (format))
787 switch (format [0]) {
807 throw new FormatException (
809 "Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\""
811 "Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\" or \"b\""