File: system\security\permissionset.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// <OWNER>Microsoft</OWNER>
// 
 
namespace System.Security {
    using System;
    using System.Threading;
    using System.Security.Util;
    using System.Collections;
    using System.IO;
    using System.Security.Permissions;
    using System.Runtime.CompilerServices;
    using System.Security.Policy;
#if FEATURE_SERIALIZATION
    using System.Runtime.Serialization.Formatters.Binary;
#endif // FEATURE_SERIALIZATION
    using BindingFlags = System.Reflection.BindingFlags;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Globalization;
    using System.Runtime.Versioning;
    using System.Diagnostics.Contracts;
 
    [Serializable] 
    internal enum SpecialPermissionSetFlag
    {
        // These also appear in clr/src/vm/permset.h
        Regular = 0,
        NoSet = 1,
        EmptySet = 2,
        SkipVerification = 3
    }
 
    [Serializable] 
#if !FEATURE_CORECLR
    [StrongNameIdentityPermissionAttribute(SecurityAction.InheritanceDemand, Name = "mscorlib", PublicKey = "0x" + AssemblyRef.EcmaPublicKeyFull)]
#endif
    [System.Runtime.InteropServices.ComVisible(true)]
    public class PermissionSet : ISecurityEncodable, ICollection, IStackWalk, IDeserializationCallback
    {
    #if _DEBUG
        internal static readonly bool debug;
    #endif
    
        [System.Diagnostics.Conditional( "_DEBUG" )]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private static void DEBUG_WRITE(String str) {
        #if _DEBUG
            if (debug) Console.WriteLine(str);
        #endif
         }
 
        [System.Diagnostics.Conditional( "_DEBUG" )]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private static void DEBUG_COND_WRITE(bool exp, String str)
        {
        #if _DEBUG
            if (debug && (exp)) Console.WriteLine(str);
        #endif
        }
 
        [System.Diagnostics.Conditional( "_DEBUG" )]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private static void DEBUG_PRINTSTACK(Exception e)
        {
        #if _DEBUG
            if (debug) Console.Error.WriteLine((e).StackTrace);
        #endif
        }
    
        // These members are accessed from EE using their hardcoded offset.
        // Please update the PermissionSetObject in object.h if you make any changes 
        // to the fields here. !dumpobj will show the field layout
 
        // First the fields that are serialized x-appdomain (for perf reasons)
        private bool m_Unrestricted;
        [OptionalField(VersionAdded = 2)]
        private bool m_allPermissionsDecoded = false;
 
        [OptionalField(VersionAdded = 2)]
        internal TokenBasedSet m_permSet = null;
 
        // This is a hack so that SQL can operate under default policy without actually
        // granting permissions in assemblies that they disallow.  @
 
 
        [OptionalField(VersionAdded = 2)]
        private bool m_ignoreTypeLoadFailures = false;
 
        // This field will be populated only for non X-AD scenarios where we create a XML-ised string of the PermissionSet
        [OptionalField(VersionAdded = 2)]
        private String m_serializedPermissionSet; 
 
        [NonSerialized] private bool m_CheckedForNonCas;
        [NonSerialized] private bool m_ContainsCas;
        [NonSerialized] private bool m_ContainsNonCas;
 
        // only used during non X-AD serialization to save the m_permSet value (which we dont want serialized)
        [NonSerialized] private TokenBasedSet m_permSetSaved;         
 
        // Following 4 fields are used only for serialization compat purposes: DO NOT USE THESE EVER!
#pragma warning disable 169
        private bool readableonly;    
        private TokenBasedSet m_unrestrictedPermSet;
        private TokenBasedSet m_normalPermSet;
 
        [OptionalField(VersionAdded = 2)]
        private bool m_canUnrestrictedOverride;
#pragma warning restore 169
        // END: Serialization-only fields
 
        internal static readonly PermissionSet s_fullTrust = new PermissionSet( true );
 
#if FEATURE_REMOTING
        [OnDeserializing]
        private void OnDeserializing(StreamingContext ctx)
        {
            Reset();
        }   
 
        [OnDeserialized]
        private void OnDeserialized(StreamingContext ctx)
        {
            if (m_serializedPermissionSet != null)
            {
                // Whidbey non X-AD case
                FromXml(SecurityElement.FromString(m_serializedPermissionSet));
            }
            else if (m_normalPermSet != null)
            {
                // Everett non X-AD case
                m_permSet = m_normalPermSet.SpecialUnion(m_unrestrictedPermSet);
            }
            else if (m_unrestrictedPermSet != null)
            {
                // Everett non X-AD case
                m_permSet = m_unrestrictedPermSet.SpecialUnion(m_normalPermSet);
            }
 
            m_serializedPermissionSet = null;
            m_normalPermSet = null;
            m_unrestrictedPermSet = null;
 
        }
 
        [OnSerializing]
        private void OnSerializing(StreamingContext ctx)
        {
 
            if ((ctx.State & ~(StreamingContextStates.Clone|StreamingContextStates.CrossAppDomain)) != 0)
            {
                m_serializedPermissionSet = ToString(); // For v2.x and beyond
                if (m_permSet != null)
                    m_permSet.SpecialSplit(ref m_unrestrictedPermSet, ref m_normalPermSet, m_ignoreTypeLoadFailures);
                m_permSetSaved = m_permSet;
                m_permSet = null;
            }
        }
#endif // !FEATURE_REMOTING
 
#if FEATURE_REMOTING || _DEBUG
        [OnSerialized]
        private void OnSerialized(StreamingContext context)
        {
#if FEATURE_REMOTING
            if ((context.State & ~(StreamingContextStates.Clone|StreamingContextStates.CrossAppDomain)) != 0)
            {
                m_serializedPermissionSet = null;
                m_permSet = m_permSetSaved;
                m_permSetSaved = null;
                m_unrestrictedPermSet = null;
                m_normalPermSet = null;
            }
#else // !FEATURE_REMOTING
            Contract.Assert(false, "PermissionSet does not support serialization on CoreCLR");
#endif // !FEATURE_REMOTING
        }
#endif // FEATURE_REMOTING || _DEBUG
 
        internal PermissionSet()
        {
            Reset();
            m_Unrestricted = true;
        }
        
        internal PermissionSet(bool fUnrestricted)
            : this()
        {
            SetUnrestricted(fUnrestricted);
        }
        
        public PermissionSet(PermissionState state)
            : this()
        {
            if (state == PermissionState.Unrestricted)
            {
                SetUnrestricted( true );
            }
            else if (state == PermissionState.None)
            {
                SetUnrestricted( false );
            }
            else
            {
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPermissionState"));
            }
        }
    
        public PermissionSet(PermissionSet permSet)
            : this()
        {
            if (permSet == null)
            {
                Reset();
                return;
            }
 
            m_Unrestricted = permSet.m_Unrestricted;
            m_CheckedForNonCas = permSet.m_CheckedForNonCas;
            m_ContainsCas = permSet.m_ContainsCas;
            m_ContainsNonCas = permSet.m_ContainsNonCas;
            m_ignoreTypeLoadFailures = permSet.m_ignoreTypeLoadFailures;
 
            if (permSet.m_permSet != null)
            {
                m_permSet = new TokenBasedSet(permSet.m_permSet);
                
                // now deep copy all permissions in set
                for (int i = m_permSet.GetStartingIndex(); i <= m_permSet.GetMaxUsedIndex(); i++)
                {
                    Object obj = m_permSet.GetItem(i);
                    IPermission perm = obj as IPermission;
#if FEATURE_CAS_POLICY
                    ISecurityElementFactory elem = obj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
                    if (perm != null)
                    {
                        m_permSet.SetItem(i, perm.Copy());
                    }
#if FEATURE_CAS_POLICY
                    else if (elem != null)
                    {
                        m_permSet.SetItem(i, elem.Copy());
                    }
#endif // FEATURE_CAS_POLICY
                }
            }
        }
 
        public virtual void CopyTo(Array array, int index)
        {
            if (array == null)
                throw new ArgumentNullException( "array" );
            Contract.EndContractBlock();
        
            PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(this);
            
            while (enumerator.MoveNext())
            {
                array.SetValue(enumerator.Current , index++ );
            }
        }
        
        
        // private constructor that doesn't create any token based sets
        private PermissionSet( Object trash, Object junk )
        {
            m_Unrestricted = false;
        }
           
        
        // Returns an object appropriate for synchronizing access to this 
        // Array.
        public virtual Object SyncRoot
        {  get { return this; } }   
        
        // Is this Array synchronized (i.e., thread-safe)?  If you want a synchronized
        // collection, you can use SyncRoot as an object to synchronize your 
        // collection with.  You could also call GetSynchronized() 
        // to get a synchronized wrapper around the Array.
        public virtual bool IsSynchronized
        {  get { return false; } }  
            
        // Is this Collection ReadOnly?
        public virtual bool IsReadOnly 
        {  get {return false; } }   
 
        // Reinitializes all state in PermissionSet - DO NOT null-out m_serializedPermissionSet
        internal void Reset()
        {
            m_Unrestricted = false;
            m_allPermissionsDecoded = true;
            m_permSet = null;
            
            m_ignoreTypeLoadFailures = false;
 
            m_CheckedForNonCas = false;
            m_ContainsCas = false;
            m_ContainsNonCas = false;
            m_permSetSaved = null;
 
 
        }
 
        internal void CheckSet()
        {
            if (this.m_permSet == null)
                this.m_permSet = new TokenBasedSet();
        }
 
        public bool IsEmpty()
        {
            if (m_Unrestricted)
                return false;
 
            if (m_permSet == null || m_permSet.FastIsEmpty())
                return true;
 
            PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(this);
 
            while (enumerator.MoveNext())
            {
                IPermission perm = (IPermission)enumerator.Current;
 
                if (!perm.IsSubsetOf( null ))
                {
                    return false;
                }
            }
 
            return true;
        }
 
        internal bool FastIsEmpty()
        {
            if (m_Unrestricted)
                return false;
 
            if (m_permSet == null || m_permSet.FastIsEmpty())
                return true;
 
            return false;
        }            
    
        public virtual int Count
        {
            get
            {
                int count = 0;
 
                if (m_permSet != null)
                    count += m_permSet.GetCount();
 
                return count;
            }
        }
 
