ResourceReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Resources / ResourceReader.cs / 1305376 / ResourceReader.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  ResourceReader 
**
** [....] 
**
**
** Purpose: Default way to read streams of resources on
** demand. 
**
**         Version 2 support on October 6, 2003 
** 
===========================================================*/
namespace System.Resources { 
    using System;
    using System.IO;
    using System.Text;
    using System.Collections; 
    using System.Collections.Generic;
#if FEATURE_SERIALIZATION 
    using System.Runtime.Serialization; 
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.Serialization.Formatters.Binary; 
#endif // FEATURE_SERIALIZATION
    using System.Reflection;
    using System.Security.Permissions;
    using System.Security; 
    using System.Globalization;
    using System.Configuration.Assemblies; 
    using System.Runtime.Versioning; 
    using System.Diagnostics.Contracts;
 
    // Provides the default implementation of IResourceReader, reading
    // .resources file from the system default binary format.  This class
    // can be treated as an enumerator once.
    // 
    // See the RuntimeResourceSet overview for details on the system
    // default file format. 
    // 

    internal struct ResourceLocator 
    {
        internal Object _value;  // Can be null.  Consider WeakReference instead?
        internal int _dataPos;
 
        internal ResourceLocator(int dataPos, Object value)
        { 
            _dataPos = dataPos; 
            _value = value;
        } 

        internal int DataPosition {
            get { return _dataPos; }
            //set { _dataPos = value; } 
        }
 
        // Allows adding in profiling data in a future version, or a special 
        // resource profiling build.  We could also use WeakReference.
        internal Object Value { 
            get { return _value; }
            set { _value = value; }
        }
 
        internal static bool CanCache(ResourceTypeCode value)
        { 
            Contract.Assert(value >= 0, "negative ResourceTypeCode.  What?"); 
            return value <= ResourceTypeCode.LastPrimitive;
        } 
    }


    [System.Runtime.InteropServices.ComVisible(true)] 
    public sealed class ResourceReader : IResourceReader
    { 
        // A reasonable default buffer size for reading from files, especially 
        // when we will likely be seeking frequently.  Could be smaller, but does
        // it make sense to use anything less than one page? 
        private const int DefaultFileStreamBufferSize = 4096;

        private BinaryReader _store;    // backing store we're reading from.
        // Used by RuntimeResourceSet and this class's enumerator.  Maps 
        // resource name to a value, a ResourceLocator, or a
        // LooselyLinkedManifestResource. 
        internal Dictionary _resCache; 
        private long _nameSectionOffset;  // Offset to name section of file.
        private long _dataSectionOffset;  // Offset to Data section of file. 

        // Note this class is tightly coupled with UnmanagedMemoryStream.
        // At runtime when getting an embedded resource from an assembly,
        // we're given an UnmanagedMemoryStream referring to the mmap'ed portion 
        // of the assembly.  The pointers here are pointers into that block of
        // memory controlled by the OS's loader. 
        private int[] _nameHashes;    // hash values for all names. 
        private unsafe int* _nameHashesPtr;  // In case we're using UnmanagedMemoryStream
        private int[] _namePositions; // relative locations of names 
        private unsafe int* _namePositionsPtr;  // If we're using UnmanagedMemoryStream
        private RuntimeType[] _typeTable;    // Lazy array of Types for resource values.
        private int[] _typeNamePositions;  // To delay initialize type table
#if FEATURE_SERIALIZATION 
        private BinaryFormatter _objFormatter; // Deserialization stuff.
#endif // FEATURE_SERIALIZATION 
        private int _numResources;    // Num of resources files, in case arrays aren't allocated. 

        // We'll include a separate code path that uses UnmanagedMemoryStream to 
        // avoid allocating String objects and the like.
        private UnmanagedMemoryStream _ums;

        // Version number of .resources file, for compatibility 
        private int _version;
 
#if RESOURCE_FILE_FORMAT_DEBUG 
        private bool _debug;   // Whether this file has debugging stuff in it.
#endif 

#if !FEATURE_PAL && FEATURE_SERIALIZATION
        private bool[] _safeToDeserialize; // Whether to assert serialization permission
        private TypeLimitingDeserializationBinder _typeLimitingBinder; 

        // One of our goals is to make sure localizable Windows Forms apps 
        // work in semi-trusted scenarios (ie, without serialization permission). 
        // Unfortunate we're serializing out some complex types that currently
        // require a security check on deserialization.  We may fix this 
        // in a next version, but for now just hard-code a list.
        // Hard-code in the assembly name (minus version) so people can't spoof us.
        private static readonly String[] TypesSafeForDeserialization = {
            "System.String[], mscorlib, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.DateTime[], mscorlib, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.Bitmap, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.Drawing.Imaging.Metafile, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.Drawing.Point, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.PointF, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.Drawing.Size, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.SizeF, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.Font, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.Icon, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.Drawing.Color, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Windows.Forms.Cursor, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken, 
            "System.Windows.Forms.Padding, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken, 
            "System.Windows.Forms.LinkArea, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken,
            "System.Windows.Forms.ImageListStreamer, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken, 
            "System.Windows.Forms.ListViewGroup, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken,
            "System.Windows.Forms.ListViewItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken,
            "System.Windows.Forms.TreeNode, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken
        }; 
#endif // !FEATURE_PAL && FEATURE_SERIALIZATION
 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public ResourceReader(String fileName)
        {
            _resCache = new Dictionary(FastResourceComparer.Default);
            _store = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize, FileOptions.RandomAccess), Encoding.UTF8); 
            BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(String).  UnmanagedMemoryStream: "+(_ums!=null));
 
            try { 
                ReadResources();
            } 
            catch {
                _store.Close(); // If we threw an exception, close the file.
                throw;
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public ResourceReader(Stream stream)
        { 
            if (stream==null)
                throw new ArgumentNullException("stream");
            if (!stream.CanRead)
                throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotReadable")); 
            Contract.EndContractBlock();
 
            _resCache = new Dictionary(FastResourceComparer.Default); 
            _store = new BinaryReader(stream, Encoding.UTF8);
            // We have a faster code path for reading resource files from an assembly. 
            _ums = stream as UnmanagedMemoryStream;

            BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(Stream).  UnmanagedMemoryStream: "+(_ums!=null));
            ReadResources(); 
        }
 
        // This is the constructor the RuntimeResourceSet calls, 
        // passing in the stream to read from and the RuntimeResourceSet's
        // internal hash table (hash table of names with file offsets 
        // and values, coupled to this ResourceReader).
        [System.Security.SecurityCritical]  // auto-generated
        internal ResourceReader(Stream stream, Dictionary resCache)
        { 
            Contract.Assert(stream != null, "Need a stream!");
            Contract.Assert(stream.CanRead, "Stream should be readable!"); 
            Contract.Assert(resCache != null, "Need a Dictionary!"); 

            _resCache = resCache; 
            _store = new BinaryReader(stream, Encoding.UTF8);

            _ums = stream as UnmanagedMemoryStream;
 
            BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(Stream, Hashtable).  UnmanagedMemoryStream: "+(_ums!=null));
            ReadResources(); 
        } 

 
        public void Close()
        {
            Dispose(true);
        } 

        public void Dispose() 
        { 
            Close();
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated
        private unsafe void Dispose(bool disposing)
        { 
            if (_store != null) {
                _resCache = null; 
                if (disposing) { 
                    // Close the stream in a thread-safe way.  This fix means
                    // that we may call Close n times, but that's safe. 
                    BinaryReader copyOfStore = _store;
                    _store = null;
                    if (copyOfStore != null)
                        copyOfStore.Close(); 
                }
                _store = null; 
                _namePositions = null; 
                _nameHashes = null;
                _ums = null; 
                _namePositionsPtr = null;
                _nameHashesPtr = null;
            }
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal static unsafe int ReadUnalignedI4(int* p) 
        {
            byte* buffer = (byte*)p; 
            // Unaligned, little endian format
            return buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
        }
 
        private void SkipInt32() {
            _store.BaseStream.Seek(4, SeekOrigin.Current); 
        } 

 
        private void SkipString() {
            int stringLength = _store.Read7BitEncodedInt();
            if (stringLength < 0) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_NegativeStringLength")); 
            }
            _store.BaseStream.Seek(stringLength, SeekOrigin.Current); 
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated 
        private unsafe int GetNameHash(int index)
        {
            Contract.Assert(index >=0 && index < _numResources, "Bad index into hash array.  index: "+index);
            Contract.Assert((_ums == null && _nameHashes != null && _nameHashesPtr == null) || 
                            (_ums != null && _nameHashes == null && _nameHashesPtr != null), "Internal state mangled.");
            if (_ums == null) 
                return _nameHashes[index]; 
            else
                return ReadUnalignedI4(&_nameHashesPtr[index]); 
        }

        [System.Security.SecuritySafeCritical]  // auto-generated
        private unsafe int GetNamePosition(int index) 
        {
            Contract.Assert(index >=0 && index < _numResources, "Bad index into name position array.  index: "+index); 
            Contract.Assert((_ums == null && _namePositions != null && _namePositionsPtr == null) || 
                            (_ums != null && _namePositions == null && _namePositionsPtr != null), "Internal state mangled.");
            int r; 
            if (_ums == null)
                r = _namePositions[index];
            else
                r = ReadUnalignedI4(&_namePositionsPtr[index]); 
            if (r < 0 || r > _dataSectionOffset - _nameSectionOffset) {
                throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesNameInvalidOffset", r)); 
            } 
            return r;
        } 

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator(); 
        }
 
        public IDictionaryEnumerator GetEnumerator() 
        {
            if (_resCache == null) 
                throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed"));
            return new ResourceEnumerator(this);
        }
 
        internal ResourceEnumerator GetEnumeratorInternal()
        { 
            return new ResourceEnumerator(this); 
        }
 
        // From a name, finds the associated virtual offset for the data.
        // To read the data, seek to _dataSectionOffset + dataPos, then
        // read the resource type & data.
        // This does a binary search through the names. 
        internal int FindPosForResource(String name)
        { 
            Contract.Assert(_store != null, "ResourceReader is closed!"); 
            int hash = FastResourceComparer.HashFunction(name);
            BCLDebug.Log("RESMGRFILEFORMAT", "FindPosForResource for "+name+"  hash: "+hash.ToString("x", CultureInfo.InvariantCulture)); 
            // Binary search over the hashes.  Use the _namePositions array to
            // determine where they exist in the underlying stream.
            int lo = 0;
            int hi = _numResources - 1; 
            int index = -1;
            bool success = false; 
            while (lo <= hi) { 
                index = (lo + hi) >> 1;
                // Do NOT use subtraction here, since it will wrap for large 
                // negative numbers.
                int currentHash = GetNameHash(index);
                int c;
                if (currentHash == hash) 
                    c = 0;
                else if (currentHash < hash) 
                    c = -1; 
                else
                    c = 1; 
                //BCLDebug.Log("RESMGRFILEFORMAT", "  Probing index "+index+"  lo: "+lo+"  hi: "+hi+"  c: "+c);
                if (c == 0) {
                    success = true;
                    break; 
                }
                if (c < 0) 
                    lo = index + 1; 
                else
                    hi = index - 1; 
            }
            if (!success) {
#if RESOURCE_FILE_FORMAT_DEBUG
                String lastReadString; 
                lock(this) {
                    _store.BaseStream.Seek(_nameSectionOffset + GetNamePosition(index), SeekOrigin.Begin); 
                    lastReadString = _store.ReadString(); 
                }
                BCLDebug.Log("RESMGRFILEFORMAT", LogLevel.Status, "FindPosForResource for ", name, " failed.  i: ", index, "  lo: ", lo, "  hi: ", hi, "  last read string: \"", lastReadString, '\''); 
#endif
                return -1;
            }
 
            // index is the location in our hash array that corresponds with a
            // value in the namePositions array. 
            // There could be collisions in our hash function.  Check on both sides 
            // of index to find the range of hash values that are equal to the
            // target hash value. 
            if (lo != index) {
                lo = index;
                while (lo > 0 && GetNameHash(lo - 1) == hash)
                    lo--; 
            }
            if (hi != index) { 
                hi = index; 
                while (hi < _numResources - 1 && GetNameHash(hi + 1) == hash)
                    hi++; 
            }

            lock(this) {
                for(int i = lo; i<=hi; i++) { 
                    _store.BaseStream.Seek(_nameSectionOffset + GetNamePosition(i), SeekOrigin.Begin);
                    if (CompareStringEqualsName(name)) { 
                        int dataPos = _store.ReadInt32(); 
                        if (dataPos < 0 || dataPos >= _store.BaseStream.Length - _dataSectionOffset) {
                            throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dataPos)); 
                        }
                        return dataPos;
                    }
                } 
            }
            BCLDebug.Log("RESMGRFILEFORMAT", "FindPosForResource for "+name+": Found a hash collision, HOWEVER, neither of these collided values equaled the given string."); 
            return -1; 
        }
 
