#ifdef __cplusplus
extern "C" {
#endif
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#define NEED_sv_2pvbyte
#define NEED_newCONSTSUB
#include "ppport.h"
#include "zstd.h"
#include "compress/zstdmt_compress.h"
typedef struct Compress__Zstd__Compressor_s {
ZSTD_CStream* stream;
char* buf;
size_t bufsize;
}* Compress__Zstd__Compressor;
typedef struct Compress__Zstd__Decompressor_s {
ZSTD_DStream* stream;
char* buf;
size_t bufsize;
}* Compress__Zstd__Decompressor;
typedef ZSTD_CCtx* Compress__Zstd__CompressionContext;
typedef ZSTD_DCtx* Compress__Zstd__DecompressionContext;
typedef ZSTD_CDict* Compress__Zstd__CompressionDictionary;
typedef ZSTD_DDict* Compress__Zstd__DecompressionDictionary;
static SV*
decompress_using_streaming(pTHX_ const char* src, size_t srcSize)
{
char* buf;
size_t bufsize;
SV* output;
ZSTD_inBuffer inbuf = { src, srcSize, 0 };
int iserror = 0;
ZSTD_DStream* stream = ZSTD_createDStream();
if (stream == NULL) {
croak("Failed to call ZSTD_createDStream()");
}
ZSTD_initDStream(stream);
bufsize = ZSTD_DStreamOutSize();
Newx(buf, bufsize, char);
output = newSVpv("", 0);
while (inbuf.pos < inbuf.size) {
ZSTD_outBuffer outbuf = { buf, bufsize, 0 };
size_t ret = ZSTD_decompressStream(stream, &outbuf, &inbuf);
if (ZSTD_isError(ret)) {
iserror = 1;
break;
}
sv_catpvn(output, outbuf.dst, outbuf.pos);
}
Safefree(buf);
ZSTD_freeDStream(stream);
if (iserror != 0) {
SvREFCNT_dec(output);
return NULL;
}
return output;
}
MODULE = Compress::Zstd PACKAGE = Compress::Zstd
BOOT:
{
HV* stash = gv_stashpv("Compress::Zstd", 1);
newCONSTSUB(stash, "ZSTD_VERSION_NUMBER", newSViv(ZSTD_VERSION_NUMBER));
newCONSTSUB(stash, "ZSTD_VERSION_STRING", newSVpvs(ZSTD_VERSION_STRING));
newCONSTSUB(stash, "ZSTD_MAX_CLEVEL", newSViv(ZSTD_maxCLevel()));
}
PROTOTYPES: DISABLE
void
compress(source, level = 1)
SV* source;
int level;
PREINIT:
const char* src;
STRLEN src_len;
SV* dest;
char* dst;
size_t bound, ret;
PPCODE:
if (SvROK(source)) {
source = SvRV(source);
}
if (!SvOK(source)) {
XSRETURN_UNDEF;
}
src = SvPVbyte(source, src_len);
bound = ZSTD_compressBound(src_len);
dest = sv_2mortal(newSV(bound + 1));
dst = SvPVX(dest);
ret = ZSTD_compress(dst, bound + 1, src, src_len, level);
if (ZSTD_isError(ret)) {
XSRETURN_UNDEF;
}
dst[ret] = '\0';
SvCUR_set(dest, ret);
SvPOK_on(dest);
EXTEND(SP, 1);
PUSHs(dest);
void
compress_mt(source, nbThreads, level = 1)
SV* source;
unsigned int nbThreads;
int level;
PREINIT:
const char* src;
STRLEN src_len;
SV* dest;
char* dst;
size_t bound, ret;
ZSTDMT_CCtx* cctx;
PPCODE:
if (SvROK(source)) {
source = SvRV(source);
}
if (!SvOK(source)) {
XSRETURN_UNDEF;
}
cctx = ZSTDMT_createCCtx(nbThreads);
src = SvPVbyte(source, src_len);
bound = ZSTD_compressBound(src_len);
dest = sv_2mortal(newSV(bound + 1));
dst = SvPVX(dest);
ret = ZSTDMT_compressCCtx(cctx, dst, bound + 1, src, src_len, level);
ZSTDMT_freeCCtx(cctx);
if (ZSTD_isError(ret)) {
XSRETURN_UNDEF;
}
dst[ret] = '\0';
SvCUR_set(dest, ret);
SvPOK_on(dest);
EXTEND(SP, 1);
PUSHs(dest);
void
decompress(source)
SV* source;
ALIAS:
uncompress = 1
PREINIT:
const char* src;
STRLEN src_len;
unsigned long long dest_len;
SV* dest;
char* dst;
size_t ret;
PPCODE:
if (SvROK(source)) {
source = SvRV(source);
}
if (!SvOK(source)) {
XSRETURN_UNDEF;
}
src = SvPVbyte(source, src_len);
dest_len = ZSTD_getFrameContentSize(src, src_len);
if (dest_len == ZSTD_CONTENTSIZE_UNKNOWN) {
SV* output = decompress_using_streaming(aTHX_ src, src_len);
if (output == NULL) {
XSRETURN_UNDEF;
}
EXTEND(SP, 1);
mPUSHs(output);
XSRETURN(1);
}
if (dest_len == ULLONG_MAX || ZSTD_isError(dest_len)) {
XSRETURN_UNDEF;
}
dest = sv_2mortal(newSV(dest_len + 1));
dst = SvPVX(dest);
ret = ZSTD_decompress(dst, dest_len + 1, src, src_len);
if (ZSTD_isError(ret)) {
XSRETURN_UNDEF;
}
dst[ret] = '\0';
SvCUR_set(dest, ret);
SvPOK_on(dest);
EXTEND(SP, 1);
PUSHs(dest);
XSRETURN(1);
MODULE = Compress::Zstd PACKAGE = Compress::Zstd::Compressor
PROTOTYPES: DISABLE
BOOT:
{
HV* stash = gv_stashpv("Compress::Zstd::Compressor", 1);
newCONSTSUB(stash, "ZSTD_CSTREAM_IN_SIZE", newSViv(ZSTD_CStreamInSize()));
}
Compress::Zstd::Compressor
new(klass, level = 1)
const char* klass;
int level;
PREINIT:
Compress__Zstd__Compressor self;
char* buf;
size_t bufsize;
CODE:
ZSTD_CStream* stream = ZSTD_createCStream();
if (stream == NULL) {
croak("Failed to call ZSTD_createCStream()");
}
ZSTD_initCStream(stream, level);
Newx(self, sizeof(struct Compress__Zstd__Compressor_s), struct Compress__Zstd__Compressor_s);
self->stream = stream;
bufsize = ZSTD_CStreamOutSize();
Newx(buf, bufsize, char);
self->buf = buf;
self->bufsize = bufsize;
RETVAL = self;
OUTPUT:
RETVAL
void
init(self, level = 1)
Compress::Zstd::Compressor self;
int level;
CODE:
ZSTD_initCStream(self->stream, level);
SV*
compress(self, input)
Compress::Zstd::Compressor self;
SV* input;
PREINIT:
STRLEN len;
SV* output;
CODE:
const char* in = SvPVbyte(input, len);
ZSTD_inBuffer inbuf = { in, len, 0 };
output = newSVpv("", 0);
while (inbuf.pos < inbuf.size) {
ZSTD_outBuffer outbuf = { self->buf, self->bufsize, 0 };
size_t toread = ZSTD_compressStream(self->stream, &outbuf, &inbuf);
if (ZSTD_isError(toread)) {
croak("%s", ZSTD_getErrorName(toread));
}
sv_catpvn(output, outbuf.dst, outbuf.pos);
}
RETVAL = output;
OUTPUT:
RETVAL
SV*
flush(self)
Compress::Zstd::Compressor self;
PREINIT:
SV* output;
size_t ret;
CODE:
output = newSVpv("", 0);
do {
ZSTD_outBuffer outbuf = { self->buf, self->bufsize, 0 };
ret = ZSTD_flushStream(self->stream, &outbuf);
if (ZSTD_isError(ret)) {
croak("%s", ZSTD_getErrorName(ret));
}
sv_catpvn(output, outbuf.dst, outbuf.pos);
} while (ret > 0);
RETVAL = output;
OUTPUT:
RETVAL
SV*
end(self)
Compress::Zstd::Compressor self;
PREINIT:
SV* output;
size_t ret;
CODE:
output = newSVpv("", 0);
do {
ZSTD_outBuffer outbuf = { self->buf, self->bufsize, 0 };
ret = ZSTD_endStream(self->stream, &outbuf);
if (ZSTD_isError(ret)) {
croak("%s", ZSTD_getErrorName(ret));
}
sv_catpvn(output, outbuf.dst, outbuf.pos);
} while (ret > 0);
RETVAL = output;
OUTPUT:
RETVAL
void
DESTROY(self)
Compress::Zstd::Compressor self;
CODE:
ZSTD_freeCStream(self->stream);
Safefree(self->buf);
Safefree(self);
MODULE = Compress::Zstd PACKAGE = Compress::Zstd::Decompressor
PROTOTYPES: DISABLE
BOOT:
{
HV* stash = gv_stashpv("Compress::Zstd::Decompressor", 1);
newCONSTSUB(stash, "ZSTD_DSTREAM_IN_SIZE", newSViv(ZSTD_DStreamInSize()));
}
Compress::Zstd::Decompressor
new(klass)
const char* klass;
PREINIT:
Compress__Zstd__Decompressor self;
char* buf;
size_t bufsize;
CODE:
ZSTD_DStream* stream = ZSTD_createDStream();
if (stream == NULL) {
croak("Failed to call ZSTD_createDStream()");
}
ZSTD_initDStream(stream);
Newx(self, sizeof(struct Compress__Zstd__Decompressor_s), struct Compress__Zstd__Decompressor_s);
self->stream = stream;
bufsize = ZSTD_DStreamOutSize();
Newx(buf, bufsize, char);
self->buf = buf;
self->bufsize = bufsize;
RETVAL = self;
OUTPUT:
RETVAL
void
init(self)
Compress::Zstd::Decompressor self;
CODE:
ZSTD_initDStream(self->stream);
SV*
decompress(self, input)
Compress::Zstd::Decompressor self;
SV* input;
PREINIT:
STRLEN len;
SV* output;
CODE:
const char* in = SvPVbyte(input, len);
ZSTD_inBuffer inbuf = { in, len, 0 };
output = newSVpv("", 0);
while (inbuf.pos < inbuf.size) {
ZSTD_outBuffer outbuf = { self->buf, self->bufsize, 0 };
size_t ret = ZSTD_decompressStream(self->stream, &outbuf, &inbuf);
if (ZSTD_isError(ret)) {
croak("%s", ZSTD_getErrorName(ret));
}
sv_catpvn(output, outbuf.dst, outbuf.pos);
}
RETVAL = output;
OUTPUT:
RETVAL
void
DESTROY(self)
Compress::Zstd::Decompressor self;
CODE:
ZSTD_freeDStream(self->stream);
Safefree(self->buf);
Safefree(self);
MODULE = Compress::Zstd PACKAGE = Compress::Zstd::CompressionContext
PROTOTYPES: DISABLE
Compress::Zstd::CompressionContext
new(klass)
const char* klass;
CODE:
ZSTD_CCtx* cctx = ZSTD_createCCtx();
if (cctx == NULL) {
croak("Failed to call ZSTD_createCCtx()");
}
RETVAL = (Compress__Zstd__CompressionContext) cctx;
OUTPUT:
RETVAL
SV*
compress(self, source, level = 1)
Compress::Zstd::CompressionContext self;
SV* source;
int level;
PREINIT:
const char* src;
STRLEN src_len;
SV* dest;
char* dst;
size_t bound, ret;
PPCODE:
if (!SvOK(source)) {
XSRETURN_UNDEF;
}
src = SvPVbyte(source, src_len);
bound = ZSTD_compressBound(src_len);
dest = sv_2mortal(newSV(bound + 1));
dst = SvPVX(dest);
ret = ZSTD_compressCCtx((ZSTD_CCtx*) self, dst, bound + 1, src, src_len, level);
if (ZSTD_isError(ret)) {
XSRETURN_UNDEF;
}
dst[ret] = '\0';
SvCUR_set(dest, ret);
SvPOK_on(dest);
EXTEND(SP, 1);
PUSHs(dest);
SV*
compress_using_dict(self, source, dict)
Compress::Zstd::CompressionContext self;
SV* source;
Compress::Zstd::CompressionDictionary dict;
PREINIT:
const char* src;
STRLEN src_len;
SV* dest;
char* dst;
size_t bound, ret;
PPCODE:
if (!SvOK(source)) {
XSRETURN_UNDEF;
}
src = SvPVbyte(source, src_len);
bound = ZSTD_compressBound(src_len);
dest = sv_2mortal(newSV(bound + 1));
dst = SvPVX(dest);
ret = ZSTD_compress_usingCDict((ZSTD_CCtx*) self, dst, bound + 1, src, src_len, (ZSTD_CDict*) dict);
if (ZSTD_isError(ret)) {
XSRETURN_UNDEF;
}
dst[ret] = '\0';
SvCUR_set(dest, ret);
SvPOK_on(dest);
EXTEND(SP, 1);
PUSHs(dest);
void
DESTROY(self)
Compress::Zstd::CompressionContext self;
CODE:
ZSTD_freeCCtx((ZSTD_CCtx*) self);
MODULE = Compress::Zstd PACKAGE = Compress::Zstd::DecompressionContext
PROTOTYPES: DISABLE
Compress::Zstd::DecompressionContext
new(klass)
const char* klass;
CODE:
ZSTD_DCtx* dctx = ZSTD_createDCtx();
if (dctx == NULL) {
croak("Failed to call ZSTD_createDCtx()");
}
RETVAL = (Compress__Zstd__DecompressionContext) dctx;
OUTPUT:
RETVAL
SV*
decompress(self, source)
Compress::Zstd::DecompressionContext self;
SV* source;
ALIAS:
uncompress = 1
PREINIT:
const char* src;
STRLEN src_len;
unsigned long long dest_len;
SV* dest;
char* dst;
size_t ret;
PPCODE:
if (!SvOK(source)) {
XSRETURN_UNDEF;
}
src = SvPVbyte(source, src_len);
dest_len = ZSTD_getFrameContentSize(src, src_len);
if (dest_len == ZSTD_CONTENTSIZE_UNKNOWN || dest_len == ULLONG_MAX || ZSTD_isError(dest_len)) {
/* TODO: Support ZSTD_CONTENTSIZE_UNKNOWN */
XSRETURN_UNDEF;
}
dest = sv_2mortal(newSV(dest_len + 1));
dst = SvPVX(dest);
ret = ZSTD_decompressDCtx((ZSTD_DCtx*) self, dst, dest_len + 1, src, src_len);
if (ZSTD_isError(ret)) {
XSRETURN_UNDEF;
}
dst[ret] = '\0';
SvCUR_set(dest, ret);
SvPOK_on(dest);
EXTEND(SP, 1);
PUSHs(dest);
SV*
decompress_using_dict(self, source, dict)
Compress::Zstd::DecompressionContext self;
SV* source;
Compress::Zstd::DecompressionDictionary dict;
PREINIT:
const char* src;
STRLEN src_len;
unsigned long long dest_len;
SV* dest;
char* dst;
size_t ret;
PPCODE:
if (!SvOK(source)) {
XSRETURN_UNDEF;
}
src = SvPVbyte(source, src_len);
dest_len = ZSTD_getFrameContentSize(src, src_len);
if (dest_len == ZSTD_CONTENTSIZE_UNKNOWN || dest_len == ULLONG_MAX || ZSTD_isError(dest_len)) {
/* TODO: Support ZSTD_CONTENTSIZE_UNKNOWN */
XSRETURN_UNDEF;
}
dest = sv_2mortal(newSV(dest_len + 1));
dst = SvPVX(dest);
ret = ZSTD_decompress_usingDDict((ZSTD_DCtx*) self, dst, dest_len + 1, src, src_len, (ZSTD_DDict*) dict);
if (ZSTD_isError(ret)) {
XSRETURN_UNDEF;
}
dst[ret] = '\0';
SvCUR_set(dest, ret);
SvPOK_on(dest);
EXTEND(SP, 1);
PUSHs(dest);
void
DESTROY(self)
Compress::Zstd::DecompressionContext self;
CODE:
ZSTD_freeDCtx((ZSTD_DCtx*) self);
MODULE = Compress::Zstd PACKAGE = Compress::Zstd::CompressionDictionary
PROTOTYPES: DISABLE
Compress::Zstd::CompressionDictionary
new(klass, dict, level = 1)
const char* klass;
SV* dict;
int level;
PREINIT:
ZSTD_CDict* cdict;
const char* dct;
size_t dct_len;
CODE:
dct = SvPVbyte(dict, dct_len);
cdict = ZSTD_createCDict(dct, dct_len, level);
if (cdict == NULL) {
croak("Failed to call ZSTD_createCDict()");
}
RETVAL = (Compress__Zstd__CompressionDictionary) cdict;
OUTPUT:
RETVAL
void
DESTROY(self)
Compress::Zstd::CompressionDictionary self;
CODE:
ZSTD_freeCDict((ZSTD_CDict*) self);
MODULE = Compress::Zstd PACKAGE = Compress::Zstd::DecompressionDictionary
PROTOTYPES: DISABLE
Compress::Zstd::DecompressionDictionary
new(klass, dict)
const char* klass;
SV* dict;
PREINIT:
ZSTD_DDict* ddict;
const char* dct;
size_t dct_len;
CODE:
dct = SvPVbyte(dict, dct_len);
ddict = ZSTD_createDDict(dct, dct_len);
if (ddict == NULL) {
croak("Failed to call ZSTD_createDDict()");
}
RETVAL = (Compress__Zstd__DecompressionDictionary) ddict;
OUTPUT:
RETVAL
void
DESTROY(self)
Compress::Zstd::DecompressionDictionary self;
CODE:
ZSTD_freeDDict((ZSTD_DDict*) self);