FontCacheUtil.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / MS / Internal / FontCache / FontCacheUtil.cs / 1 / FontCacheUtil.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Description: Miscellaneous utility functions for font handling code. 
//
//--------------------------------------------------------------------------- 
 
using System;
using System.Collections; 
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization; 
using System.IO;
using System.IO.Packaging; 
using System.Reflection; 
using System.Resources;
using System.Runtime.InteropServices; 
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading; 
using System.Windows;
using System.Windows.Markup;    // for XmlLanguage 
using System.Windows.Media; 
using System.Windows.Navigation;
using System.Windows.Threading; 

using MS.Win32;
using MS.Internal;
using MS.Internal.FontFace; 
using MS.Internal.PresentationCore;
using MS.Internal.Resources; 
using MS.Utility; 

using Microsoft.Win32.SafeHandles; 

// Since we disable PreSharp warnings in this file, we first need to disable warnings about unknown message numbers and unknown pragmas.
#pragma warning disable 1634, 1691
 
namespace MS.Internal.FontCache
{ 
    ///  
    /// CheckedPointer is used to reference a fixed size memory block.
    /// The purpose of the class is to protect the memory block from overruns. 
    /// ArgumentOutOfRangeException is thrown when an overrun is detected.
    /// 
    /// 
    /// This class could potentially contain critical information for the case 
    /// where the data pointed to by "pointer" parameter is obtained under an
    /// elevation.  We consder CheckedPointer class itself to be security Agnostic. 
    /// When someone creates this instance from critical data, they'll need to 
    /// mark the instance as SecurityCritical and track usage.
    ///  
    [FriendAccessAllowed]
    internal struct CheckedPointer
    {
        ///  
        ///   Critical: This code yields unverifiable demand
        ///  
        [SecurityCritical] 
        internal unsafe CheckedPointer(void * pointer, int size)
        { 
            _pointer = pointer;
            _size = size;
        }
 
        /// 
        ///    Critical: This calls into PositionPointer which is link demand protected 
        ///    also it constructs data for a checked pointer. 
        /// 
        [SecurityCritical] 
        internal CheckedPointer(UnmanagedMemoryStream stream)
        {
            Debug.Assert(stream.Position == 0);
            unsafe { _pointer = stream.PositionPointer; } 
            long length = stream.Length;
            if (length < 0 || length > int.MaxValue) 
                throw new ArgumentOutOfRangeException(); 
            _size = (int)length;
        } 

        /// 
        ///     Critical: Call into unsafe code block
        ///     TreatAsSafe: This is ok to call 
        /// 
        internal bool IsNull 
        { 

            [SecurityCritical,SecurityTreatAsSafe] 
            get
            {
                unsafe
                { 
                    return (_pointer == null);
                } 
            } 
        }
 
        /// 
        ///     Critical: _size is marked as critical.
        ///     TreatAsSafe: _size is critical only for set.
        ///  
        internal int Size
        { 
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                return _size;
            }
        }
 
        /// 
        ///   Critical: This code yields unverifiable demand. This code can be used to expose contents of arbitrary pointers 
        ///  
        [SecurityCritical]
        internal byte[] ToArray() 
        {
            byte[] b = new byte[_size];
            unsafe
            { 
                if (_pointer == null)
                    throw new ArgumentOutOfRangeException(); 
 
                Marshal.Copy((IntPtr)_pointer, b, 0, Size);
            } 
            return b;
        }

        ///  
        ///   Critical: This code exposes contents of arbitrary pointers.
        ///  
        [SecurityCritical] 
        internal void CopyTo(CheckedPointer dest)
        { 
            unsafe
            {
                if (_pointer == null)
                    throw new ArgumentOutOfRangeException(); 

                byte* s = (byte*)_pointer; 
                byte * d = (byte *)dest.Probe(0, _size); 
                for (int i = 0; i < _size; ++i)
                { 
                    d[i] = s[i];
                }
            }
        } 

        // Returns the offset of the given pointer within this mapping, 
        // with a bounds check.  The returned offset may be equal to the size, 
        // but not greater. Throws ArgumentOutOfRangeException if pointer
        // is not within the bounds of the mapping. 
        /// 
        ///   Critical: The method takes a pointer and performs pointer arithmetic.
        /// 
        [SecurityCritical] 
        internal unsafe int OffsetOf(void * pointer)
        { 
            long offset = (byte*)pointer - (byte*)_pointer; 
            if (offset < 0 || offset > _size || _pointer == null || pointer == null)
                throw new ArgumentOutOfRangeException(); 
            return (int)offset;//no truncation possible since _size is an int
        }

        // Returns the offset of the given pointer within this mapping, 
        // with a bounds check.  The returned offset may be equal to the size,
        // but not greater. Throws ArgumentOutOfRangeException if pointer 
        // is not within the bounds of the mapping. 
        /// 
        ///   Critical: The method contains unsafe code and calls the critical OffsetOf(void*) method. 
        /// 
        [SecurityCritical]
        internal int OffsetOf(CheckedPointer pointer)
        { 
            unsafe
            { 
                return OffsetOf(pointer._pointer); 
            }
        } 

        /// 
        ///   Critical: This code yields unverifiable demand
        ///   TreatAsSafe: This code simply overloads the + operator to increment pointer. 
        ///   It is safe because it is bounds checked to ensure it does not corrupt memory
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        public static CheckedPointer operator+(CheckedPointer rhs, int offset)
        { 
            // In future I'll just use checked context. That'll require modifying callers to expect integer overflow exceptions.
            unsafe
            {
                if (offset < 0 || offset > rhs._size || rhs._pointer == null) 
                    throw new ArgumentOutOfRangeException();
                rhs._pointer = (byte*)rhs._pointer + offset; 
            } 
            rhs._size -= offset;
            return rhs; 
        }

        /// 
        ///  Critical: This code yields unverifiable demand and returns a pointer 
        ///  Although it is bounds checked the fact that it returns a pointer makes it risky.
        ///  
        [SecurityCritical] 
        internal unsafe void * Probe(int offset, int length)
        { 
            if (_pointer == null || offset < 0 || offset > _size || offset + length > _size || offset + length < 0)
                throw new ArgumentOutOfRangeException();
            return (byte *)_pointer + offset;
        } 

        ///  
        /// Same as Probe, but returns a CheckedPointer instead of an unsafe pointer 
        /// 
        ///  
        /// 
        /// 
        /// 
        ///       Critical: This calls into unsafe code and also calls into checkedpointer which has a link demand 
        ///       TreatAsSafe: This code returns a checkedpointer and accessing the content is critical. Accessing is tracked in Probe
        ///  
        [SecurityCritical,SecurityTreatAsSafe] 
        internal CheckedPointer CheckedProbe(int offset, int length)
        { 
            unsafe
            {
                if (_pointer == null || offset < 0 || offset > _size || offset + length > _size || offset + length < 0)
                    throw new ArgumentOutOfRangeException(); 

                return new CheckedPointer((byte*)_pointer + offset, length); 
            } 
        }
 
