// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*=============================================================================
**
** Class: AppDomainSetup
** 
** <OWNER>blanders</OWNER>
**
** Purpose: Defines the settings that the loader uses to find assemblies in an
**          AppDomain
**
** Date: Dec 22, 2000
**
=============================================================================*/

namespace System {
    using System;
#if FEATURE_CLICKONCE        
#if !FEATURE_PAL
    using System.Deployment.Internal.Isolation;
    using System.Deployment.Internal.Isolation.Manifest;
    using System.Runtime.Hosting;    
#endif
#endif
    using System.Runtime.CompilerServices;
    using System.Runtime;
    using System.Text;
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.Reflection;
    using System.Security;
    using System.Security.Permissions;
    using System.Security.Policy;
    using System.Globalization;
    using Path = System.IO.Path;
    using System.Runtime.Versioning;
    using System.Diagnostics.Contracts;
    using System.Collections;
    using System.Collections.Generic;

    [Serializable]
    [ClassInterface(ClassInterfaceType.None)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public sealed class AppDomainSetup :
        IAppDomainSetup
    {
        [Serializable]
        internal enum LoaderInformation
        {
            // If you add a new value, add the corresponding property
            // to AppDomain.GetData() and SetData()'s switch statements.
            ApplicationBaseValue = LOADER_APPLICATION_BASE,
            ConfigurationFileValue = LOADER_CONFIGURATION_BASE,
            DynamicBaseValue = LOADER_DYNAMIC_BASE,
            DevPathValue = LOADER_DEVPATH,
            ApplicationNameValue = LOADER_APPLICATION_NAME,
            PrivateBinPathValue = LOADER_PRIVATE_PATH,
            PrivateBinPathProbeValue = LOADER_PRIVATE_BIN_PATH_PROBE,
            ShadowCopyDirectoriesValue = LOADER_SHADOW_COPY_DIRECTORIES,
            ShadowCopyFilesValue = LOADER_SHADOW_COPY_FILES,
            CachePathValue = LOADER_CACHE_PATH,
            LicenseFileValue = LOADER_LICENSE_FILE,
            DisallowPublisherPolicyValue = LOADER_DISALLOW_PUBLISHER_POLICY,
            DisallowCodeDownloadValue = LOADER_DISALLOW_CODE_DOWNLOAD,
            DisallowBindingRedirectsValue = LOADER_DISALLOW_BINDING_REDIRECTS,
            DisallowAppBaseProbingValue = LOADER_DISALLOW_APPBASE_PROBING,
            ConfigurationBytesValue = LOADER_CONFIGURATION_BYTES,
            LoaderMaximum = LOADER_MAXIMUM,
        }

        // This class has an unmanaged representation so be aware you will need to make edits in vm\object.h if you change the order
        // of these fields or add new ones.

        private string[] _Entries;
        private LoaderOptimization _LoaderOptimization;
#pragma warning disable 169
        private String _AppBase; // for compat with v1.1
#pragma warning restore 169
        [OptionalField(VersionAdded = 2)]
        private AppDomainInitializer  _AppDomainInitializer;
        [OptionalField(VersionAdded = 2)]
        private string[] _AppDomainInitializerArguments;
#if FEATURE_CLICKONCE
        [OptionalField(VersionAdded = 2)]
        private ActivationArguments _ActivationArguments;
#endif
#if FEATURE_CORECLR
        // On the CoreCLR, this contains just the name of the permission set that we install in the new appdomain.
        // Not the ToXml().ToString() of an ApplicationTrust object.
#endif
        [OptionalField(VersionAdded = 2)]
        private string _ApplicationTrust;
        [OptionalField(VersionAdded = 2)]
        private byte[] _ConfigurationBytes;
#if FEATURE_COMINTEROP
        [OptionalField(VersionAdded = 3)]
        private bool _DisableInterfaceCache = false;
#endif // FEATURE_COMINTEROP
        [OptionalField(VersionAdded = 4)]
        private string _AppDomainManagerAssembly;
        [OptionalField(VersionAdded = 4)]
        private string _AppDomainManagerType;

#if FEATURE_APTCA
        [OptionalField(VersionAdded = 4)]
        private string[] _AptcaVisibleAssemblies;
#endif

        // A collection of strings used to indicate which breaking changes shouldn't be applied
        // to an AppDomain. We only use the keys, the values are ignored.
        [OptionalField(VersionAdded = 4)]
        private Dictionary<string, object> _CompatFlags;

        [OptionalField(VersionAdded = 5)] // This was added in .NET FX v4.5
        private String _TargetFrameworkName;

#if !FEATURE_CORECLR
        [NonSerialized]
        internal AppDomainSortingSetupInfo _AppDomainSortingSetupInfo;
#endif

        [OptionalField(VersionAdded = 5)] // This was added in .NET FX v4.5
        private bool _CheckedForTargetFrameworkName;

#if FEATURE_RANDOMIZED_STRING_HASHING
        [OptionalField(VersionAdded = 5)] // This was added in .NET FX v4.5
        private bool _UseRandomizedStringHashing;
#endif

        [SecuritySafeCritical]
        internal AppDomainSetup(AppDomainSetup copy, bool copyDomainBoundData)
        {
            string[] mine = Value;
            if(copy != null) {
                string[] other = copy.Value;
                int mineSize = _Entries.Length;
                int otherSize = other.Length;
                int size = (otherSize < mineSize) ? otherSize : mineSize;

                for (int i = 0; i < size; i++)
                    mine[i] = other[i];

                if (size < mineSize)
                {
                    // This case can happen when the copy is a deserialized version of
                    // an AppDomainSetup object serialized by Everett.
                    for (int i = size; i < mineSize; i++)
                        mine[i] = null;
                }

                _LoaderOptimization = copy._LoaderOptimization;

                _AppDomainInitializerArguments = copy.AppDomainInitializerArguments;
#if FEATURE_CLICKONCE
                _ActivationArguments = copy.ActivationArguments;
#endif
                _ApplicationTrust = copy._ApplicationTrust;
                if (copyDomainBoundData)
                    _AppDomainInitializer = copy.AppDomainInitializer;
                else
                    _AppDomainInitializer = null;

                _ConfigurationBytes = copy.GetConfigurationBytes();
#if FEATURE_COMINTEROP
                _DisableInterfaceCache = copy._DisableInterfaceCache;
#endif // FEATURE_COMINTEROP
                _AppDomainManagerAssembly = copy.AppDomainManagerAssembly;
                _AppDomainManagerType = copy.AppDomainManagerType;
#if FEATURE_APTCA
                _AptcaVisibleAssemblies = copy.PartialTrustVisibleAssemblies;
#endif

                if (copy._CompatFlags != null)
                {
                    SetCompatibilitySwitches(copy._CompatFlags.Keys);
                }

#if !FEATURE_CORECLR
                if(copy._AppDomainSortingSetupInfo != null)
                {
                    _AppDomainSortingSetupInfo = new AppDomainSortingSetupInfo(copy._AppDomainSortingSetupInfo);
                }
#endif
                _TargetFrameworkName = copy._TargetFrameworkName;

#if FEATURE_RANDOMIZED_STRING_HASHING
                _UseRandomizedStringHashing = copy._UseRandomizedStringHashing;
#endif

            }
            else 
                _LoaderOptimization = LoaderOptimization.NotSpecified;
        }

        public AppDomainSetup()
        {
            _LoaderOptimization = LoaderOptimization.NotSpecified;
        }

#if FEATURE_CLICKONCE
        // Creates an AppDomainSetup object from an application identity.
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public AppDomainSetup (ActivationContext activationContext) : this (new ActivationArguments(activationContext)) {}

        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public AppDomainSetup (ActivationArguments activationArguments) {
            if (activationArguments == null)
                throw new ArgumentNullException("activationArguments");
            Contract.EndContractBlock();

            _LoaderOptimization = LoaderOptimization.NotSpecified;
            ActivationArguments = activationArguments;

            Contract.Assert(activationArguments.ActivationContext != null, "Cannot set base directory without activation context");
            string entryPointPath = CmsUtils.GetEntryPointFullPath(activationArguments);
            if (!String.IsNullOrEmpty(entryPointPath))
                SetupDefaults(entryPointPath);
            else
                ApplicationBase = activationArguments.ActivationContext.ApplicationDirectory;

        }
#endif // !FEATURE_CLICKONCE

        #if FEATURE_CORECLR
        [System.Security.SecurityCritical] // auto-generated
        #endif
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        internal void SetupDefaults(string imageLocation, bool imageLocationAlreadyNormalized = false) {
            char[] sep = {'\\', '/'};
            int i = imageLocation.LastIndexOfAny(sep);

            if (i == -1) {
                ApplicationName = imageLocation;
            }
            else {
                ApplicationName = imageLocation.Substring(i+1);
                string appBase = imageLocation.Substring(0, i+1);

                if (imageLocationAlreadyNormalized)
                    Value[(int) LoaderInformation.ApplicationBaseValue] = appBase;
                else 
                    ApplicationBase = appBase;
            }
            ConfigurationFile = ApplicationName + AppDomainSetup.ConfigurationExtension;
        }

        internal string[] Value
        {
            get {
                if( _Entries == null)
                    _Entries = new String[LOADER_MAXIMUM];
                return _Entries;
            }
        }

        internal String GetUnsecureApplicationBase()
        {
            return Value[(int) LoaderInformation.ApplicationBaseValue];
        }

        public string AppDomainManagerAssembly
        {
            get { return _AppDomainManagerAssembly; }
            set { _AppDomainManagerAssembly = value; }
        }

        public string AppDomainManagerType
        {
            get { return _AppDomainManagerType; }
            set { _AppDomainManagerType = value; }
        }

#if FEATURE_APTCA
        public string[] PartialTrustVisibleAssemblies
        {
            get { return _AptcaVisibleAssemblies; }
            set { 
                if (value != null) {
                    _AptcaVisibleAssemblies = (string[])value.Clone(); 
                    Array.Sort<string>(_AptcaVisibleAssemblies, StringComparer.OrdinalIgnoreCase);
                }
                else {
                    _AptcaVisibleAssemblies = null;
                }
            }
        }
#endif

        public String ApplicationBase
        {
            #if FEATURE_CORECLR
            [System.Security.SecurityCritical] // auto-generated
            #else
            [System.Security.SecuritySafeCritical]
            #endif
            [Pure]
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                return VerifyDir(GetUnsecureApplicationBase(), false);
            }

            #if FEATURE_CORECLR
            [System.Security.SecurityCritical] // auto-generated
            #endif
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                Value[(int) LoaderInformation.ApplicationBaseValue] = NormalizePath(value, false);
            }
        }

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private String NormalizePath(String path, bool useAppBase)
        {
            if(path == null)
                return null;

            // If we add very long file name support ("\\?\") to the Path class then this is unnecesary,
            // but we do not plan on doing this for now.
            if (!useAppBase)
                path = System.Security.Util.URLString.PreProcessForExtendedPathRemoval(path, false);

            int len = path.Length;
            if (len == 0)
                return null;

            bool UNCpath = false;

            if ((len > 7) &&
                (String.Compare( path, 0, "file:", 0, 5, StringComparison.OrdinalIgnoreCase) == 0)) {
                int trim;
                
                if (path[6] == '\\') {
                    if ((path[7] == '\\') || (path[7] == '/')) {

                        // Don't allow "file:\\\\", because we can't tell the difference
                        // with it for "file:\\" + "\\server" and "file:\\\" + "\localpath"
                        if ( (len > 8) && 
                             ((path[8] == '\\') || (path[8] == '/')) )
                            throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars"));
                        
                        // file:\\\ means local path
                        else
                            trim = 8;
                    }

                    // file:\\ means remote server
                    else {
                        trim = 5;
                        UNCpath = true;
                    }
                }

                // local path
                else if (path[7] == '/')
                    trim = 8;

                // remote
                else {
                    // file://\\remote
                    if ( (len > 8) && (path[7] == '\\') && (path[8] == '\\') )
                        trim = 7;
                    else { // file://remote
                        trim = 5;
                        // Create valid UNC path by changing
                        // all occurences of '/' to '\\' in path
                        System.Text.StringBuilder winPathBuilder =
                            new System.Text.StringBuilder(len);
                        for (int i = 0; i < len; i++) {
                            char c = path[i];
                            if (c == '/')
                                winPathBuilder.Append('\\');
                            else
                                winPathBuilder.Append(c);
                        }
                        path = winPathBuilder.ToString();
                    }
                    UNCpath = true;
                }

                path = path.Substring(trim);
                len -= trim;
            }

            bool localPath;

            // UNC
            if (UNCpath ||
                ( (len > 1) &&
                  ( (path[0] == '/') || (path[0] == '\\') ) &&
                  ( (path[1] == '/') || (path[1] == '\\') ) ))
                localPath = false;

            else {
                int colon = path.IndexOf(':') + 1;

                // protocol other than file:
                if ((colon != 0) &&
                    (len > colon+1) &&
                    ( (path[colon] == '/') || (path[colon] == '\\') ) &&
                    ( (path[colon+1] == '/') || (path[colon+1] == '\\') ))
                    localPath = false;

                else
                    localPath = true;
            }

            if (localPath) 
            {

                if (useAppBase &&
                    ( (len == 1) || (path[1] != ':') )) {
                    String appBase = Value[(int) LoaderInformation.ApplicationBaseValue];

                    if ((appBase == null) || (appBase.Length == 0))
                        throw new MemberAccessException(Environment.GetResourceString("AppDomain_AppBaseNotSet"));

                    StringBuilder result = StringBuilderCache.Acquire();

                    bool slash = false;
                    if ((path[0] == '/') || (path[0] == '\\')) {
                        String pathRoot = Path.GetPathRoot(appBase);
                        if (pathRoot.Length == 0) { // URL
                            int index = appBase.IndexOf(":/", StringComparison.Ordinal);
                            if (index == -1)
                                index = appBase.IndexOf(":\\", StringComparison.Ordinal);

                            // Get past last slashes of "url:http://"
                            int urlLen = appBase.Length;
                            for (index += 1;
                                 (index < urlLen) && ((appBase[index] == '/') || (appBase[index] == '\\'));
                                 index++);

                            // Now find the next slash to get domain name
                            for(; (index < urlLen) && (appBase[index] != '/') && (appBase[index] != '\\');
                                index++);

                            pathRoot = appBase.Substring(0, index);
                        }

                        result.Append(pathRoot);
                        slash = true;
                    }
                    else
                        result.Append(appBase);

                    // Make sure there's a slash separator (and only one)
                    int aLen = result.Length - 1;
                    if ((result[aLen] != '/') &&
                        (result[aLen] != '\\')) {
                        if (!slash) {
                            if (appBase.IndexOf(":/", StringComparison.Ordinal) == -1)
                                result.Append('\\');
                            else
                                result.Append('/');
                        }
                    }
                    else if (slash)
                        result.Remove(aLen, 1);

                    result.Append(path);
                    path = StringBuilderCache.GetStringAndRelease(result);
                }
                else
                    path = Path.GetFullPathInternal(path);
            }

            return path;
        }