        internal IPermission GetPermission(int index)
        {
            if (m_permSet == null)
                return null;
            Object obj = m_permSet.GetItem( index );
            if (obj == null)
                return null;
            IPermission perm = obj as IPermission;
            if (perm != null)
                return perm;
#if FEATURE_CAS_POLICY
            perm = CreatePermission(obj, index);
#endif // FEATURE_CAS_POLICY
            if (perm == null)
                return null;  
            Contract.Assert( PermissionToken.IsTokenProperlyAssigned( perm, PermissionToken.GetToken( perm ) ),
                             "PermissionToken was improperly assigned" );
            Contract.Assert( PermissionToken.GetToken( perm ).m_index == index,
                             "Assigning permission to incorrect index in tokenbasedset" );
            return perm;
        }
 
        internal IPermission GetPermission(PermissionToken permToken)
        {
            if (permToken == null)
                return null;
                    
            return GetPermission( permToken.m_index );
        }
 
        internal IPermission GetPermission( IPermission perm )
        {
            if (perm == null)
                return null;
 
            return GetPermission(PermissionToken.GetToken( perm ));
        }
 
#if FEATURE_CAS_POLICY
        public IPermission GetPermission(Type permClass)
        {
            return GetPermissionImpl(permClass);
        }
 
        protected virtual IPermission GetPermissionImpl(Type permClass)
        {
            if (permClass == null)
                return null;
 
            return GetPermission(PermissionToken.FindToken(permClass));
        }
#endif // FEATURE_CAS_POLICY
 
        public IPermission SetPermission(IPermission perm)
        {
            return SetPermissionImpl(perm);
        }
 
        // SetPermission overwrites a permission in a permissionset.
        protected virtual IPermission SetPermissionImpl(IPermission perm)
        {
            // can't get token if perm is null
            if (perm == null)
                return null;
 
            PermissionToken permToken = PermissionToken.GetToken(perm);
 
            if ((permToken.m_type & PermissionTokenType.IUnrestricted) != 0)
            {
                // SetPermission Makes the Permission "Restricted"
                m_Unrestricted = false;
            }
 
            CheckSet();
 
            IPermission currPerm = GetPermission( permToken.m_index );
 
            m_CheckedForNonCas = false;
 
            // Should we copy here?
            m_permSet.SetItem( permToken.m_index, perm );
            return perm;
        }
 
        public IPermission AddPermission(IPermission perm)
        {
            return AddPermissionImpl(perm);
        }
 
        protected virtual IPermission AddPermissionImpl(IPermission perm)
        {
            // can't get token if perm is null
            if (perm == null)
                return null;
 
            m_CheckedForNonCas = false;
 
            // If the permission set is unrestricted, then return an unrestricted instance
            // of perm.
 
            PermissionToken permToken = PermissionToken.GetToken(perm);
 
            if (this.IsUnrestricted() && ((permToken.m_type & PermissionTokenType.IUnrestricted) != 0))
            {
                Type perm_type = perm.GetType();
                Object[] objs = new Object[1];
                objs[0] = PermissionState.Unrestricted;
                return (IPermission) Activator.CreateInstance(perm_type, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, objs, null );
            }
 
            CheckSet();
            IPermission currPerm = GetPermission(permToken.m_index);
 
            // If a Permission exists in this slot, then union it with perm
            // Otherwise, just add perm.
 
            if (currPerm != null) {
                IPermission ip_union = currPerm.Union(perm);
                m_permSet.SetItem( permToken.m_index, ip_union );
                return ip_union;
            } else {
                // Should we copy here?
                m_permSet.SetItem( permToken.m_index, perm );
                return perm;
            }
                
        }
 
        private IPermission RemovePermission( int index )
        {
            IPermission perm = GetPermission(index);
            if (perm == null)
                return null;
            return (IPermission)m_permSet.RemoveItem( index ); // this cast is safe because the call to GetPermission will guarantee it is an IPermission
        }
 
#if FEATURE_CAS_POLICY
        public IPermission RemovePermission(Type permClass)
        {
            return RemovePermissionImpl(permClass);
        }
 
        protected virtual IPermission RemovePermissionImpl(Type permClass)
        {
            if (permClass == null)
            {
                return null;
            }
 
            PermissionToken permToken = PermissionToken.FindToken(permClass);
            if (permToken == null)
            {
                return null;
            }
 
            return RemovePermission(permToken.m_index);
        }
#endif // FEATURE_CAS_POLICY
 
        // Make this internal soon.
        internal void SetUnrestricted(bool unrestricted)
        {
            m_Unrestricted = unrestricted;
            if (unrestricted)
            {
                // if this is to be an unrestricted permset, null the m_permSet member
                m_permSet = null;
            }
        }
    
        public bool IsUnrestricted()
        {
            return m_Unrestricted;
        }
    
        internal enum IsSubsetOfType
        {
            Normal,
            CheckDemand,
            CheckPermitOnly,
            CheckAssertion,
        }
 
        internal bool IsSubsetOfHelper(PermissionSet target, IsSubsetOfType type, out IPermission firstPermThatFailed, bool ignoreNonCas)
        {
    #if _DEBUG
            if (debug)     
                DEBUG_WRITE("IsSubsetOf\n" +
                            "Other:\n" +
                            (target == null ? "<null>" : target.ToString()) +
                            "\nMe:\n" +
                            ToString());
    #endif
    
            firstPermThatFailed = null;
            if (target == null || target.FastIsEmpty())
            {
                if(this.IsEmpty())
                    return true;
                else
                {
                    firstPermThatFailed = GetFirstPerm();
                    return false;
                }
            }
            else if (this.IsUnrestricted() && !target.IsUnrestricted())
                return false;
            else if (this.m_permSet == null)
                return true;
            else
            {
                target.CheckSet();
 
                for (int i = m_permSet.GetStartingIndex(); i <= this.m_permSet.GetMaxUsedIndex(); ++i)
                {
                    IPermission thisPerm = this.GetPermission(i);
                    if (thisPerm == null || thisPerm.IsSubsetOf(null))
                        continue;
 
                    IPermission targetPerm = target.GetPermission(i);
#if _DEBUG                    
                    PermissionToken token = (PermissionToken)PermissionToken.s_tokenSet.GetItem( i );
                    Contract.Assert(targetPerm == null || (token.m_type & PermissionTokenType.DontKnow) == 0, "Token not properly initialized");
#endif
 
                    if (target.m_Unrestricted)
                        continue;
 
                    // targetPerm can be null here, but that is fine since it thisPerm is a subset
                    // of empty/null then we can continue in the loop.
                    CodeAccessPermission cap = thisPerm as CodeAccessPermission;
                    if(cap == null)
                    {
                        if (!ignoreNonCas && !thisPerm.IsSubsetOf( targetPerm ))
                        {
                            firstPermThatFailed = thisPerm;
                            return false;
                        }
                    }
                    else
                    {
                        firstPermThatFailed = thisPerm;
                        switch(type)
                        {
                        case IsSubsetOfType.Normal:
                            if (!thisPerm.IsSubsetOf( targetPerm ))
                                return false;
                            break;
                        case IsSubsetOfType.CheckDemand:
                            if (!cap.CheckDemand( (CodeAccessPermission)targetPerm ))
                                return false;
                            break;
                        case IsSubsetOfType.CheckPermitOnly:
                            if (!cap.CheckPermitOnly( (CodeAccessPermission)targetPerm ))
                                return false;
                            break;
                        case IsSubsetOfType.CheckAssertion:
                            if (!cap.CheckAssert( (CodeAccessPermission)targetPerm ))
                                return false;
                            break;
                        }
                        firstPermThatFailed = null;
                    }
                }
            }
 
            return true;
        }
 
        public bool IsSubsetOf(PermissionSet target)
        {
            IPermission perm;
            return IsSubsetOfHelper(target, IsSubsetOfType.Normal, out perm, false);
        }
 
        internal bool CheckDemand(PermissionSet target, out IPermission firstPermThatFailed)
        {
            return IsSubsetOfHelper(target, IsSubsetOfType.CheckDemand, out firstPermThatFailed, true);
        }
 
        internal bool CheckPermitOnly(PermissionSet target, out IPermission firstPermThatFailed)
        {
            return IsSubsetOfHelper(target, IsSubsetOfType.CheckPermitOnly, out firstPermThatFailed, true);
        }
 
        internal bool CheckAssertion(PermissionSet target)
        {
            IPermission perm;
            return IsSubsetOfHelper(target, IsSubsetOfType.CheckAssertion, out perm, true);
        }
        
        internal bool CheckDeny(PermissionSet deniedSet, out IPermission firstPermThatFailed)
        {
            firstPermThatFailed = null;
            if (deniedSet == null || deniedSet.FastIsEmpty() || this.FastIsEmpty())
                return true;
 
            if(this.m_Unrestricted && deniedSet.m_Unrestricted)
                return false;
 
            CodeAccessPermission permThis, permThat;
            PermissionSetEnumeratorInternal enumThis = new PermissionSetEnumeratorInternal(this);
 
            while (enumThis.MoveNext())
            {
                permThis = enumThis.Current as CodeAccessPermission;
                if(permThis == null || permThis.IsSubsetOf(null))
                    continue; // ignore non-CAS permissions in the grant set.
                if (deniedSet.m_Unrestricted)
                {
                    firstPermThatFailed = permThis;
                    return false;
                }
                permThat = (CodeAccessPermission)deniedSet.GetPermission(enumThis.GetCurrentIndex());
                if (!permThis.CheckDeny(permThat))
                {
                    firstPermThatFailed = permThis;
                    return false;
                }
            }
            if(this.m_Unrestricted)
            {
                PermissionSetEnumeratorInternal enumThat = new PermissionSetEnumeratorInternal(deniedSet);
                while (enumThat.MoveNext())
                {
                    if(enumThat.Current is IPermission)
                        return false;
                }
            }
            return true;
        }
 
        internal void CheckDecoded( CodeAccessPermission demandedPerm, PermissionToken tokenDemandedPerm )
        {
            Contract.Assert( demandedPerm != null, "Expected non-null value" );
 
            if (this.m_allPermissionsDecoded || this.m_permSet == null)
                return;
 
            if (tokenDemandedPerm == null)
                tokenDemandedPerm = PermissionToken.GetToken( demandedPerm );
 
            Contract.Assert( tokenDemandedPerm != null, "Unable to find token for demanded permission" );
        
            CheckDecoded( tokenDemandedPerm.m_index );
        }
 
        internal void CheckDecoded( int index )
        {
            if (this.m_allPermissionsDecoded || this.m_permSet == null)
                return;
 
            GetPermission(index);
        }
 
