static
const
char
*fugz_imps[] = {
""
,
"libdeflate"
,
"zlib-ng"
,
"zlib"
};
static
int
fugz_imp = -1;
typedef
struct
{
const
char
*next_in;
unsigned
int
avail_in;
unsigned
long
total_in;
char
*next_out;
unsigned
int
avail_out;
unsigned
long
total_out;
const
char
*msg;
struct
internal_state *state;
void
*zalloc;
void
*zfree;
void
*opaque;
int
data_type;
unsigned
long
adler;
unsigned
long
reserved;
} z_stream;
static
int
(*deflate)(z_stream *,
int
);
static
int
(*deflateEnd)(z_stream *);
static
int
(*deflateInit2)(z_stream *,
int
,
int
,
int
,
int
,
int
);
static
int
(*deflateInit2_)(z_stream *,
int
,
int
,
int
,
int
,
int
,
const
char
*,
int
);
static
unsigned
long
(*compressBound)(unsigned
long
);
static
struct
libdeflate_compressor *fugz_ld_ctx;
static
int
fugz_ld_comp = -1;
static
struct
libdeflate_compressor *(*libdeflate_alloc_compressor)(
int
);
static
void
(*libdeflate_free_compressor)(
struct
libdeflate_compressor *);
static
size_t
(*libdeflate_gzip_compress_bound)(
struct
libdeflate_compressor *,
size_t
);
static
size_t
(*libdeflate_gzip_compress)(
struct
libdeflate_compressor *,
const
void
*,
size_t
,
void
*,
size_t
);
static
const
char
*fugz_lib() {
if
(fugz_imp >= 0)
goto
done;
void
*handle;
if
((handle = dlopen(
"libdeflate.so"
, RTLD_LAZY))) {
if
((libdeflate_alloc_compressor = dlsym(handle,
"libdeflate_alloc_compressor"
))
&& (libdeflate_free_compressor = dlsym(handle,
"libdeflate_free_compressor"
))
&& (libdeflate_gzip_compress_bound = dlsym(handle,
"libdeflate_gzip_compress_bound"
))
&& (libdeflate_gzip_compress = dlsym(handle,
"libdeflate_gzip_compress"
))) {
fugz_imp = 1;
goto
done;
}
}
int
i;
for
(i=2; i<=3; i++) {
if
((handle = dlopen(i == 2 ?
"libz-ng.so"
:
"libz.so"
, RTLD_LAZY))) {
if
(((deflate = dlsym(handle,
"zng_deflate"
)) || (deflate = dlsym(handle,
"deflate"
)))
&& ((deflateEnd = dlsym(handle,
"zng_deflateEnd"
)) || (deflateEnd = dlsym(handle,
"deflateEnd"
)))
&& ((deflateInit2 = dlsym(handle,
"zng_deflateInit2"
)) || (deflateInit2_ = dlsym(handle,
"deflateInit2_"
)))
&& ((compressBound = dlsym(handle,
"zng_compressBound"
)) || (compressBound = dlsym(handle,
"compressBound"
)))) {
fugz_imp = i;
goto
done;
}
}
}
fugz_imp = 0;
done:
return
fugz_imps[fugz_imp];
}
static
SV *fugz_compress_ld(pTHX_
int
level,
const
char
*bytes,
size_t
inlen) {
if
(fugz_ld_comp != level) {
if
(fugz_ld_ctx) libdeflate_free_compressor(fugz_ld_ctx);
fugz_ld_ctx = NULL;
fugz_ld_comp = level;
}
if
(!fugz_ld_ctx) fugz_ld_ctx = libdeflate_alloc_compressor(level);
size_t
outlen = libdeflate_gzip_compress_bound(fugz_ld_ctx, inlen);
SV *out = sv_2mortal(newSV(outlen));
SvPOK_only(out);
size_t
len = libdeflate_gzip_compress(fugz_ld_ctx, bytes, inlen, SvPVX(out), outlen);
if
(!len) fu_confess(
"Libdeflate compression failed"
);
SvCUR_set(out, len);
return
out;
}
static
SV *fugz_compress_zlib(pTHX_
int
level,
const
char
*bytes,
size_t
inlen) {
z_stream stream;
memset
(&stream, 0,
sizeof
(stream));
int
r = deflateInit2
? deflateInit2(&stream, level > 9 ? 9 : level, 8, 16+15, 9, 0)
: deflateInit2_(&stream, level > 9 ? 9 : level, 8, 16+15, 9, 0,
"1.3.1"
, (
int
)
sizeof
(stream));
if
(r) fu_confess(
"Zlib compression failed (%d)"
, r);
stream.avail_out = compressBound(inlen) + 64;
SV *out = sv_2mortal(newSV(stream.avail_out));
SvPOK_only(out);
stream.next_out = SvPVX(out);
stream.next_in = bytes;
stream.avail_in = inlen;
if
((r = deflate(&stream, 4)) != 1) fu_confess(
"Zlib compression failed (%d)"
, r);
SvCUR_set(out, stream.total_out);
deflateEnd(&stream);
return
out;
}
static
SV *fugz_compress(pTHX_ IV level, SV *in) {
if
(level < 0 || level > 12) fu_confess(
"Invalid compression level: %"
IVdf, level);
if
(!*fugz_lib()) fu_confess(
"Unable to load a suitable compression library"
);
STRLEN inlen;
const
char
*bytes = SvPVbyte(in, inlen);
if
(fugz_imp == 1)
return
fugz_compress_ld(aTHX_ level, bytes, inlen);
else
return
fugz_compress_zlib(aTHX_ level, bytes, inlen);
}
typedef
enum
{ BROTLI_MODE_GENERIC = 0, BROTLI_MODE_TEXT = 1, BROTLI_MODE_FONT = 2 } BrotliEncoderMode;
static
size_t
(*BrotliEncoderMaxCompressedSize)(
size_t
);
static
int
(*BrotliEncoderCompress)(
int
,
int
, BrotliEncoderMode,
size_t
,
const
char
*,
size_t
*,
char
*);
static
SV *fubr_compress(pTHX_ IV level, SV *in) {
if
(!BrotliEncoderCompress) {
void
*handle;
if
(!(handle = dlopen(
"libbrotlienc.so"
, RTLD_LAZY))
|| !(BrotliEncoderMaxCompressedSize = dlsym(handle,
"BrotliEncoderMaxCompressedSize"
))
|| !(BrotliEncoderCompress = dlsym(handle,
"BrotliEncoderCompress"
)))
fu_confess(
"Unable to load libbrotlienc.so: %s"
, dlerror());
}
if
(level < 0 || level > 11) fu_confess(
"Invalid compression level: %"
IVdf, level);
STRLEN inlen;
const
char
*bytes = SvPVbyte(in, inlen);
size_t
outlen = BrotliEncoderMaxCompressedSize(inlen);
if
(level < 2 && outlen < inlen + 256) outlen = inlen + 256;
SV *out = sv_2mortal(newSV(outlen));
SvPOK_only(out);
if
(!BrotliEncoderCompress(level, 22, BROTLI_MODE_GENERIC, inlen, bytes, &outlen, SvPVX(out)))
fu_confess(
"Brotli compression failed"
);
SvCUR_set(out, outlen);
return
out;
}