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)]
45 public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
47 public struct Guid : IFormattable, IComparable {
49 private int _a; //_timeLow;
50 private short _b; //_timeMid;
51 private short _c; //_timeHighAndVersion;
52 private byte _d; //_clockSeqHiAndReserved;
53 private byte _e; //_clockSeqLow;
54 private byte _f; //_node0;
55 private byte _g; //_node1;
56 private byte _h; //_node2;
57 private byte _i; //_node3;
58 private byte _j; //_node4;
59 private byte _k; //_node5;
61 internal class GuidParser
67 public GuidParser (string src)
76 _length = _src.Length;
81 return _cur >= _length;
84 private void ThrowFormatException ()
86 throw new FormatException (Locale.GetText ("Invalid format for Guid.Guid(string)."));
89 private ulong ParseHex(int length, bool strictLength)
95 for (i=0; (!end) && i<length; ++i) {
97 if (strictLength || i==0) {
98 ThrowFormatException ();
105 char c = Char.ToLowerInvariant (_src[_cur]);
106 if (Char.IsDigit (c)) {
107 res = res * 16 + c - '0';
110 else if (c >= 'a' && c <= 'f') {
111 res = res * 16 + c - 'a' + 10;
115 if (strictLength || i==0) {
116 ThrowFormatException ();
127 private bool ParseOptChar (char c)
129 if (!AtEnd() && _src[_cur] == c) {
138 private void ParseChar (char c)
140 bool b = ParseOptChar (c);
142 ThrowFormatException ();
146 private Guid ParseGuid1 ()
154 byte[] d = new byte[8];
157 openBrace = ParseOptChar ('{');
159 openBrace = ParseOptChar ('(');
160 if (openBrace) endChar = ')';
163 a = (int) ParseHex(8, true);
165 if (openBrace) ParseChar('-');
166 else groups = ParseOptChar('-');
168 b = (short) ParseHex(4, true);
169 if (groups) ParseChar('-');
171 c = (short) ParseHex(4, true);
172 if (groups) ParseChar('-');
174 for (i=0; i<8; ++i) {
175 d[i] = (byte) ParseHex(2, true);
176 if (i == 1 && groups) {
181 if (openBrace && !ParseOptChar(endChar)) {
182 ThrowFormatException ();
185 return new Guid(a, b, c, d);
188 private void ParseHexPrefix ()
194 private Guid ParseGuid2 ()
199 byte[] d = new byte [8];
204 a = (int) ParseHex (8, false);
207 b = (short) ParseHex (4, false);
210 c = (short) ParseHex (4, false);
213 for (i=0; i<8; ++i) {
215 d[i] = (byte) ParseHex (2, false);
223 return new Guid (a,b,c,d);
234 catch (FormatException) {
239 ThrowFormatException ();
245 private static void CheckNull (object o)
248 throw new ArgumentNullException (Locale.GetText ("Value cannot be null."));
252 private static void CheckLength (byte[] o, int l)
254 if (o . Length != l) {
255 throw new ArgumentException (String.Format (Locale.GetText ("Array should be exactly {0} bytes long."), l));
259 private static void CheckArray (byte[] o, int l)
265 public Guid (byte[] b)
268 _a = Mono.Security.BitConverterLE.ToInt32 (b, 0);
269 _b = Mono.Security.BitConverterLE.ToInt16 (b, 4);
270 _c = Mono.Security.BitConverterLE.ToInt16 (b, 6);
281 public Guid (string g)
285 GuidParser p = new GuidParser (g);
286 Guid guid = p.Parse();
291 public Guid (int a, short b, short c, byte[] d)
307 public Guid (int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
322 [CLSCompliant (false)]
323 public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
324 : this((int) a, (short) b, (short) c, d, e, f, g, h, i, j, k)
328 public static readonly Guid Empty = new Guid (0,0,0,0,0,0,0,0,0,0,0);
330 private static int Compare (int x, int y)
340 public int CompareTo (object value)
345 if (!(value is Guid)) {
346 throw new ArgumentException ("value", Locale.GetText (
347 "Argument of System.Guid.CompareTo should be a Guid."));
350 return CompareTo ((Guid)value);
353 public override bool Equals (object o)
356 return CompareTo ((Guid)o) == 0;
361 public int CompareTo (Guid value)
363 internal 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);
403 public bool Equals (Guid g)
405 return CompareTo (g) == 0;
409 public override int GetHashCode ()
414 res = res ^ ((int) _b << 16 | _c);
415 res = res ^ ((int) _d << 24);
416 res = res ^ ((int) _e << 16);
417 res = res ^ ((int) _f << 8);
418 res = res ^ ((int) _g);
419 res = res ^ ((int) _h << 24);
420 res = res ^ ((int) _i << 16);
421 res = res ^ ((int) _j << 8);
422 res = res ^ ((int) _k);
427 private static char ToHex (int b)
429 return (char)((b<0xA)?('0' + b):('a' + b - 0xA));
432 private static object _rngAccess = new object ();
433 private static RandomNumberGenerator _rng;
434 private static RandomNumberGenerator _fastRng;
436 // generated as per section 3.4 of the specification
437 public static Guid NewGuid ()
439 byte[] b = new byte [16];
441 // thread-safe access to the prng
444 _rng = RandomNumberGenerator.Create ();
448 Guid res = new Guid (b);
449 // Mask in Variant 1-0 in Bit[7..6]
450 res._d = (byte) ((res._d & 0x3fu) | 0x80u);
451 // Mask in Version 4 (random based Guid) in Bits[15..13]
452 res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
457 // used in ModuleBuilder so mcs doesn't need to invoke
458 // CryptoConfig for simple assemblies.
459 internal static byte[] FastNewGuidArray ()
461 byte[] guid = new byte [16];
463 // thread-safe access to the prng
465 // if known, use preferred RNG
468 // else use hardcoded default RNG (bypassing CryptoConfig)
469 if (_fastRng == null)
470 _fastRng = new RNGCryptoServiceProvider ();
471 _fastRng.GetBytes (guid);
474 // Mask in Variant 1-0 in Bit[7..6]
475 guid [8] = (byte) ((guid [8] & 0x3f) | 0x80);
476 // Mask in Version 4 (random based Guid) in Bits[15..13]
477 guid [7] = (byte) ((guid [7] & 0x0f) | 0x40);
482 public byte[] ToByteArray ()
484 byte[] res = new byte[16];
489 tmp = Mono.Security.BitConverterLE.GetBytes(_a);
490 for (s=0; s<4; ++s) {
494 tmp = Mono.Security.BitConverterLE.GetBytes(_b);
495 for (s=0; s<2; ++s) {
499 tmp = Mono.Security.BitConverterLE.GetBytes(_c);
500 for (s=0; s<2; ++s) {
516 private string BaseToString (bool h, bool p, bool b)
518 StringBuilder res = new StringBuilder (40);
526 res.Append (_a.ToString ("x8"));
530 res.Append (_b.ToString ("x4"));
534 res.Append (_c.ToString ("x4"));
540 ToHex((_d >> 4) & 0xf),
542 ToHex((_e >> 4) & 0xf),
553 ToHex((_f >> 4) & 0xf),
555 ToHex((_g >> 4) & 0xf),
557 ToHex((_h >> 4) & 0xf),
559 ToHex((_i >> 4) & 0xf),
561 ToHex((_j >> 4) & 0xf),
563 ToHex((_k >> 4) & 0xf),
575 return res.ToString ();
578 public override string ToString ()
580 return BaseToString (true, false, false);
583 public string ToString (string format)
589 if (format != null) {
590 string f = format.ToLowerInvariant();
601 else if (f != "d" && f != String.Empty) {
602 throw new FormatException (Locale.GetText (
603 "Argument to Guid.ToString(string format) should be \"b\", \"B\", \"d\", \"D\", \"n\", \"N\", \"p\" or \"P\""));
607 return BaseToString (h, p, b);
610 public string ToString (string format, IFormatProvider provider)
612 return ToString (format);
615 public static bool operator == (Guid a, Guid b)
620 public static bool operator != (Guid a, Guid b)
622 return !( a.Equals (b) );