Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,143 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** <OWNER>[....]</OWNER>
**
** Class: FastResourceComparer
**
**
** Purpose: A collection of quick methods for comparing
** resource keys (strings)
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
internal sealed class FastResourceComparer : IComparer, IEqualityComparer, IComparer<String>, IEqualityComparer<String>
{
internal static readonly FastResourceComparer Default = new FastResourceComparer();
// Implements IHashCodeProvider too, due to Hashtable requirements.
public int GetHashCode(Object key)
{
String s = (String) key;
return FastResourceComparer.HashFunction(s);
}
public int GetHashCode(String key)
{
return FastResourceComparer.HashFunction(key);
}
// This hash function MUST be publically documented with the resource
// file format, AND we may NEVER change this hash function's return
// value (without changing the file format).
internal static int HashFunction(String key)
{
// Never change this hash function. We must standardize it so that
// others can read & write our .resources files. Additionally, we
// have a copy of it in InternalResGen as well.
uint hash = 5381;
for(int i=0; i<key.Length; i++)
hash = ((hash << 5) + hash) ^ key[i];
return (int) hash;
}
// Compares Strings quickly in a case-sensitive way
public int Compare(Object a, Object b)
{
if (a == b) return 0;
String sa = (String)a;
String sb = (String)b;
return String.CompareOrdinal(sa, sb);
}
public int Compare(String a, String b)
{
return String.CompareOrdinal(a, b);
}
public bool Equals(String a, String b)
{
return String.Equals(a, b);
}
public new bool Equals(Object a, Object b)
{
if (a == b) return true;
String sa = (String)a;
String sb = (String)b;
return String.Equals(sa,sb);
}
// Input is one string to compare with, and a byte[] containing chars in
// little endian unicode. Pass in the number of valid chars.
[System.Security.SecurityCritical] // auto-generated
public unsafe static int CompareOrdinal(String a, byte[] bytes, int bCharLength)
{
Contract.Assert(a != null && bytes != null, "FastResourceComparer::CompareOrdinal must have non-null params");
Contract.Assert(bCharLength * 2 <= bytes.Length, "FastResourceComparer::CompareOrdinal - numChars is too big!");
// This is a managed version of strcmp, but I can't take advantage
// of a terminating 0, unlike strcmp in C.
int i = 0;
int r = 0;
// Compare the min length # of characters, then return length diffs.
int numChars = a.Length;
if (numChars > bCharLength)
numChars = bCharLength;
if (bCharLength == 0) // Can't use fixed on a 0-element array.
return (a.Length == 0) ? 0 : -1;
fixed(byte* pb = bytes) {
byte *pChar = pb;
while (i < numChars && r == 0) {
// little endian format
int b = pChar[0] | pChar[1] << 8;
r = a[i++] - b;
pChar += sizeof(char);
}
}
if (r != 0) return r;
return a.Length - bCharLength;
}
[System.Security.SecurityCritical] // auto-generated
public static int CompareOrdinal(byte[] bytes, int aCharLength, String b)
{
return -CompareOrdinal(b, bytes, aCharLength);
}
// This method is to handle potentially misaligned data accesses.
// The byte* must point to little endian Unicode characters.
[System.Security.SecurityCritical] // auto-generated
internal unsafe static int CompareOrdinal(byte* a, int byteLen, String b)
{
Contract.Assert((byteLen & 1) == 0, "CompareOrdinal is expecting a UTF-16 string length, which must be even!");
Contract.Assert(a != null && b != null, "Null args not allowed.");
Contract.Assert(byteLen >= 0, "byteLen must be non-negative.");
int r = 0;
int i = 0;
// Compare the min length # of characters, then return length diffs.
int numChars = byteLen >> 1;
if (numChars > b.Length)
numChars = b.Length;
while(i < numChars && r == 0) {
// Must compare character by character, not byte by byte.
char aCh = (char) (*a++ | (*a++ << 8));
r = aCh - b[i++];
}
if (r != 0) return r;
return byteLen - b.Length * 2;
}
}
}

View File

@@ -0,0 +1,26 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//=============================================================================
//
// Class: __HResults
//
// <OWNER>[....]</OWNER>
//
// Purpose: Define HResult constants returned by the Windows Modern Resource Manager
// and consumed by System.Resources.ResourceManager.
//
//===========================================================================*/
#if !FEATURE_CORECLR
namespace System.Resources {
using System;
// Only static data no need to serialize
internal static class __HResults
{
// From WinError.h
public const int ERROR_MRM_MAP_NOT_FOUND = unchecked((int)0x80073B1F);
}
}
#endif //FEATURE_CORECLR

View File

@@ -0,0 +1,181 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: FileBasedResourceGroveler
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Searches for resources on disk, used for file-
** based resource lookup.
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Diagnostics.Contracts;
internal class FileBasedResourceGroveler : IResourceGroveler
{
private ResourceManager.ResourceManagerMediator _mediator;
public FileBasedResourceGroveler(ResourceManager.ResourceManagerMediator mediator)
{
Contract.Assert(mediator != null, "mediator shouldn't be null; check caller");
_mediator = mediator;
}
// Consider modifying IResourceGroveler interface (hence this method signature) when we figure out
// serialization compat story for moving ResourceManager members to either file-based or
// manifest-based classes. Want to continue tightening the design to get rid of unused params.
[System.Security.SecuritySafeCritical] // auto-generated
public ResourceSet GrovelForResourceSet(CultureInfo culture, Dictionary<String, ResourceSet> localResourceSets, bool tryParents, bool createIfNotExists, ref StackCrawlMark stackMark)
{
Contract.Assert(culture != null, "culture shouldn't be null; check caller");
String fileName = null;
ResourceSet rs = null;
// Don't use Assembly manifest, but grovel on disk for a file.
try
{
new System.Security.Permissions.FileIOPermission(System.Security.Permissions.PermissionState.Unrestricted).Assert();
// Create new ResourceSet, if a file exists on disk for it.
String tempFileName = _mediator.GetResourceFileName(culture);
fileName = FindResourceFile(culture, tempFileName);
if (fileName == null)
{
if (tryParents)
{
// If we've hit top of the Culture tree, return.
if (culture.HasInvariantCultureName)
{
// We really don't think this should happen - we always
// expect the neutral locale's resources to be present.
throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoNeutralDisk") + Environment.NewLine + "baseName: " + _mediator.BaseNameField + " locationInfo: " + (_mediator.LocationInfo == null ? "<null>" : _mediator.LocationInfo.FullName) + " fileName: " + _mediator.GetResourceFileName(culture));
}
}
}
else
{
rs = CreateResourceSet(fileName);
}
return rs;
}
finally
{
System.Security.CodeAccessPermission.RevertAssert();
}
}
#if !FEATURE_CORECLR // PAL doesn't support eventing, and we don't compile event providers for coreclr
public bool HasNeutralResources(CultureInfo culture, String defaultResName)
{
// Detect missing neutral locale resources.
String defaultResPath = FindResourceFile(culture, defaultResName);
if (defaultResPath == null || !File.Exists(defaultResPath))
{
String dir = _mediator.ModuleDir;
if (defaultResPath != null)
{
dir = Path.GetDirectoryName(defaultResPath);
}
return false;
}
return true;
}
#endif
// Given a CultureInfo, it generates the path &; file name for
// the .resources file for that CultureInfo. This method will grovel
// the disk looking for the correct file name & path. Uses CultureInfo's
// Name property. If the module directory was set in the ResourceManager
// constructor, we'll look there first. If it couldn't be found in the module
// diretory or the module dir wasn't provided, look in the current
// directory.
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
private String FindResourceFile(CultureInfo culture, String fileName)
{
Contract.Assert(culture != null, "culture shouldn't be null; check caller");
Contract.Assert(fileName != null, "fileName shouldn't be null; check caller");
// If we have a moduleDir, check there first. Get module fully
// qualified name, append path to that.
if (_mediator.ModuleDir != null)
{
#if _DEBUG
if (ResourceManager.DEBUG >= 3)
BCLDebug.Log("FindResourceFile: checking module dir: \""+_mediator.ModuleDir+'\"');
#endif
String path = Path.Combine(_mediator.ModuleDir, fileName);
if (File.Exists(path))
{
#if _DEBUG
if (ResourceManager.DEBUG >= 3)
BCLDebug.Log("Found resource file in module dir! "+path);
#endif
return path;
}
}
#if _DEBUG
if (ResourceManager.DEBUG >= 3)
BCLDebug.Log("Couldn't find resource file in module dir, checking .\\"+fileName);
#endif
// look in .
if (File.Exists(fileName))
return fileName;
return null; // give up.
}
// Constructs a new ResourceSet for a given file name. The logic in
// here avoids a ReflectionPermission check for our RuntimeResourceSet
// for perf and working set reasons.
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
private ResourceSet CreateResourceSet(String file)
{
Contract.Assert(file != null, "file shouldn't be null; check caller");
if (_mediator.UserResourceSet == null)
{
// Explicitly avoid CreateInstance if possible, because it
// requires ReflectionPermission to call private & protected
// constructors.
return new RuntimeResourceSet(file);
}
else
{
Object[] args = new Object[1];
args[0] = file;
try
{
return (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args);
}
catch (MissingMethodException e)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResMgrBadResSet_Type", _mediator.UserResourceSet.AssemblyQualifiedName), e);
}
}
}
}
}

View File

@@ -0,0 +1,34 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: IResourceGroveler
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Interface for resource grovelers
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.Globalization;
using System.Threading;
using System.Collections.Generic;
using System.Runtime.Versioning;
internal interface IResourceGroveler
{
ResourceSet GrovelForResourceSet(CultureInfo culture, Dictionary<String, ResourceSet> localResourceSets, bool tryParents,
bool createIfNotExists, ref StackCrawlMark stackMark);
#if !FEATURE_CORECLR // PAL doesn't support eventing, and we don't compile event providers for coreclr
bool HasNeutralResources(CultureInfo culture, String defaultResName);
#endif
}
}

View File

@@ -0,0 +1,33 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: IResourceReader
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Abstraction to read streams of resources.
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.IO;
using System.Collections;
[System.Runtime.InteropServices.ComVisible(true)]
public interface IResourceReader : IEnumerable, IDisposable
{
// Interface does not need to be marked with the serializable attribute
// Closes the ResourceReader, releasing any resources associated with it.
// This could close a network connection, a file, or do nothing.
void Close();
new IDictionaryEnumerator GetEnumerator();
}
}

View File

@@ -0,0 +1,47 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: IResourceWriter
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Default way to write strings to a COM+ resource
** file.
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.IO;
[System.Runtime.InteropServices.ComVisible(true)]
public interface IResourceWriter : IDisposable
{
// Interface does not need to be marked with the serializable attribute
// Adds a string resource to the list of resources to be written to a file.
// They aren't written until WriteFile() is called.
//
void AddResource(String name, String value);
// Adds a resource to the list of resources to be written to a file.
// They aren't written until WriteFile() is called.
//
void AddResource(String name, Object value);
// Adds a named byte array as a resource to the list of resources to
// be written to a file. They aren't written until WriteFile() is called.
//
void AddResource(String name, byte[] value);
// Closes the underlying resource file.
void Close();
// After calling AddResource, this writes all resources to the output
// stream. This does NOT close the output stream.
void Generate();
}
}

View File

@@ -0,0 +1,89 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: LooselyLinkedResourceReference
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Provides a localizable way of retrieving a file
** that is linked into your assembly and/or satellite assembly
** while also leaving the file on disk for unmanaged tools.
**
**
===========================================================*/
// Removing LooselyLinkedResourceReference from Whidbey. We don't
// yet have any strong customer need for it yet.
#if LOOSELY_LINKED_RESOURCE_REFERENCE
namespace System.Resources {
using System.Reflection;
using System.Diagnostics.Contracts;
using System.IO;
using System.Runtime.InteropServices;
using System.Globalization;
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public struct LooselyLinkedResourceReference {
private String _manifestResourceName;
private String _typeName;
public LooselyLinkedResourceReference(String looselyLinkedResourceName, String typeName)
{
if (looselyLinkedResourceName == null)
throw new ArgumentNullException("looselyLinkedResourceName");
if (typeName == null)
throw new ArgumentNullException("typeName");
if (looselyLinkedResourceName.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "looselyLinkedResourceName");
if (typeName.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "typeName");
Contract.EndContractBlock();
_manifestResourceName = looselyLinkedResourceName;
_typeName = typeName;
}
public String LooselyLinkedResourceName {
get { return _manifestResourceName; }
}
public String TypeName {
get { return _typeName; }
}
public Object Resolve(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
Contract.EndContractBlock();
// @
Stream data = assembly.GetManifestResourceStream(_manifestResourceName);
if (data == null)
throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_LooselyLinked", _manifestResourceName, assembly.FullName));
Type type = Type.GetType(_typeName, true);
Object obj = Activator.CreateInstance(type, new Object[] { data });
return obj;
}
// For good debugging with tools like ResView
public override String ToString()
{
// This is for debugging only. Since we use the property names,
// this does not need to be localized.
return "LooselyLinkedResourceName = \""+ _manifestResourceName +"\", TypeName = \"" + _typeName + "\"";
}
}
}
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: MissingManifestResourceException
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Exception for a missing assembly-level resource
**
**
===========================================================*/
using System;
using System.Runtime.Serialization;
namespace System.Resources {
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class MissingManifestResourceException : SystemException
{
public MissingManifestResourceException()
: base(Environment.GetResourceString("Arg_MissingManifestResourceException")) {
SetErrorCode(System.__HResults.COR_E_MISSINGMANIFESTRESOURCE);
}
public MissingManifestResourceException(String message)
: base(message) {
SetErrorCode(System.__HResults.COR_E_MISSINGMANIFESTRESOURCE);
}
public MissingManifestResourceException(String message, Exception inner)
: base(message, inner) {
SetErrorCode(System.__HResults.COR_E_MISSINGMANIFESTRESOURCE);
}
#if FEATURE_SERIALIZATION
protected MissingManifestResourceException(SerializationInfo info, StreamingContext context) : base (info, context) {
}
#endif // FEATURE_SERIALIZATION
}
}

View File

@@ -0,0 +1,60 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: MissingSatelliteAssemblyException
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Exception for a missing satellite assembly needed
** for ultimate resource fallback. This usually
** indicates a setup and/or deployment problem.
**
**
===========================================================*/
using System;
using System.Runtime.Serialization;
namespace System.Resources {
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class MissingSatelliteAssemblyException : SystemException
{
private String _cultureName;
public MissingSatelliteAssemblyException()
: base(Environment.GetResourceString("MissingSatelliteAssembly_Default")) {
SetErrorCode(System.__HResults.COR_E_MISSINGSATELLITEASSEMBLY);
}
public MissingSatelliteAssemblyException(String message)
: base(message) {
SetErrorCode(System.__HResults.COR_E_MISSINGSATELLITEASSEMBLY);
}
public MissingSatelliteAssemblyException(String message, String cultureName)
: base(message) {
SetErrorCode(System.__HResults.COR_E_MISSINGSATELLITEASSEMBLY);
_cultureName = cultureName;
}
public MissingSatelliteAssemblyException(String message, Exception inner)
: base(message, inner) {
SetErrorCode(System.__HResults.COR_E_MISSINGSATELLITEASSEMBLY);
}
#if FEATURE_SERIALIZATION
protected MissingSatelliteAssemblyException(SerializationInfo info, StreamingContext context) : base (info, context) {
}
#endif // FEATURE_SERIALIZATION
public String CultureName {
get { return _cultureName; }
}
}
}

View File

@@ -0,0 +1,67 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: NeutralResourcesLanguageAttribute
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Tells the ResourceManager what language your main
** assembly's resources are written in. The
** ResourceManager won't try loading a satellite
** assembly for that culture, which helps perf.
**
**
** NOTE:
**
** This custom attribute is no longer implemented in managed code. As part of a perf optimization,
** it is now read in Module::GetNeutralResourcesLanguage, accessed from ManifestBasedResourceGroveler
** through an internal runtime call.
===========================================================*/
namespace System.Resources {
using System;
using System.Diagnostics.Contracts;
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple=false)]
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class NeutralResourcesLanguageAttribute : Attribute
{
private String _culture;
private UltimateResourceFallbackLocation _fallbackLoc;
public NeutralResourcesLanguageAttribute(String cultureName)
{
if (cultureName == null)
throw new ArgumentNullException("cultureName");
Contract.EndContractBlock();
_culture = cultureName;
_fallbackLoc = UltimateResourceFallbackLocation.MainAssembly;
}
public NeutralResourcesLanguageAttribute(String cultureName, UltimateResourceFallbackLocation location)
{
if (cultureName == null)
throw new ArgumentNullException("cultureName");
if (!Enum.IsDefined(typeof(UltimateResourceFallbackLocation), location))
throw new ArgumentException(Environment.GetResourceString("Arg_InvalidNeutralResourcesLanguage_FallbackLoc", location));
Contract.EndContractBlock();
_culture = cultureName;
_fallbackLoc = location;
}
public String CultureName {
get { return _culture; }
}
public UltimateResourceFallbackLocation Location {
get { return _fallbackLoc; }
}
}
}

View File

@@ -0,0 +1,284 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: ResourceFallbackManager
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Encapsulates CultureInfo fallback for resource
** lookup
**
**
===========================================================*/
using System;
using System.Collections;
using System.Collections.Generic;
#if FEATURE_CORECLR
using System.Diagnostics.Contracts;
#endif
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace System.Resources
{
internal class ResourceFallbackManager : IEnumerable<CultureInfo>
{
private CultureInfo m_startingCulture;
private CultureInfo m_neutralResourcesCulture;
private bool m_useParents;
// Added but disabled from desktop in .NET 4.0, stayed disabled in .NET 4.5
#if FEATURE_CORECLR
// This is a cache of the thread, process, user, and OS-preferred fallback cultures.
// However, each thread may have a different value, and these may change during the
// lifetime of the process. So this cache must be verified each time we use it.
// Hence, we'll keep an array of strings for culture names & check it each time,
// but we'll really cache an array of CultureInfo's. Using thread-local statics
// as well to avoid differences across threads.
[ThreadStatic]
private static CultureInfo[] cachedOsFallbackArray;
#endif // FEATURE_CORECLR
internal ResourceFallbackManager(CultureInfo startingCulture, CultureInfo neutralResourcesCulture, bool useParents)
{
if (startingCulture != null)
{
m_startingCulture = startingCulture;
}
else
{
m_startingCulture = CultureInfo.CurrentUICulture;
}
m_neutralResourcesCulture = neutralResourcesCulture;
m_useParents = useParents;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
// WARING: This function must be kept in [....] with ResourceManager.GetFirstResourceSet()
public IEnumerator<CultureInfo> GetEnumerator()
{
bool reachedNeutralResourcesCulture = false;
// 1. starting culture chain, up to neutral
CultureInfo currentCulture = m_startingCulture;
do
{
if (m_neutralResourcesCulture != null && currentCulture.Name == m_neutralResourcesCulture.Name)
{
// Return the invariant culture all the time, even if the UltimateResourceFallbackLocation
// is a satellite assembly. This is fixed up later in ManifestBasedResourceGroveler::UltimateFallbackFixup.
yield return CultureInfo.InvariantCulture;
reachedNeutralResourcesCulture = true;
break;
}
yield return currentCulture;
currentCulture = currentCulture.Parent;
} while (m_useParents && !currentCulture.HasInvariantCultureName);
if (!m_useParents || m_startingCulture.HasInvariantCultureName)
{
yield break;
}
// Added but disabled from desktop in .NET 4.0, stayed disabled in .NET 4.5
#if FEATURE_CORECLR
#if FEATURE_LEGACYNETCF
if(!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
{
#endif // FEATURE_LEGACYNETCF
// 2. user preferred cultures, omitting starting culture if tried already
// Compat note: For console apps, this API will return cultures like Arabic
// or Hebrew that are displayed right-to-left. These don't work with today's
// CMD.exe. Since not all apps can short-circuit RTL languages to look at
// US English resources, we're exposing an appcompat flag for this, to make the
// osFallbackArray an empty array, mimicing our V2 behavior. Apps should instead
// be using CultureInfo.GetConsoleFallbackUICulture, and then test whether that
// culture's code page can be displayed on the console, and if not, they should
// set their culture to their neutral resources language.
// Note: the app compat switch will omit the OS Preferred fallback culture.
// Compat note 2: This feature breaks certain apps dependent on fallback to neutral
// resources. See extensive note in GetResourceFallbackArray.
CultureInfo[] osFallbackArray = LoadPreferredCultures();
if (osFallbackArray != null)
{
foreach (CultureInfo ci in osFallbackArray)
{
// only have to check starting culture and immediate parent for now.
// in Dev10, revisit this policy.
if (m_startingCulture.Name != ci.Name && m_startingCulture.Parent.Name != ci.Name)
{
yield return ci;
}
}
}
#if FEATURE_LEGACYNETCF
}
#endif // FEATURE_LEGACYNETCF
#endif // FEATURE_CORECLR
// 3. invariant
// Don't return invariant twice though.
if (reachedNeutralResourcesCulture)
yield break;
yield return CultureInfo.InvariantCulture;
}
// Added but disabled from desktop in .NET 4.0, stayed disabled in .NET 4.5
#if FEATURE_CORECLR
private static CultureInfo[] LoadPreferredCultures()
{
// The list of preferred cultures includes thread, process, user, and OS
// information and may theoretically change every time we call it.
// The caching does save us some allocations - this complexity saved about
// 7% of the wall clock time on a US English machine, and may save more on non-English
// boxes (since the fallback list may be longer).
String[] cultureNames = GetResourceFallbackArray();
if (cultureNames == null)
return null;
bool useCachedNames = (cachedOsFallbackArray != null && cultureNames.Length == cachedOsFallbackArray.Length);
if (useCachedNames)
{
for (int i = 0; i < cultureNames.Length; i++)
{
if (!String.Equals(cultureNames[i], cachedOsFallbackArray[i].Name))
{
useCachedNames = false;
break;
}
}
}
if (useCachedNames)
return cachedOsFallbackArray;
cachedOsFallbackArray = LoadCulturesFromNames(cultureNames);
return cachedOsFallbackArray;
}
private static CultureInfo[] LoadCulturesFromNames(String[] cultureNames)
{
if (cultureNames == null)
return null;
CultureInfo[] cultures = new CultureInfo[cultureNames.Length];
int culturesIndex = 0;
for (int i = 0; i < cultureNames.Length; i++)
{
// get cached, read-only cultures to avoid excess allocations
cultures[culturesIndex] = CultureInfo.GetCultureInfo(cultureNames[i]);
// Note GetCultureInfo can return null for a culture name that we don't support on the current OS.
// Don't leave a null in the middle of the array.
if (!Object.ReferenceEquals(cultures[culturesIndex], null))
culturesIndex++;
}
// If we couldn't create a culture, return an array of the right length.
if (culturesIndex != cultureNames.Length)
{
CultureInfo[] ret = new CultureInfo[culturesIndex];
Array.Copy(cultures, ret, culturesIndex);
cultures = ret;
}
return cultures;
}
// Note: May return null.
[System.Security.SecuritySafeCritical] // auto-generated
private static String[] GetResourceFallbackArray()
{
// AppCompat note: We've added this feature for desktop V4 but we ripped it out
// before shipping V4. It shipped in SL 2 and SL 3. We preserved this behavior in SL 4
// for compat with previous Silverlight releases. We considered re-introducing this in .NET
// 4.5 for Windows 8 but chose not to because the Windows 8 immersive resources model
// has been redesigned from the ground up and we chose to support it (for portable libraries
// only) instead of further enhancing support for the classic resources model.
// ---------------------------------------------------------------------
//
// We have an appcompat problem that prevents us from adopting the ideal MUI model for
// culture fallback. Up until .NET Framework v4, our fallback was this:
//
// CurrentUICulture & parents Neutral
//
// We also had applications that took a dependency on falling back to neutral resources.
// IE, say an app is developed by US English developers - they may include English resources
// in the main assembly, not ship an "en" satellite assembly, and ship a French satellite.
// They may also omit the NeutralResourcesLanguageAttribute.
//
// Starting with Silverlight v2 and following advice from the MUI team, we wanted to call
// the OS's GetThreadPreferredUILanguages, inserting the results like this:
//
// CurrentUICulture & parents user-preferred fallback OS-preferred fallback Neutral
//
// This does not fit well for two reasons:
// 1) There is no concept of neutral resources in MUI
// 2) The user-preferred culture fallbacks make no sense in servers & non-interactive apps
// This leads to bad results on certain combinations of OS language installations, user
// settings, and applications built in certain styles. The OS-preferred fallback should
// be last, and the user-preferred fallback just breaks certain apps no matter where you put it.
//
// Necessary and sufficient conditions for an AppCompat bug (if we respected user & OS fallbacks):
// 1) A French OS (ie, you walk into an Internet caf<61> in Paris)
// 2) A .NET application whose neutral resources are authored in English.
// 3) The application did not provide an English satellite assembly (a common pattern).
// 4) The application is localized to French.
// 5) The user wants to read English, expressed in either of two ways:
// a. Changing Windows<77> Display Language in the Regional Options Control Panel
// b. The application explicitly ASKS THE USER what language to display.
//
// Obviously the exact languages above can be interchanged a bit - I<>m keeping this concrete.
// Also the NeutralResourcesLanguageAttribute will allow this to work, but usually we set it
// to en-US for our assemblies, meaning all other English cultures are broken.
//
// Workarounds:
// *) Use the NeutralResourcesLanguageAttribute and tell us that your neutral resources
// are in region-neutral English (en).
// *) Consider shipping a region-neutral English satellite assembly.
// Future work:
// 2) Consider a mechanism for individual assemblies to opt into wanting user-preferred fallback.
// They should ship their neutral resources in a satellite assembly, or use the
// NeutralResourcesLanguageAttribute to say their neutral resources are in a REGION-NEUTRAL
// language. An appdomain or process-wide flag may not be sufficient.
// 3) Ask Windows to clarify the scenario for the OS preferred fallback list, to decide whether
// we should probe there before or after looking at the neutral resources. If we move it
// to after the neutral resources, ask Windows to return a user-preferred fallback list
// without the OS preferred fallback included. This is a feature request for
// GetThreadPreferredUILanguages. We can muddle through without it by removing the OS
// preferred fallback cultures from end of the combined user + OS preferred fallback list, carefully.
// 4) Do not look at user-preferred fallback if Environment.UserInteractive is false. (IE,
// the Windows user who launches ASP.NET shouldn't determine how a web page gets
// localized - the server itself must respect the remote client's requested languages.)
// 6) Figure out what should happen in servers (ASP.NET, SQL, NT Services, etc).
//
// Done:
// 1) Got data from Windows on priority of supporting OS preferred fallback. We need to do it.
// Helps with consistency w/ Windows, and may be necessary for a long tail of other languages
// (ie, Windows has various degrees of localization support for ~135 languages, and fallbacks
// to certain languages is important.)
// 5) Revisited guidance for using the NeutralResourcesLanguageAttribute. Our docs should now say
// always pick a region-neutral language (ie, "en").
return CultureInfo.nativeGetResourceFallbackArray();
}
#endif // FEATURE_CORECLR
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,336 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: ResourceSet
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Culture-specific collection of resources.
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.Collections;
using System.IO;
using System.Globalization;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
// A ResourceSet stores all the resources defined in one particular CultureInfo.
//
// The method used to load resources is straightforward - this class
// enumerates over an IResourceReader, loading every name and value, and
// stores them in a hash table. Custom IResourceReaders can be used.
//
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class ResourceSet : IDisposable, IEnumerable
{
[NonSerialized] protected IResourceReader Reader;
#if FEATURE_CORECLR
internal Hashtable Table;
#else
protected Hashtable Table;
#endif
private Hashtable _caseInsensitiveTable; // For case-insensitive lookups.
#if LOOSELY_LINKED_RESOURCE_REFERENCE
[OptionalField]
private Assembly _assembly; // For LooselyLinkedResourceReferences
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
protected ResourceSet()
{
// To not inconvenience people subclassing us, we should allocate a new
// hashtable here just so that Table is set to something.
CommonInit();
}
// For RuntimeResourceSet, ignore the Table parameter - it's a wasted
// allocation.
internal ResourceSet(bool junk)
{
}
// Creates a ResourceSet using the system default ResourceReader
// implementation. Use this constructor to open & read from a file
// on disk.
//
#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#endif
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public ResourceSet(String fileName)
{
Reader = new ResourceReader(fileName);
CommonInit();
ReadResources();
}
#if LOOSELY_LINKED_RESOURCE_REFERENCE
public ResourceSet(String fileName, Assembly assembly)
{
Reader = new ResourceReader(fileName);
CommonInit();
_assembly = assembly;
ReadResources();
}
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
// Creates a ResourceSet using the system default ResourceReader
// implementation. Use this constructor to read from an open stream
// of data.
//
[System.Security.SecurityCritical] // auto-generated_required
public ResourceSet(Stream stream)
{
Reader = new ResourceReader(stream);
CommonInit();
ReadResources();
}
#if LOOSELY_LINKED_RESOURCE_REFERENCE
[System.Security.SecurityCritical] // auto_generated_required
public ResourceSet(Stream stream, Assembly assembly)
{
Reader = new ResourceReader(stream);
CommonInit();
_assembly = assembly;
ReadResources();
}
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
public ResourceSet(IResourceReader reader)
{
if (reader == null)
throw new ArgumentNullException("reader");
Contract.EndContractBlock();
Reader = reader;
CommonInit();
ReadResources();
}
#if LOOSELY_LINKED_RESOURCE_REFERENCE
public ResourceSet(IResourceReader reader, Assembly assembly)
{
if (reader == null)
throw new ArgumentNullException("reader");
Contract.EndContractBlock();
Reader = reader;
CommonInit();
_assembly = assembly;
ReadResources();
}
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
private void CommonInit()
{
Table = new Hashtable();
}
// Closes and releases any resources used by this ResourceSet, if any.
// All calls to methods on the ResourceSet after a call to close may
// fail. Close is guaranteed to be safely callable multiple times on a
// particular ResourceSet, and all subclasses must support these semantics.
public virtual void Close()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing) {
// Close the Reader in a thread-safe way.
IResourceReader copyOfReader = Reader;
Reader = null;
if (copyOfReader != null)
copyOfReader.Close();
}
Reader = null;
_caseInsensitiveTable = null;
Table = null;
}
public void Dispose()
{
Dispose(true);
}
#if LOOSELY_LINKED_RESOURCE_REFERENCE
// Optional - used for resolving assembly manifest resource references.
// This can safely be null.
[ComVisible(false)]
public Assembly Assembly {
get { return _assembly; }
/*protected*/ set { _assembly = value; }
}
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
// Returns the preferred IResourceReader class for this kind of ResourceSet.
// Subclasses of ResourceSet using their own Readers &; should override
// GetDefaultReader and GetDefaultWriter.
public virtual Type GetDefaultReader()
{
return typeof(ResourceReader);
}
#if !FEATURE_CORECLR
// Returns the preferred IResourceWriter class for this kind of ResourceSet.
// Subclasses of ResourceSet using their own Readers &; should override
// GetDefaultReader and GetDefaultWriter.
public virtual Type GetDefaultWriter()
{
return typeof(ResourceWriter);
}
#endif // !FEATURE_CORECLR
[ComVisible(false)]
public virtual IDictionaryEnumerator GetEnumerator()
{
return GetEnumeratorHelper();
}
/// <internalonly/>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumeratorHelper();
}
private IDictionaryEnumerator GetEnumeratorHelper()
{
Hashtable copyOfTable = Table; // Avoid a race with Dispose
if (copyOfTable == null)
throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
return copyOfTable.GetEnumerator();
}
// Look up a string value for a resource given its name.
//
public virtual String GetString(String name)
{
Object obj = GetObjectInternal(name);
try {
return (String)obj;
}
catch (InvalidCastException) {
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Name", name));
}
}
public virtual String GetString(String name, bool ignoreCase)
{
Object obj;
String s;
// Case-sensitive lookup
obj = GetObjectInternal(name);
try {
s = (String)obj;
}
catch (InvalidCastException) {
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Name", name));
}
// case-sensitive lookup succeeded
if (s != null || !ignoreCase) {
return s;
}
// Try doing a case-insensitive lookup
obj = GetCaseInsensitiveObjectInternal(name);
try {
return (String)obj;
}
catch (InvalidCastException) {
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Name", name));
}
}
// Look up an object value for a resource given its name.
//
public virtual Object GetObject(String name)
{
return GetObjectInternal(name);
}
public virtual Object GetObject(String name, bool ignoreCase)
{
Object obj = GetObjectInternal(name);
if (obj != null || !ignoreCase)
return obj;
return GetCaseInsensitiveObjectInternal(name);
}
protected virtual void ReadResources()
{
IDictionaryEnumerator en = Reader.GetEnumerator();
while (en.MoveNext()) {
Object value = en.Value;
#if LOOSELY_LINKED_RESOURCE_REFERENCE
if (Assembly != null && value is LooselyLinkedResourceReference) {
LooselyLinkedResourceReference assRef = (LooselyLinkedResourceReference) value;
value = assRef.Resolve(Assembly);
}
#endif //LOOSELYLINKEDRESOURCEREFERENCE
Table.Add(en.Key, value);
}
// While technically possible to close the Reader here, don't close it
// to help with some WinRes lifetime issues.
}
private Object GetObjectInternal(String name)
{
if (name == null)
throw new ArgumentNullException("name");
Contract.EndContractBlock();
Hashtable copyOfTable = Table; // Avoid a race with Dispose
if (copyOfTable == null)
throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
return copyOfTable[name];
}
private Object GetCaseInsensitiveObjectInternal(String name)
{
Hashtable copyOfTable = Table; // Avoid a race with Dispose
if (copyOfTable == null)
throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
Hashtable caseTable = _caseInsensitiveTable; // Avoid ---- with Close
if (caseTable == null)
{
caseTable = new Hashtable(StringComparer.OrdinalIgnoreCase);
#if _DEBUG
//Console.WriteLine("ResourceSet::GetObject loading up case-insensitive data");
BCLDebug.Perf(false, "Using case-insensitive lookups is bad perf-wise. Consider capitalizing "+name+" correctly in your source");
#endif
IDictionaryEnumerator en = copyOfTable.GetEnumerator();
while (en.MoveNext())
{
caseTable.Add(en.Key, en.Value);
}
_caseInsensitiveTable = caseTable;
}
return caseTable[name];
}
}
}

View File

@@ -0,0 +1,59 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: ResourceTypeCode
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Marker for types in .resources files
**
**
===========================================================*/
namespace System.Resources {
/* An internal implementation detail for .resources files, describing
what type an object is.
Ranges:
0 - 0x1F Primitives and reserved values
0x20 - 0x3F Specially recognized types, like byte[] and Streams
Note this data must be included in any documentation describing the
internals of .resources files.
*/
[Serializable]
internal enum ResourceTypeCode {
// Primitives
Null = 0,
String = 1,
Boolean = 2,
Char = 3,
Byte = 4,
SByte = 5,
Int16 = 6,
UInt16 = 7,
Int32 = 8,
UInt32 = 9,
Int64 = 0xa,
UInt64 = 0xb,
Single = 0xc,
Double = 0xd,
Decimal = 0xe,
DateTime = 0xf,
TimeSpan = 0x10,
// A meta-value - change this if you add new primitives
LastPrimitive = TimeSpan,
// Types with a special representation, like byte[] and Stream
ByteArray = 0x20,
Stream = 0x21,
// User types - serialized using the binary formatter.
StartOfUserTypes = 0x40
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,439 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: RuntimeResourceSet
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: CultureInfo-specific collection of resources.
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
// A RuntimeResourceSet stores all the resources defined in one
// particular CultureInfo, with some loading optimizations.
//
// It is expected that nearly all the runtime's users will be satisfied with the
// default resource file format, and it will be more efficient than most simple
// implementations. Users who would consider creating their own ResourceSets and/or
// ResourceReaders and ResourceWriters are people who have to interop with a
// legacy resource file format, are creating their own resource file format
// (using XML, for instance), or require doing resource lookups at runtime over
// the network. This group will hopefully be small, but all the infrastructure
// should be in place to let these users write & plug in their own tools.
//
// The Default Resource File Format
//
// The fundamental problems addressed by the resource file format are:
//
// * Versioning - A ResourceReader could in theory support many different
// file format revisions.
// * Storing intrinsic datatypes (ie, ints, Strings, DateTimes, etc) in a compact
// format
// * Support for user-defined classes - Accomplished using Serialization
// * Resource lookups should not require loading an entire resource file - If you
// look up a resource, we only load the value for that resource, minimizing working set.
//
//
// There are four sections to the default file format. The first
// is the Resource Manager header, which consists of a magic number
// that identifies this as a Resource file, and a ResourceSet class name.
// The class name is written here to allow users to provide their own
// implementation of a ResourceSet (and a matching ResourceReader) to
// control policy. If objects greater than a certain size or matching a
// certain naming scheme shouldn't be stored in memory, users can tweak that
// with their own subclass of ResourceSet.
//
// The second section in the system default file format is the
// RuntimeResourceSet specific header. This contains a version number for
// the .resources file, the number of resources in this file, the number of
// different types contained in the file, followed by a list of fully
// qualified type names. After this, we include an array of hash values for
// each resource name, then an array of virtual offsets into the name section
// of the file. The hashes allow us to do a binary search on an array of
// integers to find a resource name very quickly without doing many string
// compares (except for once we find the real type, of course). If a hash
// matches, the index into the array of hash values is used as the index
// into the name position array to find the name of the resource. The type
// table allows us to read multiple different classes from the same file,
// including user-defined types, in a more efficient way than using
// Serialization, at least when your .resources file contains a reasonable
// proportion of base data types such as Strings or ints. We use
// Serialization for all the non-instrinsic types.
//
// The third section of the file is the name section. It contains a
// series of resource names, written out as byte-length prefixed little
// endian Unicode strings (UTF-16). After each name is a four byte virtual
// offset into the data section of the file, pointing to the relevant
// string or serialized blob for this resource name.
//
// The fourth section in the file is the data section, which consists
// of a type and a blob of bytes for each item in the file. The type is
// an integer index into the type table. The data is specific to that type,
// but may be a number written in binary format, a String, or a serialized
// Object.
//
// The system default file format (V1) is as follows:
//
// What Type of Data
// ==================================================== ===========
//
// Resource Manager header
// Magic Number (0xBEEFCACE) Int32
// Resource Manager header version Int32
// Num bytes to skip from here to get past this header Int32
// Class name of IResourceReader to parse this file String
// Class name of ResourceSet to parse this file String
//
// RuntimeResourceReader header
// ResourceReader version number Int32
// [Only in debug V2 builds - "***DEBUG***"] String
// Number of resources in the file Int32
// Number of types in the type table Int32
// Name of each type Set of Strings
// Padding bytes for 8-byte alignment (use PAD) Bytes (0-7)
// Hash values for each resource name Int32 array, sorted
// Virtual offset of each resource name Int32 array, coupled with hash values
// Absolute location of Data section Int32
//
// RuntimeResourceReader Name Section
// Name & virtual offset of each resource Set of (UTF-16 String, Int32) pairs
//
// RuntimeResourceReader Data Section
// Type and Value of each resource Set of (Int32, blob of bytes) pairs
//
// This implementation, when used with the default ResourceReader class,
// loads only the strings that you look up for. It can do string comparisons
// without having to create a new String instance due to some memory mapped
// file optimizations in the ResourceReader and FastResourceComparer
// classes. This keeps the memory we touch to a minimum when loading
// resources.
//
// If you use a different IResourceReader class to read a file, or if you
// do case-insensitive lookups (and the case-sensitive lookup fails) then
// we will load all the names of each resource and each resource value.
// This could probably use some optimization.
//
// In addition, this supports object serialization in a similar fashion.
// We build an array of class types contained in this file, and write it
// to RuntimeResourceReader header section of the file. Every resource
// will contain its type (as an index into the array of classes) with the data
// for that resource. We will use the Runtime's serialization support for this.
//
// All strings in the file format are written with BinaryReader and
// BinaryWriter, which writes out the length of the String in bytes as an
// Int32 then the contents as Unicode chars encoded in UTF-8. In the name
// table though, each resource name is written in UTF-16 so we can do a
// string compare byte by byte against the contents of the file, without
// allocating objects. Ideally we'd have a way of comparing UTF-8 bytes
// directly against a String object, but that may be a lot of work.
//
// The offsets of each resource string are relative to the beginning
// of the Data section of the file. This way, if a tool decided to add
// one resource to a file, it would only need to increment the number of
// resources, add the hash &amp; location of last byte in the name section
// to the array of resource hashes and resource name positions (carefully
// keeping these arrays sorted), add the name to the end of the name &amp;
// offset list, possibly add the type list of types types (and increase
// the number of items in the type table), and add the resource value at
// the end of the file. The other offsets wouldn't need to be updated to
// reflect the longer header section.
//
// Resource files are currently limited to 2 gigabytes due to these
// design parameters. A future version may raise the limit to 4 gigabytes
// by using unsigned integers, or may use negative numbers to load items
// out of an assembly manifest. Also, we may try sectioning the resource names
// into smaller chunks, each of size sqrt(n), would be substantially better for
// resource files containing thousands of resources.
//
internal sealed class RuntimeResourceSet : ResourceSet, IEnumerable
{
internal const int Version = 2; // File format version number
// Cache for resources. Key is the resource name, which can be cached
// for arbitrarily long times, since the object is usually a string
// literal that will live for the lifetime of the appdomain. The
// value is a ResourceLocator instance, which might cache the object.
private Dictionary<String, ResourceLocator> _resCache;
// For our special load-on-demand reader, cache the cast. The
// RuntimeResourceSet's implementation knows how to treat this reader specially.
private ResourceReader _defaultReader;
// This is a lookup table for case-insensitive lookups, and may be null.
// Consider always using a case-insensitive resource cache, as we don't
// want to fill this out if we can avoid it. The problem is resource
// fallback will somewhat regularly cause us to look up resources that
// don't exist.
private Dictionary<String, ResourceLocator> _caseInsensitiveTable;
// If we're not using our custom reader, then enumerate through all
// the resources once, adding them into the table.
private bool _haveReadFromReader;
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
internal RuntimeResourceSet(String fileName) : base(false)
{
BCLDebug.Log("RESMGRFILEFORMAT", "RuntimeResourceSet .ctor(String)");
_resCache = new Dictionary<String, ResourceLocator>(FastResourceComparer.Default);
Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
_defaultReader = new ResourceReader(stream, _resCache);
Reader = _defaultReader;
}
#if LOOSELY_LINKED_RESOURCE_REFERENCE
internal RuntimeResourceSet(Stream stream, Assembly assembly) : base(false)
{
BCLDebug.Log("RESMGRFILEFORMAT", "RuntimeResourceSet .ctor(Stream)");
_resCache = new Dictionary<String, ResourceLocator>(FastResourceComparer.Default);
_defaultReader = new ResourceReader(stream, _resCache);
Reader = _defaultReader;
Assembly = assembly;
}
#else
[System.Security.SecurityCritical] // auto-generated
internal RuntimeResourceSet(Stream stream) : base(false)
{
BCLDebug.Log("RESMGRFILEFORMAT", "RuntimeResourceSet .ctor(Stream)");
_resCache = new Dictionary<String, ResourceLocator>(FastResourceComparer.Default);
_defaultReader = new ResourceReader(stream, _resCache);
Reader = _defaultReader;
}
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
protected override void Dispose(bool disposing)
{
if (Reader == null)
return;
if (disposing) {
lock(Reader) {
_resCache = null;
if (_defaultReader != null) {
_defaultReader.Close();
_defaultReader = null;
}
_caseInsensitiveTable = null;
// Set Reader to null to avoid a race in GetObject.
base.Dispose(disposing);
}
}
else {
// Just to make sure we always clear these fields in the future...
_resCache = null;
_caseInsensitiveTable = null;
_defaultReader = null;
base.Dispose(disposing);
}
}
public override IDictionaryEnumerator GetEnumerator()
{
return GetEnumeratorHelper();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumeratorHelper();
}
private IDictionaryEnumerator GetEnumeratorHelper()
{
IResourceReader copyOfReader = Reader;
if (copyOfReader == null || _resCache == null)
throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
return copyOfReader.GetEnumerator();
}
public override String GetString(String key)
{
Object o = GetObject(key, false, true);
return (String) o;
}
public override String GetString(String key, bool ignoreCase)
{
Object o = GetObject(key, ignoreCase, true);
return (String) o;
}
public override Object GetObject(String key)
{
return GetObject(key, false, false);
}
public override Object GetObject(String key, bool ignoreCase)
{
return GetObject(key, ignoreCase, false);
}
private Object GetObject(String key, bool ignoreCase, bool isString)
{
if (key==null)
throw new ArgumentNullException("key");
if (Reader == null || _resCache == null)
throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
Contract.EndContractBlock();
Object value = null;
ResourceLocator resLocation;
lock(Reader) {
if (Reader == null)
throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
if (_defaultReader != null) {
BCLDebug.Log("RESMGRFILEFORMAT", "Going down fast path in RuntimeResourceSet::GetObject");
// Find the offset within the data section
int dataPos = -1;
if (_resCache.TryGetValue(key, out resLocation)) {
value = resLocation.Value;
dataPos = resLocation.DataPosition;
}
if (dataPos == -1 && value == null) {
dataPos = _defaultReader.FindPosForResource(key);
}
if (dataPos != -1 && value == null) {
Contract.Assert(dataPos >= 0, "data section offset cannot be negative!");
// Normally calling LoadString or LoadObject requires
// taking a lock. Note that in this case, we took a
// lock on the entire RuntimeResourceSet, which is
// sufficient since we never pass this ResourceReader
// to anyone else.
ResourceTypeCode typeCode;
if (isString) {
value = _defaultReader.LoadString(dataPos);
typeCode = ResourceTypeCode.String;
}
else {
value = _defaultReader.LoadObject(dataPos, out typeCode);
}
resLocation = new ResourceLocator(dataPos, (ResourceLocator.CanCache(typeCode)) ? value : null);
lock(_resCache) {
_resCache[key] = resLocation;
}
}
if (value != null || !ignoreCase) {
#if LOOSELY_LINKED_RESOURCE_REFERENCE
if (Assembly != null && (value is LooselyLinkedResourceReference)) {
LooselyLinkedResourceReference assRef = (LooselyLinkedResourceReference) value;
value = assRef.Resolve(Assembly);
}
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
return value; // may be null
}
} // if (_defaultReader != null)
// At this point, we either don't have our default resource reader
// or we haven't found the particular resource we're looking for
// and may have to search for it in a case-insensitive way.
if (!_haveReadFromReader) {
// If necessary, init our case insensitive hash table.
if (ignoreCase && _caseInsensitiveTable == null) {
_caseInsensitiveTable = new Dictionary<String, ResourceLocator>(StringComparer.OrdinalIgnoreCase);
}
#if _DEBUG
BCLDebug.Perf(!ignoreCase, "Using case-insensitive lookups is bad perf-wise. Consider capitalizing "+key+" correctly in your source");
#endif
if (_defaultReader == null) {
IDictionaryEnumerator en = Reader.GetEnumerator();
while (en.MoveNext()) {
DictionaryEntry entry = en.Entry;
String readKey = (String) entry.Key;
ResourceLocator resLoc = new ResourceLocator(-1, entry.Value);
_resCache.Add(readKey, resLoc);
if (ignoreCase)
_caseInsensitiveTable.Add(readKey, resLoc);
}
// Only close the reader if it is NOT our default one,
// since we need it around to resolve ResourceLocators.
if (!ignoreCase)
Reader.Close();
}
else {
Contract.Assert(ignoreCase, "This should only happen for case-insensitive lookups");
ResourceReader.ResourceEnumerator en = _defaultReader.GetEnumeratorInternal();
while (en.MoveNext()) {
// Note: Always ask for the resource key before the data position.
String currentKey = (String) en.Key;
int dataPos = en.DataPosition;
ResourceLocator resLoc = new ResourceLocator(dataPos, null);
_caseInsensitiveTable.Add(currentKey, resLoc);
}
}
_haveReadFromReader = true;
}
Object obj = null;
bool found = false;
bool keyInWrongCase = false;
if (_defaultReader != null) {
if (_resCache.TryGetValue(key, out resLocation)) {
found = true;
obj = ResolveResourceLocator(resLocation, key, _resCache, keyInWrongCase);
}
}
if (!found && ignoreCase) {
if (_caseInsensitiveTable.TryGetValue(key, out resLocation)) {
found = true;
keyInWrongCase = true;
obj = ResolveResourceLocator(resLocation, key, _resCache, keyInWrongCase);
}
}
return obj;
} // lock(Reader)
}
// The last parameter indicates whether the lookup required a
// case-insensitive lookup to succeed, indicating we shouldn't add
// the ResourceLocation to our case-sensitive cache.
private Object ResolveResourceLocator(ResourceLocator resLocation, String key, Dictionary<String, ResourceLocator> copyOfCache, bool keyInWrongCase)
{
// We need to explicitly resolve loosely linked manifest
// resources, and we need to resolve ResourceLocators with null objects.
Object value = resLocation.Value;
if (value == null) {
ResourceTypeCode typeCode;
lock(Reader) {
value = _defaultReader.LoadObject(resLocation.DataPosition, out typeCode);
}
if (!keyInWrongCase && ResourceLocator.CanCache(typeCode)) {
resLocation.Value = value;
copyOfCache[key] = resLocation;
}
}
#if LOOSELY_LINKED_RESOURCE_REFERENCE
if (Assembly != null && value is LooselyLinkedResourceReference) {
LooselyLinkedResourceReference assRef = (LooselyLinkedResourceReference) value;
value = assRef.Resolve(Assembly);
}
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
return value;
}
}
}

View File

@@ -0,0 +1,41 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: SatelliteContractVersionAttribute
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Specifies which version of a satellite assembly
** the ResourceManager should ask for.
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.Diagnostics.Contracts;
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple=false)]
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class SatelliteContractVersionAttribute : Attribute
{
private String _version;
public SatelliteContractVersionAttribute(String version)
{
if (version == null)
throw new ArgumentNullException("version");
Contract.EndContractBlock();
_version = version;
}
public String Version {
get { return _version; }
}
}
}

View File

@@ -0,0 +1,32 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Enum: UltimateResourceFallbackLocation
**
** <OWNER>[....]</OWNER>
**
** <EMAIL>Author: Brian Grunkemeyer ([....])</EMAIL>
**
** Purpose: Tells the ResourceManager where to find the
** ultimate fallback resources for your assembly.
**
** Date: August 21, 2003
**
===========================================================*/
using System;
namespace System.Resources {
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum UltimateResourceFallbackLocation
{
MainAssembly,
Satellite
}
}