1 // This file is part of Deark.
2 // Copyright (C) 2019 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 static void *my_delzw_calloc(void *userdata
, size_t nmemb
, size_t size
);
13 static void my_delzw_free(void *userdata
, void *ptr
);
15 #define DELZW_UINT8 u8
16 #define DELZW_UINT16 u16
17 #define DELZW_UINT32 u32
18 #define DELZW_OFF_T i64
19 #define DELZW_MEMCPY de_memcpy
20 #define DELZW_STRLCPY de_strlcpy
21 #define DELZW_VSNPRINTF de_vsnprintf
22 #define DELZW_GNUC_ATTRIBUTE de_gnuc_attribute
23 #define DELZW_CALLOC(u, nmemb, size, ty) my_delzw_calloc((u), (nmemb), (size))
24 #define DELZW_FREE my_delzw_free
26 #include "../foreign/delzw.h"
28 ///////////////////////////////////////////////////
30 static void setup_delzw_common(deark
*c
, delzwctx
*dc
, struct de_lzw_params
*delzwp
)
32 dc
->debug_level
= c
->debug_level
;
34 if(delzwp
->fmt
==DE_LZWFMT_UNIXCOMPRESS
) {
35 dc
->basefmt
= DELZW_BASEFMT_UNIXCOMPRESS
;
36 dc
->auto_inc_codesize
= 1;
37 if(delzwp
->flags
& DE_LZWFLAG_HAS3BYTEHEADER
) {
38 dc
->header_type
= DELZW_HEADERTYPE_UNIXCOMPRESS3BYTE
;
40 else if(delzwp
->flags
& DE_LZWFLAG_HAS1BYTEHEADER
) {
41 dc
->header_type
= DELZW_HEADERTYPE_ARC1BYTE
;
44 dc
->unixcompress_has_clear_code
= 1;
45 dc
->max_codesize
= delzwp
->max_code_size
;
48 if((delzwp
->flags
& DE_LZWFLAG_TOLERATETRAILINGJUNK
) &&
49 !dc
->output_len_known
)
51 dc
->stop_on_invalid_code
= 1;
54 else if(delzwp
->fmt
==DE_LZWFMT_ZIPSHRINK
) {
55 dc
->basefmt
= DELZW_BASEFMT_ZIPSHRINK
;
57 else if(delzwp
->fmt
==DE_LZWFMT_GIF
) {
58 dc
->basefmt
= DELZW_BASEFMT_GIF
;
59 dc
->gif_root_codesize
= delzwp
->gif_root_code_size
;
61 else if(delzwp
->fmt
==DE_LZWFMT_ZOOLZD
) {
62 dc
->basefmt
= DELZW_BASEFMT_ZOOLZD
;
63 dc
->auto_inc_codesize
= 1;
64 dc
->max_codesize
= delzwp
->max_code_size
;
66 else if(delzwp
->fmt
==DE_LZWFMT_TIFF
) {
67 if(delzwp
->tifflzw_oldversion
)
68 dc
->basefmt
= DELZW_BASEFMT_TIFFOLD
;
70 dc
->basefmt
= DELZW_BASEFMT_TIFF
;
71 dc
->auto_inc_codesize
= 1;
72 dc
->max_codesize
= 12;
74 else if(delzwp
->fmt
==DE_LZWFMT_ARC5
) {
75 dc
->basefmt
= DELZW_BASEFMT_ARC5
;
76 dc
->arc5_has_stop_code
= (int)delzwp
->arc5_has_stop_code
;
80 void fmtutil_decompress_lzw(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
81 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
,
82 struct de_lzw_params
*lzwp
)
84 de_dfilter_decompress_oneshot(c
, dfilter_lzw_codec
, (void*)lzwp
,
85 dcmpri
, dcmpro
, dres
);
88 static size_t wrapped_dfctx_write_cb(delzwctx
*dc
, const DELZW_UINT8
*buf
, size_t size
,
89 unsigned int *outflags
)
91 struct de_dfilter_ctx
*dfctx
= (struct de_dfilter_ctx
*)dc
->userdata
;
93 // Note: We could be writing to a custom dbuf, in which case the client has
94 // a chance to examine the decompressed bytes, and might want to stop the
95 // decompression based on their contents. But there's currently no way to
97 dbuf_write(dfctx
->dcmpro
->f
, buf
, (i64
)size
);
101 static void wrapped_dfctx_debugmsg(delzwctx
*dc
, int level
, const char *msg
)
103 struct de_dfilter_ctx
*dfctx
= (struct de_dfilter_ctx
*)dc
->userdata
;
105 de_dbg(dfctx
->c
, "[delzw:i%"I64_FMT
"/o%"I64_FMT
"] %s",
106 (i64
)dc
->total_nbytes_processed
, (i64
)dc
->uncmpr_nbytes_decoded
, msg
);
109 static void my_lzw_codec_finish(struct de_dfilter_ctx
*dfctx
)
111 const char *modname
= "delzw";
112 delzwctx
*dc
= (delzwctx
*)dfctx
->codec_private
;
117 dfctx
->dres
->bytes_consumed
= dc
->total_nbytes_processed
;
118 dfctx
->dres
->bytes_consumed_valid
= 1;
121 de_dfilter_set_errorf(dfctx
->c
, dfctx
->dres
, modname
, "%s", dc
->errmsg
);
125 static void my_lzw_codec_addbuf(struct de_dfilter_ctx
*dfctx
,
126 const u8
*buf
, i64 buf_len
)
128 delzwctx
*dc
= (delzwctx
*)dfctx
->codec_private
;
131 delzw_addbuf(dc
, buf
, (size_t)buf_len
);
132 if(dc
->state
== DELZW_STATE_FINISHED
) {
133 dfctx
->finished_flag
= 1;
137 static void my_lzw_codec_destroy(struct de_dfilter_ctx
*dfctx
)
139 delzwctx
*dc
= (delzwctx
*)dfctx
->codec_private
;
142 dfctx
->codec_private
= NULL
;
145 // Print dbg messages and warnings about the header
146 static void my_lzw_after_header_parsed(delzwctx
*dc
)
148 struct de_dfilter_ctx
*dfctx
= (struct de_dfilter_ctx
*)dc
->userdata
;
151 if(dc
->header_type
==DELZW_HEADERTYPE_UNIXCOMPRESS3BYTE
) {
152 de_dbg(c
, "LZW mode: 0x%02x", (unsigned int)dc
->header_unixcompress_mode
);
154 de_dbg(c
, "maxbits: %u", (unsigned int)dc
->header_unixcompress_max_codesize
);
155 de_dbg(c
, "blockmode: %d", (int)dc
->header_unixcompress_block_mode
);
156 if(!dc
->header_unixcompress_block_mode
) {
157 de_warn(c
, "This file uses an obsolete compress'd format, which "
158 "might not be decompressed correctly");
160 de_dbg_indent(c
, -1);
162 else if(dc
->header_type
==DELZW_HEADERTYPE_ARC1BYTE
) {
163 de_dbg(c
, "LZW maxbits: %u", (unsigned int)dc
->header_unixcompress_max_codesize
);
167 static void *my_delzw_calloc(void *userdata
, size_t nmemb
, size_t size
)
169 struct de_dfilter_ctx
*dfctx
= (struct de_dfilter_ctx
*)userdata
;
171 return de_mallocarray(dfctx
->c
, (i64
)nmemb
, size
);
174 static void my_delzw_free(void *userdata
, void *ptr
)
176 struct de_dfilter_ctx
*dfctx
= (struct de_dfilter_ctx
*)userdata
;
178 de_free(dfctx
->c
, ptr
);
181 // codec_private_params is type struct de_lzw_params.
182 void dfilter_lzw_codec(struct de_dfilter_ctx
*dfctx
, void *codec_private_params
)
185 struct de_lzw_params
*delzwp
= (struct de_lzw_params
*)codec_private_params
;
187 dc
= delzw_create((void*)dfctx
);
189 dfctx
->codec_private
= (void*)dc
;
190 dfctx
->codec_finish_fn
= my_lzw_codec_finish
;
191 dfctx
->codec_destroy_fn
= my_lzw_codec_destroy
;
192 dfctx
->codec_addbuf_fn
= my_lzw_codec_addbuf
;
194 dc
->cb_write
= wrapped_dfctx_write_cb
;
195 dc
->cb_debugmsg
= wrapped_dfctx_debugmsg
;
196 dc
->cb_after_header_parsed
= my_lzw_after_header_parsed
;
197 dc
->output_len_known
= dfctx
->dcmpro
->len_known
;
198 dc
->output_expected_len
= dfctx
->dcmpro
->expected_len
;
200 setup_delzw_common(dfctx
->c
, dc
, delzwp
);