From d746282206486223da841605e5798b7eb1359752 Mon Sep 17 00:00:00 2001 From: Matthew Jimenez Date: Sun, 17 Dec 2023 16:14:37 -0600 Subject: [PATCH] ULTIMA8: Read flex file metadata instead of seeking back to the table. --- engines/ultima/ultima8/filesys/flex_file.cpp | 67 +++++++++++-------- engines/ultima/ultima8/filesys/flex_file.h | 15 +++-- .../ultima/ultima8/filesys/u8_save_file.cpp | 2 +- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/engines/ultima/ultima8/filesys/flex_file.cpp b/engines/ultima/ultima8/filesys/flex_file.cpp index 09d2ee62263..a57ff3acdec 100644 --- a/engines/ultima/ultima8/filesys/flex_file.cpp +++ b/engines/ultima/ultima8/filesys/flex_file.cpp @@ -31,25 +31,11 @@ static const int FLEX_TABLE_OFFSET = 0x80; static const int FLEX_HDR_SIZE = 0x52; static const char FLEX_HDR_PAD = 0x1A; -FlexFile::FlexFile(Common::SeekableReadStream *rs) : _rs(rs), _count(0) { +FlexFile::FlexFile(Common::SeekableReadStream *rs) : _rs(rs) { _valid = isFlexFile(_rs); - if (_valid) { - _rs->seek(FLEX_HDR_SIZE + 2); - _count = _rs->readUint32LE(); - } - if (_count > 4095) { - // In practice the largest flex in either Crusader or U8 games has - // 3074 entries, so this seems invalid. - warning("Flex invalid: improbable number of entries %d", _count); - _valid = false; - _count = 0; - } - if (rs->size() < FLEX_TABLE_OFFSET + 8 * _count) { - warning("Flex invalid: stream not long enough for offset table"); - _valid = false; - _count = 0; - } + if (_valid) + _valid = readMetadata(); } FlexFile::~FlexFile() { @@ -76,9 +62,33 @@ bool FlexFile::isFlexFile(Common::SeekableReadStream *rs) { return false; } -uint32 FlexFile::getOffset(uint32 index) { - _rs->seek(FLEX_TABLE_OFFSET + 8 * index); - return _rs->readUint32LE(); +bool FlexFile::readMetadata() { + _rs->seek(FLEX_HDR_SIZE + 2); + uint32 count = _rs->readUint32LE(); + + if (count > 4095) { + // In practice the largest flex in either Crusader or U8 games has + // 3074 entries, so this seems invalid. + warning("Flex invalid: improbable number of entries %d", count); + return false; + } + + if (_rs->size() < FLEX_TABLE_OFFSET + 8 * count) { + warning("Flex invalid: stream not long enough for offset table"); + return false; + } + + _entries.reserve(count); + _rs->seek(FLEX_TABLE_OFFSET); + for (unsigned int i = 0; i < count; ++i) { + FileEntry fe; + fe._offset = _rs->readUint32LE(); + fe._size = _rs->readUint32LE(); + + _entries.push_back(fe); + } + + return true; } Common::SeekableReadStream *FlexFile::getDataSource(uint32 index, bool is_text) { @@ -92,31 +102,30 @@ Common::SeekableReadStream *FlexFile::getDataSource(uint32 index, bool is_text) } uint8 *FlexFile::getObject(uint32 index, uint32 *sizep) { - if (index >= _count) + if (index >= _entries.size()) return nullptr; - uint32 size = getSize(index); + uint32 size = _entries[index]._size; if (size == 0) return nullptr; uint8 *object = new uint8[size]; - uint32 offset = getOffset(index); + uint32 offset = _entries[index]._offset; _rs->seek(offset); _rs->read(object, size); - if (sizep) *sizep = size; + if (sizep) + *sizep = size; return object; } uint32 FlexFile::getSize(uint32 index) const { - if (index >= _count) return 0; + if (index >= _entries.size()) + return 0; - _rs->seek(FLEX_TABLE_OFFSET + 4 + 8 * index); - uint32 length = _rs->readUint32LE(); - - return length; + return _entries[index]._size; } } // End of namespace Ultima8 diff --git a/engines/ultima/ultima8/filesys/flex_file.h b/engines/ultima/ultima8/filesys/flex_file.h index 884922b09ee..8e5282cb740 100644 --- a/engines/ultima/ultima8/filesys/flex_file.h +++ b/engines/ultima/ultima8/filesys/flex_file.h @@ -63,25 +63,32 @@ public: //! In an indexed file this is (probably) the highest index plus one, //! while in a named file it's (probably) the actual count uint32 getCount() const { - return _count; + return _entries.size(); } //! Get the highest index in the file //! Guaranteed to be sufficiently large for a vector that needs to //! store the indexed entries of this file uint32 getIndexCount() const { - return _count; + return _entries.size(); } static bool isFlexFile(Common::SeekableReadStream *rs); protected: Common::SeekableReadStream *_rs; - uint32 _count; bool _valid; + struct FileEntry { + uint32 _offset; + uint32 _size; + FileEntry() : _offset(0), _size(0) {} + }; + + Common::Array _entries; + private: - uint32 getOffset(uint32 index); + bool readMetadata(); }; } // End of namespace Ultima8 diff --git a/engines/ultima/ultima8/filesys/u8_save_file.cpp b/engines/ultima/ultima8/filesys/u8_save_file.cpp index 21980a9e9ed..cf7c8816e70 100644 --- a/engines/ultima/ultima8/filesys/u8_save_file.cpp +++ b/engines/ultima/ultima8/filesys/u8_save_file.cpp @@ -55,7 +55,7 @@ bool U8SaveFile::readMetadata() { for (unsigned int i = 0; i < count; ++i) { uint32 namelen = _rs->readUint32LE(); char *name = new char[namelen]; - _rs->read(name, static_cast(namelen)); + _rs->read(name, namelen); FileEntry fe; fe._size = _rs->readUint32LE();