5 // Duco Fijma (duco@lorentz.xs4all.nl)
6 // Sebastien Pouliot (sebastien@ximian.com)
9 // Copyright (C) 2004 Novell (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)]
43 public struct Guid : IFormattable, IComparable
45 private int _a; //_timeLow;
46 private short _b; //_timeMid;
47 private short _c; //_timeHighAndVersion;
48 private byte _d; //_clockSeqHiAndReserved;
49 private byte _e; //_clockSeqLow;
50 private byte _f; //_node0;
51 private byte _g; //_node1;
52 private byte _h; //_node2;
53 private byte _i; //_node3;
54 private byte _j; //_node4;
55 private byte _k; //_node5;
57 internal class GuidParser
63 public GuidParser (string src)
72 _length = _src.Length;
77 return _cur >= _length;
80 private void ThrowFormatException ()
82 throw new FormatException (Locale.GetText ("Invalid format for Guid.Guid(string)."));
85 private ulong ParseHex(int length, bool strictLength)
91 for (i=0; (!end) && i<length; ++i) {
93 if (strictLength || i==0) {
94 ThrowFormatException ();
101 char c = Char.ToLowerInvariant (_src[_cur]);
102 if (Char.IsDigit (c)) {
103 res = res * 16 + c - '0';
106 else if (c >= 'a' && c <= 'f') {
107 res = res * 16 + c - 'a' + 10;
111 if (strictLength || i==0) {
112 ThrowFormatException ();
123 private bool ParseOptChar (char c)
125 if (!AtEnd() && _src[_cur] == c) {
134 private void ParseChar (char c)
136 bool b = ParseOptChar (c);
138 ThrowFormatException ();
142 private Guid ParseGuid1 ()
150 byte[] d = new byte[8];
153 openBrace = ParseOptChar ('{');
155 openBrace = ParseOptChar ('(');
156 if (openBrace) endChar = ')';
159 a = (int) ParseHex(8, true);
161 if (openBrace) ParseChar('-');
162 else groups = ParseOptChar('-');
164 b = (short) ParseHex(4, true);
165 if (groups) ParseChar('-');
167 c = (short) ParseHex(4, true);
168 if (groups) ParseChar('-');
170 for (i=0; i<8; ++i) {
171 d[i] = (byte) ParseHex(2, true);
172 if (i == 1 && groups) {
177 if (openBrace && !ParseOptChar(endChar)) {
178 ThrowFormatException ();
181 return new Guid(a, b, c, d);
184 private void ParseHexPrefix ()
190 private Guid ParseGuid2 ()
195 byte[] d = new byte [8];
200 a = (int) ParseHex (8, false);
203 b = (short) ParseHex (4, false);
206 c = (short) ParseHex (4, false);
209 for (i=0; i<8; ++i) {
211 d[i] = (byte) ParseHex (2, false);
219 return new Guid (a,b,c,d);
230 catch (FormatException) {
235 ThrowFormatException ();
241 private static void CheckNull (object o)
244 throw new ArgumentNullException (Locale.GetText ("Value cannot be null."));
248 private static void CheckLength (byte[] o, int l)
250 if (o . Length != l) {
251 throw new ArgumentException (String.Format (Locale.GetText ("Array should be exactly {0} bytes long."), l));
255 private static void CheckArray (byte[] o, int l)
261 public Guid (byte[] b)
264 _a = System.BitConverter.ToInt32 (b, 0);
265 _b = System.BitConverter.ToInt16 (b, 4);
266 _c = System.BitConverter.ToInt16 (b, 6);
277 public Guid (string g)
281 GuidParser p = new GuidParser (g);
282 Guid guid = p.Parse();
287 public Guid (int a, short b, short c, byte[] d)
303 public Guid (int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
318 [CLSCompliant (false)]
319 public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
320 : this((int) a, (short) b, (short) c, d, e, f, g, h, i, j, k)
324 public static readonly Guid Empty = new Guid (0,0,0,0,0,0,0,0,0,0,0);
326 private static int Compare (int x, int y)
336 public int CompareTo (object value)
341 if (!(value is Guid)) {
342 throw new ArgumentException (Locale.GetText (
343 "Argument of System.Guid.CompareTo should be a Guid."));
346 Guid v = (Guid) value;
349 return Compare (_a, v._a);
351 else if (_b != v._b) {
352 return Compare (_b, v._b);
354 else if (_c != v._c) {
355 return Compare (_c, v._c);
357 else if (_d != v._d) {
358 return Compare (_d, v._d);
360 else if (_e != v._e) {
361 return Compare (_e, v._e);
363 else if (_f != v._f) {
364 return Compare (_f, v._f);
366 else if (_g != v._g) {
367 return Compare (_g, v._g);
369 else if (_h != v._h) {
370 return Compare (_h, v._h);
372 else if (_i != v._i) {
373 return Compare (_i, v._i);
375 else if (_j != v._j) {
376 return Compare (_j, v._j);
378 else if (_k != v._k) {
379 return Compare (_k, v._k);
384 public override bool Equals (object o)
387 return CompareTo (o) == 0;
389 catch (ArgumentException) {
394 public override int GetHashCode ()
399 res = res ^ ((int) _b << 16 | _c);
400 res = res ^ ((int) _d << 24);
401 res = res ^ ((int) _e << 16);
402 res = res ^ ((int) _f << 8);
403 res = res ^ ((int) _g);
404 res = res ^ ((int) _h << 24);
405 res = res ^ ((int) _i << 16);
406 res = res ^ ((int) _j << 8);
407 res = res ^ ((int) _k);
412 private static char ToHex (int b)
414 return (char)((b<0xA)?('0' + b):('a' + b - 0xA));
417 private static object _rngAccess = new object ();
418 private static RandomNumberGenerator _rng;
419 private static RandomNumberGenerator _fastRng;
421 // generated as per section 3.4 of the specification
422 public static Guid NewGuid ()
424 byte[] b = new byte [16];
426 // thread-safe access to the prng
429 _rng = RandomNumberGenerator.Create ();
433 Guid res = new Guid (b);
434 // Mask in Variant 1-0 in Bit[7..6]
435 res._d = (byte) ((res._d & 0x3fu) | 0x80u);
436 // Mask in Version 4 (random based Guid) in Bits[15..13]
437 res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
442 // used in ModuleBuilder so mcs doesn't need to invoke
443 // CryptoConfig for simple assemblies.
444 internal static byte[] FastNewGuidArray ()
446 byte[] guid = new byte [16];
448 // thread-safe access to the prng
450 // if known, use preferred RNG
453 // else use hardcoded default RNG (bypassing CryptoConfig)
454 if (_fastRng == null)
455 _fastRng = new RNGCryptoServiceProvider ();
456 _fastRng.GetBytes (guid);
459 // Mask in Variant 1-0 in Bit[7..6]
460 guid [8] = (byte) ((guid [8] & 0x3f) | 0x80);
461 // Mask in Version 4 (random based Guid) in Bits[15..13]
462 guid [7] = (byte) ((guid [7] & 0x0f) | 0x40);
467 public byte[] ToByteArray ()
469 byte[] res = new byte[16];
474 tmp = BitConverter.GetBytes(_a);
475 for (s=0; s<4; ++s) {
479 tmp = BitConverter.GetBytes(_b);
480 for (s=0; s<2; ++s) {
484 tmp = BitConverter.GetBytes(_c);
485 for (s=0; s<2; ++s) {
501 private string BaseToString (bool h, bool p, bool b)
503 StringBuilder res = new StringBuilder (40);
511 res.Append (_a.ToString ("x8"));
515 res.Append (_b.ToString ("x4"));
519 res.Append (_c.ToString ("x4"));
525 ToHex((_d >> 4) & 0xf),
527 ToHex((_e >> 4) & 0xf),
538 ToHex((_f >> 4) & 0xf),
540 ToHex((_g >> 4) & 0xf),
542 ToHex((_h >> 4) & 0xf),
544 ToHex((_i >> 4) & 0xf),
546 ToHex((_j >> 4) & 0xf),
548 ToHex((_k >> 4) & 0xf),
560 return res.ToString ();
563 public override string ToString ()
565 return BaseToString (true, false, false);
568 public string ToString (string format)
574 if (format != null) {
575 string f = format.ToLowerInvariant();
586 else if (f != "d" && f != "") {
587 throw new FormatException (Locale.GetText (
588 "Argument to Guid.ToString(string format) should be \"b\", \"B\", \"d\", \"D\", \"n\", \"N\", \"p\" or \"P\""));
592 return BaseToString (h, p, b);
595 public string ToString (string format, IFormatProvider provider)
597 return ToString (format);
600 public static bool operator == (Guid a, Guid b)
605 public static bool operator != (Guid a, Guid b)
607 return !( a.Equals (b) );