summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2023-04-05 20:21:01 +0200
committerRémi Verschelde <rverschelde@gmail.com>2023-04-05 20:21:01 +0200
commitdf91291a564fe95313936f4d60fde9192f222ec4 (patch)
treea252bcf979e96f1f22b08f387753c32f9c083668
parent44d539465acca7592e0c88748e231fe5f151da37 (diff)
parentca0feabbb08daf28606a37e8a46295b7e7fdcaf3 (diff)
downloadredot-engine-df91291a564fe95313936f4d60fde9192f222ec4.tar.gz
Merge pull request #74463 from bend-n/0x686578206465636f6465
Add a `String.hex_decode()` method to complement `PackedByteArray.hex_encode()`
-rw-r--r--core/string/ustring.cpp29
-rw-r--r--core/string/ustring.h2
-rw-r--r--core/variant/variant_call.cpp1
-rw-r--r--doc/classes/String.xml18
-rw-r--r--doc/classes/StringName.xml18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs20
6 files changed, 88 insertions, 0 deletions
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 6a59942a56..773445edb6 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<uint8_t> String::hex_decode() const {
+ ERR_FAIL_COND_V_MSG(length() % 2 != 0, Vector<uint8_t>(), "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<uint8_t>(), "Invalid hexadecimal character \"" + chr(c) + "\" at index " + m_index + "."); \
+ }
+
+ Vector<uint8_t> 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 28e3af92c5..90034b1b07 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<uint8_t> 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 ae15158836..13e9da37f2 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 1f4ffa417d..fd50b308c3 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.
</description>
</method>
+ <method name="hex_decode" qualifiers="const">
+ <return type="PackedByteArray" />
+ <description>
+ 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]
+ </description>
+ </method>
<method name="hex_to_int" qualifiers="const">
<return type="int" />
<description>
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index 2140c53e20..5b630a092e 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.
</description>
</method>
+ <method name="hex_decode" qualifiers="const">
+ <return type="PackedByteArray" />
+ <description>
+ 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]
+ </description>
+ </method>
<method name="hex_to_int" qualifiers="const">
<return type="int" />
<description>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index df67e075ac..d53bb9f536 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -729,6 +729,26 @@ namespace Godot
}
/// <summary>
+ /// Decodes a hexadecimal string.
+ /// </summary>
+ /// <param name="instance">The hexadecimal string.</param>
+ /// <returns>The byte array representation of this string.</returns>
+ 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;
+ }
+
+ /// <summary>
/// Returns a hexadecimal representation of this byte as a string.
/// </summary>
/// <param name="b">The byte to encode.</param>