diff options
| -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  | 
