[Scummvm-git-logs] scummvm-tools master -> 59eebfed5fc9392470389aaa0f1fb84939b35706

sev- noreply at scummvm.org
Sun Nov 20 16:00:00 UTC 2022


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

Summary:
39563a9fad COMMON: Add 64-bit datatype and related primitives
7b1e313fed COMMON: Add big-endian primitives
2b7dab2f74 COMMON: Import STATIC_ASSERT
7bc5baf4fd COMMON: Import common/ptr.h
6ff42bafcd COMMON: Import common/stream.cpp
7b9337fe2b COMMON: Import common/dcl.cpp
3aa7ad671d MADS: Switch from libblast to common/dcl
59eebfed5f MADS: Remove libblast


Commit: 39563a9fad1ef932362017656e829772ff06862b
    https://github.com/scummvm/scummvm-tools/commit/39563a9fad1ef932362017656e829772ff06862b
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-20T16:59:55+01:00

Commit Message:
COMMON: Add 64-bit datatype and related primitives

Changed paths:
    common/endian.h
    configure


diff --git a/common/endian.h b/common/endian.h
index 8f3c521a..818a1184 100644
--- a/common/endian.h
+++ b/common/endian.h
@@ -42,6 +42,17 @@
 #  define MKID_BE(a) ((uint32)(a))
 #endif
 