        private bool IsFilePath(String path)
        {
            return (path[1] == ':') || ( (path[0] == '\\') && (path[1] == '\\') );
        }

        internal static String ApplicationBaseKey
        {
            get {
                return ACTAG_APP_BASE_URL;
            }
        }

        public String ConfigurationFile
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                return VerifyDir(Value[(int) LoaderInformation.ConfigurationFileValue], true);
            }

            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                Value[(int) LoaderInformation.ConfigurationFileValue] = value;
            }
        }

        // Used by the ResourceManager internally.  This must not do any 
        // security checks to avoid infinite loops.
        internal String ConfigurationFileInternal
        {
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                return NormalizePath(Value[(int) LoaderInformation.ConfigurationFileValue], true);
            }
        }

        internal static String ConfigurationFileKey
        {
            get {
                return ACTAG_APP_CONFIG_FILE;
            }
        }

        public byte[] GetConfigurationBytes()
        {
            if (_ConfigurationBytes == null)
                return null;

            return (byte[]) _ConfigurationBytes.Clone();
        }

        public void SetConfigurationBytes(byte[] value)
        {
            _ConfigurationBytes = value;
        }

        private static String ConfigurationBytesKey
        {
            get {
                return ACTAG_APP_CONFIG_BLOB;
            }
        }

        // only needed by AppDomain.Setup(). Not really needed by users. 
        internal Dictionary<string, object> GetCompatibilityFlags()
        {
            return _CompatFlags;
        }

        public void SetCompatibilitySwitches(IEnumerable<String> switches)
        {

#if !FEATURE_CORECLR
            if(_AppDomainSortingSetupInfo != null)
            {
                _AppDomainSortingSetupInfo._useV2LegacySorting = false;
                _AppDomainSortingSetupInfo._useV4LegacySorting = false;
            }
#endif

#if FEATURE_RANDOMIZED_STRING_HASHING
            _UseRandomizedStringHashing = false;
#endif
            if (switches != null)
            {
                _CompatFlags = new Dictionary<string, object>();
                foreach (String str in switches) 
                {
#if !FEATURE_CORECLR
                    if(StringComparer.OrdinalIgnoreCase.Equals("NetFx40_Legacy20SortingBehavior", str)) {
                        if(_AppDomainSortingSetupInfo == null)
                        {
                            _AppDomainSortingSetupInfo = new AppDomainSortingSetupInfo();
                        }
                        _AppDomainSortingSetupInfo._useV2LegacySorting = true;
                    }

                    if(StringComparer.OrdinalIgnoreCase.Equals("NetFx45_Legacy40SortingBehavior", str)) {
                        if(_AppDomainSortingSetupInfo == null)
                        {
                            _AppDomainSortingSetupInfo = new AppDomainSortingSetupInfo();
                        }
                        _AppDomainSortingSetupInfo._useV4LegacySorting = true;
                    }
#endif

#if FEATURE_RANDOMIZED_STRING_HASHING
                    if(StringComparer.OrdinalIgnoreCase.Equals("UseRandomizedStringHashAlgorithm", str)) {
                        _UseRandomizedStringHashing = true;
                    }
#endif

                    _CompatFlags.Add(str, null);
                }
            }
            else
            {
                _CompatFlags = null;
            }

        }

        // A target Framework moniker, in a format parsible by the FrameworkName class.
        public String TargetFrameworkName {
            get {
                return _TargetFrameworkName;
            }
            set {
                _TargetFrameworkName = value;
            }
        }

        internal bool CheckedForTargetFrameworkName
        {
            get { return _CheckedForTargetFrameworkName; }
            set { _CheckedForTargetFrameworkName = value; }
        }