        // This compares the String in the .resources file at the current position
        // with the string you pass in.
        // Whoever calls this method should make sure that they take a lock
        // so no one else can cause us to seek in the stream. 
        [System.Security.SecuritySafeCritical]  // auto-generated
        private unsafe bool CompareStringEqualsName(String name) 
        { 
            Contract.Assert(_store != null, "ResourceReader is closed!");
            int byteLen = _store.Read7BitEncodedInt(); 
            if (byteLen < 0) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_NegativeStringLength"));
            }
            if (_ums != null) { 
                byte* bytes = _ums.PositionPointer;
                // Skip over the data in the Stream, positioning ourselves right after it. 
                _ums.Seek(byteLen, SeekOrigin.Current); 
                if (_ums.Position > _ums.Length) {
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesNameTooLong")); 
                }

                // On 64-bit machines, these char*'s may be misaligned.  Use a
                // byte-by-byte comparison instead. 
                //return FastResourceComparer.CompareOrdinal((char*)bytes, byteLen/2, name) == 0;
                return FastResourceComparer.CompareOrdinal(bytes, byteLen, name) == 0; 
            } 
            else {
                // This code needs to be fast 
                byte[] bytes = new byte[byteLen];
                int numBytesToRead = byteLen;
                while(numBytesToRead > 0) {
                    int n = _store.Read(bytes, byteLen - numBytesToRead, numBytesToRead); 
                    if (n == 0)
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceNameCorrupted")); 
                    numBytesToRead -= n; 
                }
                return FastResourceComparer.CompareOrdinal(bytes, byteLen/2, name) == 0; 
            }
        }

        // This is used in the enumerator.  The enumerator iterates from 0 to n 
        // of our resources and this returns the resource name for a particular
        // index.  The parameter is NOT a virtual offset. 
        [System.Security.SecurityCritical]  // auto-generated 
        private unsafe String AllocateStringForNameIndex(int index, out int dataOffset)
        { 
            Contract.Assert(_store != null, "ResourceReader is closed!");
            byte[] bytes;
            int byteLen;
            long nameVA = GetNamePosition(index); 
            lock (this) {
                _store.BaseStream.Seek(nameVA + _nameSectionOffset, SeekOrigin.Begin); 
                // Can't use _store.ReadString, since it's using UTF-8! 
                byteLen = _store.Read7BitEncodedInt();
                if (byteLen < 0) { 
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_NegativeStringLength"));
                }

                if (_ums != null) { 
                    if (_ums.Position > _ums.Length - byteLen)
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesIndexTooLong", index)); 
 
                    String s = null;
                    char* charPtr = (char*)_ums.PositionPointer; 
#if IA64
                    if (((int)charPtr & 1) != 0) {
                        char[] destArray = new char[byteLen/2];
                        fixed(char* pDest = destArray) { 
                            Buffer.memcpyimpl((byte*)charPtr, (byte*)pDest, byteLen);
                        } 
                        s = new String(destArray); 
                    }
                    else { 
#endif //IA64
                    s = new String(charPtr, 0, byteLen/2);
#if IA64
                    } 
#endif //IA64
                    _ums.Position += byteLen; 
                    dataOffset = _store.ReadInt32(); 
                    if (dataOffset < 0 || dataOffset >= _store.BaseStream.Length - _dataSectionOffset) {
                        throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dataOffset)); 
                    }
                    return s;
                }
 
                bytes = new byte[byteLen];
                // We must read byteLen bytes, or we have a corrupted file. 
                // Use a blocking read in case the stream doesn't give us back 
                // everything immediately.
                int count = byteLen; 
                while(count > 0) {
                    int n = _store.Read(bytes, byteLen - count, count);
                    if (n == 0)
                        throw new EndOfStreamException(Environment.GetResourceString("BadImageFormat_ResourceNameCorrupted_NameIndex", index)); 
                    count -= n;
                } 
                dataOffset = _store.ReadInt32(); 
                if (dataOffset < 0 || dataOffset >= _store.BaseStream.Length - _dataSectionOffset) {
                    throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dataOffset)); 
                }
            }
            return Encoding.Unicode.GetString(bytes, 0, byteLen);
        } 

        // This is used in the enumerator.  The enumerator iterates from 0 to n 
        // of our resources and this returns the resource value for a particular 
        // index.  The parameter is NOT a virtual offset.
        [System.Security.SecuritySafeCritical]  // auto-generated 
        private Object GetValueForNameIndex(int index)
        {
            Contract.Assert(_store != null, "ResourceReader is closed!");
            long nameVA = GetNamePosition(index); 
            lock(this) {
                _store.BaseStream.Seek(nameVA + _nameSectionOffset, SeekOrigin.Begin); 
                SkipString(); 
                //BCLDebug.Log("RESMGRFILEFORMAT", "GetValueForNameIndex for index: "+index+"  skip (name length): "+skip);
                int dataPos = _store.ReadInt32(); 
                if (dataPos < 0 || dataPos >= _store.BaseStream.Length - _dataSectionOffset) {
                    throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dataPos));
                }
                BCLDebug.Log("RESMGRFILEFORMAT", "GetValueForNameIndex: dataPos: "+dataPos); 
                ResourceTypeCode junk;
                if (_version == 1) 
                    return LoadObjectV1(dataPos); 
                else
                    return LoadObjectV2(dataPos, out junk); 
            }
        }

        // This takes a virtual offset into the data section and reads a String 
        // from that location.
        // Anyone who calls LoadObject should make sure they take a lock so 
        // no one can cause us to do a seek in here. 
        [System.Security.SecuritySafeCritical]  // auto-generated
        internal String LoadString(int pos) 
        {
            Contract.Assert(_store != null, "ResourceReader is closed!");
            _store.BaseStream.Seek(_dataSectionOffset+pos, SeekOrigin.Begin);
            String s = null; 
            int typeIndex = _store.Read7BitEncodedInt();
            if (_version == 1) { 
                if (typeIndex == -1) 
                    return null;
                if (FindType(typeIndex) != typeof(String)) 
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Type", FindType(typeIndex).FullName));
                s = _store.ReadString();
            }
            else { 
                ResourceTypeCode typeCode = (ResourceTypeCode) typeIndex;
                if (typeCode != ResourceTypeCode.String && typeCode != ResourceTypeCode.Null) { 
                    String typeString; 
                    if (typeCode < ResourceTypeCode.StartOfUserTypes)
                        typeString = typeCode.ToString(); 
                    else
                        typeString = FindType(typeCode - ResourceTypeCode.StartOfUserTypes).FullName;
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Type", typeString));
                } 
                if (typeCode == ResourceTypeCode.String) // ignore Null
                    s = _store.ReadString(); 
            } 
            BCLDebug.Log("RESMGRFILEFORMAT", "LoadString("+pos.ToString("x", CultureInfo.InvariantCulture)+" returned "+(s==null ? "[a null string]" : s));
            return s; 
        }

        // Called from RuntimeResourceSet
        internal Object LoadObject(int pos) 
        {
            if (_version == 1) 
                return LoadObjectV1(pos); 
            ResourceTypeCode typeCode;
            return LoadObjectV2(pos, out typeCode); 
        }

        internal Object LoadObject(int pos, out ResourceTypeCode typeCode)
        { 
            if (_version == 1) {
                Object o = LoadObjectV1(pos); 
                typeCode = (o is String) ? ResourceTypeCode.String : ResourceTypeCode.StartOfUserTypes; 
                return o;
            } 
            return LoadObjectV2(pos, out typeCode);
        }

        // This takes a virtual offset into the data section and reads an Object 
        // from that location.
        // Anyone who calls LoadObject should make sure they take a lock so 
        // no one can cause us to do a seek in here. 
        internal Object LoadObjectV1(int pos)
        { 
            Contract.Assert(_store != null, "ResourceReader is closed!");
            Contract.Assert(_version == 1, ".resources file was not a V1 .resources file!");

            try { 
                // mega try-catch performs exceptionally bad on x64; factored out body into
                // _LoadObjectV1 and wrap here. 
                return _LoadObjectV1(pos); 
            }
            catch (EndOfStreamException eof) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch"), eof);
            }
            catch (ArgumentOutOfRangeException e) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch"), e); 
            }
        } 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        private Object _LoadObjectV1(int pos) { 
            _store.BaseStream.Seek(_dataSectionOffset+pos, SeekOrigin.Begin);
            int typeIndex = _store.Read7BitEncodedInt();
            if (typeIndex == -1)
                return null; 
            RuntimeType type = FindType(typeIndex);
            BCLDebug.Log("RESMGRFILEFORMAT", "LoadObject type: "+type.Name+"  pos: 0x"+_store.BaseStream.Position.ToString("x", CultureInfo.InvariantCulture)); 
            // Consider putting in logic to see if this type is a 
            // primitive or a value type first, so we can reach the
            // deserialization code faster for arbitrary objects. 

            if (type == typeof(String))
                return _store.ReadString();
            else if (type == typeof(Int32)) 
                return _store.ReadInt32();
            else if (type == typeof(Byte)) 
                return _store.ReadByte(); 
            else if (type == typeof(SByte))
                return _store.ReadSByte(); 
            else if (type == typeof(Int16))
                return _store.ReadInt16();
            else if (type == typeof(Int64))
                return _store.ReadInt64(); 
            else if (type == typeof(UInt16))
                return _store.ReadUInt16(); 
            else if (type == typeof(UInt32)) 
                return _store.ReadUInt32();
            else if (type == typeof(UInt64)) 
                return _store.ReadUInt64();
            else if (type == typeof(Single))
                return _store.ReadSingle();
            else if (type == typeof(Double)) 
                return _store.ReadDouble();
            else if (type == typeof(DateTime)) { 
                // Ideally we should use DateTime's ToBinary & FromBinary, 
                // but we can't for compatibility reasons.
                return new DateTime(_store.ReadInt64()); 
            }
            else if (type == typeof(TimeSpan))
                return new TimeSpan(_store.ReadInt64());
            else if (type == typeof(Decimal)) { 
                int[] bits = new int[4];
                for(int i=0; i= 2, ".resources file was not a V2 (or higher) .resources file!"); 

            try { 
                // mega try-catch performs exceptionally bad on x64; factored out body into 
                // _LoadObjectV2 and wrap here.
                return _LoadObjectV2(pos, out typeCode); 
            }
            catch (EndOfStreamException eof) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch"), eof);
            } 
            catch (ArgumentOutOfRangeException e) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch"), e); 
            } 
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        private Object _LoadObjectV2(int pos, out ResourceTypeCode typeCode) {
            _store.BaseStream.Seek(_dataSectionOffset+pos, SeekOrigin.Begin);
            typeCode = (ResourceTypeCode) _store.Read7BitEncodedInt(); 

            BCLDebug.Log("RESMGRFILEFORMAT", "LoadObjectV2 type: "+typeCode+"  pos: 0x"+_store.BaseStream.Position.ToString("x", CultureInfo.InvariantCulture)); 
 
            switch(typeCode) {
            case ResourceTypeCode.Null: 
                return null;

            case ResourceTypeCode.String:
                return _store.ReadString(); 

            case ResourceTypeCode.Boolean: 
                return _store.ReadBoolean(); 

            case ResourceTypeCode.Char: 
                return (char) _store.ReadUInt16();

            case ResourceTypeCode.Byte:
                return _store.ReadByte(); 

            case ResourceTypeCode.SByte: 
                return _store.ReadSByte(); 

            case ResourceTypeCode.Int16: 
                return _store.ReadInt16();

            case ResourceTypeCode.UInt16:
                return _store.ReadUInt16(); 

            case ResourceTypeCode.Int32: 
                return _store.ReadInt32(); 

            case ResourceTypeCode.UInt32: 
                return _store.ReadUInt32();

            case ResourceTypeCode.Int64:
                return _store.ReadInt64(); 

            case ResourceTypeCode.UInt64: 
                return _store.ReadUInt64(); 

            case ResourceTypeCode.Single: 
                return _store.ReadSingle();

            case ResourceTypeCode.Double:
                return _store.ReadDouble(); 

            case ResourceTypeCode.Decimal: 
                return _store.ReadDecimal(); 

            case ResourceTypeCode.DateTime: 
                // Use DateTime's ToBinary & FromBinary.
                Int64 data = _store.ReadInt64();
                return DateTime.FromBinary(data);
 
            case ResourceTypeCode.TimeSpan:
                Int64 ticks = _store.ReadInt64(); 
                return new TimeSpan(ticks); 

            // Special types 
            case ResourceTypeCode.ByteArray: {
                    int len = _store.ReadInt32();
                    if (len < 0) {
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len)); 
                    }
 
                            if (_ums == null) { 
                                if (len > _store.BaseStream.Length) {
                            throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len)); 
                                }
                        return _store.ReadBytes(len);
                            }
 
                    if (len > _ums.Length - _ums.Position) {
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len)); 
                    } 

                    byte[] bytes = new byte[len]; 
                    int r = _ums.Read(bytes, 0, len);
                    Contract.Assert(r == len, "ResourceReader needs to use a blocking read here.  (Call _store.ReadBytes(len)?)");
                    return bytes;
                } 

                    case ResourceTypeCode.Stream: { 
                    int len = _store.ReadInt32(); 
                    if (len < 0) {
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len)); 
                    }
                    if (_ums == null) {
                        byte[] bytes = _store.ReadBytes(len);
                        // Lifetime of memory == lifetime of this stream. 
                        return new PinnedBufferMemoryStream(bytes);
                    } 
 
                    // make sure we don't create an UnmanagedMemoryStream that is longer than the resource stream.
                    if (len > _ums.Length - _ums.Position) { 
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len));
                    }

                    // For the case that we've memory mapped in the .resources 
                    // file, just return a Stream pointing to that block of memory.
                    unsafe { 
                        return new UnmanagedMemoryStream(_ums.PositionPointer, len, len, FileAccess.Read, true); 
                    }
                } 

            default:
                if (typeCode < ResourceTypeCode.StartOfUserTypes) {
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch")); 
                }
                break; 
            } 

            // Normal serialized objects 
