diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/c++11-compat.h | 2 | ||||
-rw-r--r-- | common/ini-file.cpp | 4 | ||||
-rw-r--r-- | common/ini-file.h | 4 | ||||
-rw-r--r-- | common/language.cpp | 3 | ||||
-rw-r--r-- | common/language.h | 3 | ||||
-rw-r--r-- | common/module.mk | 1 | ||||
-rw-r--r-- | common/quicktime.cpp | 3 | ||||
-rw-r--r-- | common/recorderfile.cpp | 2 | ||||
-rw-r--r-- | common/scummsys.h | 6 | ||||
-rw-r--r-- | common/str.h | 7 | ||||
-rw-r--r-- | common/unarj.cpp | 11 | ||||
-rw-r--r-- | common/ustr.cpp | 329 | ||||
-rw-r--r-- | common/ustr.h | 194 | ||||
-rw-r--r-- | common/winexe_ne.cpp | 2 | ||||
-rw-r--r-- | common/winexe_ne.h | 2 | ||||
-rw-r--r-- | common/zlib.cpp | 22 |
16 files changed, 574 insertions, 21 deletions
diff --git a/common/c++11-compat.h b/common/c++11-compat.h index 50d79bd79e..f963ba9ac8 100644 --- a/common/c++11-compat.h +++ b/common/c++11-compat.h @@ -31,7 +31,9 @@ // Custom nullptr replacement. This is not type safe as the real C++11 nullptr // though. // +#if !defined(nullptr) // XCode 5.0.1 has __cplusplus=199711 but defines this #define nullptr 0 +#endif // // Replacement for the override keyword. This allows compilation of code diff --git a/common/ini-file.cpp b/common/ini-file.cpp index be5247dcfb..9de0b38e93 100644 --- a/common/ini-file.cpp +++ b/common/ini-file.cpp @@ -53,7 +53,7 @@ bool INIFile::loadFromFile(const String &filename) { return false; } -bool INIFile::loadFromSaveFile(const char *filename) { +bool INIFile::loadFromSaveFile(const String &filename) { assert(g_system); SaveFileManager *saveFileMan = g_system->getSavefileManager(); SeekableReadStream *loadFile; @@ -181,7 +181,7 @@ bool INIFile::saveToFile(const String &filename) { return false; } -bool INIFile::saveToSaveFile(const char *filename) { +bool INIFile::saveToSaveFile(const String &filename) { assert(g_system); SaveFileManager *saveFileMan = g_system->getSavefileManager(); WriteStream *saveFile; diff --git a/common/ini-file.h b/common/ini-file.h index 1d94ce7bdc..a1505fe468 100644 --- a/common/ini-file.h +++ b/common/ini-file.h @@ -94,10 +94,10 @@ public: void clear(); bool loadFromFile(const String &filename); - bool loadFromSaveFile(const char *filename); + bool loadFromSaveFile(const String &filename); bool loadFromStream(SeekableReadStream &stream); bool saveToFile(const String &filename); - bool saveToSaveFile(const char *filename); + bool saveToSaveFile(const String &filename); bool saveToStream(WriteStream &stream); bool hasSection(const String §ion) const; diff --git a/common/language.cpp b/common/language.cpp index 898adf8d0e..6704a52373 100644 --- a/common/language.cpp +++ b/common/language.cpp @@ -28,6 +28,7 @@ namespace Common { const LanguageDescription g_languages[] = { { "zh-cn", "zh_CN", "Chinese (China)", ZH_CNA }, { "zh", "zh_TW", "Chinese (Taiwan)", ZH_TWN }, + { "hr", "hr_HR", "Croatian", HR_HRV }, { "cz", "cs_CZ", "Czech", CZ_CZE }, { "nl", "nl_NL", "Dutch", NL_NLD }, { "en", "en", "English", EN_ANY }, // Generic English (when only one game version exist) @@ -38,11 +39,11 @@ const LanguageDescription g_languages[] = { { "gr", "el_GR", "Greek", GR_GRE }, { "he", "he_IL", "Hebrew", HE_ISR }, { "hb", "he_IL", "Hebrew", HE_ISR }, // Deprecated - { "hr", "hr_HR", "Croatian", HR_HRV }, { "hu", "hu_HU", "Hungarian", HU_HUN }, { "it", "it_IT", "Italian", IT_ITA }, { "jp", "ja_JP", "Japanese", JA_JPN }, { "kr", "ko_KR", "Korean", KO_KOR }, + { "lv", "lv_LV", "Latvian", LV_LAT }, { "nb", "nb_NO", "Norwegian Bokm\xE5l", NB_NOR }, // TODO Someone should verify the unix locale { "pl", "pl_PL", "Polish", PL_POL }, { "br", "pt_BR", "Portuguese", PT_BRA }, diff --git a/common/language.h b/common/language.h index 03b9ebaf8e..f18815509b 100644 --- a/common/language.h +++ b/common/language.h @@ -34,6 +34,7 @@ class String; enum Language { ZH_CNA, ZH_TWN, + HR_HRV, CZ_CZE, NL_NLD, EN_ANY, // Generic English (when only one game version exist) @@ -43,11 +44,11 @@ enum Language { DE_DEU, GR_GRE, HE_ISR, - HR_HRV, HU_HUN, IT_ITA, JA_JPN, KO_KOR, + LV_LAT, NB_NOR, PL_POL, PT_BRA, diff --git a/common/module.mk b/common/module.mk index 1b34d151d0..67c498df00 100644 --- a/common/module.mk +++ b/common/module.mk @@ -35,6 +35,7 @@ MODULE_OBJS := \ translation.o \ unarj.o \ unzip.o \ + ustr.o \ util.o \ winexe.o \ winexe_ne.o \ diff --git a/common/quicktime.cpp b/common/quicktime.cpp index a3efc2b443..6ab5a42b89 100644 --- a/common/quicktime.cpp +++ b/common/quicktime.cpp @@ -368,9 +368,6 @@ int QuickTimeParser::readMVHD(Atom atom) { int QuickTimeParser::readTRAK(Atom atom) { Track *track = new Track(); - if (!track) - return -1; - track->codecType = CODEC_TYPE_MOV_OTHER; track->startTime = 0; // XXX: check _tracks.push_back(track); diff --git a/common/recorderfile.cpp b/common/recorderfile.cpp index d08bc599f1..7c438cbf69 100644 --- a/common/recorderfile.cpp +++ b/common/recorderfile.cpp @@ -45,6 +45,8 @@ PlaybackFile::PlaybackFile() : _tmpRecordFile(_tmpBuffer, kRecordBuffSize), _tmp _recordCount = 0; _eventsSize = 0; memset(_tmpBuffer, 1, kRecordBuffSize); + + _playbackParseState = kFileStateCheckFormat; } PlaybackFile::~PlaybackFile() { diff --git a/common/scummsys.h b/common/scummsys.h index 3e9d5ef063..48dffc53a6 100644 --- a/common/scummsys.h +++ b/common/scummsys.h @@ -23,6 +23,10 @@ #ifndef COMMON_SCUMMSYS_H #define COMMON_SCUMMSYS_H +#ifndef __has_feature // Optional of course. + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + // This is a convenience macro to test whether the compiler used is a GCC // version, which is at least major.minor. #define GCC_ATLEAST(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))) @@ -401,6 +405,8 @@ typedef unsigned int uint32; typedef signed int int32; typedef unsigned int uint; + typedef signed long long int64; + typedef unsigned long long uint64; #endif diff --git a/common/str.h b/common/str.h index 6b4475e1c4..ea2db1d1d6 100644 --- a/common/str.h +++ b/common/str.h @@ -234,6 +234,13 @@ public: static String vformat(const char *fmt, va_list args); public: + typedef char value_type; + /** + * Unsigned version of the underlying type. This can be used to cast + * individual string characters to bigger integer types without sign + * extension happening. + */ + typedef unsigned char unsigned_type; typedef char * iterator; typedef const char * const_iterator; diff --git a/common/unarj.cpp b/common/unarj.cpp index fe3c17a2ac..e8aed7cbd1 100644 --- a/common/unarj.cpp +++ b/common/unarj.cpp @@ -95,6 +95,12 @@ class ArjDecoder { public: ArjDecoder(const ArjHeader *hdr) { _compsize = hdr->compSize; + _compressed = 0; + _outstream = 0; + _bitbuf = 0; + _bytebuf = 0; + _bitcount = 0; + _blocksize = 0; } ~ArjDecoder() { @@ -112,7 +118,6 @@ public: uint16 _bitbuf; uint16 _bytebuf; int32 _compsize; - byte _subbitbuf; int _bitcount; void init_getbits(); @@ -132,9 +137,6 @@ public: private: byte _ntext[ARJ_FDICSIZ]; - int16 _getlen; - int16 _getbuf; - uint16 _left[2 * ARJ_NC - 1]; uint16 _right[2 * ARJ_NC - 1]; byte _c_len[ARJ_NC]; @@ -656,7 +658,6 @@ void ArjDecoder::decode_f(int32 origsize) { init_getbits(); ncount = 0; - _getlen = _getbuf = 0; r = 0; while (ncount < (uint32)origsize) { diff --git a/common/ustr.cpp b/common/ustr.cpp new file mode 100644 index 0000000000..fbc831cb56 --- /dev/null +++ b/common/ustr.cpp @@ -0,0 +1,329 @@ +/* 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. + */ + +#include "common/ustr.h" +#include "common/memorypool.h" +#include "common/util.h" + +namespace Common { + +extern MemoryPool *g_refCountPool; + +static uint32 computeCapacity(uint32 len) { + // By default, for the capacity we use the next multiple of 32 + return ((len + 32 - 1) & ~0x1F); +} + +U32String::U32String(const value_type *str) : _size(0), _str(_storage) { + if (str == 0) { + _storage[0] = 0; + _size = 0; + } else { + uint32 len = 0; + const value_type *s = str; + while (*s++) { + ++len; + } + initWithCStr(str, len); + } +} + +U32String::U32String(const value_type *str, uint32 len) : _size(0), _str(_storage) { + initWithCStr(str, len); +} + +U32String::U32String(const value_type *beginP, const value_type *endP) : _size(0), _str(_storage) { + assert(endP >= beginP); + initWithCStr(beginP, endP - beginP); +} + +U32String::U32String(const U32String &str) + : _size(str._size) { + if (str.isStorageIntern()) { + // String in internal storage: just copy it + memcpy(_storage, str._storage, _builtinCapacity * sizeof(value_type)); + _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); +} + +U32String::~U32String() { + decRefCount(_extern._refCount); +} + +U32String &U32String::operator=(const U32String &str) { + if (&str == this) + return *this; + + if (str.isStorageIntern()) { + decRefCount(_extern._refCount); + _size = str._size; + _str = _storage; + memcpy(_str, str._str, (_size + 1) * sizeof(value_type)); + } else { + str.incRefCount(); + decRefCount(_extern._refCount); + + _extern._refCount = str._extern._refCount; + _extern._capacity = str._extern._capacity; + _size = str._size; + _str = str._str; + } + + return *this; +} + +U32String &U32String::operator+=(const U32String &str) { + if (&str == this) { + return operator+=(U32String(str)); + } + + int len = str._size; + if (len > 0) { + ensureCapacity(_size + len, true); + + memcpy(_str + _size, str._str, (len + 1) * sizeof(value_type)); + _size += len; + } + return *this; +} + +U32String &U32String::operator+=(value_type c) { + ensureCapacity(_size + 1, true); + + _str[_size++] = c; + _str[_size] = 0; + + return *this; +} + +bool U32String::equals(const U32String &x) const { + if (this == &x || _str == x._str) { + return true; + } + + if (x.size() != _size) { + return false; + } + + return !memcmp(_str, x._str, _size * sizeof(value_type)); +} + +bool U32String::contains(value_type x) const { + for (uint32 i = 0; i < _size; ++i) { + if (_str[i] == x) { + return true; + } + } + + return false; +} + +void U32String::deleteChar(uint32 p) { + assert(p < _size); + + makeUnique(); + while (p++ < _size) + _str[p - 1] = _str[p]; + _size--; +} + +void U32String::clear() { + decRefCount(_extern._refCount); + + _size = 0; + _str = _storage; + _storage[0] = 0; +} + +void U32String::toLowercase() { + makeUnique(); + for (uint32 i = 0; i < _size; ++i) { + if (_str[i] < 128) { + _str[i] = tolower(_str[i]); + } + } +} + +void U32String::toUppercase() { + makeUnique(); + for (uint32 i = 0; i < _size; ++i) { + if (_str[i] < 128) { + _str[i] = toupper(_str[i]); + } + } +} + +uint32 U32String::find(const U32String &str, uint32 pos) const { + if (pos >= _size) { + return npos; + } + + const value_type *strP = str.c_str(); + + for (const_iterator cur = begin() + pos; *cur; ++cur) { + uint i = 0; + while (true) { + if (!strP[i]) { + return cur - begin(); + } + + if (cur[i] != strP[i]) { + break; + } + + ++i; + } + } + + return npos; +} + +void U32String::makeUnique() { + ensureCapacity(_size, true); +} + +void U32String::ensureCapacity(uint32 new_size, bool keep_old) { + bool isShared; + uint32 curCapacity, newCapacity; + value_type *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 + // If the current capacity is sufficient we use the same capacity + if (new_size < curCapacity) + newCapacity = curCapacity; + else + newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1)); + + // Allocate new storage + newStorage = new value_type[newCapacity]; + assert(newStorage); + } + + // Copy old data if needed, elsewise reset the new storage. + if (keep_old) { + assert(_size < newCapacity); + memcpy(newStorage, _str, (_size + 1) * sizeof(value_type)); + } 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 U32String::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 U32String::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. + } +} + +void U32String::initWithCStr(const value_type *str, uint32 len) { + assert(str); + + _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 value_type[_extern._capacity]; + assert(_str != 0); + } + + // Copy the string into the storage area + memmove(_str, str, len * sizeof(value_type)); + _str[len] = 0; +} + +} // End of namespace Common diff --git a/common/ustr.h b/common/ustr.h new file mode 100644 index 0000000000..ab9dac70de --- /dev/null +++ b/common/ustr.h @@ -0,0 +1,194 @@ +/* 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. + */ + +#ifndef COMMON_USTR_H +#define COMMON_USTR_H + +#include "common/scummsys.h" + +namespace Common { + +/** + * Very simple string class for UTF-32 strings in ScummVM. The main intention + * behind this class is to feature a simple way of displaying UTF-32 strings + * through the Graphics::Font API. + * + * Please note that operations like equals, deleteCharacter, toUppercase, etc. + * are only very simplified convenience operations. They might not fully work + * as you would expect for a proper UTF-32 string class. + * + * The presence of \0 characters in the string will cause undefined + * behavior in some operations. + */ +class U32String { +public: + static const uint32 npos = 0xFFFFFFFF; + + typedef uint32 value_type; + typedef uint32 unsigned_type; +private: + /** + * 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. + */ + static const uint32 _builtinCapacity = 32; + + /** + * Length of the string. + */ + uint32 _size; + + /** + * Pointer to the actual string storage. Either points to _storage, + * or to a block allocated on the heap via malloc. + */ + value_type *_str; + + + union { + /** + * Internal string storage. + */ + value_type _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: + /** Construct a new empty string. */ + U32String() : _size(0), _str(_storage) { _storage[0] = 0; } + + /** Construct a new string from the given NULL-terminated C string. */ + explicit U32String(const value_type *str); + + /** Construct a new string containing exactly len characters read from address str. */ + U32String(const value_type *str, uint32 len); + + /** Construct a new string containing the characters between beginP (including) and endP (excluding). */ + U32String(const value_type *beginP, const value_type *endP); + + /** Construct a copy of the given string. */ + U32String(const U32String &str); + + ~U32String(); + + U32String &operator=(const U32String &str); + U32String &operator+=(const U32String &str); + U32String &operator+=(value_type c); + + /** + * Equivalence comparison operator. + * @see equals + */ + bool operator==(const U32String &x) const { return equals(x); } + + /** + * Compares whether two U32String are the same based on memory comparison. + * This does *not* do comparison based on canonical equivalence. + */ + bool equals(const U32String &x) const; + + bool contains(value_type x) const; + + inline const value_type *c_str() const { return _str; } + inline uint32 size() const { return _size; } + + inline bool empty() const { return (_size == 0); } + + value_type operator[](int idx) const { + assert(_str && idx >= 0 && idx < (int)_size); + return _str[idx]; + } + + /** + * Removes the value at position p from the string. + * Using this on decomposed characters will not remove the whole + * character! + */ + void deleteChar(uint32 p); + + /** Clears the string, making it empty. */ + void clear(); + + /** + * Convert all characters in the string to lowercase. + * + * Be aware that this only affects the case of ASCII characters. All + * other characters will not be touched at all. + */ + void toLowercase(); + + /** + * Convert all characters in the string to uppercase. + * + * Be aware that this only affects the case of ASCII characters. All + * other characters will not be touched at all. + */ + void toUppercase(); + + uint32 find(const U32String &str, uint32 pos = 0) const; + + typedef value_type * iterator; + typedef const value_type * const_iterator; + + iterator begin() { + // Since the user could potentially + // change the string via the returned + // iterator we have to assure we are + // pointing to a unique storage. + makeUnique(); + + return _str; + } + + iterator end() { + return begin() + size(); + } + + const_iterator begin() const { + return _str; + } + + const_iterator end() const { + return begin() + size(); + } +private: + void makeUnique(); + void ensureCapacity(uint32 new_size, bool keep_old); + void incRefCount() const; + void decRefCount(int *oldRefCount); + void initWithCStr(const value_type *str, uint32 len); +}; + +} // End of namespace Common + +#endif diff --git a/common/winexe_ne.cpp b/common/winexe_ne.cpp index c3698d5fce..8ab7e707bb 100644 --- a/common/winexe_ne.cpp +++ b/common/winexe_ne.cpp @@ -187,7 +187,7 @@ uint32 NEResources::getResourceTableOffset() { static const char *s_resTypeNames[] = { "", "cursor", "bitmap", "icon", "menu", "dialog", "string", "font_dir", "font", "accelerator", "rc_data", "msg_table", - "group_cursor", "group_icon", "", "", "version", "dlg_include", + "group_cursor", "", "group_icon", "", "version", "dlg_include", "", "plug_play", "vxd", "ani_cursor", "ani_icon", "html", "manifest" }; diff --git a/common/winexe_ne.h b/common/winexe_ne.h index f00941412f..3f50b5cc54 100644 --- a/common/winexe_ne.h +++ b/common/winexe_ne.h @@ -46,7 +46,7 @@ enum NEResourceType { kNERCData = 0x0A, kNEMessageTable = 0x0B, kNEGroupCursor = 0x0C, - kNEGroupIcon = 0x0D, + kNEGroupIcon = 0x0E, kNEVersion = 0x10, kNEDlgInclude = 0x11, kNEPlugPlay = 0x13, diff --git a/common/zlib.cpp b/common/zlib.cpp index 920338e57e..f1a298a9f1 100644 --- a/common/zlib.cpp +++ b/common/zlib.cpp @@ -27,6 +27,7 @@ #include "common/ptr.h" #include "common/util.h" #include "common/stream.h" +#include "common/textconsole.h" #if defined(USE_ZLIB) #ifdef __SYMBIAN32__ @@ -158,10 +159,11 @@ protected: uint32 _pos; uint32 _origSize; bool _eos; + bool _shownBackwardSeekingWarning; public: - GZipReadStream(SeekableReadStream *w, uint32 knownSize = 0) : _wrapped(w), _stream() { + GZipReadStream(SeekableReadStream *w, uint32 knownSize = 0) : _wrapped(w), _stream(), _shownBackwardSeekingWarning(false) { assert(w != 0); // Verify file header is correct @@ -241,13 +243,17 @@ public: } bool seek(int32 offset, int whence = SEEK_SET) { int32 newPos = 0; - assert(whence != SEEK_END); // SEEK_END not supported switch (whence) { case SEEK_SET: newPos = offset; break; case SEEK_CUR: newPos = _pos + offset; + break; + case SEEK_END: + // NOTE: This can be an expensive operation (see below). + newPos = size() + offset; + break; } assert(newPos >= 0); @@ -256,9 +262,15 @@ public: // To search backward, we have to restart the whole decompression // from the start of the file. A rather wasteful operation, best // to avoid it. :/ -#if DEBUG - warning("Backward seeking in GZipReadStream detected"); -#endif + + if (!_shownBackwardSeekingWarning) { + // We only throw this warning once per stream, to avoid + // getting the console swarmed with warnings when consecutive + // seeks are made. + warning("Backward seeking in GZipReadStream detected"); + _shownBackwardSeekingWarning = true; + } + _pos = 0; _wrapped->seek(0, SEEK_SET); _zlibErr = inflateReset(&_stream); |