#if !FEATURE_CORECLR
        [SecurityCritical]
        public void SetNativeFunction(string functionName, int functionVersion, IntPtr functionPointer) 
        {
            if(functionName == null) 
            {
                throw new ArgumentNullException("functionName");
            }

            if(functionPointer == IntPtr.Zero)
            {
                throw new ArgumentNullException("functionPointer");
            }

            if(String.IsNullOrWhiteSpace(functionName))
            {
                throw new ArgumentException(Environment.GetResourceString("Argument_NPMSInvalidName"), "functionName");
            }

            Contract.EndContractBlock();

            if(functionVersion < 1)
            {
                throw new ArgumentException(Environment.GetResourceString("ArgumentException_MinSortingVersion", 1, functionName));
            }

            if(_AppDomainSortingSetupInfo == null)
            {
                _AppDomainSortingSetupInfo = new AppDomainSortingSetupInfo();
            }

            if(String.Equals(functionName, "IsNLSDefinedString", StringComparison.OrdinalIgnoreCase))
            {
                _AppDomainSortingSetupInfo._pfnIsNLSDefinedString = functionPointer;
            }

            if (String.Equals(functionName, "CompareStringEx", StringComparison.OrdinalIgnoreCase))
            {
                _AppDomainSortingSetupInfo._pfnCompareStringEx = functionPointer;
            }

            if (String.Equals(functionName, "LCMapStringEx", StringComparison.OrdinalIgnoreCase))
            {
                _AppDomainSortingSetupInfo._pfnLCMapStringEx = functionPointer;
            }

            if (String.Equals(functionName, "FindNLSStringEx", StringComparison.OrdinalIgnoreCase))
            {
                _AppDomainSortingSetupInfo._pfnFindNLSStringEx = functionPointer;
            }

            if (String.Equals(functionName, "CompareStringOrdinal", StringComparison.OrdinalIgnoreCase))
            {
                _AppDomainSortingSetupInfo._pfnCompareStringOrdinal = functionPointer;
            }

            if (String.Equals(functionName, "GetNLSVersionEx", StringComparison.OrdinalIgnoreCase))
            {
                _AppDomainSortingSetupInfo._pfnGetNLSVersionEx = functionPointer;
            }

            if (String.Equals(functionName, "FindStringOrdinal", StringComparison.OrdinalIgnoreCase))
            {
                _AppDomainSortingSetupInfo._pfnFindStringOrdinal = functionPointer;
            }
        }
