[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