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
NewPermissionElement(IPermission ip)49         NewPermissionElement (IPermission ip)
50         {
51             return NewPermissionElement (ip.GetType ().FullName) ;
52         }
53 
54         public static SecurityElement
NewPermissionElement(String name)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
AddClassAttribute( SecurityElement element, Type type, String typename )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 
ParseElementForAssemblyIdentification(SecurityElement el, out String className, out String assemblyName, out String assemblyVersion)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
ParseElementForObjectCreation( SecurityElement el, String requiredNamespace, out String className, out int classNameStart, out int classNameLength )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
SecurityObjectToXmlString(Object ob)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
XmlStringToSecurityObject(String s)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
CreatePermission(SecurityElement el, PermissionState permState, bool ignoreTypeLoadFailures)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
CreateCodeGroup(SecurityElement el)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
CreateMembershipCondition( SecurityElement el )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
GetClassFromElement(SecurityElement el, bool ignoreTypeLoadFailures)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
IsPermissionElement(IPermission ip, SecurityElement el)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
IsUnrestricted(SecurityElement el)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 
BitFieldEnumToString( Type type, Object value )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 }
719