#endif

        public String DynamicBase
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                return VerifyDir(Value[(int) LoaderInformation.DynamicBaseValue], true);
            }

            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                if (value == null)
                    Value[(int) LoaderInformation.DynamicBaseValue] = null;
                else {
                    if(ApplicationName == null)
                        throw new MemberAccessException(Environment.GetResourceString("AppDomain_RequireApplicationName"));
                    
                    StringBuilder s = new StringBuilder( NormalizePath(value, false) );
                    s.Append('\\');
                    string h = ParseNumbers.IntToString(ApplicationName.GetLegacyNonRandomizedHashCode(),
                                                        16, 8, '0', ParseNumbers.PrintAsI4);
                    s.Append(h);
                    
                    Value[(int) LoaderInformation.DynamicBaseValue] = s.ToString();
                }
            }
        }

        internal static String DynamicBaseKey
        {
            get {
                return ACTAG_APP_DYNAMIC_BASE;
            }
        }


        public bool DisallowPublisherPolicy
        {
            get 
            {
                return (Value[(int) LoaderInformation.DisallowPublisherPolicyValue] != null);
            }
            set
            {
                if (value)
                    Value[(int) LoaderInformation.DisallowPublisherPolicyValue]="true";
                else
                    Value[(int) LoaderInformation.DisallowPublisherPolicyValue]=null;
            }
        }


        public bool DisallowBindingRedirects
        {
            get 
            {
                return (Value[(int) LoaderInformation.DisallowBindingRedirectsValue] != null);
            }
            set
            {
                if (value)
                    Value[(int) LoaderInformation.DisallowBindingRedirectsValue] = "true";
                else
                    Value[(int) LoaderInformation.DisallowBindingRedirectsValue] = null;
            }
        }

        public bool DisallowCodeDownload
        {
            get 
            {
                return (Value[(int) LoaderInformation.DisallowCodeDownloadValue] != null);
            }
            set
            {
                if (value)
                    Value[(int) LoaderInformation.DisallowCodeDownloadValue] = "true";
                else
                    Value[(int) LoaderInformation.DisallowCodeDownloadValue] = null;
            }
        }


        public bool DisallowApplicationBaseProbing
        {
            get 
            {
                return (Value[(int) LoaderInformation.DisallowAppBaseProbingValue] != null);
            }
            set
            {
                if (value)
                    Value[(int) LoaderInformation.DisallowAppBaseProbingValue] = "true";
                else
                    Value[(int) LoaderInformation.DisallowAppBaseProbingValue] = null;
            }
        }

        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private String VerifyDir(String dir, bool normalize)
        {
            if (dir != null) {
                if (dir.Length == 0)
                    dir = null;
                else {
                    if (normalize)
                        dir = NormalizePath(dir, true);

                // The only way AppDomainSetup is exposed in coreclr is through the AppDomainManager 
                // and the AppDomainManager is a SecurityCritical type. Also, all callers of callstacks 
                // leading from VerifyDir are SecurityCritical. So we can remove the Demand because 
                // we have validated that all callers are SecurityCritical
#if !FEATURE_CORECLR
                    if (IsFilePath(dir))
                        new FileIOPermission( FileIOPermissionAccess.PathDiscovery, dir ).Demand();
#endif // !FEATURE_CORECLR
                }
            }

            return dir;
        }

        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private void VerifyDirList(String dirs)
        {
            if (dirs != null) {
                String[] dirArray = dirs.Split(';');
                int len = dirArray.Length;
                
                for (int i = 0; i < len; i++)
                    VerifyDir(dirArray[i], true);
            }
        }

        internal String DeveloperPath
        {
            [System.Security.SecurityCritical]  // auto-generated
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                String dirs = Value[(int) LoaderInformation.DevPathValue];
                VerifyDirList(dirs);
                return dirs;
            }

            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                if(value == null)
                    Value[(int) LoaderInformation.DevPathValue] = null;
                else {
                    String[] directories = value.Split(';');
                    int size = directories.Length;
                    StringBuilder newPath = StringBuilderCache.Acquire();
                    bool fDelimiter = false;
                        
                    for(int i = 0; i < size; i++) {
                        if(directories[i].Length != 0) {
                            if(fDelimiter) 
                                newPath.Append(";");
                            else
                                fDelimiter = true;
                            
                            newPath.Append(Path.GetFullPathInternal(directories[i]));
                        }
                    }
                    
                    String newString = StringBuilderCache.GetStringAndRelease(newPath);
                    if (newString.Length == 0)
                        Value[(int) LoaderInformation.DevPathValue] = null;
                    else
                        Value[(int) LoaderInformation.DevPathValue] = newString;
                }
            }
        }
        
        internal static String DisallowPublisherPolicyKey
        {
            get
            {
                return ACTAG_DISALLOW_APPLYPUBLISHERPOLICY;
            }
        }

        internal static String DisallowCodeDownloadKey
        {
            get
            {
                return ACTAG_CODE_DOWNLOAD_DISABLED;
            }
        }

        internal static String DisallowBindingRedirectsKey
        {
            get
            {
                return ACTAG_DISALLOW_APP_BINDING_REDIRECTS;
            }
        }

        internal static String DeveloperPathKey
        {
            get {
                return ACTAG_DEV_PATH;
            }
        }

        internal static String DisallowAppBaseProbingKey
        {
            get
            {
                return ACTAG_DISALLOW_APP_BASE_PROBING;
            }
        }

        public String ApplicationName
        {
            get {
                return Value[(int) LoaderInformation.ApplicationNameValue];
            }

            set {
                Value[(int) LoaderInformation.ApplicationNameValue] = value;
            }
        }

        internal static String ApplicationNameKey
        {
            get {
                return ACTAG_APP_NAME;
            }
        }

        [XmlIgnoreMember]
        public AppDomainInitializer AppDomainInitializer
        {
            get {
                return _AppDomainInitializer;
            }

            set {
                _AppDomainInitializer = value;
            }
        }
        public string[] AppDomainInitializerArguments
        {
            get {
                return _AppDomainInitializerArguments;
            }

            set {
                _AppDomainInitializerArguments = value;
            }
        }

