5 // Duco Fijma (duco@lorentz.xs4all.nl)
6 // Sebastien Pouliot (sebastien@ximian.com)
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
12 // 1. UUIDs and GUIDs (DRAFT), Section 3.4
13 // http://www.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01.txt
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Runtime.InteropServices;
36 using System.Security.Cryptography;
42 [StructLayout (LayoutKind.Sequential)]
44 public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
47 if (MonoTouchAOTHelper.FalseFlag) {
48 var comparer = new System.Collections.Generic.GenericComparer <Guid> ();
49 var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <Guid> ();
53 private int _a; //_timeLow;
54 private short _b; //_timeMid;
55 private short _c; //_timeHighAndVersion;
56 private byte _d; //_clockSeqHiAndReserved;
57 private byte _e; //_clockSeqLow;
58 private byte _f; //_node0;
59 private byte _g; //_node1;
60 private byte _h; //_node2;
61 private byte _i; //_node3;
62 private byte _j; //_node4;
63 private byte _k; //_node5;
65 internal class GuidParser
71 public GuidParser (string src)
80 _length = _src.Length;
85 return _cur >= _length;
88 private void ThrowFormatException ()
90 throw new FormatException (Locale.GetText ("Invalid format for Guid.Guid(string)."));
93 private ulong ParseHex(int length, bool strictLength)
99 for (i=0; (!end) && i<length; ++i) {
101 if (strictLength || i==0) {
102 ThrowFormatException ();
109 char c = Char.ToLowerInvariant (_src[_cur]);
110 if (Char.IsDigit (c)) {
111 res = res * 16 + c - '0';
114 else if (c >= 'a' && c <= 'f') {
115 res = res * 16 + c - 'a' + 10;
119 if (strictLength || i==0) {
120 ThrowFormatException ();
131 private bool ParseOptChar (char c)
133 if (!AtEnd() && _src[_cur] == c) {
142 private void ParseChar (char c)
144 bool b = ParseOptChar (c);
146 ThrowFormatException ();
150 private Guid ParseGuid1 ()
158 byte[] d = new byte[8];
161 openBrace = ParseOptChar ('{');
163 openBrace = ParseOptChar ('(');
164 if (openBrace) endChar = ')';
167 a = (int) ParseHex(8, true);
169 if (openBrace) ParseChar('-');
170 else groups = ParseOptChar('-');
172 b = (short) ParseHex(4, true);
173 if (groups) ParseChar('-');
175 c = (short) ParseHex(4, true);
176 if (groups) ParseChar('-');
178 for (i=0; i<8; ++i) {
179 d[i] = (byte) ParseHex(2, true);
180 if (i == 1 && groups) {
185 if (openBrace && !ParseOptChar(endChar)) {
186 ThrowFormatException ();
189 return new Guid(a, b, c, d);
192 private void ParseHexPrefix ()
198 private Guid ParseGuid2 ()
203 byte[] d = new byte [8];
208 a = (int) ParseHex (8, false);
211 b = (short) ParseHex (4, false);
214 c = (short) ParseHex (4, false);
217 for (i=0; i<8; ++i) {
219 d[i] = (byte) ParseHex (2, false);
227 return new Guid (a,b,c,d);
238 catch (FormatException) {
243 ThrowFormatException ();
249 private static void CheckNull (object o)
252 throw new ArgumentNullException (Locale.GetText ("Value cannot be null."));
256 private static void CheckLength (byte[] o, int l)
258 if (o . Length != l) {
259 throw new ArgumentException (String.Format (Locale.GetText ("Array should be exactly {0} bytes long."), l));
263 private static void CheckArray (byte[] o, int l)
269 public Guid (byte[] b)
272 _a = Mono.Security.BitConverterLE.ToInt32 (b, 0);
273 _b = Mono.Security.BitConverterLE.ToInt16 (b, 4);
274 _c = Mono.Security.BitConverterLE.ToInt16 (b, 6);
285 public Guid (string g)
289 GuidParser p = new GuidParser (g);
290 Guid guid = p.Parse();
295 public Guid (int a, short b, short c, byte[] d)
311 public Guid (int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
326 [CLSCompliant (false)]
327 public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
328 : this((int) a, (short) b, (short) c, d, e, f, g, h, i, j, k)
332 public static readonly Guid Empty = new Guid (0,0,0,0,0,0,0,0,0,0,0);
334 private static int Compare (int x, int y)
344 public int CompareTo (object value)
349 if (!(value is Guid)) {
350 throw new ArgumentException ("value", Locale.GetText (
351 "Argument of System.Guid.CompareTo should be a Guid."));
354 return CompareTo ((Guid)value);
357 public override bool Equals (object o)
360 return CompareTo ((Guid)o) == 0;
364 public int CompareTo (Guid value)
366 if (_a != value._a) {
367 return Compare (_a, value._a);
369 else if (_b != value._b) {
370 return Compare (_b, value._b);
372 else if (_c != value._c) {
373 return Compare (_c, value._c);
375 else if (_d != value._d) {
376 return Compare (_d, value._d);
378 else if (_e != value._e) {
379 return Compare (_e, value._e);
381 else if (_f != value._f) {
382 return Compare (_f, value._f);
384 else if (_g != value._g) {
385 return Compare (_g, value._g);
387 else if (_h != value._h) {
388 return Compare (_h, value._h);
390 else if (_i != value._i) {
391 return Compare (_i, value._i);
393 else if (_j != value._j) {
394 return Compare (_j, value._j);
396 else if (_k != value._k) {
397 return Compare (_k, value._k);
402 public bool Equals (Guid g)
404 return CompareTo (g) == 0;
407 public override int GetHashCode ()
412 res = res ^ ((int) _b << 16 | _c);
413 res = res ^ ((int) _d << 24);
414 res = res ^ ((int) _e << 16);
415 res = res ^ ((int) _f << 8);
416 res = res ^ ((int) _g);
417 res = res ^ ((int) _h << 24);
418 res = res ^ ((int) _i << 16);
419 res = res ^ ((int) _j << 8);
420 res = res ^ ((int) _k);
425 private static char ToHex (int b)
427 return (char)((b<0xA)?('0' + b):('a' + b - 0xA));
430 private static object _rngAccess = new object ();
431 private static RandomNumberGenerator _rng;
432 private static RandomNumberGenerator _fastRng;
434 // generated as per section 3.4 of the specification
435 public static Guid NewGuid ()
437 byte[] b = new byte [16];
439 // thread-safe access to the prng
442 _rng = RandomNumberGenerator.Create ();
446 Guid res = new Guid (b);
447 // Mask in Variant 1-0 in Bit[7..6]
448 res._d = (byte) ((res._d & 0x3fu) | 0x80u);
449 // Mask in Version 4 (random based Guid) in Bits[15..13]
450 res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
455 // used in ModuleBuilder so mcs doesn't need to invoke
456 // CryptoConfig for simple assemblies.
457 internal static byte[] FastNewGuidArray ()
459 byte[] guid = new byte [16];
461 // thread-safe access to the prng
463 // if known, use preferred RNG
466 // else use hardcoded default RNG (bypassing CryptoConfig)
467 if (_fastRng == null)
468 _fastRng = new RNGCryptoServiceProvider ();
469 _fastRng.GetBytes (guid);
472 // Mask in Variant 1-0 in Bit[7..6]
473 guid [8] = (byte) ((guid [8] & 0x3f) | 0x80);
474 // Mask in Version 4 (random based Guid) in Bits[15..13]
475 guid [7] = (byte) ((guid [7] & 0x0f) | 0x40);
480 public byte[] ToByteArray ()
482 byte[] res = new byte[16];
487 tmp = Mono.Security.BitConverterLE.GetBytes(_a);
488 for (s=0; s<4; ++s) {
492 tmp = Mono.Security.BitConverterLE.GetBytes(_b);
493 for (s=0; s<2; ++s) {
497 tmp = Mono.Security.BitConverterLE.GetBytes(_c);
498 for (s=0; s<2; ++s) {
514 static void AppendInt (StringBuilder builder, int value) {
515 builder.Append (ToHex ((value >> 28) & 0xf));
516 builder.Append (ToHex ((value >> 24) & 0xf));
517 builder.Append (ToHex ((value >> 20) & 0xf));
518 builder.Append (ToHex ((value >> 16) & 0xf));
519 builder.Append (ToHex ((value >> 12) & 0xf));
520 builder.Append (ToHex ((value >> 8) & 0xf));
521 builder.Append (ToHex ((value >> 4) & 0xf));
522 builder.Append (ToHex (value & 0xf));
525 static void AppendShort (StringBuilder builder, short value) {
526 builder.Append (ToHex ((value >> 12) & 0xf));
527 builder.Append (ToHex ((value >> 8) & 0xf));
528 builder.Append (ToHex ((value >> 4) & 0xf));
529 builder.Append (ToHex (value & 0xf));
532 static void AppendByte (StringBuilder builder, byte value) {
533 builder.Append (ToHex ((value >> 4) & 0xf));
534 builder.Append (ToHex (value & 0xf));
537 private string BaseToString (bool h, bool p, bool b)
539 StringBuilder res = new StringBuilder (40);
551 AppendShort (res, _b);
555 AppendShort (res, _c);
560 AppendByte (res, _d);
561 AppendByte (res, _e);
567 AppendByte (res, _f);
568 AppendByte (res, _g);
569 AppendByte (res, _h);
570 AppendByte (res, _i);
571 AppendByte (res, _j);
572 AppendByte (res, _k);
581 return res.ToString ();
584 public override string ToString ()
586 return BaseToString (true, false, false);
589 public string ToString (string format)
595 if (format != null) {
596 string f = format.ToLowerInvariant();
607 else if (f != "d" && f != String.Empty) {
608 throw new FormatException (Locale.GetText (
609 "Argument to Guid.ToString(string format) should be \"b\", \"B\", \"d\", \"D\", \"n\", \"N\", \"p\" or \"P\""));
613 return BaseToString (h, p, b);
616 public string ToString (string format, IFormatProvider provider)
618 return ToString (format);
621 public static bool operator == (Guid a, Guid b)
626 public static bool operator != (Guid a, Guid b)
628 return !( a.Equals (b) );