Minor refactoring, related to lzah
[deark.git] / src / fmtutil-lzw.c
blob112c622cbeb09ee3720e34362e04f78b21c4d9a7
1 // This file is part of Deark.
2 // Copyright (C) 2019 Jason Summers
3 // See the file COPYING for terms of use.
5 // LZW decompressor
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;
43 else {
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;
69 else
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
96 // do that.
97 dbuf_write(dfctx->dcmpro->f, buf, (i64)size);
98 return 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;
114 if(!dc) return;
115 delzw_finish(dc);
117 dfctx->dres->bytes_consumed = dc->total_nbytes_processed;
118 dfctx->dres->bytes_consumed_valid = 1;
120 if(dc->errcode) {
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;
130 if(!dc) return;
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;
141 delzw_destroy(dc);
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;
149 deark *c = dfctx->c;
151 if(dc->header_type==DELZW_HEADERTYPE_UNIXCOMPRESS3BYTE) {
152 de_dbg(c, "LZW mode: 0x%02x", (unsigned int)dc->header_unixcompress_mode);
153 de_dbg_indent(c, 1);
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)
184 delzwctx *dc = NULL;
185 struct de_lzw_params *delzwp = (struct de_lzw_params*)codec_private_params;
187 dc = delzw_create((void*)dfctx);
188 if(!dc) goto done;
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);
201 done: