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
) );