mirror of
https://github.com/vlang/v.git
synced 2025-08-03 17:57:59 -04:00
101 lines
3.6 KiB
V
101 lines
3.6 KiB
V
module compress
|
|
|
|
#flag -I @VEXEROOT/thirdparty/zip
|
|
#include "miniz.h"
|
|
|
|
pub const max_size = u64(1 << 31)
|
|
|
|
fn C.tdefl_compress_mem_to_heap(source_buf voidptr, source_buf_len usize, out_len &usize, flags int) voidptr
|
|
fn C.tinfl_decompress_mem_to_heap(source_buf voidptr, source_buf_len usize, out_len &usize, flags int) voidptr
|
|
|
|
// compresses an array of bytes based on providing flags and returns the compressed bytes in a new array
|
|
// NB: this is a low level api, a high level implementation like zlib/gzip should be preferred
|
|
@[manualfree]
|
|
pub fn compress(data []u8, flags int) ![]u8 {
|
|
if u64(data.len) > max_size {
|
|
return error('data too large (${data.len} > ${max_size})')
|
|
}
|
|
mut out_len := usize(0)
|
|
|
|
address := C.tdefl_compress_mem_to_heap(data.data, data.len, &out_len, flags)
|
|
if address == 0 {
|
|
return error('compression failed')
|
|
}
|
|
if u64(out_len) > max_size {
|
|
return error('compressed data is too large (${out_len} > ${max_size})')
|
|
}
|
|
unsafe {
|
|
ret := address.vbytes(int(out_len)).clone()
|
|
C.free(address)
|
|
return ret
|
|
}
|
|
}
|
|
|
|
// decompresses an array of bytes based on providing flags and returns the decompressed bytes in a new array
|
|
// NB: this is a low level api, a high level implementation like zlib/gzip should be preferred
|
|
@[manualfree]
|
|
pub fn decompress(data []u8, flags int) ![]u8 {
|
|
mut out_len := usize(0)
|
|
|
|
address := C.tinfl_decompress_mem_to_heap(data.data, data.len, &out_len, flags)
|
|
if address == 0 {
|
|
return error('decompression failed')
|
|
}
|
|
if u64(out_len) > max_size {
|
|
return error('decompressed data is too large (${out_len} > ${max_size})')
|
|
}
|
|
|
|
unsafe {
|
|
ret := address.vbytes(int(out_len)).clone()
|
|
C.free(address)
|
|
return ret
|
|
}
|
|
}
|
|
|
|
// ChunkCallback is used to receive decompressed chunks of maximum 32768 bytes.
|
|
// After processing the chunk this function should return the chunk's length to indicate
|
|
// the decompressor to send more chunks, otherwise the decompression stops.
|
|
// The userdata parameter comes from the call to decompress_with_callback/4, and can be used
|
|
// to pass arbitrary data, without having to create a closure.
|
|
pub type ChunkCallback = fn (chunk []u8, userdata voidptr) int
|
|
|
|
// decompress_with_callback decompresses an array of bytes, based on the provided flags, and a V fn callback to receive decompressed chunks, of at most 32 kilobytes each.
|
|
// It returns the total decompressed length, or a decompression error.
|
|
// NB: this is a low level api, a high level implementation like zlib/gzip should be preferred.
|
|
pub fn decompress_with_callback(data []u8, cb ChunkCallback, userdata voidptr, flags int) !u64 {
|
|
cbdata := DecompressionCallBackData{
|
|
data: data.data
|
|
size: usize(data.len)
|
|
cb: cb
|
|
userdata: userdata
|
|
}
|
|
status := C.tinfl_decompress_mem_to_callback(cbdata.data, &cbdata.size, c_cb_for_decompress_mem,
|
|
&cbdata, flags)
|
|
if status == 0 {
|
|
return error('decompression error')
|
|
}
|
|
return cbdata.decompressed_size
|
|
}
|
|
|
|
struct DecompressionCallBackData {
|
|
mut:
|
|
data voidptr
|
|
size usize
|
|
decompressed_size u64
|
|
userdata voidptr
|
|
cb ChunkCallback = unsafe { nil }
|
|
}
|
|
|
|
fn c_cb_for_decompress_mem(buf &char, len int, pdcbd voidptr) int {
|
|
mut cbdata := unsafe { &DecompressionCallBackData(pdcbd) }
|
|
if cbdata.cb(unsafe { voidptr(buf).vbytes(len) }, cbdata.userdata) == len {
|
|
cbdata.decompressed_size += u64(len)
|
|
return 1 // continue decompressing
|
|
}
|
|
return 0 // stop decompressing
|
|
}
|
|
|
|
type DecompressCallback = fn (const_buffer voidptr, len int, userdata voidptr) int
|
|
|
|
fn C.tinfl_decompress_mem_to_callback(const_input_buffer voidptr, psize &usize, put_buf_cb DecompressCallback, userdata voidptr, flags int) int
|