aboutsummaryrefslogtreecommitdiff
path: root/engines/gob
diff options
context:
space:
mode:
authorSven Hesse2011-08-26 01:47:25 +0200
committerSven Hesse2011-08-26 01:53:16 +0200
commitc57fd31246412aaa3698210dc0871ad42cf1efbb (patch)
tree3955150ce9e54e2d245f8298c2c2ee1cf622882b /engines/gob
parentc9873dae4312be326c04ab1081db6b57da237daa (diff)
downloadscummvm-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.
Diffstat (limited to 'engines/gob')
-rw-r--r--engines/gob/dataio.cpp116
-rw-r--r--engines/gob/dataio.h15
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