|
//-----------------------------------------------------------------------------
//
// <copyright file="ResourcePart.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved.
// </copyright>
//
// Description:
// ResourcePart is an implementation of the abstract PackagePart class. It contains an override for GetStreamCore.
//
// History:
// 10/04/2004: Microsoft: Initial creation.
//
//-----------------------------------------------------------------------------
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
/// <SecurityNote>
/// Critical - because _rmWrapper, which is being set, is marked SecurityCriticalDataForSet.
/// </SecurityNote>
[SecurityCritical]
public ResourcePart(Package container, Uri uri, string name, ResourceManagerWrapper rmWrapper) :
base(container, uri)
{
if (rmWrapper == null)
{
throw new ArgumentNullException("rmWrapper");
}
_rmWrapper.Value = rmWrapper;
_name = name;
}
#endregion
//------------------------------------------------------
//
// Protected Methods
//
//------------------------------------------------------
#region Protected Methods
/// <SecurityNote>
/// Critical - because creating a BamlStream is critical as it stores the assembly
/// passed in to it the _assembly field, and this field is used by the
/// BamlRecordReader to allow legitimate internal types in Partial Trust.
/// Safe - because the _rmWrapper from which the assembly is obtained is SecurityCriticalDataForSet,
/// and setting that when a ResourcePart is constructed is treated as safe by
/// ResourceContainer.GetPartCore(). The _rmWrapper is trated as safe as it guarantees
/// that any stream created by it is always from the assembly that it also holds on to.
/// So to the BamlRecordReader, this Assembly that it uses is always guaranteed to be
/// the one from which the baml stream that it reads, was created from.
/// </SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
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.Value.GetStream(_name);
if (stream == null)
{
throw new IOException(SR.Get(SRID.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.Value.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.Compare(Path.GetExtension(_name), ResourceContainer.BamlExt, StringComparison.OrdinalIgnoreCase) == 0)
{
throw new IOException(SR.Get(SRID.UnableToLocateResource, _name));
}
if (String.Compare(Path.GetExtension(_name), ResourceContainer.XamlExt, StringComparison.OrdinalIgnoreCase) == 0)
{
// 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.Value.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 SecurityCriticalDataForSet<ResourceManagerWrapper> _rmWrapper;
private bool _ensureResourceIsCalled = false;
private string _name;
private Object _globalLock = new Object();
#endregion Private Members
}
}
|