Current section
Files
Jump to
Current section
Files
c_src/lz4_nif.c
#include <stdbool.h>
#include "erl_nif.h"
#include "lz4.h"
#include "lz4hc.h"
static ERL_NIF_TERM nif_compress(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM nif_uncompress(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[]);
static ErlNifFunc nif_funcs[] =
{
{"compress", 2, nif_compress},
{"uncompress", 2, nif_uncompress}
};
static ERL_NIF_TERM atom_ok;
static ERL_NIF_TERM atom_error;
static ERL_NIF_TERM atom_high;
static ERL_NIF_TERM atom_compress_failed;
static ERL_NIF_TERM atom_uncompress_failed;
static ERL_NIF_TERM
nif_compress(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM opts_term, head_term, tail_term, ret_term;
ErlNifBinary src_bin, res_bin;
bool high = false;
int real_size;
size_t res_size;
if (!enif_inspect_binary(env, argv[0], &src_bin) ||
!enif_is_list(env, argv[1]))
return 0;
opts_term = argv[1];
while (enif_get_list_cell(env, opts_term, &head_term, &tail_term)) {
if (enif_is_identical(head_term, atom_high))
high = true;
opts_term = tail_term;
}
res_size = LZ4_compressBound(src_bin.size);
enif_alloc_binary(res_size, &res_bin);
if (high)
real_size = LZ4_compressHC((char *)src_bin.data,
(char *)res_bin.data, src_bin.size);
else
real_size = LZ4_compress((char *)src_bin.data,
(char *)res_bin.data, src_bin.size);
if (real_size >= 0) {
enif_realloc_binary(&res_bin, real_size);
ret_term = enif_make_tuple2(env, atom_ok,
enif_make_binary(env, &res_bin));
enif_release_binary(&res_bin);
return ret_term;
} else {
enif_release_binary(&res_bin);
return enif_make_tuple2(env, atom_error, atom_compress_failed);
}
}
static ERL_NIF_TERM
nif_uncompress(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM ret_term;
ErlNifBinary src_bin, res_bin;
long res_size;
if (!enif_inspect_binary(env, argv[0], &src_bin) ||
!enif_get_long(env, argv[1], &res_size))
return 0;
enif_alloc_binary((size_t)res_size, &res_bin);
int ret_size = LZ4_decompress_safe((char *)src_bin.data,
(char *)res_bin.data, src_bin.size, res_bin.size);
if (ret_size >= 0) {
if (ret_size != res_bin.size) {
if (!enif_realloc_binary(&res_bin, ret_size))
goto error;
}
ret_term = enif_make_tuple2(env, atom_ok,
enif_make_binary(env, &res_bin));
enif_release_binary(&res_bin);
return ret_term;
}
error:
enif_release_binary(&res_bin);
return enif_make_tuple2(env, atom_error, atom_uncompress_failed);
}
static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
atom_ok = enif_make_atom(env, "ok");
atom_error = enif_make_atom(env, "error");
atom_high = enif_make_atom(env, "high");
atom_compress_failed = enif_make_atom(env, "compress_failed");
atom_uncompress_failed = enif_make_atom(env, "uncompress_failed");
return 0;
}
ERL_NIF_INIT(lz4, nif_funcs, &on_load, NULL, NULL, NULL);