1 // This file is part of Deark.
2 // Copyright (C) 2016-2019 Jason Summers
3 // See the file COPYING for terms of use.
5 // Compression and decompression of Deflate and zlib
7 #define DE_NOT_IN_MODULE
8 #include "deark-config.h"
9 #include "deark-private.h"
10 #include "deark-fmtutil.h"
12 #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
13 #define MINIZ_NO_STDIO
14 #define MINIZ_NO_ARCHIVE_APIS
15 #include "../foreign/miniz.h"
17 void fmtutil_inflate_codectype1(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
18 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
,
19 void *codec_private_params
)
21 struct de_inflate_params
*inflparams
= (struct de_inflate_params
*)codec_private_params
;
25 #define DE_DFL_INBUF_SIZE 32768
26 #define DE_DFL_OUTBUF_SIZE (DE_DFL_INBUF_SIZE*4)
29 i64 inbuf_num_valid_bytes
; // Number of valid bytes in inbuf, starting with [0].
30 i64 inbuf_num_consumed_bytes
; // Of inbuf_num_valid_bytes, the number that have been consumed.
31 i64 inbuf_num_consumed_bytes_this_time
;
32 unsigned int orig_avail_in
;
34 i64 output_bytes_this_time
;
37 i64 nbytes_written_total
= 0;
38 int stream_open_flag
= 0;
39 static const char *modname
= "inflate";
41 dres
->bytes_consumed
= 0;
43 de_dfilter_set_errorf(c
, dres
, modname
, "Internal error");
47 inbuf
= de_malloc(c
, DE_DFL_INBUF_SIZE
);
48 outbuf
= de_malloc(c
, DE_DFL_OUTBUF_SIZE
);
50 de_zeromem(&strm
, sizeof(strm
));
51 if(inflparams
->flags
&DE_DEFLATEFLAG_ISZLIB
) {
52 ret
= mz_inflateInit(&strm
);
55 ret
= mz_inflateInit2(&strm
, -MZ_DEFAULT_WINDOW_BITS
);
58 de_dfilter_set_errorf(c
, dres
, modname
, "Inflate error");
62 if(inflparams
->starting_dict
) {
63 inflate_state
*pDecomp
= (inflate_state
*)strm
.state
;
65 de_memcpy(pDecomp
->m_dict
, inflparams
->starting_dict
, 32768);
70 input_cur_pos
= dcmpri
->pos
;
72 inbuf_num_valid_bytes
= 0;
73 inbuf_num_consumed_bytes
= 0;
75 de_dbg2(c
, "inflating up to %d bytes", (int)dcmpri
->len
);
78 de_dbg3(c
, "input remaining: %d", (int)(dcmpri
->pos
+dcmpri
->len
-input_cur_pos
));
80 // If we have written enough bytes, stop.
81 if((dcmpro
->len_known
) && (nbytes_written_total
>= dcmpro
->expected_len
)) {
85 if(inbuf_num_consumed_bytes
>0) {
86 if(inbuf_num_valid_bytes
>inbuf_num_consumed_bytes
) {
87 // Move unconsumed bytes to the beginning of the input buffer
88 de_memmove(inbuf
, &inbuf
[inbuf_num_consumed_bytes
], (size_t)(inbuf_num_valid_bytes
-inbuf_num_consumed_bytes
));
89 inbuf_num_valid_bytes
-= inbuf_num_consumed_bytes
;
90 inbuf_num_consumed_bytes
= 0;
93 inbuf_num_valid_bytes
= 0;
94 inbuf_num_consumed_bytes
= 0;
98 nbytes_to_read
= dcmpri
->pos
+dcmpri
->len
-input_cur_pos
;
99 if(nbytes_to_read
>DE_DFL_INBUF_SIZE
-inbuf_num_valid_bytes
) {
100 nbytes_to_read
= DE_DFL_INBUF_SIZE
-inbuf_num_valid_bytes
;
103 // top off input buffer
104 dbuf_read(dcmpri
->f
, &inbuf
[inbuf_num_valid_bytes
], input_cur_pos
, nbytes_to_read
);
105 input_cur_pos
+= nbytes_to_read
;
106 inbuf_num_valid_bytes
+= nbytes_to_read
;
108 strm
.next_in
= inbuf
;
109 strm
.avail_in
= (unsigned int)inbuf_num_valid_bytes
;
110 orig_avail_in
= strm
.avail_in
;
112 strm
.next_out
= outbuf
;
113 strm
.avail_out
= DE_DFL_OUTBUF_SIZE
;
115 ret
= mz_inflate(&strm
, MZ_SYNC_FLUSH
);
117 if(ret
!=MZ_STREAM_END
&& ret
!=MZ_OK
) {
118 de_dfilter_set_errorf(c
, dres
, modname
, "Inflate error (%d)", (int)ret
);
122 output_bytes_this_time
= DE_DFL_OUTBUF_SIZE
- strm
.avail_out
;
123 de_dbg3(c
, "got %d output bytes", (int)output_bytes_this_time
);
125 nbytes_to_write
= output_bytes_this_time
;
126 if((dcmpro
->len_known
) &&
127 (nbytes_to_write
> dcmpro
->expected_len
- nbytes_written_total
))
129 nbytes_to_write
= dcmpro
->expected_len
- nbytes_written_total
;
131 dbuf_write(dcmpro
->f
, outbuf
, nbytes_to_write
);
132 nbytes_written_total
+= nbytes_to_write
;
134 if(ret
==MZ_STREAM_END
) {
135 de_dbg2(c
, "inflate finished normally");
140 inbuf_num_consumed_bytes_this_time
= (i64
)(orig_avail_in
- strm
.avail_in
);
141 if(inbuf_num_consumed_bytes_this_time
<1 && output_bytes_this_time
<1) {
142 de_dfilter_set_errorf(c
, dres
, modname
, "Inflate error");
145 inbuf_num_consumed_bytes
+= inbuf_num_consumed_bytes_this_time
;
150 dres
->bytes_consumed
= (i64
)strm
.total_in
;
151 dres
->bytes_consumed_valid
= 1;
152 de_dbg2(c
, "inflated %u to %u bytes", (unsigned int)strm
.total_in
,
153 (unsigned int)strm
.total_out
);
155 if(stream_open_flag
) {
156 mz_inflateEnd(&strm
);
163 // DE_DEFLATEFLAG_ISZLIB
164 // DE_DEFLATEFLAG_USEMAXUNCMPRSIZE
165 int fmtutil_decompress_deflate(dbuf
*inf
, i64 inputstart
, i64 inputsize
, dbuf
*outf
,
166 i64 maxuncmprsize
, i64
*bytes_consumed
, unsigned int flags
)
169 struct de_dfilter_results dres
;
170 struct de_dfilter_in_params dcmpri
;
171 struct de_dfilter_out_params dcmpro
;
172 struct de_inflate_params inflparams
;
174 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
175 if(bytes_consumed
) *bytes_consumed
= 0;
178 dcmpri
.pos
= inputstart
;
179 dcmpri
.len
= inputsize
;
182 if(flags
& DE_DEFLATEFLAG_USEMAXUNCMPRSIZE
) {
183 dcmpro
.len_known
= 1;
184 dcmpro
.expected_len
= maxuncmprsize
;
185 flags
-= DE_DEFLATEFLAG_USEMAXUNCMPRSIZE
;
188 de_zeromem(&inflparams
, sizeof(struct de_inflate_params
));
189 inflparams
.flags
= flags
;
190 fmtutil_inflate_codectype1(c
, &dcmpri
, &dcmpro
, &dres
, (void*)&inflparams
);
192 if(bytes_consumed
&& dres
.bytes_consumed_valid
) {
193 *bytes_consumed
= dres
.bytes_consumed
;
196 if(dres
.errcode
!= 0) {
197 de_err(c
, "%s", de_dfilter_get_errmsg(c
, &dres
));
204 // DE_DEFLATEFLAG_ISZLIB
205 void fmtutil_decompress_deflate_ex(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
206 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
,
209 struct de_inflate_params inflparams
;
211 de_zeromem(&inflparams
, sizeof(struct de_inflate_params
));
212 inflparams
.flags
= flags
;
213 fmtutil_inflate_codectype1(c
, dcmpri
, dcmpro
, dres
, (void*)&inflparams
);
216 struct fmtutil_tdefl_ctx
{
218 tdefl_compressor pComp
;
221 static mz_bool
my_fmtutil_tdefl_output_buffer_putter(const void *pBuf
, int len
, void *pUser
)
223 dbuf
*f
= (dbuf
*)pUser
;
225 dbuf_write(f
, (const u8
*)pBuf
, (i64
)len
);
229 struct fmtutil_tdefl_ctx
*fmtutil_tdefl_create(deark
*c
, dbuf
*outf
, int flags
)
231 struct fmtutil_tdefl_ctx
*tdctx
= NULL
;
233 tdctx
= de_malloc(c
, sizeof(struct fmtutil_tdefl_ctx
));
235 tdefl_init(&tdctx
->pComp
, my_fmtutil_tdefl_output_buffer_putter
, (void*)outf
,
240 static enum fmtutil_tdefl_status
tdefl_status_to_fmtutil(tdefl_status n
)
243 case TDEFL_STATUS_BAD_PARAM
: return FMTUTIL_TDEFL_STATUS_BAD_PARAM
;
244 case TDEFL_STATUS_PUT_BUF_FAILED
: return FMTUTIL_TDEFL_STATUS_PUT_BUF_FAILED
;
245 case TDEFL_STATUS_OKAY
: return FMTUTIL_TDEFL_STATUS_OKAY
;
246 case TDEFL_STATUS_DONE
: return FMTUTIL_TDEFL_STATUS_DONE
;
248 return FMTUTIL_TDEFL_STATUS_PUT_BUF_FAILED
;
251 static tdefl_flush
fmtutil_flush_to_tdefl(enum fmtutil_tdefl_flush n
)
254 case FMTUTIL_TDEFL_NO_FLUSH
: return TDEFL_NO_FLUSH
;
255 case FMTUTIL_TDEFL_SYNC_FLUSH
: return TDEFL_SYNC_FLUSH
;
256 case FMTUTIL_TDEFL_FULL_FLUSH
: return TDEFL_FULL_FLUSH
;
257 case FMTUTIL_TDEFL_FINISH
: return TDEFL_FINISH
;
259 return TDEFL_NO_FLUSH
;
262 enum fmtutil_tdefl_status
fmtutil_tdefl_compress_buffer(struct fmtutil_tdefl_ctx
*tdctx
,
263 const void *pIn_buf
, size_t in_buf_size
, enum fmtutil_tdefl_flush flush
)
267 st
= tdefl_compress_buffer(&tdctx
->pComp
, pIn_buf
, in_buf_size
,
268 fmtutil_flush_to_tdefl(flush
));
269 return tdefl_status_to_fmtutil(st
);
272 void fmtutil_tdefl_destroy(struct fmtutil_tdefl_ctx
*tdctx
)
281 unsigned int fmtutil_tdefl_create_comp_flags_from_zip_params(int level
, int window_bits
,
284 return (unsigned int)tdefl_create_comp_flags_from_zip_params(level
, window_bits
,