[Scummvm-cvs-logs] SF.net SVN: scummvm:[46729] tools/trunk

sev at users.sourceforge.net sev at users.sourceforge.net
Wed Dec 30 00:23:31 CET 2009


Revision: 46729
          http://scummvm.svn.sourceforge.net/scummvm/?rev=46729&view=rev
Author:   sev
Date:     2009-12-29 23:23:31 +0000 (Tue, 29 Dec 2009)

Log Message:
-----------
Add Mohawk engine code. Part 3/3: tools (non working on new framework yet).

Added Paths:
-----------
    tools/trunk/common/algorithm.h
    tools/trunk/common/array.h
    tools/trunk/common/str.cpp
    tools/trunk/common/str.h
    tools/trunk/engines/mohawk/
    tools/trunk/engines/mohawk/deriven.cpp
    tools/trunk/engines/mohawk/extract_mohawk.cpp
    tools/trunk/engines/mohawk/mohawk_file.cpp
    tools/trunk/engines/mohawk/mohawk_file.h

Copied: tools/trunk/common/algorithm.h (from rev 46716, scummvm/trunk/common/algorithm.h)
===================================================================
--- tools/trunk/common/algorithm.h	                        (rev 0)
+++ tools/trunk/common/algorithm.h	2009-12-29 23:23:31 UTC (rev 46729)
@@ -0,0 +1,226 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef COMMON_ALGORITHM_H
+#define COMMON_ALGORITHM_H
+
+#include "common/scummsys.h"
+#include "common/func.h"
+
+namespace Common {
+
+/**
+ * Copies data from the range [first, last) to [dst, dst + (last - first)).
+ * It requires the range [dst, dst + (last - first)) to be valid.
+ * It also requires dst not to be in the range [first, last).
+ */
+template<class In, class Out>
+Out copy(In first, In last, Out dst) {
+	while (first != last)
+		*dst++ = *first++;
+	return dst;
+}
+
+/**
+ * Copies data from the range [first, last) to [dst - (last - first), dst).
+ * It requires the range [dst - (last - first), dst) to be valid.
+ * It also requires dst not to be in the range [first, last).
+ *
+ * Unlike copy copy_backward copies the data from the end to the beginning.
+ */
+template<class In, class Out>
+Out copy_backward(In first, In last, Out dst) {
+	while (first != last)
+		*--dst = *--last;
+	return dst;
+}
+
+/**
+ * Copies data from the range [first, last) to [dst, dst + (last - first)).
+ * It requires the range [dst, dst + (last - first)) to be valid.
+ * It also requires dst not to be in the range [first, last).
+ *
+ * Unlike copy or copy_backward it does not copy all data. It only copies
+ * a data element when operator() of the op parameter returns true for the
+ * passed data element.
+ */
+template<class In, class Out, class Op>
+Out copy_if(In first, In last, Out dst, Op op) {
+	while (first != last) {
+		if (op(*first))
+			*dst++ = *first;
+		++first;
+	}
+	return dst;
+}
+
+// Our 'specialized' 'set_to' template for char, signed char and unsigned char arrays.
+// Since C++ doesn't support partial specialized template functions (currently) we
+// are going this way...
+// With this we assure the usage of memset for those, which should be
+// faster than a simple loop like for the generic 'set_to'.
+template<class Value>
+signed char *set_to(signed char *first, signed char *last, Value val) {
+	memset(first, (val & 0xFF), last - first);
+	return last;
+}
+
+template<class Value>
+unsigned char *set_to(unsigned char *first, unsigned char *last, Value val) {
+	memset(first, (val & 0xFF), last - first);
+	return last;
+}
+
+template<class Value>
+char *set_to(char *first, char *last, Value val) {
+	memset(first, (val & 0xFF), last - first);
+	return last;
+}
+
+/**
+ * Sets all elements in the range [first, last) to val.
+ */
+template<class In, class Value>
+In set_to(In first, In last, Value val) {
+	while (first != last)
+		*first++ = val;
+	return first;
+}
+
+/**
+ * Finds the first data value in the range [first, last) matching v.
+ * For data comperance it uses operator == of the data elements.
+ */
+template<class In, class T>
+In find(In first, In last, const T &v) {
+	while (first != last) {
+		if (*first == v)
+			return first;
+		++first;
+	}
+	return last;
+}
+
+/**
+ * Finds the first data value in the range [first, last) for which
+ * the specified predicate p returns true.
+ */
+template<class In, class Pred>
+In find_if(In first, In last, Pred p) {
+	while (first != last) {
+		if (p(*first))
+			return first;
+		++first;
+	}
+	return last;
+}
+
+/**
+ * Applies the function f on all elements of the range [first, last).
+ * The processing order is from beginning to end.
+ */
+template<class In, class Op>
+Op for_each(In first, In last, Op f) {
+	while (first != last) f(*first++);
+	return f;
+}
+
+template<typename T>
+unsigned int distance(T *first, T *last) {
+	return last - first;
+}
+
+template<typename T>
+unsigned int distance(T first, T last) {
+	unsigned int n = 0;
+	while (first != last) {
+		++n;
+		++first;
+	}
+	return n;
+}
+
+template<typename T>
+T *sortChoosePivot(T *first, T *last) {
+	return first + distance(first, last) / 2;
+}
+
+template<typename T>
+T sortChoosePivot(T first, T last) {
+	unsigned int n = distance(first, last);
+	n /= 2;
+	while (n--)
+		++first;
+	return first;
+}
+
+template<typename T, class StrictWeakOrdering>
+T sortPartition(T first, T last, T pivot, StrictWeakOrdering &comp) {
+	--last;
+	SWAP(*pivot, *last);
+
+	T sorted;
+	for (sorted = first; first != last; ++first) {
+		if (!comp(*last, *first)) {
+			if (first != sorted)
+				SWAP(*first, *sorted);
+			++sorted;
+		}
+	}
+
+	SWAP(*last, *sorted);
+	return sorted;
+}
+
+/**
+ * Simple sort function, modeled after std::sort.
+ * It compares data with the given comparator object comp.
+ */
+template<typename T, class StrictWeakOrdering>
+void sort(T first, T last, StrictWeakOrdering comp) {
+	if (first == last)
+		return;
+
+	T pivot = sortChoosePivot(first, last);
+	pivot = sortPartition(first, last, pivot, comp);
+	sort<T, StrictWeakOrdering>(first, pivot, comp);
+	sort<T, StrictWeakOrdering>(++pivot, last, comp);
+}
+
+/**
+ * Simple sort function, modeled after std::sort.
+ */
+template<typename T>
+void sort(T *first, T *last) {
+	sort(first, last, Common::Less<T>());
+}
+
+template<class T>
+void sort(T first, T last) {
+	sort(first, last, Common::Less<typename T::ValueType>());
+}
+
+} // End of namespace Common
+#endif
+