        internal void CheckDecoded(PermissionSet demandedSet)
        {
            Contract.Assert(demandedSet != null, "Expected non-null value");
 
            if (this.m_allPermissionsDecoded || this.m_permSet == null)
                return;
 
            PermissionSetEnumeratorInternal enumerator = demandedSet.GetEnumeratorInternal();
 
            while (enumerator.MoveNext())
            {
                CheckDecoded(enumerator.GetCurrentIndex());
            }
        }
 
#if FEATURE_CAS_POLICY
        static internal void SafeChildAdd( SecurityElement parent, ISecurityElementFactory child, bool copy )
        {
            if (child == parent)
                return;
            if (child.GetTag().Equals( "IPermission" ) || child.GetTag().Equals( "Permission" ))
            {
                parent.AddChild( child );
            }
            else if (parent.Tag.Equals( child.GetTag() ))
            {
                Contract.Assert( child is SecurityElement, "SecurityElement expected" );
                SecurityElement elChild = (SecurityElement)child;
                Contract.Assert( elChild.InternalChildren != null,
                    "Non-permission elements should have children" );
                    
                for (int i = 0; i < elChild.InternalChildren.Count; ++i)
                {
                    ISecurityElementFactory current = (ISecurityElementFactory)elChild.InternalChildren[i];
                    Contract.Assert( !current.GetTag().Equals( parent.Tag ),
                        "Illegal to insert a like-typed element" );
                    parent.AddChildNoDuplicates( current );
                }
            }
            else
            {
                parent.AddChild( (ISecurityElementFactory)(copy ? child.Copy() : child) );
            }
        }
#endif // FEATURE_CAS_POLICY
 
        internal void InplaceIntersect( PermissionSet other )
        {
            Exception savedException = null;
        
            m_CheckedForNonCas = false;
            
            if (this == other)
                return;
            
            if (other == null || other.FastIsEmpty())
            {
                // If the other is empty or null, make this empty.
                Reset();
                return;
            }
 
            if (this.FastIsEmpty())
                return;
 
            int maxMax = this.m_permSet == null ? -1 : this.m_permSet.GetMaxUsedIndex();
            int otherMax = other.m_permSet == null ? -1 : other.m_permSet.GetMaxUsedIndex();
 
            if (this.IsUnrestricted() && maxMax < otherMax)
            {
                maxMax = otherMax;
                this.CheckSet();
            }
                
            if (other.IsUnrestricted())
            {
                other.CheckSet();
            }
                
            for (int i = 0; i <= maxMax; ++i)
            {
                Object thisObj = this.m_permSet.GetItem( i );
                IPermission thisPerm = thisObj as IPermission;
#if FEATURE_CAS_POLICY
                ISecurityElementFactory thisElem = thisObj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
 
                Object otherObj = other.m_permSet.GetItem( i );
                IPermission otherPerm = otherObj as IPermission;
#if FEATURE_CAS_POLICY
                ISecurityElementFactory otherElem = otherObj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
 
                if (thisObj == null && otherObj == null)
                    continue;
 
#if FEATURE_CAS_POLICY
                if (thisElem != null && otherElem != null)
                {
                    // If we already have an intersection node, just add another child
                    if (thisElem.GetTag().Equals( s_str_PermissionIntersection ) ||
                        thisElem.GetTag().Equals( s_str_PermissionUnrestrictedIntersection ))
                    {
                        Contract.Assert( thisElem is SecurityElement, "SecurityElement expected" );
                        SafeChildAdd( (SecurityElement)thisElem, otherElem, true );
                    }
                    // If either set is unrestricted, intersect the nodes unrestricted
                    else
                    {
                        bool copyOther = true;
                        if (this.IsUnrestricted())
                        {
                            SecurityElement newElemUU = new SecurityElement( s_str_PermissionUnrestrictedUnion );
                            newElemUU.AddAttribute( "class", thisElem.Attribute( "class" ) );
                            SafeChildAdd( newElemUU, thisElem, false );
                            thisElem = newElemUU;
                        }
                        if (other.IsUnrestricted())
                        {
                            SecurityElement newElemUU = new SecurityElement( s_str_PermissionUnrestrictedUnion );
                            newElemUU.AddAttribute( "class", otherElem.Attribute( "class" ) );
                            SafeChildAdd( newElemUU, otherElem, true );
                            otherElem = newElemUU;
                            copyOther = false;
                        }
                        
                        SecurityElement newElem = new SecurityElement( s_str_PermissionIntersection );
                        newElem.AddAttribute( "class", thisElem.Attribute( "class" ) );
                        
                        SafeChildAdd( newElem, thisElem, false );
                        SafeChildAdd( newElem, otherElem, copyOther );
                        this.m_permSet.SetItem( i, newElem );
                    }
                }
                else
#endif // FEATURE_CAS_POLICY
                if (thisObj == null)
                {
                    // There is no object in <this>, so intersection is empty except for IUnrestrictedPermissions
                    if (this.IsUnrestricted())
                    {
#if FEATURE_CAS_POLICY
                        if (otherElem != null)
                        {
                            SecurityElement newElem = new SecurityElement( s_str_PermissionUnrestrictedIntersection );
                            newElem.AddAttribute( "class", otherElem.Attribute( "class" ) );
                            SafeChildAdd( newElem, otherElem, true );
                            this.m_permSet.SetItem( i, newElem );
                            Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                        }
                        else
#endif // FEATURE_CAS_POLICY
                        {
                            PermissionToken token = (PermissionToken)PermissionToken.s_tokenSet.GetItem( i );
                            if ((token.m_type & PermissionTokenType.IUnrestricted) != 0)
                            {
                                this.m_permSet.SetItem( i, otherPerm.Copy() );
                                Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                            }
                        }
                    }
                }
                else if (otherObj == null)
                {
                    if (other.IsUnrestricted())
                    {
#if FEATURE_CAS_POLICY
                        if (thisElem != null)
                        {
                            SecurityElement newElem = new SecurityElement( s_str_PermissionUnrestrictedIntersection );
                            newElem.AddAttribute( "class", thisElem.Attribute( "class" ) );
                            SafeChildAdd( newElem, thisElem, false );
                            this.m_permSet.SetItem( i, newElem );
                        }
                        else
#endif // FEATURE_CAS_POLICY
                        {
                            PermissionToken token = (PermissionToken)PermissionToken.s_tokenSet.GetItem( i );
                            if ((token.m_type & PermissionTokenType.IUnrestricted) == 0)
                                this.m_permSet.SetItem( i, null );
                        }
                    }
                    else
                    {
                        this.m_permSet.SetItem( i, null );
                    }
                }
                else
                {
#if FEATURE_CAS_POLICY
                    if (thisElem != null)
                        thisPerm = this.CreatePermission(thisElem, i);
                    if (otherElem != null)
                        otherPerm = other.CreatePermission(otherElem, i);
#endif // FEATURE_CAS_POLICY
 
                    try
                    {
                        IPermission intersectPerm;
                        if (thisPerm == null)
                            intersectPerm = otherPerm;
                        else if(otherPerm == null)
                            intersectPerm = thisPerm;
                        else
                            intersectPerm = thisPerm.Intersect( otherPerm );
                        this.m_permSet.SetItem( i, intersectPerm );
                    }
                    catch (Exception e)
                    {
                        if (savedException == null)
                            savedException = e;
                    }
                }
            }
 
            this.m_Unrestricted = this.m_Unrestricted && other.m_Unrestricted;
 
            if (savedException != null)
                throw savedException;
        }
 