#if FEATURE_SERIALIZATION
            int typeIndex = typeCode - ResourceTypeCode.StartOfUserTypes;
            return DeserializeObject(typeIndex);
#else 
            throw new NotSupportedException(Environment.GetResourceString("NotSupported_ResourceObjectSerialization"));
#endif // FEATURE_SERIALIZATION 
        } 

 
#if FEATURE_SERIALIZATION
        // Helper method to safely deserialize a type, using a type-limiting
        // deserialization binder to simulate a type-limiting deserializer.
        // This method handles types that are safe to deserialize, as well as 
        // ensuring we only get back what we expect.
        [System.Security.SecurityCritical]  // auto-generated 
        private Object DeserializeObject(int typeIndex) 
        {
            RuntimeType type = FindType(typeIndex); 
#if !FEATURE_PAL
            // Initialize deserialization permission array, if needed
            if (_safeToDeserialize == null)
                InitSafeToDeserializeArray(); 
#endif // !FEATURE_PAL
 
            // Ensure that the object we deserialized is exactly the same 
            // type of object we thought we should be deserializing.  This
            // will help prevent hacked .resources files from using our 
            // serialization permission assert to deserialize anything
            // via a hacked type ID.

            Object graph; 
#if FEATURE_PAL
            graph = _objFormatter.Deserialize(_store.BaseStream); 
#else 
            if (_safeToDeserialize[typeIndex]) {
                // Don't assert serialization permission - just ask the binary 
                // formatter to avoid a permission check.  This ensures that any
                // types which do demand serialization permission in their
                // deserialization .cctors will fail.
                // Also, use a serialization binder to limit bind requests to 
                // our allowed list of [....] types.
                _objFormatter.Binder = _typeLimitingBinder; 
                _typeLimitingBinder.ExpectingToDeserialize(type); 
                graph = _objFormatter.UnsafeDeserialize(_store.BaseStream, null);
            } 
            else {
                _objFormatter.Binder = null;
                graph = _objFormatter.Deserialize(_store.BaseStream);
            } 
#endif // FEATURE_PAL
 
            // This check is about correctness, not security at this point. 
            if (graph.GetType() != type)
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResType&SerBlobMismatch", type.FullName, graph.GetType().FullName)); 

            return graph;
        }
#endif // FEATURE_SERIALIZATION 

        // Reads in the header information for a .resources file.  Verifies some 
        // of the assumptions about this resource set, and builds the class table 
        // for the default resource file format.
        [System.Security.SecurityCritical]  // auto-generated 
        private void ReadResources()
        {
            Contract.Assert(_store != null, "ResourceReader is closed!");
#if FEATURE_SERIALIZATION 
            BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File | StreamingContextStates.Persistence));
#if !FEATURE_PAL 
            _typeLimitingBinder = new TypeLimitingDeserializationBinder(); 
            bf.Binder = _typeLimitingBinder;
#endif 
            _objFormatter = bf;
#endif // FEATURE_SERIALIZATION

            try { 
                // mega try-catch performs exceptionally bad on x64; factored out body into
                // _ReadResources and wrap here. 
                _ReadResources(); 
            }
            catch (EndOfStreamException eof) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"), eof);
            }
            catch (IndexOutOfRangeException e) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"), e); 
            }
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        private void _ReadResources() 
        {
            // Read ResourceManager header
            // Check for magic number
            int magicNum = _store.ReadInt32(); 
            if (magicNum != ResourceManager.MagicNumber)
                throw new ArgumentException(Environment.GetResourceString("Resources_StreamNotValid")); 
            // Assuming this is ResourceManager header V1 or greater, hopefully 
            // after the version number there is a number of bytes to skip
            // to bypass the rest of the ResMgr header. For V2 or greater, we 
            // use this to skip to the end of the header
            int resMgrHeaderVersion = _store.ReadInt32();
            int numBytesToSkip = _store.ReadInt32();
            if (numBytesToSkip < 0 || resMgrHeaderVersion < 0) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
            } 
            if (resMgrHeaderVersion > 1) { 
                BCLDebug.Log("RESMGRFILEFORMAT", LogLevel.Status, "ReadResources: Unexpected ResMgr header version: {0}  Skipping ahead {1} bytes.", resMgrHeaderVersion, numBytesToSkip);
                _store.BaseStream.Seek(numBytesToSkip, SeekOrigin.Current); 
            }
            else {
                BCLDebug.Log("RESMGRFILEFORMAT", "ReadResources: Parsing ResMgr header v1.");
                // We don't care about numBytesToSkip; read the rest of the header 

                // Read in type name for a suitable ResourceReader 
                // Note ResourceWriter & InternalResGen use different Strings. 
                String readerType = _store.ReadString();
                AssemblyName mscorlib = new AssemblyName(ResourceManager.MscorlibName); 

                if (!ResourceManager.CompareNames(readerType, ResourceManager.ResReaderTypeName, mscorlib))
                    throw new NotSupportedException(Environment.GetResourceString("NotSupported_WrongResourceReader_Type", readerType));
 
                // Skip over type name for a suitable ResourceSet
                SkipString(); 
            } 

            // Read RuntimeResourceSet header 
            // Do file version check
            int version = _store.ReadInt32();
            if (version != RuntimeResourceSet.Version && version != 1)
                throw new ArgumentException(Environment.GetResourceString("Arg_ResourceFileUnsupportedVersion", RuntimeResourceSet.Version, version)); 
            _version = version;
 
#if RESOURCE_FILE_FORMAT_DEBUG 
            // Look for ***DEBUG*** to see if this is a debuggable file.
            long oldPos = _store.BaseStream.Position; 
            _debug = false;
            try {
                String debugString = _store.ReadString();
                _debug = String.Equals("***DEBUG***", debugString); 
            }
            catch(IOException) { 
            } 
            catch(OutOfMemoryException) {
            } 
            if (_debug) {
                Console.WriteLine("ResourceReader is looking at a debuggable .resources file, version {0}", _version);
            }
            else { 
                _store.BaseStream.Position = oldPos;
            } 
#endif 

            _numResources = _store.ReadInt32(); 
            if (_numResources < 0) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
            }
            BCLDebug.Log("RESMGRFILEFORMAT", "ReadResources: Expecting " + _numResources + " resources."); 
#if _DEBUG
            if (ResourceManager.DEBUG >= 4) 
                Console.WriteLine("ResourceReader::ReadResources - Reading in "+_numResources+" resources"); 
#endif
 
            // Read type positions into type positions array.
            // But delay initialize the type table.
            int numTypes = _store.ReadInt32();
            if (numTypes < 0) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
            } 
            _typeTable = new RuntimeType[numTypes]; 
            _typeNamePositions = new int[numTypes];
            for (int i=0; i= 5)
                    Console.WriteLine("ResourceReader::ReadResources - Reading in "+numTypes+" type table entries"); 
#endif

            // Prepare to read in the array of name hashes
            //  Note that the name hashes array is aligned to 8 bytes so 
            //  we can use pointers into it on 64 bit machines. (4 bytes
            //  may be sufficient, but let's plan for the future) 
            //  Skip over alignment stuff.  All public .resources files 
            //  should be aligned   No need to verify the byte values.
            long pos = _store.BaseStream.Position; 
            int alignBytes = ((int)pos) & 7;
            if (alignBytes != 0) {
                for (int i = 0; i < 8 - alignBytes; i++) {
                    _store.ReadByte(); 
                }
            } 
 
            // Read in the array of name hashes
#if RESOURCE_FILE_FORMAT_DEBUG 
                //  Skip over "HASHES->"
                if (_debug) {
                    _store.BaseStream.Position += 8;
                } 
#endif
 
            if (_ums == null) { 
                _nameHashes = new int[_numResources];
                for (int i = 0; i < _numResources; i++) { 
                    _nameHashes[i] = _store.ReadInt32();
                }
            }
            else { 
                int seekPos = unchecked(4 * _numResources);
                if (seekPos < 0) { 
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted")); 
                }
                unsafe { 
                    _nameHashesPtr = (int*)_ums.PositionPointer;
                    // Skip over the array of nameHashes.
                    _ums.Seek(seekPos, SeekOrigin.Current);
                    // get the position pointer once more to check that the whole table is within the stream 
                    byte* junk = _ums.PositionPointer;
                } 
            } 

            // Read in the array of relative positions for all the names. 
#if RESOURCE_FILE_FORMAT_DEBUG
            // Skip over "POS---->"
            if (_debug) {
                _store.BaseStream.Position += 8; 
            }
#endif 
            if (_ums == null) { 
                _namePositions = new int[_numResources];
                for (int i = 0; i < _numResources; i++) { 
                    int namePosition = _store.ReadInt32();
                    if (namePosition < 0) {
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
                    } 

                    _namePositions[i] = namePosition; 
                } 
            }
            else { 
                int seekPos = unchecked(4 * _numResources);
                if (seekPos < 0) {
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
                } 
                unsafe {
                    _namePositionsPtr = (int*)_ums.PositionPointer; 
                    // Skip over the array of namePositions. 
                    _ums.Seek(seekPos, SeekOrigin.Current);
                    // get the position pointer once more to check that the whole table is within the stream 
                    byte* junk = _ums.PositionPointer;
                }
            }
 
            // Read location of data section.
            _dataSectionOffset = _store.ReadInt32(); 
            if (_dataSectionOffset < 0) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
            } 

            // Store current location as start of name section
            _nameSectionOffset = _store.BaseStream.Position;
 
            // _nameSectionOffset should be <= _dataSectionOffset; if not, it's corrupt
            if (_dataSectionOffset < _nameSectionOffset) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted")); 
            }
 
            BCLDebug.Log("RESMGRFILEFORMAT", String.Format(CultureInfo.InvariantCulture, "ReadResources: _nameOffset = 0x{0:x}  _dataOffset = 0x{1:x}", _nameSectionOffset, _dataSectionOffset));
        }

        // This allows us to delay-initialize the Type[].  This might be a 
        // good startup time savings, since we might have to load assemblies
        // and initialize Reflection. 
        private RuntimeType FindType(int typeIndex) 
        {
            if (typeIndex < 0 || typeIndex >= _typeTable.Length) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_InvalidType"));
            }
            if (_typeTable[typeIndex] == null) {
                long oldPos = _store.BaseStream.Position; 
                try {
                    _store.BaseStream.Position = _typeNamePositions[typeIndex]; 
                    String typeName = _store.ReadString(); 
                    _typeTable[typeIndex] = (RuntimeType)Type.GetType(typeName, true);
                } 
#if !FEATURE_SERIALIZATION
                // If serialization isn't supported, we convert FileNotFoundException to
                // NotSupportedException for consistency with v2. This is a corner-case, but the
                // idea is that we want to give the user a more accurate error message. Even if 
                // the dependency were found, we know it will require serialization since it
                // can't be one of the types we special case. So if the dependency were found, 
                // it would go down the serialization code path, resulting in NotSupported for 
                // SKUs without serialization.
                // 
                // We don't want to regress the expected case by checking the type info before
                // getting to Type.GetType -- this is costly with v1 resource formats.
                catch (FileNotFoundException)
                { 
                    throw new NotSupportedException(Environment.GetResourceString("NotSupported_ResourceObjectSerialization"));
                } 
#endif // FEATURE_SERIALIZATION 
                finally {
                    _store.BaseStream.Position = oldPos; 
                }
            }
            Contract.Assert(_typeTable[typeIndex] != null, "Should have found a type!");
            return _typeTable[typeIndex]; 
        }
 