+static inline uint64 SWAP_64(uint64 a) {
+	return ((uint64)((((a) >> 56) & 0x000000FF) |
+			 (((a) >> 40) & 0x0000FF00) |
+			 (((a) >> 24) & 0x00FF0000) |
+			 (((a) >>  8) & 0xFF000000) |
+			 (((a) & 0xFF000000) <<  8) |
+			 (((a) & 0x00FF0000) << 24) |
+			 (((a) & 0x0000FF00) << 40) |
+			 (((a) & 0x000000FF) << 56) ));
+}
+
 static inline uint32 SWAP_32(uint32 a) {
 	return (uint32)
 		(((a >> 24) & 0x000000FF) |
@@ -55,13 +66,17 @@ static inline uint16 SWAP_16(uint16 a) {
 }
 
 #if defined(SCUMM_BIG_ENDIAN)
+	#define FROM_LE_64(a) SWAP_64(a)
 	#define FROM_LE_32(a) SWAP_32(a)
 	#define FROM_LE_16(a) SWAP_16(a)
+	#define TO_LE_64(a) SWAP_64(a)
 	#define TO_LE_32(a) SWAP_32(a)
 	#define TO_LE_16(a) SWAP_16(a)
 #else
+	#define FROM_LE_64(a) ((uint64)(a))
 	#define FROM_LE_32(a) ((uint32)(a))
 	#define FROM_LE_16(a) ((uint16)(a))
+	#define TO_LE_64(a) ((uint64)(a))
 	#define TO_LE_32(a) ((uint32)(a))
 	#define TO_LE_16(a) ((uint16)(a))
 #endif
diff --git a/configure b/configure
index 901c61f6..21bdbf07 100755
--- a/configure
+++ b/configure
@@ -1081,7 +1081,7 @@ esac
 # Determine a data type with the given length
 #
 find_type_with_size() {
-	for datatype in int short char long unknown; do
+	for datatype in int short char long "long long" unknown; do
 		cat > tmp_find_type_with_size.cpp << EOF
 typedef $datatype ac__type_sizeof_;
 int main() {
@@ -1101,7 +1101,7 @@ EOF
 		fi
 	done
 	cc_check_clean tmp_find_type_with_size.cpp
-	echo $datatype
+	echo "$datatype"
 }
 
 #
@@ -1125,6 +1125,12 @@ TMPR="$?"
 echo "$type_4_byte"
 test $TMPR -eq 0 || exit 1	# check exit code of subshell
 
+echo_n "Type with 8 bytes... "
+type_8_byte=`find_type_with_size 8`
+TMPR="$?"
+echo "$type_8_byte"
+test $TMPR -eq 0 || exit 1	# check exit code of subshell
+
 #
 # Check whether memory alignment is required
 #
@@ -1933,9 +1939,11 @@ typedef unsigned int uint;
 typedef unsigned $type_1_byte uint8;
 typedef unsigned $type_2_byte uint16;
 typedef unsigned $type_4_byte uint32;
+typedef unsigned $type_8_byte uint64;
 typedef signed $type_1_byte int8;
 typedef signed $type_2_byte int16;
 typedef signed $type_4_byte int32;
+typedef signed $type_8_byte int64;
 
 #endif /* CONFIG_H */
 EOF


Commit: 7b1e313fedbd8738ef38d811b273b803e21723a6
    https://github.com/scummvm/scummvm-tools/commit/7b1e313fedbd8738ef38d811b273b803e21723a6
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-20T16:59:55+01:00

Commit Message:
COMMON: Add big-endian primitives

Changed paths:
    common/endian.h


diff --git a/common/endian.h b/common/endian.h
index 818a1184..ca2c0d71 100644
--- a/common/endian.h
+++ b/common/endian.h
@@ -72,6 +72,12 @@ static inline uint16 SWAP_16(uint16 a) {
 	#define TO_LE_64(a) SWAP_64(a)
 	#define TO_LE_32(a) SWAP_32(a)
 	#define TO_LE_16(a) SWAP_16(a)
+	#define FROM_BE_64(a) ((uint64)(a))
+	#define FROM_BE_32(a) ((uint32)(a))
+	#define FROM_BE_16(a) ((uint16)(a))
+	#define TO_BE_64(a) ((uint64)(a))
+	#define TO_BE_32(a) ((uint32)(a))
+	#define TO_BE_16(a) ((uint16)(a))
 #else
 	#define FROM_LE_64(a) ((uint64)(a))
 	#define FROM_LE_32(a) ((uint32)(a))
@@ -79,6 +85,12 @@ static inline uint16 SWAP_16(uint16 a) {
 	#define TO_LE_64(a) ((uint64)(a))
 	#define TO_LE_32(a) ((uint32)(a))
 	#define TO_LE_16(a) ((uint16)(a))
+	#define FROM_BE_64(a) SWAP_64(a)
+	#define FROM_BE_32(a) SWAP_32(a)
+	#define FROM_BE_16(a) SWAP_16(a)
+	#define TO_BE_64(a) SWAP_64(a)
+	#define TO_BE_32(a) SWAP_32(a)
+	#define TO_BE_16(a) SWAP_16(a)
 #endif
 
 FORCEINLINE uint16 READ_LE_UINT16(const void *ptr) {


Commit: 2b7dab2f74f7ebdcc035218a40e44beceae49a15
    https://github.com/scummvm/scummvm-tools/commit/2b7dab2f74f7ebdcc035218a40e44beceae49a15
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-20T16:59:55+01:00

Commit Message:
COMMON: Import STATIC_ASSERT

Changed paths:
    common/scummsys.h


diff --git a/common/scummsys.h b/common/scummsys.h
index 399de75b..1b7e23a5 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -479,5 +479,32 @@
 	typedef uint16 OverlayColor;
 #endif
 
+#ifndef STATIC_ASSERT
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER > 1600)
+	/**
+	 * Generates a compile-time assertion.
+	 *
+	 * @param expression An expression that can be evaluated at compile time.
+	 * @param message An underscore-delimited message to be presented at compile
+	 * time if the expression evaluates to false.
+	 */
+	#define STATIC_ASSERT(expression, message) \
+		static_assert((expression), #message)
+#else
+	/**
+	 * Generates a compile-time assertion.
+	 *
+	 * @param expression An expression that can be evaluated at compile time.
+	 * @param message An underscore-delimited message to be presented at compile
+	 * time if the expression evaluates to false.
+	 */
+	#define STATIC_ASSERT(expression, message) \
+		do { \
+			extern int STATIC_ASSERT_##message[(expression) ? 1 : -1]; \
+			(void)(STATIC_ASSERT_##message); \
+		} while (false)
+#endif
+#endif
+
 
 #endif


Commit: 7bc5baf4fde4249ab0ddacebf7f4c703d96976b1
    https://github.com/scummvm/scummvm-tools/commit/7bc5baf4fde4249ab0ddacebf7f4c703d96976b1
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-20T16:59:55+01:00

Commit Message:
COMMON: Import common/ptr.h

Changed paths:
  A common/ptr.h
  A common/safe-bool.h
  A common/types.h


diff --git a/common/ptr.h b/common/ptr.h
new file mode 100644
index 00000000..9193b9b1
--- /dev/null
+++ b/common/ptr.h
@@ -0,0 +1,719 @@
+/* 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_PTR_H
+#define COMMON_PTR_H
+
+#include "common/scummsys.h"
+#include "common/noncopyable.h"
+#include "common/safe-bool.h"
+#include "common/types.h"
+
+/* For nullptr_t */
+#include <cstddef>
+
+namespace Common {
+
+/**
+ * @defgroup common_ptr Pointers
+ * @ingroup common
+ *
+ * @brief API and templates for pointers.
+ * @{
+ */
+
+class BasePtrTrackerInternal {
+public:
+	typedef int RefValue;
+
+	BasePtrTrackerInternal() : _weakRefCount(1), _strongRefCount(1) {}
+	virtual ~BasePtrTrackerInternal() {}
+
+	void incWeak() {
+		_weakRefCount++;
+	}
+
+	void decWeak() {
+		if (--_weakRefCount == 0)
+			delete this;
+	}
+
+	void incStrong() {
+		_strongRefCount++;
+	}
+
+	void decStrong() {
+		if (--_strongRefCount == 0) {
+			destructObject();
+			decWeak();
+		}
+	}
+
+	bool isAlive() const {
+		return _strongRefCount > 0;
+	}
+
+	RefValue getStrongCount() const {
+		return _strongRefCount;
+	}
+
+protected:
+	virtual void destructObject() = 0;
+
+private:
+	RefValue _weakRefCount; // Weak ref count + 1 if object ref count > 0
+	RefValue _strongRefCount;
+};
+
+template<class T>
+class BasePtrTrackerImpl : public BasePtrTrackerInternal {
+public:
+	BasePtrTrackerImpl(T *ptr) : _ptr(ptr) {}
+
+protected:
+	void destructObject() override {
+		STATIC_ASSERT(sizeof(T) > 0, SharedPtr_cannot_delete_incomplete_type);
+		delete _ptr;
+	}
+
+	T *_ptr;
+};
+
+template<class T, class DL>
+class BasePtrTrackerDeletionImpl : public BasePtrTrackerInternal {
+public:
+	BasePtrTrackerDeletionImpl(T *ptr, DL d) : _ptr(ptr), _deleter(d) {}
+
+private:
+	void destructObject() override {
+		_deleter(_ptr);
+	}
+
+	T *_ptr;
+	DL _deleter;
+};
+
+template<class T>
+class WeakPtr;
+
+/**
+ * A simple shared pointer implementation modelled after boost.
+ *
+ * This object keeps track of the assigned pointer and automatically
+ * frees it when no more SharedPtr references to it exist.
+ *
+ * To achieve that the object implements an internal reference counting.
+ * Thus you should try to avoid using the plain pointer after assigning
+ * it to a SharedPtr object for the first time. If you still use the
+ * plain pointer be sure you do not delete it on your own. You may also
+ * not use the plain pointer to create a new SharedPtr object, since that
+ * would result in a double deletion of the pointer sooner or later.
+ *
+ * Example creation:
+ * Common::SharedPtr<int> pointer(new int(1));
+ * would create a pointer to int. Later on usage via *pointer is the same
+ * as for a normal pointer. If you need to access the plain pointer value
+ * itself later on use the get method. The class also supplies a operator
+ * ->, which does the same as the -> operator on a normal pointer.
+ *
+ * Be sure you are using new to initialize the pointer you want to manage.
+ * If you do not use new for allocating, you have to supply a deleter as
+ * second parameter when creating a SharedPtr object. The deleter has to
+ * implement operator() which takes the pointer it should free as argument.
+ *
+ * Note that you have to specify the type itself not the pointer type as
+ * template parameter.
+ *
+ * When creating a SharedPtr object from a normal pointer you need a real
+ * definition of the type you want SharedPtr to manage, a simple forward
+ * definition is not enough.
+ *
+ * The class has implicit upcast support, so if you got a class B derived
+ * from class A, you can assign a pointer to B without any problems to a
+ * SharedPtr object with template parameter A. The very same applies to
+ * assignment of a SharedPtr<B> object to a SharedPtr<A> object.
+ *
+ * There are also operators != and == to compare two SharedPtr objects
+ * with compatible pointers. Comparison between a SharedPtr object and
+ * a plain pointer is only possible via SharedPtr::get.
+ */
+template<class T>
+class SharedPtr : public SafeBool<SharedPtr<T> > {
+	template<class T2>
+	friend class WeakPtr;
+	template<class T2>
+	friend class SharedPtr;
+public:
+	// Invariant: If _tracker is non-null, then the object is alive
+	typedef T *PointerType;
+	typedef T &ReferenceType;
+	typedef BasePtrTrackerInternal::RefValue RefValue;
+
+	SharedPtr() : _pointer(nullptr), _tracker(nullptr) {
+	}
+
+	SharedPtr(std::nullptr_t) : _pointer(nullptr), _tracker(nullptr) {
+	}
+
+	~SharedPtr() {
+		if (_tracker)
+			_tracker->decStrong();
+	}
+
+	template<class T2>
+	explicit SharedPtr(T2 *p) : _pointer(p), _tracker(p ? (new BasePtrTrackerImpl<T2>(p)) : nullptr) {
+	}
+
+	template<class T2, class DL>
+	SharedPtr(T2 *p, DL d) : _pointer(p), _tracker(p ? (new BasePtrTrackerDeletionImpl<T2, DL>(p, d)) : nullptr) {
+	}
+
+	SharedPtr(const SharedPtr<T> &r) : _pointer(r._pointer), _tracker(r._tracker) {
+		if (_tracker)
+			_tracker->incStrong();
+	}
+
+	template<class T2>
+	SharedPtr(const SharedPtr<T2> &r) : _pointer(r._pointer), _tracker(r._tracker) {
+		if (_tracker)
+			_tracker->incStrong();
+	}
+
+	template<class T2>
+	explicit SharedPtr(const WeakPtr<T2> &r) : _pointer(nullptr), _tracker(nullptr) {
+		if (r._tracker && r._tracker->isAlive()) {
+			_pointer = r._pointer;
+			_tracker = r._tracker;
+			_tracker->incStrong();
+		}
+	}
+
+	SharedPtr &operator=(const SharedPtr &r) {
+		reset(r);
+		return *this;
+	}
+
+	template<class T2>
+	SharedPtr &operator=(const SharedPtr<T2> &r) {
+		reset(r);
+		return *this;
+	}
+
+	T &operator*() const { assert(_pointer); return *_pointer; }
+	T *operator->() const { assert(_pointer); return _pointer; }
+
+	/**
+	 * Returns the plain pointer value. Be sure you know what you
+	 * do if you are continuing to use that pointer.
+	 *
+	 * @return the pointer the SharedPtr object manages
+	 */
+	PointerType get() const { return _pointer; }
+
+	template<class T2>
+	bool operator==(const SharedPtr<T2> &r) const {
+		return _pointer == r.get();
+	}
+
+	template<class T2>
+	bool operator!=(const SharedPtr<T2> &r) const {
+		return _pointer != r.get();
+	}
+
+	bool operator==(std::nullptr_t) const {
+		return _pointer == nullptr;
+	}
+
+	bool operator!=(std::nullptr_t) const {
+		return _pointer != nullptr;
+	}
+
+	/**
+	 * Implicit conversion operator to bool for convenience, to make
+	 * checks like "if (sharedPtr) ..." possible.
+	 */
+	bool operator_bool() const {
+		return _pointer != nullptr;
+	}
+
+	/**
+	 * Returns the number of strong references to the object.
+	 */
+	int refCount() const {
+		if (_tracker == nullptr)
+			return 0;
+		return _tracker->getStrongCount();
+	}
+
+	/**
+	 * Checks if the object is the only object refering
+	 * to the assigned pointer. This should just be used for
+	 * debugging purposes.
+	 */
+	bool unique() const {
+		return refCount() == 1;
+	}
+
+	/**
+	 * Resets the object to a NULL pointer.
+	 */
+	void reset() {
+		if (_tracker)
+			_tracker->decStrong();
+		_tracker = nullptr;
+		_pointer = nullptr;
+	}
+
+	/**
+	 * Resets the object to the specified shared pointer
+	 */
+	template<class T2>
+	void reset(const SharedPtr<T2> &r) {
+		BasePtrTrackerInternal *oldTracker = _tracker;
+
+		_pointer = r._pointer;
+		_tracker = r._tracker;
+
+		if (_tracker)
+			_tracker->incStrong();
+		if (oldTracker)
+			oldTracker->decStrong();
+	}
+
+	/**
+	 * Resets the object to the specified weak pointer
+	 */
+	template<class T2>
+	void reset(const WeakPtr<T2> &r) {
+		BasePtrTrackerInternal *oldTracker = _tracker;
+
+		if (r._tracker && r._tracker->isAlive()) {
+			_tracker = r._tracker;
+			_pointer = r._pointer;
+			_tracker->incStrong();
+		} else {
+			_tracker = nullptr;
+			_pointer = nullptr;
+		}
+
+		if (oldTracker)
+			oldTracker->decStrong();
+	}
+
+	/**
+	 * Resets the object to the specified pointer
+	 */
+	void reset(T *ptr) {
+		if (_tracker)
+			_tracker->decStrong();
+
+		_pointer = ptr;
+		_tracker = new BasePtrTrackerImpl<T>(ptr);
+	}
+
+	/**
+	 * Performs the equivalent of static_cast to a new pointer type
+	 */
+	template<class T2>
+	SharedPtr<T2> staticCast() const {
+		return SharedPtr<T2>(static_cast<T2 *>(_pointer), _tracker);
+	}
+
+	/**
+	 * Performs the equivalent of dynamic_cast to a new pointer type
+	 */
+	template<class T2>
+	SharedPtr<T2> dynamicCast() const {
+		return SharedPtr<T2>(dynamic_cast<T2 *>(_pointer), _tracker);
+	}
+
+	/**
+	 * Performs the equivalent of const_cast to a new pointer type
+	 */
+	template<class T2>
+	SharedPtr<T2> constCast() const {
+		return SharedPtr<T2>(const_cast<T2 *>(_pointer), _tracker);
+	}
+
+	/**
+	 * Performs the equivalent of const_cast to a new pointer type
+	 */
+	template<class T2>
+	SharedPtr<T2> reinterpretCast() const {
+		return SharedPtr<T2>(reinterpret_cast<T2 *>(_pointer), _tracker);
+	}
+
+private:
+	SharedPtr(T *pointer, BasePtrTrackerInternal *tracker) : _pointer(pointer), _tracker(tracker) {
+		if (tracker)
+			tracker->incStrong();
+	}
+
+	T *_pointer;
+	BasePtrTrackerInternal *_tracker;
+};
+
+
+
+/**
+ * Implements a smart pointer that holds a non-owning ("weak") reference to
+ * a pointer. It needs to be converted to a SharedPtr to access it.
+ */
+template<class T>
+class WeakPtr {
+	template<class T2>
+	friend class WeakPtr;
+	template<class T2>
+	friend class SharedPtr;
+public:
+	WeakPtr() : _pointer(nullptr), _tracker(nullptr) {
+	}
+
+	WeakPtr(std::nullptr_t) : _pointer(nullptr), _tracker(nullptr) {
+	}
+
+	WeakPtr(const WeakPtr<T> &r) : _pointer(r._pointer), _tracker(r._tracker) {
+		if (_tracker)
+			_tracker->incWeak();
+	}
+
+	~WeakPtr() {
+		if (_tracker)
+			_tracker->decWeak();
+	}
+
+	template<class T2>
+	WeakPtr(const WeakPtr<T2> &r) : _pointer(r._pointer), _tracker(r._tracker) {
+		if (_tracker)
+			_tracker->incWeak();
+	}
+
+	template<class T2>
+	WeakPtr(const SharedPtr<T2> &r) : _pointer(r._pointer), _tracker(r._tracker) {
+		if (_tracker)
+			_tracker->incWeak();
+	}
+
+	/**
+	 * Performs the equivalent of static_cast to a new pointer type
+	 */
+	template<class T2>
+	WeakPtr<T2> staticCast() const {
+		return WeakPtr<T2>(expired() ? nullptr : static_cast<T2 *>(_pointer), _tracker);
+	}
+
+	/**
+	 * Performs the equivalent of dynamic_cast to a new pointer type
+	 */
+	template<class T2>
+	WeakPtr<T2> dynamicCast() const {
+		return WeakPtr<T2>(expired() ? nullptr : dynamic_cast<T2 *>(_pointer), _tracker);
+	}
+
+	/**
+	 * Performs the equivalent of const_cast to a new pointer type
+	 */
+	template<class T2>
+	WeakPtr<T2> constCast() const {
+		return WeakPtr<T2>(expired() ? nullptr : const_cast<T2 *>(_pointer), _tracker);
+	}
+
+	/**
+	 * Performs the equivalent of const_cast to a new pointer type
+	 */
+	template<class T2>
+	WeakPtr<T2> reinterpretCast() const {
+		return WeakPtr<T2>(expired() ? nullptr : reinterpret_cast<T2 *>(_pointer), _tracker);
+	}
+
+	/**
+	 * Creates a SharedPtr that manages the referenced object
+	 */
+	SharedPtr<T> lock() const {
+		return SharedPtr<T>(*this);
+	}
+
+	/**
+	 * Returns the number of strong references to the object.
+	 */
+	int refCount() const {
+		if (_tracker == nullptr)
+			return 0;
+		return _tracker->getStrongCount();
+	}
+
+	/**
+	 * Returns whether the referenced object isn't valid
+	 */
+	bool expired() const {
+		return _tracker == nullptr || _tracker->getStrongCount() == 0;
+	}
+
+	/**
+	 * Returns whether this precedes another weak pointer in owner-based order
+	 */
+	template<class T2>
+	bool owner_before(const WeakPtr<T2>& other) const {
+		return _tracker < other._tracker;
+	}
+
+	/**
+	 * Returns whether this precedes a shared pointer in owner-based order
+	 */
+	template<class T2>
+	bool owner_before(const SharedPtr<T2> &other) const {
+		return _tracker < other._tracker;
+	}
+
+	WeakPtr<T> &operator=(const WeakPtr<T> &r) {
+		reset(r);
+		return *this;
+	}
+
+	template<class T2>
+	WeakPtr<T> &operator=(const WeakPtr<T2> &r) {
+		reset(r);
+		return *this;
+	}
+
+	template<class T2>
+	WeakPtr<T> &operator=(const SharedPtr<T2> &r) {
+		reset(r);
+		return *this;
+	}
+
+	/**
+	 * Resets the object to a NULL pointer.
+	 */
+	void reset() {
+		if (_tracker)
+			_tracker->decWeak();
+		_tracker = nullptr;
+		_pointer = nullptr;
+	}
+
+	/**
+	 * Resets the object to the specified shared pointer
+	 */
+	template<class T2>
+	void reset(const SharedPtr<T2> &r) {
+		BasePtrTrackerInternal *oldTracker = _tracker;
+
+		_pointer = r._pointer;
+		_tracker = r._tracker;
+
+		if (_tracker)
+			_tracker->incWeak();
+		if (oldTracker)
+			oldTracker->decWeak();
+	}
+
+	/**
+	 * Resets the object to the specified weak pointer
+	 */
+	template<class T2>
+	void reset(const WeakPtr<T2> &r) {
+		BasePtrTrackerInternal *oldTracker = _tracker;
+
+		_pointer = r._pointer;
+		_tracker = r._tracker;
+
+		if (_tracker)
+			_tracker->incWeak();
+		if (oldTracker)
+			oldTracker->decWeak();
+	}
+
+private:
+	WeakPtr(T *pointer, BasePtrTrackerInternal *tracker) : _pointer(pointer), _tracker(tracker) {
+		if (tracker)
+			tracker->incWeak();
+	}
+
+	T *_pointer;
+	BasePtrTrackerInternal *_tracker;
+};
+
+template <typename T>
+struct DefaultDeleter {
+	inline void operator()(T *object) {
+		STATIC_ASSERT(sizeof(T) > 0, cannot_delete_incomplete_type);
+		delete object;
+	}
+};
+
+template <typename T>
+struct ArrayDeleter {
+	inline void operator()(T *object) {
+		STATIC_ASSERT(sizeof(T) > 0, cannot_delete_incomplete_type);
+		delete[] object;
+	}
+};
+
+template<typename T, class DL = DefaultDeleter<T> >
+class ScopedPtr : private NonCopyable, public SafeBool<ScopedPtr<T, DL> > {
+public:
+	typedef T ValueType;
+	typedef T *PointerType;
+	typedef T &ReferenceType;
+
+	explicit ScopedPtr(PointerType o = nullptr) : _pointer(o) {}
+	ScopedPtr(std::nullptr_t) : _pointer(nullptr) {}
+
+	/**
+	 * Move constructor
+	 */
+	template<class T2>
+	ScopedPtr(ScopedPtr<T2> &&o) : _pointer(o._pointer) {
+		o._pointer = nullptr;
+        }
+
+	ReferenceType operator*() const { return *_pointer; }
+	PointerType operator->() const { return _pointer; }
+
+	/**
+	 * Implicit conversion operator to bool for convenience, to make
+	 * checks like "if (scopedPtr) ..." possible.
+	 */
+	bool operator_bool() const { return _pointer != nullptr; }
+
+	~ScopedPtr() {
+		DL()(_pointer);
+	}
+
+	/**
+	 * Resets the pointer with the new value. Old object will be destroyed
+	 */
+	void reset(PointerType o = nullptr) {
+		DL()(_pointer);
+		_pointer = o;
+	}
+
+	/**
+	 * Affectation with nullptr
+	 */
+	ScopedPtr &operator=(std::nullptr_t) {
+		reset(nullptr);
+	}
+
+	/**
+	 * Replaces the ScopedPtr with another scoped ScopedPtr.
+	 */
+	template<class T2>
+	ScopedPtr &operator=(ScopedPtr<T2> &&other) {
+		PointerType oldPointer = _pointer;
+		_pointer = other._pointer;
+		other._pointer = nullptr;
+		DL()(oldPointer);
+		return *this;
+	}
+
+	/**
+	 * Returns the plain pointer value.
+	 *
+	 * @return the pointer the ScopedPtr manages
+	 */
+	PointerType get() const { return _pointer; }
+
+	/**
+	 * Returns the plain pointer value and releases ScopedPtr.
+	 * After release() call you need to delete object yourself
+	 *
+	 * @return the pointer the ScopedPtr manages
+	 */
+	PointerType release() {
+		PointerType r = _pointer;
+		_pointer = nullptr;
+		return r;
+	}
+
+private:
+	PointerType _pointer;
+};
+
+template<typename T, class DL = DefaultDeleter<T> >
+class DisposablePtr : private NonCopyable, public SafeBool<DisposablePtr<T, DL> > {
+public:
+	typedef T  ValueType;
+	typedef T *PointerType;
+	typedef T &ReferenceType;
+
+	explicit DisposablePtr(PointerType o, DisposeAfterUse::Flag dispose) : _pointer(o), _dispose(dispose) {}
+
+	~DisposablePtr() {
+		if (_dispose) DL()(_pointer);
+	}
+
+	ReferenceType operator*() const { return *_pointer; }
+	PointerType operator->() const { return _pointer; }
+
+	/**
+	 * Implicit conversion operator to bool for convenience, to make
+	 * checks like "if (scopedPtr) ..." possible.
+	 */
+	bool operator_bool() const { return _pointer != nullptr; }
+
+	/**
+	 * Resets the pointer with the new value. Old object will be destroyed
+	 */
+	void reset(PointerType o, DisposeAfterUse::Flag dispose) {
+		if (_dispose) DL()(_pointer);
+		_pointer = o;
+		_dispose = dispose;
+	}
+
+	/**
+	 * Clears the pointer. Old object will be destroyed
+	 */
+	void reset() {
+		reset(nullptr, DisposeAfterUse::NO);
+	}
+
+	/**
+	 * Clears the pointer without destroying the old object.
+	 */
+	void disownPtr() {
+		_pointer = nullptr;
+		_dispose = DisposeAfterUse::NO;
+	}
+
+	/**
+	 * Returns the plain pointer value.
+	 *
+	 * @return the pointer the DisposablePtr manages
+	 */
+	PointerType get() const { return _pointer; }
+
+	/**
+	 * Returns the pointer's dispose flag.
+	 */
+	DisposeAfterUse::Flag getDispose() const { return _dispose; }
+
+private:
+	PointerType           _pointer;
+	DisposeAfterUse::Flag _dispose;
+};
+
+/** @} */
+
+} // End of namespace Common
+
+#endif
diff --git a/common/safe-bool.h b/common/safe-bool.h
new file mode 100644
index 00000000..f51cd8c2
--- /dev/null
+++ b/common/safe-bool.h
@@ -0,0 +1,75 @@
+/**
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef COMMON_SAFE_BOOL_H
+#define COMMON_SAFE_BOOL_H
+
+namespace Common {
+	namespace impl {
+		template <typename T>
+		struct no_base {};
+
+		template <typename T>
+		struct safe_bool_impl {
+			typedef T *TP; // workaround to make parsing easier
+			TP stub;
+			typedef TP safe_bool_impl::*type;
+		};
+	}
+
+	/**
+	 * @defgroup common_safe_bool Safe Boolean
+	 * @ingroup common
+	 *
+	 * @brief Template for a SafeBool function.
+	 *
+	 * @{
+	 */
+
+	/**
+	 * Prevents `operator bool` from implicitly converting to other types.
+	 */
+	template <typename DerivedT, typename BaseT = impl::no_base<DerivedT> >
+	struct SafeBool : BaseT {
+	private:
+		typedef impl::safe_bool_impl<DerivedT> impl_t;
+		typedef typename impl_t::type bool_type;
+
+	public:
+		operator bool_type() const {
+			return static_cast<const DerivedT *>(this)->operator_bool() ?
+			&impl_t::stub : nullptr;
+		}
+
+		operator bool_type() {
+			return static_cast<DerivedT *>(this)->operator_bool() ?
+			&impl_t::stub : 0;
+		}
+	};
+	/** @} */
+} // End of namespace Common
+
+#endif
diff --git a/common/types.h b/common/types.h
new file mode 100644
index 00000000..afa6e18f
--- /dev/null
+++ b/common/types.h
@@ -0,0 +1,32 @@
+/* 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_TYPES_H
+#define COMMON_TYPES_H
+
+#include "common/scummsys.h"
+
+namespace DisposeAfterUse {
+	enum Flag { NO, YES };
+}
+
+
+#endif


Commit: 6ff42bafcdcc123a75b0026c248391722cef8a20
    https://github.com/scummvm/scummvm-tools/commit/6ff42bafcdcc123a75b0026c248391722cef8a20
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-20T16:59:55+01:00

Commit Message:
COMMON: Import common/stream.cpp

Changed paths:
  A common/memstream.h
  A common/stream.cpp
  A common/stream.h
  A common/substream.h
    Makefile.common


diff --git a/Makefile.common b/Makefile.common
index 2d069fd5..7457a65b 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -96,6 +96,7 @@ UTILS := \
 	common/md5.o \
 	common/memorypool.o \
 	common/str.o \
+	common/stream.o \
 	common/util.o \
 	sound/adpcm.o \
 	sound/audiostream.o \
diff --git a/common/memstream.h b/common/memstream.h
new file mode 100644
index 00000000..17bbc30d
--- /dev/null
+++ b/common/memstream.h
@@ -0,0 +1,479 @@
+/* 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_MEMSTREAM_H
+#define COMMON_MEMSTREAM_H
+
+#include "common/stream.h"
+#include "common/types.h"
+#include "common/util.h"
+
+namespace Common {
+
+/**
+ * @defgroup common_memory_pool Memory stream
+ * @ingroup common_memory
+ *
+ * @brief API for managing the memory stream.
+ * @{
+ */
+
+/**
+ * Simple memory based 'stream', which implements the ReadStream interface for
+ * a plain memory block.
+ */
+class MemoryReadStream : virtual public SeekableReadStream {
+private:
+	const byte * const _ptrOrig;
+	const byte *_ptr;
+	const uint32 _size;
+	uint32 _pos;
+	DisposeAfterUse::Flag _disposeMemory;
+	bool _eos;
+
+public:
+
+	/**
+	 * This constructor takes a pointer to a memory buffer and a length, and
+	 * wraps it. If disposeMemory is true, the MemoryReadStream takes ownership
+	 * of the buffer and hence free's it when destructed.
+	 */
+	MemoryReadStream(const byte *dataPtr, uint32 dataSize, DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO) :
+		_ptrOrig(dataPtr),
+		_ptr(dataPtr),
+		_size(dataSize),
+		_pos(0),
+		_disposeMemory(disposeMemory),
+		_eos(false) {}
+
+	~MemoryReadStream() {
+		if (_disposeMemory)
+			free(const_cast<byte *>(_ptrOrig));
+	}
+
+	uint32 read(void *dataPtr, uint32 dataSize);
+
+	bool eos() const { return _eos; }
+	void clearErr() { _eos = false; }
+
+	int64 pos() const { return _pos; }
+	int64 size() const { return _size; }
+
+	bool seek(int64 offs, int whence = SEEK_SET);
+};
+
+
+/**
+ * This is a MemoryReadStream subclass which adds non-endian
+ * read methods whose endianness is set on the stream creation.
+ */
+class MemoryReadStreamEndian : public MemoryReadStream, public SeekableReadStreamEndian {
+public:
+	MemoryReadStreamEndian(const byte *buf, uint32 len, bool bigEndian, DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO)
+		: MemoryReadStream(buf, len, disposeMemory), SeekableReadStreamEndian(bigEndian), ReadStreamEndian(bigEndian) {}
+
+	int64 pos() const override { return MemoryReadStream::pos(); }
+	int64 size() const override { return MemoryReadStream::size(); }
+
+	bool seek(int64 offs, int whence = SEEK_SET) override { return MemoryReadStream::seek(offs, whence); }
+
+	bool skip(uint32 offset) override { return MemoryReadStream::seek(offset, SEEK_CUR); }
+};
+
+/**
+ * Simple memory based 'stream', which implements the WriteStream interface for
+ * a plain memory block.
+ */
+class MemoryWriteStream : public SeekableWriteStream {
+private:
+	const uint32 _bufSize;
+protected:
+	byte *_ptr;
+	uint32 _pos;
+	bool _err;
+public:
+	MemoryWriteStream(byte *buf, uint32 len) : _ptr(buf), _bufSize(len), _pos(0), _err(false) {}
+
+	uint32 write(const void *dataPtr, uint32 dataSize) override {
+		// Write at most as many bytes as are still available...
+		if (dataSize > _bufSize - _pos) {
+			dataSize = _bufSize - _pos;
+			// We couldn't write all the data => set error indicator
+			_err = true;
+		}
+		memcpy(_ptr, dataPtr, dataSize);
+		_ptr += dataSize;
+		_pos += dataSize;
+		return dataSize;
+	}
+
+	int64 pos() const override { return _pos; }
+	int64 size() const override { return _bufSize; }
+
+	bool err() const override { return _err; }
+	void clearErr() override { _err = false; }
+
+	bool seek(int64 offset, int whence = SEEK_SET) override { return false; }
+};
+
+/**
+ * MemoryWriteStream subclass with ability to set stream position indicator.
+ */
+class SeekableMemoryWriteStream : public MemoryWriteStream {
+private:
+	byte *_ptrOrig;
+public:
+	SeekableMemoryWriteStream(byte *buf, uint32 len) : MemoryWriteStream(buf, len), _ptrOrig(buf) {}
+
+	bool seek(int64 offset, int whence = SEEK_SET) override {
+		switch (whence) {
+		case SEEK_END:
+			// SEEK_END works just like SEEK_SET, only 'reversed',
+			// i.e. from the end.
+			offset = size() + offset;
+			// Fall through
+		case SEEK_SET:
+			// Fall through
+		default:
+			_ptr = _ptrOrig + offset;
+			_pos = offset;
+			break;
+		case SEEK_CUR:
+			_ptr += offset;
+			_pos += offset;
+			break;
+		}
+		// Post-Condition
+		if ((int32)_pos > size()) {
+			_pos = size();
+			_ptr = _ptrOrig + _pos;
+		}
+
+		return true;
+	}
+};
+
+
+/**
+ * A sort of hybrid between MemoryWriteStream and Array classes. A stream
+ * that grows as it's written to.
+ */
+class MemoryWriteStreamDynamic : public SeekableWriteStream {
+protected:
+	uint32 _capacity;
+	uint32 _size;
+	byte *_ptr;
+	byte *_data;
+	uint32 _pos;
+	DisposeAfterUse::Flag _disposeMemory;
+
+	void ensureCapacity(uint32 capacity) {
+		if (capacity <= _capacity)
+			return;
+
+		byte *old_data = _data;
+
+		_capacity = capacity;
+		_data = (byte *)malloc(_capacity);
+		_ptr = _data + _pos;
+
+		if (old_data) {
+			// Copy old data
+			memcpy(_data, old_data, _size);
+			free(old_data);
+		}
+	}
+
+	/** Round up capacity to the next power of 2.
+	  * A minimal capacity of 8 is used.
+	  */
+	static size_t roundUpCapacity(size_t capacity) {
+		size_t capa = 8;
+		while (capa < capacity)
+			capa <<= 1;
+		return capa;
+	}
+public:
+	explicit MemoryWriteStreamDynamic(DisposeAfterUse::Flag disposeMemory) : _capacity(0), _size(0), _ptr(nullptr), _data(nullptr), _pos(0), _disposeMemory(disposeMemory) {}
+
+	~MemoryWriteStreamDynamic() {
+		if (_disposeMemory)
+			free(_data);
+	}
+
+	uint32 write(const void *dataPtr, uint32 dataSize) override {
+		if ((_pos + dataSize) >= _capacity)
+			ensureCapacity(roundUpCapacity(_pos + dataSize));
+
+		memcpy(_ptr, dataPtr, dataSize);
+		_ptr += dataSize;
+		_pos += dataSize;
+		if (_pos > _size)
+			_size = _pos;
+		return dataSize;
+	}
+
+	int64 pos() const override { return _pos; }
+	int64 size() const override { return _size; }
+
+	byte *getData() { return _data; }
+
+	bool seek(int64 offs, int whence = SEEK_SET) override {
+		// Pre-Condition
+		assert(_pos <= _size);
+		switch (whence) {
+		case SEEK_END:
+			// SEEK_END works just like SEEK_SET, only 'reversed', i.e. from the end.
+			offs = _size + offs;
+			// Fall through
+		case SEEK_SET:
+			// Fall through
+		default:
+			_ptr = _data + offs;
+			_pos = offs;
+			break;
+
+		case SEEK_CUR:
+			_ptr += offs;
+			_pos += offs;
+			break;
+		}
+
+		assert(_pos <= _size);
+		return true;
+	}
+};
+
+/**
+* MemoryStream based on RingBuffer. Grows if has insufficient buffer size.
+*/
+class MemoryReadWriteStream : public SeekableReadStream, public SeekableWriteStream {
+private:
+	uint32 _capacity;
+	uint32 _size;
+	byte *_data;
+	uint32 _writePos, _readPos, _pos, _length;
+	DisposeAfterUse::Flag _disposeMemory;
+	bool _eos;
+
+	void ensureCapacity(uint32 new_len) {
+		if (new_len <= _capacity)
+			return;
+
+		byte *old_data = _data;
+		uint32 oldCapacity = _capacity;
+
+		_capacity = MAX(new_len + 32, _capacity * 2);
+		_data = (byte *)malloc(_capacity);
+
+		if (old_data) {
+			// Copy old data
+			if (_readPos < _writePos) {
+				memcpy(_data, old_data + _readPos, _writePos - _readPos);
+				_writePos = _length;
+				_readPos = 0;
+			} else {
+				memcpy(_data, old_data + _readPos, oldCapacity - _readPos);
+				memcpy(_data + oldCapacity - _readPos, old_data, _writePos);
+				_writePos = _length;
+				_readPos = 0;
+			}
+			free(old_data);
+		}
+	}
+public:
+	explicit MemoryReadWriteStream(DisposeAfterUse::Flag disposeMemory) : _capacity(0), _size(0), _data(nullptr), _writePos(0), _readPos(0), _pos(0), _length(0), _disposeMemory(disposeMemory), _eos(false) {}
+
+	~MemoryReadWriteStream() {
+		if (_disposeMemory)
+			free(_data);
+	}
+
+	uint32 write(const void *dataPtr, uint32 dataSize) override {
+		ensureCapacity(_length + dataSize);
+		if (_writePos + dataSize < _capacity) {
+			memcpy(_data + _writePos, dataPtr, dataSize);
+		} else {
+			memcpy(_data + _writePos, dataPtr, _capacity - _writePos);
+			const byte *shiftedPtr = (const byte *)dataPtr + _capacity - _writePos;
+			memcpy(_data, shiftedPtr, dataSize - (_capacity - _writePos));
+		}
+		_writePos = (_writePos + dataSize) % _capacity;
+		_pos += dataSize;
+		_length += dataSize;
+		if (_pos > _size)
+			_size = _pos;
+		return dataSize;
+	}
+
+	uint32 read(void *dataPtr, uint32 dataSize) override {
+		if (_length < dataSize) {
+			dataSize = _length;
+			_eos = true;
+		}
+		if (dataSize == 0 || _capacity == 0) return 0;
+		if (_readPos + dataSize < _capacity) {
+			memcpy(dataPtr, _data + _readPos, dataSize);
+		} else {
+			memcpy(dataPtr, _data + _readPos, _capacity - _readPos);
+			byte *shiftedPtr = (byte *)dataPtr + _capacity - _readPos;
+			memcpy(shiftedPtr, _data, dataSize - (_capacity - _readPos));
+		}
+		_readPos = (_readPos + dataSize) % _capacity;
+		_length -= dataSize;
+		return dataSize;
+	}
+
+	bool seek(int64 offset, int whence) override {
+		switch (whence) {
+		case SEEK_END:
+			// SEEK_END works just like SEEK_SET, only 'reversed',
+			// i.e. from the end.
+			offset = size() + offset;
+			// Fall through
+		case SEEK_SET:
+			// Fall through
+		default:
+			_writePos = offset;
+			_readPos = offset;
+			break;
+		case SEEK_CUR:
+			// Not supported
+			return false;
+		}
+
+		// Post-Condition
+		_eos = (int64)_readPos >= size();
+		return true;
+	}
+
+	int64 pos() const override { return _pos - _length; }
+	int64 size() const override { return _size; }
+	bool eos() const override { return _eos; }
+	void clearErr() override { _eos = false; }
+
+	byte *getData() { return _data; }
+};
+
+/**
+ * A seekable read and writeable memory stream that operates on an already existing memory buffer
+ */
+class MemorySeekableReadWriteStream : public SeekableReadStream, public SeekableWriteStream {
+private:
+	const uint32 _bufSize;
+	byte *_ptrOrig;
+	byte *_ptr;
+	uint32 _pos;
+	bool _err;
+	bool _eos;
+	DisposeAfterUse::Flag _disposeMemory;
+
+public:
+	MemorySeekableReadWriteStream(byte *buf, uint32 len, DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO) :
+			_ptrOrig(buf), _ptr(buf), _bufSize(len), _pos(0), _err(false), _eos(false), _disposeMemory(disposeMemory) {}
+
+	~MemorySeekableReadWriteStream() {
+		if (_disposeMemory) {
+			free(_ptrOrig);
+		}
+	}
+
+	uint32 write(const void *dataPtr, uint32 dataSize) override {
+		// Write at most as many bytes as are still available...
+		if (dataSize > _bufSize - _pos) {
+			dataSize = _bufSize - _pos;
+			// We couldn't write all the data => set error indicator
+			_err = true;
+		}
+		memcpy(_ptr, dataPtr, dataSize);
+		_ptr += dataSize;
+		_pos += dataSize;
+		return dataSize;
+	}
+
+	int64 pos() const override { return _pos; }
+	int64 size() const override { return _bufSize; }
+
+	bool eos() const override { return _eos; }
+
+	bool err() const override { return _err; }
+	void clearErr() override { _err = false; }
+
+	inline void rewind(int32 bytes) {
+		seek(pos() - bytes);
+	}
+
+	byte peekByte() {
+		if (_bufSize - _pos <= 0) {
+			_eos = true;
+			return 0;
+		}
+		return *_ptr;
+	}
+
+	uint32 read(void *dataPtr, uint32 dataSize) override {
+		// Read at most as many bytes as are still available...
+		if (dataSize > _bufSize - _pos) {
+			dataSize = _bufSize - _pos;
+			_eos = true;
+		}
+		memcpy(dataPtr, _ptr, dataSize);
+
+		_ptr += dataSize;
+		_pos += dataSize;
+
+		return dataSize;
+	}
+
+	bool seek(int64 offset, int whence = SEEK_SET) override {
+		switch (whence) {
+		case SEEK_END:
+			// SEEK_END works just like SEEK_SET, only 'reversed',
+			// i.e. from the end.
+			offset = size() + offset;
+			// Fall through
+		case SEEK_SET:
+			// Fall through
+		default:
+			_ptr = _ptrOrig + offset;
+			_pos = offset;
+			break;
+		case SEEK_CUR:
+			_ptr += offset;
+			_pos += offset;
+			break;
+		}
+		// Post-Condition
+		if ((int32)_pos > size()) {
+			_pos = size();
+			_ptr = _ptrOrig + _pos;
+		}
+
+		_eos = false;
+		return true;
+	}
+};
+
+/** @} */
+
+} // End of namespace Common
+
+#endif
diff --git a/common/stream.cpp b/common/stream.cpp
new file mode 100644
index 00000000..aae006b3
--- /dev/null
+++ b/common/stream.cpp
@@ -0,0 +1,550 @@
+/* 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/ptr.h"
+#include "common/stream.h"
+#include "common/memstream.h"
+#include "common/substream.h"
+#include "common/str.h"
+
+namespace Common {
+
+uint32 WriteStream::writeStream(ReadStream *stream, uint32 dataSize) {
+	void *buf = malloc(dataSize);
+	dataSize = stream->read(buf, dataSize);
+	assert(dataSize > 0);
+	dataSize = write(buf, dataSize);
+	free(buf);
+	return dataSize;
+}
+
+uint32 WriteStream::writeStream(SeekableReadStream *stream) {
+	return writeStream(stream, stream->size());
+}
+
+void WriteStream::writeString(const String &str) {
+	write(str.c_str(), str.size());
+}
+
+SeekableReadStream *ReadStream::readStream(uint32 dataSize) {
+	void *buf = malloc(dataSize);
+	dataSize = read(buf, dataSize);
+	assert(dataSize > 0);
+	return new MemoryReadStream((byte *)buf, dataSize, DisposeAfterUse::YES);
+}
+
+Common::String ReadStream::readPascalString(bool transformCR) {
+	Common::String s;
+	char *buf;
+	int len;
+	int i;
+
+	len = readByte();
+	buf = (char *)malloc(len + 1);
+	for (i = 0; i < len; i++) {
+		buf[i] = readByte();
+		if (transformCR && buf[i] == 0x0d)
+			buf[i] = '\n';
+	}
+
+	buf[i] = 0;
+
+	s = buf;
+	free(buf);
+
+	return s;
+}
+
+uint32 MemoryReadStream::read(void *dataPtr, uint32 dataSize) {
+	// Read at most as many bytes as are still available...
+	if (dataSize > _size - _pos) {
+		dataSize = _size - _pos;
+		_eos = true;
+	}
+	memcpy(dataPtr, _ptr, dataSize);
+
+	_ptr += dataSize;
+	_pos += dataSize;
+
+	return dataSize;
+}
+
+bool MemoryReadStream::seek(int64 offs, int whence) {
+	// Pre-Condition
+	assert(_pos <= _size);
+	switch (whence) {
+	case SEEK_END:
+		// SEEK_END works just like SEEK_SET, only 'reversed',
+		// i.e. from the end.
+		offs = _size + offs;
+		// Fall through
+	case SEEK_SET:
+		// Fall through
+	default:
+		_ptr = _ptrOrig + offs;
+		_pos = offs;
+		break;
+
+	case SEEK_CUR:
+		_ptr += offs;
+		_pos += offs;
+		break;
+	}
+	// Post-Condition
+	assert(_pos <= _size);
+
+	// Reset end-of-stream flag on a successful seek
+	_eos = false;
+	return true; // FIXME: STREAM REWRITE
+}
+
+#pragma mark -
+
+enum {
+	LF = 0x0A,
+	CR = 0x0D
+};
+
+char *SeekableReadStream::readLine(char *buf, size_t bufSize, bool handleCR) {
+	assert(buf != nullptr && bufSize > 1);
+	char *p = buf;
+	size_t len = 0;
+	char c = 0;
+
+	// If end-of-file occurs before any characters are read, return NULL
+	// and the buffer contents remain unchanged.
+	if (eos() || err()) {
+		return nullptr;
+	}
+
+	// Loop as long as there is still free space in the buffer,
+	// and the line has not ended
+	while (len + 1 < bufSize && c != LF) {
+		c = readByte();
+
+		if (eos()) {
+			// If end-of-file occurs before any characters are read, return
+			// NULL and the buffer contents remain unchanged.
+			if (len == 0)
+				return nullptr;
+
+			break;
+		}
+
+		// If an error occurs, return NULL and the buffer contents
+		// are indeterminate.
+		if (err())
+			return nullptr;
+
+		// Check for CR or CR/LF
+		// * DOS and Windows use CRLF line breaks
+		// * Unix and macOS use LF line breaks
+		// * Macintosh before macOS used CR line breaks
+		if (c == CR && handleCR) {
+			// Look at the next char -- is it LF? If not, seek back
+			c = readByte();
+
+			if (err()) {
+				return nullptr; // error: the buffer contents are indeterminate
+			}
+			if (eos()) {
+				// The CR was the last character in the file.
+				// Reset the eos() flag since we successfully finished a line
+				clearErr();
+			} else if (c != LF) {
+				seek(-1, SEEK_CUR);
+			}
+
+			// Treat CR & CR/LF as plain LF
+			c = LF;
+		}
+
+		*p++ = c;
+		len++;
+	}
+
+	// We always terminate the buffer if no error occurred
+	*p = 0;
+	return buf;
+}
+
+String SeekableReadStream::readLine(bool handleCR) {
+	// Read a line
+	String line;
+	while (line.lastChar() != '\n') {
+		char buf[256];
+		if (!readLine(buf, 256, handleCR))
+			break;
+		line += buf;
+	}
+
+	if (line.lastChar() == '\n')
+		line.deleteLastChar();
+
+	return line;
+}
+
+uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) {
+	if (dataSize > _end - _pos) {
+		dataSize = _end - _pos;
+		_eos = true;
+	}
+
+	dataSize = _parentStream->read(dataPtr, dataSize);
+	_pos += dataSize;
+
+	return dataSize;
+}
+
+SeekableSubReadStream::SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, DisposeAfterUse::Flag disposeParentStream)
+	: SubReadStream(parentStream, end, disposeParentStream),
+	_parentStream(parentStream),
+	_begin(begin) {
+	assert(_begin <= _end);
+	_pos = _begin;
+	_parentStream->seek(_pos);
+	_eos = false;
+}
+
+bool SeekableSubReadStream::seek(int64 offset, int whence) {
+	assert(_pos >= _begin);
+	assert(_pos <= _end);
+
+	switch (whence) {
+	case SEEK_END:
+		offset = size() + offset;
+		// fallthrough
+	case SEEK_SET:
+		// Fall through
+	default:
+		_pos = _begin + offset;
+		break;
+	case SEEK_CUR:
+		_pos += offset;
+	}
+
+	assert(_pos >= _begin);
+	assert(_pos <= _end);
+
+	bool ret = _parentStream->seek(_pos);
+	if (ret) _eos = false; // reset eos on successful seek
+
+	return ret;
+}
+
+uint32 SafeSeekableSubReadStream::read(void *dataPtr, uint32 dataSize) {
+	// Make sure the parent stream is at the right position
+	seek(0, SEEK_CUR);
+
+	return SeekableSubReadStream::read(dataPtr, dataSize);
+}
+
+#pragma mark -
+
+namespace {
+
+/**
+ * Wrapper class which adds buffering to any given ReadStream.
+ * Users can specify how big the buffer should be, and whether the
+ * wrapped stream should be disposed when the wrapper is disposed.
+ */
+class BufferedReadStream : virtual public ReadStream {
+protected:
+	DisposablePtr<ReadStream> _parentStream;
+	byte *_buf;
+	uint32 _pos;
+	bool _eos; // end of stream
+	uint32 _bufSize;
+	uint32 _realBufSize;
+
+public:
+	BufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream);
+	virtual ~BufferedReadStream();
+
+	bool eos() const override { return _eos; }
+	bool err() const override { return _parentStream->err(); }
+	void clearErr() override { _eos = false; _parentStream->clearErr(); }
+
+	uint32 read(void *dataPtr, uint32 dataSize) override;
+};
+
+BufferedReadStream::BufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream)
+	: _parentStream(parentStream, disposeParentStream),
+	_pos(0),
+	_eos(false),
+	_bufSize(0),
+	_realBufSize(bufSize) {
+
+	assert(parentStream);
+	_buf = new byte[bufSize];
+	assert(_buf);
+}
+
+BufferedReadStream::~BufferedReadStream() {
+	delete[] _buf;
+}
+
+uint32 BufferedReadStream::read(void *dataPtr, uint32 dataSize) {
+	uint32 alreadyRead = 0;
+	const uint32 bufBytesLeft = _bufSize - _pos;
+
+	// Check whether the data left in the buffer suffices....
+	if (dataSize > bufBytesLeft) {
+		// Nope, we need to read more data
+
+		// First, flush the buffer, if it is non-empty
+		if (0 < bufBytesLeft) {
+			memcpy(dataPtr, _buf + _pos, bufBytesLeft);
+			_pos = _bufSize;
+			alreadyRead += bufBytesLeft;
+			dataPtr = (byte *)dataPtr + bufBytesLeft;
+			dataSize -= bufBytesLeft;
+		}
+
+		// At this point the buffer is empty. Now if the read request
+		// exceeds the buffer size, just satisfy it directly.
+		if (dataSize > _realBufSize) {
+			uint32 n = _parentStream->read(dataPtr, dataSize);
+			if (_parentStream->eos())
+				_eos = true;
+
+			// Fill the buffer from the user buffer so a seek back in
+			// the stream into the buffered area brings consistent data.
+			_bufSize = MIN(n, _realBufSize);
+			_pos = _bufSize;
+			memcpy(_buf, (byte *)dataPtr + n - _bufSize, _bufSize);
+
+			return alreadyRead + n;
+		}
+
+		// Refill the buffer.
+		// If we didn't read as many bytes as requested, the reason
+		// is EOF or an error. In that case we truncate the buffer
+		// size, as well as the number of  bytes we are going to
+		// return to the caller.
+		_bufSize = _parentStream->read(_buf, _realBufSize);
+		_pos = 0;
+		if (_bufSize < dataSize) {
+			// we didn't get enough data from parent
+			if (_parentStream->eos())
+				_eos = true;
+			dataSize = _bufSize;
+		}
+	}
+
+	if (dataSize) {
+		// Satisfy the request from the buffer
+		memcpy(dataPtr, _buf + _pos, dataSize);
+		_pos += dataSize;
+	}
+	return alreadyRead + dataSize;
+}
+
+} // End of anonymous namespace
+
+
+ReadStream *wrapBufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream) {
+	if (parentStream)
+		return new BufferedReadStream(parentStream, bufSize, disposeParentStream);
+	return nullptr;
+}
+
+#pragma mark -
+
+namespace {
+
+/**
+ * Wrapper class which adds buffering to any given SeekableReadStream.
+ * @see BufferedReadStream
+ */
+class BufferedSeekableReadStream : public BufferedReadStream, public SeekableReadStream {
+protected:
+	SeekableReadStream *_parentStream;
+public:
+	BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO);
+
+	int64 pos() const override { return _parentStream->pos() - (_bufSize - _pos); }
+	int64 size() const override { return _parentStream->size(); }
+
+	bool seek(int64 offset, int whence = SEEK_SET) override;
+};
+
+BufferedSeekableReadStream::BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream)
+	: BufferedReadStream(parentStream, bufSize, disposeParentStream),
+	_parentStream(parentStream) {
+}
+
+bool BufferedSeekableReadStream::seek(int64 offset, int whence) {
+	// If it is a "local" seek, we may get away with "seeking" around
+	// in the buffer only.
+	_eos = false; // seeking always cancels EOS
+
+	int relOffset = 0;
+	switch (whence) {
+	case SEEK_SET:
+		relOffset = offset - pos();
+		break;
+	case SEEK_CUR:
+		relOffset = offset;
+		break;
+	case SEEK_END:
+		relOffset = (size() + offset) - pos();
+		break;
+	default:
+		break;
+	}
+
+	if ((int)_pos + relOffset >= 0 && _pos + relOffset <= _bufSize) {
+		_pos += relOffset;
+
+		// Note: we do not need to reset parent's eos flag here. It is
+		// sufficient that it is reset when actually seeking in the parent.
+	} else {
+		// Seek was not local enough, so we reset the buffer and
+		// just seek normally in the parent stream.
+		if (whence == SEEK_CUR)
+			offset -= (_bufSize - _pos);
+		// We invalidate the buffer here. This assures that successive seeks
+		// do not have the chance to incorrectly think they seeked back into
+		// the buffer.
+		// Note: This does not take full advantage of the buffer. But it is
+		// a simple way to prevent nasty errors. It would be possible to take
+		// full advantage of the buffer by saving its actual start position.
+		// This seems not worth the effort for this seemingly uncommon use.
+		_pos = _bufSize = 0;
+		_parentStream->seek(offset, whence);
+	}
+
+	return true;
+}
+
+} // End of anonymous namespace
+
+SeekableReadStream *wrapBufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream) {
+	if (parentStream)
+		return new BufferedSeekableReadStream(parentStream, bufSize, disposeParentStream);
+	return nullptr;
+}
+
+#pragma mark -
+
+namespace {
+
+/**
+ * Wrapper class which adds buffering to any WriteStream.
+ */
+class BufferedWriteStream : public SeekableWriteStream {
+protected:
+	WriteStream *_parentStream;
+	byte *_buf;
+	uint32 _pos;
+	const uint32 _bufSize;
+
+	/**
+	 * Write out the data in the buffer.
+	 *
+	 * @note This method is identical to flush() (which actually is
+	 * implemented by calling this method), except that it is not
+	 * virtual, hence there is less overhead calling it.
+	 */
+	bool flushBuffer() {
+		const uint32 bytesToWrite = _pos;
+
+		if (bytesToWrite) {
+			_pos = 0;
+			if (_parentStream->write(_buf, bytesToWrite) != bytesToWrite)
+				return false;
+		}
+		return true;
+	}
+
+public:
+	BufferedWriteStream(WriteStream *parentStream, uint32 bufSize)
+		: _parentStream(parentStream),
+		_pos(0),
+		_bufSize(bufSize) {
+
+		assert(parentStream);
+		_buf = new byte[bufSize];
+		assert(_buf);
+	}
+
+	virtual ~BufferedWriteStream() {
+		const bool flushResult = flushBuffer();
+		assert(flushResult);
+
+		delete _parentStream;
+
+		delete[] _buf;
+	}
+
+	uint32 write(const void *dataPtr, uint32 dataSize) override {
+		// check if we have enough space for writing to the buffer
+		if (_bufSize - _pos >= dataSize) {
+			memcpy(_buf + _pos, dataPtr, dataSize);
+			_pos += dataSize;
+		} else if (_bufSize >= dataSize) {	// check if we can flush the buffer and load the data
+			const bool flushResult = flushBuffer();
+			assert(flushResult);
+			memcpy(_buf, dataPtr, dataSize);
+			_pos += dataSize;
+		} else	{	// too big for our buffer
+			const bool flushResult = flushBuffer();
+			assert(flushResult);
+			return _parentStream->write(dataPtr, dataSize);
+		}
+		return dataSize;
+	}
+
+	bool flush() override { return flushBuffer(); }
+
+	int64 pos() const override { return _pos + _parentStream->pos(); }
+
+	bool seek(int64 offset, int whence) override {
+		flush();
+
+		Common::SeekableWriteStream *sws =
+			dynamic_cast<Common::SeekableWriteStream *>(_parentStream);
+		return sws ? sws->seek(offset, whence) : false;
+	}
+
+	int64 size() const override {
+		Common::SeekableWriteStream *sws =
+			dynamic_cast<Common::SeekableWriteStream *>(_parentStream);
+		return sws ? MAX(sws->pos() + _pos, sws->size()) : -1;
+	}
+};
+
+} // End of anonymous namespace
+
+SeekableWriteStream *wrapBufferedWriteStream(SeekableWriteStream *parentStream, uint32 bufSize) {
+	if (parentStream)
+		return new BufferedWriteStream(parentStream, bufSize);
+	return nullptr;
+}
+
+WriteStream *wrapBufferedWriteStream(WriteStream *parentStream, uint32 bufSize) {
+	if (parentStream)
+		return new BufferedWriteStream(parentStream, bufSize);
+	return nullptr;
+}
+
+} // End of namespace Common
diff --git a/common/stream.h b/common/stream.h
new file mode 100644
index 00000000..f8c66984
--- /dev/null
+++ b/common/stream.h
@@ -0,0 +1,769 @@
+/* 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_STREAM_H
+#define COMMON_STREAM_H
+
+#include "common/endian.h"
+#include "common/scummsys.h"
+#include "common/str.h"
+
+namespace Common {
+
+/**
+ * @defgroup common_stream Streams
+ * @ingroup common
+ *
+ * @brief API for managing readable and writable data streams.
+ *
+ * @{
+ */
+
+class ReadStream;
+class SeekableReadStream;
+
+/**
+ * Virtual base class for both ReadStream and WriteStream.
+ */
+class Stream {
+public:
+	virtual ~Stream() {}
+
+	/**
+	 * Return true if an I/O failure occurred.
+	 *
+	 * This flag is never cleared automatically. In order to clear it,
+	 * the client code must call clearErr() explicitly.
+	 *
+	 * @note The semantics of any implementation of this method is
+	 * supposed to match that of ISO C ferror().
+	 */
+	virtual bool err() const { return false; }
+
+	/**
+	 * Reset the I/O error status as returned by err().
+	 *
+	 * For a ReadStream, also reset the end-of-stream status returned by eos().
+	 *
+	 * @note The semantics of any implementation of this method is
+	 * supposed to match that of ISO C clearerr().
+	 */
+	virtual void clearErr() {}
+};
+
+/**
+ * Generic interface for a writable data stream.
+ */
+class WriteStream : virtual public Stream {
+public:
+	/**
+	 * Write data into the stream. Subclasses must implement this
+	 * method. All other write methods are implemented using it.
+	 *
+	 * @note The semantics of any implementation of this method is
+	 * supposed to match that of ISO C fwrite().
+	 *
+	 * @param dataPtr	Pointer to the data to be written.
+	 * @param dataSize	Number of bytes to be written.
+	 *
+	 * @return The number of bytes that were actually written.
+	 */
+	virtual uint32 write(const void *dataPtr, uint32 dataSize) = 0;
+
+	/**
+	 * Commit any buffered data to the underlying channel or
+	 * storage medium. Unbuffered streams can use the default
+	 * implementation.
+	 *
+	 * @note The semantics of any implementation of this method is
+	 * supposed to match that of ISO C fflush().
+	 *
+	 * @return True on success, false in case of a failure.
+	 */
+	virtual bool flush() { return true; }
+
+	/**
+	 * Finalize and close this stream.
+	 *
+	 * Call this method right before this stream instance is deleted.
+	 * The goal is to enable the client code to detect
+	 * and handle I/O errors that might occur when closing
+	 * (and flushing, if buffered) the stream.
+	 *
+	 * After this method has been called, no further writes can be
+	 * performed on the stream. Calling err() is allowed.
+	 *
+	 * By default, this just flushes the stream.
+	 */
+	virtual void finalize() {
+		flush();
+	}
+
+	/**
+	* Obtain the current value of the stream position indicator.
+	*
+	* @return The current position indicator, or -1 if an error occurred.
+	 */
+	virtual int64 pos() const = 0;
+
+	/**
+	 * @name Functions for writing data
+	 *
+	 * The following methods all have default implementations.
+	 * Subclasses need not (and should not) overload them.
+	 * @{
+	 */
+
+	/**
+	 * Write the given byte to the current position in the stream.
+	 */
+	void writeByte(byte value) {
+		write(&value, 1);
+	}
+	/**
+	 * Write the given signed byte to the current position in the stream.
+	 */
+	void writeSByte(int8 value) {
+		write(&value, 1);
+	}
+	/**
+	 * Write an unsigned 16-bit word stored in little endian order into the stream.
+	 */
+	void writeUint16LE(uint16 value) {
+		value = TO_LE_16(value);
+		write(&value, 2);
+	}
+	/**
+	 * Write an unsigned 32-bit word stored in little endian order into the stream.
+	 */
+	void writeUint32LE(uint32 value) {
+		value = TO_LE_32(value);
+		write(&value, 4);
+	}
+	/**
+	 * Write an unsigned 64-bit word stored in little endian order into the stream.
+	 */
+	void writeUint64LE(uint64 value) {
+		value = TO_LE_64(value);
+		write(&value, 8);
+	}
+	/**
+	 * Write an unsigned 16-bit word stored in big endian order into the stream.
+	 */
+	void writeUint16BE(uint16 value) {
+		value = TO_BE_16(value);
+		write(&value, 2);
+	}
+	/**
+	 * Write an unsigned 32-bit word stored in big endian order into the stream.
+	 */
+	void writeUint32BE(uint32 value) {
+		value = TO_BE_32(value);
+		write(&value, 4);
+	}
+	/**
+	 * Write an unsigned 64-bit word stored in big endian order into the stream.
+	 */
+	void writeUint64BE(uint64 value) {
+		value = TO_BE_64(value);
+		write(&value, 8);
+	}
+	/**
+	 * Write a signed 16-bit word stored in little endian order into the stream.
+	 */
+	FORCEINLINE void writeSint16LE(int16 value) {
+		writeUint16LE((uint16)value);
+	}
+	/**
+	 * Write a signed 32-bit word stored in little endian order into the stream.
+	 */
+	FORCEINLINE void writeSint32LE(int32 value) {
+		writeUint32LE((uint32)value);
+	}
+	/**
+	 * Write a signed 64-bit word stored in little endian order into the stream.
+	 */
+	FORCEINLINE void writeSint64LE(int64 value) {
+		writeUint64LE((uint64)value);
+	}
+	/**
+	 * Write a signed 16-bit word stored in big endian order into the stream.
+	 */
+	FORCEINLINE void writeSint16BE(int16 value) {
+		writeUint16BE((uint16)value);
+	}
+	/**
+	 * Write a signed 32-bit word stored in big endian order into the stream.
+	 */
+	FORCEINLINE void writeSint32BE(int32 value) {
+		writeUint32BE((uint32)value);
+	}
+	/**
+	 * Write a signed 64-bit word stored in big endian order into the stream.
+	 */
+	FORCEINLINE void writeSint64BE(int64 value) {
+		writeUint64BE((uint64)value);
+	}
+
+
+	/**
+	 * Write a 32-bit floating point value
+	 * stored in little endian (LSB first) order into the stream.
+	 */
+	FORCEINLINE void writeFloatLE(float value) {
+		uint32 n;
+
+		memcpy(&n, &value, 4);
+
+		writeUint32LE(n);
+	}
+
+
+	/**
+	 * Write a 32-bit floating point value
+	 * stored in big endian order into the stream.
+	 */
+	FORCEINLINE void writeFloatBE(float value) {
+		uint32 n;
+
+		memcpy(&n, &value, 4);
+
+		writeUint32BE(n);
+	}
+
+	/**
+	 * Write a 64-bit floating point value (with decimals)
+	 * stored in little endian (LSB first) order into the stream.
+	 */
+	FORCEINLINE void writeDoubleLE(double value) {
+		uint64 n;
+
+		memcpy(&n, &value, 8);
+
+		writeUint64LE(n);
+	}
+
+
+	/**
+	 * Write the given 64-bit floating point value (with decimals)
+	 * stored in big endian order into the stream.
+	 */
+	FORCEINLINE void writeDoubleBE(double value) {
+		uint64 n;
+
+		memcpy(&n, &value, 8);
+
+		writeUint64BE(n);
+	}
+
+	/**
+	 * Write at most @p dataSize of data from another stream into this one,
+	 * starting from the current stream position.
+	 *
+	 * @return The number of bytes written into the stream.
+	 */
+	uint32 writeStream(ReadStream *stream, uint32 dataSize);
+	/**
+	 * Write data from another stream into this one,
+	 * starting from its current position to the end of the stream.
+	 *
+	 * @return The number of bytes written into the stream.
+	 */
+	uint32 writeStream(SeekableReadStream *stream);
+
+	/**
+	 * Write the given string to the stream.
+	 * This writes str.size() characters, but no terminating zero byte.
+	 */
+	void writeString(const String &str);
+	/** @} */
+};
+
+/**
+ * Derived abstract base class for write streams that are seekable.
+ */
+class SeekableWriteStream : public WriteStream {
+public:
+	/**
+	 * Set the stream position indicator for the stream.
+	 *
+	 * The new position, measured in bytes, is obtained by adding offset bytes
+	 * to the position specified by whence. If whence is set to SEEK_SET, SEEK_CUR,
+	 * or SEEK_END, the offset is relative to the start of the file, the current
+	 * position indicator, or end-of-stream, respectively. A successful call
+	 * to the seek() method clears the end-of-stream indicator for the stream.
+	 *
+	 * @note The semantics of any implementation of this method is
+	 * supposed to match that of ISO C fseek().
+	 *
+	 * @param offset        The relative offset in bytes.
+	 * @param whence        The seek reference: SEEK_SET, SEEK_CUR, or SEEK_END.
+	 *
+	 * @return True on success, false in case of a failure.
+	 */
+	virtual bool seek(int64 offset, int whence = SEEK_SET) = 0;
+
+	/**
+	 * Obtain the current size of the stream, measured in bytes.
+	 *
+	 * If this value is unknown or cannot be computed, -1 is returned.
+	 *
+	 * @return The size of the stream, or -1 if an error occurred.
+	 */
+	virtual int64 size() const = 0;
+};
+
+/**
+ * Generic interface for a readable data stream.
+ */
+class ReadStream : virtual public Stream {
+public:
+	ReadStream() {}
+
+	/**
+	 * Return true if a read failed because the stream end has been reached.
+	 *
+	 * This flag is cleared by clearErr().
+	 * For a SeekableReadStream, the flag is also cleared by a successful seek.
+	 *
+	 * @note The semantics of any implementation of this method is
+	 * supposed to match that of ISO C feof(). In particular, in a stream
+	 * with N bytes, reading exactly N bytes from the start should *not*
+	 * set eos; only reading *beyond* the available data should set it.
+	 */
+	virtual bool eos() const = 0;
+
+	/**
+	 * Read data from the stream.
+	 *
+	 * Subclasses must implement this method.
+	 * All other read methods are implemented using it.
+	 *
+	 * @note The semantics of any implementation of this method is
+	 * supposed to match that of ISO C fread(), in particular where
+	 * it concerns setting error and end of file/stream flags.
+	 *
+	 * @param dataPtr	Pointer to a buffer into which the data is read.
+	 * @param dataSize	Number of bytes to be read.
+	 *
+	 * @return The number of bytes that were actually read.
+	 */
+	virtual uint32 read(void *dataPtr, uint32 dataSize) = 0;
+
+	/**
+	 * @name Functions for reading data
+	 *
+	 * The following methods all have default implementations.
+	 * Subclasses in general should not overload them.
+	 * @{
+	 */
+
+	/**
+	 * Read an unsigned byte from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	byte readByte() {
+		byte b = 0; // FIXME: remove initialisation
+		read(&b, 1);
+		return b;
+	}
+
+	/**
+	 * Read a signed byte from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE int8 readSByte() {
+		return (int8)readByte();
+	}
+
+	/**
+	 * Read an unsigned 16-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	uint16 readUint16LE() {
+		uint16 val;
+		read(&val, 2);
+		return FROM_LE_16(val);
+	}
+
+	/**
+	 * Read an unsigned 32-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	uint32 readUint32LE() {
+		uint32 val;
+		read(&val, 4);
+		return FROM_LE_32(val);
+	}
+
+	/**
+	 * Read an unsigned 64-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	uint64 readUint64LE() {
+		uint64 val;
+		read(&val, 8);
+		return FROM_LE_64(val);
+	}
+
+	/**
+	 * Read an unsigned 16-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	uint16 readUint16BE() {
+		uint16 val;
+		read(&val, 2);
+		return FROM_BE_16(val);
+	}
+
+	/**
+	 * Read an unsigned 32-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	uint32 readUint32BE() {
+		uint32 val;
+		read(&val, 4);
+		return FROM_BE_32(val);
+	}
+
+	/**
+	 * Read an unsigned 64-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	uint64 readUint64BE() {
+		uint64 val;
+		read(&val, 8);
+		return FROM_BE_64(val);
+	}
+
+	/**
+	 * Read a signed 16-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE int16 readSint16LE() {
+		return (int16)readUint16LE();
+	}
+
+	/**
+	 * Read a signed 32-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE int32 readSint32LE() {
+		return (int32)readUint32LE();
+	}
+
+	/**
+	 * Read a signed 64-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE int64 readSint64LE() {
+		return (int64)readUint64LE();
+	}
+
+	/**
+	 * Read a signed 16-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE int16 readSint16BE() {
+		return (int16)readUint16BE();
+	}
+
+	/**
+	 * Read a signed 32-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE int32 readSint32BE() {
+		return (int32)readUint32BE();
+	}
+
+	/**
+	 * Read a signed 64-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 *
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which the client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE int64 readSint64BE() {
+		return (int64)readUint64BE();
+	}
+
+	/**
+	 * Read the specified amount of data into a malloc'ed buffer
+	 * which is then wrapped into a MemoryReadStream.
+	 *
+	 * The returned stream might contain less data than requested
+	 * if reading more data failed. This is because of an I/O error or because
+	 * the end of the stream was reached. It can be determined by
+	 * calling err() and eos().
+	 */
+	SeekableReadStream *readStream(uint32 dataSize);
+
+	/**
+	 * Read a string in Pascal format, that is, one byte is
+	 * string length, followed by string data.
+	 *
+	 * @param transformCR	If set (default), then transform \\r into \\n.
+	 */
+	Common::String readPascalString(bool transformCR = true);
+	/** @} */
+};
+
+/**
+ * Interface for a seekable and readable data stream.
+ *
+ * @todo Get rid of SEEK_SET, SEEK_CUR, or SEEK_END, use our own constants.
+ */
+class SeekableReadStream : virtual public ReadStream {
+public:
+
+	/**
+	 * Obtain the current value of the stream position indicator.
+	 *
+	 * @return The current position indicator, or -1 if an error occurred.
+	 */
+	virtual int64 pos() const = 0;
+
+	/**
+	 * Obtain the total size of the stream, measured in bytes.
+	 * If this value is unknown or cannot be computed, -1 is returned.
+	 *
+	 * @return The size of the stream, or -1 if an error occurred.
+	 */
+	virtual int64 size() const = 0;
+
+	/**
+	 * Set the stream position indicator for the stream.
+	 *
+	 * The new position, measured in bytes, is obtained by adding offset bytes
+	 * to the position specified by whence. If whence is set to SEEK_SET, SEEK_CUR,
+	 * or SEEK_END, the offset is relative to the start of the file, the current
+	 * position indicator, or end-of-stream, respectively. A successful call
+	 * to the seek() method clears the end-of-stream indicator for the stream.
+	 *
+	 * @note The semantics of any implementation of this method is
+	 * supposed to match that of ISO C fseek().
+	 *
+	 * @param offset	Relative offset in bytes.
+	 * @param whence	Seek reference: SEEK_SET, SEEK_CUR, or SEEK_END.
+	 *
+	 * @return True on success, false in case of a failure.
+	 */
+	virtual bool seek(int64 offset, int whence = SEEK_SET) = 0;
+
+	/**
+	 * Skip the given number of bytes in the stream.
+	 *
+	 * This is equivalent to calling:
+	 * @code
+	 * seek(offset, SEEK_CUR)
+	 * @endcode
+	 * to add the given number of bytes to the current position indicator of the stream.
+	 *
+	 * @return True on success, false in case of a failure.
+	 */
+	virtual bool skip(uint32 offset) { return seek(offset, SEEK_CUR); }
+
+	/**
+	 * Read at most one less than the number of characters specified
+	 * by @p bufSize from the stream and store them in the string buffer.
+	 *
+	 * Reading stops when the end of a line is reached (CR, CR/LF, or LF),
+	 * and at end-of-stream or error. The newline, if any, is retained (CR
+	 * and CR/LF are translated to ``LF = 0xA = '\n'``). If any characters
+	 * are read and there is no error, a `\0` character is appended
+	 * to end the string.
+	 *
+	 * Upon successful completion, return a pointer to the string. If
+	 * end-of-stream occurs before any characters are read, returns NULL
+	 * and the buffer contents remain unchanged. If an error occurs,
+	 * returns NULL and the buffer contents are indeterminate.
+	 * This method does not distinguish between end-of-stream and error;
+	 * callers must use err() or eos() to determine which occurred.
+	 *
+	 * @note This method is closely modeled after the standard fgets()
+	 *       function from stdio.h.
+	 *
+	 * @param s         The buffer to store into.
+	 * @param bufSize	Size of the buffer.
+	 * @param handleCR	If set (default), then CR and CR/LF are handled, as well as LF.
+	 *
+	 * @return Pointer to the read string, or NULL if an error occurred.
+	 */
+	virtual char *readLine(char *s, size_t bufSize, bool handleCR = true);
+
+
+	/**
+	 * Read a full line and returns it as a Common::String.
+	 *
+	 * Reading stops when the end of a line is reached (CR, CR/LF, or LF),
+	 * and at end-of-stream or error.
+	 *
+	 * Upon successful completion, return a string with the content
+	 * of the line, *without* the end of a line marker. This method
+	 * does not indicate whether an error occurred. Callers must use
+	 * err() or eos() to determine whether an exception occurred.
+	 *
+	 * @param handleCR	If set (default), then CR and CR/LF are handled, as well as LF.
+	 */
+	virtual String readLine(bool handleCR = true);
+};
+
+/**
+ * ReadStream mixin subclass that adds non-endian read
+ * methods whose endianness is set during the stream creation.
+ */
+class ReadStreamEndian : virtual public ReadStream {
+private:
+	const bool _bigEndian;
+
+public:
+	/**
+	 * Set the endianness of the read stream.
+	 *
+	 * @param bigEndian If true, create a big endian stream.
+	 *                  If false, create a little endian stream.
+	 */
+	ReadStreamEndian(bool bigEndian) : _bigEndian(bigEndian) {}
+	/**
+	 * Return true if data is encoded in big endian order.
+	 */
+	bool isBE() const { return _bigEndian; }
+	/**
+	 * Read an unsigned 16-bit word using the stream endianness
+	 * and return it in native endianness.
+	 */
+	uint16 readUint16() {
+		uint16 val;
+		read(&val, 2);
+		return (_bigEndian) ? FROM_BE_16(val) : FROM_LE_16(val);
+	}
+	/**
+	 * Read an unsigned 32-bit word using the stream endianness
+	 * and return it in native endianness.
+	 */
+	uint32 readUint32() {
+		uint32 val;
+		read(&val, 4);
+		return (_bigEndian) ? FROM_BE_32(val) : FROM_LE_32(val);
+	}
+	/**
+	 * Read an unsigned 64-bit word using the stream endianness
+	 * and return it in native endianness.
+	 */
+	uint64 readUint64() {
+		uint64 val;
+		read(&val, 8);
+		return (_bigEndian) ? FROM_BE_64(val) : FROM_LE_64(val);
+	}
+	/**
+	 * Read a signed 16-bit word using the stream endianness
+	 * and return it in native endianness.
+	 */
+	FORCEINLINE int16 readSint16() {
+		return (int16)readUint16();
+	}
+	/**
+	 * Read a signed 32-bit word using the stream endianness
+	 * and return it in native endianness.
+	 */
+	FORCEINLINE int32 readSint32() {
+		return (int32)readUint32();
+	}
+	/**
+	 * Read a signed 64-bit word using the stream endianness
+	 * and return it in native endianness.
+	 */
+	FORCEINLINE int64 readSint64() {
+		return (int64)readUint64();
+	}
+};
+
+/**
+ * SeekableReadStream subclass that adds non-endian read
+ * methods whose endianness is set during the stream creation.
+ */
+class SeekableReadStreamEndian : virtual public SeekableReadStream, virtual public ReadStreamEndian {
+public:
+	/**
+	 * Set the endianness of the read stream.
+	 *
+	 * @param bigEndian If true, create a big endian stream.
+	 *                  If false, create a little endian stream.
+	 */
+	SeekableReadStreamEndian(bool bigEndian) : ReadStreamEndian(bigEndian) {}
+};
+
+/** @} */
+
+} // End of namespace Common
+
+#endif
diff --git a/common/substream.h b/common/substream.h
new file mode 100644
index 00000000..4082f0e9
--- /dev/null
+++ b/common/substream.h
@@ -0,0 +1,138 @@
+/* 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_SUBSTREAM_H
+#define COMMON_SUBSTREAM_H
+
+#include "common/ptr.h"
+#include "common/stream.h"
+#include "common/types.h"
+
+namespace Common {
+
+/**
+ * @defgroup common_substream Substreams
+ * @ingroup common_stream
+ *
+ * @brief API for managing readable data substreams.
+ *
+ * @{
+ */
+
+/**
+ * SubReadStream provides access to a ReadStream restricted to the range
+ * [currentPosition, currentPosition+end).
+ *
+ * Manipulating the parent stream directly /will/ mess up a substream.
+ * Likewise, manipulating two substreams of a parent stream will cause them to
+ * step on each others toes.
+ */
+class SubReadStream : virtual public ReadStream {
+protected:
+	DisposablePtr<ReadStream> _parentStream;
+	uint32 _pos;
+	uint32 _end;
+	bool _eos;
+public:
+	SubReadStream(ReadStream *parentStream, uint32 end, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO)
+		: _parentStream(parentStream, disposeParentStream),
+		  _pos(0),
+		  _end(end),
+		  _eos(false) {
+		assert(parentStream);
+	}
+
+	virtual bool eos() const { return _eos | _parentStream->eos(); }
+	virtual bool err() const { return _parentStream->err(); }
+	virtual void clearErr() { _eos = false; _parentStream->clearErr(); }
+	virtual uint32 read(void *dataPtr, uint32 dataSize);
+};
+
+/*
+ * SeekableSubReadStream provides access to a SeekableReadStream restricted to
+ * the range [begin, end).
+ * The same caveats apply to SeekableSubReadStream as do to SeekableReadStream.
+ *
+ * Manipulating the parent stream directly /will/ mess up a substream.
+ * @see SubReadStream
+ */
+class SeekableSubReadStream : public SubReadStream, virtual public SeekableReadStream {
+protected:
+	SeekableReadStream *_parentStream;
+	uint32 _begin;
+public:
+	SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO);
+
+	virtual int64 pos() const { return _pos - _begin; }
+	virtual int64 size() const { return _end - _begin; }
+
+	virtual bool seek(int64 offset, int whence = SEEK_SET);
+};
+
+/**
+ * This is a SeekableSubReadStream subclass which adds non-endian
+ * read methods whose endianness is set on the stream creation.
+ *
+ * Manipulating the parent stream directly /will/ mess up a substream.
+ * @see SubReadStream
+ */
+class SeekableSubReadStreamEndian :  virtual public SeekableSubReadStream, virtual public SeekableReadStreamEndian {
+public:
+	SeekableSubReadStreamEndian(SeekableReadStream *parentStream, uint32 begin, uint32 end, bool bigEndian, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO)
+		: SeekableSubReadStream(parentStream, begin, end, disposeParentStream),
+		  SeekableReadStreamEndian(bigEndian),
+		  ReadStreamEndian(bigEndian) {
+	}
+
+	int64 pos() const override { return SeekableSubReadStream::pos(); }
+	int64 size() const override { return SeekableSubReadStream::size(); }
+
+	bool seek(int64 offset, int whence = SEEK_SET) override { return SeekableSubReadStream::seek(offset, whence); }
+	bool skip(uint32 offset) override { return SeekableSubReadStream::seek(offset, SEEK_CUR); }
+};
+
+/**
+ * A seekable substream that removes the exclusivity demand required by the
+ * normal SeekableSubReadStream, at the cost of seek()ing the parent stream
+ * before each read().
+ *
+ * More than one SafeSeekableSubReadStream to the same parent stream can be used
+ * at the same time; they won't mess up each other. They will, however,
+ * reposition the parent stream, so don't depend on its position to be
+ * the same after a read() or seek() on one of its SafeSeekableSubReadStream.
+ *
+ * Note that this stream is *not* threading safe. Calling read from the audio
+ * thread and from the main thread might mess up the data retrieved.
+ */
+class SafeSeekableSubReadStream : public SeekableSubReadStream {
+public:
+	SafeSeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO)
+		: SeekableSubReadStream(parentStream, begin, end, disposeParentStream) {
+	}
+
+	virtual uint32 read(void *dataPtr, uint32 dataSize);
+};
+
+/** @} */
+
+} // End of namespace Common
+
+#endif


