public ResourceReader(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } if (!stream.CanRead) { throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotReadable")); } _table = new Hashtable(FastResourceComparer.Default, 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). internal ResourceReader(Stream stream, Hashtable table) { if (stream == null) { throw new ArgumentNullException("stream"); } if (table == null) { throw new ArgumentNullException("table"); } if (!stream.CanRead) { throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotReadable")); } _table = table; _store = new BinaryReader(stream, Encoding.UTF8); _ums = stream as __UnmanagedMemoryStream; BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(Stream, Hashtable). UnmanagedMemoryStream: " + (_ums != null)); ReadResources(); }
private void Dispose(bool disposing) { if (_store != 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; if (copyOfStore != null) { copyOfStore.Close(); } } _store = null; _table = null; _namePositions = null; _nameHashes = null; _ums = null; _namePositionsPtr = null; _nameHashesPtr = null; } }
// 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. private void ReadResources() { BCLDebug.Assert(_store != null, "ResourceReader is closed!"); BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File | StreamingContextStates.Persistence)); // Do partial binds so we can be tolerant of version number changes. bf.AssemblyFormat = FormatterAssemblyStyle.Simple; _objFormatter = bf; try { // 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. int resMgrHeaderVersion = _store.ReadInt32(); if (resMgrHeaderVersion > 1) { int numBytesToSkip = _store.ReadInt32(); BCLDebug.Log("RESMGRFILEFORMAT", LogLevel.Status, "ReadResources: Unexpected ResMgr header version: {0} Skipping ahead {1} bytes.", resMgrHeaderVersion, numBytesToSkip); BCLDebug.Assert(numBytesToSkip >= 0, "numBytesToSkip in ResMgr header should be positive!"); _store.BaseStream.Seek(numBytesToSkip, SeekOrigin.Current); } else { BCLDebug.Log("RESMGRFILEFORMAT", "ReadResources: Parsing ResMgr header v1."); _store.ReadInt32(); // We don't care about numBytesToSkip. // Read in type name for a suitable ResourceReader // Note ResourceWriter & InternalResGen use different Strings. String readerType = _store.ReadString(); if (!readerType.Equals(ResourceManager.ResReaderTypeName) && !readerType.Equals(typeof(ResourceReader).FullName) && !readerType.Equals(ResourceManager.ResReaderTypeNameInternal)) { throw new NotSupportedException("This .resources file shouldn't be used with this reader. Your resource reader type: " + readerType); } // Skip over type name for a suitable ResourceSet _store.ReadString(); } // Read RuntimeResourceSet header // Do file version check int version = _store.ReadInt32(); if (version != RuntimeResourceSet.Version) { throw new ArgumentException(String.Format("Version conflict with ResourceManager .resources files! Expected version: {0} but got: {1}", RuntimeResourceSet.Version, version)); } _numResources = _store.ReadInt32(); BCLDebug.Log("RESMGRFILEFORMAT", "ReadResources: Expecting " + _numResources + " resources."); #if _DEBUG if (ResourceManager.DEBUG >= 4) { Console.WriteLine("ResourceReader::ReadResources - Reading in " + _numResources + " resources"); } #endif // Read type names into type array. int numTypes = _store.ReadInt32(); _typeTable = new Type[numTypes]; for (int i = 0; i < numTypes; i++) { String typeName = _store.ReadString(); // Do partial binds to be tolerant of version number changes. _typeTable[i] = Assembly.LoadTypeWithPartialName(typeName, false); if (_typeTable[i] == null) { throw new TypeLoadException(Environment.GetResourceString("TypeLoad_PartialBindFailed", typeName)); } } // Initialize deserialization permission array InitSafeToDeserializeArray(); #if _DEBUG if (ResourceManager.DEBUG >= 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, if it's present. long pos = _store.BaseStream.Position; int alignBytes = ((int)pos) & 7; bool fileIsAligned = true; if (alignBytes != 0) { // For backwards compatibility, don't require the "PAD" stuff // in here, but we should definitely skip it if present. for (int i = 0; i < 8 - alignBytes; i++) { byte b = _store.ReadByte(); if (b != "PAD"[i % 3]) { fileIsAligned = false; break; } } // If we weren't aligned, we shouldn't have skipped this data! if (!fileIsAligned) { _store.BaseStream.Position = pos; } else { BCLDebug.Assert((_store.BaseStream.Position & 7) == 0, "ResourceReader: Stream should be aligned on an 8 byte boundary now!"); } } #if RESOURCE_FILE_FORMAT_DEBUG Console.WriteLine("ResourceReader: File alignment: " + fileIsAligned); #endif #if !WIN32 // If the file wasn't aligned, we can't use the _ums code on IA64. // However, this should only be a problem for .resources files // that weren't rebuilt after ~August 11, 2001 when I introduced // the alignment code. We can rip this check in the next // version. -- Brian Grunkemeyer, 8/8/2001 if (!fileIsAligned) { _ums = null; } #endif // Read in the array of name hashes #if RESOURCE_FILE_FORMAT_DEBUG // Skip over "HASHES->" _store.BaseStream.Position += 8; #endif if (_ums == null) { _nameHashes = new int[_numResources]; for (int i = 0; i < _numResources; i++) { _nameHashes[i] = _store.ReadInt32(); } } else { _nameHashesPtr = (int *)_ums.GetBytePtr(); // Skip over the array of nameHashes. _ums.Seek(4 * _numResources, SeekOrigin.Current); } // Read in the array of relative positions for all the names. #if RESOURCE_FILE_FORMAT_DEBUG // Skip over "POS---->" _store.BaseStream.Position += 8; #endif if (_ums == null) { _namePositions = new int[_numResources]; for (int i = 0; i < _numResources; i++) { _namePositions[i] = _store.ReadInt32(); } } else { _namePositionsPtr = (int *)_ums.GetBytePtr(); // Skip over the array of namePositions. _ums.Seek(4 * _numResources, SeekOrigin.Current); } // Read location of data section. _dataSectionOffset = _store.ReadInt32(); // Store current location as start of name section _nameSectionOffset = _store.BaseStream.Position; BCLDebug.Log("RESMGRFILEFORMAT", String.Format("ReadResources: _nameOffset = 0x{0:x} _dataOffset = 0x{1:x}", _nameSectionOffset, _dataSectionOffset)); } catch (EndOfStreamException eof) { throw new ArgumentException("Stream is not a valid .resources file! It was possibly truncated.", eof); } }