        public PermissionSet Intersect(PermissionSet other)
        {
            if (other == null || other.FastIsEmpty() || this.FastIsEmpty())
            {
                return null;
            }
 
            int thisMax = this.m_permSet == null ? -1 : this.m_permSet.GetMaxUsedIndex();
            int otherMax = other.m_permSet == null ? -1 : other.m_permSet.GetMaxUsedIndex();
            int minMax = thisMax < otherMax ? thisMax : otherMax;
 
            if (this.IsUnrestricted() && minMax < otherMax)
            {
                minMax = otherMax;
                this.CheckSet();
            }
 
            if (other.IsUnrestricted() && minMax < thisMax)
            {
                minMax = thisMax;
                other.CheckSet();
            }
 
            PermissionSet pset = new PermissionSet( false );
 
            if (minMax > -1)
            {
                pset.m_permSet = new TokenBasedSet();
            }
 
            for (int i = 0; i <= minMax; ++i)
            {
                Object thisObj = this.m_permSet.GetItem( i );
                IPermission thisPerm = thisObj as IPermission;
#if FEATURE_CAS_POLICY
                ISecurityElementFactory thisElem = thisObj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
 
                Object otherObj = other.m_permSet.GetItem( i );
                IPermission otherPerm = otherObj as IPermission;
#if FEATURE_CAS_POLICY
                ISecurityElementFactory otherElem = otherObj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
 
                if (thisObj == null && otherObj == null)
                    continue;
 
#if FEATURE_CAS_POLICY
                if (thisElem != null && otherElem != null)
                {
                    bool copyOther = true;
                    bool copyThis = true;
                    SecurityElement newElem = new SecurityElement( s_str_PermissionIntersection );
                    newElem.AddAttribute( "class", otherElem.Attribute( "class" ) );
                    if (this.IsUnrestricted())
                    {
                        SecurityElement newElemUU = new SecurityElement( s_str_PermissionUnrestrictedUnion );
                        newElemUU.AddAttribute( "class", thisElem.Attribute( "class" ) );
                        SafeChildAdd( newElemUU, thisElem, true );
                        copyThis = false;
                        thisElem = newElemUU;
                    }
                    if (other.IsUnrestricted())
                    {
                        SecurityElement newElemUU = new SecurityElement( s_str_PermissionUnrestrictedUnion );
                        newElemUU.AddAttribute( "class", otherElem.Attribute( "class" ) );
                        SafeChildAdd( newElemUU, otherElem, true );
                        copyOther = false;
                        otherElem = newElemUU;
                    }
 
                    SafeChildAdd( newElem, otherElem, copyOther );
                    SafeChildAdd( newElem, thisElem, copyThis );
                    pset.m_permSet.SetItem( i, newElem );
                }
                else
#endif // FEATURE_CAS_POLICY
                if (thisObj == null)
                {
                    if (this.m_Unrestricted)
                    {
#if FEATURE_CAS_POLICY
                        if (otherElem != null)
                        {
                            SecurityElement newElem = new SecurityElement( s_str_PermissionUnrestrictedIntersection );
                            newElem.AddAttribute( "class", otherElem.Attribute( "class" ) );
                            SafeChildAdd( newElem, otherElem, true );
                            pset.m_permSet.SetItem( i, newElem );
                            Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                        }
                        else
#endif // FEATURE_CAS_POLICY
                        if (otherPerm != null)
                        {
                            PermissionToken token = (PermissionToken)PermissionToken.s_tokenSet.GetItem( i );
                            if ((token.m_type & PermissionTokenType.IUnrestricted) != 0)
                            {
                                pset.m_permSet.SetItem( i, otherPerm.Copy() );
                                Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                            }
                        }
                    }
                }
                else if (otherObj == null)
                {
                    if (other.m_Unrestricted)
                    {
#if FEATURE_CAS_POLICY
                        if (thisElem != null)
                        {
                            SecurityElement newElem = new SecurityElement( s_str_PermissionUnrestrictedIntersection );
                            newElem.AddAttribute( "class", thisElem.Attribute( "class" ) );
                            SafeChildAdd( newElem, thisElem, true );
                            pset.m_permSet.SetItem( i, newElem );
                            Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                        }
                        else
#endif // FEATURE_CAS_POLICY
                        if (thisPerm != null)
                        {
                            PermissionToken token = (PermissionToken)PermissionToken.s_tokenSet.GetItem( i );
                            if ((token.m_type & PermissionTokenType.IUnrestricted) != 0)
                            {
                                pset.m_permSet.SetItem( i, thisPerm.Copy() );
                                Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                            }
                        }
                    }
                }
                else
                {
#if FEATURE_CAS_POLICY
                    if (thisElem != null)
                        thisPerm = this.CreatePermission(thisElem, i);
                    if (otherElem != null)
                        otherPerm = other.CreatePermission(otherElem, i);
#endif // FEATURE_CAS_POLICY
 
                    IPermission intersectPerm;
                    if (thisPerm == null)
                        intersectPerm = otherPerm;
                    else if(otherPerm == null)
                        intersectPerm = thisPerm;
                    else
                        intersectPerm = thisPerm.Intersect( otherPerm );
                    pset.m_permSet.SetItem( i, intersectPerm );
                    Contract.Assert( intersectPerm == null || PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                }
            }
 
            pset.m_Unrestricted = this.m_Unrestricted && other.m_Unrestricted;
            if (pset.FastIsEmpty())
                return null;
            else
                return pset;
        }
 
        internal void InplaceUnion( PermissionSet other )
        {
            // Unions the "other" PermissionSet into this one.  It can be optimized to do less copies than
            // need be done by the traditional union (and we don't have to create a new PermissionSet).
            
            if (this == other)
                return;
            
            // Quick out conditions, union doesn't change this PermissionSet
            if (other == null || other.FastIsEmpty())
                return;
    
    
            m_CheckedForNonCas = false;
            
 
 
                
            this.m_Unrestricted = this.m_Unrestricted || other.m_Unrestricted;
 
            if (this.m_Unrestricted)
            {
                // if the result of Union is unrestricted permset, null the m_permSet member
                this.m_permSet = null;
                return;
            }
 
 
            // If we reach here, result of Union is not unrestricted
            // We have to union "normal" permission no matter what now.
            int maxMax = -1;            
            if (other.m_permSet != null)
            {
                maxMax = other.m_permSet.GetMaxUsedIndex();                        
                this.CheckSet();
            }
            // Save exceptions until the end
            Exception savedException = null;
 
            for (int i = 0; i <= maxMax; ++i)
            {
                Object thisObj = this.m_permSet.GetItem( i );
                IPermission thisPerm = thisObj as IPermission;
#if FEATURE_CAS_POLICY
                ISecurityElementFactory thisElem = thisObj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
 
                Object otherObj = other.m_permSet.GetItem( i );
                IPermission otherPerm = otherObj as IPermission;
#if FEATURE_CAS_POLICY
                ISecurityElementFactory otherElem = otherObj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
 
                if (thisObj == null && otherObj == null)
                    continue;
 
#if FEATURE_CAS_POLICY
                if (thisElem != null && otherElem != null)
                {
                    if (thisElem.GetTag().Equals( s_str_PermissionUnion ) ||
                        thisElem.GetTag().Equals( s_str_PermissionUnrestrictedUnion ))
                    {
                        Contract.Assert( thisElem is SecurityElement, "SecurityElement expected" );
                        SafeChildAdd( (SecurityElement)thisElem, otherElem, true );
                    }
                    else
                    {
                        SecurityElement newElem;
                        if (this.IsUnrestricted() || other.IsUnrestricted())
                            newElem = new SecurityElement( s_str_PermissionUnrestrictedUnion );
                        else
                            newElem = new SecurityElement( s_str_PermissionUnion );
                        newElem.AddAttribute( "class", thisElem.Attribute( "class" ) );
                        SafeChildAdd( newElem, thisElem, false );
                        SafeChildAdd( newElem, otherElem, true );
                        this.m_permSet.SetItem( i, newElem );
                    }
                }
                else
#endif // FEATURE_CAS_POLICY
                if (thisObj == null)
                {
#if FEATURE_CAS_POLICY
                    if (otherElem != null)
                    {
                        this.m_permSet.SetItem( i, otherElem.Copy() );
                    }
                    else
#endif // FEATURE_CAS_POLICY
                    if (otherPerm != null)
                    {
                        PermissionToken token = (PermissionToken)PermissionToken.s_tokenSet.GetItem( i );
                        if (((token.m_type & PermissionTokenType.IUnrestricted) == 0) || !this.m_Unrestricted)
                        {
                            this.m_permSet.SetItem( i, otherPerm.Copy() );
                        }
                    }
                }
                else if (otherObj == null)
                {
                    continue;
                }
                else
                {
#if FEATURE_CAS_POLICY
                    if (thisElem != null)
                        thisPerm = this.CreatePermission(thisElem, i);
                    if (otherElem != null)
                        otherPerm = other.CreatePermission(otherElem, i);
#endif // FEATURE_CAS_POLICY
 
                    try
                    {
                        IPermission unionPerm;
                        if(thisPerm == null)
                            unionPerm = otherPerm;
                        else if(otherPerm == null)
                            unionPerm = thisPerm;
                        else
                            unionPerm = thisPerm.Union( otherPerm );
                        this.m_permSet.SetItem( i, unionPerm );
                    }
                    catch (Exception e)
                    {
                        if (savedException == null)
                            savedException = e;
                    }
                }
            }
            
            if (savedException != null)
                throw savedException;
        }
 
        public PermissionSet Union(PermissionSet other)
        {
            // if other is null or empty, return a clone of myself
            if (other == null || other.FastIsEmpty())
            {
                return this.Copy();
            }
            
            if (this.FastIsEmpty())
            {
                return other.Copy();
            }
 
            int maxMax = -1;
 
            PermissionSet pset = new PermissionSet();
            pset.m_Unrestricted = this.m_Unrestricted || other.m_Unrestricted;
            if (pset.m_Unrestricted)
            {
                // if the result of Union is unrestricted permset, just return
                return pset;
            }
            
            // degenerate case where we look at both this.m_permSet and other.m_permSet
            this.CheckSet();
            other.CheckSet();
            maxMax = this.m_permSet.GetMaxUsedIndex() > other.m_permSet.GetMaxUsedIndex() ? this.m_permSet.GetMaxUsedIndex() : other.m_permSet.GetMaxUsedIndex();
            pset.m_permSet = new TokenBasedSet();
 
 
 
            for (int i = 0; i <= maxMax; ++i)
            {
                Object thisObj = this.m_permSet.GetItem( i );
                IPermission thisPerm = thisObj as IPermission;
#if FEATURE_CAS_POLICY
                ISecurityElementFactory thisElem = thisObj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
 
                Object otherObj = other.m_permSet.GetItem( i );
                IPermission otherPerm = otherObj as IPermission;
#if FEATURE_CAS_POLICY
                ISecurityElementFactory otherElem = otherObj as ISecurityElementFactory;
#endif // FEATURE_CAS_POLICY
 
                if (thisObj == null && otherObj == null)
                    continue;
 
#if FEATURE_CAS_POLICY
                if (thisElem != null && otherElem != null)
                {
                    SecurityElement newElem;
                    if (this.IsUnrestricted() || other.IsUnrestricted())
                        newElem = new SecurityElement( s_str_PermissionUnrestrictedUnion );
                    else
                        newElem = new SecurityElement( s_str_PermissionUnion );
                    newElem.AddAttribute( "class", thisElem.Attribute( "class" ) );
                    SafeChildAdd( newElem, thisElem, true );
                    SafeChildAdd( newElem, otherElem, true );
                    pset.m_permSet.SetItem( i, newElem );
                }
                else
#endif // FEATURE_CAS_POLICY
                if (thisObj == null)
                {
#if FEATURE_CAS_POLICY
                    if (otherElem != null)
                    {
                        pset.m_permSet.SetItem( i, otherElem.Copy() );
                        Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                    }
                    else
#endif // FEATURE_CAS_POLICY
                    if (otherPerm != null)
                    {
                        PermissionToken token = (PermissionToken)PermissionToken.s_tokenSet.GetItem( i );
                        if (((token.m_type & PermissionTokenType.IUnrestricted) == 0) || !pset.m_Unrestricted)
                        {
                            pset.m_permSet.SetItem( i, otherPerm.Copy() );
                            Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                        }
                    }
                }
                else if (otherObj == null)
                {
#if FEATURE_CAS_POLICY
                    if (thisElem != null)
                    {
                        pset.m_permSet.SetItem( i, thisElem.Copy() );
                    }
                    else
#endif // FEATURE_CAS_POLICY
                    if (thisPerm != null)
                    {
                        PermissionToken token = (PermissionToken)PermissionToken.s_tokenSet.GetItem( i );
                        if (((token.m_type & PermissionTokenType.IUnrestricted) == 0) || !pset.m_Unrestricted)
                        {
                            pset.m_permSet.SetItem( i, thisPerm.Copy() );
                            Contract.Assert( PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                        }
                    }
                }
                else
                {
#if FEATURE_CAS_POLICY
                    if (thisElem != null)
                        thisPerm = this.CreatePermission(thisElem, i);
                    if (otherElem != null)
                        otherPerm = other.CreatePermission(otherElem, i);
#endif // FEATURE_CAS_POLICY
 
                    IPermission unionPerm;
                    if(thisPerm == null)
                        unionPerm = otherPerm;
                    else if(otherPerm == null)
                        unionPerm = thisPerm;
                    else
                        unionPerm = thisPerm.Union( otherPerm );
                    pset.m_permSet.SetItem( i, unionPerm );
                    Contract.Assert( unionPerm == null || PermissionToken.s_tokenSet.GetItem( i ) != null, "PermissionToken should already be assigned" );
                }
            }
            
            return pset;
        }
 
        // Treating the current permission set as a grant set, and the input set as
        // a set of permissions to be denied, try to cancel out as many permissions
        // from both sets as possible. For a first cut, any granted permission that
        // is a safe subset of the corresponding denied permission can result in
        // that permission being removed from both sides.
 
        internal void MergeDeniedSet(PermissionSet denied)
        {
            if (denied == null || denied.FastIsEmpty() || this.FastIsEmpty())
                return;
 
            m_CheckedForNonCas = false;
 
            // Check for the unrestricted case: FastIsEmpty() will return false if the PSet is unrestricted, but has no items
            if (this.m_permSet == null || denied.m_permSet == null)
                return; //nothing can be removed
 
            int maxIndex = denied.m_permSet.GetMaxUsedIndex() > this.m_permSet.GetMaxUsedIndex() ? this.m_permSet.GetMaxUsedIndex() : denied.m_permSet.GetMaxUsedIndex();
            for (int i = 0; i <= maxIndex; ++i) {
                IPermission deniedPerm = denied.m_permSet.GetItem(i) as IPermission;
                if (deniedPerm == null)
                    continue;
 
                IPermission thisPerm = this.m_permSet.GetItem(i) as IPermission;
 
                if (thisPerm == null && !this.m_Unrestricted) {
                    denied.m_permSet.SetItem(i, null);
                    continue;
                }
 
                if (thisPerm != null && deniedPerm != null) {
                    if (thisPerm.IsSubsetOf(deniedPerm)) {
                        this.m_permSet.SetItem(i, null);
                        denied.m_permSet.SetItem(i, null);
                    }
                }
            }
        }
 
        // Returns true if perm is contained in this
        internal bool Contains(IPermission perm)
        {
            if (perm == null)
                return true;
            if (m_Unrestricted)
                return true;
            if (FastIsEmpty())
                return false;
 
            PermissionToken token = PermissionToken.GetToken(perm);
            Object thisObj = this.m_permSet.GetItem( token.m_index );
            if (thisObj == null)
                return perm.IsSubsetOf( null );
 
            IPermission thisPerm = GetPermission(token.m_index);
            if (thisPerm != null)
                return perm.IsSubsetOf( thisPerm );
            else
                return perm.IsSubsetOf( null );
        }
 
        [System.Runtime.InteropServices.ComVisible(false)]
        public override bool Equals( Object obj )
        {
            // Note: this method is designed to accept both PermissionSet and NamedPermissionSets.
            // It will compare them based on the values in the base type, thereby ignoring the
            // name and description of the named permission set.
 
            PermissionSet other = obj as PermissionSet;
 
            if (other == null)
                return false;
 
            if (this.m_Unrestricted != other.m_Unrestricted)
                return false;
 
            CheckSet();
            other.CheckSet();
 
            DecodeAllPermissions();
            other.DecodeAllPermissions();
 
            int maxIndex = Math.Max( this.m_permSet.GetMaxUsedIndex(), other.m_permSet.GetMaxUsedIndex() );
 
            for (int i = 0; i <= maxIndex; ++i)
            {
                IPermission thisPerm = (IPermission)this.m_permSet.GetItem( i );
                IPermission otherPerm = (IPermission)other.m_permSet.GetItem( i );
 
                if (thisPerm == null && otherPerm == null)
                {
                    continue;
                }
                else if (thisPerm == null)
                {
                    if (!otherPerm.IsSubsetOf( null ))
                        return false;
                }
                else if (otherPerm == null)
                {
                    if (!thisPerm.IsSubsetOf( null ))
                        return false;
                }
                else
                {
                    if (!thisPerm.Equals( otherPerm ))
                        return false;
                }
            }
 
            return true;
        }
 
        [System.Runtime.InteropServices.ComVisible(false)]
        public override int GetHashCode()
        {
            int accumulator;
 
            accumulator = this.m_Unrestricted ? -1 : 0;
 
            if (this.m_permSet != null)
            {
                DecodeAllPermissions();
 
                int maxIndex = this.m_permSet.GetMaxUsedIndex();
 
                for (int i = m_permSet.GetStartingIndex(); i <= maxIndex; ++i)
                {
                    IPermission perm = (IPermission)this.m_permSet.GetItem( i );
                    if (perm != null)
                    {
                        accumulator = accumulator ^ perm.GetHashCode();
                    }
                }
            }
 
            return accumulator;
        }
    
        // Mark this method as requiring a security object on the caller's frame
        // so the caller won't be inlined (which would mess up stack crawling).
        [System.Security.SecuritySafeCritical]  // auto-generated
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public void Demand()
        {
            if (this.FastIsEmpty())
                return;  // demanding the empty set always passes.
 
            ContainsNonCodeAccessPermissions();
 
            if (m_ContainsCas)
            {
                StackCrawlMark stackMark = StackCrawlMark.LookForMyCallersCaller;
                CodeAccessSecurityEngine.Check(GetCasOnlySet(), ref stackMark);
            }
            if (m_ContainsNonCas)
            {
                DemandNonCAS();
            }
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal void DemandNonCAS()
        {
            ContainsNonCodeAccessPermissions();
 
            if (m_ContainsNonCas)
            {
                if (this.m_permSet != null)
                {
                    CheckSet();
                    for (int i = m_permSet.GetStartingIndex(); i <= this.m_permSet.GetMaxUsedIndex(); ++i)
                    {
                        IPermission currPerm = GetPermission(i);
                        if (currPerm != null && !(currPerm is CodeAccessPermission))
                            currPerm.Demand();
                    }
                }
            }
        }
 
        // Metadata for this method should be flaged with REQ_SQ so that
        // EE can allocate space on the stack frame for FrameSecurityDescriptor
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public void Assert() 
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
            SecurityRuntime.Assert(this, ref stackMark);
        }
    
        // Metadata for this method should be flaged with REQ_SQ so that
        // EE can allocate space on the stack frame for FrameSecurityDescriptor
    
        [System.Security.SecuritySafeCritical]  // auto-generated
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        [Obsolete("Deny is obsolete and will be removed in a future release of the .NET Framework. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
        public void Deny()
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
            SecurityRuntime.Deny(this, ref stackMark);
        }
    
        // Metadata for this method should be flaged with REQ_SQ so that
        // EE can allocate space on the stack frame for FrameSecurityDescriptor
    
        [System.Security.SecuritySafeCritical]  // auto-generated
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public void PermitOnly()
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
            SecurityRuntime.PermitOnly(this, ref stackMark);
        }
 
        internal IPermission GetFirstPerm()
        {
            IEnumerator enumerator = GetEnumerator();
            if(!enumerator.MoveNext())
                return null;
            return enumerator.Current as IPermission;
        }
 
        // Returns a deep copy
        public virtual PermissionSet Copy()
        {
            return new PermissionSet(this);
        }
 
        internal PermissionSet CopyWithNoIdentityPermissions()
        {
            // Explicitly make a new PermissionSet, rather than copying, since we may have a
            // ReadOnlyPermissionSet which cannot have identity permissions removed from it in a true copy.
            PermissionSet copy = new PermissionSet(this);
 
            // There's no easy way to distinguish an identity permission from any other CodeAccessPermission,
            // so remove them directly.
#if FEATURE_CAS_POLICY
            copy.RemovePermission(typeof(GacIdentityPermission));
#if FEATURE_X509
            copy.RemovePermission(typeof(PublisherIdentityPermission));
#endif
            copy.RemovePermission(typeof(StrongNameIdentityPermission));
            copy.RemovePermission(typeof(UrlIdentityPermission));
            copy.RemovePermission(typeof(ZoneIdentityPermission));
#endif // FEATURE_CAS_POLICY
 
            return copy;
        }
 
        public IEnumerator GetEnumerator()
        {
            return GetEnumeratorImpl();
        }
 
        protected virtual IEnumerator GetEnumeratorImpl()
        {
            return new PermissionSetEnumerator(this);
        }
 
        internal PermissionSetEnumeratorInternal GetEnumeratorInternal()
        {
            return new PermissionSetEnumeratorInternal(this);
        }
 
#if FEATURE_CAS_POLICY
        public override String ToString()
        {
            return ToXml().ToString();
        }
#endif // FEATURE_CAS_POLICY
 
        private void NormalizePermissionSet()
        {
            // This function guarantees that all the permissions are placed at
            // the proper index within the token based sets.  This becomes necessary
            // since these indices are dynamically allocated based on usage order.
        
            PermissionSet permSetTemp = new PermissionSet(false);
            
            permSetTemp.m_Unrestricted = this.m_Unrestricted;
 
            // Move all the normal permissions to the new permission set
 
            if (this.m_permSet != null)
            {
                for (int i = m_permSet.GetStartingIndex(); i <= this.m_permSet.GetMaxUsedIndex(); ++i)
                {
                    Object obj = this.m_permSet.GetItem(i);
                    IPermission perm = obj as IPermission;
#if FEATURE_CAS_POLICY
                    ISecurityElementFactory elem = obj as ISecurityElementFactory;
 
                    if (elem != null)
                        perm = CreatePerm( elem );
#endif // FEATURE_CAS_POLICY
                    if (perm != null)
                        permSetTemp.SetPermission( perm );
                }
            }
    
            this.m_permSet = permSetTemp.m_permSet;
        }
 
#if FEATURE_CAS_POLICY
        private bool DecodeXml(byte[] data, HostProtectionResource fullTrustOnlyResources, HostProtectionResource inaccessibleResources )
        {
            if (data != null && data.Length > 0)
            {
                FromXml( new Parser( data, Tokenizer.ByteTokenEncoding.UnicodeTokens ).GetTopElement() );
            }
 
            FilterHostProtectionPermissions(fullTrustOnlyResources, inaccessibleResources);
 
            // We call this method from unmanaged to code a set we are going to use declaratively.  In
            // this case, all the lazy evaluation for partial policy resolution is wasted since we'll
            // need to decode all of these shortly to make the demand for whatever.  Therefore, we
            // pay that price now so that we can calculate whether all the permissions in the set
            // implement the IUnrestrictedPermission interface (the common case) for use in some
            // unmanaged optimizations.
 
            DecodeAllPermissions();
 
            return true;
        }
#endif // FEATURE_CAS_POLICY
 
        private void DecodeAllPermissions()
        {
            if (m_permSet == null)
            {
                m_allPermissionsDecoded = true;
                return;
            }
 
            int maxIndex = m_permSet.GetMaxUsedIndex();
            for (int i = 0; i <= maxIndex; ++i)
            {
                // GetPermission has the side-effect of decoding the permission in the slot
                GetPermission(i);
            }
 
            m_allPermissionsDecoded = true;
        }
 
        internal void FilterHostProtectionPermissions(HostProtectionResource fullTrustOnly, HostProtectionResource inaccessible)
        {
            HostProtectionPermission.protectedResources = fullTrustOnly;
            HostProtectionPermission hpp = (HostProtectionPermission)GetPermission(HostProtectionPermission.GetTokenIndex());
            if(hpp == null)
                return;
 
            HostProtectionPermission newHpp = (HostProtectionPermission)hpp.Intersect(new HostProtectionPermission(fullTrustOnly));
            if (newHpp == null)
            {
#if FEATURE_CAS_POLICY
                RemovePermission(typeof(HostProtectionPermission));
#else // !FEATURE_CAS_POLICY
                RemovePermission(HostProtectionPermission.GetTokenIndex());
#endif // FEATURE_CAS_POLICY
            }
            else if (newHpp.Resources != hpp.Resources)
            {
                SetPermission(newHpp);
            }
        }
 
#if FEATURE_CAS_POLICY
        public virtual void FromXml( SecurityElement et )
        {
            FromXml( et, false, false );
        }
 
        internal static bool IsPermissionTag( String tag, bool allowInternalOnly )
        {
            if (tag.Equals( s_str_Permission ) ||
                tag.Equals( s_str_IPermission ))
            {
                return true;
            }
 
            if (allowInternalOnly &&
                (tag.Equals( s_str_PermissionUnion ) ||
                 tag.Equals( s_str_PermissionIntersection ) ||
                 tag.Equals( s_str_PermissionUnrestrictedIntersection ) ||
                 tag.Equals( s_str_PermissionUnrestrictedUnion)))
            {
                return true;
            }
 
            return false;
        }
 
        internal virtual void FromXml( SecurityElement et, bool allowInternalOnly, bool ignoreTypeLoadFailures )
        {
            if (et == null)
                throw new ArgumentNullException("et");
 
            if (!et.Tag.Equals(s_str_PermissionSet))
                throw new ArgumentException(String.Format( null, Environment.GetResourceString( "Argument_InvalidXMLElement" ), "PermissionSet", this.GetType().FullName) );
            Contract.EndContractBlock();
 
            Reset();
            m_ignoreTypeLoadFailures = ignoreTypeLoadFailures;
            m_allPermissionsDecoded = false;
            m_Unrestricted = XMLUtil.IsUnrestricted( et );
 
            if (et.InternalChildren != null)
            {
                int childCount = et.InternalChildren.Count;
                for (int i = 0; i < childCount; ++i)
                {
                    SecurityElement elem = (SecurityElement)et.Children[i];
                
                    if (IsPermissionTag( elem.Tag, allowInternalOnly ))
                    {
                        String className = elem.Attribute( "class" );
 
                        PermissionToken token;
                        Object objectToInsert;
                        
                        if (className != null)
                        {
                            token = PermissionToken.GetToken( className );
                            if (token == null)
                            {
                                objectToInsert = CreatePerm( elem );
#if _DEBUG
                                PermissionToken tokenDebug = PermissionToken.GetToken( (IPermission)objectToInsert );
                                Contract.Assert( tokenDebug != null && (tokenDebug.m_type & PermissionTokenType.BuiltIn) != 0, "This should only be called for built-ins" );
#endif
                                if (objectToInsert != null)
                                {
                                    Contract.Assert( objectToInsert.GetType().Module.Assembly == System.Reflection.Assembly.GetExecutingAssembly(),
                                        "PermissionToken.GetToken returned null for non-mscorlib permission" );
                                    token = PermissionToken.GetToken( (IPermission)objectToInsert );
                                    Contract.Assert( (token.m_type & PermissionTokenType.DontKnow) == 0, "We should always know the permission type when getting a token from an instance" );
                                }
                            }
                            else
                            {
                                objectToInsert = elem;
                            }
                        }
                        else
                        {
                            IPermission ip = CreatePerm( elem );
                            if (ip == null)
                            {
                                token = null;
                                objectToInsert = null;
                            }
                            else
                            {
                                token = PermissionToken.GetToken( ip );
                                Contract.Assert( PermissionToken.IsTokenProperlyAssigned( ip, token ),
                                                 "PermissionToken was improperly assigned" );
                                objectToInsert = ip;
                            }
                        }
 
                        if (token != null && objectToInsert != null)
                        {
                            if (m_permSet == null)
                                m_permSet = new TokenBasedSet();
 
                            if (this.m_permSet.GetItem( token.m_index ) != null)
                            {
                                // If there is already something in that slot, let's union them
                                // together.
 
                                IPermission permInSlot;
 
                                if (this.m_permSet.GetItem( token.m_index ) is IPermission)
                                    permInSlot = (IPermission)this.m_permSet.GetItem( token.m_index );
                                else
                                    permInSlot = CreatePerm( (SecurityElement)this.m_permSet.GetItem( token.m_index ) );
                                    
                                if (objectToInsert is IPermission)
                                    objectToInsert = ((IPermission)objectToInsert).Union( permInSlot );
                                else
                                    objectToInsert = CreatePerm( (SecurityElement)objectToInsert ).Union( permInSlot );
                            }
 
                            if(m_Unrestricted && objectToInsert is IPermission)
                                objectToInsert = null;
 
                            this.m_permSet.SetItem( token.m_index, objectToInsert );
                        }
                    }
                }
            }
        }
 
        internal virtual void FromXml( SecurityDocument doc, int position, bool allowInternalOnly )
        {
            if (doc == null)
                throw new ArgumentNullException("doc");
            Contract.EndContractBlock();
            
            if (!doc.GetTagForElement( position ).Equals(s_str_PermissionSet))
                throw new ArgumentException(String.Format( null, Environment.GetResourceString( "Argument_InvalidXMLElement" ), "PermissionSet", this.GetType().FullName) );
            
            Reset();
            m_allPermissionsDecoded = false;
            Exception savedException = null;
            String strUnrestricted = doc.GetAttributeForElement( position, "Unrestricted" );
            if (strUnrestricted != null)
                m_Unrestricted = strUnrestricted.Equals( "True" ) || strUnrestricted.Equals( "true" ) || strUnrestricted.Equals( "TRUE" );
            else
                m_Unrestricted = false;
 
            ArrayList childrenIndices = doc.GetChildrenPositionForElement( position );
            int childCount = childrenIndices.Count;
            for (int i = 0; i < childCount; ++i)
            {
                int childIndex = (int)childrenIndices[i];
                if (IsPermissionTag( doc.GetTagForElement( childIndex ), allowInternalOnly ))
                {
                    try
                    {
                        String className = doc.GetAttributeForElement( childIndex, "class" );
 
                        PermissionToken token;
                        Object objectToInsert;
                        
                        if (className != null)
                        {
                            token = PermissionToken.GetToken( className );
                            if (token == null)
                            {
                                objectToInsert = CreatePerm( doc.GetElement( childIndex, true ) );
 
                                if (objectToInsert != null)
                                {
#if _DEBUG
                                    PermissionToken tokenDebug = PermissionToken.GetToken( (IPermission)objectToInsert );
                                    Contract.Assert((tokenDebug != null), "PermissionToken.GetToken returned null ");
                                    Contract.Assert( (tokenDebug.m_type & PermissionTokenType.BuiltIn) != 0, "This should only be called for built-ins" );
#endif
                                    Contract.Assert( objectToInsert.GetType().Module.Assembly == System.Reflection.Assembly.GetExecutingAssembly(),
                                        "PermissionToken.GetToken returned null for non-mscorlib permission" );
                                    token = PermissionToken.GetToken( (IPermission)objectToInsert );
                                    Contract.Assert((token != null), "PermissionToken.GetToken returned null ");
                                    Contract.Assert( (token.m_type & PermissionTokenType.DontKnow) == 0, "We should always know the permission type when getting a token from an instance" );
                                }
                            }
                            else
                            {
                                objectToInsert = ((ISecurityElementFactory)new SecurityDocumentElement(doc, childIndex)).CreateSecurityElement();
                            }
                        }
                        else
                        {
                            IPermission ip = CreatePerm( doc.GetElement( childIndex, true ) );
                            if (ip == null)
                            {
                                token = null;
                                objectToInsert = null;
                            }
                            else
                            {
                                token = PermissionToken.GetToken( ip );
                                Contract.Assert( PermissionToken.IsTokenProperlyAssigned( ip, token ),
                                                 "PermissionToken was improperly assigned" );
                                objectToInsert = ip;
                            }
                        }
 
                        if (token != null && objectToInsert != null)
                        {
                            if (m_permSet == null)
                                m_permSet = new TokenBasedSet();
 
                            IPermission permInSlot = null;
                            if (this.m_permSet.GetItem( token.m_index ) != null)
                            {
                                // If there is already something in that slot, let's union them
                                // together.
                                
                                if (this.m_permSet.GetItem( token.m_index ) is IPermission)
                                    permInSlot = (IPermission)this.m_permSet.GetItem( token.m_index );
                                else
                                    permInSlot = CreatePerm( this.m_permSet.GetItem( token.m_index ) );
                            }
 
                            if (permInSlot != null)
                            {
                                if (objectToInsert is IPermission)
                                    objectToInsert = permInSlot.Union((IPermission)objectToInsert);
                                else
                                    objectToInsert = permInSlot.Union(CreatePerm( objectToInsert ));
                            }
 
                            if(m_Unrestricted && objectToInsert is IPermission)
                                objectToInsert = null;
 
                            this.m_permSet.SetItem( token.m_index, objectToInsert );
                        }
                    }
                    catch (Exception e)
                    {
#if _DEBUG
                        if (debug)
                            DEBUG_WRITE( "error while decoding permission set =\n" + e.ToString() );
#endif
                        if (savedException == null)
                            savedException = e;
 
                    }
                }
            }
 
            if (savedException != null)
                throw savedException;
                
        }
 
        private  IPermission CreatePerm(Object obj)
        {
            return CreatePerm(obj, m_ignoreTypeLoadFailures);
        }
 
        internal static IPermission CreatePerm(Object obj, bool ignoreTypeLoadFailures)
        {
            SecurityElement el = obj as SecurityElement;
            ISecurityElementFactory isf = obj as ISecurityElementFactory;
            if (el == null && isf != null)
            {
                el = isf.CreateSecurityElement();
            }
 
            IEnumerator enumerator;
            IPermission finalPerm = null;
 
            switch (el.Tag)
            {
            case s_str_PermissionUnion:
                enumerator = el.Children.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    IPermission tempPerm = CreatePerm( (SecurityElement)enumerator.Current, ignoreTypeLoadFailures);
 
                    if (finalPerm != null)
                        finalPerm = finalPerm.Union( tempPerm );
                    else
                        finalPerm = tempPerm;
                }
                break;
 
            case s_str_PermissionIntersection:
                enumerator = el.Children.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    IPermission tempPerm = CreatePerm( (SecurityElement)enumerator.Current, ignoreTypeLoadFailures);
 
                    if (finalPerm != null)
                        finalPerm = finalPerm.Intersect( tempPerm );
                    else
                        finalPerm = tempPerm;
 
                    if (finalPerm == null)
                        return null;
                }
                break;
 
            case s_str_PermissionUnrestrictedUnion:
                enumerator = el.Children.GetEnumerator();
                bool first = true;
                while (enumerator.MoveNext())
                {
                    IPermission tempPerm = CreatePerm( (SecurityElement)enumerator.Current, ignoreTypeLoadFailures );
                    
                    if (tempPerm == null)
                        continue;
 
                    PermissionToken token = PermissionToken.GetToken( tempPerm );
 
                    Contract.Assert( (token.m_type & PermissionTokenType.DontKnow) == 0, "We should know the permission type already" );
 
                    if ((token.m_type & PermissionTokenType.IUnrestricted) != 0)
                    {
                        finalPerm = XMLUtil.CreatePermission( GetPermissionElement((SecurityElement)enumerator.Current), PermissionState.Unrestricted, ignoreTypeLoadFailures );
                        first = false;
                        break;
                    }
                    else
                    {
                        Contract.Assert( tempPerm != null, "We should only come here if we have a real permission" );
                        if (first)
                            finalPerm = tempPerm;
                        else
                            finalPerm = tempPerm.Union( finalPerm );
                        first = false;
                    }
                }
                break;
 
            case s_str_PermissionUnrestrictedIntersection:
                enumerator = el.Children.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    IPermission tempPerm = CreatePerm( (SecurityElement)enumerator.Current, ignoreTypeLoadFailures );
                    
                    if (tempPerm == null)
                        return null;
 
                    PermissionToken token = PermissionToken.GetToken( tempPerm );
 
                    Contract.Assert( (token.m_type & PermissionTokenType.DontKnow) == 0, "We should know the permission type already" );
 
                    if ((token.m_type & PermissionTokenType.IUnrestricted) != 0)
                    {
                        if (finalPerm != null)
                            finalPerm = tempPerm.Intersect( finalPerm );
                        else
                            finalPerm = tempPerm;
                    }
                    else
                    {
                        finalPerm = null;
                    }
 
                    if (finalPerm == null)
                        return null;
                }
                break;
 
            case "IPermission":
            case "Permission":
                finalPerm = el.ToPermission(ignoreTypeLoadFailures);
                break;
 
            default:
                Contract.Assert( false, "Unrecognized case found during permission creation" );
                break;
            }
 
