[Scummvm-git-logs] scummvm master -> 29cfa7bb0f2c1c76a9ef285b8e5799a7ec91020b
sev-
sev at scummvm.org
Sat Oct 31 13:05:34 UTC 2020
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
29cfa7bb0f COMMON: Merge code for str.cpp and ustr.cpp
Commit: 29cfa7bb0f2c1c76a9ef285b8e5799a7ec91020b
https://github.com/scummvm/scummvm/commit/29cfa7bb0f2c1c76a9ef285b8e5799a7ec91020b
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-10-31T14:05:30+01:00
Commit Message:
COMMON: Merge code for str.cpp and ustr.cpp
Most of the code in str.cpp and ustr.cpp is actually the same. Do some
template magic to merge them.
Changed paths:
A common/base-str.cpp
A common/base-str.h
A devtools/create_titanic/base-str.cpp
A devtools/create_xeen/base-str.cpp
R devtools/create_titanic/str.h
audio/musicplugin.cpp
common/hash-str.h
common/module.mk
common/serializer.h
common/str.cpp
common/str.h
common/ustr.cpp
common/ustr.h
common/winexe.h
devtools/create_titanic/hash-str.h
devtools/create_titanic/module.mk
devtools/create_titanic/str.cpp
devtools/create_titanic/winexe.cpp
devtools/create_titanic/winexe.h
devtools/create_titanic/winexe_pe.cpp
devtools/create_titanic/winexe_pe.h
devtools/create_xeen/module.mk
devtools/create_xeen/str.cpp
engines/glk/adrift/os_glk.cpp
engines/glk/advsys/glk_interface.cpp
engines/glk/comprehend/comprehend.cpp
engines/glk/glk_api.cpp
engines/glk/scott/scott.cpp
engines/glk/window_text_buffer.cpp
engines/glk/zcode/zcode.cpp
gui/widgets/popup.cpp
diff --git a/audio/musicplugin.cpp b/audio/musicplugin.cpp
index 56f73fd57e..50d6d1af1c 100644
--- a/audio/musicplugin.cpp
+++ b/audio/musicplugin.cpp
@@ -57,5 +57,5 @@ Common::String MusicDevice::getCompleteId() {
}
MidiDriver::DeviceHandle MusicDevice::getHandle() {
- return (MidiDriver::DeviceHandle)Common::hashit(getCompleteId());
+ return (MidiDriver::DeviceHandle)getCompleteId().hash();
}
diff --git a/common/base-str.cpp b/common/base-str.cpp
new file mode 100644
index 0000000000..9a2fb7ffd2
--- /dev/null
+++ b/common/base-str.cpp
@@ -0,0 +1,803 @@
+/* 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/base-str.h"
+#include "common/hash-str.h"
+#include "common/list.h"
+#include "common/memorypool.h"
+#include "common/util.h"
+#include "common/mutex.h"
+
+namespace Common {
+
+#define TEMPLATE template<class T>
+#define BASESTRING BaseString<T>
+
+MemoryPool *g_refCountPool = nullptr; // FIXME: This is never freed right now
+#ifndef SCUMMVM_UTIL
+Mutex *g_refCountPoolMutex = nullptr;
+
+void lockMemoryPoolMutex() {
+ // The Mutex class can only be used once g_system is set and initialized,
+ // but we may use the String class earlier than that (it is for example
+ // used in the OSystem_POSIX constructor). However in those early stages
+ // we can hope we don't have multiple threads either.
+ if (!g_system || !g_system->backendInitialized())
+ return;
+ if (!g_refCountPoolMutex)
+ g_refCountPoolMutex = new Mutex();
+ g_refCountPoolMutex->lock();
+}
+
+void unlockMemoryPoolMutex() {
+ if (g_refCountPoolMutex)
+ g_refCountPoolMutex->unlock();
+}
+
+TEMPLATE void BASESTRING::releaseMemoryPoolMutex() {
+ if (g_refCountPoolMutex){
+ delete g_refCountPoolMutex;
+ g_refCountPoolMutex = nullptr;
+ }
+}
+
+#endif
+
+static uint32 computeCapacity(uint32 len) {
+ // By default, for the capacity we use the next multiple of 32
+ return ((len + 32 - 1) & ~0x1F);
+}
+
+TEMPLATE
+BASESTRING::BaseString(const BASESTRING &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 != nullptr);
+}
+
+TEMPLATE BASESTRING::BaseString(const value_type *str) : _size(0), _str(_storage) {
+ if (str == nullptr) {
+ _storage[0] = 0;
+ _size = 0;
+ } else {
+ uint32 len = 0;
+ const value_type *s = str;
+ while (*s++) {
+ ++len;
+ }
+ initWithValueTypeStr(str, len);
+ }
+}
+
+TEMPLATE BASESTRING::BaseString(const value_type *str, uint32 len) : _size(0), _str(_storage) {
+ initWithValueTypeStr(str, len);
+}
+
+TEMPLATE BASESTRING::BaseString(const value_type *beginP, const value_type *endP) : _size(0), _str(_storage) {
+ assert(endP >= beginP);
+ initWithValueTypeStr(beginP, endP - beginP);
+}
+
+TEMPLATE void BASESTRING::makeUnique() {
+ ensureCapacity(_size, true);
+}
+
+TEMPLATE void BASESTRING::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 = nullptr;
+ _extern._capacity = newCapacity;
+ }
+}
+
+TEMPLATE
+void BASESTRING::incRefCount() const {
+ assert(!isStorageIntern());
+ if (_extern._refCount == nullptr) {
+ if (g_refCountPool == nullptr) {
+ g_refCountPool = new MemoryPool(sizeof(int));
+ assert(g_refCountPool);
+ }
+
+ _extern._refCount = (int *)g_refCountPool->allocChunk();
+ *_extern._refCount = 2;
+ } else {
+ ++(*_extern._refCount);
+ }
+}
+
+TEMPLATE
+void BASESTRING::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);
+ }
+ // Coverity thinks that we always free memory, as it assumes
+ // (correctly) that there are cases when oldRefCount == 0
+ // Thus, DO NOT COMPILE, trick it and shut tons of false positives
+#ifndef __COVERITY__
+ delete[] _str;
+#endif
+
+ // 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.
+ }
+}
+
+TEMPLATE void BASESTRING::initWithValueTypeStr(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 = nullptr;
+ _str = new value_type[_extern._capacity];
+ assert(_str != nullptr);
+ }
+
+ // Copy the string into the storage area
+ memmove(_str, str, len * sizeof(value_type));
+ _str[len] = 0;
+}
+
+TEMPLATE void BASESTRING::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 = nullptr;
+ _str = new value_type[_extern._capacity];
+ assert(_str != nullptr);
+ }
+
+ // Copy the string into the storage area
+ for (size_t idx = 0; idx < len; ++idx, ++str)
+ _str[idx] = (byte)(*str);
+
+ _str[len] = 0;
+}
+
+TEMPLATE bool BASESTRING::equals(const BaseString &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));
+}
+
+TEMPLATE bool BASESTRING::equals(const value_type *ptr) const {
+ if (_str == ptr) {
+ return true;
+ }
+
+ uint i = 0;
+
+ for (; i < _size && *ptr; i++, ptr++) {
+ if (_str[i] != *ptr)
+ return false;
+ }
+
+ if (i == _size && *ptr == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+TEMPLATE bool BASESTRING::equalsC(const char *ptr) const {
+ uint i = 0;
+
+ for (; i < _size && *ptr; i++, ptr++) {
+ if (_str[i] != *ptr)
+ return false;
+ }
+
+ if (i == _size && *ptr == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+TEMPLATE bool BASESTRING::operator==(const BaseString &x) const {
+ return equals(x);
+}
+
+TEMPLATE bool BASESTRING::operator==(const value_type *x) const {
+ return equals(BaseString(x));
+}
+
+TEMPLATE bool BASESTRING::operator!=(const BaseString &x) const {
+ return !equals(x);
+}
+
+TEMPLATE bool BASESTRING::operator!=(const value_type *x) const {
+ return !equals(BaseString(x));
+}
+
+TEMPLATE int BASESTRING::compareTo(const BaseString &x) const {
+ for (uint32 i = 0, n = x.size(); i < _size && i < n; ++i) {
+ uint32 sc = _str[i];
+ uint32 xc = x[i];
+ if (sc < xc)
+ return -1;
+ else if (sc > xc)
+ return +1;
+ }
+ if (_size < x.size())
+ return -1;
+ if (_size == x.size())
+ return 0;
+ return +1;
+}
+
+TEMPLATE int BASESTRING::compareTo(const value_type *ptr) const {
+ uint32 i = 0;
+ for (; i < _size && *ptr; ++i, ptr++) {
+ uint32 sc = _str[i];
+ uint32 xc = *ptr;
+ if (sc < xc)
+ return -1;
+ else if (sc > xc)
+ return +1;
+ }
+ if (i == _size && *ptr == 0)
+ return 0;
+ if (*ptr == 0)
+ return +1;
+ return -1;
+}
+
+TEMPLATE int BASESTRING::compareToC(const char *ptr) const {
+ uint32 i = 0;
+ for (; i < _size && *ptr; ++i, ptr++) {
+ uint32 sc = _str[i];
+ uint32 xc = *ptr;
+ if (sc < xc)
+ return -1;
+ else if (sc > xc)
+ return +1;
+ }
+ if (i == _size && *ptr == 0)
+ return 0;
+ if (*ptr == 0)
+ return +1;
+ return -1;
+}
+
+TEMPLATE bool BASESTRING::operator<(const BaseString &x) const {
+ return compareTo(x) < 0;
+}
+
+TEMPLATE bool BASESTRING::operator<=(const BaseString &x) const {
+ return compareTo(x) <= 0;
+}
+
+TEMPLATE bool BASESTRING::operator>(const BaseString &x) const {
+ return compareTo(x) > 0;
+}
+
+TEMPLATE bool BASESTRING::operator>=(const BaseString &x) const {
+ return compareTo(x) >= 0;
+}
+
+TEMPLATE bool BASESTRING::operator<(const value_type *x) const {
+ return compareTo(x) < 0;
+}
+
+TEMPLATE bool BASESTRING::operator<=(const value_type *x) const {
+ return compareTo(x) <= 0;
+}
+
+TEMPLATE bool BASESTRING::operator>(const value_type *x) const {
+ return compareTo(x) > 0;
+}
+
+TEMPLATE bool BASESTRING::operator>=(const value_type *x) const {
+ return compareTo(x) >= 0;
+}
+
+TEMPLATE bool BASESTRING::contains(value_type x) const {
+ for (uint32 i = 0; i < _size; ++i) {
+ if (_str[i] == x) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+TEMPLATE bool BASESTRING::contains(const BaseString &otherString) const {
+ if (empty() || otherString.empty() || _size < otherString.size()) {
+ return false;
+ }
+
+ uint32 size = 0;
+ BaseString::const_iterator itr = otherString.begin();
+
+ for (BaseString::const_iterator itr2 = begin(); itr != otherString.end() && itr2 != end(); itr2++) {
+ if (*itr == *itr2) {
+ itr++;
+ size++;
+ if (size == otherString.size())
+ return true;
+ } else {
+ size = 0;
+ itr = otherString.begin();
+ }
+ }
+
+ return false;
+}
+
+TEMPLATE void BASESTRING::insertChar(value_type 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;
+}
+
+TEMPLATE void BASESTRING::deleteChar(uint32 p) {
+ assert(p < _size);
+
+ makeUnique();
+ while (p++ < _size)
+ _str[p - 1] = _str[p];
+ _size--;
+}
+
+TEMPLATE void BASESTRING::deleteLastChar() {
+ if (_size > 0)
+ deleteChar(_size - 1);
+}
+
+TEMPLATE void BASESTRING::erase(uint32 p, uint32 len) {
+ assert(p < _size);
+
+ makeUnique();
+ // If len == npos or p + len is over the end, remove all the way to the end
+ if (len == npos || p + len >= _size) {
+ // Delete char at p as well. So _size = (p - 1) + 1
+ _size = p;
+ // Null terminate
+ _str[_size] = 0;
+ return;
+ }
+
+ for ( ; p + len <= _size; p++) {
+ _str[p] = _str[p + len];
+ }
+ _size -= len;
+}
+
+TEMPLATE typename BASESTRING::iterator BASESTRING::erase(iterator it) {
+ this->deleteChar(it - _str);
+ return it;
+}
+
+TEMPLATE void BASESTRING::clear() {
+ decRefCount(_extern._refCount);
+
+ _size = 0;
+ _str = _storage;
+ _storage[0] = 0;
+}
+
+
+TEMPLATE void BASESTRING::setChar(value_type c, uint32 p) {
+ assert(p < _size);
+
+ makeUnique();
+ _str[p] = c;
+}
+
+TEMPLATE void BASESTRING::assign(const BaseString &str) {
+ if (&str == this)
+ return;
+
+ 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;
+ }
+}
+
+TEMPLATE void BASESTRING::assign(value_type c) {
+ decRefCount(_extern._refCount);
+ _str = _storage;
+
+ _str[0] = c;
+ _str[1] = 0;
+
+ _size = (c == 0) ? 0 : 1;
+}
+
+TEMPLATE void BASESTRING::insertString(const value_type *s, uint32 p) {
+ while (*s != '\0') {
+ BaseString::insertChar(*s++, p++);
+ }
+}
+
+TEMPLATE void BASESTRING::insertString(const BaseString &s, uint32 p) {
+ for (uint i = 0; i < s._size; i++) {
+ BaseString::insertChar(s[i], p+i);
+ }
+}
+
+TEMPLATE uint32 BASESTRING::find(value_type x, uint32 pos) const {
+ for (uint32 i = pos; i < _size; ++i) {
+ if (_str[i] == x) {
+ return i;
+ }
+ }
+
+ return npos;
+}
+
+TEMPLATE uint32 BASESTRING::find(const BaseString &str, uint32 pos) const {
+ if (pos >= _size) {
+ return npos;
+ }
+
+ const value_type *strP = str.c_str();
+
+ for (const_iterator cur = begin() + pos; cur != end(); ++cur) {
+ uint i = 0;
+ while (true) {
+ if (!strP[i]) {
+ return cur - begin();
+ }
+
+ if (cur[i] != strP[i]) {
+ break;
+ }
+
+ ++i;
+ }
+ }
+
+ return npos;
+}
+
+TEMPLATE size_t BASESTRING::find(const value_type *strP, uint32 pos) const {
+ if (pos >= _size) {
+ return npos;
+ }
+
+ for (const_iterator cur = begin() + pos; cur != end(); ++cur) {
+ uint i = 0;
+ while (true) {
+ if (!strP[i]) {
+ return cur - begin();
+ }
+
+ if (cur[i] != strP[i]) {
+ break;
+ }
+
+ ++i;
+ }
+ }
+
+ return npos;
+}
+
+TEMPLATE uint64 BASESTRING::asUint64() const {
+ uint64 result = 0;
+ for (uint32 i = 0; i < _size; ++i) {
+ if (_str[i] < '0' || _str[i] > '9') break;
+ result = result * 10L + (_str[i] - '0');
+ }
+ return result;
+}
+
+TEMPLATE uint64 BASESTRING::asUint64Ext() const {
+ uint64 result = 0;
+ uint64 base = 10;
+ uint32 skip = 0;
+
+ if (_size >= 3 && _str[0] == '0' && _str[1] == 'x') {
+ base = 16;
+ skip = 2;
+ } else if (_size >= 2 && _str[0] == '0') {
+ base = 8;
+ skip = 1;
+ } else {
+ base = 10;
+ skip = 0;
+ }
+ for (uint32 i = skip; i < _size; ++i) {
+ char digit = _str[i];
+ uint64 digitval = 17; // sentinel
+ if (digit >= '0' && digit <= '9')
+ digitval = digit - '0';
+ else if (digit >= 'a' && digit <= 'f')
+ digitval = digit - 'a' + 10;
+ else if (digit >= 'A' && digit <= 'F')
+ digitval = digit - 'A' + 10;
+ if (digitval > base)
+ break;
+ result = result * base + digitval;
+ }
+ return result;
+}
+
+#ifndef SCUMMVM_UTIL
+
+TEMPLATE void BASESTRING::wordWrap(const uint32 maxLength) {
+ if (_size < maxLength) {
+ return;
+ }
+
+ makeUnique();
+
+ const uint32 kNoSpace = 0xFFFFFFFF;
+
+ uint32 i = 0;
+ while (i < _size) {
+ uint32 lastSpace = kNoSpace;
+ uint32 x = 0;
+ while (i < _size && x <= maxLength) {
+ const char c = _str[i];
+ if (c == '\n') {
+ lastSpace = kNoSpace;
+ x = 0;
+ } else {
+ if (Common::isSpace(c)) {
+ lastSpace = i;
+ }
+ ++x;
+ }
+ ++i;
+ }
+
+ if (x > maxLength) {
+ if (lastSpace == kNoSpace) {
+ insertChar('\n', i - 1);
+ } else {
+ setChar('\n', lastSpace);
+ i = lastSpace + 1;
+ }
+ }
+ }
+}
+
+#endif
+
+TEMPLATE void BASESTRING::toLowercase() {
+ makeUnique();
+ for (uint32 i = 0; i < _size; ++i) {
+ if (_str[i] > 0 && _str[i] < 128) {
+ _str[i] = tolower(_str[i]);
+ }
+ }
+}
+
+TEMPLATE void BASESTRING::toUppercase() {
+ makeUnique();
+ for (uint32 i = 0; i < _size; ++i) {
+ if (_str[i] > 0 && _str[i] < 128) {
+ _str[i] = toupper(_str[i]);
+ }
+ }
+}
+
+#ifndef SCUMMVM_UTIL
+
+TEMPLATE void BASESTRING::trim() {
+ if (_size == 0)
+ return;
+
+ makeUnique();
+
+ // Trim trailing whitespace
+ while (_size >= 1 && isSpace(_str[_size - 1]))
+ --_size;
+ _str[_size] = 0;
+
+ // Trim leading whitespace
+ value_type *t = _str;
+ while (isSpace(*t))
+ t++;
+
+ if (t != _str) {
+ _size -= t - _str;
+ memmove(_str, t, (_size + 1) * sizeof(_str[0]));
+ }
+}
+#endif
+
+TEMPLATE void BASESTRING::assignAppend(value_type c) {
+ ensureCapacity(_size + 1, true);
+
+ _str[_size++] = c;
+ _str[_size] = 0;
+}
+
+TEMPLATE void BASESTRING::assignAppend(const BaseString &str) {
+ if (&str == this) {
+ assignAppend(BaseString(str));
+ return;
+ }
+
+ int len = str._size;
+ if (len > 0) {
+ ensureCapacity(_size + len, true);
+
+ memcpy(_str + _size, str._str, (len + 1) * sizeof(value_type));
+ _size += len;
+ }
+}
+
+TEMPLATE bool BASESTRING::pointerInOwnBuffer(const value_type *str) const {
+ //compared pointers must be in the same array or UB
+ //cast to intptr however is IB
+ //which includes comparision of the values
+ uintptr ownBuffStart = (uintptr)_str;
+ uintptr ownBuffEnd = (uintptr)(_str + _size);
+ uintptr candidateAddr = (uintptr)str;
+ return ownBuffStart <= candidateAddr && candidateAddr <= ownBuffEnd;
+}
+
+TEMPLATE void BASESTRING::assignAppend(const value_type *str) {
+ if (pointerInOwnBuffer(str)) {
+ assignAppend(BaseString(str));
+ return;
+ }
+
+ uint32 len;
+ for (len = 0; str[len]; len++);
+ if (len > 0) {
+ ensureCapacity(_size + len, true);
+
+ memcpy(_str + _size, str, (len + 1) * sizeof(value_type));
+ _size += len;
+ }
+}
+
+TEMPLATE void BASESTRING::assign(const value_type *str) {
+ uint32 len;
+ for (len = 0; str[len]; len++);
+ ensureCapacity(len, false);
+ _size = len;
+ memmove(_str, str, (len + 1) * sizeof(value_type));
+}
+
+TEMPLATE uint BASESTRING::getUnsignedValue(uint pos) const {
+ const int shift = (sizeof(uint) - sizeof(value_type)) * 8;
+ return ((uint)_str[pos]) << shift >> shift;
+}
+
+// Hash function for strings, taken from CPython.
+TEMPLATE uint BASESTRING::hash() const {
+ uint hash = getUnsignedValue(0) << 7;
+ for (uint i = 0; i < _size; i++) {
+ hash = (1000003 * hash) ^ getUnsignedValue(i);
+ }
+ return hash ^ _size;
+}
+
+template class BaseString<char>;
+template class BaseString<u32char_type_t>;
+
+}
diff --git a/common/base-str.h b/common/base-str.h
new file mode 100644
index 0000000000..b3119322e2
--- /dev/null
+++ b/common/base-str.h
@@ -0,0 +1,258 @@
+/* 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_BASE_STRING_H
+#define COMMON_BASE_STRING_H
+
+#include "common/scummsys.h"
+#include "common/str-enc.h"
+
+#include <stdarg.h>
+
+namespace Common {
+template<class T>
+class BaseString {
+public:
+ static void releaseMemoryPoolMutex();
+
+ static const uint32 npos = 0xFFFFFFFF;
+ typedef T value_type;
+ typedef T * iterator;
+ typedef const T * const_iterator;
+
+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.
+ */
+ static const uint32 _builtinCapacity = 32 - (sizeof(uint32) + sizeof(char *)) / sizeof(value_type);
+
+ /**
+ * 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.
+ */
+ 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. */
+ BaseString() : _size(0), _str(_storage) { _storage[0] = 0; }
+
+ /** Construct a copy of the given string. */
+ BaseString(const BaseString &str);
+
+ /** Construct a new string from the given NULL-terminated C string. */
+ explicit BaseString(const value_type *str);
+
+ /** Construct a new string containing exactly len characters read from address str. */
+ BaseString(const value_type *str, uint32 len);
+
+ /** Construct a new string containing the characters between beginP (including) and endP (excluding). */
+ BaseString(const value_type *beginP, const value_type *endP);
+
+ bool operator==(const BaseString &x) const;
+ bool operator==(const value_type *x) const;
+ bool operator!=(const BaseString &x) const;
+ bool operator!=(const value_type *x) const;
+
+ bool operator<(const BaseString &x) const;
+ bool operator<(const value_type *x) const;
+ bool operator<=(const BaseString &x) const;
+ bool operator<=(const value_type *x) const;
+ bool operator>(const BaseString &x) const;
+ bool operator>(const value_type *x) const;
+ bool operator>=(const BaseString &x) const;
+ bool operator>=(const value_type *x) const;
+
+ /**
+ * Compares whether two BaseString are the same based on memory comparison.
+ * This does *not* do comparison based on canonical equivalence.
+ */
+ bool equals(const BaseString &x) const;
+ bool equals(const value_type *x) const;
+ bool equalsC(const char *x) const;
+ int compareTo(const BaseString &x) const; // strcmp clone
+ int compareTo(const value_type *x) const; // strcmp clone
+ int compareToC(const char *x) const; // strcmp clone
+
+ /** Set character c at position p, replacing the previous character there. */
+ void setChar(value_type c, uint32 p);
+
+ /**
+ * Removes the value at position p from the string.
+ * Using this on decomposed characters will not remove the whole
+ * character!
+ */
+ void deleteChar(uint32 p);
+
+ /** Remove the last character from the string. */
+ void deleteLastChar();
+
+ /** Remove all characters from position p to the p + len. If len = String::npos, removes all characters to the end */
+ void erase(uint32 p, uint32 len = npos);
+
+ /** Erases the character at the given iterator location */
+ iterator erase(iterator it);
+
+ /** Clears the string, making it empty. */
+ void clear();
+
+ 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();
+ }
+
+ inline const value_type *c_str() const { return _str; }
+ inline uint size() const { return _size; }
+
+ inline bool empty() const { return (_size == 0); }
+ value_type firstChar() const { return (_size > 0) ? _str[0] : 0; }
+ value_type lastChar() const { return (_size > 0) ? _str[_size - 1] : 0; }
+
+ value_type operator[](int idx) const {
+ assert(_str && idx >= 0 && idx < (int)_size);
+ return _str[idx];
+ }
+
+ /**
+ * Checks if a given string is present in the internal string or not.
+ */
+ bool contains(const BaseString &otherString) const;
+ bool contains(value_type x) const;
+
+ /** Insert character c before position p. */
+ void insertChar(value_type c, uint32 p);
+ void insertString(const value_type *s, uint32 p);
+ void insertString(const BaseString &s, uint32 p);
+
+ /** Finds the index of a character in the string */
+ uint32 find(value_type x, uint32 pos = 0) const;
+ /** Does a find for the passed string */
+ size_t find(const value_type *s, uint32 pos = 0) const;
+ uint32 find(const BaseString &str, uint32 pos = 0) const;
+
+ /**
+ * Wraps the text in the string to the given line maximum. Lines will be
+ * broken at any whitespace character. New lines are assumed to be
+ * represented using '\n'.
+ *
+ * This is a very basic line wrap which does not perform tab stop
+ * calculation, consecutive whitespace collapsing, auto-hyphenation, or line
+ * balancing.
+ */
+ void wordWrap(const uint32 maxLength);
+
+ /** Return uint64 corrensponding to String's contents. */
+ uint64 asUint64() const;
+
+ /** Return uint64 corrensponding to String's contents. This variant recognizes 0 (oct) and 0x (hex) prefixes. */
+ uint64 asUint64Ext() const;
+
+ /**
+ * 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();
+
+ /**
+ * Removes trailing and leading whitespaces. Uses isspace() to decide
+ * what is whitespace and what not.
+ */
+ void trim();
+
+ uint hash() const;
+
+protected:
+ void makeUnique();
+ void ensureCapacity(uint32 new_size, bool keep_old);
+ void incRefCount() const;
+ void decRefCount(int *oldRefCount);
+ void initWithValueTypeStr(const value_type *str, uint32 len);
+ void initWithCStr(const char *str, uint32 len);
+
+ void assignAppend(const value_type *str);
+ void assignAppend(value_type c);
+ void assignAppend(const BaseString &str);
+ void assign(const BaseString &str);
+ void assign(value_type c);
+ void assign(const value_type *str);
+
+ bool pointerInOwnBuffer(const value_type *str) const;
+
+ uint getUnsignedValue(uint pos) const;
+};
+}
+#endif
diff --git a/common/hash-str.h b/common/hash-str.h
index fcd41ab6a7..f8a75f632c 100644
--- a/common/hash-str.h
+++ b/common/hash-str.h
@@ -30,7 +30,6 @@ namespace Common {
uint hashit(const char *str);
uint hashit_lower(const char *str); // Generate a hash based on the lowercase version of the string
-inline uint hashit(const String &str) { return hashit(str.c_str()); }
inline uint hashit_lower(const String &str) { return hashit_lower(str.c_str()); }
// FIXME: The following functors obviously are not consistently named
@@ -40,7 +39,7 @@ struct CaseSensitiveString_EqualTo {
};
struct CaseSensitiveString_Hash {
- uint operator()(const String& x) const { return hashit(x.c_str()); }
+ uint operator()(const String& x) const { return x.hash(); }
};
@@ -61,7 +60,14 @@ struct IgnoreCase_Hash {
template<>
struct Hash<String> {
uint operator()(const String& s) const {
- return hashit(s.c_str());
+ return s.hash();
+ }
+};
+
+template<>
+struct Hash<U32String> {
+ uint operator()(const U32String& s) const {
+ return s.hash();
}
};
diff --git a/common/module.mk b/common/module.mk
index a258dd480a..a897e85a83 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -3,6 +3,7 @@ MODULE := common
MODULE_OBJS := \
achievements.o \
archive.o \
+ base-str.o \
config-manager.o \
coroutines.o \
dcl.o \
diff --git a/common/serializer.h b/common/serializer.h
index 8478030759..ea2cda91d0 100644
--- a/common/serializer.h
+++ b/common/serializer.h
@@ -264,6 +264,29 @@ public:
}
}
+ /**
+ * Sync a U32-string
+ */
+ void syncString32(U32String &str, Version minVersion = 0, Version maxVersion = kLastVersion) {
+ if (_version < minVersion || _version > maxVersion)
+ return; // Ignore anything which is not supposed to be present in this save game version
+
+ uint32 len = str.size();
+
+ syncAsUint32LE(len);
+
+ if (isLoading()) {
+ U32String::value_type *sl = new U32String::value_type[len];
+ for (uint i = 0; i < len; i++)
+ syncAsUint32LE(sl[i]);
+ str = U32String(sl, len);
+ } else {
+ for (uint i = 0; i < len; i++)
+ _saveStream->writeUint32LE(str[i]);
+ _bytesSynced += 4 * len;
+ }
+ }
+
template <typename T>
void syncArray(T *arr, size_t entries, void (*serializer)(Serializer &, T &), Version minVersion = 0, Version maxVersion = kLastVersion) {
if (_version < minVersion || _version > maxVersion)
diff --git a/common/str.cpp b/common/str.cpp
index 4a15ccd957..fb1dba44e6 100644
--- a/common/str.cpp
+++ b/common/str.cpp
@@ -29,95 +29,8 @@
namespace Common {
-MemoryPool *g_refCountPool = nullptr; // FIXME: This is never freed right now
-Mutex *g_refCountPoolMutex = nullptr;
-
-void lockMemoryPoolMutex() {
- // The Mutex class can only be used once g_system is set and initialized,
- // but we may use the String class earlier than that (it is for example
- // used in the OSystem_POSIX constructor). However in those early stages
- // we can hope we don't have multiple threads either.
- if (!g_system || !g_system->backendInitialized())
- return;
- if (!g_refCountPoolMutex)
- g_refCountPoolMutex = new Mutex();
- g_refCountPoolMutex->lock();
-}
-
-void unlockMemoryPoolMutex() {
- if (g_refCountPoolMutex)
- g_refCountPoolMutex->unlock();
-}
-
-void String::releaseMemoryPoolMutex() {
- if (g_refCountPoolMutex){
- delete g_refCountPoolMutex;
- g_refCountPoolMutex = nullptr;
- }
-}
-
-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 == nullptr) {
- _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 = nullptr;
- _str = new char[_extern._capacity];
- assert(_str != nullptr);
- }
-
- // 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 != nullptr);
-}
-
String::String(char c)
- : _size(0), _str(_storage) {
+ : BaseString() {
_storage[0] = c;
_storage[1] = 0;
@@ -125,214 +38,45 @@ String::String(char c)
_size = (c == 0) ? 0 : 1;
}
+#ifndef SCUMMVM_UTIL
String::String(const U32String &str)
- : _size(0), _str(_storage) {
+ : BaseString() {
_storage[0] = 0;
*this = String(str.encode());
}
+#endif
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;
-
- // 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 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 = nullptr;
- _extern._capacity = newCapacity;
- }
-}
-
-void String::incRefCount() const {
- assert(!isStorageIntern());
- if (_extern._refCount == nullptr) {
- lockMemoryPoolMutex();
- if (g_refCountPool == nullptr) {
- g_refCountPool = new MemoryPool(sizeof(int));
- assert(g_refCountPool);
- }
-
- _extern._refCount = (int *)g_refCountPool->allocChunk();
- unlockMemoryPoolMutex();
- *_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) {
- lockMemoryPoolMutex();
- assert(g_refCountPool);
- g_refCountPool->freeChunk(oldRefCount);
- unlockMemoryPoolMutex();
- }
- // Coverity thinks that we always free memory, as it assumes
- // (correctly) that there are cases when oldRefCount == 0
- // Thus, DO NOT COMPILE, trick it and shut tons of false positives
-#ifndef __COVERITY__
- delete[] _str;
-#endif
-
- // 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);
+ assign(str);
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;
- }
-
+ assign(str);
return *this;
}
String &String::operator=(char c) {
- decRefCount(_extern._refCount);
- _str = _storage;
-
- _str[0] = c;
- _str[1] = 0;
-
- _size = (c == 0) ? 0 : 1;
+ assign(c);
return *this;
}
String &String::operator+=(const char *str) {
- if (pointerInOwnBuffer(str))
- return operator+=(String(str));
-
- int len = strlen(str);
- if (len > 0) {
- ensureCapacity(_size + len, true);
-
- memcpy(_str + _size, str, len + 1);
- _size += len;
- }
+ assignAppend(str);
return *this;
}
-bool String::pointerInOwnBuffer(const char *str) const {
- //compared pointers must be in the same array or UB
- //cast to intptr however is IB
- //which includes comparision of the values
- uintptr ownBuffStart = (uintptr)_str;
- uintptr ownBuffEnd = (uintptr)(_str + _size);
- uintptr candidateAddr = (uintptr)str;
- return ownBuffStart <= candidateAddr && candidateAddr <= ownBuffEnd;
-}
-
String &String::operator+=(const String &str) {
- if (&str == this)
- return operator+=(String(str));
-
- int len = str._size;
- if (len > 0) {
- ensureCapacity(_size + len, true);
-
- memcpy(_str + _size, str._str, len + 1);
- _size += len;
- }
+ assignAppend(str);
return *this;
}
String &String::operator+=(char c) {
- ensureCapacity(_size + 1, true);
-
- _str[_size++] = c;
- _str[_size] = 0;
-
+ assignAppend(c);
return *this;
}
@@ -432,45 +176,7 @@ bool String::contains(uint32 x) const {
return false;
}
-uint64 String::asUint64() const {
- uint64 result = 0;
- for (uint32 i = 0; i < _size; ++i) {
- if (_str[i] < '0' || _str[i] > '9') break;
- result = result * 10L + (_str[i] - '0');
- }
- return result;
-}
-
-uint64 String::asUint64Ext() const {
- uint64 result = 0;
- uint64 base = 10;
- uint32 skip = 0;
-
- if (_size >= 3 && _str[0] == '0' && _str[1] == 'x') {
- base = 16;
- skip = 2;
- } else if (_size >= 2 && _str[0] == '0') {
- base = 8;
- skip = 1;
- } else {
- base = 10;
- skip = 0;
- }
- for (uint32 i = skip; i < _size; ++i) {
- char digit = _str[i];
- uint64 digitval = 17; // sentinel
- if (digit >= '0' && digit <= '9')
- digitval = digit - '0';
- else if (digit >= 'a' && digit <= 'f')
- digitval = digit - 'a' + 10;
- else if (digit >= 'A' && digit <= 'F')
- digitval = digit - 'A' + 10;
- if (digitval > base)
- break;
- result = result * base + digitval;
- }
- return result;
-}
+#ifndef SCUMMVM_UTIL
bool String::matchString(const char *pat, bool ignoreCase, bool pathMode) const {
return Common::matchString(c_str(), pat, ignoreCase, pathMode);
@@ -480,146 +186,7 @@ bool String::matchString(const String &pat, bool ignoreCase, bool pathMode) cons
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::erase(uint32 p, uint32 len) {
- if (p == npos || len == 0)
- return;
- assert(p < _size);
-
- makeUnique();
- // If len == npos or p + len is over the end, remove all the way to the end
- if (len == npos || p + len >= _size) {
- // Delete char at p as well. So _size = (p - 1) + 1
- _size = p;
- // Null terminate
- _str[_size] = 0;
- return;
- }
-
- for ( ; p + len <= _size; p++) {
- _str[p] = _str[p + len];
- }
- _size -= len;
-}
-
-String::iterator String::erase(iterator it) {
- this->deleteChar(it - _str);
- return it;
-}
-
-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);
- }
-}
-
-void String::wordWrap(const uint32 maxLength) {
- if (_size < maxLength) {
- return;
- }
-
- makeUnique();
-
- const uint32 kNoSpace = 0xFFFFFFFF;
-
- uint32 i = 0;
- while (i < _size) {
- uint32 lastSpace = kNoSpace;
- uint32 x = 0;
- while (i < _size && x <= maxLength) {
- const char c = _str[i];
- if (c == '\n') {
- lastSpace = kNoSpace;
- x = 0;
- } else {
- if (Common::isSpace(c)) {
- lastSpace = i;
- }
- ++x;
- }
- ++i;
- }
-
- if (x > maxLength) {
- if (lastSpace == kNoSpace) {
- insertChar('\n', i - 1);
- } else {
- setChar('\n', lastSpace);
- i = lastSpace + 1;
- }
- }
- }
-}
-
-uint String::hash() const {
- return hashit(c_str());
-}
+#endif
void String::replace(uint32 pos, uint32 count, const String &str) {
replace(pos, count, str, 0, str._size);
@@ -645,12 +212,13 @@ void String::replace(uint32 posOri, uint32 countOri, const String &str,
void String::replace(uint32 posOri, uint32 countOri, const char *str,
uint32 posDest, uint32 countDest) {
- ensureCapacity(_size + countDest - countOri, true);
-
// Prepare string for the replaced text.
if (countOri < countDest) {
uint32 offset = countDest - countOri; ///< Offset to copy the characters
uint32 newSize = _size + offset;
+
+ ensureCapacity(newSize, true);
+
_size = newSize;
// Push the old characters to the end of the string
@@ -660,11 +228,15 @@ void String::replace(uint32 posOri, uint32 countOri, const char *str,
} else if (countOri > countDest){
uint32 offset = countOri - countDest; ///< Number of positions that we have to pull back
+ makeUnique();
+
// Pull the remainder string back
- for (uint32 i = posOri + countDest; i < _size; i++)
+ for (uint32 i = posOri + countDest; i + offset <= _size; i++)
_str[i] = _str[i + offset];
_size -= offset;
+ } else {
+ makeUnique();
}
// Copy the replaced part of the string
@@ -673,31 +245,6 @@ void String::replace(uint32 posOri, uint32 countOri, const char *str,
}
-uint32 String::find(const String &str, uint32 pos) const {
- if (pos >= _size) {
- return npos;
- }
-
- const char *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;
-}
-
// static
String String::format(const char *fmt, ...) {
String output;
@@ -762,17 +309,6 @@ String String::vformat(const char *fmt, va_list args) {
return output;
}
-
-size_t String::find(char c, size_t pos) const {
- const char *p = strchr(_str + pos, c);
- return p ? p - _str : npos;
-}
-
-size_t String::find(const char *s) const {
- const char *str = strstr(_str, s);
- return str ? str - _str : npos;
-}
-
size_t String::rfind(const char *s) const {
int sLen = strlen(s);
@@ -874,42 +410,6 @@ String String::substr(size_t pos, size_t len) const {
#pragma mark -
-bool String::operator==(const String &x) const {
- return equals(x);
-}
-
-bool String::operator==(const char *x) const {
- assert(x != nullptr);
- return equals(x);
-}
-
-bool String::operator!=(const String &x) const {
- return !equals(x);
-}
-
-bool String::operator !=(const char *x) const {
- assert(x != nullptr);
- 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);
}
@@ -920,15 +420,6 @@ bool operator!=(const char* y, const String &x) {
#pragma mark -
-bool String::equals(const String &x) const {
- return (0 == compareTo(x));
-}
-
-bool String::equals(const char *x) const {
- assert(x != nullptr);
- return (0 == compareTo(x));
-}
-
bool String::equalsIgnoreCase(const String &x) const {
return (0 == compareToIgnoreCase(x));
}
@@ -938,15 +429,6 @@ bool String::equalsIgnoreCase(const char *x) const {
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 != nullptr);
- return strcmp(c_str(), x);
-}
-
int String::compareToIgnoreCase(const String &x) const {
return compareToIgnoreCase(x.c_str());
}
@@ -997,6 +479,8 @@ String operator+(const String &x, char y) {
return temp;
}
+#ifndef SCUMMVM_UTIL
+
char *ltrim(char *t) {
while (isSpace(*t))
t++;
@@ -1014,6 +498,8 @@ char *trim(char *t) {
return rtrim(ltrim(t));
}
+#endif
+
String lastPathComponent(const String &path, const char sep) {
const char *str = path.c_str();
const char *last = str + path.size();
@@ -1089,6 +575,8 @@ String normalizePath(const String &path, const char sep) {
return result;
}
+#ifndef SCUMMVM_UTIL
+
bool matchString(const char *str, const char *pat, bool ignoreCase, bool pathMode) {
assert(str);
assert(pat);
@@ -1193,6 +681,8 @@ String tag2string(uint32 tag) {
return String(str);
}
+#endif
+
size_t strlcpy(char *dst, const char *src, size_t size) {
// Our backup of the source's start, we need this
// to calculate the source's length.
diff --git a/common/str.h b/common/str.h
index 5371bcffda..6b1113aa64 100644
--- a/common/str.h
+++ b/common/str.h
@@ -26,6 +26,7 @@
#include "common/scummsys.h"
#include "common/str-enc.h"
#include "common/ustr.h"
+#include "common/base-str.h"
#include <stdarg.h>
@@ -56,84 +57,29 @@ class U32String;
* The presence of \0 characters in the string will cause undefined
* behavior in some operations.
*/
-class String {
+class String : public BaseString<char> {
public:
- static const uint32 npos = 0xFFFFFFFF;
-
- static void releaseMemoryPoolMutex();
-
- 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;
-
-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:
/** Construct a new empty string. */
- String() : _size(0), _str(_storage) { _storage[0] = 0; }
+ String() : BaseString() {}
/** Construct a new string from the given NULL-terminated C string. */
- String(const char *str);
+ String(const char *str) : BaseString(str) {}
/** Construct a new string containing exactly len characters read from address str. */
- String(const char *str, uint32 len);
+ String(const char *str, uint32 len) : BaseString(str, len) {}
/** Construct a new string containing the characters between beginP (including) and endP (excluding). */
- String(const char *beginP, const char *endP);
+ String(const char *beginP, const char *endP) : BaseString(beginP, endP) {}
/** Construct a copy of the given string. */
- String(const String &str);
+ String(const String &str) : BaseString(str) {};
/** Construct a string consisting of the given character. */
explicit String(char c);
@@ -150,24 +96,10 @@ public:
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
int compareDictionary(const String &x) const;
int compareDictionary(const char *x) const;
@@ -187,12 +119,6 @@ public:
bool contains(char x) const;
bool contains(uint32 x) const;
- /** Return uint64 corrensponding to String's contents. */
- uint64 asUint64() const;
-
- /** Return uint64 corrensponding to String's contents. This variant recognizes 0 (oct) and 0x (hex) prefixes. */
- uint64 asUint64Ext() const;
-
/**
* Simple DOS-style pattern matching function (understands * and ? like used in DOS).
* Taken from exult/files/listfiles.cc
@@ -221,65 +147,6 @@ public:
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 firstChar() const { return (_size > 0) ? _str[0] : 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);
-
- /** Remove all characters from position p to the p + len. If len = String::npos, removes all characters to the end */
- void erase(uint32 p, uint32 len = npos);
-
- /** Erases the character at the given iterator location */
- iterator erase(iterator it);
-
- /** 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();
-
- /**
- * Wraps the text in the string to the given line maximum. Lines will be
- * broken at any whitespace character. New lines are assumed to be
- * represented using '\n'.
- *
- * This is a very basic line wrap which does not perform tab stop
- * calculation, consecutive whitespace collapsing, auto-hyphenation, or line
- * balancing.
- */
- void wordWrap(const uint32 maxLength);
-
- uint hash() const;
-
/**@{
* Functions to replace some amount of chars with chars from some other string.
*
@@ -326,13 +193,6 @@ public:
*/
static String vformat(const char *fmt, va_list args);
- /** Finds the index of a character in the string */
- size_t find(char c, size_t pos = 0) const;
-
- /** Does a find for the passed string */
- size_t find(const char *s) const;
- uint32 find(const String &str, uint32 pos = 0) const;
-
/** Does a reverse find for the passed string */
size_t rfind(const char *s) const;
size_t rfind(const String &s) const {
@@ -381,42 +241,10 @@ public:
/** Return a substring of this string */
String substr(size_t pos = 0, size_t len = npos) const;
-public:
-
- 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();
- }
-
/** Python-like method **/
U32String decode(CodePage page = kUtf8) const;
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);
-
- bool pointerInOwnBuffer(const char *str) const;
-
void decodeUTF8(U32String &dst) const;
void decodeOneByte(U32String &dst, CodePage page) const;
};
diff --git a/common/ustr.cpp b/common/ustr.cpp
index 00584dd629..a4bad790a6 100644
--- a/common/ustr.cpp
+++ b/common/ustr.cpp
@@ -28,53 +28,7 @@
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 == nullptr) {
- _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 != nullptr);
-}
-
-U32String::U32String(const char *str) : _size(0), _str(_storage) {
+U32String::U32String(const char *str) : BaseString() {
if (str == nullptr) {
_storage[0] = 0;
_size = 0;
@@ -83,21 +37,21 @@ U32String::U32String(const char *str) : _size(0), _str(_storage) {
}
}
-U32String::U32String(const char *str, uint32 len) : _size(0), _str(_storage) {
+U32String::U32String(const char *str, uint32 len) : BaseString() {
initWithCStr(str, len);
}
-U32String::U32String(const char *beginP, const char *endP) : _size(0), _str(_storage) {
+U32String::U32String(const char *beginP, const char *endP) : BaseString() {
assert(endP >= beginP);
initWithCStr(beginP, endP - beginP);
}
-U32String::U32String(const String &str) : _size(0), _str(_storage) {
+U32String::U32String(const String &str) : BaseString() {
initWithCStr(str.c_str(), str.size());
}
-U32String::U32String(const UnicodeBiDiText &txt) : _size(0), _str(_storage) {
- initWithCStr(txt.visual.c_str(), txt.visual.size());
+U32String::U32String(const UnicodeBiDiText &txt) : BaseString() {
+ initWithValueTypeStr(txt.visual.c_str(), txt.visual.size());
}
U32String::~U32String() {
@@ -105,24 +59,7 @@ U32String::~U32String() {
}
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;
- }
-
+ assign(str);
return *this;
}
@@ -166,465 +103,43 @@ U32String &U32String::operator+=(value_type c) {
return *this;
}
-bool U32String::operator==(const U32String &x) const {
- return equals(x);
-}
-
bool U32String::operator==(const String &x) const {
- return equals(x);
-}
-
-bool U32String::operator==(const value_type *x) const {
- return equals(U32String(x));
+ return equalsC(x.c_str());
}
bool U32String::operator==(const char *x) const {
- return equals(x);
-}
-
-bool U32String::operator!=(const U32String &x) const {
- return !equals(x);
+ return equalsC(x);
}
bool U32String::operator!=(const String &x) const {
- return !equals(x);
-}
-
-bool U32String::operator!=(const value_type *x) const {
- return !equals(U32String(x));
+ return !equalsC(x.c_str());
}
bool U32String::operator!=(const char *x) const {
- return !equals(x);
-}
-
-bool U32String::operator<(const U32String &x) const {
- for (uint32 i = 0, n = x.size(); i < _size && i < n; ++i) {
- uint32 sc = _str[i];
- uint32 xc = x[i];
- if (sc < xc)
- return true;
- else if (sc > xc)
- return false;
- }
- return (_size < x.size());
-}
-
-bool U32String::operator<=(const U32String &x) const {
- return !operator>(x);
-}
-
-bool U32String::operator>(const U32String &x) const {
- for (uint i = 0, n = x.size(); i < _size && i < n; ++i) {
- uint32 sc = _str[i];
- uint32 xc = x[i];
- if (sc > xc)
- return true;
- else if (sc < xc)
- return false;
- }
- return (_size > x.size());
-}
-
-bool U32String::operator>=(const U32String &x) const {
- return !operator<(x);
-}
-
-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::equals(const String &x) const {
- if (x.size() != _size)
- return false;
-
- for (uint32 idx = 0; idx < _size; ++idx)
- if (_str[idx] != static_cast<value_type>(x[idx]))
- return false;
-
- return true;
-}
-
-bool U32String::contains(value_type x) const {
- for (uint32 i = 0; i < _size; ++i) {
- if (_str[i] == x) {
- return true;
- }
- }
-
- return false;
-}
-
-bool U32String::contains(const U32String &otherString) const {
- if (empty() || otherString.empty() || _size < otherString.size()) {
- return false;
- }
-
- uint32 size = 0;
- U32String::const_iterator itr = otherString.begin();
-
- for (U32String::const_iterator itr2 = begin(); itr != otherString.end() && itr2 != end(); itr2++) {
- if (*itr == *itr2) {
- itr++;
- size++;
- if (size == otherString.size())
- return true;
- } else {
- size = 0;
- itr = otherString.begin();
- }
- }
-
- return false;
-}
-
-void U32String::insertChar(value_type 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 U32String::insertString(String s, uint32 p) {
- for (String::iterator i = s.begin(); i != s.end(); i++) {
- U32String::insertChar(*i, p++);
- }
-}
-
-void U32String::insertString(value_type *s, uint32 p) {
- while (*s != '\0') {
- U32String::insertChar(*s++, p++);
- }
-}
-
-void U32String::deleteChar(uint32 p) {
- assert(p < _size);
-
- makeUnique();
- while (p++ < _size)
- _str[p - 1] = _str[p];
- _size--;
-}
-
-void U32String::deleteLastChar() {
- if (_size > 0)
- deleteChar(_size - 1);
-}
-
-void U32String::erase(uint32 p, uint32 len) {
- assert(p < _size);
-
- makeUnique();
- // If len == npos or p + len is over the end, remove all the way to the end
- if (len == npos || p + len >= _size) {
- // Delete char at p as well. So _size = (p - 1) + 1
- _size = p;
- // Null terminate
- _str[_size] = 0;
- return;
- }
-
- for ( ; p + len <= _size; p++) {
- _str[p] = _str[p + len];
- }
- _size -= len;
-}
-
-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(value_type x, uint32 pos) const {
- for (uint32 i = pos; i < _size; ++i) {
- if (_str[i] == x) {
- return i;
- }
- }
-
- return npos;
-}
-
-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 = nullptr;
- _extern._capacity = newCapacity;
- }
-}
-
-void U32String::incRefCount() const {
- assert(!isStorageIntern());
- if (_extern._refCount == nullptr) {
- if (g_refCountPool == nullptr) {
- 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);
- }
- // Coverity thinks that we always free memory, as it assumes
- // (correctly) that there are cases when oldRefCount == 0
- // Thus, DO NOT COMPILE, trick it and shut tons of false positives
-#ifndef __COVERITY__
- delete[] _str;
-#endif
-
- // 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 = nullptr;
- _str = new value_type[_extern._capacity];
- assert(_str != nullptr);
- }
-
- // Copy the string into the storage area
- memmove(_str, str, len * sizeof(value_type));
- _str[len] = 0;
-}
-
-void U32String::initWithCStr(const char *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 = nullptr;
- _str = new value_type[_extern._capacity];
- assert(_str != nullptr);
- }
-
- // Copy the string into the storage area
- for (size_t idx = 0; idx < len; ++idx, ++str)
- _str[idx] = (byte)(*str);
-
- _str[len] = 0;
+ return !equalsC(x);
}
-
U32String operator+(const U32String &x, const U32String &y) {
U32String temp(x);
temp += y;
return temp;
}
-void U32String::wordWrap(const uint32 maxLength) {
- if (_size < maxLength) {
- return;
- }
-
- makeUnique();
-
- const uint32 kNoSpace = 0xFFFFFFFF;
-
- uint32 i = 0;
- while (i < _size) {
- uint32 lastSpace = kNoSpace;
- uint32 x = 0;
- while (i < _size && x <= maxLength) {
- const char c = _str[i];
- if (c == '\n') {
- lastSpace = kNoSpace;
- x = 0;
- } else {
- if (Common::isSpace(c)) {
- lastSpace = i;
- }
- ++x;
- }
- ++i;
- }
-
- if (x > maxLength) {
- if (lastSpace == kNoSpace) {
- insertChar('\n', i - 1);
- } else {
- setChar('\n', lastSpace);
- i = lastSpace + 1;
- }
- }
- }
+U32String operator+(const U32String &x, const uint32 y) {
+ U32String temp(x);
+ temp += y;
+ return temp;
}
-uint64 U32String::asUint64() const {
- uint64 result = 0;
- for (uint32 i = 0; i < _size; ++i) {
- if (_str[i] < '0' || _str[i] > '9') break;
- result = result * 10L + (_str[i] - '0');
+void U32String::insertString(const char *s, uint32 p) {
+ while (*s != '\0') {
+ BaseString::insertChar(*s++, p++);
}
- return result;
}
-void U32String::trim() {
- if (_size == 0)
- return;
-
- makeUnique();
-
- // Trim trailing whitespace
- while (_size >= 1 && isSpace(_str[_size - 1]))
- --_size;
- _str[_size] = 0;
-
- // Trim leading whitespace
- value_type *t = _str;
- while (isSpace(*t))
- t++;
-
- if (t != _str) {
- _size -= t - _str;
- memmove(_str, t, _size + 1);
+void U32String::insertString(const String &s, uint32 p) {
+ for (uint32 i = 0; i < s.size(); ++i) {
+ BaseString::insertChar(s[i], p++);
}
}
@@ -633,7 +148,7 @@ U32String U32String::format(U32String fmt, ...) {
va_list va;
va_start(va, fmt);
- U32String::vformat(fmt.begin(), fmt.end(), output, va);
+ U32String::vformat(fmt.c_str(), fmt.c_str() + fmt.size(), output, va);
va_end(va);
return output;
@@ -645,13 +160,14 @@ U32String U32String::format(const char *fmt, ...) {
Common::U32String fmtU32(fmt);
va_list va;
va_start(va, fmt);
- U32String::vformat(fmtU32.begin(), fmtU32.end(), output, va);
+ U32String::vformat(fmtU32.c_str(), fmtU32.c_str() + fmtU32.size(),
+ output, va);
va_end(va);
return output;
}
-int U32String::vformat(U32String::const_iterator fmt, const U32String::const_iterator inputItrEnd, U32String &output, va_list args) {
+int U32String::vformat(const value_type *fmt, const value_type *fmtEnd, U32String &output, va_list args) {
int int_temp;
char *string_temp;
@@ -664,7 +180,7 @@ int U32String::vformat(U32String::const_iterator fmt, const U32String::const_ite
char buffer[512];
- while (fmt != inputItrEnd) {
+ while (fmt != fmtEnd) {
ch = *fmt++;
if (ch == '%') {
switch (ch = *fmt++) {
@@ -680,10 +196,10 @@ int U32String::vformat(U32String::const_iterator fmt, const U32String::const_ite
break;
case 's':
string_temp = va_arg(args, char *);
- len = strlen(string_temp);
- length += len;
-
+ tempPos = output.size();
output.insertString(string_temp, pos);
+ len = output.size() - tempPos;
+ length += len;
pos += len - 1;
break;
case 'i':
diff --git a/common/ustr.h b/common/ustr.h
index db4d078717..c602b1d1eb 100644
--- a/common/ustr.h
+++ b/common/ustr.h
@@ -25,6 +25,7 @@
#include "common/scummsys.h"
#include "common/str-enc.h"
+#include "common/base-str.h"
namespace Common {
@@ -52,66 +53,36 @@ class UnicodeBiDiText;
* The presence of \0 characters in the string will cause undefined
* behavior in some operations.
*/
-class U32String {
-public:
- static const uint32 npos = 0xFFFFFFFF;
+#ifdef USE_CXX11
+typedef char32_t u32char_type_t;
+#else
+typedef uint32 u32char_type_t;
+#endif
- typedef uint32 value_type;
+class U32String : public BaseString<u32char_type_t> {
+public:
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; }
+ U32String() : BaseString() {}
/** Construct a new string from the given NULL-terminated C string. */
- explicit U32String(const value_type *str);
+ explicit U32String(const value_type *str) : BaseString(str) {}
/** Construct a new string containing exactly len characters read from address str. */
- U32String(const value_type *str, uint32 len);
+ U32String(const value_type *str, uint32 len) : BaseString(str, len) {}
+
+#ifdef USE_CXX11
+ explicit U32String(const uint32 *str) : BaseString((const value_type *) str) {}
+ U32String(const uint32 *str, uint32 len) : BaseString((const value_type *) str, len) {}
+ U32String(const uint32 *beginP, const uint32 *endP) : BaseString((const value_type *) beginP, (const value_type *) endP) {}
+#endif
/** Construct a new string containing the characters between beginP (including) and endP (excluding). */
- U32String(const value_type *beginP, const value_type *endP);
+ U32String(const value_type *beginP, const value_type *endP) : BaseString(beginP, endP) {}
/** Construct a copy of the given string. */
- U32String(const U32String &str);
+ U32String(const U32String &str) : BaseString(str) {}
/** Construct a copy of the given unicode BiDi converted string. */
U32String(const UnicodeBiDiText &txt);
@@ -136,128 +107,16 @@ public:
U32String &operator=(const char *str);
U32String &operator+=(const U32String &str);
U32String &operator+=(value_type c);
- bool operator==(const U32String &x) const;
+ using BaseString<value_type>::operator==;
+ using BaseString<value_type>::operator!=;
bool operator==(const String &x) const;
- bool operator==(const value_type *x) const;
bool operator==(const char *x) const;
- bool operator!=(const U32String &x) const;
bool operator!=(const String &x) const;
- bool operator!=(const value_type *x) const;
bool operator!=(const char *x) const;
- bool operator<(const U32String &x) const;
- bool operator<=(const U32String &x) const;
- bool operator>(const U32String &x) const;
- bool operator>=(const U32String &x) const;
-
- /**
- * 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;
-
- /**
- * Compares whether two U32String are the same based on memory comparison.
- * This does *not* do comparison based on canonical equivalence.
- */
- bool equals(const String &x) const;
-
- bool contains(value_type x) const;
-
- /**
- * Checks if a given string is present in the internal string or not.
- */
- bool contains(const U32String &otherString) 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];
- }
-
- /** Set character c at position p, replacing the previous character there. */
- void setChar(value_type c, uint32 p) {
- _str[p] = c;
- }
-
- /** Insert character c before position p. */
- void insertChar(value_type c, uint32 p);
- void insertString(String s, uint32 p);
- void insertString(value_type *s, uint32 p);
-
- /**
- * Removes the value at position p from the string.
- * Using this on decomposed characters will not remove the whole
- * character!
- */
- void deleteChar(uint32 p);
-
- /** Remove the last character from the string. */
- void deleteLastChar();
-
- /** Remove all characters from position p to the p + len. If len = String::npos, removes all characters to the end */
- void erase(uint32 p, uint32 len = npos);
-
- /** 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(value_type x, uint32 pos = 0) const;
- 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();
- }
-
/** Python-like method **/
String encode(CodePage page = kUtf8) const;
- void wordWrap(const uint32 maxLength);
-
- uint64 asUint64() const;
-
- void trim();
-
/**
* Print formatted data into a U32String object.
*/
@@ -268,7 +127,7 @@ public:
* Print formatted data into a U32String object. It takes in the
* output by reference and works with iterators.
*/
- static int vformat(U32String::const_iterator fmt, const U32String::const_iterator inputItrEnd, U32String &output, va_list args);
+ static int vformat(const value_type *fmt, const value_type *fmtEnd, U32String &output, va_list args);
/**
* Helper function for vformat, convert an int to string
@@ -276,19 +135,21 @@ public:
*/
static char* itoa(int num, char* str, int base);
-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);
- void initWithCStr(const char *str, uint32 len);
+ using BaseString<value_type>::insertString;
+ void insertString(const char *s, uint32 p);
+ void insertString(const String &s, uint32 p);
+
+ const uint32 *u32_str() const {
+ return (const uint32 *) _str;
+ }
+private:
void encodeUTF8(String &dst) const;
void encodeOneByte(String &dst, CodePage page) const;
};
U32String operator+(const U32String &x, const U32String &y);
+U32String operator+(const U32String &x, U32String::value_type y);
/** @} */
diff --git a/common/winexe.h b/common/winexe.h
index 1bf203338a..b6c21cc543 100644
--- a/common/winexe.h
+++ b/common/winexe.h
@@ -94,7 +94,7 @@ private:
};
struct WinResourceID_Hash {
- uint operator()(const WinResourceID &id) const { return hashit(id.toString()); }
+ uint operator()(const WinResourceID &id) const { return id.toString().hash(); }
};
struct WinResourceID_EqualTo {
diff --git a/devtools/create_titanic/base-str.cpp b/devtools/create_titanic/base-str.cpp
new file mode 100644
index 0000000000..f5ebe1ad3b
--- /dev/null
+++ b/devtools/create_titanic/base-str.cpp
@@ -0,0 +1,2 @@
+#define SCUMMVM_UTIL 1
+#include "../common/base-str.cpp"
diff --git a/devtools/create_titanic/hash-str.h b/devtools/create_titanic/hash-str.h
index b9f6d503f8..2e0bdafd1a 100644
--- a/devtools/create_titanic/hash-str.h
+++ b/devtools/create_titanic/hash-str.h
@@ -24,7 +24,7 @@
#define COMMON_HASH_STR_H
#include "hashmap.h"
-#include "str.h"
+#include "common/str.h"
namespace Common {
diff --git a/devtools/create_titanic/module.mk b/devtools/create_titanic/module.mk
index b86fe18a2e..1a9e7bbb14 100644
--- a/devtools/create_titanic/module.mk
+++ b/devtools/create_titanic/module.mk
@@ -12,6 +12,7 @@ MODULE_OBJS := \
script_ranges.o \
script_responses.o \
script_states.o \
+ base-str.o \
str.o \
tag_maps.o \
winexe.o \
diff --git a/devtools/create_titanic/str.cpp b/devtools/create_titanic/str.cpp
index 6aa66d0d20..5623f82718 100644
--- a/devtools/create_titanic/str.cpp
+++ b/devtools/create_titanic/str.cpp
@@ -1,786 +1,2 @@
-/* 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/hash-str.h"
-#include "common/list.h"
-#include "memorypool.h"
-#include "common/str.h"
-#include "common/util.h"
-
-namespace Common {
-
-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;
-
- _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
- // 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 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;
-
- _str[0] = c;
- _str[1] = 0;
-
- _size = (c == 0) ? 0 : 1;
- return *this;
-}
-
-String &String::operator+=(const char *str) {
- if (_str <= str && str <= _str + _size)
- return operator+=(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+=(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;
-}
-
-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::erase(uint32 p, uint32 len) {
- assert(p < _size);
-
- makeUnique();
- // If len == npos or p + len is over the end, remove all the way to the end
- if (len == npos || p + len >= _size) {
- // Delete char at p as well. So _size = (p - 1) + 1
- _size = p;
- // Null terminate
- _str[_size] = 0;
- return;
- }
-
- for ( ; p + len <= _size; p++) {
- _str[p] = _str[p + len];
- }
- _size -= len;
-}
-
-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]);
-}
-
-uint String::hash() const {
- return hashit(c_str());
-}
-
-// static
-String String::format(const char *fmt, ...) {
- String output;
-
- va_list va;
- va_start(va, fmt);
- output = String::vformat(fmt, va);
- va_end(va);
-
- return output;
-}
-
-// static
-String String::vformat(const char *fmt, va_list args) {
- String output;
- assert(output.isStorageIntern());
-
- va_list va;
- scumm_va_copy(va, args);
- int len = vsnprintf(output._str, _builtinCapacity, fmt, va);
- va_end(va);
-
- if (len == -1 || len == _builtinCapacity - 1) {
- // MSVC and IRIX don't return the size the full string would take up.
- // MSVC returns -1, IRIX returns the number of characters actually written,
- // which is at the most the size of the buffer minus one, as the string is
- // truncated to fit.
-
- // We assume MSVC failed to output the correct, null-terminated string
- // if the return value is either -1 or size.
- // For IRIX, because we lack a better mechanism, we assume failure
- // if the return value equals size - 1.
- // The downside to this is that whenever we try to format a string where the
- // size is 1 below the built-in capacity, the size is needlessly increased.
-
- // Try increasing the size of the string until it fits.
- int size = _builtinCapacity;
- do {
- size *= 2;
- output.ensureCapacity(size - 1, false);
- assert(!output.isStorageIntern());
- size = output._extern._capacity;
-
- scumm_va_copy(va, args);
- len = vsnprintf(output._str, size, fmt, va);
- va_end(va);
- } while (len == -1 || len >= size - 1);
- 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);
- scumm_va_copy(va, args);
- 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;
-}
-
-String lastPathComponent(const 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 String();
-
- // Now scan the whole component
- const char *first = last - 1;
- while (first > str && *first != sep)
- --first;
-
- if (*first == sep)
- first++;
-
- return String(first, last);
-}
-
-String normalizePath(const String &path, const char sep) {
- if (path.empty())
- return path;
-
- const char *cur = path.c_str();
- String result;
-
- // If there is a leading slash, preserve that:
- if (*cur == sep) {
- result += sep;
- // Skip over multiple leading slashes, so "//" equals "/"
- while (*cur == sep)
- ++cur;
- }
-
- // Scan for path components till the end of the String
- List<String> comps;
- 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 String component(start, cur);
-
- if (component.empty() || component == ".") {
- // Skip empty components and dot components
- } else if (!comps.empty() && component == ".." && comps.back() != "..") {
- // If stack is non-empty and top is not "..", remove top
- comps.pop_back();
- } else {
- // Add the component to the stack
- comps.push_back(component);
- }
-
- // Skip over separator chars
- while (*cur == sep)
- cur++;
- }
-
- // Finally, assemble all components back into a path
- while (!comps.empty()) {
- result += comps.front();
- comps.pop_front();
- if (!comps.empty())
- result += sep;
- }
-
- return result;
-}
-
-size_t strlcpy(char *dst, const char *src, size_t size) {
- // Our backup of the source's start, we need this
- // to calculate the source's length.
- const char * const srcStart = src;
-
- // In case a non-empty size was specified we
- // copy over (size - 1) bytes at max.
- if (size != 0) {
- // Copy over (size - 1) bytes at max.
- while (--size != 0) {
- if ((*dst++ = *src) == 0)
- break;
- ++src;
- }
-
- // In case the source string was longer than the
- // destination, we need to add a terminating
- // zero.
- if (size == 0)
- *dst = 0;
- }
-
- // Move to the terminating zero of the source
- // string, we need this to determine the length
- // of the source string.
- while (*src)
- ++src;
-
- // Return the source string's length.
- return src - srcStart;
-}
-
-size_t strlcat(char *dst, const char *src, size_t size) {
- // In case the destination buffer does not contain
- // space for at least 1 character, we will just
- // return the source string's length.
- if (size == 0)
- return strlen(src);
-
- // Our backup of the source's start, we need this
- // to calculate the source's length.
- const char * const srcStart = src;
-
- // Our backup of the destination's start, we need
- // this to calculate the destination's length.
- const char * const dstStart = dst;
-
- // Search the end of the destination, but do not
- // move past the terminating zero.
- while (size-- != 0 && *dst != 0)
- ++dst;
-
- // Calculate the destination's length;
- const size_t dstLength = dst - dstStart;
-
- // In case we reached the end of the destination
- // buffer before we had a chance to append any
- // characters we will just return the destination
- // length plus the source string's length.
- if (size == 0)
- return dstLength + strlen(srcStart);
-
- // Copy over all of the source that fits
- // the destination buffer. We also need
- // to take the terminating zero we will
- // add into consideration.
- while (size-- != 0 && *src != 0)
- *dst++ = *src++;
- *dst = 0;
-
- // Move to the terminating zero of the source
- // string, we need this to determine the length
- // of the source string.
- while (*src)
- ++src;
-
- // Return the total length of the result string
- return dstLength + (src - srcStart);
-}
-
-} // End of namespace Common
-
-// Portable implementation of stricmp / strcasecmp / strcmpi.
-// TODO: Rename this to Common::strcasecmp
-int scumm_stricmp(const char *s1, const char *s2) {
- byte l1, l2;
- do {
- // Don't use ++ inside tolower, in case the macro uses its
- // arguments more than once.
- l1 = (byte)*s1++;
- l1 = tolower(l1);
- l2 = (byte)*s2++;
- l2 = tolower(l2);
- } while (l1 == l2 && l1 != 0);
- return l1 - l2;
-}
-
-// Portable implementation of strnicmp / strncasecmp / strncmpi.
-// TODO: Rename this to Common::strncasecmp
-int scumm_strnicmp(const char *s1, const char *s2, uint n) {
- byte l1, l2;
- do {
- if (n-- == 0)
- return 0; // no difference found so far -> signal equality
-
- // Don't use ++ inside tolower, in case the macro uses its
- // arguments more than once.
- l1 = (byte)*s1++;
- l1 = tolower(l1);
- l2 = (byte)*s2++;
- l2 = tolower(l2);
- } while (l1 == l2 && l1 != 0);
- return l1 - l2;
-}
+#define SCUMMVM_UTIL
+#include "../common/str.cpp"
diff --git a/devtools/create_titanic/str.h b/devtools/create_titanic/str.h
deleted file mode 100644
index 2f954dcfca..0000000000
--- a/devtools/create_titanic/str.h
+++ /dev/null
@@ -1,386 +0,0 @@
-/* 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_STRING_H
-#define COMMON_STRING_H
-
-#include "common/scummsys.h"
-
-#include <stdarg.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.
- *
- * The presence of \0 characters in the string will cause undefined
- * behavior in some operations.
- */
-class String {
-public:
- static const uint32 npos = 0xFFFFFFFF;
-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:
- /** 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;
-
- inline const char *c_str() const { return _str; }
- inline uint size() const { return _size; }
-
- inline bool empty() const { return (_size == 0); }
- char firstChar() const { return (_size > 0) ? _str[0] : 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);
-
- /** Remove all characters from position p to the p + len. If len = String::npos, removes all characters to the end */
- void erase(uint32 p, uint32 len = npos);
-
- /** 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;
-
- /**
- * Print formatted data into a String object. Similar to sprintf,
- * except that it stores the result in (variably sized) String
- * instead of a fixed size buffer.
- */
- static String format(const char *fmt, ...) GCC_PRINTF(1,2);
-
- /**
- * Print formatted data into a String object. Similar to vsprintf,
- * except that it stores the result in (variably sized) String
- * instead of a fixed size buffer.
- */
- 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;
-
- 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();
- }
-
-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.
- */
-String lastPathComponent(const String &path, const char sep);
-
-/**
- * Normalize a given 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
- */
-String normalizePath(const 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.
- * "#": any decimal digit, 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
- * String: monkey.s01 Pattern: monkey.s## => true
- * String: monkey.s01 Pattern: monkey.### => 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);
-
-
-/**
- * Take a 32 bit value and turn it into a four character string, where each of
- * the four bytes is turned into one character. Most significant byte is printed
- * first.
- */
-String tag2string(uint32 tag);
-
-/**
- * Copy up to size - 1 characters from src to dst and also zero terminate the
- * result. Note that src must be a zero terminated string.
- *
- * In case size is zero this function just returns the length of the source
- * string.
- *
- * @note This is modeled after OpenBSD's strlcpy. See the manpage here:
- * http://www.openbsd.org/cgi-bin/man.cgi?query=strlcpy
- *
- * @param dst The destination buffer.
- * @param src The source string.
- * @param size The size of the destination buffer.
- * @return The length of the (non-truncated) result, i.e. strlen(src).
- */
-size_t strlcpy(char *dst, const char *src, size_t size);
-
-/**
- * Append the string src to the string dst. Note that both src and dst must be
- * zero terminated. The result will be zero terminated. At most
- * "size - strlen(dst) - 1" bytes will be appended.
- *
- * In case the dst string does not contain a zero within the first "size" bytes
- * the dst string will not be changed and size + strlen(src) is returned.
- *
- * @note This is modeled after OpenBSD's strlcat. See the manpage here:
- * http://www.openbsd.org/cgi-bin/man.cgi?query=strlcat
- *
- * @param dst The string the source string should be appended to.
- * @param src The source string.
- * @param size The (total) size of the destination buffer.
- * @return The length of the (non-truncated) result. That is
- * strlen(dst) + strlen(src). In case strlen(dst) > size
- * size + strlen(src) is returned.
- */
-size_t strlcat(char *dst, const char *src, size_t size);
-
-/**
- * Convenience wrapper for tag2string which "returns" a C string.
- * Note: It is *NOT* safe to do anything with the return value other than directly
- * copying or printing it.
- */
-#define tag2str(x) Common::tag2string(x).c_str()
-
-
-} // End of namespace Common
-
-extern int scumm_stricmp(const char *s1, const char *s2);
-extern int scumm_strnicmp(const char *s1, const char *s2, uint n);
-
-#endif
diff --git a/devtools/create_titanic/winexe.cpp b/devtools/create_titanic/winexe.cpp
index 49be23dbd4..6371598d57 100644
--- a/devtools/create_titanic/winexe.cpp
+++ b/devtools/create_titanic/winexe.cpp
@@ -22,7 +22,7 @@
#define FORBIDDEN_SYMBOL_ALLOW_ALL
-#include "str.h"
+#include "common/str.h"
#include "winexe.h"
namespace Common {
diff --git a/devtools/create_titanic/winexe.h b/devtools/create_titanic/winexe.h
index 6bfe2a25a0..e5d7fb84cc 100644
--- a/devtools/create_titanic/winexe.h
+++ b/devtools/create_titanic/winexe.h
@@ -25,7 +25,7 @@
#include "file.h"
#include "hash-str.h"
-#include "str.h"
+#include "common/str.h"
namespace Common {
diff --git a/devtools/create_titanic/winexe_pe.cpp b/devtools/create_titanic/winexe_pe.cpp
index f55740f692..6d38261787 100644
--- a/devtools/create_titanic/winexe_pe.cpp
+++ b/devtools/create_titanic/winexe_pe.cpp
@@ -23,7 +23,7 @@
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "file.h"
-#include "str.h"
+#include "common/str.h"
#include "winexe_pe.h"
#include "common/array.h"
#include "common/endian.h"
diff --git a/devtools/create_titanic/winexe_pe.h b/devtools/create_titanic/winexe_pe.h
index 6ab7ae847a..dd2603750e 100644
--- a/devtools/create_titanic/winexe_pe.h
+++ b/devtools/create_titanic/winexe_pe.h
@@ -26,7 +26,7 @@
#include "file.h"
#include "hash-str.h"
#include "hashmap.h"
-#include "str.h"
+#include "common/str.h"
#include "winexe.h"
namespace Common {
diff --git a/devtools/create_xeen/base-str.cpp b/devtools/create_xeen/base-str.cpp
new file mode 100644
index 0000000000..f5ebe1ad3b
--- /dev/null
+++ b/devtools/create_xeen/base-str.cpp
@@ -0,0 +1,2 @@
+#define SCUMMVM_UTIL 1
+#include "../common/base-str.cpp"
diff --git a/devtools/create_xeen/module.mk b/devtools/create_xeen/module.mk
index eabd739b4f..0714fbceb6 100644
--- a/devtools/create_xeen/module.mk
+++ b/devtools/create_xeen/module.mk
@@ -9,6 +9,7 @@ MODULE_OBJS := \
map.o \
memorypool.o \
str.o \
+ base-str.o \
swords.o
# Set the name of the executable
diff --git a/devtools/create_xeen/str.cpp b/devtools/create_xeen/str.cpp
index 6aa66d0d20..5623f82718 100644
--- a/devtools/create_xeen/str.cpp
+++ b/devtools/create_xeen/str.cpp
@@ -1,786 +1,2 @@
-/* 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/hash-str.h"
-#include "common/list.h"
-#include "memorypool.h"
-#include "common/str.h"
-#include "common/util.h"
-
-namespace Common {
-
-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;
-
- _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
- // 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 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;
-
- _str[0] = c;
- _str[1] = 0;
-
- _size = (c == 0) ? 0 : 1;
- return *this;
-}
-
-String &String::operator+=(const char *str) {
- if (_str <= str && str <= _str + _size)
- return operator+=(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+=(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;
-}
-
-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::erase(uint32 p, uint32 len) {
- assert(p < _size);
-
- makeUnique();
- // If len == npos or p + len is over the end, remove all the way to the end
- if (len == npos || p + len >= _size) {
- // Delete char at p as well. So _size = (p - 1) + 1
- _size = p;
- // Null terminate
- _str[_size] = 0;
- return;
- }
-
- for ( ; p + len <= _size; p++) {
- _str[p] = _str[p + len];
- }
- _size -= len;
-}
-
-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]);
-}
-
-uint String::hash() const {
- return hashit(c_str());
-}
-
-// static
-String String::format(const char *fmt, ...) {
- String output;
-
- va_list va;
- va_start(va, fmt);
- output = String::vformat(fmt, va);
- va_end(va);
-
- return output;
-}
-
-// static
-String String::vformat(const char *fmt, va_list args) {
- String output;
- assert(output.isStorageIntern());
-
- va_list va;
- scumm_va_copy(va, args);
- int len = vsnprintf(output._str, _builtinCapacity, fmt, va);
- va_end(va);
-
- if (len == -1 || len == _builtinCapacity - 1) {
- // MSVC and IRIX don't return the size the full string would take up.
- // MSVC returns -1, IRIX returns the number of characters actually written,
- // which is at the most the size of the buffer minus one, as the string is
- // truncated to fit.
-
- // We assume MSVC failed to output the correct, null-terminated string
- // if the return value is either -1 or size.
- // For IRIX, because we lack a better mechanism, we assume failure
- // if the return value equals size - 1.
- // The downside to this is that whenever we try to format a string where the
- // size is 1 below the built-in capacity, the size is needlessly increased.
-
- // Try increasing the size of the string until it fits.
- int size = _builtinCapacity;
- do {
- size *= 2;
- output.ensureCapacity(size - 1, false);
- assert(!output.isStorageIntern());
- size = output._extern._capacity;
-
- scumm_va_copy(va, args);
- len = vsnprintf(output._str, size, fmt, va);
- va_end(va);
- } while (len == -1 || len >= size - 1);
- 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);
- scumm_va_copy(va, args);
- 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;
-}
-
-String lastPathComponent(const 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 String();
-
- // Now scan the whole component
- const char *first = last - 1;
- while (first > str && *first != sep)
- --first;
-
- if (*first == sep)
- first++;
-
- return String(first, last);
-}
-
-String normalizePath(const String &path, const char sep) {
- if (path.empty())
- return path;
-
- const char *cur = path.c_str();
- String result;
-
- // If there is a leading slash, preserve that:
- if (*cur == sep) {
- result += sep;
- // Skip over multiple leading slashes, so "//" equals "/"
- while (*cur == sep)
- ++cur;
- }
-
- // Scan for path components till the end of the String
- List<String> comps;
- 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 String component(start, cur);
-
- if (component.empty() || component == ".") {
- // Skip empty components and dot components
- } else if (!comps.empty() && component == ".." && comps.back() != "..") {
- // If stack is non-empty and top is not "..", remove top
- comps.pop_back();
- } else {
- // Add the component to the stack
- comps.push_back(component);
- }
-
- // Skip over separator chars
- while (*cur == sep)
- cur++;
- }
-
- // Finally, assemble all components back into a path
- while (!comps.empty()) {
- result += comps.front();
- comps.pop_front();
- if (!comps.empty())
- result += sep;
- }
-
- return result;
-}
-
-size_t strlcpy(char *dst, const char *src, size_t size) {
- // Our backup of the source's start, we need this
- // to calculate the source's length.
- const char * const srcStart = src;
-
- // In case a non-empty size was specified we
- // copy over (size - 1) bytes at max.
- if (size != 0) {
- // Copy over (size - 1) bytes at max.
- while (--size != 0) {
- if ((*dst++ = *src) == 0)
- break;
- ++src;
- }
-
- // In case the source string was longer than the
- // destination, we need to add a terminating
- // zero.
- if (size == 0)
- *dst = 0;
- }
-
- // Move to the terminating zero of the source
- // string, we need this to determine the length
- // of the source string.
- while (*src)
- ++src;
-
- // Return the source string's length.
- return src - srcStart;
-}
-
-size_t strlcat(char *dst, const char *src, size_t size) {
- // In case the destination buffer does not contain
- // space for at least 1 character, we will just
- // return the source string's length.
- if (size == 0)
- return strlen(src);
-
- // Our backup of the source's start, we need this
- // to calculate the source's length.
- const char * const srcStart = src;
-
- // Our backup of the destination's start, we need
- // this to calculate the destination's length.
- const char * const dstStart = dst;
-
- // Search the end of the destination, but do not
- // move past the terminating zero.
- while (size-- != 0 && *dst != 0)
- ++dst;
-
- // Calculate the destination's length;
- const size_t dstLength = dst - dstStart;
-
- // In case we reached the end of the destination
- // buffer before we had a chance to append any
- // characters we will just return the destination
- // length plus the source string's length.
- if (size == 0)
- return dstLength + strlen(srcStart);
-
- // Copy over all of the source that fits
- // the destination buffer. We also need
- // to take the terminating zero we will
- // add into consideration.
- while (size-- != 0 && *src != 0)
- *dst++ = *src++;
- *dst = 0;
-
- // Move to the terminating zero of the source
- // string, we need this to determine the length
- // of the source string.
- while (*src)
- ++src;
-
- // Return the total length of the result string
- return dstLength + (src - srcStart);
-}
-
-} // End of namespace Common
-
-// Portable implementation of stricmp / strcasecmp / strcmpi.
-// TODO: Rename this to Common::strcasecmp
-int scumm_stricmp(const char *s1, const char *s2) {
- byte l1, l2;
- do {
- // Don't use ++ inside tolower, in case the macro uses its
- // arguments more than once.
- l1 = (byte)*s1++;
- l1 = tolower(l1);
- l2 = (byte)*s2++;
- l2 = tolower(l2);
- } while (l1 == l2 && l1 != 0);
- return l1 - l2;
-}
-
-// Portable implementation of strnicmp / strncasecmp / strncmpi.
-// TODO: Rename this to Common::strncasecmp
-int scumm_strnicmp(const char *s1, const char *s2, uint n) {
- byte l1, l2;
- do {
- if (n-- == 0)
- return 0; // no difference found so far -> signal equality
-
- // Don't use ++ inside tolower, in case the macro uses its
- // arguments more than once.
- l1 = (byte)*s1++;
- l1 = tolower(l1);
- l2 = (byte)*s2++;
- l2 = tolower(l2);
- } while (l1 == l2 && l1 != 0);
- return l1 - l2;
-}
+#define SCUMMVM_UTIL
+#include "../common/str.cpp"
diff --git a/engines/glk/adrift/os_glk.cpp b/engines/glk/adrift/os_glk.cpp
index 372fcd1f3f..b4b9e4c5e2 100644
--- a/engines/glk/adrift/os_glk.cpp
+++ b/engines/glk/adrift/os_glk.cpp
@@ -2811,7 +2811,7 @@ static int gsc_startup_code(Common::SeekableReadStream *game_stream, int restore
* Display a brief loading game message; here we have to use a timeout
* to ensure that the text is flushed to Glk.
*/
- g_vm->glk_put_string_uni(_("Loading game...\n").c_str());
+ g_vm->glk_put_string_uni(_("Loading game...\n").u32_str());
if (g_vm->glk_gestalt(gestalt_Timer, 0)) {
event_t event;
diff --git a/engines/glk/advsys/glk_interface.cpp b/engines/glk/advsys/glk_interface.cpp
index e1f08d79cc..badfbefdb3 100644
--- a/engines/glk/advsys/glk_interface.cpp
+++ b/engines/glk/advsys/glk_interface.cpp
@@ -41,7 +41,7 @@ void GlkInterface::print(const Common::U32String &msg) {
// Don't print out text if loading a savegame directly from the launcher, since we don't
// want any of the intro text displayed by the startup code to show
if (_saveSlot == -1)
- glk_put_string_stream_uni(glk_window_get_stream(_window), msg.c_str());
+ glk_put_string_stream_uni(glk_window_get_stream(_window), msg.u32_str());
}
void GlkInterface::print(int number) {
diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 0416908de5..7900202a76 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -139,7 +139,7 @@ void Comprehend::print(const Common::U32String fmt, ...) {
va_end(argp);
glk_put_string_stream_uni(glk_window_get_stream(_bottomWindow),
- outputMsg.c_str());
+ outputMsg.u32_str());
}
void Comprehend::readLine(char *buffer, size_t maxLen) {
diff --git a/engines/glk/glk_api.cpp b/engines/glk/glk_api.cpp
index d9ea372d00..5398d1c8ef 100644
--- a/engines/glk/glk_api.cpp
+++ b/engines/glk/glk_api.cpp
@@ -60,7 +60,7 @@ GlkAPI::GlkAPI(OSystem *syst, const GlkGameDescription &gameDesc) :
}
void GlkAPI::glk_exit(void) {
- glk_put_string_uni(_("[ press any key to exit ]").c_str());
+ glk_put_string_uni(_("[ press any key to exit ]").u32_str());
_events->waitForPress();
// Trigger a ScumMVM shutdown of game
diff --git a/engines/glk/scott/scott.cpp b/engines/glk/scott/scott.cpp
index e9c9fa58dc..5fdf2261a1 100644
--- a/engines/glk/scott/scott.cpp
+++ b/engines/glk/scott/scott.cpp
@@ -176,7 +176,7 @@ void Scott::display(winid_t w, const Common::U32String fmt, ...) {
Common::U32String::vformat(fmt.begin(), fmt.end(), msg, ap);
va_end(ap);
- glk_put_string_stream_uni(glk_window_get_stream(w), msg.c_str());
+ glk_put_string_stream_uni(glk_window_get_stream(w), msg.u32_str());
}
void Scott::delay(int seconds) {
diff --git a/engines/glk/window_text_buffer.cpp b/engines/glk/window_text_buffer.cpp
index 19cfbb5040..870ea999b1 100644
--- a/engines/glk/window_text_buffer.cpp
+++ b/engines/glk/window_text_buffer.cpp
@@ -1304,7 +1304,7 @@ void TextBufferWindow::acceptReadLine(uint32 arg) {
if (_historyPos < 0)
_historyPos += HISTORYLEN;
s = _history[_historyPos];
- putTextUni(s.c_str(), s.size(), _inFence, _numChars - _inFence);
+ putTextUni(s.u32_str(), s.size(), _inFence, _numChars - _inFence);
break;
case keycode_Down:
@@ -1314,7 +1314,7 @@ void TextBufferWindow::acceptReadLine(uint32 arg) {
if (_historyPos >= HISTORYLEN)
_historyPos -= HISTORYLEN;
s = _history[_historyPos];
- putTextUni(s.c_str(), s.size(), _inFence, _numChars - _inFence);
+ putTextUni(s.u32_str(), s.size(), _inFence, _numChars - _inFence);
break;
// Cursor movement keys, during line input.
diff --git a/engines/glk/zcode/zcode.cpp b/engines/glk/zcode/zcode.cpp
index 179a4b99f0..d5a5520605 100644
--- a/engines/glk/zcode/zcode.cpp
+++ b/engines/glk/zcode/zcode.cpp
@@ -142,7 +142,7 @@ Common::Error ZCode::saveGameState(int slot, const Common::String &desc, bool is
file->close();
if (!success)
- print_string_uni(_("Error writing save file\n").c_str());
+ print_string_uni(_("Error writing save file\n").u32_str());
return Common::kNoError;
diff --git a/gui/widgets/popup.cpp b/gui/widgets/popup.cpp
index 6bc8f05cc9..148abd7be0 100644
--- a/gui/widgets/popup.cpp
+++ b/gui/widgets/popup.cpp
@@ -475,7 +475,7 @@ void PopUpWidget::handleMouseWheel(int x, int y, int direction) {
// Skip separator entries
while ((newSelection >= 0) && (newSelection < (int)_entries.size()) &&
- _entries[newSelection].name.equals("")) {
+ _entries[newSelection].name.empty()) {
newSelection += direction;
}
More information about the Scummvm-git-logs
mailing list