#if !FEATURE_PAL && FEATURE_SERIALIZATION 
        [System.Security.SecurityCritical]  // auto-generated
        private void InitSafeToDeserializeArray() 
        {
            _safeToDeserialize = new bool[_typeTable.Length];
            for(int i=0; i<_typeTable.Length; i++) {
                long oldPos = _store.BaseStream.Position; 
                String typeName;
                try { 
                    _store.BaseStream.Position = _typeNamePositions[i]; 
                    typeName = _store.ReadString();
                } 
                finally {
                    _store.BaseStream.Position = oldPos;
                }
 
                AssemblyName an;
                String typePart; 
                RuntimeType resourceType = (RuntimeType)Type.GetType(typeName, false); 
                if (resourceType == null) {
                    an = null; 
                    typePart = typeName;
                }
                else {
                    // Enums should be safe to deserialize, and this helps out 
                    // partially trusted, localized [....] apps.
                    if (resourceType.BaseType == typeof(Enum)) { 
                        _safeToDeserialize[i] = true; 
                        continue;
                    } 

                    // For most types, check our TypesSafeForDeserialization.
                    typePart = resourceType.FullName;
 
                    an = new AssemblyName();
 
                    // resourceType is retrieved via Type.GetType and must be a RuntimeType 
                    RuntimeAssembly a = (RuntimeAssembly)resourceType.Assembly;
                    an.Init(a.GetSimpleName(), 
                            a.GetPublicKey(),
                            null, // public key token
                            null, // version
                            a.GetLocale(), 
                            AssemblyHashAlgorithm.None,
                            AssemblyVersionCompatibility.SameMachine, 
                            null, // codebase 
                            AssemblyNameFlags.PublicKey,
                            null); // strong name key pair 
                }

                foreach(String safeType in TypesSafeForDeserialization) {
                    if (ResourceManager.CompareNames(safeType, typePart, an)) { 
#if _DEBUG
                        if (ResourceManager.DEBUG >= 7) 
                            Console.WriteLine("ResReader: Found a type-safe type to deserialize!  Type name: {0}", typeName); 
#endif
                        _safeToDeserialize[i] = true; 
                        continue;
                    }
                }
 
#if _DEBUG
                if (ResourceManager.DEBUG >= 7) 
                    if (!_safeToDeserialize[i]) 
                        Console.WriteLine("ResReader: Found a type that wasn't safe to deserialize: {0}", typeName);
#endif 
            }
        }
#endif // !FEATURE_PAL && FEATURE_SERIALIZATION
 
        public void GetResourceData(String resourceName, out String resourceType, out byte[] resourceData)
        { 
            if (resourceName == null) 
                throw new ArgumentNullException("resourceName");
            Contract.EndContractBlock(); 
            if (_resCache == null)
                throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed"));

            // Get the type information from the data section.  Also, 
            // sort all of the data section's indexes to compute length of
            // the serialized data for this type (making sure to subtract 
            // off the length of the type code). 
            int[] sortedDataPositions = new int[_numResources];
            int dataPos = FindPosForResource(resourceName); 
            if( dataPos == -1) {
                throw new ArgumentException(Environment.GetResourceString("Arg_ResourceNameNotExist", resourceName));
            }
 
            lock(this) {
                // Read all the positions of data within the data section. 
                for(int i=0; i<_numResources; i++) { 
                    _store.BaseStream.Position = _nameSectionOffset + GetNamePosition(i);
                    // Skip over name of resource 
                    int numBytesToSkip = _store.Read7BitEncodedInt();
                    if (numBytesToSkip < 0) {
                        throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesNameInvalidOffset", numBytesToSkip));
                    } 
                    _store.BaseStream.Position += numBytesToSkip;
 
                    int dPos = _store.ReadInt32(); 
                    if (dPos < 0 || dPos >= _store.BaseStream.Length - _dataSectionOffset) {
                        throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dPos)); 
                    }
                    sortedDataPositions[i] = dPos;
                }
                Array.Sort(sortedDataPositions); 

                int index = Array.BinarySearch(sortedDataPositions, dataPos); 
                Contract.Assert(index >= 0 && index < _numResources, "Couldn't find data position within sorted data positions array!"); 
                long nextData = (index < _numResources - 1) ? sortedDataPositions[index + 1] + _dataSectionOffset : _store.BaseStream.Length;
                int len = (int) (nextData - (dataPos + _dataSectionOffset)); 
                Contract.Assert(len >= 0 && len <= (int) _store.BaseStream.Length - dataPos + _dataSectionOffset, "Length was negative or outside the bounds of the file!");

                // Read type code then byte[]
                _store.BaseStream.Position = _dataSectionOffset + dataPos; 
                ResourceTypeCode typeCode = (ResourceTypeCode) _store.Read7BitEncodedInt();
                if (typeCode < 0 || typeCode >= ResourceTypeCode.StartOfUserTypes + _typeTable.Length) { 
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_InvalidType")); 
                }
                resourceType = TypeNameFromTypeCode(typeCode); 

                // The length must be adjusted to subtract off the number
                // of bytes in the 7 bit encoded type code.
                len -= (int) (_store.BaseStream.Position - (_dataSectionOffset + dataPos)); 
                byte[] bytes = _store.ReadBytes(len);
                if (bytes.Length != len) 
                    throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourceNameCorrupted")); 
                resourceData = bytes;
            } 
        }

        private String TypeNameFromTypeCode(ResourceTypeCode typeCode)
        { 
            Contract.Assert(typeCode >= 0, "can't be negative");
            if (typeCode < ResourceTypeCode.StartOfUserTypes) { 
                Contract.Assert(!String.Equals(typeCode.ToString(), "LastPrimitive"), "Change ResourceTypeCode metadata order so LastPrimitive isn't what Enum.ToString prefers."); 
                return "ResourceTypeCode." + typeCode.ToString();
            } 
            else {
                int typeIndex = typeCode - ResourceTypeCode.StartOfUserTypes;
                Contract.Assert(typeIndex >= 0 && typeIndex < _typeTable.Length, "TypeCode is broken or corrupted!");
                long oldPos = _store.BaseStream.Position; 
                try {
                    _store.BaseStream.Position = _typeNamePositions[typeIndex]; 
                    return _store.ReadString(); 
                }
                finally { 
                    _store.BaseStream.Position = oldPos;
                }
            }
        } 

#if !FEATURE_PAL && FEATURE_SERIALIZATION 
        // We need to build a type-limiting deserializer.  We know exactly which 
        // type we want to deserialize, and if someone tells us we have type X
        // (which might be safe to deserialize) and they give us a serialized 
        // form of type Y, we don't want to run the deserialization constructor
        // because we've asserted serialization formatter permission.  Instead,
        // limit the binary formatter's type binding to precisely the type we
        // expect.  If they ever don't match, that's a corrupt .resources file. 
        // We also must check the complete object graph to ensure all of the
        // graph contains safe objects. 
        // Note this is tightly coupled to the BinaryFormatter, since we use 
        // its internal ObjectReader::FastBindToType method, and we had to
        // change the ObjectReader to register itself with this type. 
        internal sealed class TypeLimitingDeserializationBinder : SerializationBinder
        {
            private RuntimeType _typeToDeserialize;
            // This is tightly coupled with the binary formatter, because we 
            // want to use exactly the same code found in the ObjectReader
            // to do the lookup, then just give a thumbs up or down based on 
            // a type equality comparison.  In the future, we could consider 
            // some better refactoring of this code.
            private ObjectReader _objectReader; 

            internal ObjectReader ObjectReader {
                get { return _objectReader; }
                set { _objectReader = value; } 
            }
 
            internal void ExpectingToDeserialize(RuntimeType type) 
            {
                _typeToDeserialize = type; 
            }

            [System.Security.SecuritySafeCritical] // overrides transparent public member
            public override Type BindToType(string assemblyName, string typeName) 
            {
                // BinaryObjectReader::Bind tries us first, then its own code. 
                // Returning null means let the default binding rules happen. 
                AssemblyName an = new AssemblyName(assemblyName);
 
                bool safe = false;
                foreach(String safeType in TypesSafeForDeserialization) {
                    if (ResourceManager.CompareNames(safeType, typeName, an)) {
                        safe = true; 
                        break;
                    } 
                } 

                // [....] types may internally use some enums that aren't 
                // on our safe to deserialize list, like Font using FontStyle.
                Type t = ObjectReader.FastBindToType(assemblyName, typeName);
                if (t.IsEnum)
                    safe = true; 

                if (safe) 
                    return null; 

                // Throw instead of returning null. 
                // If you're looking at this in a debugger, you've either
                // got a hacked .resources file on your hands, or [....]
                // types have taken a new dependency on another type.  Check
                // whether assemblyName & typeName refer to a trustworthy type, 
                // & consider adding it to the TypesSafeToDeserialize list.
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResType&SerBlobMismatch", _typeToDeserialize.FullName, typeName)); 
            } 
        }