#if FEATURE_CLICKONCE
        [XmlIgnoreMember]
        public ActivationArguments ActivationArguments {
            [Pure]
            get {
                return _ActivationArguments;
            }
            set {
                _ActivationArguments = value;
            }
        }
#endif // !FEATURE_CLICKONCE

        internal ApplicationTrust InternalGetApplicationTrust()
        {
            
            if (_ApplicationTrust == null) return null;


#if FEATURE_CORECLR            
            ApplicationTrust grantSet = new ApplicationTrust(NamedPermissionSet.GetBuiltInSet(_ApplicationTrust));
#else
            SecurityElement securityElement = SecurityElement.FromString(_ApplicationTrust);
            ApplicationTrust grantSet = new ApplicationTrust();
            grantSet.FromXml(securityElement);
#endif
            return grantSet;
        }

#if FEATURE_CORECLR
        internal void InternalSetApplicationTrust(String permissionSetName)
        {
            _ApplicationTrust = permissionSetName;
        }
#else
        internal void InternalSetApplicationTrust(ApplicationTrust value)
        {
            if (value != null)
            {
                _ApplicationTrust = value.ToXml().ToString();
            }
            else
            {
                _ApplicationTrust = null;
            }
        }
#endif

#if FEATURE_CLICKONCE
        [XmlIgnoreMember]
        public ApplicationTrust ApplicationTrust 
        {
            get {
                return InternalGetApplicationTrust();
            }
            set {
                InternalSetApplicationTrust(value);
            }
        }