Commit: 7b9337fe2bbc8d4a472e513c7f386e7be6622f23
    https://github.com/scummvm/scummvm-tools/commit/7b9337fe2bbc8d4a472e513c7f386e7be6622f23
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-20T16:59:55+01:00

Commit Message:
COMMON: Import common/dcl.cpp

Changed paths:
  A common/dcl.cpp
  A common/dcl.h


diff --git a/common/dcl.cpp b/common/dcl.cpp
new file mode 100644
index 00000000..83e227a6
--- /dev/null
+++ b/common/dcl.cpp
@@ -0,0 +1,509 @@
+/* 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/dcl.h"
+#include "common/memstream.h"
+#include "common/stream.h"
+
+namespace Common {
+
+class DecompressorDCL {
+public:
+	bool unpack(SeekableReadStream *sourceStream, WriteStream *targetStream, uint32 targetSize, bool targetFixedSize);
+
+protected:
+	/**
+	 * Initialize decompressor.
+	 * @param sourceStream	source stream to read from
+	 * @param targetStream	target memory stream to write to
+	 */
+	void init(SeekableReadStream *sourceStream, WriteStream *targetStream, uint32 targetSize, bool targetFixedSize);
+
+	/**
+	 * Get a number of bits from _src stream, starting with the least
+	 * significant unread bit of the current four byte block.
+	 * @param n		number of bits to get
+	 * @return n-bits number
+	 */
+	uint32 getBitsLSB(int n);
+
+	/**
+	 * Get one byte from _src stream.
+	 * @return byte
+	 */
+	byte getByteLSB();
+
+	void fetchBitsLSB();
+
+	/**
+	 * Write one byte into _dest stream
+	 * @param b byte to put
+	 */
+	void putByte(byte b);
+
+	int huffman_lookup(const int *tree);
+
+	uint32 _dwBits;			///< bits buffer
+	byte _nBits;			///< number of unread bits in _dwBits
+	uint32 _sourceSize;		///< size of the source stream
+	uint32 _targetSize;		///< size of the target stream (if fixed)
+	bool _targetFixedSize;  ///< if target stream is fixed size or dynamic size
+	uint32 _bytesRead;		///< number of bytes read from _sourceStream
+	uint32 _bytesWritten;	///< number of bytes written to _targetStream
+	SeekableReadStream *_sourceStream;
+	WriteStream *_targetStream;
+};
+
+void DecompressorDCL::init(SeekableReadStream *sourceStream, WriteStream *targetStream, uint32 targetSize, bool targetFixedSize) {
+	_sourceStream = sourceStream;
+	_targetStream = targetStream;
+	_sourceSize = sourceStream->size();
+	_targetSize = targetSize;
+	_targetFixedSize = targetFixedSize;
+	_nBits = 0;
+	_bytesRead = _bytesWritten = 0;
+	_dwBits = 0;
+}
+
+void DecompressorDCL::fetchBitsLSB() {
+	while (_nBits <= 24) {
+		_dwBits |= ((uint32)_sourceStream->readByte()) << _nBits;
+		_nBits += 8;
+		_bytesRead++;
+	}
+}
+
+uint32 DecompressorDCL::getBitsLSB(int n) {
+	// Fetching more data to buffer if needed
+	if (_nBits < n)
+		fetchBitsLSB();
+	uint32 ret = (_dwBits & ~(~0UL << n));
+	_dwBits >>= n;
+	_nBits -= n;
+	return ret;
+}
+
+byte DecompressorDCL::getByteLSB() {
+	return getBitsLSB(8);
+}
+
+void DecompressorDCL::putByte(byte b) {
+	_targetStream->writeByte(b);
+	_bytesWritten++;
+}
+
+#define HUFFMAN_LEAF 0x40000000
+// Branch node
+#define BN(pos, left, right)  ((left << 12) | (right)),
+// Leaf node
+#define LN(pos, value)  ((value) | HUFFMAN_LEAF),
+
+static const int length_tree[] = {
+	BN(0, 1, 2)
+	BN(1, 3, 4)     BN(2, 5, 6)
+	BN(3, 7, 8)     BN(4, 9, 10)    BN(5, 11, 12)  LN(6, 1)
+	BN(7, 13, 14)   BN(8, 15, 16)   BN(9, 17, 18)  LN(10, 3)  LN(11, 2)  LN(12, 0)
+	BN(13, 19, 20)  BN(14, 21, 22)  BN(15, 23, 24) LN(16, 6)  LN(17, 5)  LN(18, 4)
+	BN(19, 25, 26)  BN(20, 27, 28)  LN(21, 10)     LN(22, 9)  LN(23, 8)  LN(24, 7)
+	BN(25, 29, 30)  LN(26, 13)      LN(27, 12)     LN(28, 11)
+	LN(29, 15)      LN(30, 14)
+	0 // We need something witout a comma at the end
+};
+
+static const int distance_tree[] = {
+	BN(0, 1, 2)
+	BN(1, 3, 4)       BN(2, 5, 6)
+	//
+	BN(3, 7, 8)       BN(4, 9, 10)      BN(5, 11, 12)     LN(6, 0)
+	BN(7, 13, 14)     BN(8, 15, 16)     BN(9, 17, 18)     BN(10, 19, 20)
+	BN(11, 21, 22)    BN(12, 23, 24)
+	//
+	BN(13, 25, 26)    BN(14, 27, 28)    BN(15, 29, 30)    BN(16, 31, 32)
+	BN(17, 33, 34)    BN(18, 35, 36)    BN(19, 37, 38)    BN(20, 39, 40)
+	BN(21, 41, 42)    BN(22, 43, 44)    LN(23, 2)         LN(24, 1)
+	//
+	BN(25, 45, 46)    BN(26, 47, 48)    BN(27, 49, 50)    BN(28, 51, 52)
+	BN(29, 53, 54)    BN(30, 55, 56)    BN(31, 57, 58)    BN(32, 59, 60)
+	BN(33, 61, 62)	  BN(34, 63, 64)    BN(35, 65, 66)    BN(36, 67, 68)
+	BN(37, 69, 70)    BN(38, 71, 72)    BN(39, 73, 74)    BN(40, 75, 76)
+	LN(41, 6)         LN(42, 5)         LN(43, 4)         LN(44, 3)
+	//
+	BN(45, 77, 78)    BN(46, 79, 80)    BN(47, 81, 82)    BN(48, 83, 84)
+	BN(49, 85, 86)    BN(50, 87, 88)    BN(51, 89, 90)    BN(52, 91, 92)
+	BN(53, 93, 94)    BN(54, 95, 96)    BN(55, 97, 98)    BN(56, 99, 100)
+	BN(57, 101, 102)  BN(58, 103, 104)  BN(59, 105, 106)  BN(60, 107, 108)
+	BN(61, 109, 110)  LN(62, 21)        LN(63, 20)        LN(64, 19)
+	LN(65, 18)        LN(66, 17)        LN(67, 16)        LN(68, 15)
+	LN(69, 14)        LN(70, 13)        LN(71, 12)        LN(72, 11)
+	LN(73, 10)        LN(74, 9)         LN(75, 8)         LN(76, 7)
+	//
+	BN(77, 111, 112)  BN(78, 113, 114)  BN(79, 115, 116)  BN(80, 117, 118)
+	BN(81, 119, 120)  BN(82, 121, 122)  BN(83, 123, 124)  BN(84, 125, 126)
+	LN(85, 47)        LN(86, 46)        LN(87, 45)        LN(88, 44)
+	LN(89, 43)        LN(90, 42)        LN(91, 41)        LN(92, 40)
+	LN(93, 39)        LN(94, 38)        LN(95, 37)        LN(96, 36)
+	LN(97, 35)        LN(98, 34)        LN(99, 33)        LN(100, 32)
+	LN(101, 31)       LN(102, 30)       LN(103, 29)       LN(104, 28)
+	LN(105, 27)       LN(106, 26)       LN(107, 25)       LN(108, 24)
+	LN(109, 23)       LN(110, 22)       LN(111, 63)       LN(112, 62)
+	LN(113, 61)       LN(114, 60)       LN(115, 59)       LN(116, 58)
+	LN(117, 57)       LN(118, 56)       LN(119, 55)       LN(120, 54)
+	LN(121, 53)       LN(122, 52)       LN(123, 51)       LN(124, 50)
+	LN(125, 49)       LN(126, 48)
+	0 // We need something witout a comma at the end
+};
+
+static const int ascii_tree[] = {
+	BN(0, 1, 2)       BN(1, 3, 4)       BN(2, 5, 6)       BN(3, 7, 8)
+	BN(4, 9, 10)      BN(5, 11, 12)     BN(6, 13, 14)     BN(7, 15, 16)
+	BN(8, 17, 18)     BN(9, 19, 20)     BN(10, 21, 22)    BN(11, 23, 24)
+	BN(12, 25, 26)    BN(13, 27, 28)    BN(14, 29, 30)    BN(15, 31, 32)
+	BN(16, 33, 34)    BN(17, 35, 36)    BN(18, 37, 38)    BN(19, 39, 40)
+	BN(20, 41, 42)    BN(21, 43, 44)    BN(22, 45, 46)    BN(23, 47, 48)
+	BN(24, 49, 50)    BN(25, 51, 52)    BN(26, 53, 54)    BN(27, 55, 56)
+	BN(28, 57, 58)    BN(29, 59, 60)    LN(30, 32)
+	//
+	BN(31, 61, 62)    BN(32, 63, 64)    BN(33, 65, 66)    BN(34, 67, 68)
+	BN(35, 69, 70)    BN(36, 71, 72)    BN(37, 73, 74)    BN(38, 75, 76)
+	BN(39, 77, 78)    BN(40, 79, 80)    BN(41, 81, 82)    BN(42, 83, 84)
+	BN(43, 85, 86)    BN(44, 87, 88)    BN(45, 89, 90)    BN(46, 91, 92)
+	BN(47, 93, 94)    BN(48, 95, 96)    BN(49, 97, 98)    LN(50, 117)
+	LN(51, 116)       LN(52, 115)       LN(53, 114)       LN(54, 111)
+	LN(55, 110)       LN(56, 108)       LN(57, 105)       LN(58, 101)
+	LN(59, 97)        LN(60, 69)
+	//
+	BN(61, 99, 100)   BN(62, 101, 102)  BN(63, 103, 104)  BN(64, 105, 106)
+	BN(65, 107, 108)  BN(66, 109, 110)	BN(67, 111, 112)  BN(68, 113, 114)
+	BN(69, 115, 116)  BN(70, 117, 118)  BN(71, 119, 120)  BN(72, 121, 122)
+	BN(73, 123, 124)  BN(74, 125, 126)  BN(75, 127, 128)  BN(76, 129, 130)
+	BN(77, 131, 132)  BN(78, 133, 134)  LN(79, 112)       LN(80, 109)
+	LN(81, 104)       LN(82, 103)       LN(83, 102)       LN(84, 100)
+	LN(85, 99)        LN(86, 98)        LN(87, 84)        LN(88, 83)
+	LN(89, 82)        LN(90, 79)        LN(91, 78)        LN(92, 76)
+	LN(93, 73)        LN(94, 68)        LN(95, 67)        LN(96, 65)
+	LN(97, 49)        LN(98, 45)
+	//
+	BN(99, 135, 136)  BN(100, 137, 138) BN(101, 139, 140) BN(102, 141, 142)
+	BN(103, 143, 144) BN(104, 145, 146)	BN(105, 147, 148) BN(106, 149, 150)
+	BN(107, 151, 152) BN(108, 153, 154) BN(109, 155, 156) BN(110, 157, 158)
+	BN(111, 159, 160) BN(112, 161, 162) BN(113, 163, 164) LN(114, 119)
+	LN(115, 107)      LN(116, 85)       LN(117, 80)       LN(118, 77)
+	LN(119, 70)       LN(120, 66)       LN(121, 61)       LN(122, 56)
+	LN(123, 55)       LN(124, 53)       LN(125, 52)       LN(126, 51)
+	LN(127, 50)       LN(128, 48)       LN(129, 46)       LN(130, 44)
+	LN(131, 41)       LN(132, 40)       LN(133, 13)       LN(134, 10)
+	//
+	BN(135, 165, 166) BN(136, 167, 168) BN(137, 169, 170) BN(138, 171, 172)
+	BN(139, 173, 174) BN(140, 175, 176) BN(141, 177, 178) BN(142, 179, 180)
+	BN(143, 181, 182) BN(144, 183, 184) BN(145, 185, 186) BN(146, 187, 188)
+	BN(147, 189, 190) BN(148, 191, 192) LN(149, 121)      LN(150, 120)
+	LN(151, 118)      LN(152, 95)       LN(153, 91)       LN(154, 87)
+	LN(155, 72)       LN(156, 71)       LN(157, 58)       LN(158, 57)
+	LN(159, 54)       LN(160, 47)       LN(161, 42)       LN(162, 39)
+	LN(163, 34)       LN(164, 9)
+	//
+	BN(165, 193, 194) BN(166, 195, 196) BN(167, 197, 198) BN(168, 199, 200)
+	BN(169, 201, 202) BN(170, 203, 204) BN(171, 205, 206) BN(172, 207, 208)
+	BN(173, 209, 210) BN(174, 211, 212) BN(175, 213, 214) BN(176, 215, 216)
+	BN(177, 217, 218) BN(178, 219, 220) BN(179, 221, 222) BN(180, 223, 224)
+	BN(181, 225, 226) BN(182, 227, 228)	BN(183, 229, 230) BN(184, 231, 232)
+	BN(185, 233, 234) LN(186, 93)       LN(187, 89)       LN(188, 88)
+	LN(189, 86)       LN(190, 75)       LN(191, 62)       LN(192, 43)
+	//
+	BN(193, 235, 236) BN(194, 237, 238) BN(195, 239, 240) BN(196, 241, 242)
+	BN(197, 243, 244) BN(198, 245, 246)	BN(199, 247, 248) BN(200, 249, 250)
+	BN(201, 251, 252) BN(202, 253, 254) BN(203, 255, 256) BN(204, 257, 258)
+	BN(205, 259, 260) BN(206, 261, 262) BN(207, 263, 264) BN(208, 265, 266)
+	BN(209, 267, 268) BN(210, 269, 270)	BN(211, 271, 272) BN(212, 273, 274)
+	BN(213, 275, 276) BN(214, 277, 278) BN(215, 279, 280) BN(216, 281, 282)
+	BN(217, 283, 284) BN(218, 285, 286) BN(219, 287, 288) BN(220, 289, 290)
+	BN(221, 291, 292) BN(222, 293, 294) BN(223, 295, 296) BN(224, 297, 298)
+	BN(225, 299, 300) BN(226, 301, 302) BN(227, 303, 304) BN(228, 305, 306)
+	BN(229, 307, 308) LN(230, 122)      LN(231, 113)      LN(232, 38)
+	LN(233, 36)       LN(234, 33)
+	//
+	BN(235, 309, 310) BN(236, 311, 312) BN(237, 313, 314) BN(238, 315, 316)
+	BN(239, 317, 318) BN(240, 319, 320) BN(241, 321, 322) BN(242, 323, 324)
+	BN(243, 325, 326) BN(244, 327, 328) BN(245, 329, 330) BN(246, 331, 332)
+	BN(247, 333, 334) BN(248, 335, 336) BN(249, 337, 338) BN(250, 339, 340)
+	BN(251, 341, 342) BN(252, 343, 344)	BN(253, 345, 346) BN(254, 347, 348)
+	BN(255, 349, 350) BN(256, 351, 352) BN(257, 353, 354) BN(258, 355, 356)
+	BN(259, 357, 358) BN(260, 359, 360) BN(261, 361, 362) BN(262, 363, 364)
+	BN(263, 365, 366) BN(264, 367, 368) BN(265, 369, 370) BN(266, 371, 372)
+	BN(267, 373, 374) BN(268, 375, 376) BN(269, 377, 378) BN(270, 379, 380)
+	BN(271, 381, 382) BN(272, 383, 384) BN(273, 385, 386) BN(274, 387, 388)
+	BN(275, 389, 390) BN(276, 391, 392) BN(277, 393, 394) BN(278, 395, 396)
+	BN(279, 397, 398) BN(280, 399, 400) BN(281, 401, 402) BN(282, 403, 404)
+	BN(283, 405, 406) BN(284, 407, 408) BN(285, 409, 410) BN(286, 411, 412)
+	BN(287, 413, 414) BN(288, 415, 416) BN(289, 417, 418) BN(290, 419, 420)
+	BN(291, 421, 422) BN(292, 423, 424) BN(293, 425, 426) BN(294, 427, 428)
+	BN(295, 429, 430) BN(296, 431, 432) BN(297, 433, 434) BN(298, 435, 436)
+	LN(299, 124)      LN(300, 123)      LN(301, 106)      LN(302, 92)
+	LN(303, 90)       LN(304, 81)       LN(305, 74)       LN(306, 63)
+	LN(307, 60)       LN(308, 0)
+	//
+	BN(309, 437, 438) BN(310, 439, 440) BN(311, 441, 442) BN(312, 443, 444)
+	BN(313, 445, 446) BN(314, 447, 448) BN(315, 449, 450) BN(316, 451, 452)
+	BN(317, 453, 454) BN(318, 455, 456) BN(319, 457, 458) BN(320, 459, 460)
+	BN(321, 461, 462) BN(322, 463, 464) BN(323, 465, 466) BN(324, 467, 468)
+	BN(325, 469, 470) BN(326, 471, 472)	BN(327, 473, 474) BN(328, 475, 476)
+	BN(329, 477, 478) BN(330, 479, 480) BN(331, 481, 482) BN(332, 483, 484)
+	BN(333, 485, 486) BN(334, 487, 488) BN(335, 489, 490) BN(336, 491, 492)
+	BN(337, 493, 494) BN(338, 495, 496) BN(339, 497, 498) BN(340, 499, 500)
+	BN(341, 501, 502) BN(342, 503, 504) BN(343, 505, 506) BN(344, 507, 508)
+	BN(345, 509, 510) LN(346, 244)      LN(347, 243)      LN(348, 242)
+	LN(349, 238)      LN(350, 233)      LN(351, 229)      LN(352, 225)
+	LN(353, 223)      LN(354, 222)      LN(355, 221)      LN(356, 220)
+	LN(357, 219)      LN(358, 218)      LN(359, 217)      LN(360, 216)
+	LN(361, 215)      LN(362, 214)      LN(363, 213)      LN(364, 212)
+	LN(365, 211)      LN(366, 210)      LN(367, 209)      LN(368, 208)
+	LN(369, 207)      LN(370, 206)      LN(371, 205)      LN(372, 204)
+	LN(373, 203)      LN(374, 202)      LN(375, 201)      LN(376, 200)
+	LN(377, 199)      LN(378, 198)      LN(379, 197)      LN(380, 196)
+	LN(381, 195)      LN(382, 194)      LN(383, 193)      LN(384, 192)
+	LN(385, 191)      LN(386, 190)      LN(387, 189)      LN(388, 188)
+	LN(389, 187)      LN(390, 186)      LN(391, 185)      LN(392, 184)
+	LN(393, 183)      LN(394, 182)      LN(395, 181)      LN(396, 180)
+	LN(397, 179)      LN(398, 178)      LN(399, 177)      LN(400, 176)
+	LN(401, 127)      LN(402, 126)      LN(403, 125)      LN(404, 96)
+	LN(405, 94)       LN(406, 64)       LN(407, 59)       LN(408, 37)
+	LN(409, 35)       LN(410, 31)       LN(411, 30)       LN(412, 29)
+	LN(413, 28)       LN(414, 27)       LN(415, 25)       LN(416, 24)
+	LN(417, 23)       LN(418, 22)       LN(419, 21)       LN(420, 20)
+	LN(421, 19)       LN(422, 18)       LN(423, 17)       LN(424, 16)
+	LN(425, 15)       LN(426, 14)       LN(427, 12)       LN(428, 11)
+	LN(429, 8)        LN(430, 7)        LN(431, 6)        LN(432, 5)
+	LN(433, 4)        LN(434, 3)        LN(435, 2)        LN(436, 1)
+	LN(437, 255)      LN(438, 254)      LN(439, 253)      LN(440, 252)
+	LN(441, 251)      LN(442, 250)      LN(443, 249)      LN(444, 248)
+	LN(445, 247)      LN(446, 246)      LN(447, 245)      LN(448, 241)
+	LN(449, 240)      LN(450, 239)      LN(451, 237)      LN(452, 236)
+	LN(453, 235)      LN(454, 234)      LN(455, 232)      LN(456, 231)
+	LN(457, 230)      LN(458, 228)      LN(459, 227)      LN(460, 226)
+	LN(461, 224)      LN(462, 175)      LN(463, 174)      LN(464, 173)
+	LN(465, 172)      LN(466, 171)      LN(467, 170)      LN(468, 169)
+	LN(469, 168)      LN(470, 167)      LN(471, 166)      LN(472, 165)
+	LN(473, 164)      LN(474, 163)      LN(475, 162)      LN(476, 161)
+	LN(477, 160)      LN(478, 159)      LN(479, 158)      LN(480, 157)
+	LN(481, 156)      LN(482, 155)      LN(483, 154)      LN(484, 153)
+	LN(485, 152)      LN(486, 151)      LN(487, 150)      LN(488, 149)
+	LN(489, 148)      LN(490, 147)      LN(491, 146)      LN(492, 145)
+	LN(493, 144)      LN(494, 143)      LN(495, 142)      LN(496, 141)
+	LN(497, 140)      LN(498, 139)      LN(499, 138)      LN(500, 137)
+	LN(501, 136)      LN(502, 135)      LN(503, 134)      LN(504, 133)
+	LN(505, 132)      LN(506, 131)      LN(507, 130)      LN(508, 129)
+	LN(509, 128)      LN(510, 26)
+};
+
+int DecompressorDCL::huffman_lookup(const int *tree) {
+	int pos = 0;
+
+	while (!(tree[pos] & HUFFMAN_LEAF)) {
+		int bit = getBitsLSB(1);
+		pos = bit ? tree[pos] & 0xFFF : tree[pos] >> 12;
+	}
+
+	return tree[pos] & 0xFFFF;
+}
+
+#define DCL_BINARY_MODE 0
+#define DCL_ASCII_MODE 1
+
+#define MIDI_SETUP_BUNDLE_FILE_MAXIMUM_DICTIONARY_SIZE 4096
+
+bool DecompressorDCL::unpack(SeekableReadStream *sourceStream, WriteStream *targetStream, uint32 targetSize, bool targetFixedSize) {
+	byte   dictionary[MIDI_SETUP_BUNDLE_FILE_MAXIMUM_DICTIONARY_SIZE];
+	uint16 dictionaryPos = 0;
+	uint16 dictionarySize = 0;
+	uint16 dictionaryMask = 0;
+	int value;
+	uint16 tokenOffset = 0;
+	uint16 tokenLength = 0;
+
+	init(sourceStream, targetStream, targetSize, targetFixedSize);
+
+	byte mode = getByteLSB();
+	byte dictionaryType = getByteLSB();
+
+	if (mode != DCL_BINARY_MODE && mode != DCL_ASCII_MODE) {
+		warning("DCL-INFLATE: Error: Encountered mode %02x, expected 00 or 01", mode);
+		return false;
+	}
+
+	// TODO: original code supported 3 as well???
+	// Was this an accident or on purpose? And the original code did just give out a warning
+	// and didn't error out at all
+	switch (dictionaryType) {
+	case 4:
+		dictionarySize = 1024;
+		break;
+	case 5:
+		dictionarySize = 2048;
+		break;
+	case 6:
+		dictionarySize = 4096;
+		break;
+	default:
+		warning("DCL-INFLATE: Error: unsupported dictionary type %02x", dictionaryType);
+		return false;
+	}
+	dictionaryMask = dictionarySize - 1;
+
+	while ((!targetFixedSize) || (_bytesWritten < _targetSize)) {
+		if (getBitsLSB(1)) { // (length,distance) pair
+			value = huffman_lookup(length_tree);
+
+			if (value < 8)
+				tokenLength = value + 2;
+			else
+				tokenLength = 8 + (1 << (value - 7)) + getBitsLSB(value - 7);
+
+			if (tokenLength == 519)
+				break; // End of stream signal
+
+			value = huffman_lookup(distance_tree);
+
+			if (tokenLength == 2)
+				tokenOffset = (value << 2) | getBitsLSB(2);
+			else
+				tokenOffset = (value << dictionaryType) | getBitsLSB(dictionaryType);
+			tokenOffset++;
+
+			if (_targetFixedSize) {
+				if (tokenLength + _bytesWritten > _targetSize) {
+					warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes (declared unpacked size is %d bytes, current is %d + %d bytes)",
+							tokenLength, _targetSize, _bytesWritten, tokenLength);
+					return false;
+				}
+			}
+
+			if (_bytesWritten < tokenOffset) {
+				warning("DCL-INFLATE Error: Attempt to copy from before beginning of input stream (declared unpacked size is %d bytes, current is %d bytes)",
+						_targetSize, _bytesWritten);
+				return false;
+			}
+
+			uint16 dictionaryBaseIndex = (dictionaryPos - tokenOffset) & dictionaryMask;
+			uint16 dictionaryIndex = dictionaryBaseIndex;
+			uint16 dictionaryNextIndex = dictionaryPos;
+
+			while (tokenLength) {
+				// Write byte from dictionary
+				putByte(dictionary[dictionaryIndex]);
+
+				dictionary[dictionaryNextIndex] = dictionary[dictionaryIndex];
+
+				dictionaryNextIndex = (dictionaryNextIndex + 1) & dictionaryMask;
+				dictionaryIndex = (dictionaryIndex + 1) & dictionaryMask;
+
+				if (dictionaryIndex == dictionaryPos)
+					dictionaryIndex = dictionaryBaseIndex;
+				if (dictionaryNextIndex == dictionarySize)
+					dictionaryNextIndex = 0;
+
+				tokenLength--;
+			}
+			dictionaryPos = dictionaryNextIndex;
+
+		} else { // Copy byte verbatim
+			value = (mode == DCL_ASCII_MODE) ? huffman_lookup(ascii_tree) : getByteLSB();
+			putByte(value);
+
+			// Also remember it inside dictionary
+			dictionary[dictionaryPos] = value;
+			dictionaryPos++;
+			if (dictionaryPos >= dictionarySize)
+				dictionaryPos = 0;
+		}
+	}
+
+	if (_targetFixedSize) {
+		if (_bytesWritten != _targetSize)
+			warning("DCL-INFLATE Error: Inconsistent bytes written (%d) and target buffer size (%d)", _bytesWritten, _targetSize);
+		return _bytesWritten == _targetSize;
+	}
+	return true; // For targets featuring dynamic size we always succeed
+}
+
+bool decompressDCL(ReadStream *src, byte *dest, uint32 packedSize, uint32 unpackedSize) {
+	bool success = false;
+	DecompressorDCL dcl;
+
+	if (!src || !dest)
+		return false;
+
+	byte *sourceBufferPtr = (byte *)malloc(packedSize);
+	if (!sourceBufferPtr)
+		return false;
+
+	// Read source into memory
+	src->read(sourceBufferPtr, packedSize);
+
+	Common::MemoryReadStream  *sourceStream = new MemoryReadStream(sourceBufferPtr, packedSize, DisposeAfterUse::YES);
+	Common::MemoryWriteStream *targetStream = new MemoryWriteStream(dest, unpackedSize);
+
+	success = dcl.unpack(sourceStream, targetStream, unpackedSize, true);
+	delete sourceStream;
+	delete targetStream;
+	return success;
+}
+
+SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream, uint32 packedSize, uint32 unpackedSize) {
+	bool success = false;
+	byte *targetPtr = nullptr;
+	Common::MemoryWriteStream *targetStream;
+	DecompressorDCL dcl;
+
+	targetPtr = (byte *)malloc(unpackedSize);
+	if (!targetPtr)
+		return nullptr;
+
+	targetStream = new MemoryWriteStream(targetPtr, unpackedSize);
+
+	success = dcl.unpack(sourceStream, targetStream, unpackedSize, true);
+	delete targetStream;
+
+	if (!success) {
+		free(targetPtr);
+		return nullptr;
+	}
+	return new MemoryReadStream(targetPtr, unpackedSize, DisposeAfterUse::YES);
+}
+
+// This one figures out the unpacked size by itself
+// Needed for at least Simon 2, because the unpacked size is not stored anywhere
+SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream) {
+	Common::MemoryWriteStreamDynamic *targetStream;
+	DecompressorDCL dcl;
+
+	targetStream = new MemoryWriteStreamDynamic(DisposeAfterUse::NO);
+
+	if (dcl.unpack(sourceStream, targetStream, 0, false)) {
+		byte *targetPtr = targetStream->getData();
+		uint32 unpackedSize = targetStream->size();
+		delete targetStream;
+		return new MemoryReadStream(targetPtr, unpackedSize, DisposeAfterUse::YES);
+	}
+	delete targetStream;
+	return nullptr;
+}
+
+} // End of namespace Common
diff --git a/common/dcl.h b/common/dcl.h
new file mode 100644
index 00000000..bd2fcd4d
--- /dev/null
+++ b/common/dcl.h
@@ -0,0 +1,78 @@
+/* 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_DCL_H
+#define COMMON_DCL_H
+
+#include "common/scummsys.h"
+
+namespace Common {
+
+/**
+ * @defgroup common_dcl Data compression library
+ * @ingroup common
+ *
+ * @brief  PKWARE data compression library (DCL).
+ *
+ * @details PKWARE DCL ("explode") ("PKWARE data compression library") decompressor used in engines:
+ *          - AGOS (exclusively for Simon 2 setup.shr file)
+ *          - Mohawk
+ *          - Neverhood
+ *          - SCI
+ *          - MADS (exclusively for the Rex Nebular installer) 
+ * @{
+ */
+
+class ReadStream;
+class SeekableReadStream;
+
+/**
+ * Decompress a PKWARE DCL compressed stream.
+ *
+ * @return Returns true if successful.
+ */
+bool decompressDCL(ReadStream *sourceStream, byte *dest, uint32 packedSize, uint32 unpackedSize);
+
+/**
+ * @overload
+ *
+ * Decompress a PKWARE DCL compressed stream.
+ *
+ * @return Returns a valid pointer if successful or 0 otherwise.
+ */
+SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream, uint32 packedSize, uint32 unpackedSize);
+
+/**
+ * @overload
+ *
+ * Decompress a PKWARE DCL compressed stream.
+ *
+ * This method is meant for cases, where the unpacked size is not known.
+ *
+ * @return Returns a valid pointer if successful or 0 otherwise.
+ */
+SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream);
+
+/** @} */
+
+} // End of namespace Common
+
+#endif