        ///Changes the buffer size of this CheckedPointer object.  Used when memory block is resizable,
        ///like in a file mapping.
        ///
        /// Critical: Passing an invalid size can calls future calls to Probe() to succeed even if the bounds of the buffer 
        /// is being violated.  This can cause the program to write to random memory.
        /// 
        [SecurityCritical] 
        internal void SetSize(int newSize)
        { 
            _size = newSize;
        }

        ///  
        ///       Critical: Contains unsafe code, which accesses _pointer field.
        ///       TreatAsSafe: Only compares; does not expose pointer or do unsafe pointer operations. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal bool PointerEquals(CheckedPointer pointer) 
        {
            unsafe
            {
                return _pointer == pointer._pointer; 
            }
        } 
 
        /// 
        ///       Critical: Contains unsafe code. 
        ///       TreatAsSafe: Calls Probe and writes only the amount of data it probed for.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void WriteBool(bool value) 
        {
            unsafe 
            { 
                *(bool*)this.Probe(0, sizeof(bool)) = value;
            } 
        }

        /// 
        ///       Critical: Contains unsafe code. 
        ///       TreatAsSafe: Calls Probe and reads only the amount of data it probed for.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal bool ReadBool()
        { 
            unsafe
            {
                return *(bool*)this.Probe(0, sizeof(bool));
            } 
        }
 
        ///  
        ///    Critical: Holds reference to an unsafe pointer
        ///  
        [SecurityCritical]
        private unsafe void *   _pointer;