            return finalPerm;
        }
 
        internal IPermission CreatePermission(Object obj, int index)
        {
            IPermission perm = CreatePerm(obj);
            if(perm == null)
                return null;
 
            // See if the PermissionSet.m_Unrestricted flag covers this permission
            if(m_Unrestricted)
                perm = null;
 
            // Store the decoded result
            CheckSet();
            m_permSet.SetItem(index, perm);
 
            // Do some consistency checks
            Contract.Assert(perm == null || PermissionToken.IsTokenProperlyAssigned( perm, PermissionToken.GetToken( perm ) ), "PermissionToken was improperly assigned");
            if (perm != null)
            {
                PermissionToken permToken = PermissionToken.GetToken(perm);
                if (permToken != null && permToken.m_index != index)
                    throw new ArgumentException( Environment.GetResourceString( "Argument_UnableToGeneratePermissionSet"));
            }
            
 
            return perm;
        }
 
        private static SecurityElement GetPermissionElement( SecurityElement el )
        {
            switch (el.Tag)
            {
            case "IPermission":
            case "Permission":
                return el;
            }
            IEnumerator enumerator = el.Children.GetEnumerator();
            if (enumerator.MoveNext())
                return GetPermissionElement((SecurityElement)enumerator.Current);
            Contract.Assert( false, "No Permission or IPermission tag found" );
            return null;
        }
 
