From 61e0be75b5a5da1b90299f0d3ee6fb76d4b03d9b Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sat, 8 Aug 2009 02:23:04 +0000 Subject: When opening a data stream, don't read the whole file into memory if not necessary. This vastly improves the loading times of Gob3 on small devices svn-id: r43107 --- engines/gob/dataio.cpp | 262 +++++++++++++++++++++++++++---------------------- engines/gob/dataio.h | 66 ++++++++----- 2 files changed, 182 insertions(+), 146 deletions(-) (limited to 'engines/gob') diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 99cf7c1193..3b7a61d485 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -35,21 +35,22 @@ namespace Gob { DataStream::DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose) { _io = &io; - _handle = handle; - _size = dSize; + + _handle = handle; + _size = dSize; _dispose = dispose; - _data = 0; + _data = 0; _stream = 0; } DataStream::DataStream(byte *buf, uint32 dSize, bool dispose) { - _data = buf; - _size = dSize; - _stream = new Common::MemoryReadStream(_data, _size); + _data = buf; + _size = dSize; + _stream = new Common::MemoryReadStream(_data, _size); _dispose = dispose; - _io = 0; + _io = 0; _handle = -1; } @@ -84,7 +85,7 @@ int32 DataStream::size() const { bool DataStream::seek(int32 offset, int whence) { if (_stream) return _stream->seek(offset, whence); - else if ((_handle < 50) || (_handle >= 128)) + else if (!_io->isDataFileChunk(_handle)) return _io->file_getHandle(_handle)->seek(offset, whence); else { _io->seekChunk(_handle, offset, whence); @@ -103,7 +104,7 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { if (_stream) return _stream->read(dataPtr, dataSize); - if ((_handle < 50) || (_handle >= 128)) + if (!_io->isDataFileChunk(_handle)) return _io->file_getHandle(_handle)->read((byte *) dataPtr, dataSize); byte *data = (byte *) dataPtr; @@ -111,7 +112,7 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { while (dataSize > 0x3FFF) { _io->readChunk(_handle, (byte *) data, 0x3FFF); dataSize -= 0x3FFF; - data += 0x3FFF; + data += 0x3FFF; haveRead += 0x3FFF; } _io->readChunk(_handle, (byte *) data, dataSize); @@ -121,11 +122,10 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { DataIO::DataIO(GobEngine *vm) : _vm(vm) { for (int i = 0; i < MAX_DATA_FILES; i++) { - _dataFiles[i] = 0; - _numDataChunks[i] = 0; + _dataFiles[i] = 0; + _numDataChunks[i] = 0; _dataFileHandles[i] = -1; } - _packedSize = 0; } DataIO::~DataIO() { @@ -136,6 +136,46 @@ DataIO::~DataIO() { } } +bool DataIO::isDataFileChunk(int16 handle) const { + return (handle >= 50) && (handle < 128); +} + +bool DataIO::isPacked(int16 handle) const { + if (!isDataFileChunk(handle)) + return false; + + return _chunk[getIndex(handle)]->packed != 0; +} + +int DataIO::getFile(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return (handle - 50) / 10; +} + +int DataIO::getSlot(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return (handle - 50) % 10; +} + +int DataIO::getIndex(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return getIndex(getFile(handle), getSlot(handle)); +} + +int DataIO::getIndex(int file, int slot) const { + return file * MAX_SLOT_COUNT + slot; +} + +int16 DataIO::getHandle(int file, int slot) const { + return file * 10 + slot + 50; +} + int32 DataIO::unpackData(byte *src, byte *dest) { uint32 realSize; uint32 counter; @@ -222,13 +262,11 @@ int16 DataIO::file_open(const char *path) { } int16 DataIO::getChunk(const char *chunkName) { - int16 slot; - struct ChunkDesc *dataDesc; - for (int16 file = 0; file < MAX_DATA_FILES; file++) { if (_dataFiles[file] == 0) return -1; + int16 slot; for (slot = 0; slot < MAX_SLOT_COUNT; slot++) if (_chunkPos[file * MAX_SLOT_COUNT + slot] == -1) break; @@ -238,59 +276,55 @@ int16 DataIO::getChunk(const char *chunkName) { return -1; } - dataDesc = _dataFiles[file]; + ChunkDesc *dataDesc = _dataFiles[file]; for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) continue; - _isCurrentSlot[file * MAX_SLOT_COUNT + slot] = false; - _chunkSize[file * MAX_SLOT_COUNT + slot] = dataDesc->size; - _chunkOffset[file * MAX_SLOT_COUNT + slot] = dataDesc->offset; - _chunkPos[file * MAX_SLOT_COUNT + slot] = 0; - return file * 10 + slot + 50; + int index = getIndex(file, slot); + + _isCurrentSlot[index] = false; + _chunk [index] = dataDesc; + _chunkPos [index] = 0; + + return getHandle(file, slot); } } return -1; } char DataIO::freeChunk(int16 handle) { - if ((handle >= 50) && (handle < 128)) { - handle -= 50; - _chunkPos[(handle / 10) * MAX_SLOT_COUNT + (handle % 10)] = -1; + if (isDataFileChunk(handle)) { + _chunkPos[getIndex(handle)] = -1; return 0; } return 1; } int32 DataIO::readChunk(int16 handle, byte *buf, uint16 size) { - int16 file; - int16 slot; - int16 i; - int32 offset; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return -2; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; - int index = file * MAX_SLOT_COUNT + slot; + int file = getFile(handle); + int slot = getSlot(handle); + int index = getIndex(file, slot); - _chunkPos[index] = CLIP(_chunkPos[index], 0, _chunkSize[index]); + _chunkPos[index] = CLIP(_chunkPos[index], 0, _chunk[index]->size); if (!_isCurrentSlot[index]) { - for (i = 0; i < MAX_SLOT_COUNT; i++) + for (int16 i = 0; i < MAX_SLOT_COUNT; i++) _isCurrentSlot[file * MAX_SLOT_COUNT + i] = false; - offset = _chunkOffset[index] + _chunkPos[index]; + int32 offset = _chunk[index]->offset + _chunkPos[index]; - debugC(7, kDebugFileIO, "seek: %d, %d", _chunkOffset[index], _chunkPos[index]); + debugC(7, kDebugFileIO, "seek: %d, %d", _chunk[index]->offset, _chunkPos[index]); file_getHandle(_dataFileHandles[file])->seek(offset, SEEK_SET); } _isCurrentSlot[index] = true; - if ((_chunkPos[index] + size) > (_chunkSize[index])) - size = _chunkSize[index] - _chunkPos[index]; + if ((_chunkPos[index] + size) > (int32) (_chunk[index]->size)) + size = _chunk[index]->size - _chunkPos[index]; file_getHandle(_dataFileHandles[file])->read(buf, size); _chunkPos[index] += size; @@ -298,15 +332,12 @@ int32 DataIO::readChunk(int16 handle, byte *buf, uint16 size) { } int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { - int16 file; - int16 slot; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return -1; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; - int index = file * MAX_SLOT_COUNT + slot; + int file = getFile(handle); + int slot = getSlot(handle); + int index = getIndex(file, slot); _isCurrentSlot[index] = false; if (from == SEEK_SET) @@ -314,50 +345,45 @@ int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { else if (from == SEEK_CUR) _chunkPos[index] += pos; else if (from == SEEK_END) - _chunkPos[index] = _chunkSize[index] - pos; + _chunkPos[index] = _chunk[index]->size - pos; return _chunkPos[index]; } uint32 DataIO::getChunkPos(int16 handle) const { - int16 file; - int16 slot; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return 0xFFFFFFFF; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; + int file = getFile(handle); + int slot = getSlot(handle); return _chunkPos[file * MAX_SLOT_COUNT + slot]; } -int32 DataIO::getChunkSize(const char *chunkName) { - int16 file; - struct ChunkDesc *dataDesc; - int16 slot; - int32 realSize; - - for (file = 0; file < MAX_DATA_FILES; file++) { +int32 DataIO::getChunkSize(const char *chunkName, int32 &packSize) { + for (int16 file = 0; file < MAX_DATA_FILES; file++) { if (_dataFiles[file] == 0) return -1; - dataDesc = _dataFiles[file]; + ChunkDesc *dataDesc = _dataFiles[file]; for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) continue; if (dataDesc->packed == 0) { - _packedSize = -1; + packSize = -1; return dataDesc->size; } - for (slot = 0; slot < MAX_SLOT_COUNT; slot++) + for (int16 slot = 0; slot < MAX_SLOT_COUNT; slot++) _isCurrentSlot[slot] = false; + int32 realSize; + file_getHandle(_dataFileHandles[file])->seek(dataDesc->offset, SEEK_SET); realSize = file_getHandle(_dataFileHandles[file])->readUint32LE(); - _packedSize = dataDesc->size; + packSize = dataDesc->size; + return realSize; } } @@ -365,10 +391,7 @@ int32 DataIO::getChunkSize(const char *chunkName) { } void DataIO::openDataFile(const char *src, bool itk) { - ChunkDesc *dataDesc; char path[128]; - int16 file; - char *fakeTotPtr; strncpy0(path, src, 127); if (!strchr(path, '.')) { @@ -376,6 +399,7 @@ void DataIO::openDataFile(const char *src, bool itk) { strcat(path, ".stk"); } + int16 file; for (file = 0; file < MAX_DATA_FILES; file++) if (_dataFiles[file] == 0) break; @@ -388,17 +412,17 @@ void DataIO::openDataFile(const char *src, bool itk) { if (_dataFileHandles[file] == -1) error("DataIO::openDataFile(): Can't open data file \"%s\"", path); - _dataFileItk[file] = itk; + _dataFileItk [file] = itk; _numDataChunks[file] = file_getHandle(_dataFileHandles[file])->readUint16LE(); debugC(7, kDebugFileIO, "DataChunks: %d [for %s]", _numDataChunks[file], path); - dataDesc = new ChunkDesc[_numDataChunks[file]]; + ChunkDesc *dataDesc = new ChunkDesc[_numDataChunks[file]]; _dataFiles[file] = dataDesc; for (int i = 0; i < _numDataChunks[file]; i++) { file_getHandle(_dataFileHandles[file])->read(dataDesc[i].chunkName, 13); - dataDesc[i].size = file_getHandle(_dataFileHandles[file])->readUint32LE(); + dataDesc[i].size = file_getHandle(_dataFileHandles[file])->readUint32LE(); dataDesc[i].offset = file_getHandle(_dataFileHandles[file])->readUint32LE(); dataDesc[i].packed = file_getHandle(_dataFileHandles[file])->readByte(); @@ -410,7 +434,7 @@ void DataIO::openDataFile(const char *src, bool itk) { Util::replaceChar(dataDesc[i].chunkName, (char) 0x92, 'T'); // Geisha use 0ot files, which are compressed TOT files without the packed byte set. - fakeTotPtr = strstr(dataDesc[i].chunkName, "0OT"); + char *fakeTotPtr = strstr(dataDesc[i].chunkName, "0OT"); if (fakeTotPtr != 0) { strncpy(fakeTotPtr, "TOT", 3); dataDesc[i].packed = 1; @@ -436,33 +460,29 @@ void DataIO::closeDataFile(bool itk) { } byte *DataIO::getUnpackedData(const char *name) { - int32 realSize; - int16 chunk; - byte *unpackBuf; - byte *packBuf; - byte *ptr; - int32 sizeLeft; - - realSize = getChunkSize(name); - if ((_packedSize == -1) || (realSize == -1)) + int32 realSize, packSize; + + realSize = getChunkSize(name, packSize); + + if ((packSize == -1) || (realSize == -1)) return 0; - chunk = getChunk(name); + int16 chunk = getChunk(name); if (chunk == -1) return 0; - unpackBuf = new byte[realSize]; + byte *unpackBuf = new byte[realSize]; assert(unpackBuf); - packBuf = new byte[_packedSize]; + byte *packBuf = new byte[packSize]; assert(packBuf); - sizeLeft = _packedSize; - ptr = packBuf; + int32 sizeLeft = packSize; + byte *ptr = packBuf; while (sizeLeft > 0x4000) { readChunk(chunk, ptr, 0x4000); sizeLeft -= 0x4000; - ptr += 0x4000; + ptr += 0x4000; } readChunk(chunk, ptr, sizeLeft); freeChunk(chunk); @@ -478,9 +498,7 @@ void DataIO::closeData(int16 handle) { } int16 DataIO::openData(const char *path) { - int16 handle; - - handle = getChunk(path); + int16 handle = getChunk(path); if (handle >= 0) return handle; @@ -492,7 +510,6 @@ bool DataIO::existData(const char *path) { return false; int16 handle = openData(path); - if (handle < 0) return false; @@ -510,9 +527,7 @@ DataStream *DataIO::openAsStream(int16 handle, bool dispose) { } uint32 DataIO::getPos(int16 handle) { - uint32 resPos; - - resPos = getChunkPos(handle); + uint32 resPos = getChunkPos(handle); if (resPos != 0xFFFFFFFF) return resPos; @@ -520,9 +535,7 @@ uint32 DataIO::getPos(int16 handle) { } void DataIO::seekData(int16 handle, int32 pos, int16 from) { - int32 resPos; - - resPos = seekChunk(handle, pos, from); + int32 resPos = seekChunk(handle, pos, from); if (resPos != -1) return; @@ -530,9 +543,7 @@ void DataIO::seekData(int16 handle, int32 pos, int16 from) { } int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { - int32 res; - - res = readChunk(handle, buf, size); + int16 res = readChunk(handle, buf, size); if (res >= 0) return res; @@ -541,45 +552,42 @@ int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { int32 DataIO::getDataSize(const char *name) { char buf[128]; - int32 chunkSz; - Common::File file; strncpy0(buf, name, 127); - chunkSz = getChunkSize(buf); - if (chunkSz >= 0) - return chunkSz; + int32 chunkSize, packSize; + + chunkSize = getChunkSize(buf, packSize); + if (chunkSize >= 0) + return chunkSize; + Common::File file; if (!file.open(buf)) error("DataIO::getDataSize(): Can't find data \"%s\"", name); - chunkSz = file.size(); + chunkSize = file.size(); file.close(); - return chunkSz; + return chunkSize; } byte *DataIO::getData(const char *path) { - byte *data; - byte *ptr; - int32 size; - int16 handle; - - data = getUnpackedData(path); + byte *data = getUnpackedData(path); if (data) return data; - size = getDataSize(path); + int32 size = getDataSize(path); + data = new byte[size]; assert(data); - handle = openData(path); + int16 handle = openData(path); - ptr = data; + byte *ptr = data; while (size > 0x4000) { readData(handle, ptr, 0x4000); size -= 0x4000; - ptr += 0x4000; + ptr += 0x4000; } readData(handle, ptr, size); closeData(handle); @@ -588,12 +596,26 @@ byte *DataIO::getData(const char *path) { DataStream *DataIO::getDataStream(const char *path) { if (!existData(path)) + return 0; + + int16 handle = openData(path); + if (handle < 0) return 0; - uint32 size = getDataSize(path); - byte *data = getData(path); + if (isDataFileChunk(handle) && isPacked(handle)) { + // It's a packed chunk in the data files, packed, + // so we have to read it in completely and unpack it + + closeData(handle); + + uint32 size = getDataSize(path); + byte *data = getData(path); + + return new DataStream(data, size); - return new DataStream(data, size); + } else + // Otherwise, we can just return a stream + return openAsStream(handle, true); } } // End of namespace Gob diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index 1f55cac90d..6a86667e1b 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -26,16 +26,14 @@ #ifndef GOB_DATAIO_H #define GOB_DATAIO_H - #include "common/endian.h" - #include "common/file.h" namespace Gob { -#define MAX_FILES 30 -#define MAX_DATA_FILES 8 -#define MAX_SLOT_COUNT 8 +#define MAX_FILES 30 +#define MAX_DATA_FILES 8 +#define MAX_SLOT_COUNT 8 class DataIO; @@ -56,20 +54,20 @@ public: private: DataIO *_io; - int16 _handle; - uint32 _size; - byte *_data; + int16 _handle; + uint32 _size; + byte *_data; + bool _dispose; Common::MemoryReadStream *_stream; - bool _dispose; }; class DataIO { public: struct ChunkDesc { - char chunkName[13]; + char chunkName[13]; uint32 size; uint32 offset; - byte packed; + byte packed; ChunkDesc() : size(0), offset(0), packed(0) { chunkName[0] = 0; } }; @@ -77,10 +75,13 @@ public: void openDataFile(const char *src, bool itk = 0); void closeDataFile(bool itk = 0); + byte *getUnpackedData(const char *name); - void closeData(int16 handle); + + void closeData(int16 handle); int16 openData(const char *path); - bool existData(const char *path); + bool existData(const char *path); + DataStream *openAsStream(int16 handle, bool dispose = false); int32 getDataSize(const char *name); @@ -92,34 +93,47 @@ public: protected: Common::File _filesHandles[MAX_FILES]; - struct ChunkDesc *_dataFiles[MAX_DATA_FILES]; - uint16 _numDataChunks[MAX_DATA_FILES]; - int16 _dataFileHandles[MAX_DATA_FILES]; - bool _dataFileItk[MAX_DATA_FILES]; - int32 _chunkPos[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _chunkOffset[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _chunkSize[MAX_SLOT_COUNT * MAX_DATA_FILES]; - bool _isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _packedSize; + + ChunkDesc *_dataFiles [MAX_DATA_FILES]; + uint16 _numDataChunks [MAX_DATA_FILES]; + int16 _dataFileHandles[MAX_DATA_FILES]; + bool _dataFileItk [MAX_DATA_FILES]; + + ChunkDesc *_chunk [MAX_SLOT_COUNT * MAX_DATA_FILES]; + int32 _chunkPos [MAX_SLOT_COUNT * MAX_DATA_FILES]; + bool _isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES]; class GobEngine *_vm; + bool isDataFileChunk(int16 handle) const; + bool isPacked (int16 handle) const; + + int getFile (int16 handle) const; + int getSlot (int16 handle) const; + int getIndex(int16 handle) const; + + int getIndex (int file, int slot) const; + int16 getHandle(int file, int slot) const; + int16 file_open(const char *path); Common::File *file_getHandle(int16 handle); const Common::File *file_getHandle(int16 handle) const; int16 getChunk(const char *chunkName); - char freeChunk(int16 handle); + char freeChunk(int16 handle); int32 readChunk(int16 handle, byte *buf, uint16 size); int16 seekChunk(int16 handle, int32 pos, int16 from); + uint32 getChunkPos(int16 handle) const; - int32 getChunkSize(const char *chunkName); + + int32 getChunkSize(const char *chunkName, int32 &packSize); uint32 getPos(int16 handle); - void seekData(int16 handle, int32 pos, int16 from); + void seekData(int16 handle, int32 pos, int16 from); + int32 readData(int16 handle, byte *buf, uint16 size); -friend class DataStream; + friend class DataStream; }; } // End of namespace Gob -- cgit v1.2.3