[Scummvm-git-logs] scummvm master -> aaaf0a560dba8d8e0bbb53506db958508ad35d13

phcoder noreply at scummvm.org
Tue Nov 29 03:30:43 UTC 2022


This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
c778a7a310 SKY: Make RNC_SIGNATURE from macro to const
074888e6b8 COMMON: Move RNC decoder from sky to common
c5373134d2 COMMON: Uplift rnc decoder from toon to common
baf09ee417 DREAMWEB: Implement RNCA archive
b66d3ec688 COMMON: Implement ConcatReadStream
cf29e594e1 DREAMWEB: Support playing from compressed installer
aaaf0a560d DREAMWEB: Add entry for international floppy release (compressed)


Commit: c778a7a310efa0e004454e5a2a0d46aa0a86dd1b
    https://github.com/scummvm/scummvm/commit/c778a7a310efa0e004454e5a2a0d46aa0a86dd1b
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-29T04:30:36+01:00

Commit Message:
SKY: Make RNC_SIGNATURE from macro to const

Changed paths:
    engines/sky/rnc_deco.cpp
    engines/sky/rnc_deco.h


diff --git a/engines/sky/rnc_deco.cpp b/engines/sky/rnc_deco.cpp
index 5880de73605..acbe2e47fc4 100644
--- a/engines/sky/rnc_deco.cpp
+++ b/engines/sky/rnc_deco.cpp
@@ -177,7 +177,7 @@ int32 RncDecoder::unpackM1(const void *input, void *output, uint16 key) {
 	_bitCount = 0;
 
 	//Check for "RNC "
-	if (READ_BE_UINT32(inputptr) != RNC_SIGNATURE)
+	if (READ_BE_UINT32(inputptr) != kRncSignature)
 		return NOT_PACKED;
 
 	inputptr += 4;
diff --git a/engines/sky/rnc_deco.h b/engines/sky/rnc_deco.h
index dc8d77c519d..f3bfd7f8073 100644
--- a/engines/sky/rnc_deco.h
+++ b/engines/sky/rnc_deco.h
@@ -23,9 +23,6 @@
 #define SKY_RNC_DECO_H
 
 
-
-#define RNC_SIGNATURE   0x524E4301 // "RNC\001"
-
 namespace Sky {
 
 class RncDecoder {
@@ -48,6 +45,8 @@ public:
 	~RncDecoder();
 	int32 unpackM1(const void *input, void *output, uint16 key);
 
+	static const uint32 kRncSignature = 0x524E4301; // "RNC\001"
+
 protected:
 	void initCrc();
 	uint16 crcBlock(const uint8 *block, uint32 size);


Commit: 074888e6b8246f5f4820770d6fb9e835a18a1a4a
    https://github.com/scummvm/scummvm/commit/074888e6b8246f5f4820770d6fb9e835a18a1a4a
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-29T04:30:36+01:00

Commit Message:
COMMON: Move RNC decoder from sky to common

RNC is a common packing algorithm used also in Toonstruck and installer of
Dreamweb floppy.

Changed paths:
  A common/rnc_deco.cpp
  A common/rnc_deco.h
  R engines/sky/rnc_deco.cpp
  R engines/sky/rnc_deco.h
    common/module.mk
    engines/sky/disk.h
    engines/sky/module.mk


diff --git a/common/module.mk b/common/module.mk
index 707c323d98a..42720db2a0d 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -35,6 +35,7 @@ MODULE_OBJS := \
 	random.o \
 	rational.o \
 	rendermode.o \
+	rnc_deco.o \
 	str.o \
 	stream.o \
 	streamdebug.o \
diff --git a/engines/sky/rnc_deco.cpp b/common/rnc_deco.cpp
similarity index 98%
rename from engines/sky/rnc_deco.cpp
rename to common/rnc_deco.cpp
index acbe2e47fc4..9eaefafee15 100644
--- a/engines/sky/rnc_deco.cpp
+++ b/common/rnc_deco.cpp
@@ -21,9 +21,9 @@
 
 
 #include "common/endian.h"
-#include "sky/rnc_deco.h"
+#include "common/rnc_deco.h"
 
-namespace Sky {
+namespace Common {
 
 //return codes
 #define NOT_PACKED	0
@@ -258,4 +258,4 @@ int32 RncDecoder::unpackM1(const void *input, void *output, uint16 key) {
 	return unpackLen;
 }
 
-} // End of namespace Sky
+} // End of namespace Common
diff --git a/engines/sky/rnc_deco.h b/common/rnc_deco.h
similarity index 89%
rename from engines/sky/rnc_deco.h
rename to common/rnc_deco.h
index f3bfd7f8073..4bb147c1a85 100644
--- a/engines/sky/rnc_deco.h
+++ b/common/rnc_deco.h
@@ -19,12 +19,13 @@
  *
  */
 
-#ifndef SKY_RNC_DECO_H
-#define SKY_RNC_DECO_H
+#ifndef COMMON_RNC_DECO_H
+#define COMMON_RNC_DECO_H
 
 
-namespace Sky {
+namespace Common {
 
+// Decoder for RNC (Rob Norton Computing) ProPack compression.
 class RncDecoder {
 
 protected:
@@ -56,6 +57,6 @@ protected:
 
 };
 
-} // End of namespace Sky
+} // End of namespace Common
 
 #endif
diff --git a/engines/sky/disk.h b/engines/sky/disk.h
index a283acc5bc6..f58cef5f94c 100644
--- a/engines/sky/disk.h
+++ b/engines/sky/disk.h
@@ -24,7 +24,7 @@
 
 
 #include "common/scummsys.h"
-#include "sky/rnc_deco.h"
+#include "common/rnc_deco.h"
 
 #define MAX_FILES_IN_LIST 60
 
@@ -62,7 +62,7 @@ protected:
 	uint32 _dinnerTableEntries;
 	uint8 *_dinnerTableArea;
 	Common::File *_dataDiskHandle;
-	RncDecoder _rncDecoder;
+	Common::RncDecoder _rncDecoder;
 
 	uint16 _buildList[MAX_FILES_IN_LIST];
 	uint32 _loadedFilesList[MAX_FILES_IN_LIST];
diff --git a/engines/sky/module.mk b/engines/sky/module.mk
index 4dd4d20b0b9..21517d8edfc 100644
--- a/engines/sky/module.mk
+++ b/engines/sky/module.mk
@@ -12,7 +12,6 @@ MODULE_OBJS := \
 	logic.o \
 	metaengine.o \
 	mouse.o \
-	rnc_deco.o \
 	screen.o \
 	sky.o \
 	sound.o \


Commit: c5373134d24c60a83cb997dfe64992b0e49fd413
    https://github.com/scummvm/scummvm/commit/c5373134d24c60a83cb997dfe64992b0e49fd413
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-29T04:30:36+01:00

Commit Message:
COMMON: Uplift rnc decoder from toon to common

Toon has a RNC implementation with 2 differences from the one taken from SKY:

1. Protection against overread. Add it to common version and adjust callers
   in sky.
2. Lack of key parameter for obfuscation. We ignore it anyway and don't
   support obfuscation, so delete it in common version as well

Changed paths:
    common/rnc_deco.cpp
    common/rnc_deco.h
    engines/sky/disk.cpp
    engines/toon/hotspot.cpp
    engines/toon/picture.cpp
    engines/toon/tools.cpp
    engines/toon/tools.h


diff --git a/common/rnc_deco.cpp b/common/rnc_deco.cpp
index 9eaefafee15..d4cdadcda9a 100644
--- a/common/rnc_deco.cpp
+++ b/common/rnc_deco.cpp
@@ -37,6 +37,13 @@ namespace Common {
 
 RncDecoder::RncDecoder() {
 	initCrc();
+
+	_bitBuffl = 0;
+	_bitBuffh = 0;
+	_bitCount = 0;
+	_srcPtr = nullptr;
+	_dstPtr = nullptr;
+	_inputByteLeft = 0;
 }
 
 RncDecoder::~RncDecoder() { }
@@ -94,7 +101,16 @@ uint16 RncDecoder::inputBits(uint8 amount) {
 		newBitBuffl >>= newBitCount;
 		newBitBuffl |= remBits;
 		_srcPtr += 2;
-		newBitBuffh = READ_LE_UINT16(_srcPtr);
+
+		// added some more check here to prevent reading in the buffer
+		// if there are no bytes anymore.
+		_inputByteLeft -= 2;
+		if (_inputByteLeft <= 0)
+			newBitBuffh = 0;
+		else if (_inputByteLeft == 1)
+			newBitBuffh = *_srcPtr;
+		else
+			newBitBuffh = READ_LE_UINT16(_srcPtr);
 		amount -= newBitCount;
 		newBitCount = 16 - amount;
 	}
@@ -161,7 +177,18 @@ uint16 RncDecoder::inputValue(uint16 *table) {
 	return value;
 }
 
-int32 RncDecoder::unpackM1(const void *input, void *output, uint16 key) {
+int RncDecoder::getbit() {
+	if (_bitCount == 0) {
+		_bitBuffl = *_srcPtr++;
+		_bitCount = 8;
+	}
+	byte temp = (_bitBuffl & 0x80) >> 7;
+	_bitBuffl <<= 1;
+	_bitCount--;
+	return temp;
+}
+
+int32 RncDecoder::unpackM1(const void *input, uint inputSize, void *output) {
 	uint8 *outputLow, *outputHigh;
 	const uint8 *inputHigh, *inputptr = (const uint8 *)input;
 
@@ -172,12 +199,13 @@ int32 RncDecoder::unpackM1(const void *input, void *output, uint16 key) {
 	uint16 crcPacked = 0;
 
 
+	_inputByteLeft = inputSize;
 	_bitBuffl = 0;
 	_bitBuffh = 0;
 	_bitCount = 0;
 
 	//Check for "RNC "
-	if (READ_BE_UINT32(inputptr) != kRncSignature)
+	if (READ_BE_UINT32(inputptr) != kRnc1Signature)
 		return NOT_PACKED;
 
 	inputptr += 4;
@@ -210,6 +238,8 @@ int32 RncDecoder::unpackM1(const void *input, void *output, uint16 key) {
 		_srcPtr = (_dstPtr-packLen);
 	}
 
+	_inputByteLeft -= HEADER_LEN;
+
 	_dstPtr = (uint8 *)output;
 	_bitCount = 0;
 
@@ -228,11 +258,28 @@ int32 RncDecoder::unpackM1(const void *input, void *output, uint16 key) {
 			uint32 inputOffset;
 
 			if (inputLength) {
+				if (_inputByteLeft < (int32) inputLength || inputLength > 0xff000000) {
+					return NOT_PACKED;
+				}
 				memcpy(_dstPtr, _srcPtr, inputLength); //memcpy is allowed here
 				_dstPtr += inputLength;
 				_srcPtr += inputLength;
-				uint16 a = READ_LE_UINT16(_srcPtr);
-				uint16 b = READ_LE_UINT16(_srcPtr + 2);
+				_inputByteLeft -= inputLength;
+				uint16 a;
+				if (_inputByteLeft <= 0)
+					a = 0;
+				else if (_inputByteLeft == 1)
+					a = *_srcPtr;
+				else
+					a = READ_LE_UINT16(_srcPtr);
+
+				uint16 b;
+				if (_inputByteLeft <= 2)
+					b = 0;
+				else if (_inputByteLeft == 3)
+					b = *(_srcPtr + 2);
+				else
+					b = READ_LE_UINT16(_srcPtr + 2);
 
 				_bitBuffl &= ((1 << _bitCount) - 1);
 				_bitBuffl |= (a << _bitCount);
@@ -258,4 +305,124 @@ int32 RncDecoder::unpackM1(const void *input, void *output, uint16 key) {
 	return unpackLen;
 }
 
+int32 RncDecoder::unpackM2(const void *input, void *output) {
+	const uint8 *inputptr = (const uint8 *)input;
+
+	uint32 unpackLen = 0;
+	uint32 packLen = 0;
+	uint16 crcUnpacked = 0;
+	uint16 crcPacked = 0;
+
+	_bitBuffl = 0;
+	_bitCount = 0;
+
+	// Check for "RNC "
+	if (READ_BE_UINT32(inputptr) != kRnc2Signature)
+		return NOT_PACKED;
+
+	inputptr += 4;
+
+	// Read unpacked/packed file length
+	unpackLen = READ_BE_UINT32(inputptr);
+	inputptr += 4;
+	packLen = READ_BE_UINT32(inputptr);
+	inputptr += 4;
+
+	// Read CRCs
+	crcUnpacked = READ_BE_UINT16(inputptr);
+	inputptr += 2;
+	crcPacked = READ_BE_UINT16(inputptr);
+	inputptr += 2;
+	inputptr = (inputptr + HEADER_LEN - 16);
+
+	if (crcBlock(inputptr, packLen) != crcPacked)
+		return PACKED_CRC;
+
+	inputptr = (((const uint8 *)input) + HEADER_LEN);
+	_srcPtr = inputptr;
+	_dstPtr = (uint8 *)output;
+
+	uint16 ofs, len;
+	byte ofs_hi, ofs_lo;
+
+	len = 0;
+	ofs_hi = 0;
+	ofs_lo = 0;
+
+	getbit();
+	getbit();
+
+	while (1) {
+
+		bool loadVal = false;
+
+		while (getbit() == 0)
+			*_dstPtr++ = *_srcPtr++;
+
+		len = 2;
+		ofs_hi = 0;
+		if (getbit() == 0) {
+			len = (len << 1) | getbit();
+			if (getbit() == 1) {
+				len--;
+				len = (len << 1) | getbit();
+				if (len == 9) {
+					len = 4;
+					while (len--)
+						ofs_hi = (ofs_hi << 1) | getbit();
+					len = (ofs_hi + 3) * 4;
+					while (len--)
+						*_dstPtr++ = *_srcPtr++;
+					continue;
+				}
+			}
+			loadVal = true;
+		} else {
+			if (getbit() == 1) {
+				len++;
+				if (getbit() == 1) {
+					len = *_srcPtr++;
+					if (len == 0) {
+						if (getbit() == 1)
+							continue;
+						else
+							break;
+					}
+					len += 8;
+				}
+				loadVal = true;
+			} else {
+				loadVal = false;
+			}
+		}
+
+		if (loadVal) {
+			if (getbit() == 1) {
+				ofs_hi = (ofs_hi << 1) | getbit();
+				if (getbit() == 1) {
+					ofs_hi = ((ofs_hi << 1) | getbit()) | 4;
+					if (getbit() == 0)
+						ofs_hi = (ofs_hi << 1) | getbit();
+				} else if (ofs_hi == 0) {
+					ofs_hi = 2 | getbit();
+				}
+			}
+		}
+
+		ofs_lo = *_srcPtr++;
+		ofs = (ofs_hi << 8) | ofs_lo;
+		while (len--) {
+			*_dstPtr = *(byte *)(_dstPtr - ofs - 1);
+			_dstPtr++;
+		}
+
+	}
+
+	if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked)
+		return UNPACKED_CRC;
+
+	// all is done..return the amount of unpacked bytes
+	return unpackLen;
+}
+
 } // End of namespace Common
diff --git a/common/rnc_deco.h b/common/rnc_deco.h
index 4bb147c1a85..87d74558027 100644
--- a/common/rnc_deco.h
+++ b/common/rnc_deco.h
@@ -41,12 +41,16 @@ protected:
 	const uint8 *_srcPtr;
 	uint8 *_dstPtr;
 
+	int32 _inputByteLeft;
+
 public:
 	RncDecoder();
 	~RncDecoder();
-	int32 unpackM1(const void *input, void *output, uint16 key);
+	int32 unpackM1(const void *input, uint inputSize, void *output);
+	int32 unpackM2(const void *input, void *output);
 
-	static const uint32 kRncSignature = 0x524E4301; // "RNC\001"
+	static const uint32 kRnc1Signature = 0x524E4301; // "RNC\001"
+	static const uint32 kRnc2Signature = 0x524E4302; // "RNC\002"
 
 protected:
 	void initCrc();
@@ -54,7 +58,7 @@ protected:
 	uint16 inputBits(uint8 amount);
 	void makeHufftable(uint16 *table);
 	uint16 inputValue(uint16 *table);
-
+	int getbit();
 };
 
 } // End of namespace Common
diff --git a/engines/sky/disk.cpp b/engines/sky/disk.cpp
index 35fad54772f..6b56735fa5b 100644
--- a/engines/sky/disk.cpp
+++ b/engines/sky/disk.cpp
@@ -132,7 +132,7 @@ uint8 *Disk::loadFile(uint16 fileNr) {
 		if ((fileFlags >> 22) & 0x1) { //do we include the header?
 			// don't return the file's header
 			output = uncompDest;
-			unpackLen = _rncDecoder.unpackM1(input, output, 0);
+			unpackLen = _rncDecoder.unpackM1(input, fileSize - sizeof(DataFileHeader), output);
 		} else {
 #ifdef SCUMM_BIG_ENDIAN
 			// Convert DataFileHeader to BE (it only consists of 16 bit words)
@@ -143,7 +143,7 @@ uint8 *Disk::loadFile(uint16 fileNr) {
 
 			memcpy(uncompDest, fileDest, sizeof(DataFileHeader));
 			output = uncompDest + sizeof(DataFileHeader);
-			unpackLen = _rncDecoder.unpackM1(input, output, 0);
+			unpackLen = _rncDecoder.unpackM1(input, fileSize - sizeof(DataFileHeader), output);
 			if (unpackLen)
 				unpackLen += sizeof(DataFileHeader);
 		}
diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp
index eee7468f328..aeedbd4dd20 100644
--- a/engines/toon/hotspot.cpp
+++ b/engines/toon/hotspot.cpp
@@ -20,9 +20,9 @@
  */
 
 #include "common/debug.h"
+#include "common/rnc_deco.h"
 
 #include "toon/hotspot.h"
-#include "toon/tools.h"
 
 namespace Toon {
 
@@ -123,10 +123,10 @@ bool Hotspots::loadRif(const Common::String &rifName, const Common::String &addi
 	_items = new HotspotData[_numItems];
 
 	// RIFs are compressed in RNC1
-	RncDecoder decoder;
+	Common::RncDecoder decoder;
 	decoder.unpackM1(rifData, size, _items);
 	if (rifsize2) {
-		RncDecoder decoder2;
+		Common::RncDecoder decoder2;
 		decoder2.unpackM1(rifData2 , size2, _items + (rifsize >> 9));
 		for (int32 i = 0; i < (rifsize2 >> 9); i++) {
 			HotspotData *hot = _items + (rifsize >> 9) + i;
diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp
index 76cc506ce45..96bab7dc395 100644
--- a/engines/toon/picture.cpp
+++ b/engines/toon/picture.cpp
@@ -24,6 +24,7 @@
 
 #include "common/debug.h"
 #include "common/rect.h"
+#include "common/rnc_deco.h"
 #include "common/stack.h"
 
 namespace Toon {
@@ -92,7 +93,7 @@ bool Picture::loadPicture(const Common::String &file) {
 		return true;
 	}
 	case kCompRNC1: {
-		Toon::RncDecoder rnc;
+		Common::RncDecoder rnc;
 
 		// allocate enough place
 		uint32 decSize = READ_BE_UINT32(fileData + 4);
@@ -111,7 +112,7 @@ bool Picture::loadPicture(const Common::String &file) {
 		return true;
 	}
 	case kCompRNC2: {
-		Toon::RncDecoder rnc;
+		Common::RncDecoder rnc;
 
 		// allocate enough place
 		uint32 decSize = READ_BE_UINT32(fileData + 4);
diff --git a/engines/toon/tools.cpp b/engines/toon/tools.cpp
index 3063168a83c..61b30114c6a 100644
--- a/engines/toon/tools.cpp
+++ b/engines/toon/tools.cpp
@@ -123,421 +123,4 @@ uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize) {
 	return (dstp - dst);
 }
 
-//return codes
-#define NOT_PACKED  0
-#define PACKED_CRC  -1
-#define UNPACKED_CRC    -2
-
-//other defines
-#define TABLE_SIZE  (16 * 8)
-#define MIN_LENGTH  2
-#define HEADER_LEN  18
-
-RncDecoder::RncDecoder() {
-	initCrc();
-
-	_bitBuffl = 0;
-	_bitBuffh = 0;
-	_bitCount = 0;
-	_srcPtr = nullptr;
-	_dstPtr = nullptr;
-	_inputByteLeft = 0;
-}
-
-RncDecoder::~RncDecoder() { }
-
-void RncDecoder::initCrc() {
-	debugC(1, kDebugTools, "initCrc()");
-
-	uint16 cnt = 0;
-	uint16 tmp1 = 0;
-	uint16 tmp2 = 0;
-
-	for (tmp2 = 0; tmp2 < 0x100; tmp2++) {
-		tmp1 = tmp2;
-		for (cnt = 8; cnt > 0; cnt--) {
-			if (tmp1 % 2) {
-				tmp1 >>= 1;
-				tmp1 ^= 0x0a001;
-			} else
-				tmp1 >>= 1;
-		}
-		_crcTable[tmp2] = tmp1;
-	}
-}
-
-//calculate 16 bit crc of a block of memory
-uint16 RncDecoder::crcBlock(const uint8 *block, uint32 size) {
-	debugC(1, kDebugTools, "crcBlock(block, %d)", size);
-
-	uint16 crc = 0;
-	uint8 *crcTable8 = (uint8 *)_crcTable; //make a uint8* to crc_table
-	uint8 tmp;
-	uint32 i;
-
-	for (i = 0; i < size; i++) {
-		tmp = *block++;
-		crc ^= tmp;
-		tmp = (uint8)((crc >> 8) & 0x00FF);
-		crc &= 0x00FF;
-		crc = *(uint16 *)&crcTable8[crc << 1];
-		crc ^= tmp;
-	}
-
-	return crc;
-}
-
-uint16 RncDecoder::inputBits(uint8 amount) {
-	debugC(5, kDebugTools, "inputBits(%d)", amount);
-
-	uint16 newBitBuffh = _bitBuffh;
-	uint16 newBitBuffl = _bitBuffl;
-	int16 newBitCount = _bitCount;
-	uint16 remBits, returnVal;
-
-	returnVal = ((1 << amount) - 1) & newBitBuffl;
-	newBitCount -= amount;
-
-	if (newBitCount < 0) {
-		newBitCount += amount;
-		remBits = (newBitBuffh << (16 - newBitCount));
-		newBitBuffh >>= newBitCount;
-		newBitBuffl >>= newBitCount;
-		newBitBuffl |= remBits;
-		_srcPtr += 2;
-
-		// added some more check here to prevent reading in the buffer
-		// if there are no bytes anymore.
-		_inputByteLeft -= 2;
-		if (_inputByteLeft <= 0)
-			newBitBuffh = 0;
-		else if (_inputByteLeft == 1)
-			newBitBuffh = *_srcPtr;
-		else
-			newBitBuffh = READ_LE_UINT16(_srcPtr);
-		amount -= newBitCount;
-		newBitCount = 16 - amount;
-	}
-	remBits = (newBitBuffh << (16 - amount));
-	_bitBuffh = newBitBuffh >> amount;
-	_bitBuffl = (newBitBuffl >> amount) | remBits;
-	_bitCount = (uint8)newBitCount;
-
-	return returnVal;
-}
-
-void RncDecoder::makeHufftable(uint16 *table) {
-	debugC(1, kDebugTools, "makeHufftable(table)");
-
-	uint16 bitLength, i, j;
-	uint16 numCodes = inputBits(5);
-
-	if (!numCodes)
-		return;
-
-	uint8 huffLength[16];
-	for (i = 0; i < numCodes; i++)
-		huffLength[i] = (uint8)(inputBits(4) & 0x00FF);
-
-	uint16 huffCode = 0;
-
-	for (bitLength = 1; bitLength < 17; bitLength++) {
-		for (i = 0; i < numCodes; i++) {
-			if (huffLength[i] == bitLength) {
-				*table++ = (1 << bitLength) - 1;
-
-				uint16 b = huffCode >> (16 - bitLength);
-				uint16 a = 0;
-
-				for (j = 0; j < bitLength; j++)
-					a |= ((b >> j) & 1) << (bitLength - j - 1);
-				*table++ = a;
-
-				*(table + 0x1e) = (huffLength[i] << 8) | (i & 0x00FF);
-				huffCode += 1 << (16 - bitLength);
-			}
-		}
-	}
-}
-
-uint16 RncDecoder::inputValue(uint16 *table) {
-	debugC(5, kDebugTools, "inputValue(table)");
-
-	uint16 valOne, valTwo, value = _bitBuffl;
-
-	do {
-		valTwo = (*table++) & value;
-		valOne = *table++;
-	} while (valOne != valTwo);
-
-	value = *(table + 0x1e);
-	inputBits((uint8)((value >> 8) & 0x00FF));
-	value &= 0x00FF;
-
-	if (value >= 2) {
-		value--;
-		valOne = inputBits((uint8)value & 0x00FF);
-		valOne |= (1 << value);
-		value = valOne;
-	}
-
-	return value;
-}
-
-int RncDecoder::getbit() {
-	debugC(6, kDebugTools, "getbits()");
-
-	if (_bitCount == 0) {
-		_bitBuffl = *_srcPtr++;
-		_bitCount = 8;
-	}
-	byte temp = (_bitBuffl & 0x80) >> 7;
-	_bitBuffl <<= 1;
-	_bitCount--;
-	return temp;
-}
-
-int32 RncDecoder::unpackM1(const void *input, uint16 inputSize, void *output) {
-	debugC(1, kDebugTools, "unpackM1(input, output)");
-
-	uint8 *outputLow, *outputHigh;
-	const uint8 *inputHigh, *inputptr = (const uint8 *)input;
-
-	uint32 unpackLen = 0;
-	uint32 packLen = 0;
-	uint16 counts = 0;
-	uint16 crcUnpacked = 0;
-	uint16 crcPacked = 0;
-
-
-	_inputByteLeft = inputSize;
-	_bitBuffl = 0;
-	_bitBuffh = 0;
-	_bitCount = 0;
-
-	//Check for "RNC "
-	if (READ_BE_UINT32(inputptr) != RNC1_SIGNATURE)
-		return NOT_PACKED;
-
-	inputptr += 4;
-
-	// read unpacked/packed file length
-	unpackLen = READ_BE_UINT32(inputptr);
-	inputptr += 4;
-	packLen = READ_BE_UINT32(inputptr);
-	inputptr += 4;
-
-	uint8 blocks = *(inputptr + 5);
-
-	//read CRC's
-	crcUnpacked = READ_BE_UINT16(inputptr);
-	inputptr += 2;
-	crcPacked = READ_BE_UINT16(inputptr);
-	inputptr += 2;
-	inputptr = (inputptr + HEADER_LEN - 16);
-
-	if (crcBlock(inputptr, packLen) != crcPacked)
-		return PACKED_CRC;
-
-	inputptr = (((const uint8 *)input) + HEADER_LEN);
-	_srcPtr = inputptr;
-
-	inputHigh = ((const uint8 *)input) + packLen + HEADER_LEN;
-	outputLow = (uint8 *)output;
-	outputHigh = *(((const uint8 *)input) + 16) + unpackLen + outputLow;
-
-	if (!((inputHigh <= outputLow) || (outputHigh <= inputHigh))) {
-		_srcPtr = inputHigh;
-		_dstPtr = outputHigh;
-		memcpy((_dstPtr - packLen), (_srcPtr - packLen), packLen);
-		_srcPtr = (_dstPtr - packLen);
-	}
-
-	_inputByteLeft -= HEADER_LEN;
-
-	_dstPtr = (uint8 *)output;
-	_bitCount = 0;
-
-
-	_bitBuffl = READ_LE_UINT16(_srcPtr);
-	inputBits(2);
-
-	do {
-		makeHufftable(_rawTable);
-		makeHufftable(_posTable);
-		makeHufftable(_lenTable);
-
-		counts = inputBits(16);
-
-		do {
-			uint32 inputLength = inputValue(_rawTable);
-			uint32 inputOffset;
-
-			if (inputLength) {
-				memcpy(_dstPtr, _srcPtr, inputLength); //memcpy is allowed here
-				_dstPtr += inputLength;
-				_srcPtr += inputLength;
-				_inputByteLeft -= inputLength;
-				uint16 a;
-				if (_inputByteLeft <= 0)
-					a = 0;
-				else if (_inputByteLeft == 1)
-					a = *_srcPtr;
-				else
-					a = READ_LE_UINT16(_srcPtr);
-
-				uint16 b;
-				if (_inputByteLeft <= 2)
-					b = 0;
-				else if (_inputByteLeft == 3)
-					b = *(_srcPtr + 2);
-				else
-					b = READ_LE_UINT16(_srcPtr + 2);
-
-				_bitBuffl &= ((1 << _bitCount) - 1);
-				_bitBuffl |= (a << _bitCount);
-				_bitBuffh = (a >> (16 - _bitCount)) | (b << _bitCount);
-			}
-
-			if (counts > 1) {
-				inputOffset = inputValue(_posTable) + 1;
-				inputLength = inputValue(_lenTable) + MIN_LENGTH;
-
-				// Don't use memcpy here! because input and output overlap.
-				uint8 *tmpPtr = (_dstPtr - inputOffset);
-				while (inputLength--)
-					*_dstPtr++ = *tmpPtr++;
-			}
-		} while (--counts);
-	} while (--blocks);
-
-	if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked)
-		return UNPACKED_CRC;
-
-	// all is done..return the amount of unpacked bytes
-	return unpackLen;
-}
-
-int32 RncDecoder::unpackM2(const void *input, void *output) {
-	debugC(1, kDebugTools, "unpackM2(input, output)");
-
-	const uint8 *inputptr = (const uint8 *)input;
-
-	uint32 unpackLen = 0;
-	uint32 packLen = 0;
-	uint16 crcUnpacked = 0;
-	uint16 crcPacked = 0;
-
-	_bitBuffl = 0;
-	_bitCount = 0;
-
-	//Check for "RNC "
-	if (READ_BE_UINT32(inputptr) != RNC2_SIGNATURE)
-		return NOT_PACKED;
-
-	inputptr += 4;
-
-	// read unpacked/packed file length
-	unpackLen = READ_BE_UINT32(inputptr);
-	inputptr += 4;
-	packLen = READ_BE_UINT32(inputptr);
-	inputptr += 4;
-
-	//read CRC's
-	crcUnpacked = READ_BE_UINT16(inputptr);
-	inputptr += 2;
-	crcPacked = READ_BE_UINT16(inputptr);
-	inputptr += 2;
-	inputptr = (inputptr + HEADER_LEN - 16);
-
-	if (crcBlock(inputptr, packLen) != crcPacked)
-		return PACKED_CRC;
-
-	inputptr = (((const uint8 *)input) + HEADER_LEN);
-	_srcPtr = inputptr;
-	_dstPtr = (uint8 *)output;
-
-	uint16 ofs, len;
-	byte ofs_hi, ofs_lo;
-
-	len = 0;
-	ofs_hi = 0;
-	ofs_lo = 0;
-
-	getbit();
-	getbit();
-
-	while (1) {
-
-		bool loadVal = false;
-
-		while (getbit() == 0)
-			*_dstPtr++ = *_srcPtr++;
-
-		len = 2;
-		ofs_hi = 0;
-		if (getbit() == 0) {
-			len = (len << 1) | getbit();
-			if (getbit() == 1) {
-				len--;
-				len = (len << 1) | getbit();
-				if (len == 9) {
-					len = 4;
-					while (len--)
-						ofs_hi = (ofs_hi << 1) | getbit();
-					len = (ofs_hi + 3) * 4;
-					while (len--)
-						*_dstPtr++ = *_srcPtr++;
-					continue;
-				}
-			}
-			loadVal = true;
-		} else {
-			if (getbit() == 1) {
-				len++;
-				if (getbit() == 1) {
-					len = *_srcPtr++;
-					if (len == 0) {
-						if (getbit() == 1)
-							continue;
-						else
-							break;
-					}
-					len += 8;
-				}
-				loadVal = true;
-			} else {
-				loadVal = false;
-			}
-		}
-
-		if (loadVal) {
-			if (getbit() == 1) {
-				ofs_hi = (ofs_hi << 1) | getbit();
-				if (getbit() == 1) {
-					ofs_hi = ((ofs_hi << 1) | getbit()) | 4;
-					if (getbit() == 0)
-						ofs_hi = (ofs_hi << 1) | getbit();
-				} else if (ofs_hi == 0) {
-					ofs_hi = 2 | getbit();
-				}
-			}
-		}
-
-		ofs_lo = *_srcPtr++;
-		ofs = (ofs_hi << 8) | ofs_lo;
-		while (len--) {
-			*_dstPtr = *(byte *)(_dstPtr - ofs - 1);
-			_dstPtr++;
-		}
-
-	}
-
-	if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked)
-		return UNPACKED_CRC;
-
-	// all is done..return the amount of unpacked bytes
-	return unpackLen;
-}
-
 } // End of namespace Toon
diff --git a/engines/toon/tools.h b/engines/toon/tools.h
index 2358fe1bb8a..7779ab984ac 100644
--- a/engines/toon/tools.h
+++ b/engines/toon/tools.h
@@ -25,9 +25,6 @@
 #include "common/scummsys.h"
 #include "common/endian.h"
 
-#define RNC1_SIGNATURE   0x524E4301 // "RNC\001"
-#define RNC2_SIGNATURE   0x524E4302 // "RNC\002"
-
 namespace Toon {
 
 const uint32 kCompLZSS = 0x4C5A5353;
@@ -38,38 +35,6 @@ const uint32 kCompRNC2 = 0x524E4302;
 uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize);
 uint32 decompressLZSS(byte *src, byte *dst, int dstsize);
 
-class RncDecoder {
-
-protected:
-	uint16 _rawTable[64];
-	uint16 _posTable[64];
-	uint16 _lenTable[64];
-	uint16 _crcTable[256];
-
-	uint16 _bitBuffl;
-	uint16 _bitBuffh;
-	uint8 _bitCount;
-
-	const uint8 *_srcPtr;
-	uint8 *_dstPtr;
-
-	int16 _inputByteLeft;
-
-public:
-	RncDecoder();
-	~RncDecoder();
-	int32 unpackM1(const void *input, uint16 inputSize, void *output);
-	int32 unpackM2(const void *input, void *output);
-
-protected:
-	void initCrc();
-	uint16 crcBlock(const uint8 *block, uint32 size);
-	uint16 inputBits(uint8 amount);
-	void makeHufftable(uint16 *table);
-	uint16 inputValue(uint16 *table);
-	int getbit();
-};
-
 } // End of namespace Toon
 
 #endif


Commit: baf09ee417838d4da518b29ba12fac1082d67f7c
    https://github.com/scummvm/scummvm/commit/baf09ee417838d4da518b29ba12fac1082d67f7c
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-29T04:30:36+01:00

Commit Message:
DREAMWEB: Implement RNCA archive

It's used by floppy installer

Changed paths:
  A engines/dreamweb/rnca_archive.cpp
  A engines/dreamweb/rnca_archive.h
    engines/dreamweb/module.mk


diff --git a/engines/dreamweb/module.mk b/engines/dreamweb/module.mk
index d3c0f48a2a1..4e79b33da4d 100644
--- a/engines/dreamweb/module.mk
+++ b/engines/dreamweb/module.mk
@@ -14,6 +14,7 @@ MODULE_OBJS := \
 	people.o \
 	print.o \
 	rain.o \
+	rnca_archive.o \
 	saveload.o \
 	sound.o \
 	sprite.o \
diff --git a/engines/dreamweb/rnca_archive.cpp b/engines/dreamweb/rnca_archive.cpp
new file mode 100644
index 00000000000..242207db4d5
--- /dev/null
+++ b/engines/dreamweb/rnca_archive.cpp
@@ -0,0 +1,159 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/array.h"
+#include "common/gzio.h"
+#include "common/debug.h"
+#include "common/ptr.h"
+#include "common/substream.h"
+#include "common/memstream.h"
+#include "common/rnc_deco.h"
+#include "common/file.h"
+
+#include "dreamweb/rnca_archive.h"
+
+namespace DreamWeb {
+
+RNCAArchive* RNCAArchive::open(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose) {
+	FileMap files;
+
+	if (stream->readUint32BE() != 0x524e4341)
+		return nullptr;
+
+	uint16 metadataSize1 = stream->readUint16BE();
+	stream->readUint16BE(); // No idea
+	uint16 metadataSize2 = stream->readUint16BE();
+	stream->readByte(); // Always zero
+
+	if (metadataSize1 != metadataSize2 || metadataSize1 < 15)
+		return nullptr;
+
+	int headerlessMetadataSize = metadataSize1 - 11;
+	byte *metadata = new byte[headerlessMetadataSize];
+	stream->read(metadata, headerlessMetadataSize);
+	const byte *eptr = metadata;
+
+	while (eptr < metadata + headerlessMetadataSize - 5) {
+		const byte *ptr = eptr;
+		while (*ptr)
+			ptr++;
+		Common::String fileName((const char *) eptr, ptr - eptr);
+		ptr++;
+		uint32 off = READ_BE_UINT32(ptr);
+		eptr = ptr + 4;
+		files[fileName] = RNCAFileDescriptor(fileName, off);
+	}
+
+	delete[] metadata;
+
+	return new RNCAArchive(files, stream, dispose);
+}
+
+static Common::String translateName(const Common::Path &path) {
+	return Common::normalizePath(path.toString('\\'), '\\');
+}
+
+bool RNCAArchive::hasFile(const Common::Path &path) const {
+	return _files.contains(translateName(path));
+}
+
+int RNCAArchive::listMembers(Common::ArchiveMemberList &list) const {
+	for (FileMap::const_iterator i = _files.begin(), end = _files.end(); i != end; ++i) {
+		list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(i->_key, this)));
+	}
+
+	return _files.size();
+}
+
+const Common::ArchiveMemberPtr RNCAArchive::getMember(const Common::Path &path) const {
+	Common::String translated = translateName(path);
+	if (!_files.contains(translated))
+		return nullptr;
+
+	return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(_files.getVal(translated)._fileName, this));
+}
+
+// TODO: Make streams stay valid after destruction of archive
+Common::SeekableReadStream *RNCAArchive::createReadStreamForMember(const Common::Path &path) const {
+	Common::String translated = translateName(path);
+	if (!_files.contains(translated))
+		return nullptr;
+	const RNCAFileDescriptor& desc = _files.getVal(translated);
+	if (_cache.contains(desc._fileName)) {
+		const Common::SharedPtr<CacheEntry> &entry = _cache[desc._fileName];
+		if (entry->is_error) {
+			return nullptr;
+		}
+		return new Common::MemoryReadStream(entry->contents, entry->size, DisposeAfterUse::NO);
+	}
+
+	_stream->seek(desc._fileDataOffset);
+
+	if (_stream->readUint32BE() != Common::RncDecoder::kRnc1Signature) {
+		_cache[desc._fileName] = CacheEntry::error();
+		return nullptr;
+	}
+
+	// Read unpacked/packed file length
+	uint32 unpackLen = _stream->readUint32BE();
+	uint32 packLen = _stream->readUint32BE();
+
+	if (unpackLen > 0x7ffff000 || packLen > 0x7ffff000) {
+		_cache[desc._fileName] = CacheEntry::error();
+		debug("Header error for %s", desc._fileName.c_str());
+		return nullptr;
+	}
+
+	// Rewind back the header
+	_stream->seek(desc._fileDataOffset);
+	packLen += 0x12;
+
+	byte *compressedBuffer = new byte[packLen];
+	if (_stream->read(compressedBuffer, packLen) != packLen) {
+		_cache[desc._fileName] = CacheEntry::error();
+		debug("Read error for %s", desc._fileName.c_str());
+		return nullptr;		
+	}
+	byte *uncompressedBuffer = new byte[unpackLen];
+
+	Common::RncDecoder rnc;
+	
+	if (rnc.unpackM1(compressedBuffer, packLen, uncompressedBuffer) != (int32) unpackLen) {
+		_cache[desc._fileName] = CacheEntry::error();
+		debug("Unpacking error for %s", desc._fileName.c_str());
+		return nullptr;
+	}
+
+	byte b = 0;
+	for (byte *ptr = uncompressedBuffer; ptr < uncompressedBuffer + unpackLen; ptr++) {
+		b += *ptr;
+		*ptr = b;
+	}
+	
+	_cache[desc._fileName].reset(new CacheEntry);
+	_cache[desc._fileName]->size = unpackLen;
+	_cache[desc._fileName]->is_error = false;
+	_cache[desc._fileName]->contents = uncompressedBuffer;
+
+	return new Common::MemoryReadStream(uncompressedBuffer, unpackLen, DisposeAfterUse::NO);
+}
+
+} // End of namespace DreamWeb
diff --git a/engines/dreamweb/rnca_archive.h b/engines/dreamweb/rnca_archive.h
new file mode 100644
index 00000000000..49033330508
--- /dev/null
+++ b/engines/dreamweb/rnca_archive.h
@@ -0,0 +1,86 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DREAMWEB_RNCA_ARCHIVE_H
+#define DREAMWEB_RNCA_ARCHIVE_H
+
+#include "common/archive.h"
+#include "common/ptr.h"
+#include "common/stream.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+
+namespace DreamWeb {
+class RNCAArchive : public Common::Archive {
+public:
+	bool hasFile(const Common::Path &path) const override;
+	int listMembers(Common::ArchiveMemberList&) const override;
+	const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
+	Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
+
+	static RNCAArchive* open(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose = DisposeAfterUse::NO);
+	
+private:
+	class RNCAFileDescriptor {
+	private:
+		Common::String _fileName;
+		
+		// Offset of the file contents relative to the beginning of RNCA stream
+		uint32 _fileDataOffset;
+
+	        RNCAFileDescriptor(const Common::String& filename, uint32 off) : _fileName(filename), _fileDataOffset(off) {}
+		friend class RNCAArchive;
+	public:
+		// It's public for hashmap
+		RNCAFileDescriptor() : _fileDataOffset(0) {}
+	};
+
+	struct CacheEntry {
+		byte *contents;
+		uint32 size;
+		bool is_error;
+
+		~CacheEntry() {
+			delete[] contents;
+		}
+
+		static Common::SharedPtr<CacheEntry> error() {
+			Common::SharedPtr<CacheEntry> ret(new CacheEntry());
+			ret->size = 0;
+			ret->is_error = true;
+			ret->contents = nullptr;
+
+			return ret;
+		}
+	};
+
+	typedef Common::HashMap<Common::String, RNCAFileDescriptor, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
+
+	RNCAArchive(FileMap files, Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose)
+		: _files(files), _stream(stream, dispose) {
+	}
+
+	FileMap _files;
+	Common::DisposablePtr<Common::SeekableReadStream> _stream;
+	mutable Common::HashMap<Common::String, Common::SharedPtr<CacheEntry>, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _cache;
+};
+}
+#endif


Commit: b66d3ec6886b8ec6798a208076bc4114b4d1e0a8
    https://github.com/scummvm/scummvm/commit/b66d3ec6886b8ec6798a208076bc4114b4d1e0a8
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-29T04:30:36+01:00

Commit Message:
COMMON: Implement ConcatReadStream

Changed paths:
  A common/concatstream.cpp
  A common/concatstream.h
    common/module.mk


diff --git a/common/concatstream.cpp b/common/concatstream.cpp
new file mode 100644
index 00000000000..33d1153c917
--- /dev/null
+++ b/common/concatstream.cpp
@@ -0,0 +1,140 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/concatstream.h"
+
+namespace Common {
+
+ConcatReadStream::ConcatReadStream(ParentStreamArray parentStreams) : _parentStreams(parentStreams), _totalSize(0), _linearPos(0), _volume(0), _volumePos(0), _err(false), _eos(false) {
+	_sizes.resize(parentStreams.size());
+	_startOffsets.resize(parentStreams.size());
+	for (uint i = 0; i < parentStreams.size(); i++) {
+		_sizes[i] = parentStreams[i]->size();
+		_totalSize += _sizes[i];
+	}
+	_startOffsets[0] = 0;
+	for (uint i = 1; i < parentStreams.size(); i++)
+		_startOffsets[i] = _startOffsets[i - 1] + _sizes[i - 1];
+}
+
+bool ConcatReadStream::seek(int64 offset, int whence) {
+	int64 target = 0;
+	switch (whence) {
+	case SEEK_SET:
+		target = offset;
+		break;
+	case SEEK_CUR:
+		target = _linearPos + offset;
+		break;
+	case SEEK_END:
+		target = _totalSize + offset;
+		break;
+	default:
+		return false;
+	}
+
+	if (target < 0 || target > _totalSize) {
+		return false;
+	}
+
+	_linearPos = target;
+	_eos = false;
+	_err = false;
+
+	// Special case: seek'ing to the EOF.
+	if (target == _totalSize) {
+		if (_parentStreams.empty()) {
+			_volume = 0;
+			_volumePos = 0;
+			return true;
+		}
+		_volume = _parentStreams.size() - 1;
+		_volumePos = _sizes[_parentStreams.size() - 1];
+		return true;
+	}
+
+	// Find volume
+	for (unsigned vol = 0; vol < _parentStreams.size(); vol++) {
+		if (_startOffsets[vol] <= _linearPos &&
+		    _linearPos < _startOffsets[vol] + _sizes[vol]) {
+			_volume = vol;
+			_volumePos = _linearPos - _startOffsets[vol];
+			return true;
+		}
+	}
+
+	// Should never be reached.
+	_err = true;
+	return false;
+}
+
+bool ConcatReadStream::seekToVolume(int volume, int64 offset) {
+	if (volume < 0 || (uint) volume >= _parentStreams.size()
+	    || offset < 0 || offset >= _sizes[volume]) {
+		_err = true;
+		return false;
+	}
+
+	_err = false;
+	_eos = false;
+	_volume = volume;
+	_volumePos = offset;
+	_linearPos = _startOffsets[volume] + offset;
+	return true;
+}
+
+uint32 ConcatReadStream::read(void *dataPtr, uint32 dataSize) {
+	uint32 rem = dataSize;
+	uint32 alreadyRead = 0;
+	byte *curPtr = (byte*) dataPtr;
+	while (rem > 0) {
+		int64 avail = _startOffsets[_volume] + _sizes[_volume];
+		while (avail == 0) {
+			if (_volume + 1 >= _startOffsets.size()) {
+				_eos = true;
+				return alreadyRead;
+			}
+			_volume++;
+			_volumePos = 0;
+			avail = _startOffsets[_volume] + _sizes[_volume];
+		}
+
+		uint32 toRead = MIN((int64) rem, avail);
+		_parentStreams[_volume]->seek(_volumePos); // Also clears error and EOS.
+		uint32 actuallyRead = _parentStreams[_volume]->read(curPtr, toRead);
+		alreadyRead += actuallyRead;
+		rem -= actuallyRead;
+		curPtr += actuallyRead;
+		_volumePos += actuallyRead;
+		_linearPos += actuallyRead;
+		if (_volumePos == _sizes[_volume] && _volume + 1 < _startOffsets.size()) {
+			_volume++;
+			_volumePos = 0;			
+		}
+		if (_parentStreams[_volume]->err()) {
+			_err = true;
+			return alreadyRead;
+		}
+	}
+
+	return alreadyRead;
+}
+} // End of namespace Common
diff --git a/common/concatstream.h b/common/concatstream.h
new file mode 100644
index 00000000000..0fb55677b39
--- /dev/null
+++ b/common/concatstream.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef COMMON_CONCATSTREAM_H
+#define COMMON_CONCATSTREAM_H
+
+#include "common/array.h"
+#include "common/ptr.h"
+#include "common/stream.h"
+
+namespace Common {
+/*
+ * ConcatReadStream provides access to a virtually concatenated stream.
+ *
+ * Manipulating the parent stream directly /will/ mess up a concatstream.
+ *
+ * Assumptions:
+ * - number of streams is small so iterating through array sized by N is cheap
+ * - size of streams doesn't change
+ */
+class ConcatReadStream : public SeekableReadStream {
+private:
+	typedef Common::Array<Common::SharedPtr<Common::SeekableReadStream>> ParentStreamArray;
+	ParentStreamArray _parentStreams;
+	Common::Array<int64> _sizes;
+	Common::Array<int64> _startOffsets;
+
+	uint32 _totalSize, _linearPos;
+	uint32 _volume, _volumePos;
+	bool _err, _eos;
+public:
+	ConcatReadStream(ParentStreamArray parentStreams);
+
+	int64 pos() const override { return _linearPos; }
+	int64 size() const override { return _totalSize; }
+	bool eos() const override { return _eos; }
+	bool err() const override { return _err; }
+	void clearErr() override {
+		_err = false;
+		_eos = false;
+	}
+	bool seek(int64 offset, int whence = SEEK_SET) override;
+	uint32 read(void *dataPtr, uint32 dataSize) override;
+	bool seekToVolume(int volume, int64 offset);
+};
+
+}
+
+#endif // COMMON_CONCATSTREAM_H
diff --git a/common/module.mk b/common/module.mk
index 42720db2a0d..ee6a7d4cad5 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -5,6 +5,7 @@ MODULE_OBJS := \
 	archive.o \
 	base-str.o \
 	clickteam.o \
+	concatstream.o \
 	config-manager.o \
 	coroutines.o \
 	dcl.o \


Commit: cf29e594e15c12982cd0862af66b720c5b182a87
    https://github.com/scummvm/scummvm/commit/cf29e594e15c12982cd0862af66b720c5b182a87
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-29T04:30:36+01:00

Commit Message:
DREAMWEB: Support playing from compressed installer

Changed paths:
    engines/dreamweb/detection.h
    engines/dreamweb/dreamweb.cpp


diff --git a/engines/dreamweb/detection.h b/engines/dreamweb/detection.h
index 197192fb7aa..43035489287 100644
--- a/engines/dreamweb/detection.h
+++ b/engines/dreamweb/detection.h
@@ -33,6 +33,8 @@ struct DreamWebGameDescription {
 #define GAMEOPTION_TTS_THINGS        GUIO_GAMEOPTIONS3
 #define GAMEOPTION_TTS_SPEECH        GUIO_GAMEOPTIONS4
 
+#define GF_INSTALLER 1
+
 } // End of namespace DreamWeb
 
 #endif // DREAMWEB_DETECTION_H
diff --git a/engines/dreamweb/dreamweb.cpp b/engines/dreamweb/dreamweb.cpp
index cc82a598e35..2aabec79240 100644
--- a/engines/dreamweb/dreamweb.cpp
+++ b/engines/dreamweb/dreamweb.cpp
@@ -27,14 +27,17 @@
 #include "common/system.h"
 #include "common/timer.h"
 #include "common/util.h"
+#include "common/concatstream.h"
 
 #include "engines/advancedDetector.h"
 
 #include "graphics/palette.h"
 #include "graphics/surface.h"
 
+#include "dreamweb/detection.h"
 #include "dreamweb/sound.h"
 #include "dreamweb/dreamweb.h"
+#include "dreamweb/rnca_archive.h"
 
 #include "common/text-to-speech.h"
 
@@ -396,6 +399,20 @@ void DreamWebEngine::processEvents(bool processSoundEvents) {
 }
 
 Common::Error DreamWebEngine::run() {
+	if (_gameDescription->desc.flags & GF_INSTALLER) {
+		Common::Array<Common::SharedPtr<Common::SeekableReadStream>> volumes;
+		for (uint i = 0; _gameDescription->desc.filesDescriptions[i].fileName; i++) {
+			Common::File *dw = new Common::File();
+			const char *name = _gameDescription->desc.filesDescriptions[i].fileName;
+			if (!dw->open(name)) {
+				error("Can't open %s", name);
+			}
+			volumes.push_back(Common::SharedPtr<Common::SeekableReadStream>(dw));
+		}
+		Common::ConcatReadStream *concat = new Common::ConcatReadStream(volumes);
+		SearchMan.add("rnca", RNCAArchive::open(concat, DisposeAfterUse::YES));
+	}
+
 	if (_ttsMan != nullptr) {
 		Common::String languageString = Common::getLanguageCode(getLanguage());
 		_ttsMan->setLanguage(languageString);


Commit: aaaf0a560dba8d8e0bbb53506db958508ad35d13
    https://github.com/scummvm/scummvm/commit/aaaf0a560dba8d8e0bbb53506db958508ad35d13
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-29T04:30:36+01:00

Commit Message:
DREAMWEB: Add entry for international floppy release (compressed)

I don't have German, Italian or Spanish files to create entries for them.

Changed paths:
    engines/dreamweb/detection_tables.h


diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h
index 0221a1a166b..68bea7ebda3 100644
--- a/engines/dreamweb/detection_tables.h
+++ b/engines/dreamweb/detection_tables.h
@@ -27,6 +27,27 @@
 namespace DreamWeb {
 
 static const DreamWebGameDescription gameDescriptions[] = {
+	// International floppy release
+	{
+		{
+			"dreamweb",
+			"Installer",
+			{
+				{"dreamw_1.rnc", 0, "4b8a92191219cc7e84d50837e1acca93", 1400000},
+				{"dreamw_2.rnc", 0, "603e053b763c54c13a1e5e28be2ea839", 1457664},
+				{"dreamw_3.rnc", 0, "1b273aa05a6afb8e7cd3c2defe2e334f", 1457664},
+				{"dreamw_4.rnc", 0, "f7bc7a8e1147d7379272c6dbfb5e7246", 1457664},
+				{"dreamw_5.rnc", 0, "0349950d94fee72b8fd57a22f7c465d1", 1457664},
+				{"dreamw_6.rnc", 0, "c99629c842967e5e41e1c298cb58274f", 662246},
+				AD_LISTEND
+			},
+			Common::EN_ANY,
+			Common::kPlatformDOS,
+			GF_INSTALLER,
+			GUIO0()
+		},
+	},
+
 	// International floppy release
 	{
 		{




More information about the Scummvm-git-logs mailing list