Merge pull request #799 from kebby/master
[mono.git] / mcs / class / corlib / System / Guid.cs
1 //
2 // System.Guid.cs
3 //
4 // Authors:
5 //      Duco Fijma (duco@lorentz.xs4all.nl)
6 //      Sebastien Pouliot (sebastien@ximian.com)
7 //      Jb Evain (jbevain@novell.com)
8 //      Marek Safar (marek.safar@gmail.com)
9 //
10 // (C) 2002 Duco Fijma
11 // Copyright (C) 2004-2010 Novell, Inc (http://www.novell.com)
12 // Copyright 2012 Xamarin, Inc (http://www.xamarin.com)
13 //
14 // References
15 // 1.   UUIDs and GUIDs (DRAFT), Section 3.4
16 //      http://www.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01.txt 
17 //
18 // Permission is hereby granted, free of charge, to any person obtaining
19 // a copy of this software and associated documentation files (the
20 // "Software"), to deal in the Software without restriction, including
21 // without limitation the rights to use, copy, modify, merge, publish,
22 // distribute, sublicense, and/or sell copies of the Software, and to
23 // permit persons to whom the Software is furnished to do so, subject to
24 // the following conditions:
25 // 
26 // The above copyright notice and this permission notice shall be
27 // included in all copies or substantial portions of the Software.
28 // 
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 //
37
38 using System.Runtime.InteropServices;
39 using System.Security.Cryptography;
40 using System.Text;
41 #if MONOTOUCH && FULL_AOT_RUNTIME
42 using Crimson.CommonCrypto;
43 #endif
44
45 namespace System {
46
47         [Serializable]
48         [StructLayout (LayoutKind.Sequential)]
49         [ComVisible (true)]
50         public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid> {
51 #if MONOTOUCH
52                 static Guid () {
53                         if (MonoTouchAOTHelper.FalseFlag) {
54                                 var comparer = new System.Collections.Generic.GenericComparer <Guid> ();
55                                 var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <Guid> ();
56                         }
57                 }
58 #endif
59                 private int _a; //_timeLow;
60                 private short _b; //_timeMid;
61                 private short _c; //_timeHighAndVersion;
62                 private byte _d; //_clockSeqHiAndReserved;
63                 private byte _e; //_clockSeqLow;
64                 private byte _f; //_node0;
65                 private byte _g; //_node1;
66                 private byte _h; //_node2;
67                 private byte _i; //_node3;
68                 private byte _j; //_node4;
69                 private byte _k; //_node5;
70
71                 enum Format {
72                         N, // 00000000000000000000000000000000
73                         D, // 00000000-0000-0000-0000-000000000000
74                         B, // {00000000-0000-0000-0000-000000000000}
75                         P, // (00000000-0000-0000-0000-000000000000)
76                         X, // {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
77                 }
78
79                 struct GuidParser
80                 {
81                         private string _src;
82                         private int _length;
83                         private int _cur;
84
85                         public GuidParser (string src)
86                         {
87                                 _src = src;
88                                 _cur = 0;
89                                 _length = _src.Length;
90                         }
91
92                         void Reset ()
93                         {
94                                 _cur = 0;
95                                 _length = _src.Length;
96                         }
97
98                         bool Eof {
99                                 get { return _cur >= _length; }
100                         }
101
102                         public static bool HasHyphen (Format format)
103                         {
104                                 switch (format) {
105                                 case Format.D:
106                                 case Format.B:
107                                 case Format.P:
108                                         return true;
109                                 default:
110                                         return false;
111                                 }
112                         }
113
114                         bool TryParseNDBP (Format format, out Guid guid)
115                         {
116                                 ulong a, b, c;
117                                 guid = new Guid ();
118
119                                 if (format == Format.B && !ParseChar ('{'))
120                                         return false;
121
122                                 if (format == Format.P && !ParseChar ('('))
123                                         return false;
124
125                                 if (!ParseHex (8, true, out a))
126                                         return false;
127
128                                 var has_hyphen = HasHyphen (format);
129
130                                 if (has_hyphen && !ParseChar ('-'))
131                                         return false;
132
133                                 if (!ParseHex (4, true, out b))
134                                         return false;
135
136                                 if (has_hyphen && !ParseChar ('-'))
137                                         return false;
138
139                                 if (!ParseHex (4, true, out c))
140                                         return false;
141
142                                 if (has_hyphen && !ParseChar ('-'))
143                                         return false;
144
145                                 var d = new byte [8];
146                                 for (int i = 0; i < d.Length; i++) {
147                                         ulong dd;
148                                         if (!ParseHex (2, true, out dd))
149                                                 return false;
150
151                                         if (i == 1 && has_hyphen && !ParseChar ('-'))
152                                                 return false;
153
154                                         d [i] = (byte) dd;
155                                 }
156
157                                 if (format == Format.B && !ParseChar ('}'))
158                                         return false;
159
160                                 if (format == Format.P && !ParseChar (')'))
161                                         return false;
162
163                                 if (!Eof)
164                                         return false;
165
166                                 guid = new Guid ((int) a, (short) b, (short) c, d);
167                                 return true;
168                         }
169
170                         bool TryParseX (out Guid guid)
171                         {
172                                 ulong a, b, c;
173                                 guid = new Guid ();
174
175                                 if (!(ParseChar ('{')
176                                         && ParseHexPrefix ()
177                                         && ParseHex (8, false, out a)
178                                         && ParseChar (',')
179                                         && ParseHexPrefix ()
180                                         && ParseHex (4, false, out b)
181                                         && ParseChar (',')
182                                         && ParseHexPrefix ()
183                                         && ParseHex (4, false, out c)
184                                         && ParseChar (',')
185                                         && ParseChar ('{'))) {
186
187                                         return false;
188                                 }
189
190                                 var d = new byte [8];
191                                 for (int i = 0; i < d.Length; ++i) {
192                                         ulong dd;
193
194                                         if (!(ParseHexPrefix () && ParseHex (2, false, out dd)))
195                                                 return false;
196
197                                         d [i] = (byte) dd;
198
199                                         if (i != 7 && !ParseChar (','))
200                                                 return false;
201                                 }
202
203                                 if (!(ParseChar ('}') && ParseChar ('}')))
204                                         return false;
205
206                                 if (!Eof)
207                                         return false;
208
209                                 guid = new Guid ((int) a, (short) b, (short) c, d);
210                                 return true;
211                         }
212
213                         bool ParseHexPrefix ()
214                         {
215                                 if (!ParseChar ('0'))
216                                         return false;
217
218                                 return ParseChar ('x');
219                         }
220
221                         bool ParseChar (char c)
222                         {
223                                 if (!Eof && _src [_cur] == c) {
224                                         _cur++;
225                                         return true;
226                                 }
227
228                                 return false;
229                         }
230
231                         bool ParseHex (int length, bool strict, out ulong res)
232                         {
233                                 res = 0;
234
235                                 for (int i = 0; i < length; i++) {
236                                         if (Eof)
237                                                 return !(strict && (i + 1 != length));
238
239                                         char c = _src [_cur];
240                                         if (Char.IsDigit (c)) {
241                                                 res = res * 16 + c - '0';
242                                                 _cur++;
243                                                 continue;
244                                         }
245
246                                         if (c >= 'a' && c <= 'f') {
247                                                 res = res * 16 + c - 'a' + 10;
248                                                 _cur++;
249                                                 continue;
250                                         }
251
252                                         if (c >= 'A' && c <= 'F') {
253                                                 res = res * 16 + c - 'A' + 10;
254                                                 _cur++;
255                                                 continue;
256                                         }
257
258                                         if (!strict)
259                                                 return true;
260
261                                         return false; //!(strict && (i + 1 != length));
262                                 }
263
264                                 return true;
265                         }
266
267                         public bool Parse (Format format, out Guid guid)
268                         {
269                                 if (format == Format.X)
270                                         return TryParseX (out guid);
271
272                                 return TryParseNDBP (format, out guid);
273                         }
274
275                         public bool Parse (out Guid guid)
276                         {
277                                 switch (_length) {
278                                 case 32:
279                                         if (TryParseNDBP (Format.N, out guid))
280                                                 return true;
281                                         break;
282                                 case 36:
283                                         if (TryParseNDBP (Format.D, out guid))
284                                                 return true;
285                                         break;
286                                 case 38:
287                                         switch (_src [0]) {
288                                         case '{':
289                                                 if (TryParseNDBP (Format.B, out guid))
290                                                         return true;
291                                                 break;
292                                         case '(':
293                                                 if (TryParseNDBP (Format.P, out guid))
294                                                         return true;
295                                                 break;
296                                         }
297                                         break;
298                                 }
299
300                                 Reset ();
301                                 return TryParseX (out guid);
302                         }
303                 }
304
305                 private static void CheckNull (object o)
306                 {
307                         if (o == null) {
308                                 throw new ArgumentNullException (Locale.GetText ("Value cannot be null."));
309                         }
310                 }
311
312                 private static void CheckLength (byte[] o, int l)
313                 {
314                         if (o . Length != l) {
315                                 throw new ArgumentException (String.Format (Locale.GetText ("Array should be exactly {0} bytes long."), l));
316                         }
317                 }
318
319                 private static void CheckArray (byte[] o, int l)
320                 {
321                         CheckNull (o);
322                         CheckLength (o, l);
323                 }
324
325                 public Guid (byte[] b)
326                 {
327                         CheckArray (b, 16);
328                         _a = Mono.Security.BitConverterLE.ToInt32 (b, 0);
329                         _b = Mono.Security.BitConverterLE.ToInt16 (b, 4);
330                         _c = Mono.Security.BitConverterLE.ToInt16 (b, 6);
331                         _d = b [8];
332                         _e = b [9];
333                         _f = b [10];
334                         _g = b [11];
335                         _h = b [12];
336                         _i = b [13];
337                         _j = b [14];
338                         _k = b [15];
339                 }
340
341                 public Guid (string g)
342                 {
343                         CheckNull (g);
344                         g = g.Trim();
345                         var parser = new GuidParser (g);
346                         Guid guid;
347                         if (!parser.Parse (out guid))
348                                 throw CreateFormatException (g);
349
350                         this = guid;
351                 }
352
353                 static Exception CreateFormatException (string s)
354                 {
355                         return new FormatException (string.Format ("Invalid Guid format: {0}", s));
356                 }
357
358                 public Guid (int a, short b, short c, byte[] d)
359                 {
360                         CheckArray (d, 8);
361                         _a = (int) a;
362                         _b = (short) b;
363                         _c = (short) c;
364                         _d = d [0];
365                         _e = d [1];
366                         _f = d [2];
367                         _g = d [3];
368                         _h = d [4];
369                         _i = d [5];
370                         _j = d [6];
371                         _k = d [7];
372                 }
373
374                 public Guid (int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
375                 {
376                         _a = a;
377                         _b = b;
378                         _c = c;
379                         _d = d;
380                         _e = e;
381                         _f = f;
382                         _g = g;
383                         _h = h;
384                         _i = i;
385                         _j = j;
386                         _k = k;
387                 }
388
389                 [CLSCompliant (false)]
390                 public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
391                         : this((int) a, (short) b, (short) c, d, e, f, g, h, i, j, k)
392                 {
393                 }
394
395                 public static readonly Guid Empty = new Guid (0,0,0,0,0,0,0,0,0,0,0);
396
397                 private static int Compare (int x, int y)
398                 {
399                         return ((uint)x < (uint)y) ? -1 : 1;
400                 }
401
402                 public int CompareTo (object value)
403                 {
404                         if (value == null)
405                                 return 1;
406
407                         if (!(value is Guid)) {
408                                 throw new ArgumentException ("value", Locale.GetText (
409                                         "Argument of System.Guid.CompareTo should be a Guid."));
410                         }
411
412                         return CompareTo ((Guid)value);
413                 }
414
415                 public override bool Equals (object o)
416                 {
417                         if (o is Guid)
418                                 return CompareTo ((Guid)o) == 0;
419                         return false;
420                 }
421
422                 public int CompareTo (Guid value)
423                 {
424                         if (_a != value._a) {
425                                 return Compare (_a, value._a);
426                         }
427                         if (_b != value._b) {
428                                 return Compare (_b, value._b);
429                         }
430                         if (_c != value._c) {
431                                 return Compare (_c, value._c);
432                         }
433                         if (_d != value._d) {
434                                 return Compare (_d, value._d);
435                         }
436                         if (_e != value._e) {
437                                 return Compare (_e, value._e);
438                         }
439                         if (_f != value._f) {
440                                 return Compare (_f, value._f);
441                         }
442                         if (_g != value._g) {
443                                 return Compare (_g, value._g);
444                         }
445                         if (_h != value._h) {
446                                 return Compare (_h, value._h);
447                         }
448                         if (_i != value._i) {
449                                 return Compare (_i, value._i);
450                         }
451                         if (_j != value._j) {
452                                 return Compare (_j, value._j);
453                         }
454                         if (_k != value._k) {
455                                 return Compare (_k, value._k);
456                         }
457                         return 0;
458                 }
459
460                 public bool Equals (Guid g)
461                 {
462                         return CompareTo (g) == 0;
463                 }
464
465                 public override int GetHashCode ()
466                 {
467                         int res;
468         
469                         res = (int) _a; 
470                         res = res ^ ((int) _b << 16 | _c);
471                         res = res ^ ((int) _d << 24);
472                         res = res ^ ((int) _e << 16);
473                         res = res ^ ((int) _f << 8);
474                         res = res ^ ((int) _g);
475                         res = res ^ ((int) _h << 24);
476                         res = res ^ ((int) _i << 16);
477                         res = res ^ ((int) _j << 8);
478                         res = res ^ ((int) _k);
479
480                         return res;
481                 }
482
483                 private static char ToHex (int b)
484                 {
485                         return (char)((b<0xA)?('0' + b):('a' + b - 0xA));
486                 }
487
488 #if !FULL_AOT_RUNTIME
489                 private static object _rngAccess = new object ();
490                 private static RandomNumberGenerator _rng;
491                 private static RandomNumberGenerator _fastRng;
492 #endif
493
494 #if FULL_AOT_RUNTIME && !MONOTOUCH
495                 // NSA approved random generator.
496                 static void LameRandom (byte [] b)
497                 {
498                         var r = new Random ();
499                         r.NextBytes (b);
500                 }
501 #endif
502                 
503                 // generated as per section 3.4 of the specification
504                 public static Guid NewGuid ()
505                 {
506                         byte[] b = new byte [16];
507 #if !FULL_AOT_RUNTIME
508                         // thread-safe access to the prng
509                         lock (_rngAccess) {
510                                 if (_rng == null)
511                                         _rng = RandomNumberGenerator.Create ();
512                                 _rng.GetBytes (b);
513                         }
514 #elif MONOTOUCH
515                         Cryptor.GetRandom (b);
516 #else
517                         LameRandom (b);
518 #endif
519
520                         Guid res = new Guid (b);
521                         // Mask in Variant 1-0 in Bit[7..6]
522                         res._d = (byte) ((res._d & 0x3fu) | 0x80u);
523                         // Mask in Version 4 (random based Guid) in Bits[15..13]
524                         res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
525
526                         return res;
527                 }
528
529 #if !FULL_AOT_RUNTIME
530                 // used in ModuleBuilder so mcs doesn't need to invoke 
531                 // CryptoConfig for simple assemblies.
532                 internal static byte[] FastNewGuidArray ()
533                 {
534                         byte[] guid = new byte [16];
535
536                         // thread-safe access to the prng
537                         lock (_rngAccess) {
538                                 // if known, use preferred RNG
539                                 if (_rng != null)
540                                         _fastRng = _rng;
541                                 // else use hardcoded default RNG (bypassing CryptoConfig)
542                                 if (_fastRng == null)
543                                         _fastRng = new RNGCryptoServiceProvider ();
544                                 _fastRng.GetBytes (guid);
545                         }
546
547                         // Mask in Variant 1-0 in Bit[7..6]
548                         guid [8] = (byte) ((guid [8] & 0x3f) | 0x80);
549                         // Mask in Version 4 (random based Guid) in Bits[15..13]
550                         guid [7] = (byte) ((guid [7] & 0x0f) | 0x40);
551
552                         return guid;
553                 }
554 #endif
555                 public byte[] ToByteArray ()
556                 {
557                         byte[] res = new byte[16];
558                         byte[] tmp;
559                         int d = 0;
560                         int s;
561
562                         tmp = Mono.Security.BitConverterLE.GetBytes(_a);
563                         for (s=0; s<4; ++s) {
564                                 res[d++] = tmp[s];
565                         }
566
567                         tmp = Mono.Security.BitConverterLE.GetBytes(_b);
568                         for (s=0; s<2; ++s) {
569                                 res[d++] = tmp[s];
570                         }
571
572                         tmp = Mono.Security.BitConverterLE.GetBytes(_c);
573                         for (s=0; s<2; ++s) {
574                                 res[d++] = tmp[s];
575                         }
576
577                         res[8] = _d;
578                         res[9] = _e;
579                         res[10] = _f;
580                         res[11] = _g;
581                         res[12] = _h;
582                         res[13] = _i;
583                         res[14] = _j;
584                         res[15] = _k;
585
586                         return res;
587                 }
588
589                 static void AppendInt (StringBuilder builder, int value) {
590                         builder.Append (ToHex ((value >> 28) & 0xf));
591                         builder.Append (ToHex ((value >> 24) & 0xf));
592                         builder.Append (ToHex ((value >> 20) & 0xf));
593                         builder.Append (ToHex ((value >> 16) & 0xf));
594                         builder.Append (ToHex ((value >> 12) & 0xf));
595                         builder.Append (ToHex ((value >> 8) & 0xf));
596                         builder.Append (ToHex ((value >> 4) & 0xf));
597                         builder.Append (ToHex (value & 0xf));
598                 }
599
600                 static void AppendShort (StringBuilder builder, short value) {
601                         builder.Append (ToHex ((value >> 12) & 0xf));
602                         builder.Append (ToHex ((value >> 8) & 0xf));
603                         builder.Append (ToHex ((value >> 4) & 0xf));
604                         builder.Append (ToHex (value & 0xf));
605                 }
606
607                 static void AppendByte (StringBuilder builder, byte value) {
608                         builder.Append (ToHex ((value >> 4) & 0xf));
609                         builder.Append (ToHex (value & 0xf));
610                 }
611
612                 string ToString (Format format)
613                 {
614                         int length;
615                         switch (format) {
616                         case Format.B:
617                         case Format.P:
618                                 length = 38;
619                                 break;
620                         case Format.D:
621                                 length = 36;
622                                 break;
623                         case Format.N:
624                                 length = 32;
625                                 break;
626                         case Format.X:
627                                 length = 68;
628                                 break;          
629                         default:
630                                 throw new NotImplementedException (format.ToString ());
631                         }
632                         
633                         StringBuilder res = new StringBuilder (length);
634                         bool has_hyphen = GuidParser.HasHyphen (format);
635                         
636                         if (format == Format.P) {
637                                 res.Append ('(');
638                         } else if (format == Format.B) {
639                                 res.Append ('{');
640                         } else if (format == Format.X) {
641                                 res.Append ('{').Append ('0').Append ('x');
642                         }
643                 
644                         AppendInt (res, _a);
645                         if (has_hyphen) {
646                                 res.Append ('-');
647                         } else if (format == Format.X) {
648                                 res.Append (',').Append ('0').Append ('x');
649                         }
650                         
651                         AppendShort (res, _b);
652                         if (has_hyphen) {
653                                 res.Append ('-');
654                         } else if (format == Format.X) {
655                                 res.Append (',').Append ('0').Append ('x');
656                         }
657
658                         AppendShort (res, _c);
659                         if (has_hyphen) {
660                                 res.Append ('-');
661                         }
662         
663                         if (format == Format.X) {
664                                 res.Append (',').Append ('{').Append ('0').Append ('x');
665                                 AppendByte (res, _d);
666                                 res.Append (',').Append ('0').Append ('x');
667                                 AppendByte (res, _e);
668                                 res.Append (',').Append ('0').Append ('x');
669                                 AppendByte (res, _f);
670                                 res.Append (',').Append ('0').Append ('x');
671                                 AppendByte (res, _g);
672                                 res.Append (',').Append ('0').Append ('x');
673                                 AppendByte (res, _h);
674                                 res.Append (',').Append ('0').Append ('x');
675                                 AppendByte (res, _i);
676                                 res.Append (',').Append ('0').Append ('x');
677                                 AppendByte (res, _j);
678                                 res.Append (',').Append ('0').Append ('x');
679                                 AppendByte (res, _k);
680                                 res.Append ('}').Append ('}');;
681                         } else {
682                                 AppendByte (res, _d);
683                                 AppendByte (res, _e);
684         
685                                 if (has_hyphen) {
686                                         res.Append ('-');
687                                 }
688         
689                                 AppendByte (res, _f);
690                                 AppendByte (res, _g);
691                                 AppendByte (res, _h);
692                                 AppendByte (res, _i);
693                                 AppendByte (res, _j);
694                                 AppendByte (res, _k);
695         
696                                 if (format == Format.P) {
697                                         res.Append (')');
698                                 } else if (format == Format.B) {
699                                         res.Append ('}');
700                                 }
701                         }
702                 
703                         return res.ToString ();
704                 }
705         
706                 public override string ToString ()
707                 {
708                         return ToString (Format.D);
709                 }
710         
711                 public string ToString (string format)
712                 {
713                         return ToString (ParseFormat (format));
714                 }
715
716                 // provider value is never used
717                 public string ToString (string format, IFormatProvider provider)
718                 {
719                         return ToString (format);
720                 }
721
722                 public static bool operator == (Guid a, Guid b)
723                 {
724                         return a.Equals(b);
725                 }
726
727                 public static bool operator != (Guid a, Guid b)
728                 {
729                         return !( a.Equals (b) );
730                 }
731
732 #if NET_4_0
733                 public static Guid Parse (string input)
734                 {
735                         if (input == null)
736                                 throw new ArgumentNullException ("input");
737
738                         Guid guid;
739                         if (!TryParse (input, out guid))
740                                 throw CreateFormatException (input);
741
742                         return guid;
743                 }
744
745                 public static Guid ParseExact (string input, string format)
746                 {
747                         if (input == null)
748                                 throw new ArgumentNullException ("input");
749                         if (format == null)
750                                 throw new ArgumentNullException ("format");
751
752                         Guid guid;
753                         if (!TryParseExact (input, format, out guid))
754                                 throw CreateFormatException (input);
755
756                         return guid;
757                 }
758
759                 public static bool TryParse (string input, out Guid result)
760                 {
761                         if (input == null) {
762                                 result = Empty;
763                                 return false;
764                         }
765
766                         var parser = new GuidParser (input);
767                         return parser.Parse (out result);
768                 }
769
770                 public static bool TryParseExact (string input, string format, out Guid result)
771                 {
772                         if (input == null || format == null) {
773                                 result = Empty;
774                                 return false;
775                         }
776
777                         var parser = new GuidParser (input);
778                         return parser.Parse (ParseFormat (format), out result);
779                 }
780 #endif
781
782                 static Format ParseFormat (string format)
783                 {
784                         if (string.IsNullOrEmpty (format))
785                                 return Format.D;
786                         
787                         switch (format [0]) {
788                         case 'N':
789                         case 'n':
790                                 return Format.N;
791                         case 'D':
792                         case 'd':
793                                 return Format.D;
794                         case 'B':
795                         case 'b':
796                                 return Format.B;
797                         case 'P':
798                         case 'p':
799                                 return Format.P;
800 #if NET_4_0
801                         case 'X':
802                         case 'x':
803                                 return Format.X;
804 #endif
805                         }
806
807                         throw new FormatException (
808 #if NET_4_0
809                                 "Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\""
810 #else
811                                 "Format String can be only one of \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\" or \"b\""
812 #endif
813                                 );
814                 }
815         }
816 }