        ///  
        ///    Critical: Having an invalid size can cause future calls to Probe() to succeed
        /// even if the bounds of the buffer is being violated. 
        /// This can cause the program to write to random memory. 
        /// This variable should really be SecurityCriticalDataForSet of int,
        /// but SecurityCriticalDataForSet is a generic defined in another assembly, 
        /// and using it with a value type will cause JITting to happen.
        /// 
        [SecurityCritical]
        private int _size; 
    }
 
    ///  
    /// HashFn is a port of predefined hash functions from LKRHash
    ///  
    [FriendAccessAllowed]
    internal static class HashFn
    {
        // Small prime number used as a multiplier in the supplied hash functions 
        private const int HASH_MULTIPLIER = 101;
 
        internal static int HashMultiply(int hash) 
        {
            return hash * HASH_MULTIPLIER; 
        }

        /// 
        /// Distributes accumulated hash value across a range. 
        /// Should be called just before returning hash code from a hash function.
        ///  
        /// Hash value 
        /// Scrambed hash value
        internal static int HashScramble(int hash) 
        {
            // Here are 10 primes slightly greater than 10^9
            //  1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
            //  1000000093, 1000000097, 1000000103, 1000000123, 1000000181. 

            // default value for "scrambling constant" 
            const int RANDOM_CONSTANT = 314159269; 
            // large prime number, also used for scrambling
            const uint RANDOM_PRIME =   1000000007; 

            // we must cast to uint and back to int to correspond to current C++ behavior for operator%
            // since we have a matching hash function in native code
            uint a = (uint)(RANDOM_CONSTANT * hash); 
            int b = (int)(a % RANDOM_PRIME);
            return b; 
        } 

        ///  
        /// Computes a hash code for a block of memory.
        /// One should not forget to call HashScramble before returning the final hash code value to the client.
        /// 
        /// Pointer to a block of memory 
        /// Size of the memory block in bytes
        /// Previous hash code to combine with 
        /// Hash code 
        /// 
        /// Critical - as this accesses unsafe code blocks and has the potential to 
        /// corrupt memory.
        /// 
        [SecurityCritical]
        internal unsafe static int HashMemory(void * pv, int numBytes, int hash) 
        {
            byte * pb = (byte*)pv; 
 
            while (numBytes-- > 0)
            { 
                hash = HashMultiply(hash)  +  *pb;
                ++pb;
            }
 
            return hash;
        } 
 
        internal static int HashString(string s, int hash)
        { 
            foreach (char c in s)
            {
                hash = HashMultiply(hash)  +  (ushort)c;
            } 
            return hash;
        } 
    } 

    internal unsafe struct HashTable 
    {
        //Header for every font cache element in the hash table
        [StructLayout(LayoutKind.Explicit, Size = 8)]
        private struct ElementHeader 
        {
            [FieldOffset(0)] 
            internal int nextOffset;//offset of next element, relative to beginning of cache 

            [FieldOffset(4)] 
            internal int type; //type of current element

            //element data follows here
        }; 

        //Probes a checked pointer for element header information and asserts 
        //if the pointer is not aligned. 
        ///
        /// Critical - does unsafe pointer manipulation and returns a pointer 
        ///
        [SecurityCritical]
        private static ElementHeader* ProbeElementHeader(CheckedPointer p,int offset)
        { 
            void* res = p.Probe(offset, sizeof(ElementHeader));
            Util.AssertAligned4(res); 
            return (ElementHeader*)res; 
        }
 
        /// 
        /// Retrieves information about the element stored at the given pointer.
        /// 
        /// On input, *elementOffsetPtr contains the offset of an element in the cache 
        /// or Util.nullOffset.
        /// If an element is referenced, elementOffsetPtr will be adjusted to point to the next element offset field of the element 
        /// referenced.  Otherwise, elementOffsetPtr will be unmodified. 
        /// 
        /// On output, pointer to the header of the referenced element, or null if none 
        /// On output, CheckedPointer to data of referenced element, or null if none
        /// true if elementOffsetPtr references an element, false if not
        /// 
        ///   Critical: takes and returns pointers. 
        /// 
        [SecurityCritical] 
        private unsafe bool GetElementInfo(ref int* elementOffsetPtr, 
                                    out ElementHeader* elementHeader,
                                    out CheckedPointer elementDataPtr) 
        {
            int elementOffset = *elementOffsetPtr;

            if (elementOffset == Util.nullOffset) 
            {
                //No element referenced 
                elementHeader = null; 
                elementDataPtr = new CheckedPointer(null,0);
                return false; 
            }
            else
            {
                //Obtain the header 
                CheckedPointer elementPtr = _cacher.Mapping + elementOffset;
                elementHeader = ProbeElementHeader(elementPtr,0); 
 
                //Get the checked pointer for element data (implicit bounds check)
                elementDataPtr = elementPtr + sizeof(ElementHeader); 

                //Update elementOffsetPtr
                elementOffsetPtr = &elementHeader->nextOffset;
 
                return true;
            } 
        } 

        /// 
        /// Adds a new element to the hash table.
        ///
        /// Pointer to a location that stores the offset of an element in the cache.
        /// This function modifies the contents of the pointer to add the element to the cache. 
        /// 
        /// Type of the new element to add 
        /// Offset of the header of the new element, relative to the beginning of the cache 
        ///
        /// Critical: Takes a pointer as an argument.  Will write to random memory if pointer is corrupt. 
        ///
        [SecurityCritical]
        private unsafe void AddNewElement(int* elementOffsetPtr, int newElementType,int newElementOffset)
        { 
            ElementHeader* newElementHeader = ProbeElementHeader(Mapping, newElementOffset);
 
            lock (_cacher.Lock) 
            {
                //Update the new element first to keep the data in a consistent state 
                //if another thread is iterating through it at the same time
                newElementHeader->nextOffset = *elementOffsetPtr;
                newElementHeader->type = newElementType;
                *elementOffsetPtr = newElementOffset; 

                // flush the cache so that clients have a consistent view of it 
                Thread.MemoryBarrier(); 
            }
        } 

        private const int      sizeHashElement = sizeof(int);
        private int            numberOfBuckets;
        private ElementCacher _cacher; 

        private CheckedPointer Mapping { get { return _cacher.Mapping;}} 
        private CheckedPointer Table { get { return _cacher.GetCheckedPointer(ElementCacher.offHashTable); } } 

        ///  
        /// Returns a pointer to the offset of the first element in the cache of the given hash code.
        /// Modifying the contents of this pointer will alter the first element associated with the given
        /// hash code.  If *GetHashEntry(hash) is Util.nullOffset then no element is associated with the given
        /// hash code. 
        ///
        /// GetHashEntry() uses CheckedPointer.Probe() to ensure that *GetHashEntry(hash) is always 
        /// a safe operation, although no guarentees are made about the contents of the data contained. 
        /// 
        ///  
        ///   Critical: This code does  unsafe pointer manipulation and returns a pointer
        /// 
        [SecurityCritical]
        private int* GetHashEntry(int hash) 
        {
            long offsetInTable = ((uint)hash % numberOfBuckets) * sizeHashElement; 
            Invariant.Assert((offsetInTable >= 0) && (offsetInTable <= int.MaxValue)); 
            int* offsetInCache = ((int*)(Table.Probe((int)offsetInTable,sizeof(int))));
            return offsetInCache; 
        }

        /// 
        ///   Critical: This code resolves to unverifiable code and throws a demand. It takes an unverified pointer 
        /// 
        [SecurityCritical] 
        internal HashTable(ElementCacher cacher, int numberOfBuckets) 
        {
            _cacher = cacher; 
            this.numberOfBuckets = numberOfBuckets;
            Invariant.Assert((numberOfBuckets != 0) && (!Mapping.IsNull));
        }
        ///  
        ///   Critical: This code resolves to unverifiable code and throws a demand
        ///   TreatAsSafe: Initializes memory with null that is ok 
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        internal void Init() 
        {
            int size = SizeOf;
            Util.FillMemory(Table.Probe(0,size), size, Util.nullOffset);
        } 

        internal static int GetTableSize(int numberOfElements) 
        { 
            Debug.Assert(numberOfElements != 0);
            return numberOfElements * sizeHashElement; 
        }

        internal int SizeOf
        { 
            get
            { 
                return GetTableSize(numberOfBuckets); 
            }
        } 

        /// 
        ///    Critical: This code resolves to unverifiable code and throws a demand
        ///    TreatAsSafe: This is safe to expose since it looks up an element in the hash table 
        ///    and in case where the boolean is true for add adds it to the cache.
        ///    The risk is in the various function calls that deal with the pointers and 
        ///    the functions have been fortified to either be robust to pointers or there is 
        ///    checking in this code to ensure that invalid pointers do not go down the stack.
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        internal bool Lookup(IFontCacheElement e, bool add)
        {
            int hash = e.GetHashCode(); 

            int* elementOffsetPtr = GetHashEntry(hash); 
 
            ElementHeader* header;
            CheckedPointer data; 
            while(GetElementInfo(ref elementOffsetPtr, out header, out data))
            {
                if (header->type == e.Type)
                { 
                    if (e.Match(data))
                    { 
                        e.GetData(data, _cacher); 
                        return true;
                    } 
                }
            }
            if (add)
            { 
                // now, construct the new element
                int newOffset = _cacher.Alloc(e.Size + sizeof(ElementHeader)); 
 
                CheckedPointer elem = _cacher.GetCheckedPointer(newOffset + sizeof(ElementHeader));
                e.AddToCache(elem, _cacher); 

                AddNewElement(elementOffsetPtr, e.Type, newOffset);
            }
            return false; 
        }
    } 
 
    /// 
    /// Utility functions for interaction with font cache service 
    /// 
    [FriendAccessAllowed]
    internal static class Util
    { 
        internal const int nullOffset = -1;
 
        private static readonly string[] SupportedExtensions = new string[] 
            {
                // .COMPOSITEFONT must remain the first entry in this array 
                // because IsSupportedFontExtension relies on this.
                ".COMPOSITEFONT",
                ".OTF",
                ".TTC", 
                ".TTF",
                ".TTE" 
            }; 

        private static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars(); 

        internal const UriComponents UriWithoutFragment = UriComponents.AbsoluteUri & ~UriComponents.Fragment;

        private const string WinDir = "windir"; 
        private const string EmptyFontFamilyReference = "#";
        private const string EmptyCanonicalName = ""; 
 
        /// 
        ///     Critical: This code elevates to get access to environment variable windir 
        /// and exposes the local Windows fonts directory location.
        ///     TreatAsSafe: This code uses critical fields to store critical data.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        static Util()
        { 
            string s; 
            //this code elevates to get access to the windir directory
            EnvironmentPermission environmentPermission = new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Windir"); 
            environmentPermission.Assert(); //Blessed Assert
            try
            {
                s = Environment.GetEnvironmentVariable(WinDir) + @"\Fonts\"; 
            }
            finally 
            { 
                EnvironmentPermission.RevertAssert();
            } 

            _windowsFontsLocalPath = s.ToUpperInvariant();

            _windowsFontsUriObject = new Uri(_windowsFontsLocalPath, UriKind.Absolute); 

            // Characters that have reserved meanings (e.g., '%', '#', '/', etc.) remain escaped in the 
            // string, but all others are not escaped. 
            _windowsFontsUriString = _windowsFontsUriObject.GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);
        } 

        /// 
        /// Windows fonts Uri string in an unescaped form optimized for Uri manipulations.
        ///  
        /// 
        ///     Critical: Exposes the local Windows fonts directory location. 
        ///  
        [SecurityCritical]
        private static readonly string _windowsFontsLocalPath; 

        /// 
        ///     Critical: Exposes the local Windows fonts directory location.
        ///  
        internal static string WindowsFontsLocalPath
        { 
            [SecurityCritical] 
            get
            { 
                return _windowsFontsLocalPath;
            }
        }
 
        /// 
        /// Windows fonts Uri object. 
        ///  
        /// 
        ///     Critical: Exposes the local Windows fonts directory location. 
        /// 
        [SecurityCritical]
        private static readonly Uri _windowsFontsUriObject;
 
        /// 
        ///     Critical: Exposes the local Windows fonts directory location. 
        ///  
        internal static Uri WindowsFontsUriObject
        { 
            [SecurityCritical]
            get
            {
                return _windowsFontsUriObject; 
            }
        } 
 
        /// 
        /// Windows fonts Uri string in an unescaped form. 
        /// 
        /// 
        ///     Critical: Exposes the local Windows fonts directory location.
        ///  
        [SecurityCritical]
        private static readonly string _windowsFontsUriString; 
 
        /// 
        ///     Critical: Exposes the local Windows fonts directory location. 
        /// 
        internal static string WindowsFontsUriString
        {
            [SecurityCritical] 
            get
            { 
                return _windowsFontsUriString; 
            }
        } 


        /// 
        /// Checks whether the specified location string or font family reference refers to the 
        /// default Windows Fonts folder.
        ///  
        ///  
        /// Returns true if the location part is empty or is a simple file name with no path
        /// characters (e.g., "#ARIAL" or "arial.ttf#ARIAL"). Returns false if the location 
        /// is invalid or includes a path (e.g., "./#ARIAL", "..#ARIAL", "fonts/#ARIAL").
        /// 
        /// 
        /// This code is important for correcly interpreting font family references, but is NOT 
        /// security critical. Even if the client somehow spoofs us, we never expose the resulting
        /// canonical family name and we do a security demand before accessing font data. 
        ///  
        internal static bool IsReferenceToWindowsFonts(string s)
        { 
            // Empty location always refers to Windows Fonts.
            if (string.IsNullOrEmpty(s) || s[0] == '#')
                return true;
 
            // Get the length of the location part.
            int length = s.IndexOf('#'); 
            if (length < 0) 
                length = s.Length;
 
            // Check for invalid file name characters in the location. These include reserved path
            // characters ('/', '\\', ':'), wildcards ('?', '*'), control characters, etc.
            if (s.IndexOfAny(InvalidFileNameChars, 0, length) >= 0)
                return false; 

            // A font family reference is a URI reference and may contain escaped characters. We need 
            // to check their unescaped values to protect against cases like this: 
            //   1. Create canonical name by concatenating "file:///c:/windows/Fonts/" + "foo%2fbar.ttf#Arial"
            //   2. Later we create a Uri from the canonical name and pass to FontSource class 
            //   3. FontSource gets Uri.LocalPath which returns "c:\windows\Fonts\foo\bar.ttf"
            //   4. Doh!
            for (int i = s.IndexOf('%', 0, length); i >= 0; i = s.IndexOf('%', i, length - i))
            { 
                // Get the unescaped character; this always advances i by at least 1.
                char unescapedChar = Uri.HexUnescape(s, ref i); 
 
                // Is it a reserved character?
                if (Array.IndexOf(InvalidFileNameChars, unescapedChar) >= 0) 
                    return false;
            }

            // Check for special names "." and ".." which represent directories. Also reject 
            // variations like "...", ".. ", etc., as none of these are valid file names.
            if (s[0] == '.') 
            { 
                // Advance past one or more '.'
                int i = 1; 
                while (i < length && s[i] == '.')
                    ++i;

                // advance past trailing spaces, e.g., ".. #Arial" 
                while (i < length && char.IsWhiteSpace(s[i]))
                    ++i; 
 
                // return false if the whole location is just repeated '. followed by spaces
                if (i == length) 
                    return false;
            }

            // If we fall through to here the location part has no reserved or illegal characters. 
            // The "file name" could still be a reserved device name like CON, PRN, etc., but since
            // none of these will have a known font extension we won't try to open the device. 
            return true; 
        }
 

        internal static bool IsSupportedSchemeForAbsoluteFontFamilyUri(Uri absoluteUri)
        {
            // The only absolute URIs we allow in font family references are "file:" URIs. 
            return absoluteUri.IsFile;
        } 
 

        internal static void SplitFontFaceIndex(Uri fontUri, out Uri fontSourceUri, out int faceIndex) 
        {
            // extract face index
            string fragment = fontUri.GetComponents(UriComponents.Fragment, UriFormat.SafeUnescaped);
            if (!String.IsNullOrEmpty(fragment)) 
            {
                if (!int.TryParse( 
                        fragment, 
                        NumberStyles.None,
                        CultureInfo.InvariantCulture, 
                        out faceIndex
                    ))
                {
                    throw new ArgumentException(SR.Get(SRID.FaceIndexMustBePositiveOrZero), "fontUri"); 
                }
 
                // face index was specified in a fragment, we need to strip off fragment from the source Uri 
                fontSourceUri = new Uri(fontUri.GetComponents(Util.UriWithoutFragment, UriFormat.SafeUnescaped));
            } 
            else
            {
                // simple case, no face index specified
                faceIndex = 0; 
                fontSourceUri = fontUri;
            } 
        } 

        internal static Uri CombineUriWithFaceIndex(string fontUri, int faceIndex) 
        {
            if (faceIndex == 0)
                return new Uri(fontUri);
 
            // the Uri roundtrip is necessary for escaping possible '#' symbols in the folder path,
            // so that they don't conflict with the fragment part. 
            string canonicalPathUri = new Uri(fontUri).GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped); 
            string faceIndexString = faceIndex.ToString(CultureInfo.InvariantCulture);
            return new Uri(canonicalPathUri + '#' + faceIndexString); 
        }

        internal static bool IsSupportedFontExtension(string extension, out bool isComposite)
        { 
            for (int i = 0; i < SupportedExtensions.Length; ++i)
            { 
                string supportedExtension = SupportedExtensions[i]; 
                if (String.Compare(extension, supportedExtension, StringComparison.OrdinalIgnoreCase) == 0)
                { 
                    isComposite = (i == 0); // First array entry is *.CompositeFont
                    return true;
                }
            } 
            isComposite = false;
            return false; 
        } 

        internal static bool IsEnumerableFontUriScheme(Uri fontLocation) 
        {
            bool isEnumerable = false;

            // We only support file:// and pack:// application Uris to reference logical fonts. 
            if (fontLocation.IsAbsoluteUri)
            { 
                if (fontLocation.IsFile) 
                {
                    // file scheme is always enumerable 
                    isEnumerable = true;
                }
                else if (fontLocation.Scheme == PackUriHelper.UriSchemePack)
                { 
                    // This is just an arbitrary file name which we use to construct a file URI.
                    const string fakeFileName = "X"; 
 
                    // The fontLocation could be a folder-like URI even though the pack scheme does not allow this.
                    // We simulate the concept of subfolders for packaged fonts. Before calling any PackUriHelper 
                    // methods, create a Uri which we know to be a file-like (rather than folder-like) URI.
                    Uri fileUri;
                    if (Uri.TryCreate(fontLocation, fakeFileName, out fileUri))
                    { 
                        isEnumerable = BaseUriHelper.IsPackApplicationUri(fileUri);
                    } 
                } 
            }
 
            return isEnumerable;
        }

        internal static bool IsAppSpecificUri(Uri fontLocation) 
        {
            // Only file:// Uris that refer to local drives can be cached across applications. 
            // This function filters out some easy options, such as app specific pack:// Uris and 
            // UNC paths.
            // Note that we make an assumption here that local drive letters stay the same across user sessions. 
            // Also, we rely on session 0 not having access to any of the mapped drives.
            return !fontLocation.IsAbsoluteUri || !fontLocation.IsFile || fontLocation.IsUnc;
        }
 
        internal static string GetUriExtension(Uri uri)
        { 
            string unescapedPath = uri.GetComponents(UriComponents.Path, UriFormat.Unescaped); 
            return Path.GetExtension(unescapedPath);
        } 

        /// 
        /// Converts the specified portion of a friendly name to a normalized font family reference.
        ///  
        /// 
        /// Friendly names use commas as delimeters so any literal commas must be escaped by 
        /// doubling. If any doubled commas are present in the specified substring they are unescaped 
        /// in the normalized font family reference.
        ///  
        internal static string GetNormalizedFontFamilyReference(string friendlyName, int startIndex, int length)
        {
            if (friendlyName.IndexOf(',', startIndex, length) < 0)
            { 
                // We don't need to unescape any commas.
                return NormalizeFontFamilyReference(friendlyName, startIndex, length); 
            } 
            else
            { 
                // Unescape commas and then convert to normalized form.
                return NormalizeFontFamilyReference(friendlyName.Substring(startIndex, length).Replace(",,", ","));
            }
        } 

        ///  
        /// Converts a font family reference to a normalized form. 
        /// 
        private static string NormalizeFontFamilyReference(string fontFamilyReference) 
        {
            return NormalizeFontFamilyReference(fontFamilyReference, 0, fontFamilyReference.Length);
        }
 
        /// 
        /// Converts a font family reference to normalized form. 
        ///  
        /// 
        /// In normalized form, the fragment separator ('#') is always present, and the family 
        /// name part (i.e., everything after the fragment separator) has been converted to
        /// upper case. However, the case of the location part (if any) is preserved.
        /// 
        ///  
        /// "Arial"             -->  "#ARIAL"
        /// "fonts/#My Font"    -->  "fonts/#MY FONT" 
        /// "/fonts/#My Font"   -->  "/fonts/#MY FONT" 
        /// 
        private static string NormalizeFontFamilyReference(string fontFamilyReference, int startIndex, int length) 
        {
            if (length == 0)
                return EmptyFontFamilyReference;
 
            int fragmentIndex = fontFamilyReference.IndexOf('#', startIndex, length);
            if (fragmentIndex < 0) 
            { 
                // No fragment separator. The entire string is a family name so convert to uppercase
                // and add a fragment separator at the beginning. 
                return "#" + fontFamilyReference.Substring(startIndex, length).ToUpperInvariant();
            }
            else if (fragmentIndex + 1 == startIndex + length)
            { 
                // No family name part.
                return EmptyFontFamilyReference; 
            } 
            else if (fragmentIndex == startIndex)
            { 
                // Empty location part; convert the whole string to uppercase.
                return fontFamilyReference.Substring(startIndex, length).ToUpperInvariant();
            }
            else 
            {
                // Convert the fragment to uppercase, but preserve the case of the location. 
                string location = fontFamilyReference.Substring(startIndex, fragmentIndex - startIndex); 
                string fragment = fontFamilyReference.Substring(fragmentIndex, (startIndex + length) - fragmentIndex);
                return location + fragment.ToUpperInvariant(); 
            }
        }

 
        /// 
        /// Converts a font family name and location to a font family reference. 
        ///  
        /// A font family name with no characters escaped
        /// An optional location 
        /// Returns a font family reference, which may be either a URI reference or just a fragment
        /// (with or without the '#' prefix)
        internal static string ConvertFamilyNameAndLocationToFontFamilyReference(string familyName, string location)
        { 
            // Escape reserved characters in the family name. In the fragment, we need only
            // worry about literal percent signs ('%') to avoid confusion with the escape prefix 
            // and literal pound signs ('#') to avoid confusion with the fragment separator. 
            string fontFamilyReference = familyName.Replace("%", "%25").Replace("#", "%23");
 
            // Is there a location part?
            if (!string.IsNullOrEmpty(location))
            {
                // We just escaped the family name and the location part should already be a valid URI reference. 
                fontFamilyReference = string.Concat(
                    location, 
                    "#", 
                    fontFamilyReference
                    ); 
            }

            return fontFamilyReference;
        } 

        ///  
        /// Converts a font family reference to a friendly name by escaping any literal commas. 
        /// 
        /// A font family reference 
        /// Returns a friendly name.
        /// Single commas delimit multiple font family references in a friendly name so any
        /// commas in the specified string are replaced with double commas in the return value.
        ///  
        internal static string ConvertFontFamilyReferenceToFriendlyName(string fontFamilyReference)
        { 
            return fontFamilyReference.Replace(",", ",,"); 
        }
 
        /// 
        ///    Critical: This code resolves to unverifiable code and throws a demand
        /// 
        [SecurityCritical] 
        internal unsafe static void FillMemory(void* pv, int size, int valueToFill)
        { 
            AssertAligned4(pv); 
            AssertAligned4(size);
            byte* pb = (byte*)pv; 
            for (byte* p = pb; p < pb + size; p += 4)
            {
                *(int*)p = valueToFill;
            } 
        }
 
        internal static int Align8(int i) 
        {
            return (i + 7) & ~7; 
        }

        internal static int Align4(int i)
        { 
            return (i + 3) & ~3;
        } 
 
        /// 
        ///    Critical: This code resolves to unverifiable code and throws a demand 
        /// 
        [SecurityCritical]
        [Conditional("DEBUG")]
        internal unsafe static void AssertAligned4(void* p) 
        {
            Debug.Assert(p != null); 
            long i = ((IntPtr)p).ToInt64(); 
            Debug.Assert((i % 4L) == 0);
        } 

        /// 
        ///    Critical: This code resolves to unverifiable code and throws a demand
        ///   TreatAsSafe: This code is safe to expose 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        [Conditional("DEBUG")] 
        internal static void AssertAligned4(int i)
        { 
            Debug.Assert((i % 4) == 0);
        }

        ///  
        ///    Critical: This code resolves to unverifiable code and throws a demand
        ///   TreatAsSafe: This code is ok to expose 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        [Conditional("DEBUG")] 
        internal static void AssertAligned8(int i)
        {
            Debug.Assert((i % 8) == 0);
        } 

        ///  
        ///    Critical: This code resolves to unverifiable code and throws a demand 
        /// 
        [SecurityCritical] 
        [Conditional("DEBUG")]
        internal unsafe static void AssertAligned8(void* p)
        {
            Debug.Assert(p != null); 
            long i = ((IntPtr)p).ToInt64();
            Debug.Assert((i % 8L) == 0); 
        } 

        ///  
        /// Copies values from an array of ushort to a CheckedPointer and returns the number of bytes
        /// copied. Other overloads can be added as needed; unfortunately we can't use generics for this.
        /// 
        ///  
        ///     Critical:    This code does  unsafe pointer manipulation
        ///     TreatAsSafe: Probe checks for pointer validity and the creation of checked pointer 
        ///                  is tracked 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        internal static int ArrayCopyToCheckedPointer(CheckedPointer p, ushort[] array, int startIndex, int length)
        {
            if (startIndex < 0 || startIndex > array.Length)
                throw new ArgumentOutOfRangeException("startIndex"); 

            if (length < 0 || length > array.Length - startIndex) 
                throw new ArgumentOutOfRangeException("length"); 

            int sizeInBytes = length * sizeof(ushort); 

            unsafe
            {
                ushort* dst = (ushort*)p.Probe(0, sizeInBytes); 
                for (int i = startIndex, end = startIndex + length; i < end; ++i)
                { 
                    *dst++ = array[i]; 
                }
                Invariant.Assert(p.OffsetOf(dst) == sizeInBytes); 
            }

            return sizeInBytes;
        } 

        ///  
        /// Copies a string into a memory block 
        /// 
        /// Destination memory block 
        /// Source string
        /// 
        ///     Critical: This code does  unsafe pointer manipulation and dereferences p
        ///  
        [SecurityCritical]
        internal unsafe static void StringCopyToUncheckedPointer(void* p, string s) 
        { 
            char* d = (char*)p;
            for (int i = 0; i < s.Length; ++i) 
            {
                d[i] = s[i];
            }
        } 

        ///  
        ///     Critical: This code does  unsafe pointer manipulation 
        ///     TreatAsSafe: Probe checks for pointer validity and the creation of checked pointer
        ///     is tracked 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal static void StringCopyToCheckedPointer(CheckedPointer p, string s)
        { 
            unsafe { StringCopyToUncheckedPointer(p.Probe(0, s.Length * sizeof(char)), s); }
        } 
 
        /// 
        ///     Critical: This code does  unsafe pointer manipulation 
        /// 
        [SecurityCritical]
        internal unsafe static string StringCopyFromUncheckedPointer(void* p, int sizeInBytes)
        { 
            Invariant.Assert(sizeInBytes % sizeof(char) == 0);
 
            if (sizeInBytes == 0) 
                return string.Empty;
            else 
                return new string((char*)p, 0, sizeInBytes / sizeof(char));
        }

        ///  
        ///     Critical: This code does  unsafe pointer manipulation
        ///     TreatAsSafe: This uses checkedpointer which is carefully tracked and boundary checked 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal static string StringCopyFromCheckedPointer(CheckedPointer p, int sizeInBytes) 
        {
            unsafe { return StringCopyFromUncheckedPointer(p.Probe(0, sizeInBytes), sizeInBytes); }
        }
 
        /// 
        /// Copies a string and its length to a checked pointer. 
        ///  
        /// CheckedPointer to copy the string to. It will contain integer string length in the first four bytes.
        /// Input string. 
        /// The number of bytes written to the CheckedPointer.
        /// 
        ///     Critical: This code does unsafe pointer manipulation.
        ///     TreatAsSafe: This uses checkedpointer which is carefully tracked and boundary checked 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal static int StringAndLengthCopyToCheckedPointer(CheckedPointer p, string s) 
        {
            int realSize = sizeof(int) + Util.StringSize(s); 
            unsafe
            {
                int* l = (int*)p.Probe(0, realSize);
                *l = Util.StringSize(s); 
                ++l;
                Util.StringCopyToUncheckedPointer(l, s); 
            } 
            return realSize;
        } 

        /// CheckedPointer to copy the string from. It contains integer string length in the first four bytes.
        /// String to store the result in.
        ///  
        ///     Critical: This code does unsafe pointer manipulation.
        ///     TreatAsSafe: This uses checkedpointer which is carefully tracked and boundary checked 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal static string StringAndLengthCopyFromCheckedPointer(CheckedPointer p) 
        {
            unsafe
            {
                int* length = (int*)p.Probe(0, sizeof(int)); 
                return StringCopyFromCheckedPointer(p + sizeof(int), *length);
            } 
        } 

        ///  
        ///     Critical: This code does unsafe pointer manipulations.
        ///      TreatAsSafe: The pointer manipulations are checked.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal static bool StringEqual(CheckedPointer p, string s)
        { 
            // Don't throw if p points to a memory block smaller than s. 
            // This simply means that the strings are not equal.
            if (p.Size < StringSize(s)) 
                return false;

            unsafe
            { 
                char* chars = (char*)p.Probe(0, StringSize(s));
                for (int i = 0; i < s.Length; ++i) 
                { 
                    if (s[i] != chars[i])
                        return false; 
                }
                return true;
            }
        } 

        ///  
        ///     Critical: This code does unsafe pointer manipulations. 
        ///      TreatAsSafe: The pointer manipulations are checked.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal static bool StringEqualIgnoreCase(CheckedPointer p, string s)
        {
            // Don't throw if p points to a memory block smaller than s. 
            // This simply means that the strings are not equal.
            if (p.Size < StringSize(s)) 
                return false; 

            unsafe 
            {
                char* chars = (char*)p.Probe(0, StringSize(s));
                for (int i = 0; i < s.Length; ++i)
                { 
                    char dst = Char.ToUpperInvariant(chars[i]);
                    char src = Char.ToUpperInvariant(s[i]); 
                    if (dst != src) 
                        return false;
                } 
                return true;
            }
        }
 
        /// 
        ///     Critical: This code calls sizeof(char). 
        ///     TreatAsSafe: Calling sizeof(char) is obviously a safe operation. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal static int StringSize(string s)
        {
            unsafe { return s.Length * sizeof(char); }
        } 

        internal static void AddMemoryPressure(long pressure) 
        { 
            MemoryPressure.Add(pressure);
        } 

        internal static void RemoveMemoryPressure(long pressure)
        {
            MemoryPressure.Remove(pressure); 
        }
 
        ///  
        /// Compares string using character ordinals.
        /// The comparison is case insensitive based on InvariantCulture. 
        /// We have our own custom wrapper because we need to sort using the same algorithm
        /// we use in incremental charater search.
        /// There are subtle things (e.g. surrogates) that String.Compare() does and we don't.
        ///  
        /// First input string.
        /// Second input string. 
        /// Same semantics as for String.Compare 
        internal static int CompareOrdinalIgnoreCase(string a, string b)
        { 
            int aLength = a.Length;
            int bLength = b.Length;
            int minLength = Math.Min(aLength, bLength);
            for (int i = 0; i < minLength; ++i) 
            {
                int result = CompareOrdinalIgnoreCase(a[i], b[i]); 
                if (result != 0) 
                    return result;
            } 
            return aLength - bLength;
        }

        private static int CompareOrdinalIgnoreCase(char a, char b) 
        {
            char ca = Char.ToUpperInvariant(a); 
            char cb = Char.ToUpperInvariant(b); 
            return ca - cb;
        } 

        // Makes sure the caller has path discovery permission for full fileName path.
        private static void ValidateFileNamePermissions(ref string fileName)
        { 
            if (!SecurityHelper.CallerHasPathDiscoveryPermission(fileName))
            { 
                // If the caller didn't have path discovery permission for fileName, we can still give out relative file name. 
                fileName = Path.GetFileName(fileName);
            } 
        }

        /// 
        /// This function performs job similar to CLR's internal __Error.WinIOError function: 
        /// it maps win32 errors from file I/O to CLR exceptions and includes string where possible.
        /// However, we're interested only in errors when opening a file for reading. 
        ///  
        /// Win32 error code.
        /// File name string. 
        /// 
        ///     Critical - As this function throws exception containing full file name, which can result in Information Disclosure.
        ///     TreatAsSafe - As the function performs permission demand.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal static void ThrowWin32Exception(int errorCode, string fileName) 
        { 
            ValidateFileNamePermissions(ref fileName);
 
            switch (errorCode)
            {
                case NativeMethods.ERROR_FILE_NOT_FOUND:
                    throw new FileNotFoundException(SR.Get(SRID.FileNotFoundExceptionWithFileName, fileName), fileName); 

                case NativeMethods.ERROR_PATH_NOT_FOUND: 
                    throw new DirectoryNotFoundException(SR.Get(SRID.DirectoryNotFoundExceptionWithFileName, fileName)); 

                case NativeMethods.ERROR_ACCESS_DENIED: 
                    throw new UnauthorizedAccessException(SR.Get(SRID.UnauthorizedAccessExceptionWithFileName, fileName));

                case NativeMethods.ERROR_FILENAME_EXCED_RANGE:
                    throw new PathTooLongException(SR.Get(SRID.PathTooLongExceptionWithFileName, fileName)); 

                default: 
                    throw new IOException(SR.Get(SRID.IOExceptionWithFileName, fileName), NativeMethods.MakeHRFromErrorCode(errorCode)); 
            }
        } 

        /// 
        /// Critical - As this function accesses font Uri that contains absolute font path.
        /// Safe - As we use ValidateFileNamePermissions to strip off the local path part for file Uris. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal static Exception ConvertInPageException(FontSource fontSource, SEHException e) 
        {
            string fileName; 
            if (fontSource.Uri.IsFile)
            {
                fileName = fontSource.Uri.LocalPath;
                ValidateFileNamePermissions(ref fileName); 
            }
            else 
            { 
                fileName = fontSource.GetUriString();
            } 

            return new IOException(SR.Get(SRID.IOExceptionWithFileName, fileName), e);
        }
    } 

    ///  
    /// A class that wraps operations with Win32 memory sections and file mappings 
    /// 
    ///  
    /// This class could potentially contain critical information for the case
    /// where the data pointed to by the Mapping is obtained under an elevation.
    /// We consder FileMapping class itself to be security agnostic.  When
    /// someone creates this instance from critical data, they'll need to mark 
    /// the instance as SecurityCritical and track usage.  For example if a call to
    /// OpenFile is made on an instance of FileMapping, that instance will be 
    /// SecurityCritical. 
    /// 
    [FriendAccessAllowed] 
    internal class FileMapping : UnmanagedMemoryStream
    {
        ~FileMapping()
        { 
            Dispose(false);
        } 
 
        /// 
        ///    Critical: This method acceses critical elements _viewHandle and _mappingHandle 
        ///    TreatAsSafe: This data is not exposed and calling dispose is ok
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void Dispose(bool disposing) 
        {
            base.Dispose(disposing); 
            if (!_disposed) 
            {
                if (disposing) 
                {
                    if (_viewHandle != null)
                        _viewHandle.Dispose();
                    if (_mappingHandle != null) 
                        _mappingHandle.Dispose();
                } 
                if (CanWrite) 
                {
                    long currentSize = AlignToPage(Length); 
                    if (currentSize != 0)
                        Util.RemoveMemoryPressure(currentSize);
                }
            } 
            _disposed = true;
        } 
 
        /// 
        /// Creates a named memory section. May throw OutOfMemoryException. 
        /// 
        /// Memory section name
        /// The maximum reserve size of the section
        ///  
        ///     Critical - as this functions calls MapViewOfFileEx, CreateFileMapping and Initialize
        ///                which cause an elevation. 
        ///     TreatAsSafe - as this does a demand when name is not null.  When name is null, 
        ///                   it's just a chunk of memory it opens.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal void Create(string name, long maxSize)
        {
            maxSize = AlignToPage(maxSize); 

            if (name != null) 
            { 
                // This code only gets called by font cache service which runs in full trust.
                // When name is not null, this function should be protected because we could 
                // be exposing any named object on the system for read.
                SecurityHelper.DemandUnmanagedCode();
            }
 
            NativeMethods.SECURITY_ATTRIBUTES sa = new NativeMethods.SECURITY_ATTRIBUTES();
            using (sa) 
            { 
                if (name != null)
                { 
                    string securityDescriptor = "D:" + // DACL
                        "(D;;GA;;;NU)" + // Deny Network All
                        "(A;;GR;;;WD)"; // Allow World Read
 
                    if (!UnsafeNativeMethods.ConvertStringSecurityDescriptorToSecurityDescriptor(
                        securityDescriptor, UnsafeNativeMethods.SDDL_REVISION_1, 
                        ref sa.lpSecurityDescriptor, IntPtr.Zero)) 
                    {
                        throw new System.ComponentModel.Win32Exception(); 
                    }

                }
 
                UnsafeNativeMethods.ULARGE_INTEGER nSize = new UnsafeNativeMethods.ULARGE_INTEGER();
                nSize.QuadPart = (ulong)maxSize; 
 
                unsafe
                { 
                    // Disable PREsharp warning about not calling Marshal.GetLastWin32Error,
                    // because we already check the handle for invalid value and
                    // we are not particularly interested in specific Win32 error.
 
#pragma warning disable 6523
 
 
                    _mappingHandle = UnsafeNativeMethods.CreateFileMapping(
                    new SafeFileHandle(UnsafeNativeMethods.INVALID_HANDLE_VALUE, false), 
                    sa,
                    NativeMethods.PAGE_READWRITE | UnsafeNativeMethods.SEC_RESERVE,
                    nSize.HighPart,
                    nSize.LowPart, 
                    name);
                    if (_mappingHandle.IsInvalid) 
                        throw new OutOfMemoryException(); 

                    _viewHandle = UnsafeNativeMethods.MapViewOfFileEx(_mappingHandle, UnsafeNativeMethods.FILE_MAP_ALL_ACCESS, 0, 0, IntPtr.Zero, IntPtr.Zero); 
                    if (_viewHandle.IsInvalid)
                        throw new OutOfMemoryException();

#pragma warning disable 6523 

                    // Initialize() method demands UnmanagedCode permission, and Create() is already marked as critical. 
 
                    new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); //Blessed Assert
 
                    try
                    {
                        Initialize((byte*)_viewHandle.Memory, 0, maxSize, FileAccess.ReadWrite);
                    } 
                    finally
                    { 
                        SecurityPermission.RevertAssert(); 
                    }
                } 
            }
        }

        ///  
        /// Opens a named memory section. Caller should be prepared to catch IOException.
        ///  
        /// The name of the section. 
        /// 
        ///     Critical - because the code does an elevation to open a named file mapping. 
        /// 
        [SecurityCritical]
        internal void OpenSection(string name)
        { 
            // Disable PREsharp warning about not calling Marshal.GetLastWin32Error,
            // because we already check the handle for invalid value and 
            // we are not particularly interested in specific Win32 error. 

#pragma warning disable 6523 

            _mappingHandle = UnsafeNativeMethods.OpenFileMapping(UnsafeNativeMethods.FILE_MAP_READ, false, name);
            if (_mappingHandle.IsInvalid)
                throw new IOException(); 

            _viewHandle = UnsafeNativeMethods.MapViewOfFileEx(_mappingHandle, UnsafeNativeMethods.FILE_MAP_READ, 0, 0, IntPtr.Zero, IntPtr.Zero); 
            if (_viewHandle.IsInvalid) 
                throw new IOException();
 
#pragma warning restore 6523

            // Initialize() method demands UnmanagedCode permission, and OpenSection() is already marked as critical.
 
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); //Blessed Assert
 
            try 
            {
                unsafe 
                {
                    Initialize((byte*)_viewHandle.Memory, 0, 0, FileAccess.Read);
                }
            } 
            finally
            { 
                SecurityPermission.RevertAssert(); 
            }
        } 

        /// 
        /// Critical - As this function calls functions CreateFileMapping,
        ///            MapViewOfFileEx and Initialize under elevation. 
        ///            Any instance of FileMapping
        ///            object on which this function is called becomes a critical 
        ///            instance and its usage will need to be tracked for audit. 
        /// 
        [SecurityCritical] 
        internal void OpenFile(string fileName)
        {
            NativeMethods.SECURITY_ATTRIBUTES sa = new NativeMethods.SECURITY_ATTRIBUTES();
            using (sa) 
            {
                unsafe 
                { 
                    // Disable PREsharp warning about not calling Marshal.GetLastWin32Error,
                    // because we already check the handle for invalid value and 
                    // we are not particularly interested in specific Win32 error.

#pragma warning disable 6523
 
                    long size;
 
                    using (SafeFileHandle fileHandle = UnsafeNativeMethods.CreateFile( 
                        fileName,
                        NativeMethods.GENERIC_READ, 
                        NativeMethods.FILE_SHARE_READ,
                        null,
                        NativeMethods.OPEN_EXISTING,
                        0, 
                        IntPtr.Zero
                        )) 
                    { 
                        if (fileHandle.IsInvalid)
                        { 
                            Util.ThrowWin32Exception(Marshal.GetLastWin32Error(), fileName);
                        }

                        UnsafeNativeMethods.LARGE_INTEGER fileSize = new UnsafeNativeMethods.LARGE_INTEGER(); 
                        if (!UnsafeNativeMethods.GetFileSizeEx(fileHandle, ref fileSize))
                            throw new IOException(SR.Get(SRID.IOExceptionWithFileName, fileName)); 
 
                        size = (long)fileSize.QuadPart;
                        if (size == 0) 
                            throw new FileFormatException(new Uri(fileName));

                        _mappingHandle = UnsafeNativeMethods.CreateFileMapping(
                            fileHandle, 
                            sa,
                            UnsafeNativeMethods.PAGE_READONLY, 
                            0, 
                            0,
                            null); 
                    }

                    if (_mappingHandle.IsInvalid)
                        throw new IOException(SR.Get(SRID.IOExceptionWithFileName, fileName)); 

                    _viewHandle = UnsafeNativeMethods.MapViewOfFileEx(_mappingHandle, UnsafeNativeMethods.FILE_MAP_READ, 0, 0, IntPtr.Zero, IntPtr.Zero); 
                    if (_viewHandle.IsInvalid) 
                        throw new IOException(SR.Get(SRID.IOExceptionWithFileName, fileName));
 
#pragma warning restore 6523

                    // Initialize() method demands UnmanagedCode permission, and OpenFile() is already marked as critical.
 
                    new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); //Blessed Assert
 
                    try 
                    {
                        Initialize((byte*)_viewHandle.Memory, size, size, FileAccess.Read); 
                    }
                    finally
                    {
                        SecurityPermission.RevertAssert(); 
                    }
                } 
            } 
        }
 
        internal static long AlignToPage(long size)
        {
            return (size + (PageSize - 1)) & ~(PageSize - 1);
        } 

        ///  
        ///     Critical - As this function calls a native method VirtualAlloc under elevation. 
        ///     TreatAsSafe - as DOS for allocation of memory can happen in many different ways, e.g
        ///                   the app can commit lots of memory by just creating a huge number of objects. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void Commit(long size)
        { 
            Debug.Assert(size > Length);
            Debug.Assert(CanWrite); 
 
            long wantedSize = AlignToPage(size);
            long currentSize = AlignToPage(Length); 

            // No need to call VirtualAlloc if the page is already committed.
            if (wantedSize <= currentSize)
            { 
                SetLength(size);
                return; 
            } 

            // this assert would fire in case of a bug in client's code 
            Invariant.Assert(wantedSize <= Capacity);

            unsafe
            { 
                // Disable PREsharp warning about not calling Marshal.GetLastWin32Error,
                // because we already check the base address for nullness and 
                // we are not particularly interested in specific Win32 error. 

#pragma warning disable 6523 

                IntPtr baseAddress = UnsafeNativeMethods.VirtualAlloc((IntPtr)_viewHandle.Memory, (UIntPtr)wantedSize, UnsafeNativeMethods.MEM_COMMIT, UnsafeNativeMethods.PAGE_READWRITE);
                if (baseAddress == IntPtr.Zero)
                    throw new OutOfMemoryException(); 

#pragma warning restore 6523 
            } 

            SetLength(size); 

            Util.AddMemoryPressure(wantedSize - currentSize);
        }
 
        /// 
        ///     Critical: This element holds reference to an object retrieved under an elevation 
        ///  
        [SecurityCritical]
        private UnsafeNativeMethods.SafeViewOfFileHandle _viewHandle; 
        /// 
        ///     Critical: This element holds reference to an object retrieved under an elevation
        /// 
        [SecurityCritical] 
        private UnsafeNativeMethods.SafeFileMappingHandle _mappingHandle;
 
        private bool _disposed = false; 

        ///  
        /// The number of bytes to preallocate on Commit().
        /// It's equal to 2 x86 pages or 1 IA64 page.
        /// NOTE: AlignToPage relies on this being a power of 2.
        ///  
        private const int PageSize = 4096 * 2;
    } 
 
    internal class LocalizedName
    { 
        internal LocalizedName(XmlLanguage language, string name) : this(language, name, language.GetEquivalentCulture().LCID)
        {}

        internal LocalizedName(XmlLanguage language, string name, int originalLCID) 
        {
            _language = language; 
            _name = name; 
            _originalLCID = originalLCID;
        } 

        internal XmlLanguage Language
        {
            get 
            {
                return _language; 
            } 
        }
 
        internal string Name
        {
            get
            { 
                return _name;
            } 
        } 

        internal int OriginalLCID 
        {
            get
            {
                return _originalLCID; 
            }
        } 
 
        internal static IComparer NameComparer
        { 
            get
            {
                return _nameComparer;
            } 
        }
 
        internal static IComparer LanguageComparer 
        {
            get 
            {
                return _languageComparer;
            }
        } 

        private class NameComparerClass : IComparer 
        { 
            #region IComparer Members
 
            int IComparer.Compare(LocalizedName x, LocalizedName y)
            {
                return Util.CompareOrdinalIgnoreCase(x._name, y._name);
            } 

            #endregion 
        } 

        private class LanguageComparerClass : IComparer 
        {
            #region IComparer Members

            int IComparer.Compare(LocalizedName x, LocalizedName y) 
            {
                return String.Compare(x._language.IetfLanguageTag, y._language.IetfLanguageTag, StringComparison.OrdinalIgnoreCase); 
            } 

            #endregion 
        }

        private XmlLanguage _language;  // the language identifier
        private string      _name;      // name converted to Unicode 
        private int         _originalLCID; // original LCID, used in cases when we want to preserve it to avoid information loss
 
        private static NameComparerClass _nameComparer = new NameComparerClass(); 
        private static LanguageComparerClass _languageComparer = new LanguageComparerClass();
    } 
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK