summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Resources/ResourceSet.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Resources/ResourceSet.cs')
-rw-r--r--src/mscorlib/src/System/Resources/ResourceSet.cs331
1 files changed, 331 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Resources/ResourceSet.cs b/src/mscorlib/src/System/Resources/ResourceSet.cs
new file mode 100644
index 0000000000..b135f2817e
--- /dev/null
+++ b/src/mscorlib/src/System/Resources/ResourceSet.cs
@@ -0,0 +1,331 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*============================================================
+**
+**
+**
+**
+**
+** 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
+ 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 a race condition 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];
+ }
+ }
+}