File: MS\Internal\AppModel\ResourcePart.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
//
//
// Description:
// ResourcePart is an implementation of the abstract PackagePart class. It contains an override for GetStreamCore.
//
 
using System;
using System.IO.Packaging;
using System.Windows;
using System.Windows.Resources;
using System.IO;
using System.Resources;
using System.Globalization;
using System.Security;
 
using MS.Internal.Resources;
using MS.Internal;
 
//In order to avoid generating warnings about unknown message numbers and 
//unknown pragmas when compiling your C# source code with the actual C# compiler, 
//you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
 
 
namespace MS.Internal.AppModel
{
    /// <summary>
    /// ResourcePart is an implementation of the abstract PackagePart class. It contains an override for GetStreamCore.
    /// </summary>
    internal class ResourcePart : System.IO.Packaging.PackagePart
    {
        //------------------------------------------------------
        //
        //  Public Constructors
        //
        //------------------------------------------------------
 
        #region Public Constructors
 
        public ResourcePart(Package container, Uri uri, string name, ResourceManagerWrapper rmWrapper) :
            base(container, uri)
        {
            if (rmWrapper == null)
            {
                throw new ArgumentNullException("rmWrapper");
            }
 
            _rmWrapper = rmWrapper;
            _name = name;
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Protected Methods
        //
        //------------------------------------------------------
 
        #region Protected Methods
 
        protected override Stream GetStreamCore(FileMode mode, FileAccess access)
        {
            Stream stream = null;
 
            stream = EnsureResourceLocationSet();
            // in order to find the resource we might have to open a stream.
            // rather than waste the stream it is returned here and we can use it.
            if (stream == null)
            {
                // Start looking for resources using the current ui culture.
                // The resource manager will fall back to invariant culture automatically.
                stream = _rmWrapper.GetStream(_name);
 
                if (stream == null)
                {
                    throw new IOException(SR.Format(SR.UnableToLocateResource, _name));
                }
            }
 
            // 
            // If this is a Baml stream, it will return BamlStream object, which contains
            // both raw stream and the host assembly.
            //
            ContentType curContent = new ContentType(ContentType);
 
            if (MimeTypeMapper.BamlMime.AreTypeAndSubTypeEqual(curContent))
            {
                BamlStream bamlStream = new BamlStream(stream, _rmWrapper.Assembly);
 
                stream = bamlStream;
            }
 
            return stream;
        }
 
        protected override string GetContentTypeCore()
        {
            EnsureResourceLocationSet();
 
            return MS.Internal.MimeTypeMapper.GetMimeTypeFromUri(new Uri(_name, UriKind.RelativeOrAbsolute)).ToString();
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        private Stream EnsureResourceLocationSet()
        {
            Stream stream = null;
 
            lock (_globalLock)
            {
                // only need to do this once
                if (_ensureResourceIsCalled)
                {
                    return null;
                }
                _ensureResourceIsCalled = true;
 
                try
                {
                    // We do not allow the use of .baml in any Avalon public APIs. This is the code pass needed to go through for loading baml file.
                    // Throw here we will catch all those cases.
                    if (string.Equals(Path.GetExtension(_name), ResourceContainer.BamlExt, StringComparison.OrdinalIgnoreCase))
                    {
                        throw new IOException(SR.Format(SR.UnableToLocateResource, _name));
                    }
 
                    if (string.Equals(Path.GetExtension(_name), ResourceContainer.XamlExt, StringComparison.OrdinalIgnoreCase))
                    {
                        // try baml extension first since it's our most common senario.
                        string newName = Path.ChangeExtension(_name, ResourceContainer.BamlExt);
 
                        // Get resource from resource manager wrapper.
                        stream = _rmWrapper.GetStream(newName);
                        if (stream != null)
                        {
                            // Remember that we have .baml for next time GetStreamCore is called.
                            _name = newName;
                            return stream;
                        }
                    }
                }
#pragma warning disable 6502 // PRESharp - Catch statements should not have empty bodies
                catch (System.Resources.MissingManifestResourceException)
                {
                    // When the main assembly doesn't contain any resource (all the resources must come from satellite assembly)
                    // then above GetStream( ) just throws exception. We should catch this exception here and let the code continue 
                    // to try with the original file name.
 
                    // If the main assembly does contain resource, but the resource with above _name does't exist, the above GetStream( )
                    // just returns null without exception.
                }
#pragma warning restore 6502
 
            }
 
            // Do not attempt to load the original file name here.  If the .baml does not exist or if this resource not
            // .xaml or .baml then we will follow the normal code path to attempt to load the stream using the original name.
 
            return null;
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Members
 
        private ResourceManagerWrapper _rmWrapper;
        private bool _ensureResourceIsCalled = false;
        private string _name;
        private readonly Object _globalLock = new Object();
 
        #endregion Private Members
    }
}