ad0a9cb25a426025fd2d89f70b514b67c60c687b
[mono.git] / mcs / class / referencesource / mscorlib / system / security / util / xmlutil.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** CLASS:    XMLUtil
9 ** 
10 ** <OWNER>Microsoft</OWNER>
11 **
12 ** PURPOSE:  Helpers for XML input & output
13 **
14 ===========================================================*/
15 namespace System.Security.Util  {
16     
17     using System;
18     using System.Security;
19     using System.Security.Permissions;
20     using System.Security.Policy;
21     using System.Runtime.InteropServices;
22     using System.Runtime.Remoting;
23     using System.IO;
24     using System.Text;
25     using System.Runtime.CompilerServices;
26     using PermissionState = System.Security.Permissions.PermissionState;
27     using BindingFlags = System.Reflection.BindingFlags;
28     using Assembly = System.Reflection.Assembly;
29     using System.Threading;
30     using System.Globalization;
31     using System.Reflection;
32     using System.Diagnostics.Contracts;
33
34     internal static class XMLUtil
35     {
36         //
37         // Warning: Element constructors have side-effects on their
38         //          third argument.
39         //
40         
41         private const String BuiltInPermission = "System.Security.Permissions.";
42 #if FEATURE_CAS_POLICY        
43         private const String BuiltInMembershipCondition = "System.Security.Policy.";
44         private const String BuiltInCodeGroup = "System.Security.Policy.";
45         private const String BuiltInApplicationSecurityManager = "System.Security.Policy.";
46         private static readonly char[] sepChar =  {',', ' '};
47 #endif        
48         public static SecurityElement
49         NewPermissionElement (IPermission ip)
50         {
51             return NewPermissionElement (ip.GetType ().FullName) ;
52         }
53         
54         public static SecurityElement
55         NewPermissionElement (String name)
56         {
57             SecurityElement ecr = new SecurityElement( "Permission" );
58             ecr.AddAttribute( "class", name );
59             return ecr;
60         }
61         
62         public static void
63         AddClassAttribute( SecurityElement element, Type type, String typename )
64         {
65             // Replace any quotes with apostrophes so that we can include quoted materials
66             // within classnames.  Notably the assembly name member 'loc' uses a quoted string.
67         
68             // NOTE: this makes assumptions as to what reflection is expecting for a type string
69             // it will need to be updated if reflection changes what it wants.
70         
71             if ( typename == null )
72                 typename = type.FullName;
73             Contract.Assert( type.FullName.Equals( typename ), "Incorrect class name passed! Was : " + typename + " Shoule be: " + type.FullName);
74             element.AddAttribute( "class", typename + ", " + type.Module.Assembly.FullName.Replace( '\"', '\'' ) );
75         }
76         
77         internal static bool ParseElementForAssemblyIdentification(SecurityElement el,
78                                                                    out String className,
79                                                                    out String assemblyName, // for example "WindowsBase"
80                                                                    out String assemblyVersion)
81         {
82
83             className = null;
84             assemblyName = null;
85             assemblyVersion = null;
86             
87             String fullClassName = el.Attribute( "class" );
88             
89             if (fullClassName == null)
90             {
91                 return false;
92             }
93             if (fullClassName.IndexOf('\'') >= 0)
94             {
95                 fullClassName = fullClassName.Replace( '\'', '\"' );
96             }
97
98             int commaIndex = fullClassName.IndexOf( ',' );
99             int namespaceClassNameLength;
100             
101             // If the classname is tagged with assembly information, find where
102             // the assembly information begins.
103             
104             if (commaIndex == -1)
105             {
106                 return false;
107             }
108
109             namespaceClassNameLength = commaIndex;
110             className = fullClassName.Substring(0, namespaceClassNameLength);
111             String assemblyFullName = fullClassName.Substring(commaIndex + 1);
112             AssemblyName an = new AssemblyName(assemblyFullName);
113             assemblyName = an.Name;
114             assemblyVersion = an.Version.ToString();
115             return true;
116         }
117         [System.Security.SecurityCritical]  // auto-generated
118         private static bool
119         ParseElementForObjectCreation( SecurityElement el,
120                                        String requiredNamespace,
121                                        out String className,
122                                        out int classNameStart,
123                                        out int classNameLength )
124         {
125             className = null;
126             classNameStart = 0;
127             classNameLength = 0;
128             
129             int requiredNamespaceLength = requiredNamespace.Length;
130
131             String fullClassName = el.Attribute( "class" );
132             
133             if (fullClassName == null)
134             {
135                 throw new ArgumentException( Environment.GetResourceString( "Argument_NoClass" ) );
136             }
137             
138             if (fullClassName.IndexOf('\'') >= 0)
139             {
140                 fullClassName = fullClassName.Replace( '\'', '\"' );
141             }
142             
143             if (!PermissionToken.IsMscorlibClassName( fullClassName ))
144             {
145                 return false;
146             }
147
148             int commaIndex = fullClassName.IndexOf( ',' );
149             int namespaceClassNameLength;
150             
151             // If the classname is tagged with assembly information, find where
152             // the assembly information begins.
153             
154             if (commaIndex == -1)
155             {
156                 namespaceClassNameLength = fullClassName.Length;
157             }
158             else
159             {
160                 namespaceClassNameLength = commaIndex;
161             }
162
163             // Only if the length of the class name is greater than the namespace info
164             // on our requiredNamespace do we continue
165             // with our check.
166             
167             if (namespaceClassNameLength > requiredNamespaceLength)
168             {
169                 // Make sure we are in the required namespace.
170                 if (fullClassName.StartsWith(requiredNamespace, StringComparison.Ordinal))
171                 {
172                     className = fullClassName;
173                     classNameLength = namespaceClassNameLength - requiredNamespaceLength;
174                     classNameStart = requiredNamespaceLength;
175                     return true;
176                 }
177             }
178             
179             return false;
180         }
181
182 #if FEATURE_CAS_POLICY
183         public static String SecurityObjectToXmlString(Object ob)
184         {
185             if(ob == null)
186                 return "";
187             PermissionSet pset = ob as PermissionSet;
188             if(pset != null)
189                 return pset.ToXml().ToString();
190             return ((IPermission)ob).ToXml().ToString();
191         }
192
193         [System.Security.SecurityCritical]  // auto-generated
194         public static Object XmlStringToSecurityObject(String s)
195         {
196             if(s == null)
197                 return null;
198             if(s.Length < 1)
199                 return null;
200             return SecurityElement.FromString(s).ToSecurityObject();
201         }
202 #endif // FEATURE_CAS_POLICY
203
204         [SecuritySafeCritical]
205         public static IPermission
206         CreatePermission (SecurityElement el, PermissionState permState, bool ignoreTypeLoadFailures)
207         {
208             if (el == null || !(el.Tag.Equals("Permission") || el.Tag.Equals("IPermission")) )
209                 throw new ArgumentException( String.Format( null, Environment.GetResourceString( "Argument_WrongElementType" ), "<Permission>" ) ) ;
210             Contract.EndContractBlock();
211     
212             String className;
213             int classNameLength;
214             int classNameStart;
215             
216             if (!ParseElementForObjectCreation( el,
217                                                 BuiltInPermission,
218                                                 out className,
219                                                 out classNameStart,
220                                                 out classNameLength ))
221             {
222                 goto USEREFLECTION;
223             }
224                                               
225             // We have a built in permission, figure out which it is.
226                     
227             // UIPermission
228             // FileIOPermission
229             // SecurityPermission
230             // PrincipalPermission
231             // ReflectionPermission
232             // FileDialogPermission
233             // EnvironmentPermission
234             // GacIdentityPermission
235             // UrlIdentityPermission
236             // SiteIdentityPermission
237             // ZoneIdentityPermission
238             // KeyContainerPermission
239             // UnsafeForHostPermission
240             // HostProtectionPermission
241             // StrongNameIdentityPermission
242 #if !FEATURE_CORECLR                              
243             // IsolatedStorageFilePermission
244 #endif
245 #if !FEATURE_PAL
246             // RegistryPermission
247             // PublisherIdentityPermission
248 #endif // !FEATURE_PAL
249
250             switch (classNameLength)
251             {
252                 case 12:
253                     // UIPermission
254                     if (String.Compare(className, classNameStart, "UIPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
255                         return new UIPermission( permState );
256                     else
257                         goto USEREFLECTION;
258                                 
259                 case 16:
260                     // FileIOPermission
261                     if (String.Compare(className, classNameStart, "FileIOPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
262                         return new FileIOPermission( permState );
263                     else
264                         goto USEREFLECTION;
265                             
266                 case 18:
267 #if !FEATURE_PAL
268                     // RegistryPermission
269                     // SecurityPermission
270                     if (className[classNameStart] == 'R')
271                     {
272                         if (String.Compare(className, classNameStart, "RegistryPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
273                             return new RegistryPermission( permState );
274                         else
275                             goto USEREFLECTION;
276                     }
277                     else
278                     {
279                         if (String.Compare(className, classNameStart, "SecurityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
280                             return new SecurityPermission( permState );
281                         else
282                             goto USEREFLECTION;
283                     }
284 #else // !FEATURE_PAL
285                     if (String.Compare(className, classNameStart, "SecurityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
286                         return new SecurityPermission( permState );
287                     else
288                         goto USEREFLECTION;
289 #endif // !FEATURE_PAL
290                   
291 #if !FEATURE_CORECLR              
292                 case 19:
293                     // PrincipalPermission
294                     if (String.Compare(className, classNameStart, "PrincipalPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
295                         return new PrincipalPermission( permState );
296                     else
297                         goto USEREFLECTION;
298 #endif // !FEATURE_CORECLR
299                 case 20:
300                     // ReflectionPermission
301                     // FileDialogPermission
302                     if (className[classNameStart] == 'R')
303                     {
304                         if (String.Compare(className, classNameStart, "ReflectionPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
305                             return new ReflectionPermission( permState );
306                         else
307                             goto USEREFLECTION;
308                     }
309                     else
310                     {
311                         if (String.Compare(className, classNameStart, "FileDialogPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
312                             return new FileDialogPermission( permState );
313                         else
314                             goto USEREFLECTION;
315                     }
316
317                 case 21:
318                     // EnvironmentPermission
319                     // UrlIdentityPermission
320                     // GacIdentityPermission
321                     if (className[classNameStart] == 'E')
322                     {
323                         if (String.Compare(className, classNameStart, "EnvironmentPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
324                             return new EnvironmentPermission( permState );
325                         else
326                             goto USEREFLECTION;
327                     }
328                     else if (className[classNameStart] == 'U')
329                     {
330                         if (String.Compare(className, classNameStart, "UrlIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
331                             return new UrlIdentityPermission( permState );
332                         else
333                             goto USEREFLECTION;
334                     }
335                     else
336                     {
337                         if (String.Compare(className, classNameStart, "GacIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
338                             return new GacIdentityPermission( permState );
339                         else
340                             goto USEREFLECTION;
341                     }
342
343                             
344                 case 22:
345                     // SiteIdentityPermission
346                     // ZoneIdentityPermission
347                     // KeyContainerPermission
348                     if (className[classNameStart] == 'S')
349                     {
350                         if (String.Compare(className, classNameStart, "SiteIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
351                             return new SiteIdentityPermission( permState );
352                         else
353                             goto USEREFLECTION;
354                     }
355                     else if (className[classNameStart] == 'Z')
356                     {
357                         if (String.Compare(className, classNameStart, "ZoneIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
358                             return new ZoneIdentityPermission( permState );
359                         else
360                             goto USEREFLECTION;
361                     }
362                     else
363                     {
364 #if !FEATURE_PAL
365                         if (String.Compare(className, classNameStart, "KeyContainerPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
366                             return new KeyContainerPermission( permState );
367                         else
368 #endif // !FEATURE_PAL
369                             goto USEREFLECTION;
370                     }
371
372
373                 case 24:
374                     // HostProtectionPermission
375                     if (String.Compare(className, classNameStart, "HostProtectionPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
376                         return new HostProtectionPermission( permState );
377                     else
378                         goto USEREFLECTION;
379
380 #if FEATURE_X509 && FEATURE_CAS_POLICY
381                 case 27:
382                     // PublisherIdentityPermission
383                     if (String.Compare(className, classNameStart, "PublisherIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
384                         return new PublisherIdentityPermission( permState );
385                     else
386                         goto USEREFLECTION;
387 #endif // FEATURE_X509 && FEATURE_CAS_POLICY
388
389                 case 28:
390                     // StrongNameIdentityPermission
391                     if (String.Compare(className, classNameStart, "StrongNameIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
392                         return new StrongNameIdentityPermission( permState );
393                     else
394                         goto USEREFLECTION;
395 #if !FEATURE_CORECLR                                                          
396                 case 29:
397                     // IsolatedStorageFilePermission
398                     if (String.Compare(className, classNameStart, "IsolatedStorageFilePermission", 0, classNameLength, StringComparison.Ordinal) == 0)
399                         return new IsolatedStorageFilePermission( permState );
400                     else
401                         goto USEREFLECTION;
402 #endif                            
403                 default:
404                     goto USEREFLECTION;
405             }
406     
407 USEREFLECTION:
408
409             Object[] objs = new Object[1];
410             objs[0] = permState;
411
412             Type permClass = null;
413             IPermission perm = null;
414
415             new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
416             permClass = GetClassFromElement(el, ignoreTypeLoadFailures);
417             if (permClass == null)
418                 return null;
419             if (!(typeof(IPermission).IsAssignableFrom(permClass)))
420                 throw new ArgumentException( Environment.GetResourceString("Argument_NotAPermissionType") );
421
422             perm = (IPermission) Activator.CreateInstance(permClass, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, objs, null );
423
424             return perm;
425         }
426
427 #if FEATURE_CAS_POLICY
428 #pragma warning disable 618 // CodeGroups are obsolete
429         [System.Security.SecuritySafeCritical]  // auto-generated
430         public static CodeGroup
431         CreateCodeGroup (SecurityElement el)
432         {
433             if (el == null || !el.Tag.Equals("CodeGroup"))
434                 throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_WrongElementType" ), "<CodeGroup>" ) ) ;
435             Contract.EndContractBlock();
436     
437             String className;
438             int classNameLength;
439             int classNameStart;
440
441             if (!ParseElementForObjectCreation( el,
442                                                 BuiltInCodeGroup,
443                                                 out className,
444                                                 out classNameStart,
445                                                 out classNameLength ))
446             {
447                 goto USEREFLECTION;
448             }
449     
450             switch (classNameLength)
451             {
452                 case 12:
453                     // NetCodeGroup
454                     if (String.Compare(className, classNameStart, "NetCodeGroup", 0, classNameLength, StringComparison.Ordinal) == 0)
455                         return new NetCodeGroup();
456                     else
457                         goto USEREFLECTION;
458
459                 case 13:
460                     // FileCodeGroup
461                     if (String.Compare(className, classNameStart, "FileCodeGroup", 0, classNameLength, StringComparison.Ordinal) == 0)
462                         return new FileCodeGroup();
463                     else
464                         goto USEREFLECTION;
465                 case 14:
466                     // UnionCodeGroup
467                     if (String.Compare(className, classNameStart, "UnionCodeGroup", 0, classNameLength, StringComparison.Ordinal) == 0)
468                         return new UnionCodeGroup();
469                     else
470                         goto USEREFLECTION;
471                                 
472                 case 19:
473                     // FirstMatchCodeGroup
474                     if (String.Compare(className, classNameStart, "FirstMatchCodeGroup", 0, classNameLength, StringComparison.Ordinal) == 0)
475                         return new FirstMatchCodeGroup();
476                     else
477                         goto USEREFLECTION;
478
479                 default:
480                     goto USEREFLECTION;
481             }
482
483 USEREFLECTION: 
484             Type groupClass = null;
485             CodeGroup group = null;
486
487             new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
488             groupClass = GetClassFromElement(el, true);
489             if (groupClass == null)
490                 return null;
491             if (!(typeof(CodeGroup).IsAssignableFrom(groupClass)))
492                 throw new ArgumentException( Environment.GetResourceString("Argument_NotACodeGroupType") );
493
494             group = (CodeGroup) Activator.CreateInstance(groupClass, true);
495
496             Contract.Assert( groupClass.Module.Assembly != Assembly.GetExecutingAssembly(),
497                 "This path should not get called for mscorlib based classes" );
498
499             return group;
500         }
501 #pragma warning restore 618
502         
503         [System.Security.SecurityCritical]  // auto-generated
504         internal static IMembershipCondition
505         CreateMembershipCondition( SecurityElement el )
506         {
507             if (el == null || !el.Tag.Equals("IMembershipCondition"))
508                 throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_WrongElementType" ), "<IMembershipCondition>" ) ) ;
509             Contract.EndContractBlock();
510     
511             String className;
512             int classNameStart;
513             int classNameLength;
514             
515             if (!ParseElementForObjectCreation( el,
516                                                 BuiltInMembershipCondition,
517                                                 out className,
518                                                 out classNameStart,
519                                                 out classNameLength ))
520             {
521                 goto USEREFLECTION;
522             }
523
524             // We have a built in membership condition, figure out which it is.
525                     
526             // Here's the list of built in membership conditions as of 9/17/2002
527             // System.Security.Policy.AllMembershipCondition
528             // System.Security.Policy.URLMembershipCondition
529             // System.Security.Policy.SHA1MembershipCondition
530             // System.Security.Policy.SiteMembershipCondition
531             // System.Security.Policy.ZoneMembershipCondition                                                                                                                                                              
532             // System.Security.Policy.PublisherMembershipCondition
533             // System.Security.Policy.StrongNameMembershipCondition
534             // System.Security.Policy.ApplicationMembershipCondition
535             // System.Security.Policy.DomainApplicationMembershipCondition
536             // System.Security.Policy.ApplicationDirectoryMembershipCondition
537                     
538             switch (classNameLength)
539             {
540                 case 22:
541                     // AllMembershipCondition
542                     // URLMembershipCondition
543                     if (className[classNameStart] == 'A')
544                     {
545                         if (String.Compare(className, classNameStart, "AllMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
546                             return new AllMembershipCondition();
547                         else
548                             goto USEREFLECTION;
549                     }
550                     else
551                     {
552                         if (String.Compare(className, classNameStart, "UrlMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
553                             return new UrlMembershipCondition();
554                         else
555                             goto USEREFLECTION;
556                     }
557                                 
558                 case 23:
559 #if !FEATURE_PAL                
560                     // HashMembershipCondition
561                     // SiteMembershipCondition
562                     // ZoneMembershipCondition                                                                                                                                                              
563                     if (className[classNameStart] == 'H')
564                     {
565                         if (String.Compare(className, classNameStart, "HashMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
566                             return new HashMembershipCondition();
567                         else
568                             goto USEREFLECTION;
569                     }
570                     else if (className[classNameStart] == 'S')
571 #else
572                     // SiteMembershipCondition
573                     // ZoneMembershipCondition                                                                                                                                                              
574                     if (className[classNameStart] == 'S')
575 #endif // !FEATURE_PAL
576                     {
577                         if (String.Compare(className, classNameStart, "SiteMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
578                             return new SiteMembershipCondition();
579                         else
580                             goto USEREFLECTION;
581                     }
582                     else
583                     {
584                         if (String.Compare(className, classNameStart, "ZoneMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
585                             return new ZoneMembershipCondition();
586                         else
587                             goto USEREFLECTION;
588                     }
589
590                 case 28:
591 #if !FEATURE_PAL
592                     // PublisherMembershipCondition
593                     if (String.Compare(className, classNameStart, "PublisherMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
594                         return new PublisherMembershipCondition();
595                     else
596 #endif // !FEATURE_PAL
597                         goto USEREFLECTION;
598
599                 case 29:
600                     // StrongNameMembershipCondition
601                     if (String.Compare(className, classNameStart, "StrongNameMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
602                         return new StrongNameMembershipCondition();
603                     else
604                         goto USEREFLECTION;
605
606                 case 39:
607                     // ApplicationDirectoryMembershipCondition
608                     if (String.Compare(className, classNameStart, "ApplicationDirectoryMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
609                         return new ApplicationDirectoryMembershipCondition();
610                     else
611                         goto USEREFLECTION;
612
613                 default:
614                     goto USEREFLECTION;
615             }
616
617 USEREFLECTION:
618             Type condClass = null;
619             IMembershipCondition cond = null;
620     
621             new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
622             condClass = GetClassFromElement(el, true);
623             if (condClass == null)
624                 return null;
625             if (!(typeof(IMembershipCondition).IsAssignableFrom(condClass)))
626                 throw new ArgumentException( Environment.GetResourceString("Argument_NotAMembershipCondition") );
627
628             cond = (IMembershipCondition) Activator.CreateInstance(condClass, true);
629
630             return cond;
631         }
632 #endif //#if FEATURE_CAS_POLICY
633         internal static Type
634         GetClassFromElement (SecurityElement el, bool ignoreTypeLoadFailures)
635         {
636             String className = el.Attribute( "class" );
637
638             if (className == null)
639             {
640                 if (ignoreTypeLoadFailures)
641                     return null;
642                 else
643                     throw new ArgumentException( String.Format( null, Environment.GetResourceString("Argument_InvalidXMLMissingAttr"), "class") );
644             }
645
646             if (ignoreTypeLoadFailures)
647             {
648                 try
649                 {
650                     return Type.GetType(className, false, false);               
651                 }
652                 catch (SecurityException)
653                 {
654                     return null;
655                 }
656             }
657             else
658                 return Type.GetType(className, true, false);               
659         }
660
661         public static bool
662         IsPermissionElement (IPermission ip,
663                              SecurityElement el)
664         {
665             if (!el.Tag.Equals ("Permission") && !el.Tag.Equals ("IPermission"))
666                 return false;
667                 
668             return true;
669         }
670         
671         public static bool
672         IsUnrestricted (SecurityElement el)
673         {
674             String sUnrestricted = el.Attribute( "Unrestricted" );
675             
676             if (sUnrestricted == null)
677                 return false;
678
679             return sUnrestricted.Equals( "true" ) || sUnrestricted.Equals( "TRUE" ) || sUnrestricted.Equals( "True" );
680         }
681
682
683         public static String BitFieldEnumToString( Type type, Object value )
684         {
685             int iValue = (int)value;
686
687             if (iValue == 0)
688                 return Enum.GetName( type, 0 );
689
690             StringBuilder result = StringBuilderCache.Acquire();
691             bool first = true;
692             int flag = 0x1;
693
694             for (int i = 1; i < 32; ++i)
695             {
696                 if ((flag & iValue) != 0)
697                 {
698                     String sFlag = Enum.GetName( type, flag );
699
700                     if (sFlag == null)
701                         continue;
702
703                     if (!first)
704                     {
705                         result.Append( ", " );
706                     }
707
708                     result.Append( sFlag );
709                     first = false;
710                 }
711
712                 flag = flag << 1;
713             }
714             
715             return StringBuilderCache.GetStringAndRelease(result);
716         } 
717     }
718 }