Commit: 3aa7ad671da48c90c69473b3cd970de73501ac52
    https://github.com/scummvm/scummvm-tools/commit/3aa7ad671da48c90c69473b3cd970de73501ac52
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-20T16:59:55+01:00

Commit Message:
MADS: Switch from libblast to common/dcl

Changed paths:
    Makefile.common
    engines/mads/extract_mps.cpp


diff --git a/Makefile.common b/Makefile.common
index 7457a65b..e9fafb79 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -172,7 +172,7 @@ extract_lokalizator_OBJS := \
 
 extract_mps_OBJS := \
 	engines/mads/extract_mps.o \
-	engines/mads/libblast/blast.o \
+	common/dcl.o \
 	$(UTILS)
 
 deprince_OBJS := \
diff --git a/engines/mads/extract_mps.cpp b/engines/mads/extract_mps.cpp
index b54d73df..bcbfb0ce 100644
--- a/engines/mads/extract_mps.cpp
+++ b/engines/mads/extract_mps.cpp
@@ -20,9 +20,10 @@
  */
 
 #include "common/endian.h"
+#include "common/memstream.h"
 #include "common/str.h"
 #include "common/util.h"
-#include "libblast/blast.h"
+#include "common/dcl.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -37,37 +38,6 @@ struct FileDescriptorBin {
 	uint32 uncompressedSize;
 } __attribute__ ((packed));
 
