1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-20 14:45:44 +00:00

Merge pull request #106008 from beicause/cs-byte-array-compress

C#: Expose byte array compress and decompress
This commit is contained in:
Thaddeus Crews
2025-05-26 11:24:28 -05:00
3 changed files with 98 additions and 0 deletions

View File

@@ -682,5 +682,53 @@ namespace Godot
{ {
return Marshaling.ConvertManagedTypeToVariantType(type, out bool _); return Marshaling.ConvertManagedTypeToVariantType(type, out bool _);
} }
/// <summary>
/// Returns a new byte array with the data compressed.
/// </summary>
/// <param name="instance">The byte array to compress.</param>
/// <param name="compressionMode">The compression mode, one of <see cref="FileAccess.CompressionMode"/></param>
/// <returns>The compressed byte array.</returns>
public static byte[] Compress(this byte[] instance, FileAccess.CompressionMode compressionMode = 0)
{
using godot_packed_byte_array src = Marshaling.ConvertSystemArrayToNativePackedByteArray(instance);
NativeFuncs.godotsharp_packed_byte_array_compress(src, (int)compressionMode, out var ret);
using (ret)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(ret);
}
/// <summary>
/// Returns a new byte array with the data decompressed.
/// <para>Note: Decompression is not guaranteed to work with data not compressed by Godot, for example if data compressed with the deflate compression mode lacks a checksum or header.</para>
/// </summary>
/// <param name="instance">The byte array to decompress.</param>
/// <param name="bufferSize">The size of the uncompressed data.</param>
/// <param name="compressionMode">The compression mode, one of <see cref="FileAccess.CompressionMode"/></param>
/// <returns>The decompressed byte array.</returns>
public static byte[] Decompress(this byte[] instance, long bufferSize, FileAccess.CompressionMode compressionMode = 0)
{
using godot_packed_byte_array src = Marshaling.ConvertSystemArrayToNativePackedByteArray(instance);
NativeFuncs.godotsharp_packed_byte_array_decompress(src, bufferSize, (int)compressionMode, out var ret);
using (ret)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(ret);
}
/// <summary>
/// Returns a new byte array with the data decompressed. <b>This method only accepts brotli, gzip, and deflate compression modes</b>.
/// <para>This method is potentially slower than <see cref="Decompress"/>, as it may have to re-allocate its output buffer multiple times while decompressing, whereas <see cref="Decompress"/> knows it's output buffer size from the beginning.</para>
/// <para>GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [param max_output_size]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned.</para>
/// <para>Note: Decompression is not guaranteed to work with data not compressed by Godot, for example if data compressed with the deflate compression mode lacks a checksum or header.</para>
/// </summary>
/// <param name="instance">The byte array to decompress.</param>
/// <param name="maxOutputSize">The maximum size this function is allowed to allocate in bytes.</param>
/// <param name="compressionMode">The compression mode, one of <see cref="FileAccess.CompressionMode"/></param>
/// <returns>The decompressed byte array.</returns>
public static byte[] DecompressDynamic(this byte[] instance, long maxOutputSize, FileAccess.CompressionMode compressionMode = 0)
{
using godot_packed_byte_array src = Marshaling.ConvertSystemArrayToNativePackedByteArray(instance);
NativeFuncs.godotsharp_packed_byte_array_decompress_dynamic(src, maxOutputSize, (int)compressionMode, out var ret);
using (ret)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(ret);
}
} }
} }

View File

@@ -433,6 +433,12 @@ namespace Godot.NativeInterop
public static partial void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str); public static partial void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str);
public static partial void godotsharp_packed_byte_array_compress(scoped in godot_packed_byte_array p_src, int p_mode, out godot_packed_byte_array r_dst);
public static partial void godotsharp_packed_byte_array_decompress(scoped in godot_packed_byte_array p_src, long p_buffer_size, int p_mode, out godot_packed_byte_array r_dst);
public static partial void godotsharp_packed_byte_array_decompress_dynamic(scoped in godot_packed_byte_array p_src, long p_buffer_size, int p_mode, out godot_packed_byte_array r_dst);
// Dictionary // Dictionary
public static partial godot_bool godotsharp_dictionary_try_get_value(scoped ref godot_dictionary p_self, public static partial godot_bool godotsharp_dictionary_try_get_value(scoped ref godot_dictionary p_self,

View File

@@ -1168,6 +1168,47 @@ void godotsharp_array_to_string(const Array *p_self, String *r_str) {
*r_str = Variant(*p_self).operator String(); *r_str = Variant(*p_self).operator String();
} }
void godotsharp_packed_byte_array_compress(const PackedByteArray *p_src, int p_mode, PackedByteArray *r_dst) {
if (p_src->size() > 0) {
Compression::Mode mode = (Compression::Mode)(p_mode);
r_dst->resize(Compression::get_max_compressed_buffer_size(p_src->size(), mode));
int result = Compression::compress(r_dst->ptrw(), p_src->ptr(), p_src->size(), mode);
result = result >= 0 ? result : 0;
r_dst->resize(result);
}
}
void godotsharp_packed_byte_array_decompress(const PackedByteArray *p_src, int64_t p_buffer_size, int p_mode, PackedByteArray *r_dst) {
int64_t buffer_size = p_buffer_size;
Compression::Mode mode = (Compression::Mode)(p_mode);
if (buffer_size <= 0) {
ERR_FAIL_MSG("Decompression buffer size must be greater than zero.");
}
if (p_src->size() == 0) {
ERR_FAIL_MSG("Compressed buffer size must be greater than zero.");
}
r_dst->resize(buffer_size);
int result = Compression::decompress(r_dst->ptrw(), buffer_size, p_src->ptr(), p_src->size(), mode);
result = result >= 0 ? result : 0;
r_dst->resize(result);
}
void godotsharp_packed_byte_array_decompress_dynamic(const PackedByteArray *p_src, int64_t p_max_output_size, int p_mode, PackedByteArray *r_dst) {
int64_t max_output_size = p_max_output_size;
Compression::Mode mode = (Compression::Mode)(p_mode);
int result = Compression::decompress_dynamic(r_dst, max_output_size, p_src->ptr(), p_src->size(), mode);
if (result != OK) {
r_dst->clear();
ERR_FAIL_MSG("Decompression failed.");
}
}
// Dictionary // Dictionary
bool godotsharp_dictionary_try_get_value(const Dictionary *p_self, const Variant *p_key, Variant *r_value) { bool godotsharp_dictionary_try_get_value(const Dictionary *p_self, const Variant *p_key, Variant *r_value) {
@@ -1683,6 +1724,9 @@ static const void *unmanaged_callbacks[]{
(void *)godotsharp_array_slice, (void *)godotsharp_array_slice,
(void *)godotsharp_array_sort, (void *)godotsharp_array_sort,
(void *)godotsharp_array_to_string, (void *)godotsharp_array_to_string,
(void *)godotsharp_packed_byte_array_compress,
(void *)godotsharp_packed_byte_array_decompress,
(void *)godotsharp_packed_byte_array_decompress_dynamic,
(void *)godotsharp_dictionary_try_get_value, (void *)godotsharp_dictionary_try_get_value,
(void *)godotsharp_dictionary_set_value, (void *)godotsharp_dictionary_set_value,
(void *)godotsharp_dictionary_keys, (void *)godotsharp_dictionary_keys,