        internal static SecurityElement CreateEmptyPermissionSetXml()
        {
            
            SecurityElement elTrunk = new SecurityElement("PermissionSet");
            elTrunk.AddAttribute( "class", "System.Security.PermissionSet" );
 
            elTrunk.AddAttribute( "version", "1" );
            return elTrunk;
        
        }
        // internal helper which takes in the hardcoded permission name to avoid lookup at runtime
        // can be called from classes that derive from PermissionSet
        internal SecurityElement ToXml(String permName)
        {
            SecurityElement elTrunk = new SecurityElement("PermissionSet");
            elTrunk.AddAttribute( "class", permName );
 
            elTrunk.AddAttribute( "version", "1" );
        
            PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(this);
    
            if (m_Unrestricted)
            {
                elTrunk.AddAttribute(s_str_Unrestricted, "true" );
            }
   
            while (enumerator.MoveNext())
            {
                IPermission perm = (IPermission)enumerator.Current;
 
                if (!m_Unrestricted)
                    elTrunk.AddChild( perm.ToXml() );
            }
            return elTrunk;
        }
 
        internal SecurityElement InternalToXml()
        {
            SecurityElement elTrunk = new SecurityElement("PermissionSet");
            elTrunk.AddAttribute( "class", this.GetType().FullName);
            elTrunk.AddAttribute( "version", "1" );
        
            if (m_Unrestricted)
            {
                elTrunk.AddAttribute(s_str_Unrestricted, "true" );
            }
    
            if (this.m_permSet != null)
            {
                int maxIndex = this.m_permSet.GetMaxUsedIndex();
 
                for (int i = m_permSet.GetStartingIndex(); i <= maxIndex; ++i)
                {
                    Object obj = this.m_permSet.GetItem( i );
                    if (obj != null)
                    {
                        if (obj is IPermission)
                        {
                            if (!m_Unrestricted)
                                elTrunk.AddChild( ((IPermission)obj).ToXml() );
                        }
                        else
                        {
                            elTrunk.AddChild( (SecurityElement)obj );
                        }
                    }
 
                }
            }
            return elTrunk ;
        }
 
