Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
Original file line number Diff line number Diff line change
Expand Up @@ -682,5 +682,53 @@ public static Variant.Type TypeToVariantType(Type type)
{
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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,12 @@ public static partial void godotsharp_array_slice(scoped ref godot_array p_self,

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

public static partial godot_bool godotsharp_dictionary_try_get_value(scoped ref godot_dictionary p_self,
Expand Down
44 changes: 44 additions & 0 deletions modules/mono/glue/runtime_interop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,47 @@ void godotsharp_array_to_string(const Array *p_self, String *r_str) {
*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

bool godotsharp_dictionary_try_get_value(const Dictionary *p_self, const Variant *p_key, Variant *r_value) {
Expand Down Expand Up @@ -1683,6 +1724,9 @@ static const void *unmanaged_callbacks[]{
(void *)godotsharp_array_slice,
(void *)godotsharp_array_sort,
(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_set_value,
(void *)godotsharp_dictionary_keys,
Expand Down