#else // FEATURE_CLICKONCE
        [XmlIgnoreMember]
        internal ApplicationTrust ApplicationTrust
        {
            get {
                return InternalGetApplicationTrust();
            }
#if !FEATURE_CORECLR            
            set {
                InternalSetApplicationTrust(value);
            }
#endif 
        }
#endif // FEATURE_CLICKONCE

        public String PrivateBinPath
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                String dirs = Value[(int) LoaderInformation.PrivateBinPathValue];
                VerifyDirList(dirs);
                return dirs;
            }

            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                Value[(int) LoaderInformation.PrivateBinPathValue] = value;
            }
        }

        internal static String PrivateBinPathKey
        {
            get {
                return ACTAG_APP_PRIVATE_BINPATH;
            }
        }


        public String PrivateBinPathProbe
        {
            get {
                return Value[(int) LoaderInformation.PrivateBinPathProbeValue];
            }

            set {
                Value[(int) LoaderInformation.PrivateBinPathProbeValue] = value;
            }
        }

        internal static String PrivateBinPathProbeKey
        {
            get {
                return ACTAG_BINPATH_PROBE_ONLY;
            }
        }

        public String ShadowCopyDirectories
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                String dirs = Value[(int) LoaderInformation.ShadowCopyDirectoriesValue];
                VerifyDirList(dirs);
                return dirs;
            }

            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                Value[(int) LoaderInformation.ShadowCopyDirectoriesValue] = value;
            }
        }

        internal static String ShadowCopyDirectoriesKey
        {
            get {
                return ACTAG_APP_SHADOW_COPY_DIRS;
            }
        }

        public String ShadowCopyFiles
        {
            get {
                return Value[(int) LoaderInformation.ShadowCopyFilesValue];
            }

            set {
                if((value != null) && 
                   (String.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0))
                    Value[(int) LoaderInformation.ShadowCopyFilesValue] = value;
                else
                    Value[(int) LoaderInformation.ShadowCopyFilesValue] = null;
            }
        }

        internal static String ShadowCopyFilesKey
        {
            get {
                return ACTAG_FORCE_CACHE_INSTALL;
            }
        }

        public String CachePath
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                return VerifyDir(Value[(int) LoaderInformation.CachePathValue], false);
            }

            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                Value[(int) LoaderInformation.CachePathValue] = NormalizePath(value, false);
            }
        }

        internal static String CachePathKey
        {
            get {
                return ACTAG_APP_CACHE_BASE;
            }
        }

        public String LicenseFile
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                return VerifyDir(Value[(int) LoaderInformation.LicenseFileValue], true);
            }

            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                Value[(int) LoaderInformation.LicenseFileValue] = value;
            }
        }

        public LoaderOptimization LoaderOptimization
        {
            get {
                return _LoaderOptimization;
            }

            set {
                _LoaderOptimization = value;
            }
        }

        internal static string LoaderOptimizationKey
        {
            get {
                return LOADER_OPTIMIZATION;
            }
        }

        internal static string ConfigurationExtension
        {
            get {
                return CONFIGURATION_EXTENSION;
            }
        }

        internal static String PrivateBinPathEnvironmentVariable
        {
            get {
                return APPENV_RELATIVEPATH;
            }
        }

        internal static string RuntimeConfigurationFile
        {
            get {
                return MACHINE_CONFIGURATION_FILE;
            }
        }

        internal static string MachineConfigKey
        {
            get {
                return ACTAG_MACHINE_CONFIG;
            }
        }

        internal static string HostBindingKey
        {
            get {
                return ACTAG_HOST_CONFIG_FILE;
            }
        }

