mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 13:01:29 -10:00
The code did not account for unicode escape sequences when inserting scrambling characters which distorted the text and fequently caused invalid UTF-8 sequences to appear in the text. This fixes that by using the text iterators already present in the game code. I needed to rewrite the logic of this block a bit since the previous logic could not be converted to the way we need to handle unicode sequences at the moment. This fixes #1720.
160 lines
4.5 KiB
C++
160 lines
4.5 KiB
C++
//
|
|
//
|
|
|
|
#include "unicode.h"
|
|
|
|
namespace unicode {
|
|
|
|
text_iterator::text_iterator(const char* in_current_byte, const char* in_range_start_byte, const char* in_range_end_byte) :
|
|
current_byte(in_current_byte), range_end_byte(in_range_end_byte), range_start_byte(in_range_start_byte) {
|
|
if (range_end_byte == nullptr) {
|
|
#if SCP_COMPILER_IS_GNU
|
|
#pragma GCC diagnostic push
|
|
// This suppresses a GCC bug where it thinks that in_current_byte is null in release builds
|
|
#pragma GCC diagnostic ignored "-Wnonnull"
|
|
#endif
|
|
range_end_byte = in_current_byte + strlen(in_current_byte);
|
|
#if SCP_COMPILER_IS_GNU
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
}
|
|
}
|
|
text_iterator& unicode::text_iterator::operator++() {
|
|
if (Unicode_text_mode) {
|
|
try {
|
|
// Increment by UTF-8 encoded codepoints
|
|
utf8::next(current_byte, range_end_byte);
|
|
} catch(const std::exception& e) {
|
|
Error(LOCATION, "Exception while incrementing UTF-8 sequence near '%.16s': %s", current_byte, e.what());
|
|
return *this;
|
|
}
|
|
} else {
|
|
// Increment by byte
|
|
++current_byte;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
text_iterator& text_iterator::operator--() {
|
|
if (Unicode_text_mode) {
|
|
try {
|
|
// Decrement by UTF-8 encoded codepoints
|
|
utf8::prior(current_byte, range_start_byte);
|
|
} catch(const std::exception& e) {
|
|
Error(LOCATION, "Exception while decrementing text iterator near '%.16s': %s", current_byte, e.what());
|
|
return *this;
|
|
}
|
|
} else {
|
|
// Increment by byte
|
|
--current_byte;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
text_iterator::value_type text_iterator::operator*() {
|
|
if (Unicode_text_mode) {
|
|
try {
|
|
return utf8::peek_next(current_byte, range_end_byte);
|
|
} catch(const std::exception& e) {
|
|
Error(LOCATION, "Exception while decoding UTF-8 sequence near '%.16s': %s", current_byte, e.what());
|
|
return 0;
|
|
}
|
|
} else {
|
|
// Use the unsigned byte value here to avoid integer overflows
|
|
return (codepoint_t)*reinterpret_cast<const uint8_t*>(current_byte);
|
|
}
|
|
}
|
|
const char* text_iterator::pos() const {
|
|
return current_byte;
|
|
}
|
|
bool text_iterator::operator==(const text_iterator& rhs) const {
|
|
Assertion(is_from_same_range(rhs), "Iterators must be from the same byte range!");
|
|
|
|
return current_byte == rhs.current_byte;
|
|
}
|
|
bool text_iterator::operator!=(const text_iterator& rhs) const {
|
|
Assertion(is_from_same_range(rhs), "Iterators must be from the same byte range!");
|
|
|
|
return !(rhs == *this);
|
|
}
|
|
bool text_iterator::operator<(const text_iterator& rhs) const {
|
|
Assertion(is_from_same_range(rhs), "Iterators must be from the same byte range!");
|
|
|
|
return current_byte < rhs.current_byte;
|
|
}
|
|
bool text_iterator::operator>(const text_iterator& rhs) const {
|
|
Assertion(is_from_same_range(rhs), "Iterators must be from the same byte range!");
|
|
|
|
return rhs < *this;
|
|
}
|
|
bool text_iterator::operator<=(const text_iterator& rhs) const {
|
|
Assertion(is_from_same_range(rhs), "Iterators must be from the same byte range!");
|
|
|
|
return !(rhs < *this);
|
|
}
|
|
bool text_iterator::operator>=(const text_iterator& rhs) const {
|
|
Assertion(is_from_same_range(rhs), "Iterators must be from the same byte range!");
|
|
|
|
return !(*this < rhs);
|
|
}
|
|
text_iterator text_iterator::operator+(ptrdiff_t diff) const {
|
|
if (diff < 0) {
|
|
// Use minus operator to avoid duplicating code
|
|
return operator-(-diff);
|
|
}
|
|
|
|
auto iter = *this;
|
|
for (ptrdiff_t i = 0; i < diff; ++i) {
|
|
++iter;
|
|
}
|
|
return iter;
|
|
}
|
|
text_iterator text_iterator::operator-(ptrdiff_t diff) const {
|
|
if (diff < 0) {
|
|
// Use plus operator to avoid duplicating code
|
|
return operator+(-diff);
|
|
}
|
|
|
|
auto iter = *this;
|
|
for (ptrdiff_t i = 0; i < diff; ++i) {
|
|
--iter;
|
|
}
|
|
return iter;
|
|
}
|
|
bool text_iterator::is_from_same_range(const text_iterator& other) const {
|
|
return range_start_byte == other.range_start_byte && range_end_byte == other.range_end_byte;
|
|
}
|
|
|
|
codepoint_range::codepoint_range(const char* in_start, const char* in_end) : start(in_start), end_ptr(in_end) {
|
|
Assertion(start != nullptr, "Start of the string must be a valid pointer!");
|
|
|
|
if (end_ptr == nullptr) {
|
|
// Automatically determine the end of the string
|
|
end_ptr = start + strlen(start);
|
|
}
|
|
}
|
|
text_iterator codepoint_range::begin() {
|
|
return text_iterator(start, start, end_ptr);
|
|
}
|
|
text_iterator codepoint_range::end() {
|
|
return text_iterator(end_ptr, start, end_ptr);
|
|
}
|
|
|
|
size_t encoded_size(codepoint_t cp) {
|
|
if (Unicode_text_mode) {
|
|
try {
|
|
return utf8::encoded_width(cp);
|
|
} catch(const std::exception& e) {
|
|
Error(LOCATION,
|
|
"Exception while computing encoded size of Unicode code point %" PRIu32 ": %s",
|
|
(uint32_t) cp,
|
|
e.what());
|
|
return 1;
|
|
}
|
|
} else {
|
|
// In the legacy mode every code point is exactly one char
|
|
return 1;
|
|
}
|
|
}
|
|
}
|