diff options
author | Sven Hesse | 2011-08-26 01:47:25 +0200 |
---|---|---|
committer | Sven Hesse | 2011-08-26 01:53:16 +0200 |
commit | c57fd31246412aaa3698210dc0871ad42cf1efbb (patch) | |
tree | 3955150ce9e54e2d245f8298c2c2ee1cf622882b | |
parent | c9873dae4312be326c04ab1081db6b57da237daa (diff) | |
download | scummvm-rg350-c57fd31246412aaa3698210dc0871ad42cf1efbb.tar.gz scummvm-rg350-c57fd31246412aaa3698210dc0871ad42cf1efbb.tar.bz2 scummvm-rg350-c57fd31246412aaa3698210dc0871ad42cf1efbb.zip |
GOB: Fix 0OT resource loading, used in Geisha
0OT are compressed TOT files. The compression flag in the STK header
is *not* set, and 0OT files are compressed in chunks, not as a whole.
-rw-r--r-- | engines/gob/dataio.cpp | 116 | ||||
-rw-r--r-- | engines/gob/dataio.h | 15 |
2 files changed, 103 insertions, 28 deletions
diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index a576cf9487..1633a1edb7 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -32,11 +32,11 @@ namespace Gob { -DataIO::File::File() : size(0), offset(0), packed(false), archive(0) { +DataIO::File::File() : size(0), offset(0), compression(0), archive(0) { } -DataIO::File::File(const Common::String &n, uint32 s, uint32 o, bool p, Archive &a) : - name(n), size(s), offset(o), packed(p), archive(&a) { +DataIO::File::File(const Common::String &n, uint32 s, uint32 o, uint8 c, Archive &a) : + name(n), size(s), offset(o), compression(c), archive(&a) { } @@ -71,26 +71,92 @@ void DataIO::getArchiveInfo(Common::Array<ArchiveInfo> &info) const { } } -byte *DataIO::unpack(const byte *src, uint32 srcSize, int32 &size) { - size = READ_LE_UINT32(src); +uint32 DataIO::getSizeChunks(Common::SeekableReadStream &src) { + uint32 size = 0; - byte *data = new byte[size]; + uint32 chunkSize = 2, realSize; + while (chunkSize != 0xFFFF) { + src.skip(chunkSize - 2); + + chunkSize = src.readUint16LE(); + realSize = src.readUint16LE(); + + assert(chunkSize >= 4); + + size += realSize; + } + + assert(!src.eos()); + + src.seek(0); + + return size; +} + +byte *DataIO::unpack(Common::SeekableReadStream &src, int32 &size, uint8 compression, bool useMalloc) { + assert((compression == 1) || (compression == 2)); + + if (compression == 1) + size = src.readUint32LE(); + else if (compression == 2) + size = getSizeChunks(src); + + assert(size > 0); + + byte *data = 0; + if (useMalloc) + data = (byte *) malloc(size); + else + data = new byte[size]; + + if (compression == 1) + unpackChunk(src, data, size); + else if (compression == 2) + unpackChunks(src, data, size); - Common::MemoryReadStream srcStream(src + 4, srcSize - 4); - unpack(srcStream, data, size); return data; } -Common::SeekableReadStream *DataIO::unpack(Common::SeekableReadStream &src) { - uint32 size = src.readUint32LE(); +byte *DataIO::unpack(const byte *src, uint32 srcSize, int32 &size, uint8 compression) { + Common::MemoryReadStream srcStream(src, srcSize); - byte *data = (byte *) malloc(size); + return unpack(srcStream, size, compression, false); +} + +Common::SeekableReadStream *DataIO::unpack(Common::SeekableReadStream &src, uint8 compression) { + int32 size; + + byte *data = unpack(src, size, compression, true); + if (!data) + return 0; - unpack(src, data, size); return new Common::MemoryReadStream(data, size, DisposeAfterUse::YES); } -void DataIO::unpack(Common::SeekableReadStream &src, byte *dest, uint32 size) { +void DataIO::unpackChunks(Common::SeekableReadStream &src, byte *dest, uint32 size) { + uint32 chunkSize = 0, realSize; + while (chunkSize != 0xFFFF) { + uint32 pos = src.pos(); + + chunkSize = src.readUint16LE(); + realSize = src.readUint16LE(); + + assert(chunkSize >= 4); + assert(size >= realSize); + + src.skip(2); + + unpackChunk(src, dest, realSize); + + if (chunkSize != 0xFFFF) + src.seek(pos + chunkSize + 2); + + size -= realSize; + dest += realSize; + } +} + +void DataIO::unpackChunk(Common::SeekableReadStream &src, byte *dest, uint32 size) { byte *tmpBuf = new byte[4114]; assert(tmpBuf); @@ -194,9 +260,9 @@ DataIO::Archive *DataIO::openArchive(const Common::String &name) { archive->file.read(fileName, 13); fileName[13] = '\0'; - file.size = archive->file.readUint32LE(); - file.offset = archive->file.readUint32LE(); - file.packed = archive->file.readByte() != 0; + file.size = archive->file.readUint32LE(); + file.offset = archive->file.readUint32LE(); + file.compression = archive->file.readByte() != 0; // Replacing cyrillic characters Util::replaceChar(fileName, (char) 0x85, 'E'); @@ -209,8 +275,8 @@ DataIO::Archive *DataIO::openArchive(const Common::String &name) { // Geisha use 0ot files, which are compressed TOT files without the packed byte set. if (file.name.hasSuffix(".0OT")) { - file.name.setChar(file.name.size() - 3, 'T'); - file.packed = true; + file.name.setChar('T', file.name.size() - 3); + file.compression = 2; } file.archive = archive; @@ -254,7 +320,7 @@ int32 DataIO::fileSize(const Common::String &name) { // Try to find the file in the archives File *file = findFile(name); if (file) { - if (!file->packed) + if (file->compression == 0) return file->size; // Sanity checks @@ -264,6 +330,10 @@ int32 DataIO::fileSize(const Common::String &name) { // Read the full, unpacked size file->archive->file.seek(file->offset); + + if (file->compression == 2) + file->archive->file.skip(4); + return file->archive->file.readUint32LE(); } @@ -346,10 +416,10 @@ Common::SeekableReadStream *DataIO::getFile(File &file) { Common::SeekableReadStream *rawData = new Common::SafeSubReadStream(&file.archive->file, file.offset, file.offset + file.size); - if (!file.packed) + if (file.compression == 0) return rawData; - Common::SeekableReadStream *unpackedData = unpack(*rawData); + Common::SeekableReadStream *unpackedData = unpack(*rawData, file.compression); delete rawData; @@ -374,10 +444,10 @@ byte *DataIO::getFile(File &file, int32 &size) { return 0; } - if (!file.packed) + if (file.compression == 0) return rawData; - byte *unpackedData = unpack(rawData, file.size, size); + byte *unpackedData = unpack(rawData, file.size, size, file.compression); delete[] rawData; diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index d95f001097..adf0786389 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -58,8 +58,8 @@ public: Common::SeekableReadStream *getFile(const Common::String &name); byte *getFile(const Common::String &name, int32 &size); - static byte *unpack(const byte *src, uint32 srcSize, int32 &size); - static Common::SeekableReadStream *unpack(Common::SeekableReadStream &src); + static byte *unpack(const byte *src, uint32 srcSize, int32 &size, uint8 compression = 1); + static Common::SeekableReadStream *unpack(Common::SeekableReadStream &src, uint8 compression = 1); private: static const int kMaxArchives = 8; @@ -70,12 +70,12 @@ private: Common::String name; uint32 size; uint32 offset; - bool packed; + uint8 compression; Archive *archive; File(); - File(const Common::String &n, uint32 s, uint32 o, bool p, Archive &a); + File(const Common::String &n, uint32 s, uint32 o, uint8 c, Archive &a); }; typedef Common::HashMap<Common::String, File, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap; @@ -99,7 +99,12 @@ private: Common::SeekableReadStream *getFile(File &file); byte *getFile(File &file, int32 &size); - static void unpack(Common::SeekableReadStream &src, byte *dest, uint32 size); + static byte *unpack(Common::SeekableReadStream &src, int32 &size, uint8 compression, bool useMalloc); + + static uint32 getSizeChunks(Common::SeekableReadStream &src); + + static void unpackChunks(Common::SeekableReadStream &src, byte *dest, uint32 size); + static void unpackChunk (Common::SeekableReadStream &src, byte *dest, uint32 size); }; } // End of namespace Gob |