#endif // !FEATURE_PAL && FEATURE_SERIALIZATION 


        internal sealed class ResourceEnumerator : IDictionaryEnumerator
        { 
            private const int ENUM_DONE = Int32.MinValue;
            private const int ENUM_NOT_STARTED = -1; 
 
            private ResourceReader _reader;
            private bool _currentIsValid; 
            private int _currentName;
            private int _dataPosition; // cached for case-insensitive table

            internal ResourceEnumerator(ResourceReader reader) 
            {
                _currentName = ENUM_NOT_STARTED; 
                _reader = reader; 
                _dataPosition = -2;
            } 

            public bool MoveNext()
            {
                if (_currentName == _reader._numResources - 1 || _currentName == ENUM_DONE) { 
                    _currentIsValid = false;
                    _currentName = ENUM_DONE; 
                    return false; 
                }
                _currentIsValid = true; 
                _currentName++;
                return true;
            }
 
            public Object Key {
                [System.Security.SecuritySafeCritical]  // auto-generated 
                get { 
                    if (_currentName == ENUM_DONE) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
                    if (!_currentIsValid) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); 
                    if (_reader._resCache == null) throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed"));

                    return _reader.AllocateStringForNameIndex(_currentName, out _dataPosition);
                } 
            }
 
            public Object Current { 
                get {
                    return Entry; 
                }
            }

            // Warning: This requires that you call the Key or Entry property FIRST before calling it! 
            internal int DataPosition {
                get { 
                    return _dataPosition; 
                }
            } 

            public DictionaryEntry Entry {
                [System.Security.SecuritySafeCritical]  // auto-generated
                get { 
                    if (_currentName == ENUM_DONE) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
                    if (!_currentIsValid) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); 
                    if (_reader._resCache == null) throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed")); 

                    String key; 
                    Object value = null;
                    lock (_reader._resCache) {
                        key = _reader.AllocateStringForNameIndex(_currentName, out _dataPosition);
                        ResourceLocator locator; 
                        if (_reader._resCache.TryGetValue(key, out locator)) {
                            value = locator.Value; 
                        } 
                        if (value == null) {
                            if (_dataPosition == -1) 
                                value = _reader.GetValueForNameIndex(_currentName);
                            else
                                value = _reader.LoadObject(_dataPosition);
                            // If enumeration and subsequent lookups happen very 
                            // frequently in the same process, add a ResourceLocator
                            // to _resCache here.  But [....] enumerates and 
                            // just about everyone else does lookups.  So caching 
                            // here may bloat working set.
                        } 
                    }
                    return new DictionaryEntry(key, value);
                }
            } 

            public Object Value { 
                get { 
                    if (_currentName == ENUM_DONE) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
                    if (!_currentIsValid) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); 
                    if (_reader._resCache == null) throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed"));

                    // Consider using _resCache here, eventually, if
                    // this proves to be an interesting perf scenario. 
                    // But mixing lookups and enumerators shouldn't be
                    // particularly compelling. 
                    return _reader.GetValueForNameIndex(_currentName); 
                }
            } 

            public void Reset()
            {
                if (_reader._resCache == null) throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed")); 
                _currentIsValid = false;
                _currentName = ENUM_NOT_STARTED; 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  ResourceReader 
**
** [....] 
**
**
** Purpose: Default way to read streams of resources on
** demand. 
**
**         Version 2 support on October 6, 2003 
** 
===========================================================*/
namespace System.Resources { 
    using System;
    using System.IO;
    using System.Text;
    using System.Collections; 
    using System.Collections.Generic;
#if FEATURE_SERIALIZATION 
    using System.Runtime.Serialization; 
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.Serialization.Formatters.Binary; 
#endif // FEATURE_SERIALIZATION
    using System.Reflection;
    using System.Security.Permissions;
    using System.Security; 
    using System.Globalization;
    using System.Configuration.Assemblies; 
    using System.Runtime.Versioning; 
    using System.Diagnostics.Contracts;
 
    // Provides the default implementation of IResourceReader, reading
    // .resources file from the system default binary format.  This class
    // can be treated as an enumerator once.
    // 
    // See the RuntimeResourceSet overview for details on the system
    // default file format. 
    // 

    internal struct ResourceLocator 
    {
        internal Object _value;  // Can be null.  Consider WeakReference instead?
        internal int _dataPos;
 
        internal ResourceLocator(int dataPos, Object value)
        { 
            _dataPos = dataPos; 
            _value = value;
        } 

        internal int DataPosition {
            get { return _dataPos; }
            //set { _dataPos = value; } 
        }
 
        // Allows adding in profiling data in a future version, or a special 
        // resource profiling build.  We could also use WeakReference.
        internal Object Value { 
            get { return _value; }
            set { _value = value; }
        }
 
        internal static bool CanCache(ResourceTypeCode value)
        { 
            Contract.Assert(value >= 0, "negative ResourceTypeCode.  What?"); 
            return value <= ResourceTypeCode.LastPrimitive;
        } 
    }


    [System.Runtime.InteropServices.ComVisible(true)] 
    public sealed class ResourceReader : IResourceReader
    { 
        // A reasonable default buffer size for reading from files, especially 
        // when we will likely be seeking frequently.  Could be smaller, but does
        // it make sense to use anything less than one page? 
        private const int DefaultFileStreamBufferSize = 4096;

        private BinaryReader _store;    // backing store we're reading from.
        // Used by RuntimeResourceSet and this class's enumerator.  Maps 
        // resource name to a value, a ResourceLocator, or a
        // LooselyLinkedManifestResource. 
        internal Dictionary _resCache; 
        private long _nameSectionOffset;  // Offset to name section of file.
        private long _dataSectionOffset;  // Offset to Data section of file. 

        // Note this class is tightly coupled with UnmanagedMemoryStream.
        // At runtime when getting an embedded resource from an assembly,
        // we're given an UnmanagedMemoryStream referring to the mmap'ed portion 
        // of the assembly.  The pointers here are pointers into that block of
        // memory controlled by the OS's loader. 
        private int[] _nameHashes;    // hash values for all names. 
        private unsafe int* _nameHashesPtr;  // In case we're using UnmanagedMemoryStream
        private int[] _namePositions; // relative locations of names 
        private unsafe int* _namePositionsPtr;  // If we're using UnmanagedMemoryStream
        private RuntimeType[] _typeTable;    // Lazy array of Types for resource values.
        private int[] _typeNamePositions;  // To delay initialize type table
#if FEATURE_SERIALIZATION 
        private BinaryFormatter _objFormatter; // Deserialization stuff.
#endif // FEATURE_SERIALIZATION 
        private int _numResources;    // Num of resources files, in case arrays aren't allocated. 

        // We'll include a separate code path that uses UnmanagedMemoryStream to 
        // avoid allocating String objects and the like.
        private UnmanagedMemoryStream _ums;

        // Version number of .resources file, for compatibility 
        private int _version;
 
#if RESOURCE_FILE_FORMAT_DEBUG 
        private bool _debug;   // Whether this file has debugging stuff in it.
#endif 

#if !FEATURE_PAL && FEATURE_SERIALIZATION
        private bool[] _safeToDeserialize; // Whether to assert serialization permission
        private TypeLimitingDeserializationBinder _typeLimitingBinder; 

        // One of our goals is to make sure localizable Windows Forms apps 
        // work in semi-trusted scenarios (ie, without serialization permission). 
        // Unfortunate we're serializing out some complex types that currently
        // require a security check on deserialization.  We may fix this 
        // in a next version, but for now just hard-code a list.
        // Hard-code in the assembly name (minus version) so people can't spoof us.
        private static readonly String[] TypesSafeForDeserialization = {
            "System.String[], mscorlib, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.DateTime[], mscorlib, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.Bitmap, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.Drawing.Imaging.Metafile, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.Drawing.Point, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.PointF, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.Drawing.Size, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.SizeF, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.Font, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Drawing.Icon, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken, 
            "System.Drawing.Color, System.Drawing, Culture=neutral, PublicKeyToken=" + AssemblyRef.MicrosoftPublicKeyToken,
            "System.Windows.Forms.Cursor, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken, 
            "System.Windows.Forms.Padding, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken, 
            "System.Windows.Forms.LinkArea, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken,
            "System.Windows.Forms.ImageListStreamer, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken, 
            "System.Windows.Forms.ListViewGroup, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken,
            "System.Windows.Forms.ListViewItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken,
            "System.Windows.Forms.TreeNode, System.Windows.Forms, Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken
        }; 
#endif // !FEATURE_PAL && FEATURE_SERIALIZATION
 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public ResourceReader(String fileName)
        {
            _resCache = new Dictionary(FastResourceComparer.Default);
            _store = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize, FileOptions.RandomAccess), Encoding.UTF8); 
            BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(String).  UnmanagedMemoryStream: "+(_ums!=null));
 
            try { 
                ReadResources();
            } 
            catch {
                _store.Close(); // If we threw an exception, close the file.
                throw;
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public ResourceReader(Stream stream)
        { 
            if (stream==null)
                throw new ArgumentNullException("stream");
            if (!stream.CanRead)
                throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotReadable")); 
            Contract.EndContractBlock();
 
            _resCache = new Dictionary(FastResourceComparer.Default); 
            _store = new BinaryReader(stream, Encoding.UTF8);
            // We have a faster code path for reading resource files from an assembly. 
            _ums = stream as UnmanagedMemoryStream;

            BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(Stream).  UnmanagedMemoryStream: "+(_ums!=null));
            ReadResources(); 
        }
 
        // This is the constructor the RuntimeResourceSet calls, 
        // passing in the stream to read from and the RuntimeResourceSet's
        // internal hash table (hash table of names with file offsets 
        // and values, coupled to this ResourceReader).
        [System.Security.SecurityCritical]  // auto-generated
        internal ResourceReader(Stream stream, Dictionary resCache)
        { 
            Contract.Assert(stream != null, "Need a stream!");
            Contract.Assert(stream.CanRead, "Stream should be readable!"); 
            Contract.Assert(resCache != null, "Need a Dictionary!"); 

            _resCache = resCache; 
            _store = new BinaryReader(stream, Encoding.UTF8);

            _ums = stream as UnmanagedMemoryStream;
 
            BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(Stream, Hashtable).  UnmanagedMemoryStream: "+(_ums!=null));
            ReadResources(); 
        } 

 
        public void Close()
        {
            Dispose(true);
        } 

        public void Dispose() 
        { 
            Close();
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated
        private unsafe void Dispose(bool disposing)
        { 
            if (_store != null) {
                _resCache = null; 
                if (disposing) { 
                    // Close the stream in a thread-safe way.  This fix means
                    // that we may call Close n times, but that's safe. 
                    BinaryReader copyOfStore = _store;
                    _store = null;
                    if (copyOfStore != null)
                        copyOfStore.Close(); 
                }
                _store = null; 
                _namePositions = null; 
                _nameHashes = null;
                _ums = null; 
                _namePositionsPtr = null;
                _nameHashesPtr = null;
            }
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal static unsafe int ReadUnalignedI4(int* p) 
        {
            byte* buffer = (byte*)p; 
            // Unaligned, little endian format
            return buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
        }
 
        private void SkipInt32() {
            _store.BaseStream.Seek(4, SeekOrigin.Current); 
        } 

 
        private void SkipString() {
            int stringLength = _store.Read7BitEncodedInt();
            if (stringLength < 0) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_NegativeStringLength")); 
            }
            _store.BaseStream.Seek(stringLength, SeekOrigin.Current); 
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated 
        private unsafe int GetNameHash(int index)
        {
            Contract.Assert(index >=0 && index < _numResources, "Bad index into hash array.  index: "+index);
            Contract.Assert((_ums == null && _nameHashes != null && _nameHashesPtr == null) || 
                            (_ums != null && _nameHashes == null && _nameHashesPtr != null), "Internal state mangled.");
            if (_ums == null) 
                return _nameHashes[index]; 
            else
                return ReadUnalignedI4(&_nameHashesPtr[index]); 
        }

        [System.Security.SecuritySafeCritical]  // auto-generated
        private unsafe int GetNamePosition(int index) 
        {
            Contract.Assert(index >=0 && index < _numResources, "Bad index into name position array.  index: "+index); 
            Contract.Assert((_ums == null && _namePositions != null && _namePositionsPtr == null) || 
                            (_ums != null && _namePositions == null && _namePositionsPtr != null), "Internal state mangled.");
            int r; 
            if (_ums == null)
                r = _namePositions[index];
            else
                r = ReadUnalignedI4(&_namePositionsPtr[index]); 
            if (r < 0 || r > _dataSectionOffset - _nameSectionOffset) {
                throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesNameInvalidOffset", r)); 
            } 
            return r;
        } 

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator(); 
        }
 
        public IDictionaryEnumerator GetEnumerator() 
        {
            if (_resCache == null) 
                throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed"));
            return new ResourceEnumerator(this);
        }
 
        internal ResourceEnumerator GetEnumeratorInternal()
        { 
            return new ResourceEnumerator(this); 
        }
 
        // From a name, finds the associated virtual offset for the data.
        // To read the data, seek to _dataSectionOffset + dataPos, then
        // read the resource type & data.
        // This does a binary search through the names. 
        internal int FindPosForResource(String name)
        { 
            Contract.Assert(_store != null, "ResourceReader is closed!"); 
            int hash = FastResourceComparer.HashFunction(name);
            BCLDebug.Log("RESMGRFILEFORMAT", "FindPosForResource for "+name+"  hash: "+hash.ToString("x", CultureInfo.InvariantCulture)); 
            // Binary search over the hashes.  Use the _namePositions array to
            // determine where they exist in the underlying stream.
            int lo = 0;
            int hi = _numResources - 1; 
            int index = -1;
            bool success = false; 
            while (lo <= hi) { 
                index = (lo + hi) >> 1;
                // Do NOT use subtraction here, since it will wrap for large 
                // negative numbers.
                int currentHash = GetNameHash(index);
                int c;
                if (currentHash == hash) 
                    c = 0;
                else if (currentHash < hash) 
                    c = -1; 
                else
                    c = 1; 
                //BCLDebug.Log("RESMGRFILEFORMAT", "  Probing index "+index+"  lo: "+lo+"  hi: "+hi+"  c: "+c);
                if (c == 0) {
                    success = true;
                    break; 
                }
                if (c < 0) 
                    lo = index + 1; 
                else
                    hi = index - 1; 
            }
            if (!success) {
#if RESOURCE_FILE_FORMAT_DEBUG
                String lastReadString; 
                lock(this) {
                    _store.BaseStream.Seek(_nameSectionOffset + GetNamePosition(index), SeekOrigin.Begin); 
                    lastReadString = _store.ReadString(); 
                }
                BCLDebug.Log("RESMGRFILEFORMAT", LogLevel.Status, "FindPosForResource for ", name, " failed.  i: ", index, "  lo: ", lo, "  hi: ", hi, "  last read string: \"", lastReadString, '\''); 
#endif
                return -1;
            }
 
            // index is the location in our hash array that corresponds with a
            // value in the namePositions array. 
            // There could be collisions in our hash function.  Check on both sides 
            // of index to find the range of hash values that are equal to the
            // target hash value. 
            if (lo != index) {
                lo = index;
                while (lo > 0 && GetNameHash(lo - 1) == hash)
                    lo--; 
            }
            if (hi != index) { 
                hi = index; 
                while (hi < _numResources - 1 && GetNameHash(hi + 1) == hash)
                    hi++; 
            }

            lock(this) {
                for(int i = lo; i<=hi; i++) { 
                    _store.BaseStream.Seek(_nameSectionOffset + GetNamePosition(i), SeekOrigin.Begin);
                    if (CompareStringEqualsName(name)) { 
                        int dataPos = _store.ReadInt32(); 
                        if (dataPos < 0 || dataPos >= _store.BaseStream.Length - _dataSectionOffset) {
                            throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dataPos)); 
                        }
                        return dataPos;
                    }
                } 
            }
            BCLDebug.Log("RESMGRFILEFORMAT", "FindPosForResource for "+name+": Found a hash collision, HOWEVER, neither of these collided values equaled the given string."); 
            return -1; 
        }
 
        // This compares the String in the .resources file at the current position
        // with the string you pass in.
        // Whoever calls this method should make sure that they take a lock
        // so no one else can cause us to seek in the stream. 
        [System.Security.SecuritySafeCritical]  // auto-generated
        private unsafe bool CompareStringEqualsName(String name) 
        { 
            Contract.Assert(_store != null, "ResourceReader is closed!");
            int byteLen = _store.Read7BitEncodedInt(); 
            if (byteLen < 0) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_NegativeStringLength"));
            }
            if (_ums != null) { 
                byte* bytes = _ums.PositionPointer;
                // Skip over the data in the Stream, positioning ourselves right after it. 
                _ums.Seek(byteLen, SeekOrigin.Current); 
                if (_ums.Position > _ums.Length) {
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesNameTooLong")); 
                }

                // On 64-bit machines, these char*'s may be misaligned.  Use a
                // byte-by-byte comparison instead. 
                //return FastResourceComparer.CompareOrdinal((char*)bytes, byteLen/2, name) == 0;
                return FastResourceComparer.CompareOrdinal(bytes, byteLen, name) == 0; 
            } 
            else {
                // This code needs to be fast 
                byte[] bytes = new byte[byteLen];
                int numBytesToRead = byteLen;
                while(numBytesToRead > 0) {
                    int n = _store.Read(bytes, byteLen - numBytesToRead, numBytesToRead); 
                    if (n == 0)
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceNameCorrupted")); 
                    numBytesToRead -= n; 
                }
                return FastResourceComparer.CompareOrdinal(bytes, byteLen/2, name) == 0; 
            }
        }

        // This is used in the enumerator.  The enumerator iterates from 0 to n 
        // of our resources and this returns the resource name for a particular
        // index.  The parameter is NOT a virtual offset. 
        [System.Security.SecurityCritical]  // auto-generated 
        private unsafe String AllocateStringForNameIndex(int index, out int dataOffset)
        { 
            Contract.Assert(_store != null, "ResourceReader is closed!");
            byte[] bytes;
            int byteLen;
            long nameVA = GetNamePosition(index); 
            lock (this) {
                _store.BaseStream.Seek(nameVA + _nameSectionOffset, SeekOrigin.Begin); 
                // Can't use _store.ReadString, since it's using UTF-8! 
                byteLen = _store.Read7BitEncodedInt();
                if (byteLen < 0) { 
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_NegativeStringLength"));
                }

                if (_ums != null) { 
                    if (_ums.Position > _ums.Length - byteLen)
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesIndexTooLong", index)); 
 
                    String s = null;
                    char* charPtr = (char*)_ums.PositionPointer; 
#if IA64
                    if (((int)charPtr & 1) != 0) {
                        char[] destArray = new char[byteLen/2];
                        fixed(char* pDest = destArray) { 
                            Buffer.memcpyimpl((byte*)charPtr, (byte*)pDest, byteLen);
                        } 
                        s = new String(destArray); 
                    }
                    else { 
#endif //IA64
                    s = new String(charPtr, 0, byteLen/2);
#if IA64
                    } 
#endif //IA64
                    _ums.Position += byteLen; 
                    dataOffset = _store.ReadInt32(); 
                    if (dataOffset < 0 || dataOffset >= _store.BaseStream.Length - _dataSectionOffset) {
                        throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dataOffset)); 
                    }
                    return s;
                }
 
                bytes = new byte[byteLen];
                // We must read byteLen bytes, or we have a corrupted file. 
                // Use a blocking read in case the stream doesn't give us back 
                // everything immediately.
                int count = byteLen; 
                while(count > 0) {
                    int n = _store.Read(bytes, byteLen - count, count);
                    if (n == 0)
                        throw new EndOfStreamException(Environment.GetResourceString("BadImageFormat_ResourceNameCorrupted_NameIndex", index)); 
                    count -= n;
                } 
                dataOffset = _store.ReadInt32(); 
                if (dataOffset < 0 || dataOffset >= _store.BaseStream.Length - _dataSectionOffset) {
                    throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dataOffset)); 
                }
            }
            return Encoding.Unicode.GetString(bytes, 0, byteLen);
        } 

        // This is used in the enumerator.  The enumerator iterates from 0 to n 
        // of our resources and this returns the resource value for a particular 
        // index.  The parameter is NOT a virtual offset.
        [System.Security.SecuritySafeCritical]  // auto-generated 
        private Object GetValueForNameIndex(int index)
        {
            Contract.Assert(_store != null, "ResourceReader is closed!");
            long nameVA = GetNamePosition(index); 
            lock(this) {
                _store.BaseStream.Seek(nameVA + _nameSectionOffset, SeekOrigin.Begin); 
                SkipString(); 
                //BCLDebug.Log("RESMGRFILEFORMAT", "GetValueForNameIndex for index: "+index+"  skip (name length): "+skip);
                int dataPos = _store.ReadInt32(); 
                if (dataPos < 0 || dataPos >= _store.BaseStream.Length - _dataSectionOffset) {
                    throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dataPos));
                }
                BCLDebug.Log("RESMGRFILEFORMAT", "GetValueForNameIndex: dataPos: "+dataPos); 
                ResourceTypeCode junk;
                if (_version == 1) 
                    return LoadObjectV1(dataPos); 
                else
                    return LoadObjectV2(dataPos, out junk); 
            }
        }

        // This takes a virtual offset into the data section and reads a String 
        // from that location.
        // Anyone who calls LoadObject should make sure they take a lock so 
        // no one can cause us to do a seek in here. 
        [System.Security.SecuritySafeCritical]  // auto-generated
        internal String LoadString(int pos) 
        {
            Contract.Assert(_store != null, "ResourceReader is closed!");
            _store.BaseStream.Seek(_dataSectionOffset+pos, SeekOrigin.Begin);
            String s = null; 
            int typeIndex = _store.Read7BitEncodedInt();
            if (_version == 1) { 
                if (typeIndex == -1) 
                    return null;
                if (FindType(typeIndex) != typeof(String)) 
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Type", FindType(typeIndex).FullName));
                s = _store.ReadString();
            }
            else { 
                ResourceTypeCode typeCode = (ResourceTypeCode) typeIndex;
                if (typeCode != ResourceTypeCode.String && typeCode != ResourceTypeCode.Null) { 
                    String typeString; 
                    if (typeCode < ResourceTypeCode.StartOfUserTypes)
                        typeString = typeCode.ToString(); 
                    else
                        typeString = FindType(typeCode - ResourceTypeCode.StartOfUserTypes).FullName;
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Type", typeString));
                } 
                if (typeCode == ResourceTypeCode.String) // ignore Null
                    s = _store.ReadString(); 
            } 
            BCLDebug.Log("RESMGRFILEFORMAT", "LoadString("+pos.ToString("x", CultureInfo.InvariantCulture)+" returned "+(s==null ? "[a null string]" : s));
            return s; 
        }

        // Called from RuntimeResourceSet
        internal Object LoadObject(int pos) 
        {
            if (_version == 1) 
                return LoadObjectV1(pos); 
            ResourceTypeCode typeCode;
            return LoadObjectV2(pos, out typeCode); 
        }

        internal Object LoadObject(int pos, out ResourceTypeCode typeCode)
        { 
            if (_version == 1) {
                Object o = LoadObjectV1(pos); 
                typeCode = (o is String) ? ResourceTypeCode.String : ResourceTypeCode.StartOfUserTypes; 
                return o;
            } 
            return LoadObjectV2(pos, out typeCode);
        }

        // This takes a virtual offset into the data section and reads an Object 
        // from that location.
        // Anyone who calls LoadObject should make sure they take a lock so 
        // no one can cause us to do a seek in here. 
        internal Object LoadObjectV1(int pos)
        { 
            Contract.Assert(_store != null, "ResourceReader is closed!");
            Contract.Assert(_version == 1, ".resources file was not a V1 .resources file!");

            try { 
                // mega try-catch performs exceptionally bad on x64; factored out body into
                // _LoadObjectV1 and wrap here. 
                return _LoadObjectV1(pos); 
            }
            catch (EndOfStreamException eof) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch"), eof);
            }
            catch (ArgumentOutOfRangeException e) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch"), e); 
            }
        } 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        private Object _LoadObjectV1(int pos) { 
            _store.BaseStream.Seek(_dataSectionOffset+pos, SeekOrigin.Begin);
            int typeIndex = _store.Read7BitEncodedInt();
            if (typeIndex == -1)
                return null; 
            RuntimeType type = FindType(typeIndex);
            BCLDebug.Log("RESMGRFILEFORMAT", "LoadObject type: "+type.Name+"  pos: 0x"+_store.BaseStream.Position.ToString("x", CultureInfo.InvariantCulture)); 
            // Consider putting in logic to see if this type is a 
            // primitive or a value type first, so we can reach the
            // deserialization code faster for arbitrary objects. 

            if (type == typeof(String))
                return _store.ReadString();
            else if (type == typeof(Int32)) 
                return _store.ReadInt32();
            else if (type == typeof(Byte)) 
                return _store.ReadByte(); 
            else if (type == typeof(SByte))
                return _store.ReadSByte(); 
            else if (type == typeof(Int16))
                return _store.ReadInt16();
            else if (type == typeof(Int64))
                return _store.ReadInt64(); 
            else if (type == typeof(UInt16))
                return _store.ReadUInt16(); 
            else if (type == typeof(UInt32)) 
                return _store.ReadUInt32();
            else if (type == typeof(UInt64)) 
                return _store.ReadUInt64();
            else if (type == typeof(Single))
                return _store.ReadSingle();
            else if (type == typeof(Double)) 
                return _store.ReadDouble();
            else if (type == typeof(DateTime)) { 
                // Ideally we should use DateTime's ToBinary & FromBinary, 
                // but we can't for compatibility reasons.
                return new DateTime(_store.ReadInt64()); 
            }
            else if (type == typeof(TimeSpan))
                return new TimeSpan(_store.ReadInt64());
            else if (type == typeof(Decimal)) { 
                int[] bits = new int[4];
                for(int i=0; i= 2, ".resources file was not a V2 (or higher) .resources file!"); 

            try { 
                // mega try-catch performs exceptionally bad on x64; factored out body into 
                // _LoadObjectV2 and wrap here.
                return _LoadObjectV2(pos, out typeCode); 
            }
            catch (EndOfStreamException eof) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch"), eof);
            } 
            catch (ArgumentOutOfRangeException e) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch"), e); 
            } 
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        private Object _LoadObjectV2(int pos, out ResourceTypeCode typeCode) {
            _store.BaseStream.Seek(_dataSectionOffset+pos, SeekOrigin.Begin);
            typeCode = (ResourceTypeCode) _store.Read7BitEncodedInt(); 

            BCLDebug.Log("RESMGRFILEFORMAT", "LoadObjectV2 type: "+typeCode+"  pos: 0x"+_store.BaseStream.Position.ToString("x", CultureInfo.InvariantCulture)); 
 
            switch(typeCode) {
            case ResourceTypeCode.Null: 
                return null;

            case ResourceTypeCode.String:
                return _store.ReadString(); 

            case ResourceTypeCode.Boolean: 
                return _store.ReadBoolean(); 

            case ResourceTypeCode.Char: 
                return (char) _store.ReadUInt16();

            case ResourceTypeCode.Byte:
                return _store.ReadByte(); 

            case ResourceTypeCode.SByte: 
                return _store.ReadSByte(); 

            case ResourceTypeCode.Int16: 
                return _store.ReadInt16();

            case ResourceTypeCode.UInt16:
                return _store.ReadUInt16(); 

            case ResourceTypeCode.Int32: 
                return _store.ReadInt32(); 

            case ResourceTypeCode.UInt32: 
                return _store.ReadUInt32();

            case ResourceTypeCode.Int64:
                return _store.ReadInt64(); 

            case ResourceTypeCode.UInt64: 
                return _store.ReadUInt64(); 

            case ResourceTypeCode.Single: 
                return _store.ReadSingle();

            case ResourceTypeCode.Double:
                return _store.ReadDouble(); 

            case ResourceTypeCode.Decimal: 
                return _store.ReadDecimal(); 

            case ResourceTypeCode.DateTime: 
                // Use DateTime's ToBinary & FromBinary.
                Int64 data = _store.ReadInt64();
                return DateTime.FromBinary(data);
 
            case ResourceTypeCode.TimeSpan:
                Int64 ticks = _store.ReadInt64(); 
                return new TimeSpan(ticks); 

            // Special types 
            case ResourceTypeCode.ByteArray: {
                    int len = _store.ReadInt32();
                    if (len < 0) {
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len)); 
                    }
 
                            if (_ums == null) { 
                                if (len > _store.BaseStream.Length) {
                            throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len)); 
                                }
                        return _store.ReadBytes(len);
                            }
 
                    if (len > _ums.Length - _ums.Position) {
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len)); 
                    } 

                    byte[] bytes = new byte[len]; 
                    int r = _ums.Read(bytes, 0, len);
                    Contract.Assert(r == len, "ResourceReader needs to use a blocking read here.  (Call _store.ReadBytes(len)?)");
                    return bytes;
                } 

                    case ResourceTypeCode.Stream: { 
                    int len = _store.ReadInt32(); 
                    if (len < 0) {
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len)); 
                    }
                    if (_ums == null) {
                        byte[] bytes = _store.ReadBytes(len);
                        // Lifetime of memory == lifetime of this stream. 
                        return new PinnedBufferMemoryStream(bytes);
                    } 
 
                    // make sure we don't create an UnmanagedMemoryStream that is longer than the resource stream.
                    if (len > _ums.Length - _ums.Position) { 
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourceDataLengthInvalid", len));
                    }

                    // For the case that we've memory mapped in the .resources 
                    // file, just return a Stream pointing to that block of memory.
                    unsafe { 
                        return new UnmanagedMemoryStream(_ums.PositionPointer, len, len, FileAccess.Read, true); 
                    }
                } 

            default:
                if (typeCode < ResourceTypeCode.StartOfUserTypes) {
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_TypeMismatch")); 
                }
                break; 
            } 

            // Normal serialized objects 