Copied: tools/trunk/common/array.h (from rev 46716, scummvm/trunk/common/array.h)
===================================================================
--- tools/trunk/common/array.h	                        (rev 0)
+++ tools/trunk/common/array.h	2009-12-29 23:23:31 UTC (rev 46729)
@@ -0,0 +1,319 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef COMMON_ARRAY_H
+#define COMMON_ARRAY_H
+
+#include "common/scummsys.h"
+#include "common/algorithm.h"
+
+namespace Common {
+
+/**
+ * This class implements a dynamically sized container, which
+ * can be accessed similar to a regular C++ array. Accessing
+ * elements is performed in constant time (like with plain arrays).
+ * In addition, one can append, insert and remove entries (this
+ * is the 'dynamic' part). Doing that in general takes time
+ * proportional to the number of elements in the array.
+ *
+ * The container class closest to this in the C++ standard library is
+ * std::vector. However, there are some differences. The most important one is
+ * that std::vector has a far more sophisticated (and complicated) memory
+ * management scheme. There, only elements that 'live' are actually constructed
+ * (i.e., have their constructor called), and objects that are removed are
+ * immediately destructed (have their destructor called).
+ * With Common::Array, this is not the case; instead, it simply uses new[] and
+ * delete[] to allocate whole blocks of objects, possibly more than are
+ * currently 'alive'. This simplifies memory management, but may have
+ * undesirable side effects when one wants to use an Array of complex
+ * data types.
+ *
+ * @todo Improve the storage management of this class.
+ * In particular, don't use new[] and delete[], but rather
+ * construct/destruct objects manually. This way, we can
+ * ensure that storage which is not currently used does not
+ * correspond to a live active object.
+ * (This is only of interest for array of non-POD objects).
+ */
+template<class T>
+class Array {
+protected:
+	uint _capacity;
+	uint _size;
+	T *_storage;
+
+public:
+	typedef T *iterator;
+	typedef const T *const_iterator;
+
+	typedef T value_type;
+
+public:
+	Array() : _capacity(0), _size(0), _storage(0) {}
+
+	Array(const Array<T> &array) : _capacity(array._size), _size(array._size), _storage(0) {
+		if (array._storage) {
+			_storage = new T[_capacity];
+			assert(_storage);
+			copy(array._storage, array._storage + _size, _storage);
+		}
+	}
+
+	/**
+	 * Construct an array by copying data from a regular array.
+	 */
+	template<class T2>
+	Array(const T2 *data, int n) {
+		_capacity = _size = n;
+		_storage = new T[_capacity];
+		assert(_storage);
+		copy(data, data + _size, _storage);
+	}
+
+	~Array() {
+		delete[] _storage;
+		_storage = 0;
+		_capacity = _size = 0;
+	}
+
+	/** Appends element to the end of the array. */
+	void push_back(const T &element) {
+		if (_size + 1 <= _capacity)
+			_storage[_size++] = element;
+		else
+			insert_aux(end(), &element, &element + 1);
+	}
+
+	void push_back(const Array<T> &array) {
+		if (_size + array.size() <= _capacity) {
+			copy(array.begin(), array.end(), end());
+			_size += array.size();
+		} else
+			insert_aux(end(), array.begin(), array.end());
+	}
+
+	/** Removes the last element of the array. */
+	void pop_back() {
+		assert(_size > 0);
+		_size--;
+	}
+
+	/** Returns a reference to the first element of the array. */
+	T &front() {
+		assert(_size > 0);
+		return _storage[0];
+	}
+
+	/** Returns a reference to the first element of the array. */
+	const T &front() const {
+		assert(_size > 0);
+		return _storage[0];
+	}
+
+	/** Returns a reference to the last element of the array. */
+	T &back() {
+		assert(_size > 0);
+		return _storage[_size-1];
+	}
+
+	/** Returns a reference to the last element of the array. */
+	const T &back() const {
+		assert(_size > 0);
+		return _storage[_size-1];
+	}
+
+
+	void insert_at(int idx, const T &element) {
+		assert(idx >= 0 && (uint)idx <= _size);
+		insert_aux(_storage + idx, &element, &element + 1);
+	}
+
+	T remove_at(int idx) {
+		assert(idx >= 0 && (uint)idx < _size);
+		T tmp = _storage[idx];
+		copy(_storage + idx + 1, _storage + _size, _storage + idx);
+		_size--;
+		return tmp;
+	}
+
+	// TODO: insert, remove, ...
+
+	T& operator[](int idx) {
+		assert(idx >= 0 && (uint)idx < _size);
+		return _storage[idx];
+	}
+
+	const T& operator[](int idx) const {
+		assert(idx >= 0 && (uint)idx < _size);
+		return _storage[idx];
+	}
+
+	Array<T>& operator=(const Array<T> &array) {
+		if (this == &array)
+			return *this;
+
+		delete[] _storage;
+		_size = array._size;
+		_capacity = _size + 32;
+		_storage = new T[_capacity];
+		assert(_storage);
+		copy(array._storage, array._storage + _size, _storage);
+
+		return *this;
+	}
+
+	uint size() const {
+		return _size;
+	}
+
+	void clear() {
+		delete[] _storage;
+		_storage = 0;
+		_size = 0;
+		_capacity = 0;
+	}
+
+	bool empty() const {
+		return (_size == 0);
+	}
+
+	bool operator==(const Array<T> &other) const {
+		if (this == &other)
+			return true;
+		if (_size != other._size)
+			return false;
+		for (uint i = 0; i < _size; ++i) {
+			if (_storage[i] != other._storage[i])
+				return false;
+		}
+		return true;
+	}
+	bool operator!=(const Array<T> &other) const {
+		return !(*this == other);
+	}
+
+
+	iterator		begin() {
+		return _storage;
+	}
+
+	iterator		end() {
+		return _storage + _size;
+	}
+
+	const_iterator	begin() const {
+		return _storage;
+	}
+
+	const_iterator	end() const {
+		return _storage + _size;
+	}
+
+	void reserve(uint newCapacity) {
+		if (newCapacity <= _capacity)
+			return;
+
+		T *old_storage = _storage;
+		_capacity = newCapacity;
+		_storage = new T[newCapacity];
+		assert(_storage);
+
+		if (old_storage) {
+			// Copy old data
+			copy(old_storage, old_storage + _size, _storage);
+			delete[] old_storage;
+		}
+	}
+
+	void resize(uint newSize) {
+		reserve(newSize);
+		for (uint i = _size; i < newSize; ++i)
+			_storage[i] = T();
+		_size = newSize;
+	}
+
+protected:
+	static uint roundUpCapacity(uint capacity) {
+		// Round up capacity to the next power of 2;
+		// we use a minimal capacity of 8.
+		uint capa = 8;
+		while (capa < capacity)
+			capa <<= 1;
+		return capa;
+	}
+
+	/**
+	 * Insert a range of elements coming from this or another array.
+	 * Unlike std::vector::insert, this method does not accept
+	 * arbitrary iterators, mainly because our iterator system is
+	 * seriously limited and does not distinguish between input iterators,
+	 * output iterators, forward iterators or random access iterators.
+	 *
+	 * So, we simply restrict to Array iterators. Extending this to arbitrary
+	 * random access iterators would be trivial.
+	 *
+	 * Moreover, this method does not handle all cases of inserting a subrange
+	 * of an array into itself; this is why it is private for now.
+	 */
+	iterator insert_aux(iterator pos, const_iterator first, const_iterator last) {
+		assert(_storage <= pos && pos <= _storage + _size);
+		assert(first <= last);
+		const uint n = last - first;
+		if (n) {
+			const uint idx = pos - _storage;
+			T *newStorage = _storage;
+			if (_size + n > _capacity) {
+				// If there is not enough space, allocate more and
+				// copy old elements over.
+				uint newCapacity = roundUpCapacity(_size + n);
+				newStorage = new T[newCapacity];
+				assert(newStorage);
+				copy(_storage, _storage + idx, newStorage);
+				pos = newStorage + idx;
+			}
+
+			// Make room for the new elements by shifting back
+			// existing ones.
+			copy_backward(_storage + idx, _storage + _size, newStorage + _size + n);
+
+			// Insert the new elements.
+			copy(first, last, pos);
+
+			// Finally, update the internal state
+			if (newStorage != _storage) {
+				delete[] _storage;
+				_capacity = roundUpCapacity(_size + n);
+				_storage = newStorage;
+			}
+			_size += n;
+		}
+		return pos;
+	}
+
+};
+
+} // End of namespace Common
+
+#endif

