aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorNorbert Lange2009-07-01 14:45:24 +0000
committerNorbert Lange2009-07-01 14:45:24 +0000
commitabef70f4e14f495b20097cb46411d1fafbafdd53 (patch)
tree27462f82f352b303ac059dd275466930c88b2de6 /common
parent3b94e2488df9a699a899727515ac69af6a0a1a6e (diff)
parentf9298ff40310149779b37ccdecc873afba7adf2f (diff)
downloadscummvm-rg350-abef70f4e14f495b20097cb46411d1fafbafdd53.tar.gz
scummvm-rg350-abef70f4e14f495b20097cb46411d1fafbafdd53.tar.bz2
scummvm-rg350-abef70f4e14f495b20097cb46411d1fafbafdd53.zip
Merging in changes from trunk
svn-id: r41989
Diffstat (limited to 'common')
-rw-r--r--common/debug.cpp26
-rw-r--r--common/debug.h23
-rw-r--r--common/hashmap.cpp7
-rw-r--r--common/hashmap.h150
-rw-r--r--common/iff_container.h198
-rw-r--r--common/system.h38
-rw-r--r--common/util.cpp1
-rw-r--r--common/util.h1
8 files changed, 310 insertions, 134 deletions
diff --git a/common/debug.cpp b/common/debug.cpp
index cc358596f7..ff17959cbf 100644
--- a/common/debug.cpp
+++ b/common/debug.cpp
@@ -227,6 +227,19 @@ void debugC(int level, uint32 debugChannels, const char *s, ...) {
va_end(va);
}
+void debugCN(int level, uint32 debugChannels, const char *s, ...) {
+ va_list va;
+
+ // Debug level 11 turns on all special debug level messages
+ if (gDebugLevel != 11)
+ if (level > gDebugLevel || !(Common::gDebugLevelsEnabled & debugChannels))
+ return;
+
+ va_start(va, s);
+ debugHelper(s, va, false);
+ va_end(va);
+}
+
void debugC(uint32 debugChannels, const char *s, ...) {
va_list va;
@@ -240,4 +253,17 @@ void debugC(uint32 debugChannels, const char *s, ...) {
va_end(va);
}
+void debugCN(uint32 debugChannels, const char *s, ...) {
+ va_list va;
+
+ // Debug level 11 turns on all special debug level messages
+ if (gDebugLevel != 11)
+ if (!(Common::gDebugLevelsEnabled & debugChannels))
+ return;
+
+ va_start(va, s);
+ debugHelper(s, va, false);
+ va_end(va);
+}
+
#endif
diff --git a/common/debug.h b/common/debug.h
index 43fe297859..95779af617 100644
--- a/common/debug.h
+++ b/common/debug.h
@@ -106,6 +106,8 @@ inline void debug(int level, const char *s, ...) {}
inline void debugN(int level, const char *s, ...) {}
inline void debugC(int level, uint32 engine_level, const char *s, ...) {}
inline void debugC(uint32 engine_level, const char *s, ...) {}
+inline void debugCN(int level, uint32 engine_level, const char *s, ...) {}
+inline void debugCN(uint32 engine_level, const char *s, ...) {}
#else
@@ -135,7 +137,7 @@ void debugN(int level, const char *s, ...) GCC_PRINTF(2, 3);
/**
* Print a debug message to the text console (stdout), but only if
- * the specified level does not exceed the value of gDebugLevel OR
+ * the specified level does not exceed the value of gDebugLevel AND
* if the specified special debug level is active.
* As a rule of thumb, the more important the message, the lower the level.
* Automatically appends a newline.
@@ -146,6 +148,17 @@ void debugC(int level, uint32 debugChannels, const char *s, ...) GCC_PRINTF(3, 4
/**
* Print a debug message to the text console (stdout), but only if
+ * the specified level does not exceed the value of gDebugLevel AND
+ * if the specified special debug level is active.
+ * As a rule of thumb, the more important the message, the lower the level.
+ * Does not append a newline automatically.
+ *
+ * @see enableDebugChannel
+ */
+void debugCN(int level, uint32 debugChannels, const char *s, ...) GCC_PRINTF(3, 4);
+
+/**
+ * Print a debug message to the text console (stdout), but only if
* the specified special debug level is active.
* Automatically appends a newline.
*
@@ -153,6 +166,14 @@ void debugC(int level, uint32 debugChannels, const char *s, ...) GCC_PRINTF(3, 4
*/
void debugC(uint32 debugChannels, const char *s, ...) GCC_PRINTF(2, 3);
+/**
+ * Print a debug message to the text console (stdout), but only if
+ * the specified special debug level is active.
+ * Does not append a newline automatically.
+ *
+ * @see enableDebugChannel
+ */
+void debugCN(uint32 debugChannels, const char *s, ...) GCC_PRINTF(2, 3);
#endif
diff --git a/common/hashmap.cpp b/common/hashmap.cpp
index 0fb03ec3f8..d8b84f61a5 100644
--- a/common/hashmap.cpp
+++ b/common/hashmap.cpp
@@ -58,6 +58,7 @@ uint hashit_lower(const char *p) {
#ifdef DEBUG_HASH_COLLISIONS
static double
g_collisions = 0,
+ g_dummyHits = 0,
g_lookups = 0,
g_collPerLook = 0,
g_capacity = 0,
@@ -66,9 +67,10 @@ static int g_max_capacity = 0, g_max_size = 0;
static int g_totalHashmaps = 0;
static int g_stats[4] = {0,0,0,0};
-void updateHashCollisionStats(int collisions, int lookups, int arrsize, int nele) {
+void updateHashCollisionStats(int collisions, int dummyHits, int lookups, int arrsize, int nele) {
g_collisions += collisions;
g_lookups += lookups;
+ g_dummyHits += dummyHits;
if (lookups)
g_collPerLook += (double)collisions / (double)lookups;
g_capacity += arrsize;
@@ -87,9 +89,10 @@ void updateHashCollisionStats(int collisions, int lookups, int arrsize, int nele
g_max_capacity = MAX(g_max_capacity, arrsize);
g_max_size = MAX(g_max_size, nele);
- fprintf(stdout, "%d hashmaps: colls %.1f; lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)\n",
+ fprintf(stdout, "%d hashmaps: colls %.1f; dummies hit %.1f, lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)\n",
g_totalHashmaps,
g_collisions / g_totalHashmaps,
+ g_dummyHits / g_totalHashmaps,
g_lookups / g_totalHashmaps,
100 * g_collPerLook / g_totalHashmaps,
g_size / g_totalHashmaps, g_max_size,
diff --git a/common/hashmap.h b/common/hashmap.h
index 16de7cdf54..fa613782cf 100644
--- a/common/hashmap.h
+++ b/common/hashmap.h
@@ -24,8 +24,7 @@
*/
// The hash map (associative array) implementation in this file is
-// based on the PyDict implementation of CPython. The erase() method
-// is based on example code in the Wikipedia article on Hash tables.
+// based on the PyDict implementation of CPython.
#ifndef COMMON_HASHMAP_H
#define COMMON_HASHMAP_H
@@ -72,7 +71,8 @@ public:
struct Node {
const Key _key;
Val _value;
- Node(const Key &key) : _key(key), _value() {}
+ explicit Node(const Key &key) : _key(key), _value() {}
+ Node() : _key(), _value() {}
};
enum {
@@ -98,12 +98,14 @@ public:
}
void freeNode(Node *node) {
- _nodePool.deleteChunk(node);
+ if (node && node != &_dummyNode)
+ _nodePool.deleteChunk(node);
}
Node **_storage; // hashtable of size arrsize.
uint _mask; /**< Capacity of the HashMap minus one; must be a power of two of minus one */
uint _size;
+ uint _deleted; ///< Number of deleted elements (_dummyNodes)
HashFunc _hash;
EqualFunc _equal;
@@ -111,8 +113,11 @@ public:
// Default value, returned by the const getVal.
const Val _defaultVal;
+ // Dummy node, used as marker for erased objects.
+ Node _dummyNode;
+
#ifdef DEBUG_HASH_COLLISIONS
- mutable int _collisions, _lookups;
+ mutable int _collisions, _lookups, _dummyHits;
#endif
void assign(const HM_t &map);
@@ -269,7 +274,7 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap()
#ifdef __PLAYSTATION2__
{
#else
- : _defaultVal() {
+ : _defaultVal(), _dummyNode() {
#endif
_mask = HASHMAP_MIN_CAPACITY - 1;
_storage = new Node *[HASHMAP_MIN_CAPACITY];
@@ -277,10 +282,12 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap()
memset(_storage, 0, HASHMAP_MIN_CAPACITY * sizeof(Node *));
_size = 0;
+ _deleted = 0;
#ifdef DEBUG_HASH_COLLISIONS
_collisions = 0;
_lookups = 0;
+ _dummyHits = 0;
#endif
}
@@ -291,7 +298,12 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap()
*/
template<class Key, class Val, class HashFunc, class EqualFunc>
HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
- _defaultVal() {
+ _defaultVal(), _dummyNode() {
+#ifdef DEBUG_HASH_COLLISIONS
+ _collisions = 0;
+ _lookups = 0;
+ _dummyHits = 0;
+#endif
assign(map);
}
@@ -301,13 +313,12 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
template<class Key, class Val, class HashFunc, class EqualFunc>
HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() {
for (uint ctr = 0; ctr <= _mask; ++ctr)
- if (_storage[ctr] != NULL)
- freeNode(_storage[ctr]);
+ freeNode(_storage[ctr]);
delete[] _storage;
#ifdef DEBUG_HASH_COLLISIONS
- extern void updateHashCollisionStats(int, int, int, int);
- updateHashCollisionStats(_collisions, _lookups, _mask+1, _size);
+ extern void updateHashCollisionStats(int, int, int, int, int);
+ updateHashCollisionStats(_collisions, _dummyHits, _lookups, _mask+1, _size);
#endif
}
@@ -327,8 +338,12 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
// Simply clone the map given to us, one by one.
_size = 0;
+ _deleted = 0;
for (uint ctr = 0; ctr <= _mask; ++ctr) {
- if (map._storage[ctr] != NULL) {
+ if (map._storage[ctr] == &map._dummyNode) {
+ _storage[ctr] = &_dummyNode;
+ _deleted++;
+ } else if (map._storage[ctr] != NULL) {
_storage[ctr] = allocNode(map._storage[ctr]->_key);
_storage[ctr]->_value = map._storage[ctr]->_value;
_size++;
@@ -336,16 +351,15 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
}
// Perform a sanity check (to help track down hashmap corruption)
assert(_size == map._size);
+ assert(_deleted == map._deleted);
}
template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) {
for (uint ctr = 0; ctr <= _mask; ++ctr) {
- if (_storage[ctr] != NULL) {
- freeNode(_storage[ctr]);
- _storage[ctr] = NULL;
- }
+ freeNode(_storage[ctr]);
+ _storage[ctr] = NULL;
}
#ifdef USE_HASHMAP_MEMORY_POOL
@@ -362,6 +376,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) {
}
_size = 0;
+ _deleted = 0;
}
template<class Key, class Val, class HashFunc, class EqualFunc>
@@ -374,6 +389,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
// allocate a new array
_size = 0;
+ _deleted = 0;
_mask = newCapacity - 1;
_storage = new Node *[newCapacity];
assert(_storage != NULL);
@@ -381,7 +397,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
// rehash all the old elements
for (uint ctr = 0; ctr <= old_mask; ++ctr) {
- if (old_storage[ctr] == NULL)
+ if (old_storage[ctr] == NULL || old_storage[ctr] == &_dummyNode)
continue;
// Insert the element from the old table into the new table.
@@ -390,7 +406,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
// don't have to call _equal().
const uint hash = _hash(old_storage[ctr]->_key);
uint idx = hash & _mask;
- for (uint perturb = hash; _storage[idx] != NULL; perturb >>= HASHMAP_PERTURB_SHIFT) {
+ for (uint perturb = hash; _storage[idx] != NULL && _storage[idx] != &_dummyNode; perturb >>= HASHMAP_PERTURB_SHIFT) {
idx = (5 * idx + perturb + 1) & _mask;
}
@@ -412,7 +428,13 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
const uint hash = _hash(key);
uint ctr = hash & _mask;
for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
- if (_storage[ctr] == NULL || _equal(_storage[ctr]->_key, key))
+ if (_storage[ctr] == NULL)
+ break;
+ if (_storage[ctr] == &_dummyNode) {
+#ifdef DEBUG_HASH_COLLISIONS
+ _dummyHits++;
+#endif
+ } else if (_equal(_storage[ctr]->_key, key))
break;
ctr = (5 * ctr + perturb + 1) & _mask;
@@ -424,8 +446,8 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
#ifdef DEBUG_HASH_COLLISIONS
_lookups++;
- fprintf(stderr, "collisions %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
- _collisions, _lookups, ((double) _collisions / (double)_lookups),
+ fprintf(stderr, "collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
+ _collisions, _dummyHits, _lookups, ((double) _collisions / (double)_lookups),
(const void *)this, _mask+1, _size);
#endif
@@ -434,16 +456,54 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
template<class Key, class Val, class HashFunc, class EqualFunc>
int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &key) {
- uint ctr = lookup(key);
+ const uint hash = _hash(key);
+ uint ctr = hash & _mask;
+ const uint NONE_FOUND = _mask + 1;
+ uint first_free = NONE_FOUND;
+ bool found = false;
+ for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
+ if (_storage[ctr] == NULL)
+ break;
+ if (_storage[ctr] == &_dummyNode) {
+#ifdef DEBUG_HASH_COLLISIONS
+ _dummyHits++;
+#endif
+ if (first_free != _mask + 1)
+ first_free = ctr;
+ } else if (_equal(_storage[ctr]->_key, key)) {
+ found = true;
+ break;
+ }
- if (_storage[ctr] == NULL) {
+ ctr = (5 * ctr + perturb + 1) & _mask;
+
+#ifdef DEBUG_HASH_COLLISIONS
+ _collisions++;
+#endif
+ }
+
+#ifdef DEBUG_HASH_COLLISIONS
+ _lookups++;
+ fprintf(stderr, "collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
+ _collisions, _dummyHits, _lookups, ((double) _collisions / (double)_lookups),
+ (const void *)this, _mask+1, _size);
+#endif
+
+ if (!found && first_free != _mask + 1)
+ ctr = first_free;
+
+ if (!found) {
+ if (_storage[ctr])
+ _deleted--;
_storage[ctr] = allocNode(key);
assert(_storage[ctr] != NULL);
_size++;
// Keep the load factor below a certain threshold.
+ // Deleted nodes are also counted
uint capacity = _mask + 1;
- if (_size * HASHMAP_LOADFACTOR_DENOMINATOR > capacity * HASHMAP_LOADFACTOR_NUMERATOR) {
+ if ((_size + _deleted) * HASHMAP_LOADFACTOR_DENOMINATOR >
+ capacity * HASHMAP_LOADFACTOR_NUMERATOR) {
capacity = capacity < 500 ? (capacity * 4) : (capacity * 2);
expandStorage(capacity);
ctr = lookup(key);
@@ -496,44 +556,16 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::setVal(const Key &key, const Val &v
template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) {
- // This is based on code in the Wikipedia article on Hash tables.
-
- const uint hash = _hash(key);
- uint i = hash & _mask;
- uint perturb;
-
- for (perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
- if (_storage[i] == NULL || _equal(_storage[i]->_key, key))
- break;
- i = (5 * i + perturb + 1) & _mask;
- }
+ uint ctr = lookup(key);
+ if (_storage[ctr] == NULL)
+ return;
- if (_storage[i] == NULL)
- return; // key wasn't present, so no work has to be done
-
- // If we remove a key, we must check all subsequent keys and possibly
- // reinsert them.
- uint j = i;
- freeNode(_storage[i]);
- _storage[i] = NULL;
- for (perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
- // Look at the next table slot
- j = (5 * j + perturb + 1) & _mask;
- // If the next slot is empty, we are done
- if (_storage[j] == NULL)
- break;
- // Compute the slot where the content of the next slot should normally be,
- // assuming an empty table, and check whether we have to move it.
- uint k = _hash(_storage[j]->_key) & _mask;
- if ((j > i && (k <= i || k > j)) ||
- (j < i && (k <= i && k > j)) ) {
- _storage[i] = _storage[j];
- i = j;
- }
- }
- _storage[i] = NULL;
+ // If we remove a key, we replace it with a dummy node.
+ freeNode(_storage[ctr]);
+ _storage[ctr] = &_dummyNode;
_size--;
+ _deleted++;
return;
}
diff --git a/common/iff_container.h b/common/iff_container.h
index 617bdde690..ebcf9ba803 100644
--- a/common/iff_container.h
+++ b/common/iff_container.h
@@ -27,6 +27,7 @@
#include "common/scummsys.h"
#include "common/endian.h"
+#include "common/func.h"
#include "common/stream.h"
#include "common/util.h"
@@ -145,90 +146,159 @@ page 376) */
char * ID2string(Common::IFF_ID id);
-class IFFChunk : public Common::ReadStream {
-
-protected:
- Common::ReadStream *_input;
- uint32 bytesRead;
-
-public:
- IFF_ID id;
- uint32 size;
-
- IFFChunk(Common::ReadStream *input): _input(input) {
- size = bytesRead = 0;
- }
-
- void incBytesRead(uint32 inc) {
- bytesRead += inc;
- if (bytesRead > size) {
- error("Chunk '%s' overread", ID2string(id));
- }
- }
+/**
+ * Represents a IFF chunk available to client code.
+ *
+ * Client code must *not* deallocate _stream when done.
+ */
+struct IFFChunk {
+ Common::IFF_ID _type;
+ uint32 _size;
+ Common::ReadStream *_stream;
- void readHeader() {
- id = _input->readUint32BE();
- size = _input->readUint32BE();
- bytesRead = 0;
+ IFFChunk(Common::IFF_ID type, uint32 size, Common::ReadStream *stream) : _type(type), _size(size), _stream(stream) {
+ assert(_stream);
}
+};
- bool hasReadAll() const {
- return (size - bytesRead) == 0;
- }
+/**
+ * Parser for IFF containers.
+ */
+class IFFParser {
- void feed() {
- if (size % 2) {
- size++;
+ /**
+ * This private class implements IFF chunk navigation.
+ */
+ class IFFChunkNav : public Common::ReadStream {
+ protected:
+ Common::ReadStream *_input;
+ uint32 _bytesRead;
+ public:
+ Common::IFF_ID id;
+ uint32 size;
+
+ IFFChunkNav() : _input(0) {
}
- while (!hasReadAll()) {
- readByte();
+ void setInputStream(Common::ReadStream *input) {
+ _input = input;
+ size = _bytesRead = 0;
}
- }
+ void incBytesRead(uint32 inc) {
+ _bytesRead += inc;
+ if (_bytesRead > size) {
+ error("Chunk overread");
+ }
+ }
+ void readHeader() {
+ id = _input->readUint32BE();
+ size = _input->readUint32BE();
+ _bytesRead = 0;
+ }
+ bool hasReadAll() const {
+ return (size - _bytesRead) == 0;
+ }
+ void feed() {
+ if (size % 2) {
+ size++;
+ }
+ while (!hasReadAll()) {
+ readByte();
+ }
+ }
+ // Common::ReadStream implementation
+ bool eos() const { return _input->eos(); }
+ bool err() const { return _input->err(); }
+ void clearErr() { _input->clearErr(); }
+
+ uint32 read(void *dataPtr, uint32 dataSize) {
+ incBytesRead(dataSize);
+ return _input->read(dataPtr, dataSize);
+ }
+ };
- // Common::ReadStream implementation
- bool eos() const { return _input->eos(); }
- bool err() const { return _input->err(); }
- void clearErr() { _input->clearErr(); }
+protected:
+ IFFChunkNav _formChunk; //!< The root chunk of the file.
+ IFFChunkNav _chunk; //!< The current chunk.
- uint32 read(void *dataPtr, uint32 dataSize) {
- incBytesRead(dataSize);
- return _input->read(dataPtr, dataSize);
- }
+ uint32 _formSize;
+ Common::IFF_ID _formType;
-};
+ Common::ReadStream *_stream;
+ bool _disposeStream;
+
+ void setInputStream(Common::ReadStream *stream) {
+ assert(stream);
+ _formChunk.setInputStream(stream);
+ _chunk.setInputStream(stream);
-class IFFParser {
-public:
- IFFParser(Common::ReadStream &input) : _formChunk(&input), _chunk(&input) {
_formChunk.readHeader();
if (_formChunk.id != ID_FORM) {
error("IFFParser input is not a FORM type IFF file");
}
- _typeId = _formChunk.readUint32BE();
+ _formSize = _formChunk.size;
+ _formType = _formChunk.readUint32BE();
}
- virtual ~IFFParser() {}
-
- IFFChunk *nextChunk() {
- _chunk.feed();
- _formChunk.incBytesRead(_chunk.size);
-
- if (_formChunk.hasReadAll())
- return 0;
-
- _formChunk.incBytesRead(8);
- _chunk.readHeader();
-
- return &_chunk;
+public:
+ IFFParser(Common::ReadStream *stream, bool disposeStream = false) : _stream(stream), _disposeStream(disposeStream) {
+ setInputStream(stream);
+ }
+ ~IFFParser() {
+ if (_disposeStream) {
+ delete _stream;
+ }
+ _stream = 0;
}
- IFF_ID _typeId;
-
-protected:
- IFFChunk _formChunk;
- IFFChunk _chunk;
+ /**
+ * Returns the IFF FORM type.
+ * @return the IFF FORM type of the stream, or 0 if FORM header is not found.
+ */
+ Common::IFF_ID getFORMType() const;
+
+ /**
+ * Returns the size of the data.
+ * @return the size of the data in file, or -1 if FORM header is not found.
+ */
+ uint32 getFORMSize() const;
+
+ /**
+ * Callback type for the parser.
+ */
+ typedef Common::Functor1< IFFChunk&, bool > IFFCallback;
+
+ /**
+ * Parse the IFF container, invoking the callback on each chunk encountered.
+ * The callback can interrupt the parsing by returning 'true'.
+ */
+ void parse(IFFCallback &callback) {
+ bool stop;
+ do {
+ _chunk.feed();
+ _formChunk.incBytesRead(_chunk.size);
+
+ if (_formChunk.hasReadAll()) {
+ break;
+ }
+
+ _formChunk.incBytesRead(8);
+ _chunk.readHeader();
+
+ // invoke the callback
+ Common::SubReadStream stream(&_chunk, _chunk.size);
+ IFFChunk chunk(_chunk.id, _chunk.size, &stream);
+ stop = callback(chunk);
+
+ // eats up all the remaining data in the chunk
+ while (!stream.eos()) {
+ stream.readByte();
+ }
+
+ } while (!stop);
+ }
};
+
} // namespace Common
#endif
diff --git a/common/system.h b/common/system.h
index 5b72dab7c1..5b3c208661 100644
--- a/common/system.h
+++ b/common/system.h
@@ -148,6 +148,10 @@ public:
* It is currently used only by some Macintosh versions of Humongous
* Entertainment games. If the backend doesn't implement this feature then
* the engine switches to b/w versions of cursors.
+ * The GUI also relies on this feature for mouse cursors.
+ *
+ * To enable the cursor palette call "disableCursorPalette" with false.
+ * @see disableCursorPalette
*/
kFeatureCursorHasPalette,
@@ -662,10 +666,25 @@ public:
- /** @name Mouse */
+ /** @name Mouse
+ * This is the lower level implementation as provided by the
+ * backends. The engines should use the Graphics::CursorManager
+ * class instead of using it directly.
+ */
//@{
- /** Show or hide the mouse cursor. */
+ /**
+ * Show or hide the mouse cursor.
+ *
+ * Currently the backend is not required to immediately draw the
+ * mouse cursor on showMouse(true).
+ *
+ * TODO: We might want to reconsider this fact,
+ * check Graphics::CursorManager::showMouse for some details about
+ * this.
+ *
+ * @see Graphics::CursorManager::showMouse
+ */
virtual bool showMouse(bool visible) = 0;
/**
@@ -830,6 +849,9 @@ public:
* @name Audio CD
* The methods in this group deal with Audio CD playback.
* The default implementation simply does nothing.
+ * This is the lower level implementation as provided by the
+ * backends. The engines should use the Audio::AudioCDManager
+ * class instead of using it directly.
*/
//@{
@@ -875,13 +897,11 @@ public:
/**
* Set a window caption or any other comparable status display to the
- * given value. The caption must be a pure ASCII string. Passing a
- * non-ASCII string may lead to unexpected behavior, even crashes.
+ * given value. The caption must be a pure ISO LATIN 1 string. Passing a
+ * string with a different encoding may lead to unexpected behavior,
+ * even crashes.
*
- * In a future revision of this API, this may be changed to allowing
- * UTF-8 or UTF-16 encoded data, or maybe ISO LATIN 1.
- *
- * @param caption the window caption to use, as an ASCII string
+ * @param caption the window caption to use, as an ISO LATIN 1 string
*/
virtual void setWindowCaption(const char *caption) {}
@@ -891,6 +911,8 @@ public:
* rectangle over the regular screen content; or in a message box beneath
* it; etc.).
*
+ * Currently, only pure ASCII messages can be expected to show correctly.
+ *
* @note There is a default implementation which uses a TimedMessageDialog
* to display the message. Hence implementing this is optional.
*
diff --git a/common/util.cpp b/common/util.cpp
index ff665468af..e99bbeb12d 100644
--- a/common/util.cpp
+++ b/common/util.cpp
@@ -211,6 +211,7 @@ const LanguageDescription g_languages[] = {
{"ru", "Russian", RU_RUS},
{"es", "Spanish", ES_ESP},
{"se", "Swedish", SE_SWE},
+ {"hu", "Hungarian", HU_HUN},
{0, 0, UNK_LANG}
};
diff --git a/common/util.h b/common/util.h
index ea4d280fbc..e50dcebff0 100644
--- a/common/util.h
+++ b/common/util.h
@@ -172,6 +172,7 @@ enum Language {
RU_RUS,
ES_ESP,
SE_SWE,
+ HU_HUN,
UNK_LANG = -1 // Use default language (i.e. none specified)
};