#if FEATURE_SERIALIZATION
            int typeIndex = typeCode - ResourceTypeCode.StartOfUserTypes;
            return DeserializeObject(typeIndex);
#else 
            throw new NotSupportedException(Environment.GetResourceString("NotSupported_ResourceObjectSerialization"));
#endif // FEATURE_SERIALIZATION 
        } 

 
#if FEATURE_SERIALIZATION
        // Helper method to safely deserialize a type, using a type-limiting
        // deserialization binder to simulate a type-limiting deserializer.
        // This method handles types that are safe to deserialize, as well as 
        // ensuring we only get back what we expect.
        [System.Security.SecurityCritical]  // auto-generated 
        private Object DeserializeObject(int typeIndex) 
        {
            RuntimeType type = FindType(typeIndex); 
#if !FEATURE_PAL
            // Initialize deserialization permission array, if needed
            if (_safeToDeserialize == null)
                InitSafeToDeserializeArray(); 
#endif // !FEATURE_PAL
 
            // Ensure that the object we deserialized is exactly the same 
            // type of object we thought we should be deserializing.  This
            // will help prevent hacked .resources files from using our 
            // serialization permission assert to deserialize anything
            // via a hacked type ID.

            Object graph; 
#if FEATURE_PAL
            graph = _objFormatter.Deserialize(_store.BaseStream); 
#else 
            if (_safeToDeserialize[typeIndex]) {
                // Don't assert serialization permission - just ask the binary 
                // formatter to avoid a permission check.  This ensures that any
                // types which do demand serialization permission in their
                // deserialization .cctors will fail.
                // Also, use a serialization binder to limit bind requests to 
                // our allowed list of [....] types.
                _objFormatter.Binder = _typeLimitingBinder; 
                _typeLimitingBinder.ExpectingToDeserialize(type); 
                graph = _objFormatter.UnsafeDeserialize(_store.BaseStream, null);
            } 
            else {
                _objFormatter.Binder = null;
                graph = _objFormatter.Deserialize(_store.BaseStream);
            } 
#endif // FEATURE_PAL
 
            // This check is about correctness, not security at this point. 
            if (graph.GetType() != type)
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResType&SerBlobMismatch", type.FullName, graph.GetType().FullName)); 

            return graph;
        }
