File Coverage

BsDiPa.xs
Criterion Covered Total %
statement 150 166 90.3
branch 81 108 75.0
condition n/a
subroutine n/a
pod n/a
total 231 274 84.3


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             #ifdef s_BSDIPA_TEXT
89             /* Must be proof against "algorithmic complexity attacks" by default! */
90             static uint32_t a_core_diff__hash(void *user_cookie, uint8_t const *dat, size_t len);
91             #endif
92              
93             static SV *a_core_patch(int what, SV *after_sv, SV *patch_sv, SV *before_sv, SV *max_allowed_restored_len,
94             SV *io_cookie);
95              
96             static void *
97 3638           a_alloc(size_t size){
98             char *vp;
99              
100 3638           Newx(vp, size, char);
101              
102 3638           return vp;
103             }
104              
105             static void
106 3236           a_free(void *vp){
107 3236           Safefree(vp);
108 3236           }
109              
110             static SV *
111 1106           a_core_diff(int what, SV *before_sv, SV *after_sv, SV *patch_sv, SV *magic_window, SV *is_equal_data, SV *io_cookie){
112             struct s_bsdipa_io_cookie ioc, *iocp;
113             struct s_bsdipa_diff_ctx d;
114             SV *pref, *iseq;
115             enum s_bsdipa_state s;
116              
117 1106           s = s_BSDIPA_INVAL;
118              
119 1106           pref = NULL;
120 1106 100         if(/*!SvOK(patch_sv) ||*/ !SvROK(patch_sv))
121 316           goto jleave;
122 790           pref = SvRV(patch_sv);
123              
124 790 100         if(/*!SvOK(before_sv) ||*/ !SvPOK(before_sv))
125 158           goto jleave;
126              
127 632 100         if(/*!SvOK(after_sv) ||*/ !SvPOK(after_sv))
128 158           goto jleave;
129              
130 474           d.dc_mem.mc_alloc = &a_alloc;
131 474           d.dc_mem.mc_free = &a_free;
132 474           d.dc_before_len = SvCUR(before_sv);
133 474           d.dc_before_dat = SvPVbyte_nolen(before_sv);
134 474           d.dc_after_len = SvCUR(after_sv);
135 474           d.dc_after_dat = SvPVbyte_nolen(after_sv);
136 474           d.dc_magic_window = 0;
137             #ifdef s_BSDIPA_TEXT
138 474           d.dc_text_mode = 0;
139             #endif
140              
141 474 50         if(magic_window == NULL || !SvOK(magic_window)){
    100          
142 114 50         }else if(!SvIOK(magic_window))
143 0           goto jleave;
144             else{
145             IV i;
146              
147 114           i = SvIV(magic_window);
148 114 50         if(i > 4096) /* <> docu! */
149 0           goto jleave;
150 114 100         if(i >= 0)
151 72           d.dc_magic_window = (int32_t)i;
152             #ifdef s_BSDIPA_TEXT
153             else{
154 42           d.dc_text_mode = 1;
155 42           d.dc_hash = &a_core_diff__hash;
156             /*d.dc_hash_cookie =*/
157             }
158             #endif
159             }
160              
161 474 50         if(is_equal_data == NULL || !SvOK(is_equal_data))
    100          
162 158           iseq = NULL;
163 316 100         else if(!SvROK(is_equal_data))
164 158           goto jleave;
165             else
166 158           iseq = SvRV(is_equal_data);
167              
168 316 50         if(io_cookie == NULL || !SvIOK(io_cookie)){
    50          
169 316 100         if(a_level == 0)
170 237           iocp = NULL;
171             else{
172 79           memset(iocp = &ioc, 0, sizeof(ioc));
173 79           iocp->ioc_level = a_level;
174             }
175             }else
176 0           iocp = INT2PTR(struct s_bsdipa_io_cookie*,SvIV(io_cookie));
177              
178 316           s = s_bsdipa_diff(&d);
179 316 50         if(s != s_BSDIPA_OK)
180 0           goto jdone;
181              
182 316 100         if(iseq != NULL)
183 158           SvIV_set(iseq, d.dc_is_equal_data);
184              
185             /* _RAW is very "unlikely" */
186 316           SvPVCLEAR(pref);
187 316 100         if(what == s_BSDIPA_IO_ZLIB)
188 158           s = s_bsdipa_io_write_zlib(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
189             #if s__BSDIPA_BZ2
190             else if(what == s_BSDIPA_IO_BZ2)
191             s = s_bsdipa_io_write_bz2(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
192             #endif
193             #if s__BSDIPA_XZ
194             else if(what == s_BSDIPA_IO_XZ)
195             s = s_bsdipa_io_write_xz(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
196             #endif
197             #if s__BSDIPA_ZSTD
198             else if(what == s_BSDIPA_IO_ZSTD)
199             s = s_bsdipa_io_write_zstd(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
200             #endif
201             else /*if(what == s_BSDIPA_IO_RAW)*/{
202             s_bsdipa_off_t x;
203              
204 158           x = sizeof(d.dc_header) + d.dc_ctrl_len + d.dc_diff_len + d.dc_extra_len +1;
205 158 50         SvGROW(pref, x);
    100          
206 158           SvCUR_set(pref, 0);
207 158           s = s_bsdipa_io_write_raw(&d, &a_core_diff__write, pref, a_try_oneshot, iocp);
208             }
209              
210 316           jdone:
211 316           s_bsdipa_diff_free(&d);
212              
213 1106           jleave:
214 1106 100         if(s != s_BSDIPA_OK && pref != NULL)
    100          
215 474           sv_setsv(pref, &PL_sv_undef);
216              
217 1106           return newSViv(s);
218             }
219              
220             static enum s_bsdipa_state
221 790           a_core_diff__write(void *user_cookie, uint8_t const *dat, s_bsdipa_off_t len, s_bsdipa_off_t is_last){
222             SV *p;
223             enum s_bsdipa_state rv;
224              
225 790 100         if(is_last >= 0 && len <= 0)
    100          
226 158           goto jok;
227              
228 632           p = (SV*)user_cookie;
229              
230             /* Buffer takeover? Even though likely short living, minimize wastage to XXX something reasonable */
231 632 100         if(is_last < 0 && (is_last > -65535 || is_last / 10 > -len)){
    100          
    50          
232             /* In this case the additional byte is guaranteed! */
233 86           ((uint8_t*)dat)[(unsigned long)len] = '\0';
234 86           sv_usepvn_flags(p, (char*)dat, len, SV_SMAGIC | SV_HAS_TRAILING_NUL);
235 86           assert(SvPVbyte_nolen(p)[SvCUR(p)] == '\0');
236             /*xxx instead sv_setpvn(p, dat, len);*/
237             }else{
238             char *cp;
239             s_bsdipa_off_t l;
240              
241 546           l = (s_bsdipa_off_t)SvCUR(p);
242              
243 546 50         cp = SvGROW(p, l + len +1);
    100          
244 546 50         if(cp == NULL){
245 0           rv = s_BSDIPA_NOMEM;
246 0           goto jleave;
247             }
248              
249 546           memcpy(&cp[(unsigned long)l], dat, len);
250 546           l += len;
251 546           cp[(unsigned long)l] = '\0'; /* mumble */
252 546           SvCUR_set(p, l);
253 546           SvPOK_only(p);
254 546 50         SvSETMAGIC(p);
255             assert(SvPVbyte_nolen(p)[SvCUR(p)] == '\0');
256              
257 546 100         if(is_last < 0)
258 24           a_free((void*)dat);
259             }
260              
261 522           jok:
262 790           rv = s_BSDIPA_OK;
263 790           jleave:
264 790           return rv;
265             }
266              
267             #ifdef s_BSDIPA_TEXT
268             static uint32_t
269 144088           a_core_diff__hash(void *user_cookie, uint8_t const *dat, size_t len){
270             U32 h;
271             STRLEN l;
272             U8 const *p;
273             (void)user_cookie;
274              
275 144088           p = (U8 const*)dat;
276 144088           l = (STRLEN)len;
277 144088           h = 0;
278 144088 50         PERL_HASH(h, p, l);
279              
280 144088           return h;
281             }
282             #endif
283              
284             static SV *
285 1422           a_core_patch(int what, SV *after_sv, SV *patch_sv, SV *before_sv, SV *max_allowed_restored_len, SV *io_cookie){
286             struct s_bsdipa_patch_ctx p;
287             struct s_bsdipa_io_cookie *iocp;
288             SV *bref;
289             enum s_bsdipa_state s;
290              
291 1422           s = s_BSDIPA_INVAL;
292              
293 1422           bref = NULL;
294 1422 100         if(/*!SvOK(before_sv) ||*/ !SvROK(before_sv))
295 316           goto jleave;
296 1106           bref = SvRV(before_sv);
297              
298 1106 100         if(/*!SvOK(after_sv) ||*/ !SvPOK(after_sv))
299 158           goto jleave;
300              
301 948 100         if(/*!SvOK(patch_sv) ||*/ !SvPOK(patch_sv))
302 158           goto jleave;
303              
304 790           p.pc_max_allowed_restored_len = 0;
305 790 50         if(max_allowed_restored_len != NULL && SvOK(max_allowed_restored_len)){
    100          
306 632 100         if(!SvIOK(max_allowed_restored_len))
307 158           goto jleave;
308             else{
309             IV i;
310              
311 474           i = SvIV(max_allowed_restored_len);
312 474 100         if(i < 0 || (uint64_t)i != (s_bsdipa_off_t)i ||
    50          
313 316 50         (s_bsdipa_off_t)i >= s_BSDIPA_OFF_MAX)
314 158           goto jleave;
315 316           p.pc_max_allowed_restored_len = (uint64_t)i;
316             }
317             }
318              
319 474 100         if(io_cookie == NULL || !SvIOK(io_cookie))
    50          
320 474           iocp = NULL;
321             else
322 0           iocp = INT2PTR(struct s_bsdipa_io_cookie*,SvIV(io_cookie));
323              
324 474           p.pc_mem.mc_alloc = &a_alloc;
325 474           p.pc_mem.mc_free = &a_free;
326 474           p.pc_after_len = SvCUR(after_sv);
327 474           p.pc_after_dat = SvPVbyte_nolen(after_sv);
328              
329 474           p.pc_patch_len = SvCUR(patch_sv);
330 474           p.pc_patch_dat = SvPVbyte_nolen(patch_sv);
331              
332             /* _RAW is very "unlikely" */
333 474 100         if(what == s_BSDIPA_IO_ZLIB)
334 237           s = s_bsdipa_io_read_zlib(&p, iocp);
335             #if s__BSDIPA_BZ2
336             else if(what == s_BSDIPA_IO_BZ2)
337             s = s_bsdipa_io_read_bz2(&p, iocp);
338             #endif
339             #if s__BSDIPA_XZ
340             else if(what == s_BSDIPA_IO_XZ)
341             s = s_bsdipa_io_read_xz(&p, iocp);
342             #endif
343             #if s__BSDIPA_ZSTD
344             else if(what == s_BSDIPA_IO_ZSTD)
345             s = s_bsdipa_io_read_zstd(&p, iocp);
346             #endif
347             else /*if(what == s_BSDIPA_IO_RAW)*/
348 237           s = s_bsdipa_io_read_raw(&p, iocp);
349 474 100         if(s != s_BSDIPA_OK)
350 158           goto jleave;
351              
352 316           p.pc_patch_dat = p.pc_restored_dat;
353 316           p.pc_patch_len = p.pc_restored_len;
354              
355 316           s = s_bsdipa_patch(&p);
356              
357 316           a_free((void*)p.pc_patch_dat);
358              
359 316 50         if(s != s_BSDIPA_OK)
360 0           goto jdone;
361              
362             /* Hand buffer over to perl */
363 316           p.pc_restored_dat[(size_t)p.pc_restored_len] = '\0';
364 316           SvPVCLEAR(bref); /* xxx needless? */
365 316           sv_usepvn_flags(bref, (char*)p.pc_restored_dat, p.pc_restored_len, SV_SMAGIC | SV_HAS_TRAILING_NUL);
366             assert(SvPVbyte_nolen(bref)[SvCUR(bref)] == '\0');
367 316           p.pc_restored_dat = NULL;
368              
369 316           jdone:
370 316           s_bsdipa_patch_free(&p);
371              
372 1422           jleave:
373 1422 100         if(s != s_BSDIPA_OK && bref != NULL)
    100          
374 790           sv_setsv(bref, &PL_sv_undef);
375              
376 1422           return newSViv(s);
377             }
378              
379             MODULE = BsDiPa PACKAGE = BsDiPa
380             VERSIONCHECK: DISABLE
381             PROTOTYPES: ENABLE
382              
383             SV *
384             VERSION()
385             CODE:
386 0           RETVAL = newSVpv(s_BSDIPA_VERSION, sizeof(s_BSDIPA_VERSION) -1);
387             OUTPUT:
388             RETVAL
389              
390             SV *
391             CONTACT()
392             CODE:
393 0           RETVAL = newSVpv(s_BSDIPA_CONTACT, sizeof(s_BSDIPA_CONTACT) -1);
394             OUTPUT:
395             RETVAL
396              
397             SV *
398             COPYRIGHT()
399             CODE:
400 0           RETVAL = newSVpv(s_BSDIPA_COPYRIGHT, sizeof(s_BSDIPA_COPYRIGHT) -1);
401             OUTPUT:
402             RETVAL
403              
404             SV *
405             HAVE_BZ2()
406             CODE:
407 237           RETVAL = newSViv(a_have_bz2);
408             OUTPUT:
409             RETVAL
410              
411             SV *
412             HAVE_XZ()
413             CODE:
414 239           RETVAL = newSViv(a_have_xz);
415             OUTPUT:
416             RETVAL
417              
418             SV *
419             HAVE_ZSTD()
420             CODE:
421 239           RETVAL = newSViv(a_have_zstd);
422             OUTPUT:
423             RETVAL
424              
425             SV *
426             OK()
427             CODE:
428 632           RETVAL = newSViv(s_BSDIPA_OK);
429             OUTPUT:
430             RETVAL
431              
432             SV *
433             FBIG()
434             CODE:
435 158           RETVAL = newSViv(s_BSDIPA_FBIG);
436             OUTPUT:
437             RETVAL
438              
439             SV *
440             NOMEM()
441             CODE:
442 0           RETVAL = newSViv(s_BSDIPA_NOMEM);
443             OUTPUT:
444             RETVAL
445              
446             SV *
447             INVAL()
448             CODE:
449 1738           RETVAL = newSViv(s_BSDIPA_INVAL);
450             OUTPUT:
451             RETVAL
452              
453             void
454             core_try_oneshot_set(nval)
455             SV *nval
456             CODE:
457 3 50         if(SvIOK(nval))
458 3           a_try_oneshot = SvIV(nval);
459              
460             void
461             core_diff_level_set(nval)
462             SV *nval
463             CODE:
464 158 50         if(SvIOK(nval)){
465 158           a_level = SvIV(nval);
466 158 50         a_LEVEL_SET(a_level, a_level);
467             }
468              
469             SV *
470             core_diff_raw(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
471             SV *before_sv
472             SV *after_sv
473             SV *patch_sv
474             SV *magic_window
475             SV *is_equal_data
476             SV *io_cookie
477             CODE:
478 553           RETVAL = a_core_diff(s_BSDIPA_IO_RAW, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
479             OUTPUT:
480             RETVAL
481              
482             SV *
483             core_diff_zlib(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
484             SV *before_sv
485             SV *after_sv
486             SV *patch_sv
487             SV *magic_window
488             SV *is_equal_data
489             SV *io_cookie
490             CODE:
491 553           RETVAL = a_core_diff(s_BSDIPA_IO_ZLIB, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
492             OUTPUT:
493             RETVAL
494              
495             #if s__BSDIPA_BZ2
496             SV *
497             core_diff_bz2(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
498             SV *before_sv
499             SV *after_sv
500             SV *patch_sv
501             SV *magic_window
502             SV *is_equal_data
503             SV *io_cookie
504             CODE:
505             RETVAL = a_core_diff(s_BSDIPA_IO_BZ2, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
506             OUTPUT:
507             RETVAL
508             #endif
509              
510             #if s__BSDIPA_XZ
511             SV *
512             core_diff_xz(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
513             SV *before_sv
514             SV *after_sv
515             SV *patch_sv
516             SV *magic_window
517             SV *is_equal_data
518             SV *io_cookie
519             CODE:
520             RETVAL = a_core_diff(s_BSDIPA_IO_XZ, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
521             OUTPUT:
522             RETVAL
523             #endif
524              
525             #if s__BSDIPA_ZSTD
526             SV *
527             core_diff_zstd(before_sv, after_sv, patch_sv, magic_window=NULL, is_equal_data=NULL, io_cookie=NULL)
528             SV *before_sv
529             SV *after_sv
530             SV *patch_sv
531             SV *magic_window
532             SV *is_equal_data
533             SV *io_cookie
534             CODE:
535             RETVAL = a_core_diff(s_BSDIPA_IO_ZSTD, before_sv, after_sv, patch_sv, magic_window, is_equal_data, io_cookie);
536             OUTPUT:
537             RETVAL
538             #endif
539              
540             SV *
541             core_patch_raw(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
542             SV *after_sv
543             SV *patch_sv
544             SV *before_sv
545             SV *max_allowed_restored_len
546             SV *io_cookie
547             CODE:
548 711           RETVAL = a_core_patch(s_BSDIPA_IO_RAW, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
549             OUTPUT:
550             RETVAL
551              
552             SV *
553             core_patch_zlib(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
554             SV *after_sv
555             SV *patch_sv
556             SV *before_sv
557             SV *max_allowed_restored_len
558             SV *io_cookie
559             CODE:
560 711           RETVAL = a_core_patch(s_BSDIPA_IO_ZLIB, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
561             OUTPUT:
562             RETVAL
563              
564             #if s__BSDIPA_BZ2
565             SV *
566             core_patch_bz2(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
567             SV *after_sv
568             SV *patch_sv
569             SV *before_sv
570             SV *max_allowed_restored_len
571             SV *io_cookie
572             CODE:
573             RETVAL = a_core_patch(s_BSDIPA_IO_BZ2, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
574             OUTPUT:
575             RETVAL
576             #endif
577              
578             #if s__BSDIPA_XZ
579             SV *
580             core_patch_xz(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
581             SV *after_sv
582             SV *patch_sv
583             SV *before_sv
584             SV *max_allowed_restored_len
585             SV *io_cookie
586             CODE:
587             RETVAL = a_core_patch(s_BSDIPA_IO_XZ, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
588             OUTPUT:
589             RETVAL
590             #endif
591              
592             #if s__BSDIPA_ZSTD
593             SV *
594             core_patch_zstd(after_sv, patch_sv, before_sv, max_allowed_restored_len=NULL, io_cookie=NULL)
595             SV *after_sv
596             SV *patch_sv
597             SV *before_sv
598             SV *max_allowed_restored_len
599             SV *io_cookie
600             CODE:
601             RETVAL = a_core_patch(s_BSDIPA_IO_ZSTD, after_sv, patch_sv, before_sv, max_allowed_restored_len, io_cookie);
602             OUTPUT:
603             RETVAL
604             #endif
605              
606             #if s__BSDIPA_XZ
607             SV *
608             core_io_cookie_new_xz(level=NULL)
609             SV *level
610             CODE:
611             struct s_bsdipa_io_cookie_xz *iocJp;
612             IV lvl;
613              
614             lvl = (level != NULL && SvIOK(level)) ? SvIV(level) : 0;
615              
616             iocJp = (struct s_bsdipa_io_cookie_xz*)a_alloc(sizeof(*iocJp));
617             memset(iocJp, 0, sizeof(*iocJp));
618             iocJp->iocx_super.ioc_type = s_BSDIPA_IO_XZ;
619             a_LEVEL_SET(iocJp->iocx_super.ioc_level, lvl);
620             RETVAL = newSViv(PTR2IV(iocJp));
621             OUTPUT:
622             RETVAL
623             #endif
624              
625             #if s__BSDIPA_ZSTD
626             SV *
627             core_io_cookie_new_zstd(level=NULL)
628             SV *level
629             CODE:
630             struct s_bsdipa_io_cookie_zstd *iocZp;
631             IV lvl;
632              
633             lvl = (level != NULL && SvIOK(level)) ? SvIV(level) : 0;
634              
635             iocZp = (struct s_bsdipa_io_cookie_zstd*)a_alloc(sizeof(*iocZp));
636             memset(iocZp, 0, sizeof(*iocZp));
637             iocZp->iocZ_super.ioc_type = s_BSDIPA_IO_ZSTD;
638             a_LEVEL_SET(iocZp->iocZ_super.ioc_level, lvl);
639             RETVAL = newSViv(PTR2IV(iocZp));
640             OUTPUT:
641             RETVAL
642             #endif
643              
644             void
645             core_io_cookie_gut(io_cookie)
646             SV *io_cookie
647             CODE:
648 0 0         if(io_cookie != NULL && SvIOK(io_cookie)){
    0          
649             union a_io_cookie ioc;
650              
651 0           ioc.ioc_vp = INT2PTR(void*,SvIV(io_cookie));
652              
653 0 0         if(ioc.ioc_vp != NULL){
654             #if s__BSDIPA_XZ
655             if(ioc.ioc_iocp->ioc_type == s_BSDIPA_IO_XZ)
656             s_bsdipa_io_cookie_gut_xz(ioc.ioc_iocp);
657             #endif
658             #if s__BSDIPA_ZSTD
659             if(ioc.ioc_iocp->ioc_type == s_BSDIPA_IO_ZSTD)
660             s_bsdipa_io_cookie_gut_zstd(ioc.ioc_iocp);
661             #endif
662 0           a_free(ioc.ioc_vp);
663             }
664             }