#if FEATURE_FUSION
        [SecurityCritical]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal bool UpdateContextPropertyIfNeeded(LoaderInformation FieldValue, String FieldKey, String UpdatedField, IntPtr fusionContext, AppDomainSetup oldADS)
        {
            String FieldString = Value[(int) FieldValue],
                   OldFieldString = (oldADS == null ? null : oldADS.Value[(int) FieldValue]);
            if (FieldString != OldFieldString) { // Compare references since strings are immutable
                UpdateContextProperty(fusionContext, FieldKey, UpdatedField == null ? FieldString : UpdatedField);
                return true;
            }

	     return false;
        }

        [SecurityCritical]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal void UpdateBooleanContextPropertyIfNeeded(LoaderInformation FieldValue, String FieldKey, IntPtr fusionContext, AppDomainSetup oldADS)
        {
            if (Value[(int) FieldValue] != null)
                UpdateContextProperty(fusionContext, FieldKey, "true");
            else if (oldADS != null && oldADS.Value[(int) FieldValue] != null)
                UpdateContextProperty(fusionContext, FieldKey, "false");
        }

        [SecurityCritical]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal static bool ByteArraysAreDifferent(Byte[] A, Byte[] B)
        {
		int length = A.Length;
		if (length != B.Length)
		    return true;

		for(int i = 0; i < length; i++) {
		    if (A[i] != B[i])
		        return true;				
	       }

		return false;
        }

        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal static void UpdateByteArrayContextPropertyIfNeeded(Byte[] NewArray, Byte[] OldArray, String FieldKey, IntPtr fusionContext)
        {
            if ((NewArray != null && OldArray == null) ||
		   (NewArray == null && OldArray != null) ||
		   (NewArray != null && OldArray != null && ByteArraysAreDifferent(NewArray, OldArray)))
                UpdateContextProperty(fusionContext, FieldKey, NewArray);
        }
		
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal void SetupFusionContext(IntPtr fusionContext, AppDomainSetup oldADS)
        {
            UpdateContextPropertyIfNeeded(LoaderInformation.ApplicationBaseValue, ApplicationBaseKey, null, fusionContext, oldADS);
            UpdateContextPropertyIfNeeded(LoaderInformation.PrivateBinPathValue, PrivateBinPathKey, null, fusionContext, oldADS);
            UpdateContextPropertyIfNeeded(LoaderInformation.DevPathValue, DeveloperPathKey, null, fusionContext, oldADS);

            UpdateBooleanContextPropertyIfNeeded(LoaderInformation.DisallowPublisherPolicyValue, DisallowPublisherPolicyKey, fusionContext, oldADS);
            UpdateBooleanContextPropertyIfNeeded(LoaderInformation.DisallowCodeDownloadValue, DisallowCodeDownloadKey, fusionContext, oldADS);
            UpdateBooleanContextPropertyIfNeeded(LoaderInformation.DisallowBindingRedirectsValue, DisallowBindingRedirectsKey, fusionContext, oldADS);
            UpdateBooleanContextPropertyIfNeeded(LoaderInformation.DisallowAppBaseProbingValue, DisallowAppBaseProbingKey, fusionContext, oldADS);

            if(UpdateContextPropertyIfNeeded(LoaderInformation.ShadowCopyFilesValue, ShadowCopyFilesKey, ShadowCopyFiles, fusionContext, oldADS)) {

                // If we are asking for shadow copy directories then default to
                // only to the ones that are in the private bin path.
                if(Value[(int) LoaderInformation.ShadowCopyDirectoriesValue] == null)
                    ShadowCopyDirectories = BuildShadowCopyDirectories();

                UpdateContextPropertyIfNeeded(LoaderInformation.ShadowCopyDirectoriesValue, ShadowCopyDirectoriesKey, null, fusionContext, oldADS);
            }

            UpdateContextPropertyIfNeeded(LoaderInformation.CachePathValue, CachePathKey, null, fusionContext, oldADS);
            UpdateContextPropertyIfNeeded(LoaderInformation.PrivateBinPathProbeValue, PrivateBinPathProbeKey, PrivateBinPathProbe, fusionContext, oldADS);
            UpdateContextPropertyIfNeeded(LoaderInformation.ConfigurationFileValue, ConfigurationFileKey, null, fusionContext, oldADS);

            UpdateByteArrayContextPropertyIfNeeded(_ConfigurationBytes, oldADS == null ? null : oldADS.GetConfigurationBytes(), ConfigurationBytesKey, fusionContext);

            UpdateContextPropertyIfNeeded(LoaderInformation.ApplicationNameValue, ApplicationNameKey, ApplicationName, fusionContext, oldADS);
            UpdateContextPropertyIfNeeded(LoaderInformation.DynamicBaseValue, DynamicBaseKey, null, fusionContext, oldADS);

            // Always add the runtime configuration file to the appdomain
            UpdateContextProperty(fusionContext, MachineConfigKey, RuntimeEnvironment.GetRuntimeDirectoryImpl() + RuntimeConfigurationFile);

            String hostBindingFile = RuntimeEnvironment.GetHostBindingFile();
            if(hostBindingFile != null || oldADS != null) // If oldADS != null, we don't know the old value of the hostBindingFile, so we force an update even when hostBindingFile == null.
                UpdateContextProperty(fusionContext, HostBindingKey, hostBindingFile);
        }

        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern void UpdateContextProperty(IntPtr fusionContext, string key, Object value);