Copied: tools/trunk/common/str.cpp (from rev 46716, scummvm/trunk/common/str.cpp)
===================================================================
--- tools/trunk/common/str.cpp	                        (rev 0)
+++ tools/trunk/common/str.cpp	2009-12-29 23:23:31 UTC (rev 46729)
@@ -0,0 +1,734 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "common/str.h"
+#include "common/hash-str.h"
+#include "common/util.h"
+
+#include "common/memorypool.h"
+
+#include <stdarg.h>
+
+#if !defined(__SYMBIAN32__)
+#include <new>
+#endif
+
+
+namespace Common {
+
+#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__))
+const String String::emptyString;
+#else
+const char *String::emptyString = "";
+#endif
+
+
+MemoryPool *g_refCountPool = 0;	// FIXME: This is never freed right now
+
+static uint32 computeCapacity(uint32 len) {
+	// By default, for the capacity we use the next multiple of 32
+	return ((len + 32 - 1) & ~0x1F);
+}
+
+String::String(const char *str) : _size(0), _str(_storage) {
+	if (str == 0) {
+		_storage[0] = 0;
+		_size = 0;
+	} else
+		initWithCStr(str, strlen(str));
+}
+
+String::String(const char *str, uint32 len) : _size(0), _str(_storage) {
+	initWithCStr(str, len);
+}
+
+String::String(const char *beginP, const char *endP) : _size(0), _str(_storage) {
+	assert(endP >= beginP);
+	initWithCStr(beginP, endP - beginP);
+}
+
+void String::initWithCStr(const char *str, uint32 len) {
+	assert(str);
+
+	// Init _storage member explicitly (ie. without calling its constructor)
+	// for GCC 2.95.x compatibility (see also tracker item #1602879).
+	_storage[0] = 0;
+
+	_size = len;
+
+	if (len >= _builtinCapacity) {
+		// Not enough internal storage, so allocate more
+		_extern._capacity = computeCapacity(len+1);
+		_extern._refCount = 0;
+		_str = new char[_extern._capacity];
+		assert(_str != 0);
+	}
+
+	// Copy the string into the storage area
+	memmove(_str, str, len);
+	_str[len] = 0;
+}
+
+String::String(const String &str)
+ : _size(str._size) {
+	if (str.isStorageIntern()) {
+		// String in internal storage: just copy it
+		memcpy(_storage, str._storage, _builtinCapacity);
+		_str = _storage;
+	} else {
+		// String in external storage: use refcount mechanism
+		str.incRefCount();
+		_extern._refCount = str._extern._refCount;
+		_extern._capacity = str._extern._capacity;
+		_str = str._str;
+	}
+	assert(_str != 0);
+}
+
+String::String(char c)
+: _size(0), _str(_storage) {
+
+	_storage[0] = c;
+	_storage[1] = 0;
+
+	// TODO/FIXME: There is no reason for the following check -- we *do*
+	// allow strings to contain 0 bytes!
+	_size = (c == 0) ? 0 : 1;
+}
+
+String::~String() {
+	decRefCount(_extern._refCount);
+}
+
+void String::makeUnique() {
+	ensureCapacity(_size, true);
+}
+
+/**
+ * Ensure that enough storage is available to store at least new_size
+ * characters plus a null byte. In addition, if we currently share
+ * the storage with another string, unshare it, so that we can safely
+ * write to the storage.
+ */
+void String::ensureCapacity(uint32 new_size, bool keep_old) {
+	bool isShared;
+	uint32 curCapacity, newCapacity;
+	char *newStorage;
+	int *oldRefCount = _extern._refCount;
+
+	if (isStorageIntern()) {
+		isShared = false;
+		curCapacity = _builtinCapacity;
+	} else {
+		isShared = (oldRefCount && *oldRefCount > 1);
+		curCapacity = _extern._capacity;
+	}
+
+	// Special case: If there is enough space, and we do not share
+	// the storage, then there is nothing to do.
+	if (!isShared && new_size < curCapacity)
+		return;
+
+	if (isShared && new_size < _builtinCapacity) {
+		// We share the storage, but there is enough internal storage: Use that.
+		newStorage = _storage;
+		newCapacity = _builtinCapacity;
+	} else {
+		// We need to allocate storage on the heap!
+
+		// Compute a suitable new capacity limit
+		newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1));
+
+		// Allocate new storage
+		newStorage = new char[newCapacity];
+		assert(newStorage);
+	}
+
+	// Copy old data if needed, elsewise reset the new storage.
+	if (keep_old) {
+		assert(_size < newCapacity);
+		memcpy(newStorage, _str, _size + 1);
+	} else {
+		_size = 0;
+		newStorage[0] = 0;
+	}
+
+	// Release hold on the old storage ...
+	decRefCount(oldRefCount);
+
+	// ... in favor of the new storage
+	_str = newStorage;
+
+	if (!isStorageIntern()) {
+		// Set the ref count & capacity if we use an external storage.
+		// It is important to do this *after* copying any old content,
+		// else we would override data that has not yet been copied!
+		_extern._refCount = 0;
+		_extern._capacity = newCapacity;
+	}
+}
+
+void String::incRefCount() const {
+	assert(!isStorageIntern());
+	if (_extern._refCount == 0) {
+		if (g_refCountPool == 0) {
+			g_refCountPool = new MemoryPool(sizeof(int));
+			assert(g_refCountPool);
+		}
+
+		_extern._refCount = (int *)g_refCountPool->allocChunk();
+		*_extern._refCount = 2;
+	} else {
+		++(*_extern._refCount);
+	}
+}
+
+void String::decRefCount(int *oldRefCount) {
+	if (isStorageIntern())
+		return;
+
+	if (oldRefCount) {
+		--(*oldRefCount);
+	}
+	if (!oldRefCount || *oldRefCount <= 0) {
+		// The ref count reached zero, so we free the string storage
+		// and the ref count storage.
+		if (oldRefCount) {
+			assert(g_refCountPool);
+			g_refCountPool->freeChunk(oldRefCount);
+		}
+		delete[] _str;
+
+		// Even though _str points to a freed memory block now,
+		// we do not change its value, because any code that calls
+		// decRefCount will have to do this afterwards anyway.
+	}
+}
+
+String& String::operator  =(const char *str) {
+	uint32 len = strlen(str);
+	ensureCapacity(len, false);
+	_size = len;
+	memmove(_str, str, len + 1);
+	return *this;
+}
+
+String &String::operator  =(const String &str) {
+	if (&str == this)
+		return *this;
+
+	if (str.isStorageIntern()) {
+		decRefCount(_extern._refCount);
+		_size = str._size;
+		_str = _storage;
+		memcpy(_str, str._str, _size + 1);
+	} else {
+		str.incRefCount();
+		decRefCount(_extern._refCount);
+
+		_extern._refCount = str._extern._refCount;
+		_extern._capacity = str._extern._capacity;
+		_size = str._size;
+		_str = str._str;
+	}
+
+	return *this;
+}
+
+String& String::operator  =(char c) {
+	decRefCount(_extern._refCount);
+	_str = _storage;
+	_size = 1;
+	_str[0] = c;
+	_str[1] = 0;
+	return *this;
+}
+
+String &String::operator +=(const char *str) {
+	if (_str <= str && str <= _str + _size)
+		return operator+=(Common::String(str));
+
+	int len = strlen(str);
+	if (len > 0) {
+		ensureCapacity(_size + len, true);
+
+		memcpy(_str + _size, str, len + 1);
+		_size += len;
+	}
+	return *this;
+}
+
+String &String::operator +=(const String &str) {
+	if (&str == this)
+		return operator+=(Common::String(str));
+
+	int len = str._size;
+	if (len > 0) {
+		ensureCapacity(_size + len, true);
+
+		memcpy(_str + _size, str._str, len + 1);
+		_size += len;
+	}
+	return *this;
+}
+
+String &String::operator +=(char c) {
+	ensureCapacity(_size + 1, true);
+
+	_str[_size++] = c;
+	_str[_size] = 0;
+
+	return *this;
+}
+
+bool String::hasPrefix(const String &x) const {
+	return hasPrefix(x.c_str());
+}
+
+bool String::hasPrefix(const char *x) const {
+	assert(x != 0);
+	// Compare x with the start of _str.
+	const char *y = c_str();
+	while (*x && *x == *y) {
+		++x;
+		++y;
+	}
+	// It's a prefix, if and only if all letters in x are 'used up' before
+	// _str ends.
+	return *x == 0;
+}
+
+bool String::hasSuffix(const String &x) const {
+	return hasSuffix(x.c_str());
+}
+
+bool String::hasSuffix(const char *x) const {
+	assert(x != 0);
+	// Compare x with the end of _str.
+	const uint32 x_size = strlen(x);
+	if (x_size > _size)
+		return false;
+	const char *y = c_str() + _size - x_size;
+	while (*x && *x == *y) {
+		++x;
+		++y;
+	}
+	// It's a suffix, if and only if all letters in x are 'used up' before
+	// _str ends.
+	return *x == 0;
+}
+
+bool String::contains(const String &x) const {
+	return strstr(c_str(), x.c_str()) != NULL;
+}
+
+bool String::contains(const char *x) const {
+	assert(x != 0);
+	return strstr(c_str(), x) != NULL;
+}
+
+bool String::contains(char x) const {
+	return strchr(c_str(), x) != NULL;
+}
+
+bool String::matchString(const char *pat, bool ignoreCase, bool pathMode) const {
+	return Common::matchString(c_str(), pat, ignoreCase, pathMode);
+}
+
+bool String::matchString(const String &pat, bool ignoreCase, bool pathMode) const {
+	return Common::matchString(c_str(), pat.c_str(), ignoreCase, pathMode);
+}
+
+void String::deleteLastChar() {
+	if (_size > 0)
+		deleteChar(_size - 1);
+}
+
+void String::deleteChar(uint32 p) {
+	assert(p < _size);
+
+	makeUnique();
+	while (p++ < _size)
+		_str[p-1] = _str[p];
+	_size--;
+}
+
+void String::clear() {
+	decRefCount(_extern._refCount);
+
+	_size = 0;
+	_str = _storage;
+	_storage[0] = 0;
+}
+
+void String::setChar(char c, uint32 p) {
+	assert(p <= _size);
+
+	makeUnique();
+	_str[p] = c;
+}
+
+void String::insertChar(char c, uint32 p) {
+	assert(p <= _size);
+
+	ensureCapacity(_size + 1, true);
+	_size++;
+	for (uint32 i = _size; i > p; --i)
+		_str[i] = _str[i-1];
+	_str[p] = c;
+}
+
+void String::toLowercase() {
+	makeUnique();
+	for (uint32 i = 0; i < _size; ++i)
+		_str[i] = tolower(_str[i]);
+}
+
+void String::toUppercase() {
+	makeUnique();
+	for (uint32 i = 0; i < _size; ++i)
+		_str[i] = toupper(_str[i]);
+}
+
+void String::trim() {
+	if (_size == 0)
+		return;
+
+	makeUnique();
+
+	// Trim trailing whitespace
+	while (_size >= 1 && isspace(_str[_size-1]))
+		_size--;
+	_str[_size] = 0;
+
+	// Trim leading whitespace
+	char *t = _str;
+	while (isspace(*t))
+		t++;
+
+	if (t != _str) {
+		_size -= t - _str;
+		memmove(_str, t, _size + 1);
+	}
+}
+
+uint String::hash() const {
+	return hashit(c_str());
+}
+
+// static
+String String::printf(const char *fmt, ...) {
+	String output;
+	assert(output.isStorageIntern());
+
+	va_list va;
+	va_start(va, fmt);
+	int len = vsnprintf(output._str, _builtinCapacity, fmt, va);
+	va_end(va);
+
+	if (len == -1) {
+		// MSVC doesn't return the size the full string would take up.
+		// Try increasing the size of the string until it fits.
+
+		// We assume MSVC failed to output the correct, null-terminated string
+		// if the return value is either -1 or size.
+		int size = _builtinCapacity;
+		do {
+			size *= 2;
+			output.ensureCapacity(size-1, false);
+			assert(!output.isStorageIntern());
+			size = output._extern._capacity;
+
+			va_start(va, fmt);
+			len = vsnprintf(output._str, size, fmt, va);
+			va_end(va);
+		} while (len == -1 || len >= size);
+		output._size = len;
+	} else if (len < (int)_builtinCapacity) {
+		// vsnprintf succeeded
+		output._size = len;
+	} else {
+		// vsnprintf didn't have enough space, so grow buffer
+		output.ensureCapacity(len, false);
+		va_start(va, fmt);
+		int len2 = vsnprintf(output._str, len+1, fmt, va);
+		va_end(va);
+		assert(len == len2);
+		output._size = len2;
+	}
+
+	return output;
+}
+
+
+#pragma mark -
+
+bool String::operator ==(const String &x) const {
+	return equals(x);
+}
+
+bool String::operator ==(const char *x) const {
+	assert(x != 0);
+	return equals(x);
+}
+
+bool String::operator !=(const String &x) const {
+	return !equals(x);
+}
+
+bool String::operator !=(const char *x) const {
+	assert(x != 0);
+	return !equals(x);
+}
+
+bool String::operator < (const String &x) const {
+	return compareTo(x) < 0;
+}
+
+bool String::operator <= (const String &x) const {
+	return compareTo(x) <= 0;
+}
+
+bool String::operator > (const String &x) const {
+	return compareTo(x) > 0;
+}
+
+bool String::operator >= (const String &x) const {
+	return compareTo(x) >= 0;
+}
+
+#pragma mark -
+
+bool operator == (const char* y, const String &x) {
+	return (x == y);
+}
+
+bool operator != (const char* y, const String &x) {
+	return x != y;
+}
+
+#pragma mark -
+
+bool String::equals(const String &x) const {
+	return (0 == compareTo(x));
+}
+
+bool String::equals(const char *x) const {
+	assert(x != 0);
+	return (0 == compareTo(x));
+}
+
+bool String::equalsIgnoreCase(const String &x) const {
+	return (0 == compareToIgnoreCase(x));
+}
+
+bool String::equalsIgnoreCase(const char *x) const {
+	assert(x != 0);
+	return (0 == compareToIgnoreCase(x));
+}
+
+int String::compareTo(const String &x) const {
+	return compareTo(x.c_str());
+}
+
+int String::compareTo(const char *x) const {
+	assert(x != 0);
+	return strcmp(c_str(), x);
+}
+
+int String::compareToIgnoreCase(const String &x) const {
+	return compareToIgnoreCase(x.c_str());
+}
+
+int String::compareToIgnoreCase(const char *x) const {
+	assert(x != 0);
+	return scumm_stricmp(c_str(), x);
+}
+
+#pragma mark -
+
+String operator +(const String &x, const String &y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+String operator +(const char *x, const String &y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+String operator +(const String &x, const char *y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+String operator +(char x, const String &y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+String operator +(const String &x, char y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+char *ltrim(char *t) {
+	while (isspace(*t))
+		t++;
+	return t;
+}
+
+char *rtrim(char *t) {
+	int l = strlen(t) - 1;
+	while (l >= 0 && isspace(t[l]))
+		t[l--] = 0;
+	return t;
+}
+
+char *trim(char *t) {
+	return rtrim(ltrim(t));
+}
+
+Common::String lastPathComponent(const Common::String &path, const char sep) {
+	const char *str = path.c_str();
+	const char *last = str + path.size();
+
+	// Skip over trailing slashes
+	while (last > str && *(last-1) == sep)
+		--last;
+
+	// Path consisted of only slashes -> return empty string
+	if (last == str)
+		return Common::String();
+
+	// Now scan the whole component
+	const char *first = last - 1;
+	while (first >= str && *first != sep)
+		--first;
+
+	if (*first == sep)
+		first++;
+
+	return Common::String(first, last);
+}
+
+Common::String normalizePath(const Common::String &path, const char sep) {
+	if (path.empty())
+		return path;
+
+	const char *cur = path.c_str();
+	Common::String result;
+
+	// If there is a leading slash, preserve that:
+	if (*cur == sep) {
+		result += sep;
+		while (*cur == sep)
+			++cur;
+	}
+
+	// Scan till the end of the String
+	while (*cur != 0) {
+		const char *start = cur;
+
+		// Scan till the next path separator resp. the end of the string
+		while (*cur != sep && *cur != 0)
+			cur++;
+
+		const Common::String component(start, cur);
+
+		// Skip empty components and dot components, add all others
+		if (!component.empty() && component != ".") {
+			// Add a separator before the component, unless the result
+			// string already ends with one (which happens only if the
+			// path *starts* with a separator).
+			if (!result.empty() && result.lastChar() != sep)
+				result += sep;
+
+			// Add the component
+			result += component;
+		}
+
+		// Skip over separator chars
+		while (*cur == sep)
+			cur++;
+	}
+
+	return result;
+}
+
+bool matchString(const char *str, const char *pat, bool ignoreCase, bool pathMode) {
+	assert(str);
+	assert(pat);
+
+	const char *p = 0;
+	const char *q = 0;
+
+	for (;;) {
+		if (pathMode && *str == '/') {
+			p = 0;
+			q = 0;
+			if (*pat == '?')
+				return false;
+		}
+
+		switch (*pat) {
+		case '*':
+			// Record pattern / string position for backtracking
+			p = ++pat;
+			q = str;
+			// If pattern ended with * -> match
+			if (!*pat)
+				return true;
+			break;
+
+		default:
+			if ((!ignoreCase && *pat != *str) ||
+				(ignoreCase && tolower(*pat) != tolower(*str))) {
+				if (p) {
+					// No match, oops -> try to backtrack
+					pat = p;
+					str = ++q;
+					if (!*str)
+						return !*pat;
+					break;
+				}
+				else
+					return false;
+			}
+			// fallthrough
+		case '?':
+			if (!*str)
+				return !*pat;
+			pat++;
+			str++;
+		}
+	}
+}
+
+}	// End of namespace Common

Copied: tools/trunk/common/str.h (from rev 46716, scummvm/trunk/common/str.h)
===================================================================
--- tools/trunk/common/str.h	                        (rev 0)
+++ tools/trunk/common/str.h	2009-12-29 23:23:31 UTC (rev 46729)
@@ -0,0 +1,332 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef COMMON_STRING_H
+#define COMMON_STRING_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+
+namespace Common {
+
+/**
+ * Simple string class for ScummVM. Provides automatic storage managment,
+ * and overloads several operators in a 'natural' fashion, mimicking
+ * the std::string class. Even provides simple iterators.
+ *
+ * This class tries to avoid allocating lots of small blocks on the heap,
+ * since that is inefficient on several platforms supported by ScummVM.
+ * Instead, small strings are stored 'inside' the string object (i.e. on
+ * the stack, for stack allocated objects), and only for strings exceeding
+ * a certain length do we allocate a buffer on the heap.
+ */
+class String {
+protected:
+	/**
+	 * The size of the internal storage. Increasing this means less heap
+	 * allocations are needed, at the cost of more stack memory usage,
+	 * and of course lots of wasted memory. Empirically, 90% or more of
+	 * all String instances are less than 32 chars long. If a platform
+	 * is very short on stack space, it would be possible to lower this.
+	 * A value of 24 still seems acceptable, though considerably worse,
+	 * while 16 seems to be the lowest you want to go... Anything lower
+	 * than 8 makes no sense, since that's the size of member _extern
+	 * (on 32 bit machines; 12 bytes on systems with 64bit pointers).
+	 */
+	static const uint32 _builtinCapacity = 32 - sizeof(uint32) - sizeof(char*);
+
+	/**
+	 * Length of the string. Stored to avoid having to call strlen
+	 * a lot. Yes, we limit ourselves to strings shorter than 4GB --
+	 * on purpose :-).
+	 */
+	uint32		_size;
+
+	/**
+	 * Pointer to the actual string storage. Either points to _storage,
+	 * or to a block allocated on the heap via malloc.
+	 */
+	char		*_str;
+
+
+	union {
+		/**
+		 * Internal string storage.
+		 */
+		char _storage[_builtinCapacity];
+		/**
+		 * External string storage data -- the refcounter, and the
+		 * capacity of the string _str points to.
+		 */
+		struct {
+			mutable int *_refCount;
+			uint32		_capacity;
+		} _extern;
+	};
+
+	inline bool isStorageIntern() const {
+		return _str == _storage;
+	}
+
+public:
+#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__))
+	static const String emptyString;
+#else
+	static const char *emptyString;
+#endif
+
+	/** Construct a new empty string. */
+	String() : _size(0), _str(_storage) { _storage[0] = 0; }
+
+	/** Construct a new string from the given NULL-terminated C string. */
+	String(const char *str);
+
+	/** Construct a new string containing exactly len characters read from address str. */
+	String(const char *str, uint32 len);
+
+	/** Construct a new string containing the characters between beginP (including) and endP (excluding). */
+	String(const char *beginP, const char *endP);
+
+	/** Construct a copy of the given string. */
+	String(const String &str);
+
+	/** Construct a string consisting of the given character. */
+	explicit String(char c);
+
+	~String();
+
+	String &operator  =(const char *str);
+	String &operator  =(const String &str);
+	String &operator  =(char c);
+	String &operator +=(const char *str);
+	String &operator +=(const String &str);
+	String &operator +=(char c);
+
+	bool operator ==(const String &x) const;
+	bool operator ==(const char *x) const;
+	bool operator !=(const String &x) const;
+	bool operator !=(const char *x) const;
+
+	bool operator <(const String &x) const;
+	bool operator <=(const String &x) const;
+	bool operator >(const String &x) const;
+	bool operator >=(const String &x) const;
+
+	bool equals(const String &x) const;
+	bool equalsIgnoreCase(const String &x) const;
+	int compareTo(const String &x) const;	// strcmp clone
+	int compareToIgnoreCase(const String &x) const;	// stricmp clone
+
+	bool equals(const char *x) const;
+	bool equalsIgnoreCase(const char *x) const;
+	int compareTo(const char *x) const;	// strcmp clone
+	int compareToIgnoreCase(const char *x) const;	// stricmp clone
+
+	bool hasSuffix(const String &x) const;
+	bool hasSuffix(const char *x) const;
+
+	bool hasPrefix(const String &x) const;
+	bool hasPrefix(const char *x) const;
+
+	bool contains(const String &x) const;
+	bool contains(const char *x) const;
+	bool contains(char x) const;
+
+	/**
+	 * Simple DOS-style pattern matching function (understands * and ? like used in DOS).
+	 * Taken from exult/files/listfiles.cc
+	 *
+	 * Token meaning:
+	 *		"*": any character, any amount of times.
+	 *		"?": any character, only once.
+	 *
+	 * Example strings/patterns:
+	 *		String: monkey.s01	 Pattern: monkey.s??	=> true
+	 *		String: monkey.s101	 Pattern: monkey.s??	=> false
+	 *		String: monkey.s99	 Pattern: monkey.s?1	=> false
+	 *		String: monkey.s101	 Pattern: monkey.s*		=> true
+	 *		String: monkey.s99	 Pattern: monkey.s*1	=> false
+	 *
+	 * @param str Text to be matched against the given pattern.
+	 * @param pat Glob pattern.
+	 * @param ignoreCase Whether to ignore the case when doing pattern match
+	 * @param pathMode Whether to use path mode, i.e., whether slashes must be matched explicitly.
+	 *
+	 * @return true if str matches the pattern, false otherwise.
+	 */
+	bool matchString(const char *pat, bool ignoreCase = false, bool pathMode = false) const;
+	bool matchString(const String &pat, bool ignoreCase = false, bool pathMode = false) const;
+
+
+	inline const char *c_str() const		{ return _str; }
+	inline uint size() const				{ return _size; }
+
+	inline bool empty() const	{ return (_size == 0); }
+	char lastChar() const	{ return (_size > 0) ? _str[_size-1] : 0; }
+
+	char operator[](int idx) const {
+		assert(_str && idx >= 0 && idx < (int)_size);
+		return _str[idx];
+	}
+
+	/** Remove the last character from the string. */
+	void deleteLastChar();
+
+	/** Remove the character at position p from the string. */
+	void deleteChar(uint32 p);
+
+	/** Set character c at position p, replacing the previous character there. */
+	void setChar(char c, uint32 p);
+
+	/** Insert character c before position p. */
+	void insertChar(char c, uint32 p);
+
+	/** Clears the string, making it empty. */
+	void clear();
+
+	/** Convert all characters in the string to lowercase. */
+	void toLowercase();
+
+	/** Convert all characters in the string to uppercase. */
+	void toUppercase();
+
+	/**
+	 * Removes trailing and leading whitespaces. Uses isspace() to decide
+	 * what is whitespace and what not.
+	 */
+	void trim();
+
+	uint hash() const;
+
+	/**
+	 * Printf-like function. Returns a formatted String.
+	 */
+	static Common::String printf(const char *fmt, ...) GCC_PRINTF(1,2);
+
+public:
+	typedef char *        iterator;
+	typedef const char *  const_iterator;
+
+	iterator		begin() {
+		return _str;
+	}
+
+	iterator		end() {
+		return begin() + size();
+	}
+
+	const_iterator	begin() const {
+		return _str;
+	}
+
+	const_iterator	end() const {
+		return begin() + size();
+	}
+
+protected:
+	void makeUnique();
+	void ensureCapacity(uint32 new_size, bool keep_old);
+	void incRefCount() const;
+	void decRefCount(int *oldRefCount);
+	void initWithCStr(const char *str, uint32 len);
+};
+
+// Append two strings to form a new (temp) string
+String operator +(const String &x, const String &y);
+
+String operator +(const char *x, const String &y);
+String operator +(const String &x, const char *y);
+
+String operator +(const String &x, char y);
+String operator +(char x, const String &y);
+
+// Some useful additional comparison operators for Strings
+bool operator == (const char *x, const String &y);
+bool operator != (const char *x, const String &y);
+
+// Utility functions to remove leading and trailing whitespaces
+extern char *ltrim(char *t);
+extern char *rtrim(char *t);
+extern char *trim(char *t);
+
+
+/**
+ * Returns the last component of a given path.
+ *
+ * Examples:
+ *			/foo/bar.txt would return 'bar.txt'
+ *			/foo/bar/    would return 'bar'
+ *			/foo/./bar//    would return 'bar'
+ *
+ * @param path the path of which we want to know the last component
+ * @param sep character used to separate path components
+ * @return The last component of the path.
+ */
+Common::String lastPathComponent(const Common::String &path, const char sep);
+
+/**
+ * Normalize a gien path to a canonical form. In particular:
+ * - trailing separators are removed:  /foo/bar/ -> /foo/bar
+ * - double separators (= empty components) are removed:   /foo//bar -> /foo/bar
+ * - dot components are removed:  /foo/./bar -> /foo/bar
+ *
+ * @todo remove double dot components:  /foo/baz/../bar -> /foo/bar
+ *
+ * @param path	the path to normalize
+ * @param sep	the separator token (usually '/' on Unix-style systems, or '\\' on Windows based stuff)
+ * @return	the normalized path
+ */
+Common::String normalizePath(const Common::String &path, const char sep);
+
+
+/**
+ * Simple DOS-style pattern matching function (understands * and ? like used in DOS).
+ * Taken from exult/files/listfiles.cc
+ *
+ * Token meaning:
+ *		"*": any character, any amount of times.
+ *		"?": any character, only once.
+ *
+ * Example strings/patterns:
+ *		String: monkey.s01	 Pattern: monkey.s??	=> true
+ *		String: monkey.s101	 Pattern: monkey.s??	=> false
+ *		String: monkey.s99	 Pattern: monkey.s?1	=> false
+ *		String: monkey.s101	 Pattern: monkey.s*		=> true
+ *		String: monkey.s99	 Pattern: monkey.s*1	=> false
+ *
+ * @param str Text to be matched against the given pattern.
+ * @param pat Glob pattern.
+ * @param ignoreCase Whether to ignore the case when doing pattern match
+ * @param pathMode Whether to use path mode, i.e., whether slashes must be matched explicitly.
+ *
+ * @return true if str matches the pattern, false otherwise.
+ */
+bool matchString(const char *str, const char *pat, bool ignoreCase = false, bool pathMode = false);
+
+
+typedef Array<String> StringList;
+
+}	// End of namespace Common
+
+#endif

Added: tools/trunk/engines/mohawk/deriven.cpp
===================================================================
--- tools/trunk/engines/mohawk/deriven.cpp	                        (rev 0)
+++ tools/trunk/engines/mohawk/deriven.cpp	2009-12-29 23:23:31 UTC (rev 46729)
@@ -0,0 +1,248 @@
+/* deriven - Riven script decompiler
+ * Copyright (C) 2009 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "mohawk_file.h"
+#include "utils/file.h"
+
+#define NO_OP "empty"
+
+static const char *opcode_names[] = {
+	// 0x00 (0 decimal)
+	NO_OP,
+	"drawBitmap",
+	"switchCard",
+	"playSound_Mix",
+	// 0x04 (4 decimal)
+	"playSound",
+	NO_OP,
+	NO_OP,
+	"setVariable",
+	// 0x08 (8 decimal)
+	"mohawkSwitch",
+	"enableHotspot",
+	"disableHotspot",
+	NO_OP,
+	// 0x0C (12 decimal)
+	"clearSLST",
+	"changeCursor",
+	"delay",
+	NO_OP,
+	// 0x10 (16 decimal)
+	NO_OP,
+	"runExternalCommand",
+	"transition",
+	"refreshCard",
+	// 0x14 (20 decimal)
+	"disableScreenUpdate",
+	"enableScreenUpdate",
+	NO_OP,
+	NO_OP,
+	// 0x18 (24 decimal)
+	"incrementVariable",
+	NO_OP,
+	NO_OP,
+	"changeStack",
+	// 0x1C (28 decimal)
+	"disableMovie",
+	"disableAllMovies",
+	NO_OP,
+	"enableMovie",
+	// 0x20 (32 decimal)
+	"playMovie",
+	"playMovieBg",
+	"stopMovie",
+	NO_OP,
+	// 0x24 (36 decimal)
+	"unk_36",						// Unknown
+	"fadeAmbientSounds",
+	"complexPlayMovie",
+	"activatePLST",
+	// 0x28 (40 decimal)
+	"activateSLST",
+	"activateMLSTAndPlay",
+	NO_OP,
+	"activateBLST",
+	// 0x2C (44 decimal)
+	"activateFLST",
+	"zipMode",
+	"activateMLST",
+	"activateSLSTWithVolume"
+};
+
+void printUsage(const char *appName) {
+	printf("Usage: %s <mohawk archive> [CARD or HSPT] [id]\n", appName);
+}
+
+Common::StringList getNameList(MohawkFile *mohawkFile, uint16 id) {
+	MohawkOutputStream nameResource = mohawkFile->getRawData(ID_NAME, id);
+	Common::StringList nameList;
+	
+	uint16 namesCount = nameResource.stream->readUint16BE();
+	uint16 *stringOffsets = new uint16[namesCount];
+	for (uint16 i = 0; i < namesCount; i++)
+		stringOffsets[i] = nameResource.stream->readUint16BE();
+	nameResource.stream->seek(namesCount * 2, SEEK_CUR);
+	int32 curNamesPos = nameResource.stream->pos();
+	
+	for (uint32 i = 0; i < namesCount; i++) {
+		nameResource.stream->seek(curNamesPos + stringOffsets[i]);
+			
+		Common::String name = Common::String::emptyString;
+		for (char c = nameResource.stream->readByte(); c; c = nameResource.stream->readByte())
+			name += c;
+		nameList.push_back(name);
+	}
+	
+	delete nameResource.stream;
+	delete[] stringOffsets;
+	
+	return nameList;
+}
+
+static void printTabs(byte tabs) {
+	for (byte i = 0; i < tabs; i++)
+		printf ("\t");
+}
+
+void dumpCommands(Common::SeekableReadStream *script, Common::StringList varNames, Common::StringList exNames, byte tabs) {
+	uint16 commandCount = script->readUint16BE();
+	
+	for (uint16 i = 0; i < commandCount; i++) {
+		uint16 command = script->readUint16BE();
+		
+		if (command == 8) { // "Switch" Statement
+			if (script->readUint16BE() != 2)
+				warning ("if-then-else unknown value is not 2");
+			uint16 var = script->readUint16BE();
+			printTabs(tabs); printf("switch (%s) {\n", varNames[var].c_str());
+			uint16 logicBlockCount = script->readUint16BE();
+			for (uint16 j = 0; j < logicBlockCount; j++) {
+				uint16 varCheck = script->readUint16BE();
+				printTabs(tabs + 1); 
+				if (varCheck == 0xFFFF)
+					printf("default:\n");
+				else
+					printf("case %d:\n", varCheck);
+				dumpCommands(script, varNames, exNames, tabs + 2);
+				printTabs(tabs + 2); printf("break;\n");
+			}
+			printTabs(tabs); printf("}\n");
+		} else if (command == 7) { // Use the variable name
+			script->readUint16BE(); // Skip the opcode var count
+			printTabs(tabs);
+			uint16 varIndex = script->readUint16BE();
+			printf("%s = %d;\n", varNames[varIndex].c_str(), script->readUint16BE());
+		} else if (command == 17) { // Use the external command name
+			script->readUint16BE(); // Skip the opcode var count
+			printTabs(tabs);
+			printf("%s(", exNames[script->readUint16BE()].c_str());
+			uint16 varCount = script->readUint16BE();
+			for (uint16 j = 0; j < varCount; j++) {
+				printf("%d", script->readUint16BE());
+				if (j != varCount - 1)
+					printf(", ");
+			}
+			printf (");\n");
+		} else if (command == 24) { // Use the variable name
+			script->readUint16BE(); // Skip the opcode var count
+			printTabs(tabs);
+			uint16 varIndex = script->readUint16BE();
+			printf ("%s += %d;\n", varNames[varIndex].c_str(), script->readUint16BE());
+		} else {
+			printTabs(tabs);
+			uint16 varCount = script->readUint16BE();
+			printf("%s(", opcode_names[command]);
+			for (uint16 j = 0; j < varCount; j++) {
+				printf("%d", script->readUint16BE());
+				if (j != varCount - 1)
+					printf(", ");
+			}
+			printf(");\n");
+		}
+	}
+}
+
+void dumpScript(Common::SeekableReadStream *script, Common::StringList varNames, Common::StringList exNames, byte tabs) {
+	uint16 scriptCount = script->readUint16BE();
+	
+	for (uint16 i = 0; i < scriptCount; i++) {
+		printTabs(tabs); printf ("Stream Type %d:\n", script->readUint16BE());
+		dumpCommands(script, varNames, exNames, tabs + 1);
+	}
+}
+
+int main(int argc, char *argv[]) {
+	if (argc != 4) {
+		printUsage(argv[0]);
+		return 1;
+	}
+	
+	FILE *file = fopen(argv[1], "rb");
+	if (!file) {
+		printf ("Could not open \'%s\'\n", argv[1]);
+		return 1;
+	}
+	
+	// Open the file as a Mohawk archive
+	MohawkFile *mohawkFile = new MohawkFile();
+	mohawkFile->open(new Common::File(file));
+	
+	// Load in Variable/External Command Names'
+	Common::StringList exNames = getNameList(mohawkFile, 3);
+	Common::StringList varNames = getNameList(mohawkFile, 4);
+	
+	uint32 tag = READ_BE_UINT32(argv[2]);
+	uint32 cardId = (uint16)atoi(argv[3]);
+	
+	if (tag == ID_CARD) {
+		printf("\n\nDumping scripts for card %d!\n", cardId);
+		printf("==================================\n\n");
+	
+		MohawkOutputStream cardStream = mohawkFile->getRawData(ID_CARD, cardId);
+		cardStream.stream->readUint32BE(); // Skip first 4 bytes
+		
+		dumpScript(cardStream.stream, varNames, exNames, 0);
+		
+		delete cardStream.stream;
+	} else if (tag == ID_HSPT) {
+		printf("\n\nDumping scripts for card %d hotspots!\n", cardId);
+		printf("===========================================\n\n");
+	
+		MohawkOutputStream hsptStream = mohawkFile->getRawData(ID_HSPT, cardId);
+		uint16 hotspotCount = hsptStream.stream->readUint16BE();
+		
+		for (uint16 i = 0; i < hotspotCount; i++) {
+			printf("Hotspot %d:\n", i);
+			hsptStream.stream->seek(22, SEEK_CUR); // Skip non-script related stuff
+			dumpScript(hsptStream.stream, varNames, exNames, 1);
+		}
+		
+		delete hsptStream.stream;
+	} else {
+		printf("That resource (if it exists) doesn't contain script data!\n");
+	}
+	
+	exNames.clear();
+	varNames.clear();
+	
+	return 0;
+}


Property changes on: tools/trunk/engines/mohawk/deriven.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: tools/trunk/engines/mohawk/extract_mohawk.cpp
===================================================================
--- tools/trunk/engines/mohawk/extract_mohawk.cpp	                        (rev 0)
+++ tools/trunk/engines/mohawk/extract_mohawk.cpp	2009-12-29 23:23:31 UTC (rev 46729)
@@ -0,0 +1,181 @@
+/* extract_mohawk - Mohawk file extractor
+ * Copyright (C) 2009 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "mohawk_file.h"
+#include "utils/file.h"
+
+// Have a maximum buffer size
+#define MAX_BUF_SIZE 16384
+
+void printUsage(const char *appName) {
+	printf("Usage: %s <mohawk archive> [tag id]\n", appName);
+}
+
+static byte *outputBuffer = NULL;
+
+void convertSoundResource(MohawkOutputStream output) {
+	printf ("Converting sounds not yet supported.\n");
+}
+
+void convertMovieResource(MohawkOutputStream output) {
+	printf ("Converting movies not yet supported. Dumping instead...\n");
+}
+
+void convertMIDIResource(MohawkOutputStream output) {
+	// Read the Mohawk MIDI header
+	assert(output.stream->readUint32BE() == ID_MHWK);
+	output.stream->readUint32BE(); // Skip size
+	assert(output.stream->readUint32BE() == ID_MIDI);
+	
+	uint32 size = output.stream->size() - 12; // Skip MHWK header's size
+	
+	byte *midiData = (byte *)malloc(size);
+	
+	// Read the MThd Data
+	output.stream->read(midiData, 14);
+	
+	// Skip the unknown Prg# section
+	assert(output.stream->readUint32BE() == ID_PRG);
+	output.stream->skip(output.stream->readUint32BE());
+	
+	// Read the MTrk Data
+	uint32 mtrkSize = output.stream->size() - output.stream->pos();
+	output.stream->read(midiData + 14, mtrkSize);
+	
+	// Change the extension to midi
+	output.name += ".mid";
+	
+	printf ("Extracting \'%s\'...\n", output.name.c_str());
+	
+	FILE *outputFile = fopen(output.name.c_str(), "wb");
+	if (!outputFile) {
+		printf ("Could not open file for output!\n");
+		free(midiData);
+		return;
+	}
+	
+	// Output the data to the file.
+	fwrite(midiData, 1, 14 + mtrkSize, outputFile);
+	free(midiData);
+	
+	fflush(outputFile);
+	fclose(outputFile);
+}
+
+void outputMohawkStream(MohawkOutputStream output) {
+	// No specified name, prepare our own
+	if (output.name.empty()) {
+		char *strBuf = (char *)malloc(256);
+		sprintf(strBuf, "%s_%d", tag2str(output.tag), output.id);
+		output.name = strBuf;
+	}
+	
+	// Intercept the sound tags
+	if (output.tag == ID_TWAV || output.tag == ID_MSND || output.tag == ID_SND) {
+		convertSoundResource(output);
+		return;
+	}
+	
+	// Intercept the movie tag (need to change the offsets)
+	// TODO: Actually convert. Just dump for now.
+	if (output.tag == ID_TMOV) {
+		convertMovieResource(output);
+		//return;
+	}
+	
+	// Intercept the MIDI tag (strip out Mohawk header/Prg# stuff)
+	if (output.tag == ID_TMID) {
+		convertMIDIResource(output);
+		return;
+	}
+	
+	// TODO: Convert other resources? PICT/WDIB/tBMP?
+	
+	assert(outputBuffer);
+	
+	printf ("Extracting \'%s\'...\n", output.name.c_str());
+	
+	FILE *outputFile = fopen(output.name.c_str(), "wb");
+	if (!outputFile) {
+		printf ("Could not open file for output!\n");
+		return;
+	}
+	
+	while (output.stream->pos() < output.stream->size()) {
+		uint32 size = output.stream->read(outputBuffer, MAX_BUF_SIZE);
+		fwrite(outputBuffer, 1, size, outputFile); 
+	}
+	
+	fflush(outputFile);
+	fclose(outputFile);
+}
+
+int main(int argc, char *argv[]) {
+	if (argc < 2 || argc == 3) {
+		printUsage(argv[0]);
+		return 1;
+	}
+	
+	FILE *file = fopen(argv[1], "rb");
+	if (!file) {
+		printf ("Could not open \'%s\'\n", argv[1]);
+		return 1;
+	}
+	
+	// Open the file as a Mohawk archive
+	MohawkFile *mohawkFile;
+	if(Common::String(argv[0]).hasSuffix("old"))
+		mohawkFile = new OldMohawkFile();
+	else
+		mohawkFile = new MohawkFile();
+	mohawkFile->open(new Common::File(file));
+	
+	// Allocate a buffer for the output
+	outputBuffer = (byte *)malloc(MAX_BUF_SIZE);
+	
+	if (argc > 3) {
+		uint32 tag = READ_BE_UINT32(argv[2]);
+		uint16 id = (uint16)atoi(argv[3]);
+		
+		MohawkOutputStream output = mohawkFile->getRawData(tag, id);
+		
+		if (output.stream) {
+			outputMohawkStream(output);
+			delete output.stream;
+		} else {
+			printf ("Could not find specified data!\n");
+		}
+	} else {
+		MohawkOutputStream output = mohawkFile->getNextFile();
+		while (output.stream) {
+			outputMohawkStream(output);
+			delete output.stream;
+			output = mohawkFile->getNextFile();
+		}
+	}
+	
+	printf ("Done!\n");
+	
+	free(outputBuffer);
+
+	return 0;
+}


Property changes on: tools/trunk/engines/mohawk/extract_mohawk.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: tools/trunk/engines/mohawk/mohawk_file.cpp
===================================================================
--- tools/trunk/engines/mohawk/mohawk_file.cpp	                        (rev 0)
+++ tools/trunk/engines/mohawk/mohawk_file.cpp	2009-12-29 23:23:31 UTC (rev 46729)
@@ -0,0 +1,373 @@
+/* mohawk_file - Mohawk file parser
+ * Copyright (C) 2009 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "mohawk_file.h"
+
+inline uint32 SWAP_BYTES_32(uint32 a) {
+	const uint16 low = (uint16)a, high = (uint16)(a >> 16);
+	return ((uint32)(uint16)((low >> 8) | (low << 8)) << 16)
+		   | (uint16)((high >> 8) | (high << 8));
+}
+
+MohawkFile::MohawkFile() {
+	_mhk = NULL;
+	_curFile = Common::String::emptyString;
+	_types = NULL;
+	_fileTable = NULL;
+}
+
+void MohawkFile::close() {
+	delete _mhk; _mhk = NULL;
+	delete[] _types; _types = NULL;
+	delete[] _fileTable; _fileTable = NULL;
+	
+	_curFile = Common::String::emptyString;
+}
+
+void MohawkFile::open(Common::SeekableReadStream *stream) {
+	// Make sure no other file is open...
+	close();
+	_mhk = stream;
+
+	if (_mhk->readUint32BE() != ID_MHWK)
+		error ("Could not find tag \'MHWK\'");
+
+	_fileSize = _mhk->readUint32BE();
+
+	if (_mhk->readUint32BE() != ID_RSRC)
+		error ("Could not find tag \'RSRC\'");
+
+	_rsrc.size = _mhk->readUint32BE();
+	_rsrc.filesize = _mhk->readUint32BE();
+	_rsrc.abs_offset = _mhk->readUint32BE();
+	_rsrc.file_table_offset = _mhk->readUint16BE();
+	_rsrc.file_table_size = _mhk->readUint16BE();
+
+	debug (3, "Absolute Offset = %08x", _rsrc.abs_offset);
+
+	/////////////////////////////////
+	//Resource Dir
+	/////////////////////////////////		
+
+	// Type Table
+	_mhk->seek(_rsrc.abs_offset);
+	_typeTable.name_offset = _mhk->readUint16BE();
+	_typeTable.resource_types = _mhk->readUint16BE();
+
+	debug (0, "Name List Offset = %04x  Number of Resource Types = %04x", _typeTable.name_offset, _typeTable.resource_types);
+
+	_types = new Type[_typeTable.resource_types];
+
+	for (uint16 i = 0; i < _typeTable.resource_types; i++) {
+		_types[i].tag = _mhk->readUint32BE();
+		_types[i].resource_table_offset = _mhk->readUint16BE();
+		_types[i].name_table_offset = _mhk->readUint16BE();
+
+		// HACK: Zoombini's SND resource starts will a NULL.
+		if (_types[i].tag == ID_SND)
+			debug (3, "Type[%02d]: Tag = \'SND\' ResTable Offset = %04x  NameTable Offset = %04x", i, _types[i].resource_table_offset, _types[i].name_table_offset);
+		else
+			debug (3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x  NameTable Offset = %04x", i, tag2str(_types[i].tag), _types[i].resource_table_offset, _types[i].name_table_offset);
+
+		//Resource Table
+		_mhk->seek(_rsrc.abs_offset + _types[i].resource_table_offset);
+		_types[i].resTable.resources = _mhk->readUint16BE();
+
+		debug (3, "Resources = %04x", _types[i].resTable.resources);
+
+		_types[i].resTable.entries = new Type::ResourceTable::Entries[_types[i].resTable.resources];
+                        
+		for (uint16 j = 0; j < _types[i].resTable.resources; j++) {
+			_types[i].resTable.entries[j].id = _mhk->readUint16BE();
+			_types[i].resTable.entries[j].index = _mhk->readUint16BE();
+
+			debug (4, "Entry[%02x]: ID = %04x (%d) Index = %04x", j, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].index); 
+		}
+
+		// Name Table
+		_mhk->seek(_rsrc.abs_offset + _types[i].name_table_offset);
+		_types[i].nameTable.num = _mhk->readUint16BE();
+
+		debug (3, "Names = %04x", _types[i].nameTable.num);
+
+		_types[i].nameTable.entries = new Type::NameTable::Entries[_types[i].nameTable.num];
+                        
+		for (uint16 j = 0; j < _types[i].nameTable.num; j++) {
+			_types[i].nameTable.entries[j].offset = _mhk->readUint16BE();
+			_types[i].nameTable.entries[j].index = _mhk->readUint16BE();
+
+			debug (4, "Entry[%02x]: Name List Offset = %04x  Index = %04x", j, _types[i].nameTable.entries[j].offset, _types[i].nameTable.entries[j].index);
+
+			// Name List
+			uint32 pos = _mhk->pos();
+			_mhk->seek(_rsrc.abs_offset + _typeTable.name_offset + _types[i].nameTable.entries[j].offset);
+			char c = (char)_mhk->readByte();
+			while (c != 0) {
+				_types[i].nameTable.entries[j].name += c;
+				c = (char)_mhk->readByte();
+			}
+
+			debug (3, "Name = \'%s\'", _types[i].nameTable.entries[j].name.c_str());
+
+			// Get back to next entry
+			_mhk->seek(pos);
+		}
+
+		// Return to next TypeTable entry
+		_mhk->seek(_rsrc.abs_offset + (i + 1) * 8 + 4);
+
+		debug (3, "\n");
+	}
+
+	_mhk->seek(_rsrc.abs_offset + _rsrc.file_table_offset);
+	_fileTableAmount = _mhk->readUint32BE();
+	_fileTable = new FileTable[_fileTableAmount];
+                
+	for (uint32 i = 0; i < _fileTableAmount; i++) {
+		_fileTable[i].offset = _mhk->readUint32BE();
+		_fileTable[i].dataSize = _mhk->readUint16BE();
+		_fileTable[i].dataSize += _mhk->readByte() << 16; // Get bits 15-24 of dataSize too
+		_fileTable[i].flags = _mhk->readByte();
+		_fileTable[i].unk = _mhk->readUint16BE();
+		
+		// Add in another 3 bits for file size from the flags.
+		// The flags are useless to us except for doing this ;)
+		_fileTable[i].dataSize += (_fileTable[i].flags & 7) << 24;
+
+		debug (4, "File[%02x]: Offset = %08x  DataSize = %07x  Flags = %02x  Unk = %04x", i, _fileTable[i].offset, _fileTable[i].dataSize, _fileTable[i].flags, _fileTable[i].unk);
+	}
+}
+
+bool MohawkFile::hasResource(uint32 tag, uint16 id) {
+	if (!_mhk)
+		return false;
+
+	int16 typeIndex = getTypeIndex(tag);
+
+	if (typeIndex < 0)
+		return false;
+
+	return (getIdIndex(typeIndex, id) >= 0);
+}
+
+MohawkOutputStream MohawkFile::getRawData(uint32 tag, uint16 id) {
+	MohawkOutputStream output = { 0, 0, 0, "" };
+
+	if (!_mhk)
+		return output;
+
+	int16 typeIndex = getTypeIndex(tag);
+
+	if (typeIndex < 0)
+		return output;
+
+	int16 idIndex = getIdIndex(typeIndex, id);
+
+	if (idIndex < 0)
+		return output;
+
+	// Note: the fileTableIndex is based off 1, not 0. So, subtract 1
+	uint16 fileTableIndex = _types[typeIndex].resTable.entries[idIndex].index - 1;
+	
+	// WORKAROUND: tMOV resources pretty much ignore the size part of the file table,
+	// as the original just passed the full Mohawk file to QuickTime and the offset.
+	// We need to do this because of the way Mohawk is set up (this is much more "proper"
+	// than passing _mhk at the right offset). We may want to do that in the future, though.
+	if (_types[typeIndex].tag == ID_TMOV) {
+		if (fileTableIndex == _fileTableAmount)
+			output.stream = new Common::SeekableSubReadStream(_mhk, _fileTable[fileTableIndex].offset, _mhk->size());
+		else
+			output.stream = new Common::SeekableSubReadStream(_mhk, _fileTable[fileTableIndex].offset, _fileTable[fileTableIndex + 1].offset);
+	} else
+		output.stream = new Common::SeekableSubReadStream(_mhk, _fileTable[fileTableIndex].offset, _fileTable[fileTableIndex].offset + _fileTable[fileTableIndex].dataSize);
+	output.tag = tag;
+	output.id = id; 
+	if (_types[typeIndex].nameTable.num > 0)
+		output.name = _types[typeIndex].nameTable.entries[idIndex].name;
+
+	return output;
+}
+
+MohawkOutputStream MohawkFile::getNextFile() {
+	MohawkOutputStream output = { 0, 0, 0, "" };
+	
+	if (_curExType >= _typeTable.resource_types) // No more!
+		return output;
+		
+	if (_curExTypeIndex >= _types[_curExType].resTable.resources) {
+		_curExType++;
+		_curExTypeIndex = 0;
+		
+		if (_curExType >= _typeTable.resource_types) // No more!
+			return output;
+	}
+		
+	uint16 fileTableIndex = _types[_curExType].resTable.entries[_curExTypeIndex].index - 1;
+	
+	// For some unknown reason, all tMOV resources have incorrect sizes. We correct this by getting the differences between offsets.
+	uint32 dataSize = 0;
+	if (_types[_curExType].tag == ID_TMOV)
+		dataSize = _fileTable[fileTableIndex + 1].offset - _fileTable[fileTableIndex].offset;
+	else
+		dataSize = _fileTable[fileTableIndex].dataSize;
+		
+	output.stream = new Common::SeekableSubReadStream(_mhk, _fileTable[fileTableIndex].offset, _fileTable[fileTableIndex].offset + dataSize, false);
+	output.tag = _types[_curExType].tag;
+	output.id = _types[_curExType].resTable.entries[_curExTypeIndex].id;
+	
+	if (_types[_curExType].nameTable.num > 0)
+		output.name = _types[_curExType].nameTable.entries[_curExTypeIndex].name;
+	
+	_curExTypeIndex++;
+	return output;
+}
+
+void OldMohawkFile::open(Common::SeekableReadStream *stream) {
+	close();
+	_mhk = stream;
+	
+	// This is for the "old" Mohawk resource format used in some older
+	// Living Books. It is very similar, just missing the MHWK tag and
+	// some other minor differences, especially with the file table
+	// being merged into the resource table.
+	
+	uint32 headerSize = _mhk->readUint32BE();
+	
+	// NOTE: There are differences besides endianness! (Subtle changes,
+	// but different).
+	
+	if (headerSize == 6) { // We're in Big Endian mode (Macintosh)
+		_mhk->readUint16BE(); // Resource Table Size
+		_typeTable.resource_types = _mhk->readUint16BE();
+		_types = new OldType[_typeTable.resource_types];
+		
+		debug (0, "Old Mohawk File (Macintosh): Number of Resource Types = %04x", _typeTable.resource_types);
+		
+		for (uint16 i = 0; i < _typeTable.resource_types; i++) {
+			_types[i].tag = _mhk->readUint32BE();
+			_types[i].resource_table_offset = (uint16)_mhk->readUint32BE() + 6;
+			_mhk->readUint32BE(); // Unknown (always 0?)
+			
+			debug (3, "Type[%02d]: Tag = \'%s\'  ResTable Offset = %04x", i, tag2str(_types[i].tag), _types[i].resource_table_offset);
+
+			uint32 oldPos = _mhk->pos();
+			
+			// Resource Table/File Table
+			_mhk->seek(_types[i].resource_table_offset);
+			_types[i].resTable.resources = _mhk->readUint16BE();
+			_types[i].resTable.entries = new OldType::ResourceTable::Entries[_types[i].resTable.resources];
+			
+			for (uint16 j = 0; j < _types[i].resTable.resources; j++) {
+				_types[i].resTable.entries[j].id = _mhk->readUint16BE();
+				_types[i].resTable.entries[j].offset = _mhk->readUint32BE();
+				_types[i].resTable.entries[j].size = _mhk->readByte() << 16;
+				_types[i].resTable.entries[j].size += _mhk->readUint16BE();
+				_mhk->skip(5); // Unknown (always 0?)
+				
+				debug (4, "Entry[%02x]: ID = %04x (%d)\tOffset = %08x, Size = %08x", j, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].offset, _types[i].resTable.entries[j].size);
+			}
+			
+			_mhk->seek(oldPos);
+			debug (3, "\n");
+		}
+	} else if (SWAP_BYTES_32(headerSize) == 6) { // We're in Little Endian mode (Windows)
+		_mhk->readUint16LE(); // Resource Table Size
+		_typeTable.resource_types = _mhk->readUint16LE();
+		_types = new OldType[_typeTable.resource_types];
+		
+		debug (0, "Old Mohawk File (Windows): Number of Resource Types = %04x", _typeTable.resource_types);
+		
+		for (uint16 i = 0; i < _typeTable.resource_types; i++) {
+			_types[i].tag = _mhk->readUint32LE();
+			_types[i].resource_table_offset = _mhk->readUint16LE() + 6;
+			_mhk->readUint16LE(); // Unknown (always 0?)
+			
+			debug (3, "Type[%02d]: Tag = \'%s\'  ResTable Offset = %04x", i, tag2str(_types[i].tag), _types[i].resource_table_offset);
+			
+			uint32 oldPos = _mhk->pos();
+			
+			// Resource Table/File Table
+			_mhk->seek(_types[i].resource_table_offset);
+			_types[i].resTable.resources = _mhk->readUint16LE();
+			_types[i].resTable.entries = new OldType::ResourceTable::Entries[_types[i].resTable.resources];
+			
+			for (uint16 j = 0; j < _types[i].resTable.resources; j++) {
+				_types[i].resTable.entries[j].id = _mhk->readUint16LE();
+				_types[i].resTable.entries[j].offset = _mhk->readUint32LE();
+				_types[i].resTable.entries[j].size = _mhk->readUint16LE();
+				_mhk->readUint32LE(); // Unknown (always 0?)
+				
+				debug (4, "Entry[%02x]: ID = %04x (%d)\tOffset = %08x, Size = %08x", j, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].offset, _types[i].resTable.entries[j].size); 
+			}
+			
+			_mhk->seek(oldPos);
+			debug (3, "\n");
+		}
+	} else
+		error("Could not determine type of Old Mohawk resource");
+
+}
+
+MohawkOutputStream OldMohawkFile::getRawData(uint32 tag, uint16 id) {
+	MohawkOutputStream output = { 0, 0, 0, "" };
+
+	if (!_mhk)
+		return output;
+
+	int16 typeIndex = getTypeIndex(tag);
+
+	if (typeIndex < 0)
+		return output;
+
+	int16 idIndex = getIdIndex(typeIndex, id);
+
+	if (idIndex < 0)
+		return output;
+
+	output.stream = new Common::SeekableSubReadStream(_mhk, _types[typeIndex].resTable.entries[idIndex].offset, _types[typeIndex].resTable.entries[idIndex].offset + _types[typeIndex].resTable.entries[idIndex].size);
+	output.tag = tag;
+	output.id = id;
+
+	return output;
+}
+
+MohawkOutputStream OldMohawkFile::getNextFile() {
+	MohawkOutputStream output = { 0, 0, 0, "" };
+	
+	if (_curExType >= _typeTable.resource_types) // No more!
+		return output;
+		
+	if (_curExTypeIndex >= _types[_curExType].resTable.resources) {
+		_curExType++;
+		_curExTypeIndex = 0;
+		
+		if (_curExType >= _typeTable.resource_types) // No more!
+			return output;
+	}
+	
+	output.stream = new Common::SeekableSubReadStream(_mhk, _types[_curExType].resTable.entries[_curExTypeIndex].offset, _types[_curExType].resTable.entries[_curExTypeIndex].offset + _types[_curExType].resTable.entries[_curExTypeIndex].size);
+	output.tag = _types[_curExType].tag;
+	output.id = _types[_curExType].resTable.entries[_curExTypeIndex].id;
+	
+	_curExTypeIndex++;
+	return output;
+}


Property changes on: tools/trunk/engines/mohawk/mohawk_file.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: tools/trunk/engines/mohawk/mohawk_file.h
===================================================================
--- tools/trunk/engines/mohawk/mohawk_file.h	                        (rev 0)
+++ tools/trunk/engines/mohawk/mohawk_file.h	2009-12-29 23:23:31 UTC (rev 46729)
@@ -0,0 +1,259 @@
+/* mohawk_file - Mohawk file parser
+ * Copyright (C) 2009 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef MOHAWK_FILE_H
+#define MOHAWK_FILE_H
+
+#include "utils/str.h"
+#include "utils/stream.h"
+
+// Main FourCC's
+#define ID_MHWK MKID_BE('MHWK') // Main FourCC
+#define ID_RSRC MKID_BE('RSRC') // Resource Directory Tag
+
+// Myst Resource FourCC's
+#define ID_CLRC MKID_BE('CLRC') // Cursor Hotspots
+#define ID_EXIT MKID_BE('EXIT') // Card Exit Scripts
+#define ID_HINT MKID_BE('HINT') // Specifies Cursors in What Area
+#define ID_INIT MKID_BE('INIT') // Card Entrance Scripts
+#define ID_MSND MKID_BE('MSND') // Standard Mohawk Sound
+#define ID_RLST MKID_BE('RLST') // Resource List, Specifies HotSpots
+#define ID_RSFL MKID_BE('RSFL') // ??? (system.dat only)
+#define ID_VIEW MKID_BE('VIEW') // Card Details
+#define ID_WDIB MKID_BE('WDIB') // LZ-Compressed Windows Bitmap
+
+// Myst Masterpiece Edition Resource FourCC's (In addition to Myst FourCC's)
+#define ID_HELP MKID_BE('HELP') // Help Chunk
+#define ID_MJMP MKID_BE('MJMP') // MSND Jumps (To reduce MSND duplication)
+#define ID_PICT MKID_BE('PICT') // JPEG/PICT Image
+
+// Riven Resource FourCC's
+#define ID_BLST MKID_BE('BLST') // Card Hotspot Enabling Lists
+#define ID_CARD MKID_BE('CARD') // Card Scripts
+#define ID_FLST MKID_BE('FLST') // Card SFXE Lists
+#define ID_HSPT MKID_BE('HSPT') // Card Hotspots
+#define ID_MLST MKID_BE('MLST') // Card Movie Lists
+#define ID_NAME MKID_BE('NAME') // Object Names
+#define ID_PLST MKID_BE('PLST') // Card Picture Lists
+#define ID_RMAP MKID_BE('RMAP') // Card Code
+#define ID_SFXE MKID_BE('SFXE') // Water Effect Animations
+#define ID_SLST MKID_BE('SLST') // Card Ambient Sound Lists
+#define ID_TMOV MKID_BE('tMOV') // Game Movie
+
+// Riven Saved Game FourCC's
+#define ID_VARS MKID_BE('VARS') // Saved Game Variable Values
+#define ID_VERS MKID_BE('VERS') // Version Info
+#define ID_ZIPS MKID_BE('ZIPS') // Zip Mode Status
+
+// Zoombini Resource FourCC's
+#define ID_SND  MKID_BE('\0SND') // Standard Mohawk Sound
+#define ID_CURS MKID_BE('CURS') // Cursor?
+#define ID_SCRB MKID_BE('SCRB') // ???
+#define ID_SCRS MKID_BE('SCRS') // ???
+#define ID_NODE MKID_BE('NODE') // ???
+#define ID_PATH MKID_BE('PATH') // ???
+#define ID_SHPL MKID_BE('SHPL') // ???
+
+// Living Books Resource FourCC's
+#define ID_TCUR MKID_BE('tCUR') // Cursor
+#define ID_BITL MKID_BE('BITL') // ???
+#define ID_CTBL MKID_BE('CTBL') // Color Table?
+#define ID_SCRP MKID_BE('SCRP') // Script?
+#define ID_SPR  MKID_BE('SPR#') // Sprites?
+#define ID_VRSN MKID_BE('VRSN') // Version?
+#define ID_ANI  MKID_BE('ANI ') // Animation?
+#define ID_SHP  MKID_BE('SHP#') // ???
+
+// JamesMath Resource FourCC's
+#define ID_TANM MKID_BE('tANM') // Animation?
+#define ID_TMFO MKID_BE('tMFO') // ???
+
+// Mohawk Wave Tags
+#define ID_WAVE MKID_BE('WAVE') // Game Sound (Third Tag)
+#define ID_ADPC MKID_BE('ADPC') // Game Sound Chunk
+#define ID_DATA MKID_BE('Data') // Game Sound Chunk
+#define ID_CUE  MKID_BE('Cue#') // Game Sound Chunk
+
+// Mohawk MIDI Tags
+#define ID_MIDI MKID_BE('MIDI') // Game Sound (Third Tag), instead of WAVE
+#define ID_PRG  MKID_BE('Prg#') // Midi Program?
+
+// Old Mohawk Resource FourCC's
+#define ID_WAV  MKID_BE('WAV ') // Old Sound Resource
+#define ID_BMAP MKID_BE('BMAP') // Standard Mohawk Bitmap
+
+// Common Resource FourCC's
+#define ID_TBMP MKID_BE('tBMP') // Standard Mohawk Bitmap
+#define ID_TWAV MKID_BE('tWAV') // Standard Mohawk Sound
+#define ID_TPAL MKID_BE('tPAL') // Standard Mohawk Palette
+#define ID_TCNT MKID_BE('tCNT') // ??? (CSWorld, CSAmtrak, JamesMath)
+#define ID_TSCR MKID_BE('tSCR') // Script? Screen? (CSWorld, CSAmtrak, Treehouse)
+#define ID_STRL MKID_BE('STRL') // String List (Zoombini, CSWorld, CSAmtrak)
+#define ID_TBMH MKID_BE('tBMH') // Standard Mohawk Bitmap
+#define ID_TMID MKID_BE('tMID') // Standard Mohawk MIDI
+#define ID_REGS MKID_BE('REGS') // ??? (Zoombini, Treehouse)
+#define ID_BYTS MKID_BE('BYTS') // Database Entry (CSWorld, CSAmtrak)
+#define ID_INTS MKID_BE('INTS') // ??? (CSWorld, CSAmtrak)
+#define ID_BBOX MKID_BE('BBOX') // Boxes? (CSWorld, CSAmtrak)
+#define ID_SYSX MKID_BE('SYSX') // MIDI Sysex
+
+struct MohawkOutputStream {
+	Common::SeekableSubReadStream *stream;
+	uint32 tag;
+	uint32 id;
+	Common::String name;
+};
+
+struct FileTable {
+	uint32 offset;
+	uint32 dataSize; // Really 27 bits
+	byte flags; // Mostly useless except for the bottom 3 bits which are part of the size
+	uint16 unk; // Always 0
+};
+
+struct Type {
+	Type() { resTable.entries = NULL; nameTable.entries = NULL; }
+	~Type() { delete[] resTable.entries; delete[] nameTable.entries; }
+
+	//Type Table
+	uint32 tag;
+	uint16 resource_table_offset;
+	uint16 name_table_offset;
+		
+	struct ResourceTable {
+		uint16 resources;
+		struct Entries {
+			uint16 id;
+			uint16 index;
+		} *entries;
+	} resTable;
+		
+	struct NameTable {
+		uint16 num;
+		struct Entries {
+			uint16 offset;
+			uint16 index;
+			// Name List
+			Common::String name;
+		} *entries;
+	} nameTable;
+};
+
+struct TypeTable {
+	uint16 name_offset;
+	uint16 resource_types;
+};
+
+struct RSRC_Header {
+	uint32 size;
+	uint32 filesize;
+	uint32 abs_offset;
+	uint16 file_table_offset;
+	uint16 file_table_size;
+};
+
+class MohawkFile {
+public:
+	MohawkFile();
+	virtual ~MohawkFile() { close(); }
+	
+	virtual void open(Common::SeekableReadStream *stream);
+	void close();
+	
+	bool hasResource(uint32 tag, uint16 id);
+	virtual MohawkOutputStream getRawData(uint32 tag, uint16 id);
+	virtual MohawkOutputStream getNextFile();
+
+protected:
+	Common::SeekableReadStream *_mhk;
+	TypeTable _typeTable;
+	Common::String _curFile;
+	
+	// Extraction Variables
+	uint32 _curExType;
+	uint32 _curExTypeIndex;
+	
+	FileTable *_fileTable;
+	
+private:
+	bool _hasData;
+	uint32 _fileSize;
+	RSRC_Header _rsrc;
+	Type *_types;
+	uint16 _nameTableAmount;
+	uint16 _resourceTableAmount;
+	uint16 _fileTableAmount;
+
+	virtual int16 getTypeIndex(uint32 tag) {
+		for (uint16 i = 0; i < _typeTable.resource_types; i++)
+			if (_types[i].tag == tag)
+				return i;
+		return -1;	// not found
+	}
+
+	virtual int16 getIdIndex(int16 typeIndex, uint16 id) {
+		for (uint16 i = 0; i < _types[typeIndex].resTable.resources; i++)
+			if (_types[typeIndex].resTable.entries[i].id == id)
+				return i;
+		return -1;	// not found
+	}
+};
+
+class OldMohawkFile : public MohawkFile {
+public:
+	OldMohawkFile() : MohawkFile() {}
+	~OldMohawkFile() {}
+	
+	void open(Common::SeekableReadStream *stream);
+	MohawkOutputStream getRawData(uint32 tag, uint16 id);
+	MohawkOutputStream getNextFile();
+	
+private:
+	struct OldType {
+		uint32 tag;
+		uint16 resource_table_offset;
+		struct ResourceTable {
+			uint16 resources;
+			struct Entries {
+				uint16 id;
+				uint32 offset;
+				uint32 size;
+			} *entries;
+		} resTable;
+	} *_types;
+	
+	int16 getTypeIndex(uint32 tag) {
+		for (uint16 i = 0; i < _typeTable.resource_types; i++)
+			if (_types[i].tag == tag)
+				return i;
+		return -1;	// not found
+	}
+	
+	int16 getIdIndex(int16 typeIndex, uint16 id) {
+		for (uint16 i = 0; i < _types[typeIndex].resTable.resources; i++)
+			if (_types[typeIndex].resTable.entries[i].id == id)
+				return i;
+		return -1;	// not found
+	}
+};
+
+#endif


Property changes on: tools/trunk/engines/mohawk/mohawk_file.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list