1 // This file is part of Deark.
2 // Copyright (C) 2018 Jason Summers
3 // See the file COPYING for terms of use.
7 #define DE_NOT_IN_MODULE
8 #include "deark-config.h"
9 #include "deark-private.h"
10 #include "deark-fmtutil.h"
12 // Returns a message that is valid until the next operation on dres.
13 const char *de_dfilter_get_errmsg(deark
*c
, struct de_dfilter_results
*dres
)
15 if(dres
->errcode
==0) {
21 return "Unspecified error";
24 // Initialize or reset a dfilter results struct
25 void de_dfilter_results_clear(deark
*c
, struct de_dfilter_results
*dres
)
27 de_zeromem(dres
, sizeof(struct de_dfilter_results
));
30 // Note: It is also okay to init these objects by zeroing out their bytes.
31 void de_dfilter_init_objects(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
32 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
)
35 de_zeromem(dcmpri
, sizeof(struct de_dfilter_in_params
));
37 de_zeromem(dcmpro
, sizeof(struct de_dfilter_out_params
));
39 de_dfilter_results_clear(c
, dres
);
42 void de_dfilter_set_errorf(deark
*c
, struct de_dfilter_results
*dres
, const char *modname
,
47 if(dres
->errcode
!= 0) return; // Only record the first error
54 de_vsnprintf(tmpbuf
, sizeof(tmpbuf
), fmt
, ap
);
55 de_snprintf(dres
->errmsg
, sizeof(dres
->errmsg
), "[%s] %s", modname
, tmpbuf
);
58 de_vsnprintf(dres
->errmsg
, sizeof(dres
->errmsg
), fmt
, ap
);
63 void de_dfilter_set_generic_error(deark
*c
, struct de_dfilter_results
*dres
, const char *modname
)
65 if(dres
->errcode
!= 0) return;
66 de_dfilter_set_errorf(c
, dres
, modname
, "Unspecified error");
69 // This is a decompression API that uses a "push" input model. The client
70 // sends data to the codec as the data becomes available.
71 // (The client must still be able to consume any amount of output data
73 // This model makes it easier to chain multiple codecs together, and to handle
74 // input data that is not contiguous.
76 struct de_dfilter_ctx
*de_dfilter_create(deark
*c
,
77 dfilter_codec_type codec_init_fn
, void *codec_private_params
,
78 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
)
80 struct de_dfilter_ctx
*dfctx
= NULL
;
82 dfctx
= de_malloc(c
, sizeof(struct de_dfilter_ctx
));
85 dfctx
->dcmpro
= dcmpro
;
88 codec_init_fn(dfctx
, codec_private_params
);
90 // TODO: How should we handle failure to initialize a codec?
95 void de_dfilter_addbuf(struct de_dfilter_ctx
*dfctx
,
96 const u8
*buf
, i64 buf_len
)
98 if(dfctx
->codec_addbuf_fn
&& (buf_len
>0)) {
99 dfctx
->codec_addbuf_fn(dfctx
, buf
, buf_len
);
103 void de_dfilter_finish(struct de_dfilter_ctx
*dfctx
)
105 if(dfctx
->codec_finish_fn
) {
106 dfctx
->codec_finish_fn(dfctx
);
110 void de_dfilter_destroy(struct de_dfilter_ctx
*dfctx
)
116 if(dfctx
->codec_destroy_fn
) {
117 dfctx
->codec_destroy_fn(dfctx
);
123 static int my_dfilter_oneshot_buffered_read_cbfn(struct de_bufferedreadctx
*brctx
, const u8
*buf
,
126 struct de_dfilter_ctx
*dfctx
= (struct de_dfilter_ctx
*)brctx
->userdata
;
128 de_dfilter_addbuf(dfctx
, buf
, buf_len
);
129 if(dfctx
->finished_flag
) return 0;
133 // Use a "pushable" codec in a non-pushable way.
134 void de_dfilter_decompress_oneshot(deark
*c
,
135 dfilter_codec_type codec_init_fn
, void *codec_private_params
,
136 struct de_dfilter_in_params
*dcmpri
, struct de_dfilter_out_params
*dcmpro
,
137 struct de_dfilter_results
*dres
)
139 struct de_dfilter_ctx
*dfctx
= NULL
;
141 dfctx
= de_dfilter_create(c
, codec_init_fn
, codec_private_params
,
143 dbuf_buffered_read(dcmpri
->f
, dcmpri
->pos
, dcmpri
->len
,
144 my_dfilter_oneshot_buffered_read_cbfn
, (void*)dfctx
);
145 de_dfilter_finish(dfctx
);
146 de_dfilter_destroy(dfctx
);
149 // Trivial "decompression" of uncompressed data.
150 void fmtutil_decompress_uncompressed(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
151 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
, UI flags
)
156 nbytes_avail
= de_min_int(dcmpri
->len
, dcmpri
->f
->len
- dcmpri
->pos
);
158 if(dcmpro
->len_known
) {
159 len
= dcmpro
->expected_len
;
165 if(len
>nbytes_avail
) len
= nbytes_avail
;
168 dbuf_copy(dcmpri
->f
, dcmpri
->pos
, len
, dcmpro
->f
);
169 dres
->bytes_consumed
= len
;
170 dres
->bytes_consumed_valid
= 1;
173 void fmtutil_decompress_packbits_ex(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
174 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
)
180 i64 outf_len_limit
= 0;
182 dbuf
*unc_pixels
= dcmpro
->f
;
185 endpos
= dcmpri
->pos
+ dcmpri
->len
;
187 if(dcmpro
->len_known
) {
188 outf_len_limit
= unc_pixels
->len
+ dcmpro
->expected_len
;
192 if(dcmpro
->len_known
&& unc_pixels
->len
>= outf_len_limit
) {
193 break; // Decompressed the requested amount of dst data.
197 break; // Reached the end of source data
199 b
= dbuf_getbyte(f
, pos
++);
201 if(b
>128) { // A compressed run
202 count
= 257 - (i64
)b
;
203 b2
= dbuf_getbyte(f
, pos
++);
204 dbuf_write_run(unc_pixels
, b2
, count
);
206 else if(b
<128) { // An uncompressed run
208 dbuf_copy(f
, pos
, count
, unc_pixels
);
211 // Else b==128. No-op.
212 // TODO: Some (but not most) ILBM specs say that code 128 is used to
213 // mark the end of compressed data, so maybe there should be options to
214 // tell us what to do when code 128 is encountered.
217 dres
->bytes_consumed
= pos
- dcmpri
->pos
;
218 dres
->bytes_consumed_valid
= 1;
221 // Returns 0 on failure (currently impossible).
222 int fmtutil_decompress_packbits(dbuf
*f
, i64 pos1
, i64 len
,
223 dbuf
*unc_pixels
, i64
*cmpr_bytes_consumed
)
225 struct de_dfilter_results dres
;
226 struct de_dfilter_in_params dcmpri
;
227 struct de_dfilter_out_params dcmpro
;
229 if(cmpr_bytes_consumed
) *cmpr_bytes_consumed
= 0;
230 de_dfilter_init_objects(f
->c
, &dcmpri
, &dcmpro
, &dres
);
235 dcmpro
.f
= unc_pixels
;
236 if(unc_pixels
->has_len_limit
) {
237 dcmpro
.len_known
= 1;
238 dcmpro
.expected_len
= unc_pixels
->len_limit
- unc_pixels
->len
;
241 fmtutil_decompress_packbits_ex(f
->c
, &dcmpri
, &dcmpro
, &dres
);
243 if(cmpr_bytes_consumed
&& dres
.bytes_consumed_valid
) {
244 *cmpr_bytes_consumed
= dres
.bytes_consumed
;
246 if(dres
.errcode
!= 0) return 0;
250 // A 16-bit variant of de_fmtutil_uncompress_packbits().
251 void fmtutil_decompress_packbits16_ex(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
252 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
)
259 i64 outf_len_limit
= 0;
261 dbuf
*unc_pixels
= dcmpro
->f
;
264 endpos
= dcmpri
->pos
+ dcmpri
->len
;
266 if(dcmpro
->len_known
) {
267 outf_len_limit
= unc_pixels
->len
+ dcmpro
->expected_len
;
271 if(dcmpro
->len_known
&& unc_pixels
->len
>= outf_len_limit
) {
272 break; // Decompressed the requested amount of dst data.
276 break; // Reached the end of source data
278 b
= dbuf_getbyte(f
, pos
++);
280 if(b
>128) { // A compressed run
281 count
= 257 - (i64
)b
;
282 b1
= dbuf_getbyte(f
, pos
++);
283 b2
= dbuf_getbyte(f
, pos
++);
284 for(k
=0; k
<count
; k
++) {
285 dbuf_writebyte(unc_pixels
, b1
);
286 dbuf_writebyte(unc_pixels
, b2
);
289 else if(b
<128) { // An uncompressed run
291 dbuf_copy(f
, pos
, count
*2, unc_pixels
);
294 // Else b==128. No-op.
297 dres
->bytes_consumed
= pos
- dcmpri
->pos
;
298 dres
->bytes_consumed_valid
= 1;
301 int fmtutil_decompress_packbits16(dbuf
*f
, i64 pos1
, i64 len
,
302 dbuf
*unc_pixels
, i64
*cmpr_bytes_consumed
)
304 struct de_dfilter_results dres
;
305 struct de_dfilter_in_params dcmpri
;
306 struct de_dfilter_out_params dcmpro
;
308 if(cmpr_bytes_consumed
) *cmpr_bytes_consumed
= 0;
309 de_dfilter_init_objects(f
->c
, &dcmpri
, &dcmpro
, &dres
);
314 dcmpro
.f
= unc_pixels
;
315 if(unc_pixels
->has_len_limit
) {
316 dcmpro
.len_known
= 1;
317 dcmpro
.expected_len
= unc_pixels
->len_limit
- unc_pixels
->len
;
320 fmtutil_decompress_packbits16_ex(f
->c
, &dcmpri
, &dcmpro
, &dres
);
322 if(cmpr_bytes_consumed
&& dres
.bytes_consumed_valid
) {
323 *cmpr_bytes_consumed
= dres
.bytes_consumed
;
325 if(dres
.errcode
!= 0) return 0;
329 void fmtutil_decompress_rle90_ex(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
330 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
,
333 de_dfilter_decompress_oneshot(c
, dfilter_rle90_codec
, NULL
,
334 dcmpri
, dcmpro
, dres
);
338 i64 total_nbytes_processed
;
341 int countcode_pending
;
344 static void my_rle90_codec_addbuf(struct de_dfilter_ctx
*dfctx
,
345 const u8
*buf
, i64 buf_len
)
349 struct rle90ctx
*rctx
= (struct rle90ctx
*)dfctx
->codec_private
;
353 for(i
=0; i
<buf_len
; i
++) {
354 if(dfctx
->dcmpro
->len_known
&&
355 (rctx
->nbytes_written
>= dfctx
->dcmpro
->expected_len
))
357 dfctx
->finished_flag
= 1;
362 rctx
->total_nbytes_processed
++;
364 if(rctx
->countcode_pending
&& b
==0) {
365 // Not RLE, just an escaped 0x90 byte.
366 dbuf_writebyte(dfctx
->dcmpro
->f
, 0x90);
367 rctx
->nbytes_written
++;
368 rctx
->last_output_byte
= 0x90;
369 rctx
->countcode_pending
= 0;
371 else if(rctx
->countcode_pending
) {
374 // RLE. We already emitted one byte (because the byte to repeat
375 // comes before the repeat count), so write countcode-1 bytes.
377 if(dfctx
->dcmpro
->len_known
&&
378 (rctx
->nbytes_written
+count
> dfctx
->dcmpro
->expected_len
))
380 count
= dfctx
->dcmpro
->expected_len
- rctx
->nbytes_written
;
382 dbuf_write_run(dfctx
->dcmpro
->f
, rctx
->last_output_byte
, count
);
383 rctx
->nbytes_written
+= count
;
385 rctx
->countcode_pending
= 0;
388 rctx
->countcode_pending
= 1;
391 dbuf_writebyte(dfctx
->dcmpro
->f
, b
);
392 rctx
->nbytes_written
++;
393 rctx
->last_output_byte
= b
;
398 static void my_rle90_codec_finish(struct de_dfilter_ctx
*dfctx
)
400 struct rle90ctx
*rctx
= (struct rle90ctx
*)dfctx
->codec_private
;
403 dfctx
->dres
->bytes_consumed
= rctx
->total_nbytes_processed
;
404 dfctx
->dres
->bytes_consumed_valid
= 1;
407 static void my_rle90_codec_destroy(struct de_dfilter_ctx
*dfctx
)
409 struct rle90ctx
*rctx
= (struct rle90ctx
*)dfctx
->codec_private
;
412 de_free(dfctx
->c
, rctx
);
414 dfctx
->codec_private
= NULL
;
417 // RLE algorithm occasionally called "RLE90". Variants of this are used by
418 // BinHex, ARC, StuffIt, and others.
419 // codec_private_params: Unused, must be NULL.
420 void dfilter_rle90_codec(struct de_dfilter_ctx
*dfctx
, void *codec_private_params
)
422 struct rle90ctx
*rctx
= NULL
;
424 rctx
= de_malloc(dfctx
->c
, sizeof(struct rle90ctx
));
425 dfctx
->codec_private
= (void*)rctx
;
426 dfctx
->codec_addbuf_fn
= my_rle90_codec_addbuf
;
427 dfctx
->codec_finish_fn
= my_rle90_codec_finish
;
428 dfctx
->codec_destroy_fn
= my_rle90_codec_destroy
;
434 struct de_dfilter_out_params
*dcmpro
;
435 struct de_lz77buffer
*ringbuf
;
438 static void szdd_lz77buf_writebytecb(struct de_lz77buffer
*rb
, const u8 n
)
440 struct szdd_ctx
*sctx
= (struct szdd_ctx
*)rb
->userdata
;
442 if(sctx
->stop_flag
) return;
443 if(sctx
->dcmpro
->len_known
) {
444 if(sctx
->nbytes_written
>= sctx
->dcmpro
->expected_len
) {
450 dbuf_writebyte(sctx
->dcmpro
->f
, n
);
451 sctx
->nbytes_written
++;
454 static void szdd_init_window_default(struct de_lz77buffer
*ringbuf
)
456 de_lz77buffer_clear(ringbuf
, 0x20);
457 ringbuf
->curpos
= 4096 - 16;
460 static void szdd_init_window_lz5(struct de_lz77buffer
*ringbuf
)
465 de_zeromem(ringbuf
->buf
, 4096);
467 for(i
=1; i
<256; i
++) {
468 de_memset(&ringbuf
->buf
[wpos
], i
, 13);
471 for(i
=0; i
<256; i
++) {
472 ringbuf
->buf
[wpos
++] = i
;
474 for(i
=255; i
>=0; i
--) {
475 ringbuf
->buf
[wpos
++] = i
;
478 de_memset(&ringbuf
->buf
[wpos
], 0x20, 110);
480 ringbuf
->curpos
= (UI
)wpos
;
483 // Partially based on the libmspack's format documentation at
484 // <https://www.cabextract.org.uk/libmspack/doc/szdd_kwaj_format.html>
486 // 0x1: LArc lz5 mode
487 void fmtutil_decompress_szdd(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
488 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
, unsigned int flags
)
490 i64 pos
= dcmpri
->pos
;
491 i64 endpos
= dcmpri
->pos
+ dcmpri
->len
;
492 struct szdd_ctx
*sctx
= NULL
;
494 sctx
= de_malloc(c
, sizeof(struct szdd_ctx
));
495 sctx
->dcmpro
= dcmpro
;
496 sctx
->ringbuf
= de_lz77buffer_create(c
, 4096);
497 sctx
->ringbuf
->writebyte_cb
= szdd_lz77buf_writebytecb
;
498 sctx
->ringbuf
->userdata
= (void*)sctx
;
501 szdd_init_window_lz5(sctx
->ringbuf
);
504 szdd_init_window_default(sctx
->ringbuf
);
511 if(pos
+1 > endpos
) goto unc_done
; // Out of input data
512 control
= (UI
)dbuf_getbyte(dcmpri
->f
, pos
++);
514 for(cbit
=0x01; cbit
<=0x80; cbit
<<=1) {
515 if(control
& cbit
) { // literal
518 if(pos
+1 > endpos
) goto unc_done
;
519 b
= dbuf_getbyte(dcmpri
->f
, pos
++);
520 de_lz77buffer_add_literal_byte(sctx
->ringbuf
, b
);
521 if(sctx
->stop_flag
) goto unc_done
;
528 if(pos
+2 > endpos
) goto unc_done
;
529 x0
= (UI
)dbuf_getbyte_p(dcmpri
->f
, &pos
);
530 x1
= (UI
)dbuf_getbyte_p(dcmpri
->f
, &pos
);
531 matchpos
= ((x1
& 0xf0) << 4) | x0
;
532 matchlen
= (x1
& 0x0f) + 3;
533 de_lz77buffer_copy_from_hist(sctx
->ringbuf
, matchpos
, matchlen
);
534 if(sctx
->stop_flag
) goto unc_done
;
540 dres
->bytes_consumed_valid
= 1;
541 dres
->bytes_consumed
= pos
- dcmpri
->pos
;
543 de_lz77buffer_destroy(c
, sctx
->ringbuf
);
548 //======================= hlp_lz77 =======================
553 struct de_dfilter_out_params
*dcmpro
;
554 struct de_lz77buffer
*ringbuf
;
557 static void hlplz77_lz77buf_writebytecb(struct de_lz77buffer
*rb
, const u8 n
)
559 struct hlplz77ctx
*sctx
= (struct hlplz77ctx
*)rb
->userdata
;
561 if(sctx
->stop_flag
) return;
562 if(sctx
->dcmpro
->len_known
) {
563 if(sctx
->nbytes_written
>= sctx
->dcmpro
->expected_len
) {
569 dbuf_writebyte(sctx
->dcmpro
->f
, n
);
570 sctx
->nbytes_written
++;
573 // This is very similar to the mscompress SZDD algorithm, but
574 // gratuitously different.
575 void fmtutil_hlp_lz77_codectype1(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
576 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
,
577 void *codec_private_params
)
579 i64 pos
= dcmpri
->pos
;
580 i64 endpos
= dcmpri
->pos
+ dcmpri
->len
;
581 struct hlplz77ctx
*sctx
= NULL
;
583 sctx
= de_malloc(c
, sizeof(struct hlplz77ctx
));
584 sctx
->dcmpro
= dcmpro
;
585 sctx
->ringbuf
= de_lz77buffer_create(c
, 4096);
586 sctx
->ringbuf
->writebyte_cb
= hlplz77_lz77buf_writebytecb
;
587 sctx
->ringbuf
->userdata
= (void*)sctx
;
588 de_lz77buffer_clear(sctx
->ringbuf
, 0x20);
594 if(pos
+1 > endpos
) goto unc_done
; // Out of input data
595 control
= (UI
)dbuf_getbyte(dcmpri
->f
, pos
++);
597 for(cbit
=0x01; cbit
<=0x80; cbit
<<=1) {
598 if((control
& cbit
)==0) { // literal
601 if(pos
+1 > endpos
) goto unc_done
;
602 b
= dbuf_getbyte(dcmpri
->f
, pos
++);
603 de_lz77buffer_add_literal_byte(sctx
->ringbuf
, b
);
604 if(sctx
->stop_flag
) goto unc_done
;
611 if(pos
+2 > endpos
) goto unc_done
;
612 x
= (UI
)dbuf_getu16le_p(dcmpri
->f
, &pos
);
613 matchlen
= (x
>>12) + 3;
614 matchpos
= sctx
->ringbuf
->curpos
- ((x
& 0x0fff)+1);
615 de_lz77buffer_copy_from_hist(sctx
->ringbuf
, matchpos
, matchlen
);
616 if(sctx
->stop_flag
) goto unc_done
;
622 dres
->bytes_consumed_valid
= 1;
623 dres
->bytes_consumed
= pos
- dcmpri
->pos
;
625 de_lz77buffer_destroy(c
, sctx
->ringbuf
);
630 //========================================================
632 struct my_2layer_userdata
{
633 struct de_dfilter_ctx
*dfctx_codec2
;
634 i64 intermediate_nbytes
;
637 static void my_2layer_write_cb(dbuf
*f
, void *userdata
,
638 const u8
*buf
, i64 size
)
640 struct my_2layer_userdata
*u
= (struct my_2layer_userdata
*)userdata
;
642 de_dfilter_addbuf(u
->dfctx_codec2
, buf
, size
);
643 u
->intermediate_nbytes
+= size
;
646 static void dres_transfer_error(deark
*c
, struct de_dfilter_results
*src
,
647 struct de_dfilter_results
*dst
)
650 dst
->errcode
= src
->errcode
;
651 de_strlcpy(dst
->errmsg
, src
->errmsg
, sizeof(dst
->errmsg
));
655 // Decompress an arbitrary two-layer compressed format.
656 // tlp->codec1* is the first one that will be used during decompression (i.e. the second
657 // method used when during *compression*).
658 void de_dfilter_decompress_two_layer(deark
*c
, struct de_dcmpr_two_layer_params
*tlp
)
660 dbuf
*outf_codec1
= NULL
;
661 struct de_dfilter_out_params dcmpro_codec1
;
662 struct de_dfilter_results dres_codec2
;
663 struct my_2layer_userdata u
;
664 struct de_dfilter_ctx
*dfctx_codec2
= NULL
;
666 de_dfilter_init_objects(c
, NULL
, &dcmpro_codec1
, NULL
);
667 de_dfilter_init_objects(c
, NULL
, NULL
, &dres_codec2
);
668 de_zeromem(&u
, sizeof(struct my_2layer_userdata
));
670 // Make a custom dbuf. The output from the first decompressor will be written
671 // to it, and it will relay that output to the second decompressor.
672 outf_codec1
= dbuf_create_custom_dbuf(c
, 0, 0);
673 outf_codec1
->userdata_for_customwrite
= (void*)&u
;
674 outf_codec1
->customwrite_fn
= my_2layer_write_cb
;
676 dcmpro_codec1
.f
= outf_codec1
;
677 if(tlp
->intermed_len_known
) {
678 dcmpro_codec1
.len_known
= 1;
679 dcmpro_codec1
.expected_len
= tlp
->intermed_expected_len
;
682 dcmpro_codec1
.len_known
= 0;
683 dcmpro_codec1
.expected_len
= 0;
686 dfctx_codec2
= de_dfilter_create(c
, tlp
->codec2
, tlp
->codec2_private_params
, tlp
->dcmpro
, &dres_codec2
);
687 u
.dfctx_codec2
= dfctx_codec2
;
689 // The first codec in the chain does not need the advanced (de_dfilter_create) API.
690 if(tlp
->codec1_type1
) {
691 tlp
->codec1_type1(c
, tlp
->dcmpri
, &dcmpro_codec1
, tlp
->dres
, tlp
->codec1_private_params
);
694 de_dfilter_decompress_oneshot(c
, tlp
->codec1_pushable
, tlp
->codec1_private_params
,
695 tlp
->dcmpri
, &dcmpro_codec1
, tlp
->dres
);
697 de_dfilter_finish(dfctx_codec2
);
699 if(tlp
->dres
->errcode
) goto done
;
700 de_dbg2(c
, "size after intermediate decompression: %"I64_FMT
, u
.intermediate_nbytes
);
702 if(dres_codec2
.errcode
) {
703 // An error occurred in codec2, and not in codec1.
704 // Copy the error info to the dres that will be returned to the caller.
705 // TODO: Make a cleaner way to do this.
706 dres_transfer_error(c
, &dres_codec2
, tlp
->dres
);
711 de_dfilter_destroy(dfctx_codec2
);
712 dbuf_close(outf_codec1
);
715 // TODO: Retire this function.
716 void de_dfilter_decompress_two_layer_type2(deark
*c
,
717 dfilter_codec_type codec1
, void *codec1_private_params
,
718 dfilter_codec_type codec2
, void *codec2_private_params
,
719 struct de_dfilter_in_params
*dcmpri
, struct de_dfilter_out_params
*dcmpro
,
720 struct de_dfilter_results
*dres
)
722 struct de_dcmpr_two_layer_params tlp
;
724 de_zeromem(&tlp
, sizeof(struct de_dcmpr_two_layer_params
));
725 tlp
.codec1_pushable
= codec1
;
726 tlp
.codec1_private_params
= codec1_private_params
;
728 tlp
.codec2_private_params
= codec2_private_params
;
732 de_dfilter_decompress_two_layer(c
, &tlp
);
735 struct de_lz77buffer
*de_lz77buffer_create(deark
*c
, UI bufsize
)
737 struct de_lz77buffer
*rb
;
739 rb
= de_malloc(c
, sizeof(struct de_lz77buffer
));
740 rb
->buf
= de_malloc(c
, (i64
)bufsize
);
741 rb
->bufsize
= bufsize
;
742 rb
->mask
= bufsize
- 1;
746 void de_lz77buffer_destroy(deark
*c
, struct de_lz77buffer
*rb
)
753 // Set all bytes to the same value, and reset the current position to 0.
754 void de_lz77buffer_clear(struct de_lz77buffer
*rb
, UI val
)
756 de_memset(rb
->buf
, val
, rb
->bufsize
);
760 void de_lz77buffer_set_curpos(struct de_lz77buffer
*rb
, UI newpos
)
762 rb
->curpos
= newpos
& rb
->mask
;
765 void de_lz77buffer_add_literal_byte(struct de_lz77buffer
*rb
, u8 b
)
767 rb
->writebyte_cb(rb
, b
);
768 rb
->buf
[rb
->curpos
] = b
;
769 rb
->curpos
= (rb
->curpos
+1) & rb
->mask
;
772 void de_lz77buffer_copy_from_hist(struct de_lz77buffer
*rb
,
773 UI startpos
, UI count
)
778 frompos
= startpos
& rb
->mask
;
779 for(i
=0; i
<count
; i
++) {
780 de_lz77buffer_add_literal_byte(rb
, rb
->buf
[frompos
]);
781 frompos
= (frompos
+1) & rb
->mask
;