File Coverage

BsDiPa.xs
Criterion Covered Total %
statement 136 156 87.1
branch 75 104 72.1
condition n/a
subroutine n/a
pod n/a
total 211 260 81.1


line stmt bran cond sub pod time code
1             /*@ BsDiPa.xs: perl XS interface of/to S-bsdipa.
2             *@
3             *@ Remarks:
4             *@ - code requires ISO STD C99 (for now).
5             *
6             * Copyright (c) 2024 - 2026 Steffen Nurpmeso .
7             * SPDX-License-Identifier: ISC
8             *
9             * Permission to use, copy, modify, and/or distribute this software for any
10             * purpose with or without fee is hereby granted, provided that the above
11             * copyright notice and this permission notice appear in all copies.
12             *
13             * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14             * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15             * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16             * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17             * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18             * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19             * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20             */
21              
22             /* assert()ions (otherwise uncomment OPTIMIZE in Makefile.PL) */
23             /*#define DEBUGGING*/
24             #include "EXTERN.h"
25             #include "perl.h"
26             #include "XSUB.h"
27              
28             #include
29              
30             #define s_BSDIPA_IO_READ
31             #define s_BSDIPA_IO_WRITE
32             /**/
33             #if s__BSDIPA_BZ2
34             # undef s_BSDIPA_IO
35             # define s_BSDIPA_IO s_BSDIPA_IO_BZ2
36             # include "c-lib/s-bsdipa-io.h"
37             #endif
38             /**/
39             #undef s_BSDIPA_IO
40             #define s_BSDIPA_IO s_BSDIPA_IO_RAW
41             #include "c-lib/s-bsdipa-io.h"
42             /**/
43             #if s__BSDIPA_XZ
44             # undef s_BSDIPA_IO
45             # define s_BSDIPA_IO s_BSDIPA_IO_XZ
46             # include "c-lib/s-bsdipa-io.h"
47             #endif
48             /**/
49             #undef s_BSDIPA_IO
50             #define s_BSDIPA_IO s_BSDIPA_IO_ZLIB
51             #include "c-lib/s-bsdipa-io.h"
52             /**/
53             #if s__BSDIPA_ZSTD
54             # undef s_BSDIPA_IO
55             # define s_BSDIPA_IO s_BSDIPA_IO_ZSTD
56             # include "c-lib/s-bsdipa-io.h"
57             #endif
58              
59             #include
60             #include
61              
62             #define a_LEVEL_SET(LS,LV) LS = (LV < 0 ? 0 : LV > 9 ? 9 : LV)
63              
64             union a_io_cookie{
65             void *ioc_vp;
66             struct s_bsdipa_io_cookie *ioc_iocp;
67             #if s__BSDIPA_XZ
68             struct s_bsdipa_io_cookie_xz *ioc_iocJp;
69             #endif
70             #if s__BSDIPA_ZSTD
71             struct s_bsdipa_io_cookie_zstd *ioc_iocZp;
72             #endif
73             };
74              
75             static IV a_try_oneshot = -1;
76             static IV a_level = 0;
77             static IV const a_have_bz2 = s__BSDIPA_BZ2;
78             static IV const a_have_xz = s__BSDIPA_XZ;
79             static IV const a_have_zstd = s__BSDIPA_ZSTD;
80              
81             static void *a_alloc(size_t size);
82             static void a_free(void *vp);
83              
84             static SV *a_core_diff(int what, SV *before_sv, SV *after_sv, SV *patch_sv, SV *magic_window, SV *is_equal_data,
85             SV *io_cookie);
86             static enum s_bsdipa_state a_core_diff__write(void *user_cookie, uint8_t const *dat, s_bsdipa_off_t len,
87             s_bsdipa_off_t is_last);
88              
89             static SV *a_core_patch(int what, SV *after_sv, SV *patch_sv, SV *before_sv, SV *max_allowed_restored_len,
90             SV *io_cookie);
91              
92             static void *
93 3072           a_alloc(size_t size){
94             char *vp;
95              
96 3072           Newx(vp, size, char);
97              
98 3072           return vp;
99             }
100              
101             static void
102 2712           a_free(void *vp){
103 2712           Safefree(vp);
104 2712           }
105              
106             static SV *
107 1008           a_core_diff(int what, SV *before_sv, SV *after_sv, SV *patch_sv, SV *magic_window, SV *is_equal_data, SV *io_cookie){
108             struct s_bsdipa_io_cookie ioc, *iocp;
109             struct s_bsdipa_diff_ctx d;
110             SV *pref, *iseq;
111             enum s_bsdipa_state s;
112              
113 1008           s = s_BSDIPA_INVAL;
114              
115 1008           pref = NULL;
116 1008 100         if(/*!SvOK(patch_sv) ||*/ !SvROK(patch_sv))
117 288           goto jleave;
118 720           pref = SvRV(patch_sv);
119              
120 720 100         if(/*!SvOK(before_sv) ||*/ !SvPOK(before_sv))
121 144           goto jleave;
122              
123 576 100         if(/*!SvOK(after_sv) ||*/ !SvPOK(after_sv))
124 144           goto jleave;
125              
126 432 50         if(magic_window == NULL || !SvOK(magic_window))
    50          
127 432           d.dc_magic_window = 0;
128 0 0         else if(!SvIOK(magic_window))
129 0           goto jleave;
130             else{
131             IV i;
132              
133 0           i = SvIV(magic_window);
134 0 0         if(i > 4096) /* <> docu! */
135 0           goto jleave;
136 0           d.dc_magic_window = (int32_t)i;
137             }
138              
139 432 50         if(is_equal_data == NULL || !SvOK(is_equal_data))
    100          
140 144           iseq = NULL;
141 288 100         else if(!SvROK(is_equal_data))
142 144           goto jleave;
143             else
144 144           iseq = SvRV(is_equal_data);
145              
146 288 50         if(io_cookie == NULL || !SvIOK(io_cookie)){
    50          
147 288 100         if(a_level == 0)
148 216           iocp = NULL;
149             else{
150 72           memset(iocp = &ioc, 0, sizeof(ioc));
151 72           iocp->ioc_level = a_level;
152             }
153             }else
154 0           iocp = INT2PTR(struct s_bsdipa_io_cookie*,SvIV(io_cookie));
155              
156 288           d.dc_mem.mc_alloc = &a_alloc;
157 288           d.dc_mem.mc_free = &a_free;
158 288           d.dc_before_len = SvCUR(before_sv);
159 288           d.dc_before_dat = SvPVbyte_nolen(before_sv);
160 288           d.dc_after_len = SvCUR(after_sv);
161 288           d.dc_after_dat = SvPVbyte_nolen(after_sv);
162              
163 288           s = s_bsdipa_diff(&d);
164 288 50         if(s != s_BSDIPA_OK)
165 0           goto jdone;
166              
167 288 100         if(iseq != NULL)
168 144           SvIV_set(iseq, d.dc_is_equal_data);
169              
170             /* _RAW is very "unlikely" */
171 288           SvPVCLEAR(pref);
172 288 100         if(what == s_BSDIPA_IO_ZLIB)
173 144           s = s_bsdipa_io_write_zlib(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
174             #if s__BSDIPA_BZ2
175             else if(what == s_BSDIPA_IO_BZ2)
176             s = s_bsdipa_io_write_bz2(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
177             #endif
178             #if s__BSDIPA_XZ
179             else if(what == s_BSDIPA_IO_XZ)
180             s = s_bsdipa_io_write_xz(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
181             #endif
182             #if s__BSDIPA_ZSTD
183             else if(what == s_BSDIPA_IO_ZSTD)
184             s = s_bsdipa_io_write_zstd(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
185             #endif
186             else /*if(what == s_BSDIPA_IO_RAW)*/{
187             s_bsdipa_off_t x;
188              
189 144           x = sizeof(d.dc_header) + d.dc_ctrl_len + d.dc_diff_len + d.dc_extra_len +1;
190 144 50         SvGROW(pref, x);
    100          
191 144           SvCUR_set(pref, 0);
192 144           s = s_bsdipa_io_write_raw(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
193             }
194              
195 288           jdone:
196 288           s_bsdipa_diff_free(&d);
197              
198 1008           jleave:
199 1008 100         if(s != s_BSDIPA_OK && pref != NULL)
    100          
200 432           sv_setsv(pref, &PL_sv_undef);
201              
202 1008           return newSViv(s);
203             }
204              
205             static enum s_bsdipa_state
206 720           a_core_diff__write(void *user_cookie, uint8_t const *dat, s_bsdipa_off_t len, s_bsdipa_off_t is_last){
207             SV *p;
208             enum s_bsdipa_state rv;
209              
210 720 100         if(is_last >= 0 && len <= 0)
    100          
211 144           goto jok;
212              
213 576           p = (SV*)user_cookie;
214              
215             /* Buffer takeover? Even though likely short living, minimize wastage to XXX something reasonable */
216 576 100         if(is_last < 0 && (is_last > -65535 || is_last / 10 > -len)){
    100          
    50          
217             /* In this case the additional byte is guaranteed! */
218 72           ((uint8_t*)dat)[(unsigned long)len] = '\0';
219 72           sv_usepvn_flags(p, (char*)dat, len, SV_SMAGIC | SV_HAS_TRAILING_NUL);
220 72           assert(SvPVbyte_nolen(p)[SvCUR(p)] == '\0');
221             /*xxx instead sv_setpvn(p, dat, len);*/
222             }else{
223             char *cp;
224             s_bsdipa_off_t l;
225              
226 504           l = (s_bsdipa_off_t)SvCUR(p);
227              
228 504 50         cp = SvGROW(p, l + len +1);
    100          
229 504 50         if(cp == NULL){
230 0           rv = s_BSDIPA_NOMEM;
231 0           goto jleave;
232             }
233              
234 504           memcpy(&cp[(unsigned long)l], dat, len);
235 504           l += len;
236 504           cp[(unsigned long)l] = '\0'; /* mumble */
237 504           SvCUR_set(p, l);
238 504           SvPOK_only(p);
239 504 50         SvSETMAGIC(p);
240             assert(SvPVbyte_nolen(p)[SvCUR(p)] == '\0');
241              
242 504 100         if(is_last < 0)
243 24           a_free((void*)dat);
244             }
245              
246 480           jok:
247 720           rv = s_BSDIPA_OK;
248 720           jleave:
249 720           return rv;
250             }
251              
252             static SV *
253 1296           a_core_patch(int what, SV *after_sv, SV *patch_sv, SV *before_sv, SV *max_allowed_restored_len, SV *io_cookie){
254             struct s_bsdipa_patch_ctx p;
255             struct s_bsdipa_io_cookie *iocp;
256             SV *bref;
257             enum s_bsdipa_state s;
258              
259 1296           s = s_BSDIPA_INVAL;
260              
261 1296           bref = NULL;
262 1296 100         if(/*!SvOK(before_sv) ||*/ !SvROK(before_sv))
263 288           goto jleave;
264 1008           bref = SvRV(before_sv);
265              
266 1008 100         if(/*!SvOK(after_sv) ||*/ !SvPOK(after_sv))
267 144           goto jleave;
268              
269 864 100         if(/*!SvOK(patch_sv) ||*/ !SvPOK(patch_sv))
270 144           goto jleave;
271              
272 720           p.pc_max_allowed_restored_len = 0;
273 720 50         if(max_allowed_restored_len != NULL && SvOK(max_allowed_restored_len)){
    100          
274 576 100         if(!SvIOK(max_allowed_restored_len))
275 144           goto jleave;
276             else{
277             IV i;
278              
279 432           i = SvIV(max_allowed_restored_len);
280 432 100         if(i < 0 || (uint64_t)i != (s_bsdipa_off_t)i ||
    50          
281 288 50         (s_bsdipa_off_t)i >= s_BSDIPA_OFF_MAX)
282 144           goto jleave;
283 288           p.pc_max_allowed_restored_len = (uint64_t)i;
284             }
285             }
286              
287 432 100         if(io_cookie == NULL || !SvIOK(io_cookie))
    50          
288 432           iocp = NULL;
289             else
290 0           iocp = INT2PTR(struct s_bsdipa_io_cookie*,SvIV(io_cookie));
291              
292 432           p.pc_mem.mc_alloc = &a_alloc;
293 432           p.pc_mem.mc_free = &a_free;
294 432           p.pc_after_len = SvCUR(after_sv);
295 432           p.pc_after_dat = SvPVbyte_nolen(after_sv);
296              
297 432           p.pc_patch_len = SvCUR(patch_sv);
298 432           p.pc_patch_dat = SvPVbyte_nolen(patch_sv);
299              
300             /* _RAW is very "unlikely" */
301 432 100         if(what == s_BSDIPA_IO_ZLIB)
302 216           s = s_bsdipa_io_read_zlib(&p, iocp);
303             #if s__BSDIPA_BZ2
304             else if(what == s_BSDIPA_IO_BZ2)
305             s = s_bsdipa_io_read_bz2(&p, iocp);
306             #endif
307             #if s__BSDIPA_XZ
308             else if(what == s_BSDIPA_IO_XZ)
309             s = s_bsdipa_io_read_xz(&p, iocp);
310             #endif
311             #if s__BSDIPA_ZSTD
312             else if(what == s_BSDIPA_IO_ZSTD)
313             s = s_bsdipa_io_read_zstd(&p, iocp);
314             #endif
315             else /*if(what == s_BSDIPA_IO_RAW)*/
316 216           s = s_bsdipa_io_read_raw(&p, iocp);
317 432 100         if(s != s_BSDIPA_OK)
318 144           goto jleave;
319              
320 288           p.pc_patch_dat = p.pc_restored_dat;
321 288           p.pc_patch_len = p.pc_restored_len;
322              
323 288           s = s_bsdipa_patch(&p);
324              
325 288           a_free((void*)p.pc_patch_dat);
326              
327 288 50         if(s != s_BSDIPA_OK)
328 0           goto jdone;
329              
330             /* Hand buffer over to perl */
331 288           p.pc_restored_dat[(size_t)p.pc_restored_len] = '\0';
332 288           SvPVCLEAR(bref); /* xxx needless? */
333 288           sv_usepvn_flags(bref, (char*)p.pc_restored_dat, p.pc_restored_len, SV_SMAGIC | SV_HAS_TRAILING_NUL);
334             assert(SvPVbyte_nolen(bref)[SvCUR(bref)] == '\0');
335 288           p.pc_restored_dat = NULL;
336              
337 288           jdone:
338 288           s_bsdipa_patch_free(&p);
339              
340 1296           jleave:
341 1296 100         if(s != s_BSDIPA_OK && bref != NULL)
    100          
342 720           sv_setsv(bref, &PL_sv_undef);
343              
344 1296           return newSViv(s);
345             }
346              
347             MODULE = BsDiPa PACKAGE = BsDiPa
348             VERSIONCHECK: DISABLE
349             PROTOTYPES: ENABLE
350              
351             SV *
352             VERSION()
353             CODE:
354 0           RETVAL = newSVpv(s_BSDIPA_VERSION, sizeof(s_BSDIPA_VERSION) -1);
355             OUTPUT:
356             RETVAL
357              
358             SV *
359             CONTACT()
360             CODE:
361 0           RETVAL = newSVpv(s_BSDIPA_CONTACT, sizeof(s_BSDIPA_CONTACT) -1);
362             OUTPUT:
363             RETVAL
364              
365             SV *
366             COPYRIGHT()
367             CODE:
368 0           RETVAL = newSVpv(s_BSDIPA_COPYRIGHT, sizeof(s_BSDIPA_COPYRIGHT) -1);
369             OUTPUT:
370             RETVAL
371              
372             SV *
373             HAVE_BZ2()
374             CODE:
375 216           RETVAL = newSViv(a_have_bz2);
376             OUTPUT:
377             RETVAL
378              
379             SV *
380             HAVE_XZ()
381             CODE:
382 218           RETVAL = newSViv(a_have_xz);
383             OUTPUT:
384             RETVAL
385              
386             SV *
387             HAVE_ZSTD()
388             CODE:
389 218           RETVAL = newSViv(a_have_zstd);
390             OUTPUT:
391             RETVAL
392              
393             SV *
394             OK()
395             CODE:
396 576           RETVAL = newSViv(s_BSDIPA_OK);
397             OUTPUT:
398             RETVAL
399              
400             SV *
401             FBIG()
402             CODE:
403 144           RETVAL = newSViv(s_BSDIPA_FBIG);
404             OUTPUT:
405             RETVAL
406              
407             SV *
408             NOMEM()
409             CODE:
410 0           RETVAL = newSViv(s_BSDIPA_NOMEM);
411             OUTPUT:
412             RETVAL
413              
414             SV *
415             INVAL()
416             CODE:
417 1584           RETVAL = newSViv(s_BSDIPA_INVAL);
418             OUTPUT:
419             RETVAL
420              
421             void
422             core_try_oneshot_set(nval)
423             SV *nval
424             CODE:
425 3 50         if(SvIOK(nval))
426 3           a_try_oneshot = SvIV(nval);
427              
428             void
429             core_diff_level_set(nval)
430             SV *nval
431             CODE:
432 144 50         if(SvIOK(nval)){
433 144           a_level = SvIV(nval);
434 144 50         a_LEVEL_SET(a_level, a_level);
435             }
436              
437             SV *
438             core_diff_raw(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
439             SV *before_sv
440             SV *after_sv
441             SV *patch_sv
442             SV *magic_window
443             SV *is_equal_data
444             SV *io_cookie
445             CODE:
446 504           RETVAL = a_core_diff(s_BSDIPA_IO_RAW, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
447             OUTPUT:
448             RETVAL
449              
450             SV *
451             core_diff_zlib(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
452             SV *before_sv
453             SV *after_sv
454             SV *patch_sv
455             SV *magic_window
456             SV *is_equal_data
457             SV *io_cookie
458             CODE:
459 504           RETVAL = a_core_diff(s_BSDIPA_IO_ZLIB, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
460             OUTPUT:
461             RETVAL
462              
463             #if s__BSDIPA_BZ2
464             SV *
465             core_diff_bz2(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
466             SV *before_sv
467             SV *after_sv
468             SV *patch_sv
469             SV *magic_window
470             SV *is_equal_data
471             SV *io_cookie
472             CODE:
473             RETVAL = a_core_diff(s_BSDIPA_IO_BZ2, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
474             OUTPUT:
475             RETVAL
476             #endif
477              
478             #if s__BSDIPA_XZ
479             SV *
480             core_diff_xz(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
481             SV *before_sv
482             SV *after_sv
483             SV *patch_sv
484             SV *magic_window
485             SV *is_equal_data
486             SV *io_cookie
487             CODE:
488             RETVAL = a_core_diff(s_BSDIPA_IO_XZ, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
489             OUTPUT:
490             RETVAL
491             #endif
492              
493             #if s__BSDIPA_ZSTD
494             SV *
495             core_diff_zstd(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
496             SV *before_sv
497             SV *after_sv
498             SV *patch_sv
499             SV *magic_window
500             SV *is_equal_data
501             SV *io_cookie
502             CODE:
503             RETVAL = a_core_diff(s_BSDIPA_IO_ZSTD, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
504             OUTPUT:
505             RETVAL
506             #endif
507              
508             SV *
509             core_patch_raw(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
510             SV *after_sv
511             SV *patch_sv
512             SV *before_sv
513             SV *max_allowed_restored_len
514             SV *io_cookie
515             CODE:
516 648           RETVAL = a_core_patch(s_BSDIPA_IO_RAW, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
517             OUTPUT:
518             RETVAL
519              
520             SV *
521             core_patch_zlib(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
522             SV *after_sv
523             SV *patch_sv
524             SV *before_sv
525             SV *max_allowed_restored_len
526             SV *io_cookie
527             CODE:
528 648           RETVAL = a_core_patch(s_BSDIPA_IO_ZLIB, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
529             OUTPUT:
530             RETVAL
531              
532             #if s__BSDIPA_BZ2
533             SV *
534             core_patch_bz2(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
535             SV *after_sv
536             SV *patch_sv
537             SV *before_sv
538             SV *max_allowed_restored_len
539             SV *io_cookie
540             CODE:
541             RETVAL = a_core_patch(s_BSDIPA_IO_BZ2, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
542             OUTPUT:
543             RETVAL
544             #endif
545              
546             #if s__BSDIPA_XZ
547             SV *
548             core_patch_xz(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
549             SV *after_sv
550             SV *patch_sv
551             SV *before_sv
552             SV *max_allowed_restored_len
553             SV *io_cookie
554             CODE:
555             RETVAL = a_core_patch(s_BSDIPA_IO_XZ, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
556             OUTPUT:
557             RETVAL
558             #endif
559              
560             #if s__BSDIPA_ZSTD
561             SV *
562             core_patch_zstd(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
563             SV *after_sv
564             SV *patch_sv
565             SV *before_sv
566             SV *max_allowed_restored_len
567             SV *io_cookie
568             CODE:
569             RETVAL = a_core_patch(s_BSDIPA_IO_ZSTD, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
570             OUTPUT:
571             RETVAL
572             #endif
573              
574             #if s__BSDIPA_XZ
575             SV *
576             core_io_cookie_new_xz(level=NULL)
577             SV *level
578             CODE:
579             struct s_bsdipa_io_cookie_xz *iocJp;
580             IV lvl;
581              
582             lvl = (level != NULL && SvIOK(level)) ? SvIV(level) : 0;
583              
584             iocJp = (struct s_bsdipa_io_cookie_xz*)a_alloc(sizeof(*iocJp));
585             memset(iocJp, 0, sizeof(*iocJp));
586             iocJp->iocx_super.ioc_type = s_BSDIPA_IO_XZ;
587             a_LEVEL_SET(iocJp->iocx_super.ioc_level, lvl);
588             RETVAL = newSViv(PTR2IV(iocJp));
589             OUTPUT:
590             RETVAL
591             #endif
592              
593             #if s__BSDIPA_ZSTD
594             SV *
595             core_io_cookie_new_zstd(level=NULL)
596             SV *level
597             CODE:
598             struct s_bsdipa_io_cookie_zstd *iocZp;
599             IV lvl;
600              
601             lvl = (level != NULL && SvIOK(level)) ? SvIV(level) : 0;
602              
603             iocZp = (struct s_bsdipa_io_cookie_zstd*)a_alloc(sizeof(*iocZp));
604             memset(iocZp, 0, sizeof(*iocZp));
605             iocZp->iocZ_super.ioc_type = s_BSDIPA_IO_ZSTD;
606             a_LEVEL_SET(iocZp->iocZ_super.ioc_level, lvl);
607             RETVAL = newSViv(PTR2IV(iocZp));
608             OUTPUT:
609             RETVAL
610             #endif
611              
612             void
613             core_io_cookie_gut(io_cookie)
614             SV *io_cookie
615             CODE:
616 0 0         if(io_cookie != NULL && SvIOK(io_cookie)){
    0          
617             union a_io_cookie ioc;
618              
619 0           ioc.ioc_vp = INT2PTR(void*,SvIV(io_cookie));
620              
621 0 0         if(ioc.ioc_vp != NULL){
622             #if s__BSDIPA_XZ
623             if(ioc.ioc_iocp->ioc_type == s_BSDIPA_IO_XZ)
624             s_bsdipa_io_cookie_gut_xz(ioc.ioc_iocp);
625             #endif
626             #if s__BSDIPA_ZSTD
627             if(ioc.ioc_iocp->ioc_type == s_BSDIPA_IO_ZSTD)
628             s_bsdipa_io_cookie_gut_zstd(ioc.ioc_iocp);
629             #endif
630 0           a_free(ioc.ioc_vp);
631             }
632             }