From a23f630781dc7dc24759c14ce3e3db1eb93470ea Mon Sep 17 00:00:00 2001 From: Lukas Tenbrink Date: Fri, 14 Mar 2025 16:54:44 +0100 Subject: [PATCH] Remove `String` clipping constructors. Callers should instead call constructors with explicit encoding names, with known length `Span`. --- core/io/plist.cpp | 2 +- core/string/ustring.h | 29 ++++--------------- core/variant/variant_call.cpp | 4 +-- .../d3d12/rendering_device_driver_d3d12.cpp | 2 +- modules/gdscript/gdscript_tokenizer.cpp | 6 ++-- .../gdscript/gdscript_tokenizer_buffer.cpp | 2 +- modules/mbedtls/crypto_mbedtls.cpp | 3 +- modules/regex/regex.cpp | 2 +- modules/websocket/wsl_peer.cpp | 4 +-- platform/macos/os_macos.mm | 3 +- platform/windows/os_windows.cpp | 6 ++-- tests/core/string/test_string.h | 2 +- 12 files changed, 24 insertions(+), 41 deletions(-) diff --git a/core/io/plist.cpp b/core/io/plist.cpp index 0ef70b4213..5a70a8332d 100644 --- a/core/io/plist.cpp +++ b/core/io/plist.cpp @@ -631,7 +631,7 @@ bool PList::load_file(const String &p_filename) { unsigned char magic[8]; fb->get_buffer(magic, 8); - if (String((const char *)magic, 8) == "bplist00") { + if (String::ascii(Span((const char *)magic, 8)) == "bplist00") { fb->seek_end(-26); trailer.offset_size = fb->get_8(); trailer.ref_size = fb->get_8(); diff --git a/core/string/ustring.h b/core/string/ustring.h index fdac0d5d68..b8f75e7292 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -252,15 +252,9 @@ class String { void parse_latin1(const char *p_cstr) { parse_latin1(Span(p_cstr, p_cstr ? strlen(p_cstr) : 0)); } - void parse_latin1(const char *p_cstr, int p_clip_to) { - parse_latin1(Span(p_cstr, p_cstr ? _strlen_clipped(p_cstr, p_clip_to) : 0)); - } void parse_utf32(const char32_t *p_cstr) { parse_utf32(Span(p_cstr, p_cstr ? strlen(p_cstr) : 0)); } - void parse_utf32(const char32_t *p_cstr, int p_clip_to) { - parse_utf32(Span(p_cstr, p_cstr ? _strlen_clipped(p_cstr, p_clip_to) : 0)); - } // wchar_t copy_from depends on the platform. void parse_wstring(const Span &p_cstr) { @@ -281,15 +275,6 @@ class String { parse_utf32((const char32_t *)p_cstr); #endif } - void parse_wstring(const wchar_t *p_cstr, int p_clip_to) { -#ifdef WINDOWS_ENABLED - // wchar_t is 16-bit, parse as UTF-16 - parse_utf16((const char16_t *)p_cstr, p_clip_to); -#else - // wchar_t is 32-bit, copy directly - parse_utf32((const char32_t *)p_cstr, p_clip_to); -#endif - } bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const; int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const; @@ -540,6 +525,11 @@ public: static String utf16(const Span &p_range) { return utf16(p_range.ptr(), p_range.size()); } void parse_utf32(const Span &p_cstr); + static String utf32(const Span &p_span) { + String string; + string.parse_utf32(p_span); + return string; + } static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */ static uint32_t hash(const char32_t *p_cstr); /* hash the string */ @@ -633,15 +623,6 @@ public: String(const char32_t *p_cstr) { parse_utf32(p_cstr); } - String(const char *p_cstr, int p_clip_to_len) { - parse_latin1(p_cstr, p_clip_to_len); - } - String(const wchar_t *p_cstr, int p_clip_to_len) { - parse_wstring(p_cstr, p_clip_to_len); - } - String(const char32_t *p_cstr, int p_clip_to_len) { - parse_utf32(p_cstr, p_clip_to_len); - } // Copy assignment for NULL terminated C strings. void operator=(const char *p_cstr) { diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 8fcce92cc6..5625313959 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -716,7 +716,7 @@ struct _VariantCall { String s; if (p_instance->size() > 0) { const uint8_t *r = p_instance->ptr(); - s = String((const char32_t *)r, floor((double)p_instance->size() / (double)sizeof(char32_t))); + s.parse_utf32(Span((const char32_t *)r, floor((double)p_instance->size() / (double)sizeof(char32_t)))); } return s; } @@ -728,7 +728,7 @@ struct _VariantCall { #ifdef WINDOWS_ENABLED s.parse_utf16((const char16_t *)r, floor((double)p_instance->size() / (double)sizeof(char16_t))); #else - s = String((const char32_t *)r, floor((double)p_instance->size() / (double)sizeof(char32_t))); + s.parse_utf32(Span((const char32_t *)r, floor((double)p_instance->size() / (double)sizeof(char32_t)))); #endif } return s; diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index ad63cd8204..1edc6fb7c1 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -3543,7 +3543,7 @@ Vector RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec ComPtr error_blob; HRESULT res = D3DX12SerializeVersionedRootSignature(context_driver->lib_d3d12, &root_sig_desc, D3D_ROOT_SIGNATURE_VERSION_1_1, root_sig_blob.GetAddressOf(), error_blob.GetAddressOf()); ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), Vector(), - "Serialization of root signature failed with error " + vformat("0x%08ux", (uint64_t)res) + " and the following message:\n" + String((char *)error_blob->GetBufferPointer(), error_blob->GetBufferSize())); + "Serialization of root signature failed with error " + vformat("0x%08ux", (uint64_t)res) + " and the following message:\n" + String::ascii(Span((char *)error_blob->GetBufferPointer(), error_blob->GetBufferSize()))); binary_data.root_signature_crc = crc32(0, nullptr, 0); binary_data.root_signature_crc = crc32(binary_data.root_signature_crc, (const Bytef *)root_sig_blob->GetBufferPointer(), root_sig_blob->GetBufferSize()); diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index d7c47dd687..9a05dae92c 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -366,7 +366,7 @@ GDScriptTokenizer::Token GDScriptTokenizerText::make_token(Token::Type p_type) { token.end_column = column; token.leftmost_column = leftmost_column; token.rightmost_column = rightmost_column; - token.source = String(_start, _current - _start); + token.source = String::utf32(Span(_start, _current - _start)); if (p_type != Token::ERROR && cursor_line > -1) { // Also count whitespace after token. @@ -588,7 +588,7 @@ GDScriptTokenizer::Token GDScriptTokenizerText::potential_identifier() { return token; } - String name(_start, len); + String name = String::utf32(Span(_start, len)); if (len < MIN_KEYWORD_LENGTH || len > MAX_KEYWORD_LENGTH) { // Cannot be a keyword, as the length doesn't match any. return make_identifier(name); @@ -863,7 +863,7 @@ GDScriptTokenizer::Token GDScriptTokenizerText::number() { // Create a string with the whole number. int len = _current - _start; - String number = String(_start, len).remove_char('_'); + String number = String::utf32(Span(_start, len)).remove_char('_'); // Convert to the appropriate literal type. if (base == 16) { diff --git a/modules/gdscript/gdscript_tokenizer_buffer.cpp b/modules/gdscript/gdscript_tokenizer_buffer.cpp index 2046480f0e..d9b6ec68a2 100644 --- a/modules/gdscript/gdscript_tokenizer_buffer.cpp +++ b/modules/gdscript/gdscript_tokenizer_buffer.cpp @@ -182,7 +182,7 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector &p_buffer) cs.write[j] = decode_uint32(tmp); } - String s(reinterpret_cast(cs.ptr()), len); + String s = String::utf32(Span(reinterpret_cast(cs.ptr()), len)); b += len * 4; total_len -= len * 4; identifiers.write[i] = s; diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp index 3aa5fdd27a..0bfdbac3b6 100644 --- a/modules/mbedtls/crypto_mbedtls.cpp +++ b/modules/mbedtls/crypto_mbedtls.cpp @@ -212,7 +212,8 @@ String X509CertificateMbedTLS::save_to_string() { int ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT, cert.raw.p, cert.raw.len, w, sizeof(w), &wrote); ERR_FAIL_COND_V_MSG(ret != 0 || wrote == 0, String(), "Error saving the certificate."); - buffer += String((char *)w, wrote); + // PEM is base64, aka ascii + buffer += String::ascii(Span((char *)w, wrote)); crt = crt->next; } if (buffer.length() <= PEM_MIN_SIZE) { diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 40efa4d1db..4b08e1ffbe 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -326,7 +326,7 @@ int RegEx::_sub(const String &p_subject, const String &p_replacement, int p_offs pcre2_match_context_free_32(mctx); if (res >= 0) { - r_output = String(output.ptr(), olength) + p_subject.substr(length); + r_output = String::utf32(Span(output.ptr(), olength)) + p_subject.substr(length); } return res; diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp index 1a1f52a8a0..6aee7aabf9 100644 --- a/modules/websocket/wsl_peer.cpp +++ b/modules/websocket/wsl_peer.cpp @@ -151,7 +151,7 @@ Error WSLPeer::accept_stream(Ref p_stream) { } bool WSLPeer::_parse_client_request() { - Vector psa = String((const char *)handshake_buffer->get_data_array().ptr(), handshake_buffer->get_position() - 4).split("\r\n"); + Vector psa = String::ascii(Span((const char *)handshake_buffer->get_data_array().ptr(), handshake_buffer->get_position() - 4)).split("\r\n"); int len = psa.size(); ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers, got: " + itos(len) + ", expected >= 4."); @@ -416,7 +416,7 @@ void WSLPeer::_do_client_handshake() { } bool WSLPeer::_verify_server_response() { - Vector psa = String((const char *)handshake_buffer->get_data_array().ptr(), handshake_buffer->get_position() - 4).split("\r\n"); + Vector psa = String::ascii(Span((const char *)handshake_buffer->get_data_array().ptr(), handshake_buffer->get_position() - 4)).split("\r\n"); int len = psa.size(); ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers. Got: " + itos(len) + ", expected >= 4."); diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index 324cb67393..6a27ce43ef 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -806,7 +806,8 @@ String OS_MacOS::get_system_ca_certificates() { Error err = CryptoCore::b64_encode(pba.ptrw(), pba.size(), &b64len, (unsigned char *)CFDataGetBytePtr(der), derlen); CFRelease(der); ERR_CONTINUE(err != OK); - certs += "-----BEGIN CERTIFICATE-----\n" + String((char *)pba.ptr(), b64len) + "\n-----END CERTIFICATE-----\n"; + // Certificate is bas64 encoded, aka ascii. + certs += "-----BEGIN CERTIFICATE-----\n" + String::ascii(Span((char *)pba.ptr(), b64len)) + "\n-----END CERTIFICATE-----\n"; } CFRelease(result); return certs; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index e9d8419e0d..a00f05944e 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -966,7 +966,7 @@ static void _append_to_pipe(char *p_bytes, int p_size, String *r_pipe, Mutex *p_ // Let's hope it's compatible with UTF-8. (*r_pipe) += String::utf8(p_bytes, p_size); } else { - (*r_pipe) += String(wchars.ptr(), total_wchars); + (*r_pipe) += String::utf16((char16_t *)wchars.ptr(), total_wchars); } if (p_pipe_mutex) { p_pipe_mutex->unlock(); @@ -2234,7 +2234,7 @@ String OS_Windows::get_user_data_dir(const String &p_user_dir) const { String OS_Windows::get_unique_id() const { HW_PROFILE_INFOA HwProfInfo; ERR_FAIL_COND_V(!GetCurrentHwProfileA(&HwProfInfo), ""); - return String((HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN); + return String::ascii(Span((HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN)); } bool OS_Windows::_check_internal_feature_support(const String &p_feature) { @@ -2307,7 +2307,7 @@ String OS_Windows::get_system_ca_certificates() { PackedByteArray pba; pba.resize(size); CryptBinaryToStringA(curr->pbCertEncoded, curr->cbCertEncoded, CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, (char *)pba.ptrw(), &size); - certs += String((char *)pba.ptr(), size); + certs += String::ascii(Span((char *)pba.ptr(), size)); curr = CertEnumCertificatesInStore(cert_store, curr); } CertCloseStore(cert_store, 0); diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index 0558824e64..a1141c152a 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -59,7 +59,7 @@ TEST_CASE("[String] Assign from Latin-1 char string (copycon)") { const String &t1(s); CHECK(u32scmp(t1.get_data(), U"Sheep") == 0); - String t2 = String("Sheep", 3); + String t2 = String::latin1(Span("Sheep", 3)); CHECK(u32scmp(t2.get_data(), U"She") == 0); }