        public virtual SecurityElement ToXml()
        {
            // If you hit this assert then most likely you are trying to change the name of this class. 
            // This is ok as long as you change the hard coded string above and change the assert below.
            Contract.Assert( this.GetType().FullName.Equals( "System.Security.PermissionSet" ), "Class name changed! Was: System.Security.PermissionSet Should be:" +  this.GetType().FullName);
                        
            return ToXml("System.Security.PermissionSet");   
        }
#endif // FEATURE_CAS_POLICY
 
#if FEATURE_CAS_POLICY && FEATURE_SERIALIZATION
        internal
        byte[] EncodeXml()
        {
            MemoryStream ms = new MemoryStream();
            BinaryWriter writer = new BinaryWriter( ms, Encoding.Unicode );
            writer.Write( this.ToXml().ToString() );
            writer.Flush();
 
            // The BinaryWriter is going to place
            // two bytes indicating a Unicode stream.
            // We want to chop those off before returning
            // the bytes out.
 
            ms.Position = 2;
            int countBytes = (int)ms.Length - 2;
            byte[] retval = new byte[countBytes];
            ms.Read( retval, 0, retval.Length );
            return retval;
        }
 
        /// <internalonly/>
        [Obsolete("This method is obsolete and shoud no longer be used.")]
        public static byte[] ConvertPermissionSet(String inFormat, byte[] inData, String outFormat)
        {
            // Since this method has shipped and is public, we cannot remove it without being a breaking change
            throw new NotImplementedException();
        }
#endif
 
        // Determines whether the permission set contains any non-code access
        // security permissions.
        #if FEATURE_CORECLR
        [System.Security.SecurityCritical] // auto-generated
        #endif
        public bool ContainsNonCodeAccessPermissions()
        {
            if (m_CheckedForNonCas)
                return m_ContainsNonCas;
 
            lock (this)
            {
                if (m_CheckedForNonCas)
                    return m_ContainsNonCas;
 
                m_ContainsCas = false;
                m_ContainsNonCas = false;
 
                if (IsUnrestricted())
                    m_ContainsCas = true;
 
                if (this.m_permSet != null)
                {
                    PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(this);
 
                    while (enumerator.MoveNext() && (!m_ContainsCas || !m_ContainsNonCas))
                    {
                        IPermission perm = enumerator.Current as IPermission;
 
                        if (perm != null)
                        {
                            if (perm is CodeAccessPermission)
                                m_ContainsCas = true;
                            else
                                m_ContainsNonCas = true;
                        }
                    }
                }
 
                m_CheckedForNonCas = true;
            }
 
            return m_ContainsNonCas;
        }
        
        // Returns a permission set containing only CAS-permissions. If possible
        // this is just the input set, otherwise a new set is allocated.
        private PermissionSet GetCasOnlySet()
        {
            if (!m_ContainsNonCas)
                return this;
 
            if (IsUnrestricted())
                return this;
 
            PermissionSet pset = new PermissionSet(false);
 
            PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(this);
 
            while (enumerator.MoveNext())
            {
                IPermission perm = (IPermission)enumerator.Current;
 
                if (perm is CodeAccessPermission)
                    pset.AddPermission(perm);
            }
 
            pset.m_CheckedForNonCas = true;
            pset.m_ContainsCas = !pset.IsEmpty();
            pset.m_ContainsNonCas = false;
 
            return pset;
        }
 
#if FEATURE_CAS_POLICY
        private const String s_str_PermissionSet = "PermissionSet";
        private const String s_str_Permission    = "Permission";
        private const String s_str_IPermission    = "IPermission";
        private const String s_str_Unrestricted  = "Unrestricted";
        private const String s_str_PermissionUnion = "PermissionUnion";
        private const String s_str_PermissionIntersection = "PermissionIntersection";
        private const String s_str_PermissionUnrestrictedUnion = "PermissionUnrestrictedUnion";
        private const String s_str_PermissionUnrestrictedIntersection = "PermissionUnrestrictedIntersection";
 
