mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-10-10 16:18:35 +03:00
188 lines
6.1 KiB
C++
188 lines
6.1 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include "deflate.hpp"
|
|
#include <libdeflate.h>
|
|
|
|
namespace deflate {
|
|
static int32_t compress_static(struct libdeflate_compressor* c, const void* src, size_t src_length,
|
|
void** dst, size_t* dst_length, int32_t compression_level, mode mode);
|
|
static int32_t decompress_static(struct libdeflate_decompressor* d, const void* src, size_t src_length,
|
|
void** dst, size_t* dst_length, mode mode);
|
|
|
|
int32_t compress(const void* src, size_t src_length, void** dst,
|
|
size_t* dst_length, int32_t compression_level, mode mode) {
|
|
if (!src_length)
|
|
return -1;
|
|
else if (!src)
|
|
return -2;
|
|
else if (!dst)
|
|
return -3;
|
|
else if (!dst_length)
|
|
return -4;
|
|
else if (mode < MODE_DEFLATE || mode > MODE_ZLIB)
|
|
return -5;
|
|
|
|
struct libdeflate_compressor* c = libdeflate_alloc_compressor(compression_level);
|
|
if (!c)
|
|
return -5;
|
|
|
|
int32_t result = compress_static(c, src, src_length, dst, dst_length, compression_level, mode);
|
|
libdeflate_free_compressor(c);
|
|
return result >= 0 ? result : result - 0x10;
|
|
}
|
|
|
|
int32_t compress_gzip(const void* src, size_t src_length, void** dst,
|
|
size_t* dst_length, int32_t compression_level, const char* file_name) {
|
|
if (!src_length)
|
|
return -1;
|
|
else if (!src)
|
|
return -2;
|
|
else if (!dst)
|
|
return -3;
|
|
else if (!dst_length)
|
|
return -4;
|
|
|
|
struct libdeflate_compressor* c = libdeflate_alloc_compressor(compression_level);
|
|
if (!c)
|
|
return -5;
|
|
|
|
int32_t result = compress_static(c, src, src_length, dst, dst_length, compression_level, MODE_GZIP);
|
|
libdeflate_free_compressor(c);
|
|
if (result < 0)
|
|
return result - 0x10;
|
|
|
|
size_t file_name_length = utf8_length(file_name);
|
|
void* temp = force_malloc(*dst_length + file_name_length + 1);
|
|
size_t t = (size_t)temp;
|
|
size_t d = (size_t)*dst;
|
|
memcpy((void*)t, (void*)d, 0x0A);
|
|
memcpy((void*)(t + 0x0A), file_name, file_name_length + 1);
|
|
memcpy((void*)(t + 0x0A + file_name_length + 1), (void*)(d + 0x0A), *dst_length - 0x0A);
|
|
((uint8_t*)t)[0x03] |= 0x08;
|
|
return result;
|
|
}
|
|
|
|
int32_t decompress(const void* src, size_t src_length, void** dst,
|
|
size_t* dst_length, mode mode) {
|
|
if (!src_length)
|
|
return -1;
|
|
else if (!src)
|
|
return -2;
|
|
else if (!dst)
|
|
return -3;
|
|
else if (!dst_length)
|
|
return -4;
|
|
else if (mode < MODE_DEFLATE || mode > MODE_ZLIB)
|
|
return -5;
|
|
|
|
if (!*dst_length)
|
|
*dst_length = 1;
|
|
struct libdeflate_decompressor* d = libdeflate_alloc_decompressor();
|
|
int32_t result = decompress_static(d, src, src_length, dst, dst_length, mode);
|
|
libdeflate_free_decompressor(d);
|
|
return result >= 0 ? result : result - 0x10;
|
|
}
|
|
|
|
static int32_t compress_static(struct libdeflate_compressor* c, const void* src, size_t src_length,
|
|
void** dst, size_t* dst_length, int32_t compression_level, mode mode) {
|
|
size_t dst_max_length;
|
|
switch (mode) {
|
|
case MODE_GZIP:
|
|
dst_max_length = libdeflate_gzip_compress_bound(c, src_length);
|
|
break;
|
|
case MODE_ZLIB:
|
|
dst_max_length = libdeflate_zlib_compress_bound(c, src_length);
|
|
break;
|
|
default:
|
|
dst_max_length = libdeflate_deflate_compress_bound(c, src_length);
|
|
break;
|
|
}
|
|
|
|
*dst = force_malloc(dst_max_length);
|
|
if (!*dst)
|
|
return -1;
|
|
|
|
size_t dst_act_length;
|
|
switch (mode) {
|
|
case MODE_GZIP:
|
|
dst_act_length = libdeflate_gzip_compress(c, src, src_length, *dst, dst_max_length);
|
|
break;
|
|
case MODE_ZLIB:
|
|
dst_act_length = libdeflate_zlib_compress(c, src, src_length, *dst, dst_max_length);
|
|
break;
|
|
default:
|
|
dst_act_length = libdeflate_deflate_compress(c, src, src_length, *dst, dst_max_length);
|
|
break;
|
|
}
|
|
|
|
if (dst_act_length == dst_max_length) {
|
|
*dst_length = dst_act_length;
|
|
return 0;
|
|
}
|
|
|
|
void* temp = force_malloc(dst_act_length);
|
|
if (!temp) {
|
|
free_def(*dst);
|
|
return -2;
|
|
}
|
|
|
|
memcpy(temp, *dst, dst_act_length);
|
|
free_def(*dst);
|
|
*dst = temp;
|
|
*dst_length = dst_act_length;
|
|
return 0;
|
|
}
|
|
|
|
static int32_t decompress_static(struct libdeflate_decompressor* d, const void* src, size_t src_length,
|
|
void** dst, size_t* dst_length, mode mode) {
|
|
*dst = force_malloc(*dst_length);
|
|
if (!*dst)
|
|
return -1;
|
|
|
|
size_t dst_act_length = 0;
|
|
enum libdeflate_result result;
|
|
switch (mode) {
|
|
case MODE_GZIP:
|
|
result = libdeflate_gzip_decompress(d, src, src_length, *dst, *dst_length, &dst_act_length);
|
|
break;
|
|
case MODE_ZLIB:
|
|
result = libdeflate_zlib_decompress(d, src, src_length, *dst, *dst_length, &dst_act_length);
|
|
break;
|
|
default:
|
|
result = libdeflate_deflate_decompress(d, src, src_length, *dst, *dst_length, &dst_act_length);
|
|
break;
|
|
}
|
|
|
|
switch (result) {
|
|
case LIBDEFLATE_BAD_DATA:
|
|
free_def(*dst);
|
|
return -2;
|
|
break;
|
|
case LIBDEFLATE_INSUFFICIENT_SPACE:
|
|
free_def(*dst);
|
|
*dst_length *= 2;
|
|
decompress_static(d, src, src_length, dst, dst_length, mode);
|
|
break;
|
|
default:
|
|
if (dst_act_length >= *dst_length)
|
|
break;
|
|
|
|
void* temp = force_malloc(dst_act_length);
|
|
if (!temp) {
|
|
free_def(*dst);
|
|
return -3;
|
|
}
|
|
|
|
memcpy(temp, *dst, dst_act_length);
|
|
free_def(*dst);
|
|
*dst = temp;
|
|
*dst_length = dst_act_length;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|