RuntimeResourceSet.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / clr / src / BCL / System / Resources / RuntimeResourceSet.cs / 3 / RuntimeResourceSet.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  RuntimeResourceSet 
**
** 
** 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;
 
    // 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


 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

 
 

 



 

    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 _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 _caseInsensitiveTable;
 
        // If we're not using our custom reader, then enumerate through all
        // the resources once, adding them into the table.
        private bool _haveReadFromReader;
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        internal RuntimeResourceSet(String fileName) : base(false) 
        {
            BCLDebug.Log("RESMGRFILEFORMAT", "RuntimeResourceSet .ctor(String)"); 
            _resCache = new Dictionary(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)
#else 
        internal RuntimeResourceSet(Stream stream) : base(false)
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
        {
            BCLDebug.Log("RESMGRFILEFORMAT", "RuntimeResourceSet .ctor(Stream)"); 
            _resCache = new Dictionary(FastResourceComparer.Default);
            _defaultReader = new ResourceReader(stream, _resCache); 
            Reader = _defaultReader; 
#if LOOSELY_LINKED_RESOURCE_REFERENCE
            Assembly = assembly; 
#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 
                _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"));
 
            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) {
                        BCLDebug.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 ----Ref = (LooselyLinkedResourceReference) value;
                            value = ----Ref.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(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 {
                        BCLDebug.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 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 ----Ref = (LooselyLinkedResourceReference) value; 
                value = ----Ref.Resolve(Assembly);
            } 
#endif // LOOSELY_LINKED_RESOURCE_REFERENCE
            return value;
        }
    } 
}

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