move FrameworkName from corlib to System
[mcs.git] / class / corlib / System / Guid.cs
blob6529a286a84013e5257695db0ac9c903c8a89981
1 //
2 // System.Guid.cs
3 //
4 // Authors:
5 // Duco Fijma (duco@lorentz.xs4all.nl)
6 // Sebastien Pouliot (sebastien@ximian.com)
7 //
8 // (C) 2002 Duco Fijma
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 // References
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:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
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;
37 using System.Text;
39 namespace System {
41 [Serializable]
42 [StructLayout (LayoutKind.Sequential)]
43 [ComVisible (true)]
44 public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
45 #if MONOTOUCH
46 static Guid () {
47 if (MonoTouchAOTHelper.FalseFlag) {
48 var comparer = new System.Collections.Generic.GenericComparer <Guid> ();
49 var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <Guid> ();
52 #endif
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
67 private string _src;
68 private int _length;
69 private int _cur;
71 public GuidParser (string src)
73 _src = src;
74 Reset ();
77 private void Reset ()
79 _cur = 0;
80 _length = _src.Length;
83 private bool AtEnd ()
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)
95 ulong res = 0;
96 int i;
97 bool end = false;
99 for (i=0; (!end) && i<length; ++i) {
100 if (AtEnd ()) {
101 if (strictLength || i==0) {
102 ThrowFormatException ();
104 else {
105 end = true;
108 else {
109 char c = Char.ToLowerInvariant (_src[_cur]);
110 if (Char.IsDigit (c)) {
111 res = res * 16 + c - '0';
112 _cur++;
114 else if (c >= 'a' && c <= 'f') {
115 res = res * 16 + c - 'a' + 10;
116 _cur++;
118 else {
119 if (strictLength || i==0) {
120 ThrowFormatException ();
122 else {
123 end = true;
128 return res;
131 private bool ParseOptChar (char c)
133 if (!AtEnd() && _src[_cur] == c) {
134 _cur++;
135 return true;
137 else {
138 return false;
142 private void ParseChar (char c)
144 bool b = ParseOptChar (c);
145 if (!b) {
146 ThrowFormatException ();
150 private Guid ParseGuid1 ()
152 bool openBrace;
153 bool groups = true;
154 char endChar = '}';
155 int a;
156 short b;
157 short c;
158 byte[] d = new byte[8];
159 int i;
161 openBrace = ParseOptChar ('{');
162 if (!openBrace) {
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) {
181 ParseChar('-');
185 if (openBrace && !ParseOptChar(endChar)) {
186 ThrowFormatException ();
189 return new Guid(a, b, c, d);
192 private void ParseHexPrefix ()
194 ParseChar ('0');
195 ParseChar ('x');
198 private Guid ParseGuid2 ()
200 int a;
201 short b;
202 short c;
203 byte[] d = new byte [8];
204 int i;
206 ParseChar ('{');
207 ParseHexPrefix ();
208 a = (int) ParseHex (8, false);
209 ParseChar (',');
210 ParseHexPrefix ();
211 b = (short) ParseHex (4, false);
212 ParseChar (',');
213 ParseHexPrefix ();
214 c = (short) ParseHex (4, false);
215 ParseChar (',');
216 ParseChar ('{');
217 for (i=0; i<8; ++i) {
218 ParseHexPrefix ();
219 d[i] = (byte) ParseHex (2, false);
220 if (i != 7) {
221 ParseChar (',');
224 ParseChar ('}');
225 ParseChar ('}');
227 return new Guid (a,b,c,d);
231 public Guid Parse ()
233 Guid g;
235 try {
236 g = ParseGuid1 ();
238 catch (FormatException) {
239 Reset ();
240 g = ParseGuid2 ();
242 if (!AtEnd () ) {
243 ThrowFormatException ();
245 return g;
249 private static void CheckNull (object o)
251 if (o == null) {
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)
265 CheckNull (o);
266 CheckLength (o, l);
269 public Guid (byte[] b)
271 CheckArray (b, 16);
272 _a = Mono.Security.BitConverterLE.ToInt32 (b, 0);
273 _b = Mono.Security.BitConverterLE.ToInt16 (b, 4);
274 _c = Mono.Security.BitConverterLE.ToInt16 (b, 6);
275 _d = b [8];
276 _e = b [9];
277 _f = b [10];
278 _g = b [11];
279 _h = b [12];
280 _i = b [13];
281 _j = b [14];
282 _k = b [15];
285 public Guid (string g)
287 CheckNull (g);
288 g = g.Trim();
289 GuidParser p = new GuidParser (g);
290 Guid guid = p.Parse();
292 this = guid;
295 public Guid (int a, short b, short c, byte[] d)
297 CheckArray (d, 8);
298 _a = (int) a;
299 _b = (short) b;
300 _c = (short) c;
301 _d = d [0];
302 _e = d [1];
303 _f = d [2];
304 _g = d [3];
305 _h = d [4];
306 _i = d [5];
307 _j = d [6];
308 _k = d [7];
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)
313 _a = a;
314 _b = b;
315 _c = c;
316 _d = d;
317 _e = e;
318 _f = f;
319 _g = g;
320 _h = h;
321 _i = i;
322 _j = j;
323 _k = 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)
336 if (x < y) {
337 return -1;
339 else {
340 return 1;
344 public int CompareTo (object value)
346 if (value == null)
347 return 1;
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)
359 if (o is Guid)
360 return CompareTo ((Guid)o) == 0;
361 return false;
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);
399 return 0;
402 public bool Equals (Guid g)
404 return CompareTo (g) == 0;
407 public override int GetHashCode ()
409 int res;
411 res = (int) _a;
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);
422 return res;
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
440 lock (_rngAccess) {
441 if (_rng == null)
442 _rng = RandomNumberGenerator.Create ();
443 _rng.GetBytes (b);
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);
452 return res;
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
462 lock (_rngAccess) {
463 // if known, use preferred RNG
464 if (_rng != null)
465 _fastRng = _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);
477 return guid;
480 public byte[] ToByteArray ()
482 byte[] res = new byte[16];
483 byte[] tmp;
484 int d = 0;
485 int s;
487 tmp = Mono.Security.BitConverterLE.GetBytes(_a);
488 for (s=0; s<4; ++s) {
489 res[d++] = tmp[s];
492 tmp = Mono.Security.BitConverterLE.GetBytes(_b);
493 for (s=0; s<2; ++s) {
494 res[d++] = tmp[s];
497 tmp = Mono.Security.BitConverterLE.GetBytes(_c);
498 for (s=0; s<2; ++s) {
499 res[d++] = tmp[s];
502 res[8] = _d;
503 res[9] = _e;
504 res[10] = _f;
505 res[11] = _g;
506 res[12] = _h;
507 res[13] = _i;
508 res[14] = _j;
509 res[15] = _k;
511 return res;
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);
541 if (p) {
542 res.Append ('(');
543 } else if (b) {
544 res.Append ('{');
547 AppendInt (res, _a);
548 if (h) {
549 res.Append ('-');
551 AppendShort (res, _b);
552 if (h) {
553 res.Append ('-');
555 AppendShort (res, _c);
556 if (h) {
557 res.Append ('-');
560 AppendByte (res, _d);
561 AppendByte (res, _e);
563 if (h) {
564 res.Append ('-');
567 AppendByte (res, _f);
568 AppendByte (res, _g);
569 AppendByte (res, _h);
570 AppendByte (res, _i);
571 AppendByte (res, _j);
572 AppendByte (res, _k);
575 if (p) {
576 res.Append (')');
577 } else if (b) {
578 res.Append ('}');
581 return res.ToString ();
584 public override string ToString ()
586 return BaseToString (true, false, false);
589 public string ToString (string format)
591 bool h = true;
592 bool p = false;
593 bool b = false;
595 if (format != null) {
596 string f = format.ToLowerInvariant();
598 if (f == "b") {
599 b = true;
601 else if (f == "p") {
602 p = true;
604 else if (f == "n") {
605 h = false;
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)
623 return a.Equals(b);
626 public static bool operator != (Guid a, Guid b)
628 return !( a.Equals (b) );