From ca0feabbb08daf28606a37e8a46295b7e7fdcaf3 Mon Sep 17 00:00:00 2001 From: bendn Date: Mon, 6 Mar 2023 10:17:33 +0700 Subject: [PATCH] add `hex_decode()` to `String` --- core/string/ustring.cpp | 29 +++++++++++++++++++ core/string/ustring.h | 2 ++ core/variant/variant_call.cpp | 1 + doc/classes/String.xml | 18 ++++++++++++ doc/classes/StringName.xml | 18 ++++++++++++ .../GodotSharp/Core/StringExtensions.cs | 20 +++++++++++++ 6 files changed, 88 insertions(+) diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 6a59942a5682..773445edb695 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1644,6 +1644,35 @@ String String::hex_encode_buffer(const uint8_t *p_buffer, int p_len) { return ret; } +Vector String::hex_decode() const { + ERR_FAIL_COND_V_MSG(length() % 2 != 0, Vector(), "Hexadecimal string of uneven length."); + +#define HEX_TO_BYTE(m_output, m_index) \ + uint8_t m_output; \ + c = operator[](m_index); \ + if (is_digit(c)) { \ + m_output = c - '0'; \ + } else if (c >= 'a' && c <= 'f') { \ + m_output = c - 'a' + 10; \ + } else if (c >= 'A' && c <= 'F') { \ + m_output = c - 'A' + 10; \ + } else { \ + ERR_FAIL_V_MSG(Vector(), "Invalid hexadecimal character \"" + chr(c) + "\" at index " + m_index + "."); \ + } + + Vector out; + int len = length() / 2; + out.resize(len); + for (int i = 0; i < len; i++) { + char32_t c; + HEX_TO_BYTE(first, i * 2); + HEX_TO_BYTE(second, i * 2 + 1); + out.write[i] = first * 16 + second; + } + return out; +#undef HEX_TO_BYTE +} + void String::print_unicode_error(const String &p_message, bool p_critical) const { if (p_critical) { print_error(vformat("Unicode parsing error, some characters were replaced with spaces: %s", p_message)); diff --git a/core/string/ustring.h b/core/string/ustring.h index 28e3af92c528..90034b1b07af 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -321,6 +321,8 @@ public: static String chr(char32_t p_char); static String md5(const uint8_t *p_md5); static String hex_encode_buffer(const uint8_t *p_buffer, int p_len); + Vector hex_decode() const; + bool is_numeric() const; double to_float() const; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index ae151588362b..13e9da37f237 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1734,6 +1734,7 @@ static void _register_variant_builtin_methods() { bind_string_method(to_utf8_buffer, sarray(), varray()); bind_string_method(to_utf16_buffer, sarray(), varray()); bind_string_method(to_utf32_buffer, sarray(), varray()); + bind_string_method(hex_decode, sarray(), varray()); bind_string_method(to_wchar_buffer, sarray(), varray()); bind_static_method(String, num_scientific, sarray("number"), varray()); diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 1f4ffa417d85..fd50b308c3d8 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -313,6 +313,24 @@ [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the countrary, strings with different hash values are guaranteed to be different. + + + + Decodes a hexadecimal string as a [PackedByteArray]. + [codeblocks] + [gdscript] + var text = "hello world" + var encoded = text.to_utf8_buffer().hex_encode() # outputs "68656c6c6f20776f726c64" + print(buf.hex_decode().get_string_from_utf8()) + [/gdscript] + [csharp] + var text = "hello world"; + var encoded = text.ToUtf8Buffer().HexEncode(); # outputs "68656c6c6f20776f726c64" + GD.Print(buf.HexDecode().GetStringFromUtf8()); + [/csharp] + [/codeblocks] + + diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml index 2140c53e2097..5b630a092ee7 100644 --- a/doc/classes/StringName.xml +++ b/doc/classes/StringName.xml @@ -296,6 +296,24 @@ [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the countrary, strings with different hash values are guaranteed to be different. + + + + Decodes a hexadecimal string as a [PackedByteArray]. + [codeblocks] + [gdscript] + var text = "hello world" + var encoded = text.to_utf8_buffer().hex_encode() # outputs "68656c6c6f20776f726c64" + print(buf.hex_decode().get_string_from_utf8()) + [/gdscript] + [csharp] + var text = "hello world"; + var encoded = text.ToUtf8Buffer().HexEncode(); # outputs "68656c6c6f20776f726c64" + GD.Print(buf.HexDecode().GetStringFromUtf8()); + [/csharp] + [/codeblocks] + + diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index df67e075aca3..d53bb9f53604 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -728,6 +728,26 @@ namespace Godot return hash; } + /// + /// Decodes a hexadecimal string. + /// + /// The hexadecimal string. + /// The byte array representation of this string. + public static byte[] HexDecode(this string instance) + { + if (instance.Length % 2 != 0) + { + throw new ArgumentException("Hexadecimal string of uneven length.", nameof(instance)); + } + int len = instance.Length / 2; + byte[] ret = new byte[len]; + for (int i = 0; i < len; i++) + { + ret[i] = (byte)int.Parse(instance.AsSpan(i * 2, 2), NumberStyles.AllowHexSpecifier); + } + return ret; + } + /// /// Returns a hexadecimal representation of this byte as a string. ///