#endif // FEATURE_SERIALIZATION 

        // Reads in the header information for a .resources file.  Verifies some 
        // of the assumptions about this resource set, and builds the class table 
        // for the default resource file format.
        [System.Security.SecurityCritical]  // auto-generated 
        private void ReadResources()
        {
            Contract.Assert(_store != null, "ResourceReader is closed!");
#if FEATURE_SERIALIZATION 
            BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File | StreamingContextStates.Persistence));
#if !FEATURE_PAL 
            _typeLimitingBinder = new TypeLimitingDeserializationBinder(); 
            bf.Binder = _typeLimitingBinder;
#endif 
            _objFormatter = bf;
#endif // FEATURE_SERIALIZATION

            try { 
                // mega try-catch performs exceptionally bad on x64; factored out body into
                // _ReadResources and wrap here. 
                _ReadResources(); 
            }
            catch (EndOfStreamException eof) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"), eof);
            }
            catch (IndexOutOfRangeException e) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"), e); 
            }
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        private void _ReadResources() 
        {
            // Read ResourceManager header
            // Check for magic number
            int magicNum = _store.ReadInt32(); 
            if (magicNum != ResourceManager.MagicNumber)
                throw new ArgumentException(Environment.GetResourceString("Resources_StreamNotValid")); 
            // Assuming this is ResourceManager header V1 or greater, hopefully 
            // after the version number there is a number of bytes to skip
            // to bypass the rest of the ResMgr header. For V2 or greater, we 
            // use this to skip to the end of the header
            int resMgrHeaderVersion = _store.ReadInt32();
            int numBytesToSkip = _store.ReadInt32();
            if (numBytesToSkip < 0 || resMgrHeaderVersion < 0) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
            } 
            if (resMgrHeaderVersion > 1) { 
                BCLDebug.Log("RESMGRFILEFORMAT", LogLevel.Status, "ReadResources: Unexpected ResMgr header version: {0}  Skipping ahead {1} bytes.", resMgrHeaderVersion, numBytesToSkip);
                _store.BaseStream.Seek(numBytesToSkip, SeekOrigin.Current); 
            }
            else {
                BCLDebug.Log("RESMGRFILEFORMAT", "ReadResources: Parsing ResMgr header v1.");
                // We don't care about numBytesToSkip; read the rest of the header 

                // Read in type name for a suitable ResourceReader 
                // Note ResourceWriter & InternalResGen use different Strings. 
                String readerType = _store.ReadString();
                AssemblyName mscorlib = new AssemblyName(ResourceManager.MscorlibName); 

                if (!ResourceManager.CompareNames(readerType, ResourceManager.ResReaderTypeName, mscorlib))
                    throw new NotSupportedException(Environment.GetResourceString("NotSupported_WrongResourceReader_Type", readerType));
 
                // Skip over type name for a suitable ResourceSet
                SkipString(); 
            } 

            // Read RuntimeResourceSet header 
            // Do file version check
            int version = _store.ReadInt32();
            if (version != RuntimeResourceSet.Version && version != 1)
                throw new ArgumentException(Environment.GetResourceString("Arg_ResourceFileUnsupportedVersion", RuntimeResourceSet.Version, version)); 
            _version = version;
 
#if RESOURCE_FILE_FORMAT_DEBUG 
            // Look for ***DEBUG*** to see if this is a debuggable file.
            long oldPos = _store.BaseStream.Position; 
            _debug = false;
            try {
                String debugString = _store.ReadString();
                _debug = String.Equals("***DEBUG***", debugString); 
            }
            catch(IOException) { 
            } 
            catch(OutOfMemoryException) {
            } 
            if (_debug) {
                Console.WriteLine("ResourceReader is looking at a debuggable .resources file, version {0}", _version);
            }
            else { 
                _store.BaseStream.Position = oldPos;
            } 
#endif 

            _numResources = _store.ReadInt32(); 
            if (_numResources < 0) {
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
            }
            BCLDebug.Log("RESMGRFILEFORMAT", "ReadResources: Expecting " + _numResources + " resources."); 
#if _DEBUG
            if (ResourceManager.DEBUG >= 4) 
                Console.WriteLine("ResourceReader::ReadResources - Reading in "+_numResources+" resources"); 
#endif
 
            // Read type positions into type positions array.
            // But delay initialize the type table.
            int numTypes = _store.ReadInt32();
            if (numTypes < 0) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
            } 
            _typeTable = new RuntimeType[numTypes]; 
            _typeNamePositions = new int[numTypes];
            for (int i=0; i= 5)
                    Console.WriteLine("ResourceReader::ReadResources - Reading in "+numTypes+" type table entries"); 
#endif

            // Prepare to read in the array of name hashes
            //  Note that the name hashes array is aligned to 8 bytes so 
            //  we can use pointers into it on 64 bit machines. (4 bytes
            //  may be sufficient, but let's plan for the future) 
            //  Skip over alignment stuff.  All public .resources files 
            //  should be aligned   No need to verify the byte values.
            long pos = _store.BaseStream.Position; 
            int alignBytes = ((int)pos) & 7;
            if (alignBytes != 0) {
                for (int i = 0; i < 8 - alignBytes; i++) {
                    _store.ReadByte(); 
                }
            } 
 
            // Read in the array of name hashes
#if RESOURCE_FILE_FORMAT_DEBUG 
                //  Skip over "HASHES->"
                if (_debug) {
                    _store.BaseStream.Position += 8;
                } 
#endif
 
            if (_ums == null) { 
                _nameHashes = new int[_numResources];
                for (int i = 0; i < _numResources; i++) { 
                    _nameHashes[i] = _store.ReadInt32();
                }
            }
            else { 
                int seekPos = unchecked(4 * _numResources);
                if (seekPos < 0) { 
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted")); 
                }
                unsafe { 
                    _nameHashesPtr = (int*)_ums.PositionPointer;
                    // Skip over the array of nameHashes.
                    _ums.Seek(seekPos, SeekOrigin.Current);
                    // get the position pointer once more to check that the whole table is within the stream 
                    byte* junk = _ums.PositionPointer;
                } 
            } 

            // Read in the array of relative positions for all the names. 
#if RESOURCE_FILE_FORMAT_DEBUG
            // Skip over "POS---->"
            if (_debug) {
                _store.BaseStream.Position += 8; 
            }
#endif 
            if (_ums == null) { 
                _namePositions = new int[_numResources];
                for (int i = 0; i < _numResources; i++) { 
                    int namePosition = _store.ReadInt32();
                    if (namePosition < 0) {
                        throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
                    } 

                    _namePositions[i] = namePosition; 
                } 
            }
            else { 
                int seekPos = unchecked(4 * _numResources);
                if (seekPos < 0) {
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
                } 
                unsafe {
                    _namePositionsPtr = (int*)_ums.PositionPointer; 
                    // Skip over the array of namePositions. 
                    _ums.Seek(seekPos, SeekOrigin.Current);
                    // get the position pointer once more to check that the whole table is within the stream 
                    byte* junk = _ums.PositionPointer;
                }
            }
 
            // Read location of data section.
            _dataSectionOffset = _store.ReadInt32(); 
            if (_dataSectionOffset < 0) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
            } 

            // Store current location as start of name section
            _nameSectionOffset = _store.BaseStream.Position;
 
            // _nameSectionOffset should be <= _dataSectionOffset; if not, it's corrupt
            if (_dataSectionOffset < _nameSectionOffset) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted")); 
            }
 
            BCLDebug.Log("RESMGRFILEFORMAT", String.Format(CultureInfo.InvariantCulture, "ReadResources: _nameOffset = 0x{0:x}  _dataOffset = 0x{1:x}", _nameSectionOffset, _dataSectionOffset));
        }

        // This allows us to delay-initialize the Type[].  This might be a 
        // good startup time savings, since we might have to load assemblies
        // and initialize Reflection. 
        private RuntimeType FindType(int typeIndex) 
        {
            if (typeIndex < 0 || typeIndex >= _typeTable.Length) { 
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_InvalidType"));
            }
            if (_typeTable[typeIndex] == null) {
                long oldPos = _store.BaseStream.Position; 
                try {
                    _store.BaseStream.Position = _typeNamePositions[typeIndex]; 
                    String typeName = _store.ReadString(); 
                    _typeTable[typeIndex] = (RuntimeType)Type.GetType(typeName, true);
                } 
#if !FEATURE_SERIALIZATION
                // If serialization isn't supported, we convert FileNotFoundException to
                // NotSupportedException for consistency with v2. This is a corner-case, but the
                // idea is that we want to give the user a more accurate error message. Even if 
                // the dependency were found, we know it will require serialization since it
                // can't be one of the types we special case. So if the dependency were found, 
                // it would go down the serialization code path, resulting in NotSupported for 
                // SKUs without serialization.
                // 
                // We don't want to regress the expected case by checking the type info before
                // getting to Type.GetType -- this is costly with v1 resource formats.
                catch (FileNotFoundException)
                { 
                    throw new NotSupportedException(Environment.GetResourceString("NotSupported_ResourceObjectSerialization"));
                } 
#endif // FEATURE_SERIALIZATION 
                finally {
                    _store.BaseStream.Position = oldPos; 
                }
            }
            Contract.Assert(_typeTable[typeIndex] != null, "Should have found a type!");
            return _typeTable[typeIndex]; 
        }
 