-struct blastMemInputWrapperStruct {
-	uint32 _offset, _len;
-	byte *_data;
-	blastMemInputWrapperStruct() : _len(0), _offset(0), _data(nullptr) {}
-	blastMemInputWrapperStruct(byte *data, uint32 len) : _len(len), _offset(0), _data(data) {}
-};
-
-uint blastMemInputWrapper(void *how, byte **buf) {
-	struct blastMemInputWrapperStruct *ctx = (struct blastMemInputWrapperStruct *) how;
-	*buf = ctx->_data + ctx->_offset;
-	uint avail = ctx->_len - ctx->_offset;
-	ctx->_offset += avail;
-	return avail;
-}
-
-struct blastMemOutputWrapperStruct {
-	uint32 _written, _bufLen;
-	byte *_data;
-	blastMemOutputWrapperStruct() : _bufLen(0), _written(0), _data(nullptr) {}
-	blastMemOutputWrapperStruct(byte *data, uint32 len) : _bufLen(len), _written(0), _data(data) {}
-};
-
-int blastMemOutputWrapper(void *how, byte *buf, uint len) {
-	struct blastMemOutputWrapperStruct *ctx = (struct blastMemOutputWrapperStruct *) how;
-	if (len + ctx->_written > ctx->_bufLen)
-		return 1;
-	memcpy(ctx->_data + ctx->_written, buf, len);
-	ctx->_written += len;
-	return 0;
-}
-
 int main (int argc, char **argv) {
 	unsigned char * buf;
 	size_t indexSize;
@@ -141,12 +111,10 @@ int main (int argc, char **argv) {
 			uncompressedSize = compressedSize;
 			break;
 		case 1:
-			blastMemInputWrapperStruct blastInput(compressedBuf, compressedSize);
+			Common::MemoryReadStream compressedReadStream(compressedBuf, compressedSize);
 			uncompressedBuf = new byte[uncompressedSize];
-			blastMemOutputWrapperStruct blastOutput(uncompressedBuf, uncompressedSize);
-			BlastError blastErr = blast(blastMemInputWrapper, &blastInput, blastMemOutputWrapper, &blastOutput, nullptr, nullptr);
-			if (blastErr) {
-				fprintf (stderr, "Unable to decompress %s: %d\n", descBin->name, blastErr);
+			if (!Common::decompressDCL(&compressedReadStream, uncompressedBuf, compressedSize, uncompressedSize)) {
+				fprintf (stderr, "Unable to decompress %s\n", descBin->name);
 				continue;
 			}
 				


Commit: 59eebfed5fc9392470389aaa0f1fb84939b35706
    https://github.com/scummvm/scummvm-tools/commit/59eebfed5fc9392470389aaa0f1fb84939b35706
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-11-20T16:59:55+01:00

Commit Message:
MADS: Remove libblast

Changed paths:
  R engines/mads/libblast/blast.c
  R engines/mads/libblast/blast.h


diff --git a/engines/mads/libblast/blast.c b/engines/mads/libblast/blast.c
deleted file mode 100644
index 6aa3fb1b..00000000
--- a/engines/mads/libblast/blast.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/* blast.c
- * Copyright (C) 2003, 2012, 2013 Mark Adler
- * For conditions of distribution and use, see copyright notice in blast.h
- * version 1.3, 24 Aug 2013
- *
- * blast.c decompresses data compressed by the PKWare Compression Library.
- * This function provides functionality similar to the explode() function of
- * the PKWare library, hence the name "blast".
- *
- * This decompressor is based on the excellent format description provided by
- * Ben Rudiak-Gould in comp.compression on August 13, 2001.  Interestingly, the
- * example Ben provided in the post is incorrect.  The distance 110001 should
- * instead be 111000.  When corrected, the example byte stream becomes:
- *
- *    00 04 82 24 25 8f 80 7f
- *
- * which decompresses to "AIAIAIAIAIAIA" (without the quotes).
- */
-
-/*
- * Change history:
- *
- * 1.0  12 Feb 2003     - First version
- * 1.1  16 Feb 2003     - Fixed distance check for > 4 GB uncompressed data
- * 1.2  24 Oct 2012     - Add note about using binary mode in stdio
- *                      - Fix comparisons of differently signed integers
- * 1.3  24 Aug 2013     - Return unused input from blast()
- *                      - Fix test code to correctly report unused input
- *                      - Enable the provision of initial input to blast()
- */
-
-#include <stddef.h>             /* for NULL */
-#include <setjmp.h>             /* for setjmp(), longjmp(), and jmp_buf */
-#include "blast.h"              /* prototype for blast() */
-
-#define MAXBITS 13              /* maximum code length */
-#define MAXWIN 4096             /* maximum window size */
-
-/* input and output state */
-struct state {
-    /* input state */
-    blast_in infun;             /* input function provided by user */
-    void *inhow;                /* opaque information passed to infun() */
-    unsigned char *in;          /* next input location */
-    unsigned left;              /* available input at in */
-    int bitbuf;                 /* bit buffer */
-    int bitcnt;                 /* number of bits in bit buffer */
-
-    /* input limit error return state for bits() and decode() */
-    jmp_buf env;
-
-    /* output state */
-    blast_out outfun;           /* output function provided by user */
-    void *outhow;               /* opaque information passed to outfun() */
-    unsigned next;              /* index of next write location in out[] */
-    int first;                  /* true to check distances (for first 4K) */
-    unsigned char out[MAXWIN];  /* output buffer and sliding window */
-};
-
-/*
- * Return need bits from the input stream.  This always leaves less than
- * eight bits in the buffer.  bits() works properly for need == 0.
- *
- * Format notes:
- *
- * - Bits are stored in bytes from the least significant bit to the most
- *   significant bit.  Therefore bits are dropped from the bottom of the bit
- *   buffer, using shift right, and new bytes are appended to the top of the
- *   bit buffer, using shift left.
- */
-static int bits(struct state *s, int need)
-{
-    int val;            /* bit accumulator */
-
-    /* load at least need bits into val */
-    val = s->bitbuf;
-    while (s->bitcnt < need) {
-        if (s->left == 0) {
-            s->left = s->infun(s->inhow, &(s->in));
-            if (s->left == 0) longjmp(s->env, 1);       /* out of input */
-        }
-        val |= (int)(*(s->in)++) << s->bitcnt;          /* load eight bits */
-        s->left--;
-        s->bitcnt += 8;
-    }
-
-    /* drop need bits and update buffer, always zero to seven bits left */
-    s->bitbuf = val >> need;
-    s->bitcnt -= need;
-
-    /* return need bits, zeroing the bits above that */
-    return val & ((1 << need) - 1);
-}
-
-/*
- * Huffman code decoding tables.  count[1..MAXBITS] is the number of symbols of
- * each length, which for a canonical code are stepped through in order.
- * symbol[] are the symbol values in canonical order, where the number of
- * entries is the sum of the counts in count[].  The decoding process can be
- * seen in the function decode() below.
- */
-struct huffman {
-    short *count;       /* number of symbols of each length */
-    short *symbol;      /* canonically ordered symbols */
-};
-
-/*
- * Decode a code from the stream s using huffman table h.  Return the symbol or
- * a negative value if there is an error.  If all of the lengths are zero, i.e.
- * an empty code, or if the code is incomplete and an invalid code is received,
- * then -9 is returned after reading MAXBITS bits.
- *
- * Format notes:
- *
- * - The codes as stored in the compressed data are bit-reversed relative to
- *   a simple integer ordering of codes of the same lengths.  Hence below the
- *   bits are pulled from the compressed data one at a time and used to
- *   build the code value reversed from what is in the stream in order to
- *   permit simple integer comparisons for decoding.
- *
- * - The first code for the shortest length is all ones.  Subsequent codes of
- *   the same length are simply integer decrements of the previous code.  When
- *   moving up a length, a one bit is appended to the code.  For a complete
- *   code, the last code of the longest length will be all zeros.  To support
- *   this ordering, the bits pulled during decoding are inverted to apply the
- *   more "natural" ordering starting with all zeros and incrementing.
- */
-static int decode(struct state *s, struct huffman *h)
-{
-    int len;            /* current number of bits in code */
-    int code;           /* len bits being decoded */
-    int first;          /* first code of length len */
-    int count;          /* number of codes of length len */
-    int index;          /* index of first code of length len in symbol table */
-    int bitbuf;         /* bits from stream */
-    int left;           /* bits left in next or left to process */
-    short *next;        /* next number of codes */
-
-    bitbuf = s->bitbuf;
-    left = s->bitcnt;
-    code = first = index = 0;
-    len = 1;
-    next = h->count + 1;
-    while (1) {
-        while (left--) {
-            code |= (bitbuf & 1) ^ 1;   /* invert code */
-            bitbuf >>= 1;
-            count = *next++;
-            if (code < first + count) { /* if length len, return symbol */
-                s->bitbuf = bitbuf;
-                s->bitcnt = (s->bitcnt - len) & 7;
-                return h->symbol[index + (code - first)];
-            }
-            index += count;             /* else update for next length */
-            first += count;
-            first <<= 1;
-            code <<= 1;
-            len++;
-        }
-        left = (MAXBITS+1) - len;
-        if (left == 0) break;
-        if (s->left == 0) {
-            s->left = s->infun(s->inhow, &(s->in));
-            if (s->left == 0) longjmp(s->env, 1);       /* out of input */
-        }
-        bitbuf = *(s->in)++;
-        s->left--;
-        if (left > 8) left = 8;
-    }
-    return -9;                          /* ran out of codes */
-}
-
-/*
- * Given a list of repeated code lengths rep[0..n-1], where each byte is a
- * count (high four bits + 1) and a code length (low four bits), generate the
- * list of code lengths.  This compaction reduces the size of the object code.
- * Then given the list of code lengths length[0..n-1] representing a canonical
- * Huffman code for n symbols, construct the tables required to decode those
- * codes.  Those tables are the number of codes of each length, and the symbols
- * sorted by length, retaining their original order within each length.  The
- * return value is zero for a complete code set, negative for an over-
- * subscribed code set, and positive for an incomplete code set.  The tables
- * can be used if the return value is zero or positive, but they cannot be used
- * if the return value is negative.  If the return value is zero, it is not
- * possible for decode() using that table to return an error--any stream of
- * enough bits will resolve to a symbol.  If the return value is positive, then
- * it is possible for decode() using that table to return an error for received
- * codes past the end of the incomplete lengths.
- */
-static int construct(struct huffman *h, const unsigned char *rep, int n)
-{
-    int symbol;         /* current symbol when stepping through length[] */
-    int len;            /* current length when stepping through h->count[] */
-    int left;           /* number of possible codes left of current length */
-    short offs[MAXBITS+1];      /* offsets in symbol table for each length */
-    short length[256];  /* code lengths */
-
-    /* convert compact repeat counts into symbol bit length list */
-    symbol = 0;
-    do {
-        len = *rep++;
-        left = (len >> 4) + 1;
-        len &= 15;
-        do {
-            length[symbol++] = len;
-        } while (--left);
-    } while (--n);
-    n = symbol;
-
-    /* count number of codes of each length */
-    for (len = 0; len <= MAXBITS; len++)
-        h->count[len] = 0;
-    for (symbol = 0; symbol < n; symbol++)
-        (h->count[length[symbol]])++;   /* assumes lengths are within bounds */
-    if (h->count[0] == n)               /* no codes! */
-        return 0;                       /* complete, but decode() will fail */
-
-    /* check for an over-subscribed or incomplete set of lengths */
-    left = 1;                           /* one possible code of zero length */
-    for (len = 1; len <= MAXBITS; len++) {
-        left <<= 1;                     /* one more bit, double codes left */
-        left -= h->count[len];          /* deduct count from possible codes */
-        if (left < 0) return left;      /* over-subscribed--return negative */
-    }                                   /* left > 0 means incomplete */
-
-    /* generate offsets into symbol table for each length for sorting */
-    offs[1] = 0;
-    for (len = 1; len < MAXBITS; len++)
-        offs[len + 1] = offs[len] + h->count[len];
-
-    /*
-     * put symbols in table sorted by length, by symbol order within each
-     * length
-     */
-    for (symbol = 0; symbol < n; symbol++)
-        if (length[symbol] != 0)
-            h->symbol[offs[length[symbol]]++] = symbol;
-
-    /* return zero for complete set, positive for incomplete set */
-    return left;
-}
-
-/*
- * Decode PKWare Compression Library stream.
- *
- * Format notes:
- *
- * - First byte is 0 if literals are uncoded or 1 if they are coded.  Second
- *   byte is 4, 5, or 6 for the number of extra bits in the distance code.
- *   This is the base-2 logarithm of the dictionary size minus six.
- *
- * - Compressed data is a combination of literals and length/distance pairs
- *   terminated by an end code.  Literals are either Huffman coded or
- *   uncoded bytes.  A length/distance pair is a coded length followed by a
- *   coded distance to represent a string that occurs earlier in the
- *   uncompressed data that occurs again at the current location.
- *
- * - A bit preceding a literal or length/distance pair indicates which comes
- *   next, 0 for literals, 1 for length/distance.
- *
- * - If literals are uncoded, then the next eight bits are the literal, in the
- *   normal bit order in the stream, i.e. no bit-reversal is needed. Similarly,
- *   no bit reversal is needed for either the length extra bits or the distance
- *   extra bits.
- *
- * - Literal bytes are simply written to the output.  A length/distance pair is
- *   an instruction to copy previously uncompressed bytes to the output.  The
- *   copy is from distance bytes back in the output stream, copying for length
- *   bytes.
- *
- * - Distances pointing before the beginning of the output data are not
- *   permitted.
- *
- * - Overlapped copies, where the length is greater than the distance, are
- *   allowed and common.  For example, a distance of one and a length of 518
- *   simply copies the last byte 518 times.  A distance of four and a length of
- *   twelve copies the last four bytes three times.  A simple forward copy
- *   ignoring whether the length is greater than the distance or not implements
- *   this correctly.
- */
-static enum BlastError decomp(struct state *s)
-{
-    int lit;            /* true if literals are coded */
-    int dict;           /* log2(dictionary size) - 6 */
-    int symbol;         /* decoded symbol, extra bits for distance */
-    int len;            /* length for copy */
-    unsigned dist;      /* distance for copy */
-    int copy;           /* copy counter */
-    unsigned char *from, *to;   /* copy pointers */
-    static int virgin = 1;                              /* build tables once */
-    static short litcnt[MAXBITS+1], litsym[256];        /* litcode memory */
-    static short lencnt[MAXBITS+1], lensym[16];         /* lencode memory */
-    static short distcnt[MAXBITS+1], distsym[64];       /* distcode memory */
-    static struct huffman litcode = {litcnt, litsym};   /* length code */
-    static struct huffman lencode = {lencnt, lensym};   /* length code */
-    static struct huffman distcode = {distcnt, distsym};/* distance code */
-        /* bit lengths of literal codes */
-    static const unsigned char litlen[] = {
-        11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8,
-        9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
-        7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
-        8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
-        44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45,
-        44, 173};
-        /* bit lengths of length codes 0..15 */
-    static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23};
-        /* bit lengths of distance codes 0..63 */
-    static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248};
-    static const short base[16] = {     /* base for length codes */
-        3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264};
-    static const char extra[16] = {     /* extra bits for length codes */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};
-
-    /* set up decoding tables (once--might not be thread-safe) */
-    if (virgin) {
-        construct(&litcode, litlen, sizeof(litlen));
-        construct(&lencode, lenlen, sizeof(lenlen));
-        construct(&distcode, distlen, sizeof(distlen));
-        virgin = 0;
-    }
-
-    /* read header */
-    lit = bits(s, 8);
-    if (lit > 1) return BLAST_WRONG_LITERAL_FLAG;
-    dict = bits(s, 8);
-    if (dict < 4 || dict > 6) return BLAST_WRONG_DICTIONARY;
-
-    /* decode literals and length/distance pairs */
-    do {
-        if (bits(s, 1)) {
-            /* get length */
-            symbol = decode(s, &lencode);
-            len = base[symbol] + bits(s, extra[symbol]);
-            if (len == 519) break;              /* end code */
-
-            /* get distance */
-            symbol = len == 2 ? 2 : dict;
-            dist = decode(s, &distcode) << symbol;
-            dist += bits(s, symbol);
-            dist++;
-            if (s->first && dist > s->next)
-                return BLAST_DISTANCE_TOO_BIG;              /* distance too far back */
-
-            /* copy length bytes from distance bytes back */
-            do {
-                to = s->out + s->next;
-                from = to - dist;
-                copy = MAXWIN;
-                if (s->next < dist) {
-                    from += copy;
-                    copy = dist;
-                }
-                copy -= s->next;
-                if (copy > len) copy = len;
-                len -= copy;
-                s->next += copy;
-                do {
-                    *to++ = *from++;
-                } while (--copy);
-                if (s->next == MAXWIN) {
-                    if (s->outfun(s->outhow, s->out, s->next)) return BLAST_OUTPUT_ERROR;
-                    s->next = 0;
-                    s->first = 0;
-                }
-            } while (len != 0);
-        }
-        else {
-            /* get literal and write it */
-            symbol = lit ? decode(s, &litcode) : bits(s, 8);
-            s->out[s->next++] = symbol;
-            if (s->next == MAXWIN) {
-                if (s->outfun(s->outhow, s->out, s->next)) return BLAST_OUTPUT_ERROR;
-                s->next = 0;
-                s->first = 0;
-            }
-        }
-    } while (1);
-    return BLAST_SUCCESS;
-}
-
-
-/* See comments in blast.h */
-enum BlastError blast(blast_in infun, void *inhow, blast_out outfun, void *outhow,
-          unsigned *left, unsigned char **in)
-{
-    struct state s;             /* input/output state */
-    enum BlastError err;        /* return value */
-
-    /* initialize input state */
-    s.infun = infun;
-    s.inhow = inhow;
-    if (left != NULL && *left) {
-        s.left = *left;
-        s.in = *in;
-    }
-    else
-        s.left = 0;
-    s.bitbuf = 0;
-    s.bitcnt = 0;
-
-    /* initialize output state */
-    s.outfun = outfun;
-    s.outhow = outhow;
-    s.next = 0;
-    s.first = 1;
-
-    /* return if bits() or decode() tries to read past available input */
-    if (setjmp(s.env) != 0)             /* if came back here via longjmp(), */
-        err = BLAST_INPUT_EXHAUSTED;    /*  then skip decomp(), return error */
-    else
-        err = decomp(&s);               /* decompress */
-
-    /* return unused input */
-    if (left != NULL)
-        *left = s.left;
-    if (in != NULL)
-        *in = s.left ? s.in : NULL;
-
-    /* write any leftover output and update the error code if needed */
-    if (err != BLAST_OUTPUT_ERROR && s.next && s.outfun(s.outhow, s.out, s.next) && err == BLAST_SUCCESS)
-        err = BLAST_OUTPUT_ERROR;
-    return err;
-}
diff --git a/engines/mads/libblast/blast.h b/engines/mads/libblast/blast.h
deleted file mode 100644
index 3c7324f7..00000000
--- a/engines/mads/libblast/blast.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#pragma once
-/* blast.h -- interface for blast.c
-  Copyright (C) 2003, 2012, 2013 Mark Adler
-  version 1.3, 24 Aug 2013
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the author be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Mark Adler    madler at alumni.caltech.edu
- */
-
-
-enum BlastError {
-	BLAST_SUCCESS = 0, //< successful decompression
-
-	// If there is not enough input available or there is not enough output space, then a positive error is returned.
-	BLAST_OUTPUT_ERROR = 1,  //< output error before completing decompression
-	BLAST_INPUT_EXHAUSTED = 2,  //< ran out of input before completing decompression
-
-	// Errors in the source data
-	BLAST_WRONG_LITERAL_FLAG = -1,  //< literal flag not zero or one
-	BLAST_WRONG_DICTIONARY = -2,  //< dictionary size not in 4..6
-	BLAST_DISTANCE_TOO_BIG = -3,  //< distance is too far back
-};
-
-
-/*
- * blast() decompresses the PKWare Data Compression Library (DCL) compressed
- * format.  It provides the same functionality as the explode() function in
- * that library.  (Note: PKWare overused the "implode" verb, and the format
- * used by their library implode() function is completely different and
- * incompatible with the implode compression method supported by PKZIP.)
- *
- * The binary mode for stdio functions should be used to assure that the
- * compressed data is not corrupted when read or written.  For example:
- * fopen(..., "rb") and fopen(..., "wb").
- */
-
-
-typedef unsigned (*blast_in)(void *how, unsigned char **buf);
-typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len);
-/* Definitions for input/output functions passed to blast().  See below for
- * what the provided functions need to do.
- */
-
-#ifdef _WIN32
-    #ifdef LIBBLAST_EXPORTS
-        #define LIBBLAST_API __declspec(dllexport)
-    #else
-        #define LIBBLAST_API __declspec(dllimport)
-    #endif
-#else
-    #ifdef libblast_EXPORTS
-        #define LIBBLAST_API __attribute__((visibility("default")))
-    #else
-        #define LIBBLAST_API
-    #endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-LIBBLAST_API enum BlastError blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, unsigned *left, unsigned char **in);
-/* Decompress input to output using the provided infun() and outfun() calls.
- * On success, the return value of blast() is zero.  If there is an error in
- * the source data, i.e. it is not in the proper format, then a negative value
- * is returned.  If there is not enough input available or there is not enough
- * output space, then a positive error is returned.
- *
- * The input function is invoked: len = infun(how, &buf), where buf is set by
- * infun() to point to the input buffer, and infun() returns the number of
- * available bytes there.  If infun() returns zero, then blast() returns with
- * an input error.  (blast() only asks for input if it needs it.)  inhow is for
- * use by the application to pass an input descriptor to infun(), if desired.
- *
- * If left and in are not NULL and *left is not zero when blast() is called,
- * then the *left bytes are *in are consumed for input before infun() is used.
- *
- * The output function is invoked: err = outfun(how, buf, len), where the bytes
- * to be written are buf[0..len-1].  If err is not zero, then blast() returns
- * with an output error.  outfun() is always called with len <= 4096.  outhow
- * is for use by the application to pass an output descriptor to outfun(), if
- * desired.
- *
- * If there is any unused input, *left is set to the number of bytes that were
- * read and *in points to them.  Otherwise *left is set to zero and *in is set
- * to NULL.  If left or in are NULL, then they are not set.
- *
- * At the bottom of blast.c is an example program that uses blast() that can be
- * compiled to produce a command-line decompression filter by defining TEST.
- */
-#ifdef __cplusplus
-}
-#endif




More information about the Scummvm-git-logs mailing list