From f9b666924149bd529f37dc94dc459f351e551761 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 1 May 2023 23:03:38 +0200 Subject: [PATCH] COMMON: Add DBCS-oriented variant of String --- common/dbcs-str.cpp | 230 ++++++++++++++++++++++++++++++++++++++++++++ common/dbcs-str.h | 172 +++++++++++++++++++++++++++++++++ common/module.mk | 1 + common/str-base.cpp | 1 + 4 files changed, 404 insertions(+) create mode 100644 common/dbcs-str.cpp create mode 100644 common/dbcs-str.h diff --git a/common/dbcs-str.cpp b/common/dbcs-str.cpp new file mode 100644 index 00000000000..c286872947e --- /dev/null +++ b/common/dbcs-str.cpp @@ -0,0 +1,230 @@ +/* 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 3 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, see . + * + */ + +#include "common/dbcs-str.h" +#include "common/str.h" +#include "common/memorypool.h" +#include "common/util.h" + +namespace Common { + +void DBCSString::decodeDBCS(const char *str, uint32 len) { + for (uint i = 0; i < len; ) { + if ((str[i] & 0x80) && i + 1 < len) { + operator+=((str[i] << 8) | (str[i+1] & 0xff)); + i += 2; + } else if (str[i] & 0x80) { + operator+=(str[i] << 8); + i++; + } else { + operator+=(str[i]); + i++; + } + } +} + +DBCSString::DBCSString(const char *str) : BaseString() { + if (str == nullptr) { + _storage[0] = 0; + _size = 0; + } else { + decodeDBCS(str, strlen(str)); + } +} + +DBCSString::DBCSString(const char *str, uint32 len) : BaseString() { + decodeDBCS(str, len); +} + +DBCSString::DBCSString(const char *beginP, const char *endP) : BaseString() { + assert(endP >= beginP); + decodeDBCS(beginP, endP - beginP); +} + +DBCSString::DBCSString(const String &str) : BaseString() { + decodeDBCS(str.c_str(), str.size()); +} + +DBCSString::DBCSString(uint16 c) : BaseString() { + _storage[0] = c; + _storage[1] = 0; + + _size = (c == 0) ? 0 : 1; +} + +DBCSString &DBCSString::operator=(const DBCSString &str) { + assign(str); + return *this; +} + +DBCSString &DBCSString::operator=(DBCSString &&str) { + assign(static_cast(str)); + return *this; +} + +DBCSString &DBCSString::operator=(const String &str) { + clear(); + decodeDBCS(str.c_str(), str.size()); + return *this; +} + +DBCSString &DBCSString::operator=(const value_type *str) { + return DBCSString::operator=(DBCSString(str)); +} + +DBCSString &DBCSString::operator=(const char *str) { + clear(); + decodeDBCS(str, strlen(str)); + return *this; +} + +DBCSString &DBCSString::operator+=(const DBCSString &str) { + if (&str == this) { + return operator+=(DBCSString(str)); + } + + int len = str._size; + if (len > 0) { + ensureCapacity(_size + len, true); + + memcpy(_str + _size, str._str, (len + 1) * sizeof(value_type)); + _size += len; + } + return *this; +} + +DBCSString &DBCSString::operator+=(value_type c) { + ensureCapacity(_size + 1, true); + + _str[_size++] = c; + _str[_size] = 0; + + return *this; +} + +bool DBCSString::operator==(const String &x) const { + return equalsC(x.c_str()); +} + +bool DBCSString::operator==(const char *x) const { + return equalsC(x); +} + +bool DBCSString::operator!=(const String &x) const { + return !equalsC(x.c_str()); +} + +bool DBCSString::operator!=(const char *x) const { + return !equalsC(x); +} + +DBCSString operator+(const DBCSString &x, const DBCSString &y) { + DBCSString temp(x); + temp += y; + return temp; +} + +DBCSString operator+(const DBCSString &x, const DBCSString::value_type y) { + DBCSString temp(x); + temp += y; + return temp; +} + +DBCSString DBCSString::substr(size_t pos, size_t len) const { + if (pos >= _size) + return DBCSString(); + else if (len == npos) + return DBCSString(_str + pos); + else + return DBCSString(_str + pos, MIN((size_t)_size - pos, len)); +} + +void DBCSString::insertString(const char *s, uint32 p) { + insertString(DBCSString(s), p); +} + +void DBCSString::insertString(const String &s, uint32 p) { + insertString(DBCSString(s), p); +} + +void DBCSString::replace(uint32 pos, uint32 count, const DBCSString &str) { + replace(pos, count, str, 0, str._size); +} + +void DBCSString::replace(iterator begin_, iterator end_, const DBCSString &str) { + replace(begin_ - _str, end_ - begin_, str._str, 0, str._size); +} + +void DBCSString::replace(uint32 posOri, uint32 countOri, const DBCSString &str, + uint32 posDest, uint32 countDest) { + replace(posOri, countOri, str._str, posDest, countDest); +} + +void DBCSString::replace(uint32 posOri, uint32 countOri, const uint16 *str, + uint32 posDest, uint32 countDest) { + + // 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 + for (uint32 i = _size; i >= posOri + countDest; i--) + _str[i] = _str[i - offset]; + + } 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 + offset <= _size; i++) + _str[i] = _str[i + offset]; + + _size -= offset; + } else { + makeUnique(); + } + + // Copy the replaced part of the string + for (uint32 i = 0; i < countDest; i++) + _str[posOri + i] = str[posDest + i]; + +} + +String DBCSString::convertToString() const { + Common::String r; + for (uint i = 0; i < size(); i++) { + if (_str[i] >= 0x100) { + r += _str[i] >> 8; + r += _str[i] & 0xff; + } else + r += _str[i]; + + } + return r; +} + +} // End of namespace Common diff --git a/common/dbcs-str.h b/common/dbcs-str.h new file mode 100644 index 00000000000..dc66d555953 --- /dev/null +++ b/common/dbcs-str.h @@ -0,0 +1,172 @@ +/* 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 3 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, see . + * + */ + +#ifndef COMMON_DBCS_STR_H +#define COMMON_DBCS_STR_H + +#include "common/scummsys.h" +#include "common/util.h" +#include "common/str-enc.h" +#include "common/str-base.h" + +namespace Common { + +class String; + +/** + * A simple string class for DBCS strings in ScummVM. + * + * The presence of \0 characters in the string will cause undefined + * behavior in some operations. + */ + +class DBCSString : public BaseString { +public: + typedef uint32 unsigned_type; /*!< Unsigned version of the underlying type. */ +public: + /** Construct a new empty string. */ + constexpr DBCSString() : BaseString() {} + + /** Construct a new string from the given null-terminated C string. */ + explicit DBCSString(const value_type *str) : BaseString(str) {} + + /** Construct a new string containing exactly @p len characters read from address @p str. */ + DBCSString(const value_type *str, uint32 len) : BaseString(str, len) {} + + explicit DBCSString(const uint32 *str) : BaseString((const value_type *) str) {} + DBCSString(const uint32 *str, uint32 len) : BaseString((const value_type *) str, len) {} + DBCSString(const uint32 *beginP, const uint32 *endP) : BaseString((const value_type *) beginP, (const value_type *) endP) {} + + /** Construct a new string containing the characters between @p beginP (including) and @p endP (excluding). */ + DBCSString(const value_type *beginP, const value_type *endP) : BaseString(beginP, endP) {} + + /** Construct a copy of the given string. */ + DBCSString(const DBCSString &str) : BaseString(str) {} + + /** Construct a string by moving an existing string. */ + DBCSString(DBCSString &&str) : BaseString(static_cast &&>(str)) {} + + /** Construct a new string from the given null-terminated C string that uses the given @p page encoding. */ + explicit DBCSString(const char *str); + + /** Construct a new string containing exactly @p len characters read from address @p str. */ + DBCSString(const char *str, uint32 len); + + /** Construct a new string containing the characters between @p beginP (including) and @p endP (excluding). */ + DBCSString(const char *beginP, const char *endP); + + /** Construct a copy of the given string. */ + explicit DBCSString(const String &str); + + /** Construct a string consisting of the given character. */ + explicit DBCSString(value_type c); + + /** Assign a given string to this string. */ + DBCSString &operator=(const DBCSString &str); + + /** Move a given string to this string. */ + DBCSString &operator=(DBCSString &&str); + + /** @overload */ + DBCSString &operator=(const String &str); + + /** @overload */ + DBCSString &operator=(const value_type *str); + + /** @overload */ + DBCSString &operator=(const char *str); + + /** Append the given string to this string. */ + DBCSString &operator+=(const DBCSString &str); + + /** @overload */ + DBCSString &operator+=(value_type c); + + using BaseString::operator==; + using BaseString::operator!=; + + /** Check whether this string is identical to string @p x. */ + bool operator==(const String &x) const; + + /** @overload */ + bool operator==(const char *x) const; + + /** Check whether this string is different than string @p x. */ + bool operator!=(const String &x) const; + + /** @overload */ + bool operator!=(const char *x) const; + + /** Convert the string to the standard String represantation. */ + String convertToString() const; + + using BaseString::insertString; + void insertString(const char *s, uint32 p); /*!< Insert string @p s into this string at position @p p. */ + void insertString(const String &s, uint32 p); /*!< @overload */ + + /** Return a substring of this string */ + DBCSString substr(size_t pos = 0, size_t len = npos) const; + + /**@{ + * Functions to replace some amount of chars with chars from some other string. + * + * @note The implementation follows that of the STL's std::string: + * http://www.cplusplus.com/reference/string/string/replace/ + * + * @param pos Starting position for the replace in the original string. + * @param count Number of chars to replace from the original string. + * @param str Source of the new chars. + * @param posOri Same as pos + * @param countOri Same as count + * @param posDest Initial position to read str from. + * @param countDest Number of chars to read from str. npos by default. + */ + // Replace 'count' bytes, starting from 'pos' with str. + void replace(uint32 pos, uint32 count, const DBCSString &str); + // Replace the characters in [begin, end) with str._str. + void replace(iterator begin, iterator end, const DBCSString &str); + // Replace _str[posOri, posOri + countOri) with + // str._str[posDest, posDest + countDest) + void replace(uint32 posOri, uint32 countOri, const DBCSString &str, + uint32 posDest, uint32 countDest); + // Replace _str[posOri, posOri + countOri) with + // str[posDest, posDest + countDest) + void replace(uint32 posOri, uint32 countOri, const uint16 *str, + uint32 posDest, uint32 countDest); + /**@}*/ + +private: + void decodeDBCS(const char *str, uint32 len); + + friend class String; +}; + +/** Concatenate strings @p x and @p y. */ +DBCSString operator+(const DBCSString &x, const DBCSString &y); + +/** Append the given @p y character to the given @p x string. */ +DBCSString operator+(const DBCSString &x, DBCSString::value_type y); + +/** @} */ + +} // End of namespace Common + +#endif diff --git a/common/module.mk b/common/module.mk index 0f5f40f0b09..6cc1f16ade7 100644 --- a/common/module.mk +++ b/common/module.mk @@ -5,6 +5,7 @@ MODULE_OBJS := \ concatstream.o \ config-manager.o \ coroutines.o \ + dbcs-str.o \ debug.o \ error.o \ events.o \ diff --git a/common/str-base.cpp b/common/str-base.cpp index 1b8b36f7339..c38f33b5192 100644 --- a/common/str-base.cpp +++ b/common/str-base.cpp @@ -837,6 +837,7 @@ TEMPLATE uint BASESTRING::hash() const { } template class BaseString; +template class BaseString; template class BaseString; }