1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 namespace System {
7 
8     using System;
9     using System.Globalization;
10     using System.Text;
11     using Microsoft.Win32;
12     using System.Runtime.InteropServices;
13     using System.Runtime.CompilerServices;
14     using System.Diagnostics.Contracts;
15 
16     // Represents a Globally Unique Identifier.
17     [StructLayout(LayoutKind.Sequential)]
18     [Serializable]
19 [System.Runtime.InteropServices.ComVisible(true)]
20     [System.Runtime.Versioning.NonVersionable] // This only applies to field layout
21     public partial struct Guid : IFormattable, IComparable
22 #if GENERICS_WORK
23         , IComparable<Guid>, IEquatable<Guid>
24 #endif
25     {
26         public static readonly Guid Empty = new Guid();
27         ////////////////////////////////////////////////////////////////////////////////
28         //  Member variables
29         ////////////////////////////////////////////////////////////////////////////////
30         private int         _a;
31         private short       _b;
32         private short       _c;
33         private byte       _d;
34         private byte       _e;
35         private byte       _f;
36         private byte       _g;
37         private byte       _h;
38         private byte       _i;
39         private byte       _j;
40         private byte       _k;
41 
42 
43 
44         ////////////////////////////////////////////////////////////////////////////////
45         //  Constructors
46         ////////////////////////////////////////////////////////////////////////////////
47 
48         // Creates a new guid from an array of bytes.
49         //
GuidSystem.Guid50         public Guid(byte[] b)
51         {
52             if (b==null)
53                 throw new ArgumentNullException("b");
54             if (b.Length != 16)
55                 throw new ArgumentException(Environment.GetResourceString("Arg_GuidArrayCtor", "16"));
56             Contract.EndContractBlock();
57 
58             _a = ((int)b[3] << 24) | ((int)b[2] << 16) | ((int)b[1] << 8) | b[0];
59             _b = (short)(((int)b[5] << 8) | b[4]);
60             _c = (short)(((int)b[7] << 8) | b[6]);
61             _d = b[8];
62             _e = b[9];
63             _f = b[10];
64             _g = b[11];
65             _h = b[12];
66             _i = b[13];
67             _j = b[14];
68             _k = b[15];
69         }
70 
71         [CLSCompliant(false)]
GuidSystem.Guid72         public Guid (uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
73         {
74             _a = (int)a;
75             _b = (short)b;
76             _c = (short)c;
77             _d = d;
78             _e = e;
79             _f = f;
80             _g = g;
81             _h = h;
82             _i = i;
83             _j = j;
84             _k = k;
85         }
86 
87 
88         // Creates a new GUID initialized to the value represented by the arguments.
89         //
GuidSystem.Guid90         public Guid(int a, short b, short c, byte[] d)
91         {
92             if (d==null)
93                 throw new ArgumentNullException("d");
94             // Check that array is not too big
95             if(d.Length != 8)
96                 throw new ArgumentException(Environment.GetResourceString("Arg_GuidArrayCtor", "8"));
97             Contract.EndContractBlock();
98 
99             _a  = a;
100             _b  = b;
101             _c  = c;
102             _d = d[0];
103             _e = d[1];
104             _f = d[2];
105             _g = d[3];
106             _h = d[4];
107             _i = d[5];
108             _j = d[6];
109             _k = d[7];
110         }
111 
112         // Creates a new GUID initialized to the value represented by the
113         // arguments.  The bytes are specified like this to avoid endianness issues.
114         //
GuidSystem.Guid115         public Guid(int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
116         {
117             _a = a;
118             _b = b;
119             _c = c;
120             _d = d;
121             _e = e;
122             _f = f;
123             _g = g;
124             _h = h;
125             _i = i;
126             _j = j;
127             _k = k;
128         }
129 
130         [Flags]
131         private enum GuidStyles {
132             None                  = 0x00000000,
133             AllowParenthesis      = 0x00000001, //Allow the guid to be enclosed in parens
134             AllowBraces           = 0x00000002, //Allow the guid to be enclosed in braces
135             AllowDashes           = 0x00000004, //Allow the guid to contain dash group separators
136             AllowHexPrefix        = 0x00000008, //Allow the guid to contain {0xdd,0xdd}
137             RequireParenthesis    = 0x00000010, //Require the guid to be enclosed in parens
138             RequireBraces         = 0x00000020, //Require the guid to be enclosed in braces
139             RequireDashes         = 0x00000040, //Require the guid to contain dash group separators
140             RequireHexPrefix      = 0x00000080, //Require the guid to contain {0xdd,0xdd}
141 
142             HexFormat             = RequireBraces | RequireHexPrefix,                      /* X */
143             NumberFormat          = None,                                                  /* N */
144             DigitFormat           = RequireDashes,                                         /* D */
145             BraceFormat           = RequireBraces | RequireDashes,                         /* B */
146             ParenthesisFormat     = RequireParenthesis | RequireDashes,                    /* P */
147 
148             Any                   = AllowParenthesis | AllowBraces | AllowDashes | AllowHexPrefix,
149         }
150         private enum GuidParseThrowStyle {
151             None                     = 0,
152             All                      = 1,
153             AllButOverflow           = 2
154         }
155         private enum ParseFailureKind {
156             None                     = 0,
157             ArgumentNull             = 1,
158             Format                   = 2,
159             FormatWithParameter      = 3,
160             NativeException          = 4,
161             FormatWithInnerException = 5
162         }
163 
164         // This will store the result of the parsing.  And it will eventually be used to construct a Guid instance.
165         private struct GuidResult {
166             internal Guid parsedGuid;
167             internal GuidParseThrowStyle throwStyle;
168 
169             internal ParseFailureKind m_failure;
170             internal string m_failureMessageID;
171             internal object m_failureMessageFormatArgument;
172             internal string m_failureArgumentName;
173             internal Exception m_innerException;
174 
InitSystem.Guid.GuidResult175             internal void Init(GuidParseThrowStyle canThrow) {
176                 parsedGuid = Guid.Empty;
177                 throwStyle = canThrow;
178             }
SetFailureSystem.Guid.GuidResult179             internal void SetFailure(Exception nativeException) {
180                 m_failure = ParseFailureKind.NativeException;
181                 m_innerException = nativeException;
182             }
SetFailureSystem.Guid.GuidResult183             internal void SetFailure(ParseFailureKind failure, string failureMessageID) {
184                 SetFailure(failure, failureMessageID, null, null, null);
185             }
SetFailureSystem.Guid.GuidResult186             internal void SetFailure(ParseFailureKind failure, string failureMessageID, object failureMessageFormatArgument) {
187                 SetFailure(failure, failureMessageID, failureMessageFormatArgument, null, null);
188             }
SetFailureSystem.Guid.GuidResult189             internal void SetFailure(ParseFailureKind failure, string failureMessageID, object failureMessageFormatArgument,
190                                      string failureArgumentName, Exception innerException) {
191                 Contract.Assert(failure != ParseFailureKind.NativeException, "ParseFailureKind.NativeException should not be used with this overload");
192                 m_failure = failure;
193                 m_failureMessageID = failureMessageID;
194                 m_failureMessageFormatArgument = failureMessageFormatArgument;
195                 m_failureArgumentName = failureArgumentName;
196                 m_innerException = innerException;
197                 if (throwStyle != GuidParseThrowStyle.None) {
198                     throw GetGuidParseException();
199                 }
200             }
201 
GetGuidParseExceptionSystem.Guid.GuidResult202             internal Exception GetGuidParseException() {
203                 switch (m_failure) {
204                 case ParseFailureKind.ArgumentNull:
205                     return new ArgumentNullException(m_failureArgumentName, Environment.GetResourceString(m_failureMessageID));
206 
207                 case ParseFailureKind.FormatWithInnerException:
208                     return new FormatException(Environment.GetResourceString(m_failureMessageID), m_innerException);
209 
210                 case ParseFailureKind.FormatWithParameter:
211                     return new FormatException(Environment.GetResourceString(m_failureMessageID, m_failureMessageFormatArgument));
212 
213                 case ParseFailureKind.Format:
214                     return new FormatException(Environment.GetResourceString(m_failureMessageID));
215 
216                 case ParseFailureKind.NativeException:
217                     return m_innerException;
218 
219                 default:
220                     Contract.Assert(false, "Unknown GuidParseFailure: " + m_failure);
221                     return new FormatException(Environment.GetResourceString("Format_GuidUnrecognized"));
222                 }
223             }
224         }
225 
226         // Creates a new guid based on the value in the string.  The value is made up
227         // of hex digits speared by the dash ("-"). The string may begin and end with
228         // brackets ("{", "}").
229         //
230         // The string must be of the form dddddddd-dddd-dddd-dddd-dddddddddddd. where
231         // d is a hex digit. (That is 8 hex digits, followed by 4, then 4, then 4,
232         // then 12) such as: "CA761232-ED42-11CE-BACD-00AA0057B223"
233         //
GuidSystem.Guid234         public Guid(String g)
235         {
236             if (g==null) {
237                 throw new ArgumentNullException("g");
238             }
239             Contract.EndContractBlock();
240             this = Guid.Empty;
241 
242             GuidResult result = new GuidResult();
243             result.Init(GuidParseThrowStyle.All);
244             if (TryParseGuid(g, GuidStyles.Any, ref result)) {
245                 this = result.parsedGuid;
246             }
247             else {
248                 throw result.GetGuidParseException();
249             }
250         }
251 
252 
ParseSystem.Guid253         public static Guid Parse(String input)
254         {
255             if (input == null) {
256                 throw new ArgumentNullException("input");
257             }
258             Contract.EndContractBlock();
259 
260             GuidResult result = new GuidResult();
261             result.Init(GuidParseThrowStyle.AllButOverflow);
262             if (TryParseGuid(input, GuidStyles.Any, ref result)) {
263                 return result.parsedGuid;
264             }
265             else {
266                 throw result.GetGuidParseException();
267             }
268         }
269 
TryParseSystem.Guid270         public static bool TryParse(String input, out Guid result)
271         {
272             GuidResult parseResult = new GuidResult();
273             parseResult.Init(GuidParseThrowStyle.None);
274             if (TryParseGuid(input, GuidStyles.Any, ref parseResult)) {
275                 result = parseResult.parsedGuid;
276                 return true;
277             }
278             else {
279                 result = Guid.Empty;
280                 return false;
281             }
282         }
283 
ParseExactSystem.Guid284         public static Guid ParseExact(String input, String format)
285         {
286             if (input == null)
287                 throw new ArgumentNullException("input");
288 
289             if (format == null)
290                 throw new ArgumentNullException("format");
291 
292             if( format.Length != 1) {
293                 // all acceptable format strings are of length 1
294                 throw new FormatException(Environment.GetResourceString("Format_InvalidGuidFormatSpecification"));
295             }
296 
297             GuidStyles style;
298             char formatCh = format[0];
299             if (formatCh == 'D' || formatCh == 'd') {
300                 style = GuidStyles.DigitFormat;
301             }
302             else if (formatCh == 'N' || formatCh == 'n') {
303                 style = GuidStyles.NumberFormat;
304             }
305             else if (formatCh == 'B' || formatCh == 'b') {
306                 style = GuidStyles.BraceFormat;
307             }
308             else if (formatCh == 'P' || formatCh == 'p') {
309                 style = GuidStyles.ParenthesisFormat;
310             }
311             else if (formatCh == 'X' || formatCh == 'x') {
312                 style = GuidStyles.HexFormat;
313             }
314             else {
315                 throw new FormatException(Environment.GetResourceString("Format_InvalidGuidFormatSpecification"));
316             }
317 
318             GuidResult result = new GuidResult();
319             result.Init(GuidParseThrowStyle.AllButOverflow);
320             if (TryParseGuid(input, style, ref result)) {
321                 return result.parsedGuid;
322             }
323             else {
324                 throw result.GetGuidParseException();
325             }
326         }
327 
TryParseExactSystem.Guid328         public static bool TryParseExact(String input, String format, out Guid result)
329         {
330             if (format == null || format.Length != 1) {
331                 result = Guid.Empty;
332                 return false;
333             }
334 
335             GuidStyles style;
336             char formatCh = format[0];
337 
338             if (formatCh == 'D' || formatCh == 'd') {
339                 style = GuidStyles.DigitFormat;
340             }
341             else if (formatCh == 'N' || formatCh == 'n') {
342                 style = GuidStyles.NumberFormat;
343             }
344             else if (formatCh == 'B' || formatCh == 'b') {
345                 style = GuidStyles.BraceFormat;
346             }
347             else if (formatCh == 'P' || formatCh == 'p') {
348                 style = GuidStyles.ParenthesisFormat;
349             }
350             else if (formatCh == 'X' || formatCh == 'x') {
351                 style = GuidStyles.HexFormat;
352             }
353             else {
354                 // invalid guid format specification
355                 result = Guid.Empty;
356                 return false;
357             }
358 
359             GuidResult parseResult = new GuidResult();
360             parseResult.Init(GuidParseThrowStyle.None);
361             if (TryParseGuid(input, style, ref parseResult)) {
362                 result = parseResult.parsedGuid;
363                 return true;
364             }
365             else {
366                 result = Guid.Empty;
367                 return false;
368             }
369         }
370 
371 
TryParseGuidSystem.Guid372         private static bool TryParseGuid(String g, GuidStyles flags, ref GuidResult result)
373         {
374             if (g == null) {
375                 result.SetFailure(ParseFailureKind.Format, "Format_GuidUnrecognized");
376                 return false;
377             }
378             String guidString = g.Trim();  //Remove Whitespace
379 
380             if (guidString.Length == 0) {
381                 result.SetFailure(ParseFailureKind.Format, "Format_GuidUnrecognized");
382                 return false;
383             }
384 
385             // Check for dashes
386             bool dashesExistInString = (guidString.IndexOf('-', 0) >= 0);
387 
388             if (dashesExistInString) {
389                 if ((flags & (GuidStyles.AllowDashes | GuidStyles.RequireDashes)) == 0) {
390                     // dashes are not allowed
391                     result.SetFailure(ParseFailureKind.Format, "Format_GuidUnrecognized");
392                     return false;
393                 }
394             }
395             else {
396                 if ((flags & GuidStyles.RequireDashes) != 0) {
397                     // dashes are required
398                     result.SetFailure(ParseFailureKind.Format, "Format_GuidUnrecognized");
399                     return false;
400                 }
401             }
402 
403             // Check for braces
404             bool bracesExistInString = (guidString.IndexOf('{', 0) >= 0);
405 
406             if (bracesExistInString) {
407                 if ((flags & (GuidStyles.AllowBraces | GuidStyles.RequireBraces)) == 0) {
408                     // braces are not allowed
409                     result.SetFailure(ParseFailureKind.Format, "Format_GuidUnrecognized");
410                     return false;
411                 }
412             }
413             else {
414                 if ((flags & GuidStyles.RequireBraces) != 0) {
415                     // braces are required
416                     result.SetFailure(ParseFailureKind.Format, "Format_GuidUnrecognized");
417                     return false;
418                 }
419             }
420 
421             // Check for parenthesis
422             bool parenthesisExistInString = (guidString.IndexOf('(', 0) >= 0);
423 
424             if (parenthesisExistInString) {
425                 if ((flags & (GuidStyles.AllowParenthesis | GuidStyles.RequireParenthesis)) == 0) {
426                     // parenthesis are not allowed
427                     result.SetFailure(ParseFailureKind.Format, "Format_GuidUnrecognized");
428                     return false;
429                 }
430             }
431             else {
432                 if ((flags & GuidStyles.RequireParenthesis) != 0) {
433                     // parenthesis are required
434                     result.SetFailure(ParseFailureKind.Format, "Format_GuidUnrecognized");
435                     return false;
436                 }
437             }
438 
439             try {
440                 // let's get on with the parsing
441                 if (dashesExistInString) {
442                     // Check if it's of the form [{|(]dddddddd-dddd-dddd-dddd-dddddddddddd[}|)]
443                     return TryParseGuidWithDashes(guidString, ref result);
444                 }
445                 else if (bracesExistInString) {
446                     // Check if it's of the form {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}
447                     return TryParseGuidWithHexPrefix(guidString, ref result);
448                 }
449                 else {
450                     // Check if it's of the form dddddddddddddddddddddddddddddddd
451                     return TryParseGuidWithNoStyle(guidString, ref result);
452                 }
453             }
454             catch(IndexOutOfRangeException ex) {
455                 result.SetFailure(ParseFailureKind.FormatWithInnerException, "Format_GuidUnrecognized", null, null, ex);
456                 return false;
457             }
458             catch (ArgumentException ex) {
459                 result.SetFailure(ParseFailureKind.FormatWithInnerException, "Format_GuidUnrecognized", null, null, ex);
460                 return false;
461             }
462         }
463 
464 
465         // Check if it's of the form {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}
TryParseGuidWithHexPrefixSystem.Guid466         private static bool TryParseGuidWithHexPrefix(String guidString, ref GuidResult result) {
467             int numStart = 0;
468             int numLen = 0;
469 
470             // Eat all of the whitespace
471             guidString = EatAllWhitespace(guidString);
472 
473             // Check for leading '{'
474             if(String.IsNullOrEmpty(guidString) || guidString[0] != '{') {
475                 result.SetFailure(ParseFailureKind.Format, "Format_GuidBrace");
476                 return false;
477             }
478 
479             // Check for '0x'
480             if(!IsHexPrefix(guidString, 1)) {
481                 result.SetFailure(ParseFailureKind.Format, "Format_GuidHexPrefix", "{0xdddddddd, etc}");
482                 return false;
483             }
484 
485             // Find the end of this hex number (since it is not fixed length)
486             numStart = 3;
487             numLen = guidString.IndexOf(',', numStart) - numStart;
488             if(numLen <= 0) {
489                 result.SetFailure(ParseFailureKind.Format, "Format_GuidComma");
490                 return false;
491             }
492 
493 
494             if (!StringToInt(guidString.Substring(numStart, numLen) /*first DWORD*/, -1, ParseNumbers.IsTight, out result.parsedGuid._a, ref result))
495                 return false;
496 
497             // Check for '0x'
498             if(!IsHexPrefix(guidString, numStart+numLen+1)) {
499                 result.SetFailure(ParseFailureKind.Format, "Format_GuidHexPrefix", "{0xdddddddd, 0xdddd, etc}");
500                 return false;
501             }
502             // +3 to get by ',0x'
503             numStart = numStart + numLen + 3;
504             numLen = guidString.IndexOf(',', numStart) - numStart;
505             if(numLen <= 0) {
506                 result.SetFailure(ParseFailureKind.Format, "Format_GuidComma");
507                 return false;
508             }
509 
510             // Read in the number
511             if (!StringToShort(guidString.Substring(numStart, numLen) /*first DWORD*/, -1, ParseNumbers.IsTight, out result.parsedGuid._b, ref result))
512                 return false;
513             // Check for '0x'
514             if(!IsHexPrefix(guidString, numStart+numLen+1)) {
515                 result.SetFailure(ParseFailureKind.Format, "Format_GuidHexPrefix", "{0xdddddddd, 0xdddd, 0xdddd, etc}");
516                 return false;
517             }
518             // +3 to get by ',0x'
519             numStart = numStart + numLen + 3;
520             numLen = guidString.IndexOf(',', numStart) - numStart;
521             if(numLen <= 0) {
522                 result.SetFailure(ParseFailureKind.Format, "Format_GuidComma");
523                 return false;
524             }
525 
526             // Read in the number
527             if (!StringToShort(guidString.Substring(numStart, numLen) /*first DWORD*/, -1, ParseNumbers.IsTight, out result.parsedGuid._c, ref result))
528                 return false;
529 
530             // Check for '{'
531             if(guidString.Length <= numStart+numLen+1 || guidString[numStart+numLen+1] != '{') {
532                 result.SetFailure(ParseFailureKind.Format, "Format_GuidBrace");
533                 return false;
534             }
535 
536             // Prepare for loop
537             numLen++;
538             byte[] bytes = new byte[8];
539 
540             for(int i = 0; i < 8; i++)
541             {
542                 // Check for '0x'
543                 if(!IsHexPrefix(guidString, numStart+numLen+1)) {
544                     result.SetFailure(ParseFailureKind.Format, "Format_GuidHexPrefix", "{... { ... 0xdd, ...}}");
545                     return false;
546                 }
547 
548                 // +3 to get by ',0x' or '{0x' for first case
549                 numStart = numStart + numLen + 3;
550 
551                 // Calculate number length
552                 if(i < 7)  // first 7 cases
553                 {
554                     numLen = guidString.IndexOf(',', numStart) - numStart;
555                     if(numLen <= 0) {
556                         result.SetFailure(ParseFailureKind.Format, "Format_GuidComma");
557                         return false;
558                     }
559                 }
560                 else       // last case ends with '}', not ','
561                 {
562                     numLen = guidString.IndexOf('}', numStart) - numStart;
563                     if(numLen <= 0) {
564                         result.SetFailure(ParseFailureKind.Format, "Format_GuidBraceAfterLastNumber");
565                         return false;
566                     }
567                 }
568 
569                 // Read in the number
570                 uint number = (uint)Convert.ToInt32(guidString.Substring(numStart, numLen),16);
571                 // check for overflow
572                 if(number > 255) {
573                     result.SetFailure(ParseFailureKind.Format, "Overflow_Byte");
574                     return false;
575                 }
576                 bytes[i] = (byte)number;
577             }
578 
579             result.parsedGuid._d = bytes[0];
580             result.parsedGuid._e = bytes[1];
581             result.parsedGuid._f = bytes[2];
582             result.parsedGuid._g = bytes[3];
583             result.parsedGuid._h = bytes[4];
584             result.parsedGuid._i = bytes[5];
585             result.parsedGuid._j = bytes[6];
586             result.parsedGuid._k = bytes[7];
587 
588             // Check for last '}'
589             if(numStart+numLen+1 >= guidString.Length || guidString[numStart+numLen+1] != '}') {
590                 result.SetFailure(ParseFailureKind.Format, "Format_GuidEndBrace");
591                 return false;
592             }
593 
594             // Check if we have extra characters at the end
595             if( numStart+numLen+1 != guidString.Length -1) {
596                 result.SetFailure(ParseFailureKind.Format, "Format_ExtraJunkAtEnd");
597                 return false;
598             }
599 
600             return true;
601         }
602 
603         // Check if it's of the form dddddddddddddddddddddddddddddddd
TryParseGuidWithNoStyleSystem.Guid604         private static bool TryParseGuidWithNoStyle(String guidString, ref GuidResult result) {
605             int startPos=0;
606             int temp;
607             long templ;
608             int currentPos = 0;
609 
610             if(guidString.Length != 32) {
611                 result.SetFailure(ParseFailureKind.Format, "Format_GuidInvLen");
612                 return false;
613             }
614 
615             for(int i= 0; i< guidString.Length; i++) {
616                 char ch = guidString[i];
617                 if(ch >= '0' && ch <= '9') {
618                     continue;
619                 }
620                 else {
621                     char upperCaseCh = Char.ToUpper(ch, CultureInfo.InvariantCulture);
622                     if(upperCaseCh >= 'A' && upperCaseCh <= 'F') {
623                         continue;
624                     }
625                 }
626 
627                 result.SetFailure(ParseFailureKind.Format, "Format_GuidInvalidChar");
628                 return false;
629             }
630 
631             if (!StringToInt(guidString.Substring(startPos, 8) /*first DWORD*/, -1, ParseNumbers.IsTight, out result.parsedGuid._a, ref result))
632                 return false;
633 
634             startPos += 8;
635             if (!StringToShort(guidString.Substring(startPos, 4), -1, ParseNumbers.IsTight, out result.parsedGuid._b, ref result))
636                 return false;
637 
638             startPos += 4;
639             if (!StringToShort(guidString.Substring(startPos, 4), -1, ParseNumbers.IsTight, out result.parsedGuid._c, ref result))
640                 return false;
641 
642             startPos += 4;
643             if (!StringToInt(guidString.Substring(startPos, 4), -1, ParseNumbers.IsTight, out temp, ref result))
644                 return false;
645 
646             startPos += 4;
647             currentPos = startPos;
648 
649             if (!StringToLong(guidString, ref currentPos, ParseNumbers.NoSpace, out templ, ref result))
650                 return false;
651 
652             if (currentPos - startPos!=12) {
653                 result.SetFailure(ParseFailureKind.Format, "Format_GuidInvLen");
654                 return false;
655             }
656 
657             result.parsedGuid._d = (byte)(temp>>8);
658             result.parsedGuid._e = (byte)(temp);
659             temp = (int)(templ >> 32);
660             result.parsedGuid._f = (byte)(temp>>8);
661             result.parsedGuid._g = (byte)(temp);
662             temp = (int)(templ);
663             result.parsedGuid._h = (byte)(temp>>24);
664             result.parsedGuid._i = (byte)(temp>>16);
665             result.parsedGuid._j = (byte)(temp>>8);
666             result.parsedGuid._k = (byte)(temp);
667 
668             return true;
669         }
670 
671 
672         // Check if it's of the form [{|(]dddddddd-dddd-dddd-dddd-dddddddddddd[}|)]
TryParseGuidWithDashesSystem.Guid673         private static bool TryParseGuidWithDashes(String guidString, ref GuidResult result) {
674             int startPos=0;
675             int temp;
676             long templ;
677             int currentPos = 0;
678 
679             // check to see that it's the proper length
680             if (guidString[0]=='{') {
681                 if (guidString.Length!=38 || guidString[37]!='}') {
682                     result.SetFailure(ParseFailureKind.Format, "Format_GuidInvLen");
683                     return false;
684                 }
685                 startPos=1;
686             }
687             else if (guidString[0]=='(') {
688                 if (guidString.Length!=38 || guidString[37]!=')') {
689                     result.SetFailure(ParseFailureKind.Format, "Format_GuidInvLen");
690                     return false;
691                 }
692                 startPos=1;
693             }
694             else if(guidString.Length != 36) {
695                 result.SetFailure(ParseFailureKind.Format, "Format_GuidInvLen");
696                 return false;
697             }
698 
699             if (guidString[8+startPos] != '-' ||
700                 guidString[13+startPos] != '-' ||
701                 guidString[18+startPos] != '-' ||
702                 guidString[23+startPos] != '-') {
703                 result.SetFailure(ParseFailureKind.Format, "Format_GuidDashes");
704                 return false;
705             }
706 
707             currentPos = startPos;
708             if (!StringToInt(guidString, ref currentPos, 8, ParseNumbers.NoSpace, out temp, ref result))
709                 return false;
710             result.parsedGuid._a = temp;
711             ++currentPos; //Increment past the '-';
712 
713             if (!StringToInt(guidString, ref currentPos, 4, ParseNumbers.NoSpace, out temp, ref result))
714                 return false;
715             result.parsedGuid._b = (short)temp;
716             ++currentPos; //Increment past the '-';
717 
718             if (!StringToInt(guidString, ref currentPos, 4, ParseNumbers.NoSpace, out temp, ref result))
719                 return false;
720             result.parsedGuid._c = (short)temp;
721             ++currentPos; //Increment past the '-';
722 
723             if (!StringToInt(guidString, ref currentPos, 4, ParseNumbers.NoSpace, out temp, ref result))
724                 return false;
725             ++currentPos; //Increment past the '-';
726             startPos=currentPos;
727 
728             if (!StringToLong(guidString, ref currentPos, ParseNumbers.NoSpace, out templ, ref result))
729                 return false;
730 
731             if (currentPos - startPos != 12) {
732                 result.SetFailure(ParseFailureKind.Format, "Format_GuidInvLen");
733                 return false;
734             }
735             result.parsedGuid._d = (byte)(temp>>8);
736             result.parsedGuid._e = (byte)(temp);
737             temp = (int)(templ >> 32);
738             result.parsedGuid._f = (byte)(temp>>8);
739             result.parsedGuid._g = (byte)(temp);
740             temp = (int)(templ);
741             result.parsedGuid._h = (byte)(temp>>24);
742             result.parsedGuid._i = (byte)(temp>>16);
743             result.parsedGuid._j = (byte)(temp>>8);
744             result.parsedGuid._k = (byte)(temp);
745 
746             return true;
747         }
748 
749 
750         //
751         // StringToShort, StringToInt, and StringToLong are wrappers around COMUtilNative integer parsing routines;
752         //<
753 
754         [System.Security.SecuritySafeCritical]
StringToShortSystem.Guid755         private static unsafe bool StringToShort(String str, int requiredLength, int flags, out short result, ref GuidResult parseResult) {
756             return StringToShort(str, null, requiredLength, flags, out result, ref parseResult);
757         }
758         [System.Security.SecuritySafeCritical]
StringToShortSystem.Guid759         private static unsafe bool StringToShort(String str, ref int parsePos, int requiredLength, int flags, out short result, ref GuidResult parseResult) {
760             fixed(int * ppos = &parsePos) {
761                 return StringToShort(str, ppos, requiredLength, flags, out result, ref parseResult);
762             }
763         }
764         [System.Security.SecurityCritical]
StringToShortSystem.Guid765         private static unsafe bool StringToShort(String str, int* parsePos, int requiredLength, int flags, out short result, ref GuidResult parseResult) {
766             result = 0;
767             int x;
768             bool retValue = StringToInt(str, parsePos, requiredLength, flags, out x, ref parseResult);
769             result = (short)x;
770             return retValue;
771         }
772 
773         [System.Security.SecuritySafeCritical]
StringToIntSystem.Guid774         private static unsafe bool StringToInt(String str, int requiredLength, int flags, out int result, ref GuidResult parseResult) {
775             return StringToInt(str, null, requiredLength, flags, out result, ref parseResult);
776         }
777         [System.Security.SecuritySafeCritical]
StringToIntSystem.Guid778         private static unsafe bool StringToInt(String str, ref int parsePos, int requiredLength, int flags, out int result, ref GuidResult parseResult) {
779             fixed(int * ppos = &parsePos) {
780                 return StringToInt(str, ppos, requiredLength, flags, out result, ref parseResult);
781             }
782         }
783         [System.Security.SecurityCritical]
StringToIntSystem.Guid784         private static unsafe bool StringToInt(String str, int* parsePos, int requiredLength, int flags, out int result, ref GuidResult parseResult) {
785             result = 0;
786 
787             int currStart = (parsePos == null) ? 0 : (*parsePos);
788             try {
789                 result = ParseNumbers.StringToInt(str, 16, flags, parsePos);
790             }
791             catch (OverflowException ex) {
792                 if (parseResult.throwStyle == GuidParseThrowStyle.All) {
793                     throw;
794                 }
795                 else if (parseResult.throwStyle == GuidParseThrowStyle.AllButOverflow) {
796                     throw new FormatException(Environment.GetResourceString("Format_GuidUnrecognized"), ex);
797                 }
798                 else {
799                     parseResult.SetFailure(ex);
800                     return false;
801                 }
802             }
803             catch (Exception ex) {
804                 if (parseResult.throwStyle == GuidParseThrowStyle.None) {
805                     parseResult.SetFailure(ex);
806                     return false;
807                 }
808                 else {
809                     throw;
810                 }
811             }
812 
813             //If we didn't parse enough characters, there's clearly an error.
814             if (requiredLength != -1 && parsePos != null &&  (*parsePos) - currStart != requiredLength) {
815                 parseResult.SetFailure(ParseFailureKind.Format, "Format_GuidInvalidChar");
816                 return false;
817             }
818             return true;
819         }
820         [System.Security.SecuritySafeCritical]
StringToLongSystem.Guid821         private static unsafe bool StringToLong(String str, int flags, out long result, ref GuidResult parseResult) {
822             return StringToLong(str, null, flags, out result, ref parseResult);
823         }
824         [System.Security.SecuritySafeCritical]
StringToLongSystem.Guid825         private static unsafe bool StringToLong(String str, ref int parsePos, int flags, out long result, ref GuidResult parseResult) {
826             fixed(int * ppos = &parsePos) {
827                 return StringToLong(str, ppos, flags, out result, ref parseResult);
828             }
829         }
830         [System.Security.SecuritySafeCritical]
StringToLongSystem.Guid831         private static unsafe bool StringToLong(String str, int* parsePos, int flags, out long result, ref GuidResult parseResult) {
832             result = 0;
833 
834             try {
835                 result = ParseNumbers.StringToLong(str, 16, flags, parsePos);
836             }
837             catch (OverflowException ex) {
838                 if (parseResult.throwStyle == GuidParseThrowStyle.All) {
839                     throw;
840                 }
841                 else if (parseResult.throwStyle == GuidParseThrowStyle.AllButOverflow) {
842                     throw new FormatException(Environment.GetResourceString("Format_GuidUnrecognized"), ex);
843                 }
844                 else {
845                     parseResult.SetFailure(ex);
846                     return false;
847                 }
848             }
849             catch (Exception ex) {
850                 if (parseResult.throwStyle == GuidParseThrowStyle.None) {
851                     parseResult.SetFailure(ex);
852                     return false;
853                 }
854                 else {
855                     throw;
856                 }
857             }
858             return true;
859         }
860 
861 
EatAllWhitespaceSystem.Guid862         private static String EatAllWhitespace(String str)
863         {
864             int newLength = 0;
865             char[] chArr = new char[str.Length];
866             char curChar;
867 
868             // Now get each char from str and if it is not whitespace add it to chArr
869             for(int i = 0; i < str.Length; i++)
870             {
871                 curChar = str[i];
872                 if(!Char.IsWhiteSpace(curChar))
873                 {
874                     chArr[newLength++] = curChar;
875                 }
876             }
877 
878             // Return a new string based on chArr
879             return new String(chArr, 0, newLength);
880         }
881 
IsHexPrefixSystem.Guid882         private static bool IsHexPrefix(String str, int i)
883         {
884             if(str.Length > i+1 && str[i] == '0' && (Char.ToLower(str[i+1], CultureInfo.InvariantCulture) == 'x'))
885                 return true;
886             else
887                 return false;
888         }
889 
890 
891         // Returns an unsigned byte array containing the GUID.
ToByteArraySystem.Guid892         public byte[] ToByteArray()
893         {
894             byte[] g = new byte[16];
895 
896             g[0] = (byte)(_a);
897             g[1] = (byte)(_a >> 8);
898             g[2] = (byte)(_a >> 16);
899             g[3] = (byte)(_a >> 24);
900             g[4] = (byte)(_b);
901             g[5] = (byte)(_b >> 8);
902             g[6] = (byte)(_c);
903             g[7] = (byte)(_c >> 8);
904             g[8] = _d;
905             g[9] = _e;
906             g[10] = _f;
907             g[11] = _g;
908             g[12] = _h;
909             g[13] = _i;
910             g[14] = _j;
911             g[15] = _k;
912 
913             return g;
914         }
915 
916 
917         // Returns the guid in "registry" format.
ToStringSystem.Guid918         public override String ToString()
919         {
920             return ToString("D",null);
921         }
922 
GetHashCodeSystem.Guid923         public override int GetHashCode()
924         {
925             return _a ^ (((int)_b << 16) | (int)(ushort)_c) ^ (((int)_f << 24) | _k);
926         }
927 
928         // Returns true if and only if the guid represented
929         //  by o is the same as this instance.
EqualsSystem.Guid930         public override bool Equals(Object o)
931         {
932             Guid g;
933             // Check that o is a Guid first
934             if(o == null || !(o is Guid))
935                 return false;
936             else g = (Guid) o;
937 
938             // Now compare each of the elements
939             if(g._a != _a)
940                 return false;
941             if(g._b != _b)
942                 return false;
943             if(g._c != _c)
944                 return false;
945             if (g._d != _d)
946                 return false;
947             if (g._e != _e)
948                 return false;
949             if (g._f != _f)
950                 return false;
951             if (g._g != _g)
952                 return false;
953             if (g._h != _h)
954                 return false;
955             if (g._i != _i)
956                 return false;
957             if (g._j != _j)
958                 return false;
959             if (g._k != _k)
960                 return false;
961 
962             return true;
963         }
964 
EqualsSystem.Guid965         public bool Equals(Guid g)
966         {
967             // Now compare each of the elements
968             if(g._a != _a)
969                 return false;
970             if(g._b != _b)
971                 return false;
972             if(g._c != _c)
973                 return false;
974             if (g._d != _d)
975                 return false;
976             if (g._e != _e)
977                 return false;
978             if (g._f != _f)
979                 return false;
980             if (g._g != _g)
981                 return false;
982             if (g._h != _h)
983                 return false;
984             if (g._i != _i)
985                 return false;
986             if (g._j != _j)
987                 return false;
988             if (g._k != _k)
989                 return false;
990 
991             return true;
992         }
993 
GetResultSystem.Guid994         private int GetResult(uint me, uint them) {
995             if (me<them) {
996                 return -1;
997             }
998             return 1;
999         }
1000 
CompareToSystem.Guid1001         public int CompareTo(Object value) {
1002             if (value == null) {
1003                 return 1;
1004             }
1005             if (!(value is Guid)) {
1006                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeGuid"));
1007             }
1008             Guid g = (Guid)value;
1009 
1010             if (g._a!=this._a) {
1011                 return GetResult((uint)this._a, (uint)g._a);
1012             }
1013 
1014             if (g._b!=this._b) {
1015                 return GetResult((uint)this._b, (uint)g._b);
1016             }
1017 
1018             if (g._c!=this._c) {
1019                 return GetResult((uint)this._c, (uint)g._c);
1020             }
1021 
1022             if (g._d!=this._d) {
1023                 return GetResult((uint)this._d, (uint)g._d);
1024             }
1025 
1026             if (g._e!=this._e) {
1027                 return GetResult((uint)this._e, (uint)g._e);
1028             }
1029 
1030             if (g._f!=this._f) {
1031                 return GetResult((uint)this._f, (uint)g._f);
1032             }
1033 
1034             if (g._g!=this._g) {
1035                 return GetResult((uint)this._g, (uint)g._g);
1036             }
1037 
1038             if (g._h!=this._h) {
1039                 return GetResult((uint)this._h, (uint)g._h);
1040             }
1041 
1042             if (g._i!=this._i) {
1043                 return GetResult((uint)this._i, (uint)g._i);
1044             }
1045 
1046             if (g._j!=this._j) {
1047                 return GetResult((uint)this._j, (uint)g._j);
1048             }
1049 
1050             if (g._k!=this._k) {
1051                 return GetResult((uint)this._k, (uint)g._k);
1052             }
1053 
1054             return 0;
1055         }
1056 
1057 #if GENERICS_WORK
CompareToSystem.Guid1058         public int CompareTo(Guid value)
1059         {
1060             if (value._a!=this._a) {
1061                 return GetResult((uint)this._a, (uint)value._a);
1062             }
1063 
1064             if (value._b!=this._b) {
1065                 return GetResult((uint)this._b, (uint)value._b);
1066             }
1067 
1068             if (value._c!=this._c) {
1069                 return GetResult((uint)this._c, (uint)value._c);
1070             }
1071 
1072             if (value._d!=this._d) {
1073                 return GetResult((uint)this._d, (uint)value._d);
1074             }
1075 
1076             if (value._e!=this._e) {
1077                 return GetResult((uint)this._e, (uint)value._e);
1078             }
1079 
1080             if (value._f!=this._f) {
1081                 return GetResult((uint)this._f, (uint)value._f);
1082             }
1083 
1084             if (value._g!=this._g) {
1085                 return GetResult((uint)this._g, (uint)value._g);
1086             }
1087 
1088             if (value._h!=this._h) {
1089                 return GetResult((uint)this._h, (uint)value._h);
1090             }
1091 
1092             if (value._i!=this._i) {
1093                 return GetResult((uint)this._i, (uint)value._i);
1094             }
1095 
1096             if (value._j!=this._j) {
1097                 return GetResult((uint)this._j, (uint)value._j);
1098             }
1099 
1100             if (value._k!=this._k) {
1101                 return GetResult((uint)this._k, (uint)value._k);
1102             }
1103 
1104             return 0;
1105         }
1106 #endif // GENERICS_WORK
1107 
operator ==System.Guid1108         public static bool operator ==(Guid a, Guid b)
1109         {
1110             // Now compare each of the elements
1111             if(a._a != b._a)
1112                 return false;
1113             if(a._b != b._b)
1114                 return false;
1115             if(a._c != b._c)
1116                 return false;
1117             if(a._d != b._d)
1118                 return false;
1119             if(a._e != b._e)
1120                 return false;
1121             if(a._f != b._f)
1122                 return false;
1123             if(a._g != b._g)
1124                 return false;
1125             if(a._h != b._h)
1126                 return false;
1127             if(a._i != b._i)
1128                 return false;
1129             if(a._j != b._j)
1130                 return false;
1131             if(a._k != b._k)
1132                 return false;
1133 
1134             return true;
1135         }
1136 
operator !=System.Guid1137         public static bool operator !=(Guid a, Guid b)
1138         {
1139             return !(a == b);
1140         }
1141 #if !MONO
1142         // This will create a new guid.  Since we've now decided that constructors should 0-init,
1143         // we need a method that allows users to create a guid.
1144         [System.Security.SecuritySafeCritical]  // auto-generated
NewGuidSystem.Guid1145         public static Guid NewGuid() {
1146             // CoCreateGuid should never return Guid.Empty, since it attempts to maintain some
1147             // uniqueness guarantees.  It should also never return a known GUID, but it's unclear
1148             // how extensively it checks for known values.
1149             Contract.Ensures(Contract.Result<Guid>() != Guid.Empty);
1150 
1151             Guid guid;
1152             Marshal.ThrowExceptionForHR(Win32Native.CoCreateGuid(out guid), new IntPtr(-1));
1153             return guid;
1154         }
1155 #endif
ToStringSystem.Guid1156         public String ToString(String format) {
1157             return ToString(format, null);
1158         }
1159 
HexToCharSystem.Guid1160         private static char HexToChar(int a)
1161         {
1162             a = a & 0xf;
1163             return (char) ((a > 9) ? a - 10 + 0x61 : a + 0x30);
1164         }
1165 
1166         [System.Security.SecurityCritical]
HexsToCharsSystem.Guid1167         unsafe private static int HexsToChars(char* guidChars, int offset, int a, int b)
1168         {
1169             return HexsToChars(guidChars, offset, a, b, false);
1170         }
1171 
1172         [System.Security.SecurityCritical]
HexsToCharsSystem.Guid1173         unsafe private static int HexsToChars(char* guidChars, int offset, int a, int b, bool hex)
1174         {
1175             if (hex) {
1176                 guidChars[offset++] = '0';
1177                 guidChars[offset++] = 'x';
1178             }
1179             guidChars[offset++] = HexToChar(a>>4);
1180             guidChars[offset++] = HexToChar(a);
1181             if (hex) {
1182                 guidChars[offset++] = ',';
1183                 guidChars[offset++] = '0';
1184                 guidChars[offset++] = 'x';
1185             }
1186             guidChars[offset++] = HexToChar(b>>4);
1187             guidChars[offset++] = HexToChar(b);
1188             return offset;
1189         }
1190 
1191         // IFormattable interface
1192         // We currently ignore provider
1193         [System.Security.SecuritySafeCritical]
ToStringSystem.Guid1194         public String ToString(String format, IFormatProvider provider)
1195         {
1196             if (format == null || format.Length == 0)
1197                 format = "D";
1198 
1199             string guidString;
1200             int offset = 0;
1201             bool dash = true;
1202             bool hex = false;
1203 
1204             if( format.Length != 1) {
1205                 // all acceptable format strings are of length 1
1206                 throw new FormatException(Environment.GetResourceString("Format_InvalidGuidFormatSpecification"));
1207             }
1208 
1209             char formatCh = format[0];
1210             if (formatCh == 'D' || formatCh == 'd') {
1211                 guidString = string.FastAllocateString(36);
1212             }
1213             else if (formatCh == 'N' || formatCh == 'n') {
1214                 guidString = string.FastAllocateString(32);
1215                 dash = false;
1216             }
1217             else if (formatCh == 'B' || formatCh == 'b') {
1218                 guidString = string.FastAllocateString(38);
1219                 unsafe {
1220                     fixed (char* guidChars = guidString) {
1221                         guidChars[offset++] = '{';
1222                         guidChars[37] = '}';
1223                     }
1224                 }
1225             }
1226             else if (formatCh == 'P' || formatCh == 'p') {
1227                 guidString = string.FastAllocateString(38);
1228                 unsafe {
1229                     fixed (char* guidChars = guidString) {
1230                         guidChars[offset++] = '(';
1231                         guidChars[37] = ')';
1232                     }
1233                 }
1234             }
1235             else if (formatCh == 'X' || formatCh == 'x') {
1236                 guidString = string.FastAllocateString(68);
1237                 unsafe {
1238                     fixed (char* guidChars = guidString) {
1239                         guidChars[offset++] = '{';
1240                         guidChars[67] = '}';
1241                     }
1242                 }
1243                 dash = false;
1244                 hex = true;
1245             }
1246             else {
1247                 throw new FormatException(Environment.GetResourceString("Format_InvalidGuidFormatSpecification"));
1248             }
1249 
1250             unsafe {
1251                 fixed (char* guidChars = guidString) {
1252                     if (hex) {
1253                         // {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}
1254                         guidChars[offset++] = '0';
1255                         guidChars[offset++] = 'x';
1256                         offset = HexsToChars(guidChars, offset, _a >> 24, _a >> 16);
1257                         offset = HexsToChars(guidChars, offset, _a >> 8, _a);
1258                         guidChars[offset++] = ',';
1259                         guidChars[offset++] = '0';
1260                         guidChars[offset++] = 'x';
1261                         offset = HexsToChars(guidChars, offset, _b >> 8, _b);
1262                         guidChars[offset++] = ',';
1263                         guidChars[offset++] = '0';
1264                         guidChars[offset++] = 'x';
1265                         offset = HexsToChars(guidChars, offset, _c >> 8, _c);
1266                         guidChars[offset++] = ',';
1267                         guidChars[offset++] = '{';
1268                         offset = HexsToChars(guidChars, offset, _d, _e, true);
1269                         guidChars[offset++] = ',';
1270                         offset = HexsToChars(guidChars, offset, _f, _g, true);
1271                         guidChars[offset++] = ',';
1272                         offset = HexsToChars(guidChars, offset, _h, _i, true);
1273                         guidChars[offset++] = ',';
1274                         offset = HexsToChars(guidChars, offset, _j, _k, true);
1275                         guidChars[offset++] = '}';
1276                     }
1277                     else {
1278                         // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)]
1279                         offset = HexsToChars(guidChars, offset, _a >> 24, _a >> 16);
1280                         offset = HexsToChars(guidChars, offset, _a >> 8, _a);
1281                         if (dash) guidChars[offset++] = '-';
1282                         offset = HexsToChars(guidChars, offset, _b >> 8, _b);
1283                         if (dash) guidChars[offset++] = '-';
1284                         offset = HexsToChars(guidChars, offset, _c >> 8, _c);
1285                         if (dash) guidChars[offset++] = '-';
1286                         offset = HexsToChars(guidChars, offset, _d, _e);
1287                         if (dash) guidChars[offset++] = '-';
1288                         offset = HexsToChars(guidChars, offset, _f, _g);
1289                         offset = HexsToChars(guidChars, offset, _h, _i);
1290                         offset = HexsToChars(guidChars, offset, _j, _k);
1291                     }
1292                 }
1293             }
1294             return guidString;
1295         }
1296     }
1297 }
1298