#endif // FEATURE_FUSION

        static internal int Locate(String s)
        {
            if(String.IsNullOrEmpty(s))
                return -1;
#if FEATURE_FUSION

            // verify assumptions hardcoded into the switch below
            Contract.Assert('A' == ACTAG_APP_CONFIG_FILE[0]     , "Assumption violated");
            Contract.Assert('A' == ACTAG_APP_NAME[0]            , "Assumption violated");
            Contract.Assert('A' == ACTAG_APP_BASE_URL[0]        , "Assumption violated");
            Contract.Assert('B' == ACTAG_BINPATH_PROBE_ONLY[0]  , "Assumption violated");
            Contract.Assert('C' == ACTAG_APP_CACHE_BASE[0]      , "Assumption violated");
            Contract.Assert('D' == ACTAG_DEV_PATH[0]            , "Assumption violated");
            Contract.Assert('D' == ACTAG_APP_DYNAMIC_BASE[0]    , "Assumption violated");
            Contract.Assert('F' == ACTAG_FORCE_CACHE_INSTALL[0] , "Assumption violated");
            Contract.Assert('L' == LICENSE_FILE[0]              , "Assumption violated");
            Contract.Assert('P' == ACTAG_APP_PRIVATE_BINPATH[0] , "Assumption violated");
            Contract.Assert('S' == ACTAG_APP_SHADOW_COPY_DIRS[0], "Assumption violated");
            Contract.Assert('D' == ACTAG_DISALLOW_APPLYPUBLISHERPOLICY[0], "Assumption violated");
            Contract.Assert('C' == ACTAG_CODE_DOWNLOAD_DISABLED[0], "Assumption violated");
            Contract.Assert('D' == ACTAG_DISALLOW_APP_BINDING_REDIRECTS[0], "Assumption violated");
            Contract.Assert('D' == ACTAG_DISALLOW_APP_BASE_PROBING[0], "Assumption violated");
            Contract.Assert('A' == ACTAG_APP_CONFIG_BLOB[0], "Assumption violated");

            switch (s[0]) {
                case 'A':
                    if (s == ACTAG_APP_CONFIG_FILE)     return (int)LoaderInformation.ConfigurationFileValue;
                    if (s == ACTAG_APP_NAME)            return (int)LoaderInformation.ApplicationNameValue;
                    if (s == ACTAG_APP_BASE_URL)        return (int)LoaderInformation.ApplicationBaseValue;
                    if (s == ACTAG_APP_CONFIG_BLOB)     return (int)LoaderInformation.ConfigurationBytesValue;
                    break;
                case 'B':
                    if (s == ACTAG_BINPATH_PROBE_ONLY)  return (int)LoaderInformation.PrivateBinPathProbeValue;
                    break;
                case 'C':
                    if (s == ACTAG_APP_CACHE_BASE)      return (int)LoaderInformation.CachePathValue;
                    if (s == ACTAG_CODE_DOWNLOAD_DISABLED) return (int)LoaderInformation.DisallowCodeDownloadValue;
                    break;
                case 'D':
                    if (s == ACTAG_DEV_PATH)            return (int)LoaderInformation.DevPathValue;
                    if (s == ACTAG_APP_DYNAMIC_BASE)    return (int)LoaderInformation.DynamicBaseValue;
                    if (s == ACTAG_DISALLOW_APPLYPUBLISHERPOLICY) return (int)LoaderInformation.DisallowPublisherPolicyValue;
                    if (s == ACTAG_DISALLOW_APP_BINDING_REDIRECTS) return (int)LoaderInformation.DisallowBindingRedirectsValue;
                    if (s == ACTAG_DISALLOW_APP_BASE_PROBING) return (int)LoaderInformation.DisallowAppBaseProbingValue;
                   break;
                case 'F':
                    if (s == ACTAG_FORCE_CACHE_INSTALL) return (int)LoaderInformation.ShadowCopyFilesValue;
                    break;
                case 'L':
                    if (s == LICENSE_FILE)              return (int)LoaderInformation.LicenseFileValue;
                    break;
                case 'P':
                    if (s == ACTAG_APP_PRIVATE_BINPATH) return (int)LoaderInformation.PrivateBinPathValue;
                    break;
                case 'S':
                    if (s == ACTAG_APP_SHADOW_COPY_DIRS) return (int)LoaderInformation.ShadowCopyDirectoriesValue;
                    break;
            }
#else
            Contract.Assert('A' == ACTAG_APP_BASE_URL[0]        , "Assumption violated");
            if (s[0]=='A' && s == ACTAG_APP_BASE_URL)        
                return (int)LoaderInformation.ApplicationBaseValue;

#endif //FEATURE_FUSION

            return -1;
        }
#if FEATURE_FUSION
        private string BuildShadowCopyDirectories()
        {
            // Default to only to the ones that are in the private bin path.
            String binPath = Value[(int) LoaderInformation.PrivateBinPathValue];
            if(binPath == null)
                return null;

            StringBuilder result = StringBuilderCache.Acquire();
            String appBase = Value[(int) LoaderInformation.ApplicationBaseValue];
            if(appBase != null) {
                char[] sep = {';'};
                string[] directories = binPath.Split(sep);
                int size = directories.Length;
                bool appendSlash = !( (appBase[appBase.Length-1] == '/') ||
                                      (appBase[appBase.Length-1] == '\\') );

                if (size == 0) {
                    result.Append(appBase);
                    if (appendSlash)
                        result.Append('\\');
                    result.Append(binPath);
                }
                else {
                    for(int i = 0; i < size; i++) {
                        result.Append(appBase);
                        if (appendSlash)
                            result.Append('\\');
                        result.Append(directories[i]);
                        
                        if (i < size-1)
                            result.Append(';');
                    }
                }
            }
            
            return StringBuilderCache.GetStringAndRelease(result);
        }
#endif // FEATURE_FUSION		

#if FEATURE_COMINTEROP
        public bool SandboxInterop
        {
            get
            {
                return _DisableInterfaceCache;
            }
            set
            {
                _DisableInterfaceCache = value;
            }
        }
#endif // FEATURE_COMINTEROP
    }
}
