a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
838 lines
18 KiB
C#
838 lines
18 KiB
C#
//
|
|
// System.Guid.cs
|
|
//
|
|
// Authors:
|
|
// Duco Fijma (duco@lorentz.xs4all.nl)
|
|
// Sebastien Pouliot (sebastien@ximian.com)
|
|
// Jb Evain (jbevain@novell.com)
|
|
// Marek Safar (marek.safar@gmail.com)
|
|
//
|
|
// (C) 2002 Duco Fijma
|
|
// Copyright (C) 2004-2010 Novell, Inc (http://www.novell.com)
|
|
// Copyright 2012, 2014 Xamarin, Inc (http://www.xamarin.com)
|
|
//
|
|
// References
|
|
// 1. UUIDs and GUIDs (DRAFT), Section 3.4
|
|
// http://www.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01.txt
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
#if MONOTOUCH && FULL_AOT_RUNTIME
|
|
using Crimson.CommonCrypto;
|
|
#endif
|
|
|
|
namespace System {
|
|
|
|
[Serializable]
|
|
[StructLayout (LayoutKind.Sequential)]
|
|
[ComVisible (true)]
|
|
public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
|
|
#if MONOTOUCH
|
|
static Guid () {
|
|
if (MonoTouchAOTHelper.FalseFlag) {
|
|
var comparer = new System.Collections.Generic.GenericComparer <Guid> ();
|
|
var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <Guid> ();
|
|
}
|
|
}
|
|
#endif
|
|
private int _a; //_timeLow;
|
|
private short _b; //_timeMid;
|
|
private short _c; //_timeHighAndVersion;
|
|
private byte _d; //_clockSeqHiAndReserved;
|
|
private byte _e; //_clockSeqLow;
|
|
private byte _f; //_node0;
|
|
private byte _g; //_node1;
|
|
private byte _h; //_node2;
|
|
private byte _i; //_node3;
|
|
private byte _j; //_node4;
|
|
private byte _k; //_node5;
|
|
|
|
enum Format {
|
|
N, // 00000000000000000000000000000000
|
|
D, // 00000000-0000-0000-0000-000000000000
|
|
B, // {00000000-0000-0000-0000-000000000000}
|
|
P, // (00000000-0000-0000-0000-000000000000)
|
|
X, // {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
|
|
}
|
|
|
|
struct GuidParser
|
|
{
|
|
private string _src;
|
|
private int _length;
|
|
private int _cur;
|
|
|
|
public GuidParser (string src)
|
|
{
|
|
_src = src.Trim ();
|
|
_cur = 0;
|
|
_length = _src.Length;
|
|
}
|
|
|
|
void Reset ()
|
|
{
|
|
_cur = 0;
|
|
_length = _src.Length;
|
|
}
|
|
|
|
bool Eof {
|
|
get { return _cur >= _length; }
|
|
}
|
|
|
|
public static bool HasHyphen (Format format)
|
|
{
|
|
switch (format) {
|
|
case Format.D:
|
|
case Format.B:
|
|
case Format.P:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool TryParseNDBP (Format format, out Guid guid)
|
|
{
|
|
ulong a, b, c;
|
|
guid = new Guid ();
|
|
|
|
if (format == Format.B && !ParseChar ('{'))
|
|
return false;
|
|
|
|
if (format == Format.P && !ParseChar ('('))
|
|
return false;
|
|
|
|
if (!ParseHex (8, true, out a))
|
|
return false;
|
|
|
|
var has_hyphen = HasHyphen (format);
|
|
|
|
if (has_hyphen && !ParseChar ('-'))
|
|
return false;
|
|
|
|
if (!ParseHex (4, true, out b))
|
|
return false;
|
|
|
|
if (has_hyphen && !ParseChar ('-'))
|
|
return false;
|
|
|
|
if (!ParseHex (4, true, out c))
|
|
return false;
|
|
|
|
if (has_hyphen && !ParseChar ('-'))
|
|
return false;
|
|
|
|
var d = new byte [8];
|
|
for (int i = 0; i < d.Length; i++) {
|
|
ulong dd;
|
|
if (!ParseHex (2, true, out dd))
|
|
return false;
|
|
|
|
if (i == 1 && has_hyphen && !ParseChar ('-'))
|
|
return false;
|
|
|
|
d [i] = (byte) dd;
|
|
}
|
|
|
|
if (format == Format.B && !ParseChar ('}'))
|
|
return false;
|
|
|
|
if (format == Format.P && !ParseChar (')'))
|
|
return false;
|
|
|
|
if (!Eof)
|
|
return false;
|
|
|
|
guid = new Guid ((int) a, (short) b, (short) c, d);
|
|
return true;
|
|
}
|
|
|
|
bool TryParseX (out Guid guid)
|
|
{
|
|
ulong a, b, c;
|
|
guid = new Guid ();
|
|
|
|
if (!(ParseChar ('{')
|
|
&& ParseHexPrefix ()
|
|
&& ParseHex (8, false, out a)
|
|
&& ParseCharWithWhiteSpaces (',')
|
|
&& ParseHexPrefix ()
|
|
&& ParseHex (4, false, out b)
|
|
&& ParseCharWithWhiteSpaces (',')
|
|
&& ParseHexPrefix ()
|
|
&& ParseHex (4, false, out c)
|
|
&& ParseCharWithWhiteSpaces (',')
|
|
&& ParseCharWithWhiteSpaces ('{'))) {
|
|
|
|
return false;
|
|
}
|
|
|
|
var d = new byte [8];
|
|
for (int i = 0; i < d.Length; ++i) {
|
|
ulong dd;
|
|
|
|
if (!(ParseHexPrefix () && ParseHex (2, false, out dd)))
|
|
return false;
|
|
|
|
d [i] = (byte) dd;
|
|
|
|
if (i != 7 && !ParseCharWithWhiteSpaces (','))
|
|
return false;
|
|
}
|
|
|
|
if (!(ParseCharWithWhiteSpaces ('}') && ParseCharWithWhiteSpaces ('}')))
|
|
return false;
|
|
|
|
if (!Eof)
|
|
return false;
|
|
|
|
guid = new Guid ((int) a, (short) b, (short) c, d);
|
|
return true;
|
|
}
|
|
|
|
bool ParseHexPrefix ()
|
|
{
|
|
// It can be prefixed with whitespaces
|
|
for (; _cur < _length - 1; ++_cur) {
|
|
var ch = _src [_cur];
|
|
if (ch == '0') {
|
|
++_cur;
|
|
return _src [_cur++] == 'x';
|
|
}
|
|
|
|
if (!char.IsWhiteSpace (ch))
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ParseCharWithWhiteSpaces (char c)
|
|
{
|
|
while (!Eof) {
|
|
var ch = _src [_cur++];
|
|
if (ch == c)
|
|
return true;
|
|
|
|
if (!char.IsWhiteSpace (ch))
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ParseChar (char c)
|
|
{
|
|
if (!Eof && _src [_cur] == c) {
|
|
_cur++;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ParseHex (int length, bool strict, out ulong res)
|
|
{
|
|
res = 0;
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
if (Eof)
|
|
return !(strict && (i + 1 != length));
|
|
|
|
char c = _src [_cur];
|
|
if (Char.IsDigit (c)) {
|
|
res = res * 16 + c - '0';
|
|
_cur++;
|
|
continue;
|
|
}
|
|
|
|
if (c >= 'a' && c <= 'f') {
|
|
res = res * 16 + c - 'a' + 10;
|
|
_cur++;
|
|
continue;
|
|
}
|
|
|
|
if (c >= 'A' && c <= 'F') {
|
|
res = res * 16 + c - 'A' + 10;
|
|
_cur++;
|
|
continue;
|
|
}
|
|
|
|
if (!strict)
|
|
return true;
|
|
|
|
return false; //!(strict && (i + 1 != length));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool Parse (Format format, out Guid guid)
|
|
{
|
|
if (format == Format.X)
|
|
return TryParseX (out guid);
|
|
|
|
return TryParseNDBP (format, out guid);
|
|
}
|
|
|
|
public bool Parse (out Guid guid)
|
|
{
|
|
switch (_length) {
|
|
case 32:
|
|
if (TryParseNDBP (Format.N, out guid))
|
|
return true;
|
|
break;
|
|
case 36:
|
|
if (TryParseNDBP (Format.D, out guid))
|
|
return true;
|
|
break;
|
|
case 38:
|
|
switch (_src [0]) {
|
|
case '{':
|
|
if (TryParseNDBP (Format.B, out guid))
|
|
return true;
|
|
break;
|
|
case '(':
|
|
if (TryParseNDBP (Format.P, out guid))
|
|
return true;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
Reset ();
|
|
return TryParseX (out guid);
|
|
}
|
|
}
|
|
|
|
private static void CheckNull (object o)
|
|
{
|
|
if (o == null) {
|
|
throw new ArgumentNullException (Locale.GetText ("Value cannot be null."));
|
|
}
|
|
}
|
|
|
|
private static void CheckLength (byte[] o, int l)
|
|
{
|
|
if (o . Length != l) {
|
|
throw new ArgumentException (String.Format (Locale.GetText ("Array should be exactly {0} bytes long."), l));
|
|
}
|
|
}
|
|
|
|
private static void CheckArray (byte[] o, int l)
|
|
{
|
|
CheckNull (o);
|
|
CheckLength (o, l);
|
|
}
|
|
|
|
public Guid (byte[] b)
|
|
{
|
|
CheckArray (b, 16);
|
|
_a = Mono.Security.BitConverterLE.ToInt32 (b, 0);
|
|
_b = Mono.Security.BitConverterLE.ToInt16 (b, 4);
|
|
_c = Mono.Security.BitConverterLE.ToInt16 (b, 6);
|
|
_d = b [8];
|
|
_e = b [9];
|
|
_f = b [10];
|
|
_g = b [11];
|
|
_h = b [12];
|
|
_i = b [13];
|
|
_j = b [14];
|
|
_k = b [15];
|
|
}
|
|
|
|
public Guid (string g)
|
|
{
|
|
CheckNull (g);
|
|
Guid guid;
|
|
if (!new GuidParser (g).Parse (out guid))
|
|
throw CreateFormatException (g);
|
|
|
|
this = guid;
|
|
}
|
|
|
|
static Exception CreateFormatException (string s)
|
|
{
|
|
return new FormatException (string.Format ("Invalid Guid format: {0}", s));
|
|
}
|
|
|
|
public Guid (int a, short b, short c, byte[] d)
|
|
{
|
|
CheckArray (d, 8);
|
|
_a = (int) a;
|
|
_b = (short) b;
|
|
_c = (short) c;
|
|
_d = d [0];
|
|
_e = d [1];
|
|
_f = d [2];
|
|
_g = d [3];
|
|
_h = d [4];
|
|
_i = d [5];
|
|
_j = d [6];
|
|
_k = d [7];
|
|
}
|
|
|
|
public Guid (int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
|
|
{
|
|
_a = a;
|
|
_b = b;
|
|
_c = c;
|
|
_d = d;
|
|
_e = e;
|
|
_f = f;
|
|
_g = g;
|
|
_h = h;
|
|
_i = i;
|
|
_j = j;
|
|
_k = k;
|
|
}
|
|
|
|
[CLSCompliant (false)]
|
|
public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
|
|
: this((int) a, (short) b, (short) c, d, e, f, g, h, i, j, k)
|
|
{
|
|
}
|
|
|
|
public static readonly Guid Empty = new Guid (0,0,0,0,0,0,0,0,0,0,0);
|
|
|
|
private static int Compare (int x, int y)
|
|
{
|
|
return ((uint)x < (uint)y) ? -1 : 1;
|
|
}
|
|
|
|
public int CompareTo (object value)
|
|
{
|
|
if (value == null)
|
|
return 1;
|
|
|
|
if (!(value is Guid)) {
|
|
throw new ArgumentException ("value", Locale.GetText (
|
|
"Argument of System.Guid.CompareTo should be a Guid."));
|
|
}
|
|
|
|
return CompareTo ((Guid)value);
|
|
}
|
|
|
|
public override bool Equals (object o)
|
|
{
|
|
if (o is Guid)
|
|
return CompareTo ((Guid)o) == 0;
|
|
return false;
|
|
}
|
|
|
|
public int CompareTo (Guid value)
|
|
{
|
|
if (_a != value._a) {
|
|
return Compare (_a, value._a);
|
|
}
|
|
if (_b != value._b) {
|
|
return Compare (_b, value._b);
|
|
}
|
|
if (_c != value._c) {
|
|
return Compare (_c, value._c);
|
|
}
|
|
if (_d != value._d) {
|
|
return Compare (_d, value._d);
|
|
}
|
|
if (_e != value._e) {
|
|
return Compare (_e, value._e);
|
|
}
|
|
if (_f != value._f) {
|
|
return Compare (_f, value._f);
|
|
}
|
|
if (_g != value._g) {
|
|
return Compare (_g, value._g);
|
|
}
|
|
if (_h != value._h) {
|
|
return Compare (_h, value._h);
|
|
}
|
|
if (_i != value._i) {
|
|
return Compare (_i, value._i);
|
|
}
|
|
if (_j != value._j) {
|
|
return Compare (_j, value._j);
|
|
}
|
|
if (_k != value._k) {
|
|
return Compare (_k, value._k);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public bool Equals (Guid g)
|
|
{
|
|
return CompareTo (g) == 0;
|
|
}
|
|
|
|
public override int GetHashCode ()
|
|
{
|
|
int res;
|
|
|
|
res = (int) _a;
|
|
res = res ^ ((int) _b << 16 | _c);
|
|
res = res ^ ((int) _d << 24);
|
|
res = res ^ ((int) _e << 16);
|
|
res = res ^ ((int) _f << 8);
|
|
res = res ^ ((int) _g);
|
|
res = res ^ ((int) _h << 24);
|
|
res = res ^ ((int) _i << 16);
|
|
res = res ^ ((int) _j << 8);
|
|
res = res ^ ((int) _k);
|
|
|
|
return res;
|
|
}
|
|
|
|
private static char ToHex (int b)
|
|
{
|
|
return (char)((b<0xA)?('0' + b):('a' + b - 0xA));
|
|
}
|
|
|
|
#if !FULL_AOT_RUNTIME
|
|
private static object _rngAccess = new object ();
|
|
private static RandomNumberGenerator _rng;
|
|
private static RandomNumberGenerator _fastRng;
|
|
#endif
|
|
|
|
#if FULL_AOT_RUNTIME && !MONOTOUCH
|
|
// NSA approved random generator.
|
|
static void LameRandom (byte [] b)
|
|
{
|
|
var r = new Random ();
|
|
r.NextBytes (b);
|
|
}
|
|
#endif
|
|
|
|
// generated as per section 3.4 of the specification
|
|
public static Guid NewGuid ()
|
|
{
|
|
byte[] b = new byte [16];
|
|
#if !FULL_AOT_RUNTIME
|
|
// thread-safe access to the prng
|
|
lock (_rngAccess) {
|
|
if (_rng == null)
|
|
_rng = RandomNumberGenerator.Create ();
|
|
_rng.GetBytes (b);
|
|
}
|
|
#elif MONOTOUCH
|
|
Cryptor.GetRandom (b);
|
|
#else
|
|
LameRandom (b);
|
|
#endif
|
|
|
|
Guid res = new Guid (b);
|
|
// Mask in Variant 1-0 in Bit[7..6]
|
|
res._d = (byte) ((res._d & 0x3fu) | 0x80u);
|
|
// Mask in Version 4 (random based Guid) in Bits[15..13]
|
|
res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
|
|
|
|
return res;
|
|
}
|
|
|
|
#if !FULL_AOT_RUNTIME
|
|
// used in ModuleBuilder so mcs doesn't need to invoke
|
|
// CryptoConfig for simple assemblies.
|
|
internal static byte[] FastNewGuidArray ()
|
|
{
|
|
byte[] guid = new byte [16];
|
|
|
|
// thread-safe access to the prng
|
|
lock (_rngAccess) {
|
|
// if known, use preferred RNG
|
|
if (_rng != null)
|
|
_fastRng = _rng;
|
|
// else use hardcoded default RNG (bypassing CryptoConfig)
|
|
if (_fastRng == null)
|
|
_fastRng = new RNGCryptoServiceProvider ();
|
|
_fastRng.GetBytes (guid);
|
|
}
|
|
|
|
// Mask in Variant 1-0 in Bit[7..6]
|
|
guid [8] = (byte) ((guid [8] & 0x3f) | 0x80);
|
|
// Mask in Version 4 (random based Guid) in Bits[15..13]
|
|
guid [7] = (byte) ((guid [7] & 0x0f) | 0x40);
|
|
|
|
return guid;
|
|
}
|
|
#endif
|
|
public byte[] ToByteArray ()
|
|
{
|
|
byte[] res = new byte[16];
|
|
byte[] tmp;
|
|
int d = 0;
|
|
int s;
|
|
|
|
tmp = Mono.Security.BitConverterLE.GetBytes(_a);
|
|
for (s=0; s<4; ++s) {
|
|
res[d++] = tmp[s];
|
|
}
|
|
|
|
tmp = Mono.Security.BitConverterLE.GetBytes(_b);
|
|
for (s=0; s<2; ++s) {
|
|
res[d++] = tmp[s];
|
|
}
|
|
|
|
tmp = Mono.Security.BitConverterLE.GetBytes(_c);
|
|
for (s=0; s<2; ++s) {
|
|
res[d++] = tmp[s];
|
|
}
|
|
|
|
res[8] = _d;
|
|
res[9] = _e;
|
|
res[10] = _f;
|
|
res[11] = _g;
|
|
res[12] = _h;
|
|
res[13] = _i;
|
|
res[14] = _j;
|
|
res[15] = _k;
|
|
|
|
return res;
|
|
}
|
|
|
|
static void AppendInt (StringBuilder builder, int value) {
|
|
builder.Append (ToHex ((value >> 28) & 0xf));
|
|
builder.Append (ToHex ((value >> 24) & 0xf));
|
|
builder.Append (ToHex ((value >> 20) & 0xf));
|
|
builder.Append (ToHex ((value >> 16) & 0xf));
|
|
builder.Append (ToHex ((value >> 12) & 0xf));
|
|
builder.Append (ToHex ((value >> 8) & 0xf));
|
|
builder.Append (ToHex ((value >> 4) & 0xf));
|
|
builder.Append (ToHex (value & 0xf));
|
|
}
|
|
|
|
static void AppendShort (StringBuilder builder, short value) {
|
|
builder.Append (ToHex ((value >> 12) & 0xf));
|
|
builder.Append (ToHex ((value >> 8) & 0xf));
|
|
builder.Append (ToHex ((value >> 4) & 0xf));
|
|
builder.Append (ToHex (value & 0xf));
|
|
}
|
|
|
|
static void AppendByte (StringBuilder builder, byte value) {
|
|
builder.Append (ToHex ((value >> 4) & 0xf));
|
|
builder.Append (ToHex (value & 0xf));
|
|
}
|
|
|
|
string ToString (Format format)
|
|
{
|
|
int length;
|
|
switch (format) {
|
|
case Format.B:
|
|
case Format.P:
|
|
length = 38;
|
|
break;
|
|
case Format.D:
|
|
length = 36;
|
|
break;
|
|
case Format.N:
|
|
length = 32;
|
|
break;
|
|
case Format.X:
|
|
length = 68;
|
|
break;
|
|
default:
|
|
throw new NotImplementedException (format.ToString ());
|
|
}
|
|
|
|
StringBuilder res = new StringBuilder (length);
|
|
bool has_hyphen = GuidParser.HasHyphen (format);
|
|
|
|
if (format == Format.P) {
|
|
res.Append ('(');
|
|
} else if (format == Format.B) {
|
|
res.Append ('{');
|
|
} else if (format == Format.X) {
|
|
res.Append ('{').Append ('0').Append ('x');
|
|
}
|
|
|
|
AppendInt (res, _a);
|
|
if (has_hyphen) {
|
|
res.Append ('-');
|
|
} else if (format == Format.X) {
|
|
res.Append (',').Append ('0').Append ('x');
|
|
}
|
|
|
|
AppendShort (res, _b);
|
|
if (has_hyphen) {
|
|
res.Append ('-');
|
|
} else if (format == Format.X) {
|
|
res.Append (',').Append ('0').Append ('x');
|
|
}
|
|
|
|
AppendShort (res, _c);
|
|
if (has_hyphen) {
|
|
res.Append ('-');
|
|
}
|
|
|
|
if (format == Format.X) {
|
|
res.Append (',').Append ('{').Append ('0').Append ('x');
|
|
AppendByte (res, _d);
|
|
res.Append (',').Append ('0').Append ('x');
|
|
AppendByte (res, _e);
|
|
res.Append (',').Append ('0').Append ('x');
|
|
AppendByte (res, _f);
|
|
res.Append (',').Append ('0').Append ('x');
|
|
AppendByte (res, _g);
|
|
res.Append (',').Append ('0').Append ('x');
|
|
AppendByte (res, _h);
|
|
res.Append (',').Append ('0').Append ('x');
|
|
AppendByte (res, _i);
|
|
res.Append (',').Append ('0').Append ('x');
|
|
AppendByte (res, _j);
|
|
res.Append (',').Append ('0').Append ('x');
|
|
AppendByte (res, _k);
|
|
res.Append ('}').Append ('}');;
|
|
} else {
|
|
AppendByte (res, _d);
|
|
AppendByte (res, _e);
|
|
|
|
if (has_hyphen) {
|
|
res.Append ('-');
|
|
}
|
|
|
|
AppendByte (res, _f);
|
|
AppendByte (res, _g);
|
|
AppendByte (res, _h);
|
|
AppendByte (res, _i);
|
|
AppendByte (res, _j);
|
|
AppendByte (res, _k);
|
|
|
|
if (format == Format.P) {
|
|
res.Append (')');
|
|
} else if (format == Format.B) {
|
|
res.Append ('}');
|
|
}
|
|
}
|
|
|
|
return res.ToString ();
|
|
}
|
|
|
|
public override string ToString ()
|
|
{
|
|
return ToString (Format.D);
|
|
}
|
|
|
|
public string ToString (string format)
|
|
{
|
|
return ToString (ParseFormat (format));
|
|
}
|
|
|
|
// provider value is never used
|
|
public string ToString (string format, IFormatProvider provider)
|
|
{
|
|
return ToString (format);
|
|
}
|
|
|
|
public static bool operator == (Guid a, Guid b)
|
|
{
|
|
return a.Equals(b);
|
|
}
|
|
|
|
public static bool operator != (Guid a, Guid b)
|
|
{
|
|
return !( a.Equals (b) );
|
|
}
|
|
|
|
#if NET_4_0
|
|
public static Guid Parse (string input)
|
|
{
|
|
if (input == null)
|
|
throw new ArgumentNullException ("input");
|
|
|
|
Guid guid;
|
|
if (!TryParse (input, out guid))
|
|
throw CreateFormatException (input);
|
|
|
|
return guid;
|
|
}
|
|
|
|
public static Guid ParseExact (string input, string format)
|
|
{
|
|
if (input == null)
|
|
throw new ArgumentNullException ("input");
|
|
if (format == null)
|
|
throw new ArgumentNullException ("format");
|
|
|
|
Guid guid;
|
|
if (!TryParseExact (input, format, out guid))
|
|
throw CreateFormatException (input);
|
|
|
|
return guid;
|
|
}
|
|
|
|
public static bool TryParse (string input, out Guid result)
|
|
{
|
|
if (input == null) {
|
|
result = Empty;
|
|
return false;
|
|
}
|
|
|
|
var parser = new GuidParser (input);
|
|
return parser.Parse (out result);
|
|
}
|
|
|
|
public static bool TryParseExact (string input, string format, out Guid result)
|
|
{
|
|
if (input == null || format == null) {
|
|
result = Empty;
|
|
return false;
|
|
}
|
|
|
|
var parser = new GuidParser (input);
|
|
return parser.Parse (ParseFormat (format), out result);
|
|
}
|
|
#endif
|
|
|
|
static Format ParseFormat (string format)
|
|
{
|
|
if (string.IsNullOrEmpty (format))
|
|
return Format.D;
|
|
|
|
switch (format [0]) {
|
|
case 'N':
|
|
case 'n':
|
|
return Format.N;
|
|
case 'D':
|
|
case 'd':
|
|
return Format.D;
|
|
case 'B':
|
|
case 'b':
|
|
return Format.B;
|
|
case 'P':
|
|
case 'p':
|
|
return Format.P;
|
|
#if NET_4_0
|
|
case 'X':
|
|
case 'x':
|
|
return Format.X;
|
|
#endif
|
|
}
|
|
|
|
throw new FormatException (
|
|
#if NET_4_0
|
|
"Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\""
|
|
#else
|
|
"Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\" or \"b\""
|
|
#endif
|
|
);
|
|
}
|
|
}
|
|
}
|