FontSource.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 / FontSource.cs / 2 / FontSource.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Description: The FontSource class. 
//
// History: 
//  08/04/2003 : [....] - Created it 
//
//--------------------------------------------------------------------------- 

using System;
using System.Collections;
using System.ComponentModel; 
using System.Diagnostics;
using System.Globalization; 
using System.IO; 
using System.IO.Packaging;
using System.Net; 
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Windows; 
using System.Windows.Media;
using System.Windows.Threading; 
 
using MS.Win32;
using MS.Utility; 
using MS.Internal;
using MS.Internal.IO.Packaging;
using MS.Internal.PresentationCore;
 
namespace MS.Internal.FontCache
{ 
    ///  
    /// FontSource class encapsulates the logic for dealing with fonts in memory or on the disk.
    /// It may or may not have a Uri associated with it, but there has to be some way to obtain its contents. 
    /// 
    internal class FontSource
    {
        //----------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-----------------------------------------------------
 
        #region Constructors

        /// 
        /// Critical - fontUri can contain information about local file system, skipDemand is used to make security decisions. 
        /// 
        [SecurityCritical] 
        public FontSource(Uri fontUri, bool skipDemand) 
        {
            _fontUri = fontUri; 
            _skipDemand = skipDemand;

            Invariant.Assert(_fontUri.IsAbsoluteUri);
            Debug.Assert(String.IsNullOrEmpty(_fontUri.Fragment)); 
        }
 
        #endregion Constructors 

        //------------------------------------------------------ 
        //
        //  Internal Methods
        //
        //----------------------------------------------------- 

        #region Internal Methods 
 
        /// 
        /// Critical - as this gives out full file path. 
        /// 
        [SecurityCritical]
        public string GetUriString()
        { 
            return _fontUri.GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);
        } 
 
        /// 
        /// Critical - as this gives out full file path. 
        /// 
        [SecurityCritical]
        public string ToStringUpperInvariant()
        { 
            return GetUriString().ToUpperInvariant();
        } 
 
        /// 
        /// Critical - fontUri can contain information about local file system. 
        /// TreatAsSafe - we only compute its hash code.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        public override int GetHashCode() 
        {
            return HashFn.HashString(ToStringUpperInvariant(), 0); 
        } 

 
        /// 
        /// Critical - as this gives out full file path.
        /// 
        public Uri Uri 
        {
            [SecurityCritical] 
            get 
            {
                return _fontUri; 
            }
        }

