File Coverage

lib/Compress/Zstd.xs
Criterion Covered Total %
statement 193 224 86.1
branch 70 152 46.0
condition n/a
subroutine n/a
pod n/a
total 263 376 69.9


line stmt bran cond sub pod time code
1             #ifdef __cplusplus
2             extern "C" {
3             #endif
4             #define PERL_NO_GET_CONTEXT
5             #include "EXTERN.h"
6             #include "perl.h"
7             #include "XSUB.h"
8             #ifdef __cplusplus
9             }
10             #endif
11              
12             #define NEED_sv_2pvbyte
13             #define NEED_newCONSTSUB
14             #include "ppport.h"
15             #include "zstd.h"
16             #include "compress/zstdmt_compress.h"
17              
18             typedef struct Compress__Zstd__Compressor_s {
19             ZSTD_CStream* stream;
20             char* buf;
21             size_t bufsize;
22             }* Compress__Zstd__Compressor;
23              
24             typedef struct Compress__Zstd__Decompressor_s {
25             ZSTD_DStream* stream;
26             char* buf;
27             size_t bufsize;
28             }* Compress__Zstd__Decompressor;
29              
30             typedef ZSTD_CCtx* Compress__Zstd__CompressionContext;
31              
32             typedef ZSTD_DCtx* Compress__Zstd__DecompressionContext;
33              
34             typedef ZSTD_CDict* Compress__Zstd__CompressionDictionary;
35              
36             typedef ZSTD_DDict* Compress__Zstd__DecompressionDictionary;
37              
38             static SV*
39 1           decompress_using_streaming(pTHX_ const char* src, size_t srcSize)
40             {
41             char* buf;
42             size_t bufsize;
43             SV* output;
44 1           ZSTD_inBuffer inbuf = { src, srcSize, 0 };
45             int iserror = 0;
46              
47 1           ZSTD_DStream* stream = ZSTD_createDStream();
48 1 50         if (stream == NULL) {
49 0           croak("Failed to call ZSTD_createDStream()");
50             }
51 1           ZSTD_initDStream(stream);
52              
53 1           bufsize = ZSTD_DStreamOutSize();
54 1           Newx(buf, bufsize, char);
55              
56 1           output = newSVpv("", 0);
57 2 100         while (inbuf.pos < inbuf.size) {
58 1           ZSTD_outBuffer outbuf = { buf, bufsize, 0 };
59 1           size_t ret = ZSTD_decompressStream(stream, &outbuf, &inbuf);
60 1 50         if (ZSTD_isError(ret)) {
61             iserror = 1;
62 0           break;
63             }
64 1           sv_catpvn(output, outbuf.dst, outbuf.pos);
65             }
66 1           Safefree(buf);
67 1           ZSTD_freeDStream(stream);
68 1 50         if (iserror != 0) {
69             SvREFCNT_dec(output);
70             return NULL;
71             }
72             return output;
73             }
74              
75             MODULE = Compress::Zstd PACKAGE = Compress::Zstd
76              
77             BOOT:
78             {
79 5           HV* stash = gv_stashpv("Compress::Zstd", 1);
80 5           newCONSTSUB(stash, "ZSTD_VERSION_NUMBER", newSViv(ZSTD_VERSION_NUMBER));
81 5           newCONSTSUB(stash, "ZSTD_VERSION_STRING", newSVpvs(ZSTD_VERSION_STRING));
82 5           newCONSTSUB(stash, "ZSTD_MAX_CLEVEL", newSViv(ZSTD_maxCLevel()));
83             }
84              
85             PROTOTYPES: DISABLE
86              
87             void
88             compress(source, level = 1)
89             SV* source;
90             int level;
91             PREINIT:
92             const char* src;
93             STRLEN src_len;
94             SV* dest;
95             char* dst;
96             size_t bound, ret;
97             PPCODE:
98 2 100         if (SvROK(source)) {
99 1           source = SvRV(source);
100             }
101 2 50         if (!SvOK(source)) {
    0          
    0          
102 0           XSRETURN_UNDEF;
103             }
104 2 50         src = SvPVbyte(source, src_len);
105 2           bound = ZSTD_compressBound(src_len);
106 2           dest = sv_2mortal(newSV(bound + 1));
107 2           dst = SvPVX(dest);
108 2           ret = ZSTD_compress(dst, bound + 1, src, src_len, level);
109 2 50         if (ZSTD_isError(ret)) {
110 0           XSRETURN_UNDEF;
111             }
112 2           dst[ret] = '\0';
113 2           SvCUR_set(dest, ret);
114 2           SvPOK_on(dest);
115 2 50         EXTEND(SP, 1);
116 2           PUSHs(dest);
117              
118             void
119             compress_mt(source, nbThreads, level = 1)
120             SV* source;
121             unsigned int nbThreads;
122             int level;
123             PREINIT:
124             const char* src;
125             STRLEN src_len;
126             SV* dest;
127             char* dst;
128             size_t bound, ret;
129             ZSTDMT_CCtx* cctx;
130             PPCODE:
131 2 100         if (SvROK(source)) {
132 1           source = SvRV(source);
133             }
134 2 50         if (!SvOK(source)) {
    0          
    0          
135 0           XSRETURN_UNDEF;
136             }
137 2           cctx = ZSTDMT_createCCtx(nbThreads);
138 2 50         src = SvPVbyte(source, src_len);
139 2           bound = ZSTD_compressBound(src_len);
140 2           dest = sv_2mortal(newSV(bound + 1));
141 2           dst = SvPVX(dest);
142 2           ret = ZSTDMT_compressCCtx(cctx, dst, bound + 1, src, src_len, level);
143 2           ZSTDMT_freeCCtx(cctx);
144 2 50         if (ZSTD_isError(ret)) {
145 0           XSRETURN_UNDEF;
146             }
147 2           dst[ret] = '\0';
148 2           SvCUR_set(dest, ret);
149 2           SvPOK_on(dest);
150 2 50         EXTEND(SP, 1);
151 2           PUSHs(dest);
152              
153             void
154             decompress(source)
155             SV* source;
156             ALIAS:
157             uncompress = 1
158             PREINIT:
159             const char* src;
160             STRLEN src_len;
161             unsigned long long dest_len;
162             SV* dest;
163             char* dst;
164             size_t ret;
165             PPCODE:
166 7 100         if (SvROK(source)) {
167 1           source = SvRV(source);
168             }
169 7 50         if (!SvOK(source)) {
    0          
    0          
170 0           XSRETURN_UNDEF;
171             }
172 7 50         src = SvPVbyte(source, src_len);
173 7           dest_len = ZSTD_getFrameContentSize(src, src_len);
174 7 100         if (dest_len == ZSTD_CONTENTSIZE_UNKNOWN) {
175 1           SV* output = decompress_using_streaming(aTHX_ src, src_len);
176 1 50         if (output == NULL) {
177 0           XSRETURN_UNDEF;
178             }
179 1 50         EXTEND(SP, 1);
180 1           mPUSHs(output);
181 1           XSRETURN(1);
182             }
183 6 50         if (dest_len == ULLONG_MAX || ZSTD_isError(dest_len)) {
    100          
184 1           XSRETURN_UNDEF;
185             }
186 5           dest = sv_2mortal(newSV(dest_len + 1));
187 5           dst = SvPVX(dest);
188 5           ret = ZSTD_decompress(dst, dest_len + 1, src, src_len);
189 5 50         if (ZSTD_isError(ret)) {
190 0           XSRETURN_UNDEF;
191             }
192 5           dst[ret] = '\0';
193 5           SvCUR_set(dest, ret);
194 5           SvPOK_on(dest);
195 5 50         EXTEND(SP, 1);
196 5           PUSHs(dest);
197 5           XSRETURN(1);
198              
199             MODULE = Compress::Zstd PACKAGE = Compress::Zstd::Compressor
200              
201             PROTOTYPES: DISABLE
202              
203             BOOT:
204             {
205 5           HV* stash = gv_stashpv("Compress::Zstd::Compressor", 1);
206 5           newCONSTSUB(stash, "ZSTD_CSTREAM_IN_SIZE", newSViv(ZSTD_CStreamInSize()));
207             }
208              
209             Compress::Zstd::Compressor
210             new(klass, level = 1)
211             const char* klass;
212             int level;
213             PREINIT:
214             Compress__Zstd__Compressor self;
215             char* buf;
216             size_t bufsize;
217             CODE:
218 1           ZSTD_CStream* stream = ZSTD_createCStream();
219 1 50         if (stream == NULL) {
220 0           croak("Failed to call ZSTD_createCStream()");
221             }
222 1           ZSTD_initCStream(stream, level);
223              
224 1           Newx(self, sizeof(struct Compress__Zstd__Compressor_s), struct Compress__Zstd__Compressor_s);
225 1           self->stream = stream;
226 1           bufsize = ZSTD_CStreamOutSize();
227 1           Newx(buf, bufsize, char);
228 1           self->buf = buf;
229 1           self->bufsize = bufsize;
230             RETVAL = self;
231             OUTPUT:
232             RETVAL
233              
234             void
235             init(self, level = 1)
236             Compress::Zstd::Compressor self;
237             int level;
238             CODE:
239 0           ZSTD_initCStream(self->stream, level);
240              
241             SV*
242             compress(self, input)
243             Compress::Zstd::Compressor self;
244             SV* input;
245             PREINIT:
246             STRLEN len;
247             SV* output;
248             CODE:
249 3 50         const char* in = SvPVbyte(input, len);
250 3           ZSTD_inBuffer inbuf = { in, len, 0 };
251 3           output = newSVpv("", 0);
252 6 100         while (inbuf.pos < inbuf.size) {
253 3           ZSTD_outBuffer outbuf = { self->buf, self->bufsize, 0 };
254 3           size_t toread = ZSTD_compressStream(self->stream, &outbuf, &inbuf);
255 3 50         if (ZSTD_isError(toread)) {
256 0           croak("%s", ZSTD_getErrorName(toread));
257             }
258 3           sv_catpvn(output, outbuf.dst, outbuf.pos);
259             }
260             RETVAL = output;
261             OUTPUT:
262             RETVAL
263              
264             SV*
265             flush(self)
266             Compress::Zstd::Compressor self;
267             PREINIT:
268             SV* output;
269             size_t ret;
270             CODE:
271 1           output = newSVpv("", 0);
272             do {
273 1           ZSTD_outBuffer outbuf = { self->buf, self->bufsize, 0 };
274 1           ret = ZSTD_flushStream(self->stream, &outbuf);
275 1 50         if (ZSTD_isError(ret)) {
276 0           croak("%s", ZSTD_getErrorName(ret));
277             }
278 1           sv_catpvn(output, outbuf.dst, outbuf.pos);
279 1 50         } while (ret > 0);
280             RETVAL = output;
281             OUTPUT:
282             RETVAL
283              
284             SV*
285             end(self)
286             Compress::Zstd::Compressor self;
287             PREINIT:
288             SV* output;
289             size_t ret;
290             CODE:
291 1           output = newSVpv("", 0);
292             do {
293 1           ZSTD_outBuffer outbuf = { self->buf, self->bufsize, 0 };
294 1           ret = ZSTD_endStream(self->stream, &outbuf);
295 1 50         if (ZSTD_isError(ret)) {
296 0           croak("%s", ZSTD_getErrorName(ret));
297             }
298 1           sv_catpvn(output, outbuf.dst, outbuf.pos);
299 1 50         } while (ret > 0);
300             RETVAL = output;
301             OUTPUT:
302             RETVAL
303              
304             void
305             DESTROY(self)
306             Compress::Zstd::Compressor self;
307             CODE:
308 1           ZSTD_freeCStream(self->stream);
309 1           Safefree(self->buf);
310 1           Safefree(self);
311              
312             MODULE = Compress::Zstd PACKAGE = Compress::Zstd::Decompressor
313              
314             PROTOTYPES: DISABLE
315              
316             BOOT:
317             {
318 5           HV* stash = gv_stashpv("Compress::Zstd::Decompressor", 1);
319 5           newCONSTSUB(stash, "ZSTD_DSTREAM_IN_SIZE", newSViv(ZSTD_DStreamInSize()));
320             }
321              
322             Compress::Zstd::Decompressor
323             new(klass)
324             const char* klass;
325             PREINIT:
326             Compress__Zstd__Decompressor self;
327             char* buf;
328             size_t bufsize;
329             CODE:
330 1           ZSTD_DStream* stream = ZSTD_createDStream();
331 1 50         if (stream == NULL) {
332 0           croak("Failed to call ZSTD_createDStream()");
333             }
334 1           ZSTD_initDStream(stream);
335              
336 1           Newx(self, sizeof(struct Compress__Zstd__Decompressor_s), struct Compress__Zstd__Decompressor_s);
337 1           self->stream = stream;
338 1           bufsize = ZSTD_DStreamOutSize();
339 1           Newx(buf, bufsize, char);
340 1           self->buf = buf;
341 1           self->bufsize = bufsize;
342             RETVAL = self;
343             OUTPUT:
344             RETVAL
345              
346             void
347             init(self)
348             Compress::Zstd::Decompressor self;
349             CODE:
350 0           ZSTD_initDStream(self->stream);
351              
352             SV*
353             decompress(self, input)
354             Compress::Zstd::Decompressor self;
355             SV* input;
356             PREINIT:
357             STRLEN len;
358             SV* output;
359             CODE:
360 2 50         const char* in = SvPVbyte(input, len);
361 2           ZSTD_inBuffer inbuf = { in, len, 0 };
362 2           output = newSVpv("", 0);
363 4 100         while (inbuf.pos < inbuf.size) {
364 2           ZSTD_outBuffer outbuf = { self->buf, self->bufsize, 0 };
365 2           size_t ret = ZSTD_decompressStream(self->stream, &outbuf, &inbuf);
366 2 50         if (ZSTD_isError(ret)) {
367 0           croak("%s", ZSTD_getErrorName(ret));
368             }
369 2           sv_catpvn(output, outbuf.dst, outbuf.pos);
370             }
371             RETVAL = output;
372             OUTPUT:
373             RETVAL
374              
375             void
376             DESTROY(self)
377             Compress::Zstd::Decompressor self;
378             CODE:
379 1           ZSTD_freeDStream(self->stream);
380 1           Safefree(self->buf);
381 1           Safefree(self);
382              
383              
384             MODULE = Compress::Zstd PACKAGE = Compress::Zstd::CompressionContext
385              
386             PROTOTYPES: DISABLE
387              
388             Compress::Zstd::CompressionContext
389             new(klass)
390             const char* klass;
391             CODE:
392 2           ZSTD_CCtx* cctx = ZSTD_createCCtx();
393 2 50         if (cctx == NULL) {
394 0           croak("Failed to call ZSTD_createCCtx()");
395             }
396             RETVAL = (Compress__Zstd__CompressionContext) cctx;
397             OUTPUT:
398             RETVAL
399              
400             SV*
401             compress(self, source, level = 1)
402             Compress::Zstd::CompressionContext self;
403             SV* source;
404             int level;
405             PREINIT:
406             const char* src;
407             STRLEN src_len;
408             SV* dest;
409             char* dst;
410             size_t bound, ret;
411             PPCODE:
412 1 50         if (!SvOK(source)) {
    0          
    0          
413 0           XSRETURN_UNDEF;
414             }
415 1 50         src = SvPVbyte(source, src_len);
416 1           bound = ZSTD_compressBound(src_len);
417 1           dest = sv_2mortal(newSV(bound + 1));
418 1           dst = SvPVX(dest);
419 1           ret = ZSTD_compressCCtx((ZSTD_CCtx*) self, dst, bound + 1, src, src_len, level);
420 1 50         if (ZSTD_isError(ret)) {
421 0           XSRETURN_UNDEF;
422             }
423 1           dst[ret] = '\0';
424 1           SvCUR_set(dest, ret);
425 1           SvPOK_on(dest);
426 1 50         EXTEND(SP, 1);
427 1           PUSHs(dest);
428              
429             SV*
430             compress_using_dict(self, source, dict)
431             Compress::Zstd::CompressionContext self;
432             SV* source;
433             Compress::Zstd::CompressionDictionary dict;
434             PREINIT:
435             const char* src;
436             STRLEN src_len;
437             SV* dest;
438             char* dst;
439             size_t bound, ret;
440             PPCODE:
441 1 50         if (!SvOK(source)) {
    0          
    0          
442 0           XSRETURN_UNDEF;
443             }
444 1 50         src = SvPVbyte(source, src_len);
445 1           bound = ZSTD_compressBound(src_len);
446 1           dest = sv_2mortal(newSV(bound + 1));
447 1           dst = SvPVX(dest);
448 1           ret = ZSTD_compress_usingCDict((ZSTD_CCtx*) self, dst, bound + 1, src, src_len, (ZSTD_CDict*) dict);
449 1 50         if (ZSTD_isError(ret)) {
450 0           XSRETURN_UNDEF;
451             }
452 1           dst[ret] = '\0';
453 1           SvCUR_set(dest, ret);
454 1           SvPOK_on(dest);
455 1 50         EXTEND(SP, 1);
456 1           PUSHs(dest);
457              
458             void
459             DESTROY(self)
460             Compress::Zstd::CompressionContext self;
461             CODE:
462 2           ZSTD_freeCCtx((ZSTD_CCtx*) self);
463              
464              
465             MODULE = Compress::Zstd PACKAGE = Compress::Zstd::DecompressionContext
466              
467             PROTOTYPES: DISABLE
468              
469             Compress::Zstd::DecompressionContext
470             new(klass)
471             const char* klass;
472             CODE:
473 2           ZSTD_DCtx* dctx = ZSTD_createDCtx();
474 2 50         if (dctx == NULL) {
475 0           croak("Failed to call ZSTD_createDCtx()");
476             }
477             RETVAL = (Compress__Zstd__DecompressionContext) dctx;
478             OUTPUT:
479             RETVAL
480              
481             SV*
482             decompress(self, source)
483             Compress::Zstd::DecompressionContext self;
484             SV* source;
485             ALIAS:
486             uncompress = 1
487             PREINIT:
488             const char* src;
489             STRLEN src_len;
490             unsigned long long dest_len;
491             SV* dest;
492             char* dst;
493             size_t ret;
494             PPCODE:
495 1 50         if (!SvOK(source)) {
    0          
    0          
496 0           XSRETURN_UNDEF;
497             }
498 1 50         src = SvPVbyte(source, src_len);
499 1           dest_len = ZSTD_getFrameContentSize(src, src_len);
500 1 50         if (dest_len == ZSTD_CONTENTSIZE_UNKNOWN || dest_len == ULLONG_MAX || ZSTD_isError(dest_len)) {
    50          
501             /* TODO: Support ZSTD_CONTENTSIZE_UNKNOWN */
502 0           XSRETURN_UNDEF;
503             }
504 1           dest = sv_2mortal(newSV(dest_len + 1));
505 1           dst = SvPVX(dest);
506 1           ret = ZSTD_decompressDCtx((ZSTD_DCtx*) self, dst, dest_len + 1, src, src_len);
507 1 50         if (ZSTD_isError(ret)) {
508 0           XSRETURN_UNDEF;
509             }
510 1           dst[ret] = '\0';
511 1           SvCUR_set(dest, ret);
512 1           SvPOK_on(dest);
513 1 50         EXTEND(SP, 1);
514 1           PUSHs(dest);
515              
516             SV*
517             decompress_using_dict(self, source, dict)
518             Compress::Zstd::DecompressionContext self;
519             SV* source;
520             Compress::Zstd::DecompressionDictionary dict;
521             PREINIT:
522             const char* src;
523             STRLEN src_len;
524             unsigned long long dest_len;
525             SV* dest;
526             char* dst;
527             size_t ret;
528             PPCODE:
529 1 50         if (!SvOK(source)) {
    0          
    0          
530 0           XSRETURN_UNDEF;
531             }
532 1 50         src = SvPVbyte(source, src_len);
533 1           dest_len = ZSTD_getFrameContentSize(src, src_len);
534 1 50         if (dest_len == ZSTD_CONTENTSIZE_UNKNOWN || dest_len == ULLONG_MAX || ZSTD_isError(dest_len)) {
    50          
535             /* TODO: Support ZSTD_CONTENTSIZE_UNKNOWN */
536 0           XSRETURN_UNDEF;
537             }
538 1           dest = sv_2mortal(newSV(dest_len + 1));
539 1           dst = SvPVX(dest);
540 1           ret = ZSTD_decompress_usingDDict((ZSTD_DCtx*) self, dst, dest_len + 1, src, src_len, (ZSTD_DDict*) dict);
541 1 50         if (ZSTD_isError(ret)) {
542 0           XSRETURN_UNDEF;
543             }
544 1           dst[ret] = '\0';
545 1           SvCUR_set(dest, ret);
546 1           SvPOK_on(dest);
547 1 50         EXTEND(SP, 1);
548 1           PUSHs(dest);
549              
550             void
551             DESTROY(self)
552             Compress::Zstd::DecompressionContext self;
553             CODE:
554 2           ZSTD_freeDCtx((ZSTD_DCtx*) self);
555              
556             MODULE = Compress::Zstd PACKAGE = Compress::Zstd::CompressionDictionary
557              
558             PROTOTYPES: DISABLE
559              
560             Compress::Zstd::CompressionDictionary
561             new(klass, dict, level = 1)
562             const char* klass;
563             SV* dict;
564             int level;
565             PREINIT:
566             ZSTD_CDict* cdict;
567             const char* dct;
568             size_t dct_len;
569             CODE:
570 1 50         dct = SvPVbyte(dict, dct_len);
571 1           cdict = ZSTD_createCDict(dct, dct_len, level);
572 1 50         if (cdict == NULL) {
573 0           croak("Failed to call ZSTD_createCDict()");
574             }
575             RETVAL = (Compress__Zstd__CompressionDictionary) cdict;
576             OUTPUT:
577             RETVAL
578              
579             void
580             DESTROY(self)
581             Compress::Zstd::CompressionDictionary self;
582             CODE:
583 1           ZSTD_freeCDict((ZSTD_CDict*) self);
584              
585             MODULE = Compress::Zstd PACKAGE = Compress::Zstd::DecompressionDictionary
586              
587             PROTOTYPES: DISABLE
588              
589             Compress::Zstd::DecompressionDictionary
590             new(klass, dict)
591             const char* klass;
592             SV* dict;
593             PREINIT:
594             ZSTD_DDict* ddict;
595             const char* dct;
596             size_t dct_len;
597             CODE:
598 1 50         dct = SvPVbyte(dict, dct_len);
599 1           ddict = ZSTD_createDDict(dct, dct_len);
600 1 50         if (ddict == NULL) {
601 0           croak("Failed to call ZSTD_createDDict()");
602             }
603             RETVAL = (Compress__Zstd__DecompressionDictionary) ddict;
604             OUTPUT:
605             RETVAL
606              
607             void
608             DESTROY(self)
609             Compress::Zstd::DecompressionDictionary self;
610             CODE:
611 1           ZSTD_freeDDict((ZSTD_DDict*) self);