[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