        ///  
        /// Critical - fontUri can contain information about local file system.
        /// TreatAsSafe - we only return a flag that says whether the Uri is app specific. 
        ///  
        public bool IsAppSpecific
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                return Util.IsAppSpecificUri(_fontUri); 
            }
        } 
 
        internal long SkipLastWriteTime()
        { 
            // clients may choose to use this temporary method because GetLastWriteTime call
            // results in touching the file system
            // we need to resurrect this code when we come up with a complete solution
            // for updating fonts on the fly 
            return -1; // any non-zero value will do here
        } 
 
        /// 
        /// Critical - elevates to obtain the last write time for %windir%\fonts. 
        /// Also, fontUri can contain information about local file system.
        /// TreatAsSafe - we only use it to obtain the last write time.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal DateTime GetLastWriteTimeUtc()
        { 
            if (_fontUri.IsFile) 
            {
                bool revertAssert = false; 

                // Assert FileIORead permission for installed fonts.
                if (_skipDemand)
                { 
                    new FileIOPermission(FileIOPermissionAccess.Read, _fontUri.LocalPath).Assert(); //Blessed Assert
                    revertAssert = true; 
                } 

                try 
                {
                    return Directory.GetLastWriteTimeUtc(_fontUri.LocalPath);
                }
                finally 
                {
                    if (revertAssert) 
                        CodeAccessPermission.RevertAssert(); 
                }
            } 

            // Any special value will do here.
            return DateTime.MaxValue;
        } 

        ///  
        /// Critical - as this gives out UnmanagedMemoryStream content which is from a file. 
        /// 
        [SecurityCritical] 
        internal UnmanagedMemoryStream GetUnmanagedStream()
        {
            if (_fontUri.IsFile)
            { 
                FileMapping fileMapping = new FileMapping();
 
                DemandFileIOPermission(); 

                fileMapping.OpenFile(_fontUri.LocalPath); 
                return fileMapping;
            }

            byte[] bits; 
            // Try our cache first.
            lock (_resourceCache) 
            { 
                bits = _resourceCache.Get(_fontUri);
            } 

            if (bits == null)
            {
                WebResponse response = WpfWebRequestHelper.CreateRequestAndGetResponse(_fontUri); 
                Stream fontStream = response.GetResponseStream();
                if (String.Equals(response.ContentType, ObfuscatedContentType, StringComparison.Ordinal)) 
                { 
                    // The third parameter makes sure the original stream is closed
                    // when the deobfuscating stream is disposed. 
                    fontStream = new DeobfuscatingStream(fontStream, _fontUri, false);
                }

                UnmanagedMemoryStream unmanagedStream = fontStream as UnmanagedMemoryStream; 
                if (unmanagedStream != null)
                    return unmanagedStream; 
 
                bits = StreamToByteArray(fontStream);
 
                fontStream.Close();

                lock (_resourceCache)
                { 
                    _resourceCache.Add(_fontUri, bits, false);
                } 
            } 
            return ByteArrayToUnmanagedStream(bits);
        } 

        /// 
        /// Critical - as this gives out Stream content which is from a file.
        ///  
        [SecurityCritical]
        internal Stream GetStream() 
        { 
            if (_fontUri.IsFile)
            { 
                FileMapping fileMapping = new FileMapping();

                DemandFileIOPermission();
 
                fileMapping.OpenFile(_fontUri.LocalPath);
                return fileMapping; 
            } 

            byte[] bits; 

            // Try our cache first.
            lock (_resourceCache)
            { 
                bits = _resourceCache.Get(_fontUri);
            } 
 
            if (bits != null)
                return new MemoryStream(bits); 

            WebRequest request = PackWebRequestFactory.CreateWebRequest(_fontUri);
            WebResponse response = request.GetResponse();
 
            Stream fontStream = response.GetResponseStream();
            if (String.Equals(response.ContentType, ObfuscatedContentType, StringComparison.Ordinal)) 
            { 
                // The third parameter makes sure the original stream is closed
                // when the deobfuscating stream is disposed. 
                fontStream = new DeobfuscatingStream(fontStream, _fontUri, false);
            }
            return fontStream;
        } 

        #endregion Internal Methods 
 
        //------------------------------------------------------
        // 
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        private static UnmanagedMemoryStream ByteArrayToUnmanagedStream(byte[] bits) 
        {
            return new PinnedByteArrayStream(bits); 
        }

        private static byte [] StreamToByteArray(Stream fontStream)
        { 
            byte[] memoryFont;
 
            if (fontStream.CanSeek) 
            {
                checked 
                {
                    memoryFont = new byte[(int)fontStream.Length];
                    PackagingUtilities.ReliableRead(fontStream, memoryFont, 0, (int)fontStream.Length);
                } 
            }
            else 
            { 
                // this is inefficient, but works for now
                // we need to spend more time to implement a more performant 
                // version of this code
                // ideally this should be a part of loader functionality

                // Initial file read buffer size is set to 1MB. 
                int fileReadBufferSize = 1024 * 1024;
                byte[] fileReadBuffer = new byte[fileReadBufferSize]; 
 
                // Actual number of bytes read from the file.
                int memoryFontSize = 0; 

                for (; ; )
                {
                    int availableBytes = fileReadBufferSize - memoryFontSize; 
                    if (availableBytes < fileReadBufferSize / 3)
                    { 
                        // grow the fileReadBuffer 
                        fileReadBufferSize *= 2;
                        byte[] newBuffer = new byte[fileReadBufferSize]; 
                        Array.Copy(fileReadBuffer, newBuffer, memoryFontSize);
                        fileReadBuffer = newBuffer;
                        availableBytes = fileReadBufferSize - memoryFontSize;
                    } 
                    int numberOfBytesRead = fontStream.Read(fileReadBuffer, memoryFontSize, availableBytes);
                    if (numberOfBytesRead == 0) 
                        break; 

                    memoryFontSize += numberOfBytesRead; 
                }

                // Actual number of bytes read from the file is less or equal to the file read buffer size.
                Debug.Assert(memoryFontSize <= fileReadBufferSize); 

                if (memoryFontSize == fileReadBufferSize) 
                    memoryFont = fileReadBuffer; 
                else
                { 
                    // Trim the array if needed to that it contains the right length.
                    memoryFont = new byte[memoryFontSize];
                    Array.Copy(fileReadBuffer, memoryFont, memoryFontSize);
                } 
            }
 
            return memoryFont; 
        }
 
        /// 
        /// Demand read permissions for all fonts except system ones.
        /// 
        ///  
        ///     Critical - as this function calls critical WindowsFontsUriObject.
        ///     TreatAsSafe - as the WindowsFontsUriObject is used to determine whether to demand permissions. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void DemandFileIOPermission() 
        {
            // Demand FileIORead permission for any non-system fonts.
            if (!_skipDemand)
            { 
                SecurityHelper.DemandUriReadPermission(_fontUri);
            } 
        } 

        #endregion Private Methods 

        //-----------------------------------------------------
        //
        //  Private Classes 
        //
        //------------------------------------------------------ 
 
        #region Private Classes
 
        private class PinnedByteArrayStream : UnmanagedMemoryStream
        {
            /// 
            ///     Critical - as this function calls GCHandle.Alloc and UnmanagedMemoryStream.Initialize methods 
            ///         which cause an elevation.
            ///     TreatAsSafe - as this only pins and unpins an array of bytes. 
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            internal PinnedByteArrayStream(byte [] bits) 
            {
                _memoryHandle = GCHandle.Alloc(bits, GCHandleType.Pinned);

                unsafe 
                {
                    // Initialize() method demands UnmanagedCode permission, and PinnedByteArrayStream is already marked as critical. 
 
                    new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); //Blessed Assert
 
                    try
                    {
                        Initialize(
 	                        (byte *)_memoryHandle.AddrOfPinnedObject(), 
	                        bits.Length,
	                        bits.Length, 
	                        FileAccess.Read 
                        );
                    } 
                    finally
                    {
                        SecurityPermission.RevertAssert();
                    } 
                }
            } 
 
            ~PinnedByteArrayStream()
            { 
                Dispose(false);
            }

            ///  
            ///     Critical: This code calls into GCHandle.Free which is link demanded
            ///     TreatAsSafe: This code is ok to call. In the worst case it destroys some 
            ///     objects in the app 
            /// 
            [SecurityCritical,SecurityTreatAsSafe] 
            protected override void Dispose(bool disposing)
            {
                base.Dispose(disposing);
 
                Debug.Assert(_memoryHandle.IsAllocated);
                _memoryHandle.Free(); 
            } 

            private GCHandle    _memoryHandle; 
        }

        #endregion Private Classes
 
        //-----------------------------------------------------
        // 
        //  Private Fields 
        //
        //----------------------------------------------------- 

        #region Private Fields

        ///  
        /// Critical - fontUri can contain information about local file system.
        ///  
        [SecurityCritical] 
        private Uri     _fontUri;
 
        /// 
        /// Critical - determines whether the font source was constructed from internal data,
        /// in which case the permission demand should be skipped.
        ///  
        [SecurityCritical]
        private bool    _skipDemand; 
 
        private static SizeLimitedCache _resourceCache = new SizeLimitedCache(MaximumCacheItems);
 
        /// 
        /// The maximum number of fonts downloaded from pack:// Uris.
        /// 
        private const int MaximumCacheItems = 10; 
        private const string ObfuscatedContentType = "application/vnd.ms-package.obfuscated-opentype";
 
        #endregion Private Fields 
    }
} 

// 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