        // This method supports v1.x security attrbutes only - we'll require legacy CAS policy mode
        // to be enabled for that to work.
#pragma warning disable 618
        // Internal routine used to setup a special security context
        // for creating and manipulated security custom attributes
        // that we use when the Runtime is hosted.
        [System.Security.SecurityCritical]  // auto-generated
        private static void SetupSecurity()
        {
            PolicyLevel level = PolicyLevel.CreateAppDomainLevel();
 
            CodeGroup rootGroup = new UnionCodeGroup( new AllMembershipCondition(), level.GetNamedPermissionSet( "Execution" ) );
 
            StrongNamePublicKeyBlob microsoftBlob = new StrongNamePublicKeyBlob( AssemblyRef.MicrosoftPublicKeyFull );
            CodeGroup microsoftGroup = new UnionCodeGroup( new StrongNameMembershipCondition( microsoftBlob, null, null ), level.GetNamedPermissionSet( "FullTrust" ) );
 
            StrongNamePublicKeyBlob ecmaBlob = new StrongNamePublicKeyBlob( AssemblyRef.EcmaPublicKeyFull );
            CodeGroup ecmaGroup = new UnionCodeGroup( new StrongNameMembershipCondition( ecmaBlob, null, null ), level.GetNamedPermissionSet( "FullTrust" ) );
 
            CodeGroup gacGroup = new UnionCodeGroup( new GacMembershipCondition(), level.GetNamedPermissionSet( "FullTrust" ) );
 
            rootGroup.AddChild( microsoftGroup );
            rootGroup.AddChild( ecmaGroup );
            rootGroup.AddChild( gacGroup );
 
            level.RootCodeGroup = rootGroup;
 
            try
            {
                AppDomain.CurrentDomain.SetAppDomainPolicy( level );
            }
            catch (PolicyException)
            {
            }
        }
#endif
#pragma warning restore 618
 
        // Internal routine used by CreateSerialized to add a permission to the set
        private static void MergePermission(IPermission perm, bool separateCasFromNonCas, ref PermissionSet casPset, ref PermissionSet nonCasPset)
        {
            Contract.Assert(casPset == null || !casPset.IsReadOnly);
            Contract.Assert(nonCasPset == null || !nonCasPset.IsReadOnly);
 
            if (perm == null)
                return;
 
            if (!separateCasFromNonCas || perm is CodeAccessPermission)
            {
                if(casPset == null)
                    casPset = new PermissionSet(false);
                IPermission oldPerm = casPset.GetPermission(perm);
                IPermission unionPerm = casPset.AddPermission(perm);
                if (oldPerm != null && !oldPerm.IsSubsetOf( unionPerm ))
                    throw new NotSupportedException( Environment.GetResourceString( "NotSupported_DeclarativeUnion" ) );
            }
            else
            {
                if(nonCasPset == null)
                    nonCasPset = new PermissionSet(false);
                IPermission oldPerm = nonCasPset.GetPermission(perm);
                IPermission unionPerm = nonCasPset.AddPermission( perm );
                if (oldPerm != null && !oldPerm.IsSubsetOf( unionPerm ))
                    throw new NotSupportedException( Environment.GetResourceString( "NotSupported_DeclarativeUnion" ) );
            }
        }
 
        // Converts an array of SecurityAttributes to a PermissionSet
        #if FEATURE_CORECLR
        [System.Security.SecurityCritical] // auto-generated
        #endif
        [ResourceExposure(ResourceScope.Machine)]  // Reading these attributes can load files.
        [ResourceConsumption(ResourceScope.Machine)]
        private static byte[] CreateSerialized(Object[] attrs,
                                               bool serialize,
                                               ref byte[] nonCasBlob,
                                               out PermissionSet casPset,
                                               HostProtectionResource fullTrustOnlyResources,
                                               bool allowEmptyPermissionSets)
        {
            // Create two new (empty) sets.
            casPset = null;
            PermissionSet nonCasPset = null;
 
            // Most security attributes generate a single permission. The
            // PermissionSetAttribute class generates an entire permission set we
            // need to merge, however.
            for (int i = 0; i < attrs.Length; i++)
            {
#pragma warning disable 618
                Contract.Assert(i == 0 || ((SecurityAttribute)attrs[i]).m_action == ((SecurityAttribute)attrs[i - 1]).m_action, "Mixed SecurityActions");
#pragma warning restore 618
                if (attrs[i] is PermissionSetAttribute)
                {
                    PermissionSet pset = ((PermissionSetAttribute)attrs[i]).CreatePermissionSet();
                    if (pset == null)
                        throw new ArgumentException( Environment.GetResourceString( "Argument_UnableToGeneratePermissionSet" ) );
 
                    PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(pset);
 
                    while (enumerator.MoveNext())
                    {
                        IPermission perm = (IPermission)enumerator.Current;
                        MergePermission(perm, serialize, ref casPset, ref nonCasPset);
                    }
 
                    if(casPset == null)
                        casPset = new PermissionSet(false);
                    if (pset.IsUnrestricted())
                        casPset.SetUnrestricted(true);
                }
                else
                {
#pragma warning disable 618
                    IPermission perm = ((SecurityAttribute)attrs[i]).CreatePermission();
#pragma warning restore 618
                    MergePermission(perm, serialize, ref casPset, ref nonCasPset);
                }
            }
            Contract.Assert(serialize || nonCasPset == null, "We shouldn't separate nonCAS permissions unless fSerialize is true");
 
            //
            // Filter HostProtection permission.  In the VM, some optimizations are done based upon these
            // declarative permission sets being NULL if they do not exist.  When filtering the permission
            // set if we end up with an empty set, we can the permission set NULL rather than returning the
            // empty set in order to enable those optimizations.
            //
            
            if(casPset != null)
            {
                casPset.FilterHostProtectionPermissions(fullTrustOnlyResources, HostProtectionResource.None);
                casPset.ContainsNonCodeAccessPermissions(); // make sure all declarative PermissionSets are checked for non-CAS so we can just check the flag from native code
                if (allowEmptyPermissionSets && casPset.IsEmpty())
                    casPset = null;
            }
            if(nonCasPset != null)
            {
                nonCasPset.FilterHostProtectionPermissions(fullTrustOnlyResources, HostProtectionResource.None);
                nonCasPset.ContainsNonCodeAccessPermissions(); // make sure all declarative PermissionSets are checked for non-CAS so we can just check the flag from native code
                if (allowEmptyPermissionSets && nonCasPset.IsEmpty())
                    nonCasPset = null;
            }
 
            // Serialize the set(s).
            byte[] casBlob = null;
            nonCasBlob = null;
#if FEATURE_CAS_POLICY
            if(serialize)
            {
                if(casPset != null)
                    casBlob = casPset.EncodeXml();
                if(nonCasPset != null)
                    nonCasBlob = nonCasPset.EncodeXml();
            }
#else // FEATURE_CAS_POLICY
            Contract.Assert(!serialize, "Cannot serialize permission sets on CoreCLR");
#endif // FEATURE_CAS_POLICY
 
            return casBlob;
        }
 
#if FEATURE_SERIALIZATION
        /// <internalonly/>
        void IDeserializationCallback.OnDeserialization(Object sender)        
        {
            NormalizePermissionSet();
            m_CheckedForNonCas = false;
        }
#endif
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public static void RevertAssert()
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
            SecurityRuntime.RevertAssert(ref stackMark);
        }
 
        internal static PermissionSet RemoveRefusedPermissionSet(PermissionSet assertSet, PermissionSet refusedSet, out bool bFailedToCompress)
        {
            Contract.Assert((assertSet == null || !assertSet.IsUnrestricted()), "Cannot be unrestricted here");
            PermissionSet retPs = null;
            bFailedToCompress = false;
            if (assertSet == null)
                return null;
            if (refusedSet != null)
            {
                if (refusedSet.IsUnrestricted())
                    return null; // we're refusing everything...cannot assert anything now.
 
                PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(refusedSet);
                while (enumerator.MoveNext())
                {
                    CodeAccessPermission refusedPerm = (CodeAccessPermission)enumerator.Current;
                    int i = enumerator.GetCurrentIndex();
                    if (refusedPerm != null)
                    {
                        CodeAccessPermission perm
                            = (CodeAccessPermission)assertSet.GetPermission(i);
                        try
                        {
                            if (refusedPerm.Intersect(perm) != null)
                            {
                                if (refusedPerm.Equals(perm))
                                {
                                    if (retPs == null)
                                        retPs = assertSet.Copy();
                
                                    retPs.RemovePermission(i);
                                }
                                else
                                {
                                    // Asserting a permission, part of which is already denied/refused
                                    // cannot compress this assert
                                    bFailedToCompress = true;
                                    return assertSet;
                                }
                            }
                        }
                        catch (ArgumentException)
                        {
                            // Any exception during removing a refused set from assert set => we play it safe and not assert that perm
                            if (retPs == null)
                                retPs = assertSet.Copy();
                            retPs.RemovePermission(i);
                        }
                    }
                }
            }
            if (retPs != null)
                return retPs;
            return assertSet;
        }  
 
        internal static void RemoveAssertedPermissionSet(PermissionSet demandSet, PermissionSet assertSet, out PermissionSet alteredDemandSet)
        {
            Contract.Assert(!assertSet.IsUnrestricted(), "Cannot call this function if assertSet is unrestricted");
            alteredDemandSet = null;
            
            PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(demandSet);
            while (enumerator.MoveNext())
            {
                CodeAccessPermission demandDerm = (CodeAccessPermission)enumerator.Current;
                int i = enumerator.GetCurrentIndex();
                if (demandDerm != null)
                {
                    CodeAccessPermission assertPerm
                        = (CodeAccessPermission)assertSet.GetPermission(i);
                    try
                    {
                        if (demandDerm.CheckAssert(assertPerm))
                        {
                            if (alteredDemandSet == null)
                                alteredDemandSet = demandSet.Copy();
            
                            alteredDemandSet.RemovePermission(i);
                        }
                    }
                    catch (ArgumentException)
                    {
                    }
                }
            }
            return;
        }
 
        internal static bool IsIntersectingAssertedPermissions(PermissionSet assertSet1, PermissionSet assertSet2)
        {
            bool isIntersecting = false;
            if (assertSet1 != null && assertSet2 != null)
            {
                PermissionSetEnumeratorInternal enumerator = new PermissionSetEnumeratorInternal(assertSet2);
                while (enumerator.MoveNext())
                {
                    CodeAccessPermission perm2 = (CodeAccessPermission)enumerator.Current;
                    int i = enumerator.GetCurrentIndex();
                    if (perm2 != null)
                    {
                        CodeAccessPermission perm1
                            = (CodeAccessPermission)assertSet1.GetPermission(i);
                        try
                        {
                            if (perm1 != null && !perm1.Equals(perm2))
                            {
                                isIntersecting = true; // Same type of permission, but with different flags or something - cannot union them
                            }
                        }
                        catch (ArgumentException)
                        {
                            isIntersecting = true; //assume worst case
                        }
                    }
                }
            }
            return isIntersecting;
            
        }
 
        // This is a hack so that SQL can operate under default policy without actually
        // granting permissions in assemblies that they disallow.  @
 
 
        internal bool IgnoreTypeLoadFailures
        {
            set { m_ignoreTypeLoadFailures = value; }
        }
    }
}