#if !FEATURE_PAL && FEATURE_SERIALIZATION 
        [System.Security.SecurityCritical]  // auto-generated
        private void InitSafeToDeserializeArray() 
        {
            _safeToDeserialize = new bool[_typeTable.Length];
            for(int i=0; i<_typeTable.Length; i++) {
                long oldPos = _store.BaseStream.Position; 
                String typeName;
                try { 
                    _store.BaseStream.Position = _typeNamePositions[i]; 
                    typeName = _store.ReadString();
                } 
                finally {
                    _store.BaseStream.Position = oldPos;
                }
 
                AssemblyName an;
                String typePart; 
                RuntimeType resourceType = (RuntimeType)Type.GetType(typeName, false); 
                if (resourceType == null) {
                    an = null; 
                    typePart = typeName;
                }
                else {
                    // Enums should be safe to deserialize, and this helps out 
                    // partially trusted, localized [....] apps.
                    if (resourceType.BaseType == typeof(Enum)) { 
                        _safeToDeserialize[i] = true; 
                        continue;
                    } 

                    // For most types, check our TypesSafeForDeserialization.
                    typePart = resourceType.FullName;
 
                    an = new AssemblyName();
 
                    // resourceType is retrieved via Type.GetType and must be a RuntimeType 
                    RuntimeAssembly a = (RuntimeAssembly)resourceType.Assembly;
                    an.Init(a.GetSimpleName(), 
                            a.GetPublicKey(),
                            null, // public key token
                            null, // version
                            a.GetLocale(), 
                            AssemblyHashAlgorithm.None,
                            AssemblyVersionCompatibility.SameMachine, 
                            null, // codebase 
                            AssemblyNameFlags.PublicKey,
                            null); // strong name key pair 
                }

                foreach(String safeType in TypesSafeForDeserialization) {
                    if (ResourceManager.CompareNames(safeType, typePart, an)) { 
#if _DEBUG
                        if (ResourceManager.DEBUG >= 7) 
                            Console.WriteLine("ResReader: Found a type-safe type to deserialize!  Type name: {0}", typeName); 
#endif
                        _safeToDeserialize[i] = true; 
                        continue;
                    }
                }
 
#if _DEBUG
                if (ResourceManager.DEBUG >= 7) 
                    if (!_safeToDeserialize[i]) 
                        Console.WriteLine("ResReader: Found a type that wasn't safe to deserialize: {0}", typeName);
#endif 
            }
        }
#endif // !FEATURE_PAL && FEATURE_SERIALIZATION
 
        public void GetResourceData(String resourceName, out String resourceType, out byte[] resourceData)
        { 
            if (resourceName == null) 
                throw new ArgumentNullException("resourceName");
            Contract.EndContractBlock(); 
            if (_resCache == null)
                throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed"));

            // Get the type information from the data section.  Also, 
            // sort all of the data section's indexes to compute length of
            // the serialized data for this type (making sure to subtract 
            // off the length of the type code). 
            int[] sortedDataPositions = new int[_numResources];
            int dataPos = FindPosForResource(resourceName); 
            if( dataPos == -1) {
                throw new ArgumentException(Environment.GetResourceString("Arg_ResourceNameNotExist", resourceName));
            }
 
            lock(this) {
                // Read all the positions of data within the data section. 
                for(int i=0; i<_numResources; i++) { 
                    _store.BaseStream.Position = _nameSectionOffset + GetNamePosition(i);
                    // Skip over name of resource 
                    int numBytesToSkip = _store.Read7BitEncodedInt();
                    if (numBytesToSkip < 0) {
                        throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesNameInvalidOffset", numBytesToSkip));
                    } 
                    _store.BaseStream.Position += numBytesToSkip;
 
                    int dPos = _store.ReadInt32(); 
                    if (dPos < 0 || dPos >= _store.BaseStream.Length - _dataSectionOffset) {
                        throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourcesDataInvalidOffset", dPos)); 
                    }
                    sortedDataPositions[i] = dPos;
                }
                Array.Sort(sortedDataPositions); 

                int index = Array.BinarySearch(sortedDataPositions, dataPos); 
                Contract.Assert(index >= 0 && index < _numResources, "Couldn't find data position within sorted data positions array!"); 
                long nextData = (index < _numResources - 1) ? sortedDataPositions[index + 1] + _dataSectionOffset : _store.BaseStream.Length;
                int len = (int) (nextData - (dataPos + _dataSectionOffset)); 
                Contract.Assert(len >= 0 && len <= (int) _store.BaseStream.Length - dataPos + _dataSectionOffset, "Length was negative or outside the bounds of the file!");

                // Read type code then byte[]
                _store.BaseStream.Position = _dataSectionOffset + dataPos; 
                ResourceTypeCode typeCode = (ResourceTypeCode) _store.Read7BitEncodedInt();
                if (typeCode < 0 || typeCode >= ResourceTypeCode.StartOfUserTypes + _typeTable.Length) { 
                    throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_InvalidType")); 
                }
                resourceType = TypeNameFromTypeCode(typeCode); 

                // The length must be adjusted to subtract off the number
                // of bytes in the 7 bit encoded type code.
                len -= (int) (_store.BaseStream.Position - (_dataSectionOffset + dataPos)); 
                byte[] bytes = _store.ReadBytes(len);
                if (bytes.Length != len) 
                    throw new FormatException(Environment.GetResourceString("BadImageFormat_ResourceNameCorrupted")); 
                resourceData = bytes;
            } 
        }

        private String TypeNameFromTypeCode(ResourceTypeCode typeCode)
        { 
            Contract.Assert(typeCode >= 0, "can't be negative");
            if (typeCode < ResourceTypeCode.StartOfUserTypes) { 
                Contract.Assert(!String.Equals(typeCode.ToString(), "LastPrimitive"), "Change ResourceTypeCode metadata order so LastPrimitive isn't what Enum.ToString prefers."); 
                return "ResourceTypeCode." + typeCode.ToString();
            } 
            else {
                int typeIndex = typeCode - ResourceTypeCode.StartOfUserTypes;
                Contract.Assert(typeIndex >= 0 && typeIndex < _typeTable.Length, "TypeCode is broken or corrupted!");
                long oldPos = _store.BaseStream.Position; 
                try {
                    _store.BaseStream.Position = _typeNamePositions[typeIndex]; 
                    return _store.ReadString(); 
                }
                finally { 
                    _store.BaseStream.Position = oldPos;
                }
            }
        } 

#if !FEATURE_PAL && FEATURE_SERIALIZATION 
        // We need to build a type-limiting deserializer.  We know exactly which 
        // type we want to deserialize, and if someone tells us we have type X
        // (which might be safe to deserialize) and they give us a serialized 
        // form of type Y, we don't want to run the deserialization constructor
        // because we've asserted serialization formatter permission.  Instead,
        // limit the binary formatter's type binding to precisely the type we
        // expect.  If they ever don't match, that's a corrupt .resources file. 
        // We also must check the complete object graph to ensure all of the
        // graph contains safe objects. 
        // Note this is tightly coupled to the BinaryFormatter, since we use 
        // its internal ObjectReader::FastBindToType method, and we had to
        // change the ObjectReader to register itself with this type. 
        internal sealed class TypeLimitingDeserializationBinder : SerializationBinder
        {
            private RuntimeType _typeToDeserialize;
            // This is tightly coupled with the binary formatter, because we 
            // want to use exactly the same code found in the ObjectReader
            // to do the lookup, then just give a thumbs up or down based on 
            // a type equality comparison.  In the future, we could consider 
            // some better refactoring of this code.
            private ObjectReader _objectReader; 

            internal ObjectReader ObjectReader {
                get { return _objectReader; }
                set { _objectReader = value; } 
            }
 
            internal void ExpectingToDeserialize(RuntimeType type) 
            {
                _typeToDeserialize = type; 
            }

            [System.Security.SecuritySafeCritical] // overrides transparent public member
            public override Type BindToType(string assemblyName, string typeName) 
            {
                // BinaryObjectReader::Bind tries us first, then its own code. 
                // Returning null means let the default binding rules happen. 
                AssemblyName an = new AssemblyName(assemblyName);
 
                bool safe = false;
                foreach(String safeType in TypesSafeForDeserialization) {
                    if (ResourceManager.CompareNames(safeType, typeName, an)) {
                        safe = true; 
                        break;
                    } 
                } 

                // [....] types may internally use some enums that aren't 
                // on our safe to deserialize list, like Font using FontStyle.
                Type t = ObjectReader.FastBindToType(assemblyName, typeName);
                if (t.IsEnum)
                    safe = true; 

                if (safe) 
                    return null; 

                // Throw instead of returning null. 
                // If you're looking at this in a debugger, you've either
                // got a hacked .resources file on your hands, or [....]
                // types have taken a new dependency on another type.  Check
                // whether assemblyName & typeName refer to a trustworthy type, 
                // & consider adding it to the TypesSafeToDeserialize list.
                throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResType&SerBlobMismatch", _typeToDeserialize.FullName, typeName)); 
            } 
        }
#endif // !FEATURE_PAL && FEATURE_SERIALIZATION 


        internal sealed class ResourceEnumerator : IDictionaryEnumerator
        { 
            private const int ENUM_DONE = Int32.MinValue;
            private const int ENUM_NOT_STARTED = -1; 
 
            private ResourceReader _reader;
            private bool _currentIsValid; 
            private int _currentName;
            private int _dataPosition; // cached for case-insensitive table

            internal ResourceEnumerator(ResourceReader reader) 
            {
                _currentName = ENUM_NOT_STARTED; 
                _reader = reader; 
                _dataPosition = -2;
            } 

            public bool MoveNext()
            {
                if (_currentName == _reader._numResources - 1 || _currentName == ENUM_DONE) { 
                    _currentIsValid = false;
                    _currentName = ENUM_DONE; 
                    return false; 
                }
                _currentIsValid = true; 
                _currentName++;
                return true;
            }
 
            public Object Key {
                [System.Security.SecuritySafeCritical]  // auto-generated 
                get { 
                    if (_currentName == ENUM_DONE) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
                    if (!_currentIsValid) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); 
                    if (_reader._resCache == null) throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed"));

                    return _reader.AllocateStringForNameIndex(_currentName, out _dataPosition);
                } 
            }
 
            public Object Current { 
                get {
                    return Entry; 
                }
            }

            // Warning: This requires that you call the Key or Entry property FIRST before calling it! 
            internal int DataPosition {
                get { 
                    return _dataPosition; 
                }
            } 

            public DictionaryEntry Entry {
                [System.Security.SecuritySafeCritical]  // auto-generated
                get { 
                    if (_currentName == ENUM_DONE) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
                    if (!_currentIsValid) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); 
                    if (_reader._resCache == null) throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed")); 

                    String key; 
                    Object value = null;
                    lock (_reader._resCache) {
                        key = _reader.AllocateStringForNameIndex(_currentName, out _dataPosition);
                        ResourceLocator locator; 
                        if (_reader._resCache.TryGetValue(key, out locator)) {
                            value = locator.Value; 
                        } 
                        if (value == null) {
                            if (_dataPosition == -1) 
                                value = _reader.GetValueForNameIndex(_currentName);
                            else
                                value = _reader.LoadObject(_dataPosition);
                            // If enumeration and subsequent lookups happen very 
                            // frequently in the same process, add a ResourceLocator
                            // to _resCache here.  But [....] enumerates and 
                            // just about everyone else does lookups.  So caching 
                            // here may bloat working set.
                        } 
                    }
                    return new DictionaryEntry(key, value);
                }
            } 

            public Object Value { 
                get { 
                    if (_currentName == ENUM_DONE) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
                    if (!_currentIsValid) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); 
                    if (_reader._resCache == null) throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed"));

                    // Consider using _resCache here, eventually, if
                    // this proves to be an interesting perf scenario. 
                    // But mixing lookups and enumerators shouldn't be
                    // particularly compelling. 
                    return _reader.GetValueForNameIndex(_currentName); 
                }
            } 

            public void Reset()
            {
                if (_reader._resCache == null) throw new InvalidOperationException(Environment.GetResourceString("ResourceReaderIsClosed")); 
                _currentIsValid = false;
                _currentName = ENUM_NOT_STARTED; 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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