Updated version number to 1.5.6
[deark.git] / src / fmtutil-lzw.c
blob9c09273da1d0373166053d27994d6cd7bc838e0d
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;
68 void fmtutil_decompress_lzw(deark *c, struct de_dfilter_in_params *dcmpri,
69 struct de_dfilter_out_params *dcmpro, struct de_dfilter_results *dres,
70 struct de_lzw_params *lzwp)
72 de_dfilter_decompress_oneshot(c, dfilter_lzw_codec, (void*)lzwp,
73 dcmpri, dcmpro, dres);
76 static size_t wrapped_dfctx_write_cb(delzwctx *dc, const DELZW_UINT8 *buf, size_t size,
77 unsigned int *outflags)
79 struct de_dfilter_ctx *dfctx = (struct de_dfilter_ctx*)dc->userdata;
81 // Note: We could be writing to a custom dbuf, in which case the client has
82 // a chance to examine the decompressed bytes, and might want to stop the
83 // decompression based on their contents. But there's currently no way to
84 // do that.
85 dbuf_write(dfctx->dcmpro->f, buf, (i64)size);
86 return size;
89 static void wrapped_dfctx_debugmsg(delzwctx *dc, int level, const char *msg)
91 struct de_dfilter_ctx *dfctx = (struct de_dfilter_ctx*)dc->userdata;
93 de_dbg(dfctx->c, "[delzw:i%"I64_FMT"/o%"I64_FMT"] %s",
94 (i64)dc->total_nbytes_processed, (i64)dc->uncmpr_nbytes_decoded, msg);
97 static void my_lzw_codec_finish(struct de_dfilter_ctx *dfctx)
99 const char *modname = "delzw";
100 delzwctx *dc = (delzwctx*)dfctx->codec_private;
102 if(!dc) return;
103 delzw_finish(dc);
105 dfctx->dres->bytes_consumed = dc->total_nbytes_processed;
106 dfctx->dres->bytes_consumed_valid = 1;
108 if(dc->errcode) {
109 de_dfilter_set_errorf(dfctx->c, dfctx->dres, modname, "%s", dc->errmsg);
113 static void my_lzw_codec_addbuf(struct de_dfilter_ctx *dfctx,
114 const u8 *buf, i64 buf_len)
116 delzwctx *dc = (delzwctx*)dfctx->codec_private;
118 if(!dc) return;
119 delzw_addbuf(dc, buf, (size_t)buf_len);
120 if(dc->state == DELZW_STATE_FINISHED) {
121 dfctx->finished_flag = 1;
125 static void my_lzw_codec_destroy(struct de_dfilter_ctx *dfctx)
127 delzwctx *dc = (delzwctx*)dfctx->codec_private;
129 delzw_destroy(dc);
130 dfctx->codec_private = NULL;
133 // Print dbg messages and warnings about the header
134 static void my_lzw_after_header_parsed(delzwctx *dc)
136 struct de_dfilter_ctx *dfctx = (struct de_dfilter_ctx *)dc->userdata;
137 deark *c = dfctx->c;
139 if(dc->header_type==DELZW_HEADERTYPE_UNIXCOMPRESS3BYTE) {
140 de_dbg(c, "LZW mode: 0x%02x", (unsigned int)dc->header_unixcompress_mode);
141 de_dbg_indent(c, 1);
142 de_dbg(c, "maxbits: %u", (unsigned int)dc->header_unixcompress_max_codesize);
143 de_dbg(c, "blockmode: %d", (int)dc->header_unixcompress_block_mode);
144 if(!dc->header_unixcompress_block_mode) {
145 de_warn(c, "This file uses an obsolete compress'd format, which "
146 "might not be decompressed correctly");
148 de_dbg_indent(c, -1);
150 else if(dc->header_type==DELZW_HEADERTYPE_ARC1BYTE) {
151 de_dbg(c, "LZW maxbits: %u", (unsigned int)dc->header_unixcompress_max_codesize);
155 static void *my_delzw_calloc(void *userdata, size_t nmemb, size_t size)
157 struct de_dfilter_ctx *dfctx = (struct de_dfilter_ctx*)userdata;
159 return de_mallocarray(dfctx->c, (i64)nmemb, size);
162 static void my_delzw_free(void *userdata, void *ptr)
164 struct de_dfilter_ctx *dfctx = (struct de_dfilter_ctx*)userdata;
166 de_free(dfctx->c, ptr);
169 // codec_private_params is type struct de_lzw_params.
170 void dfilter_lzw_codec(struct de_dfilter_ctx *dfctx, void *codec_private_params)
172 delzwctx *dc = NULL;
173 struct de_lzw_params *delzwp = (struct de_lzw_params*)codec_private_params;
175 dc = delzw_create((void*)dfctx);
176 if(!dc) goto done;
177 dfctx->codec_private = (void*)dc;
178 dfctx->codec_finish_fn = my_lzw_codec_finish;
179 dfctx->codec_destroy_fn = my_lzw_codec_destroy;
180 dfctx->codec_addbuf_fn = my_lzw_codec_addbuf;
182 dc->cb_write = wrapped_dfctx_write_cb;
183 dc->cb_debugmsg = wrapped_dfctx_debugmsg;
184 dc->cb_after_header_parsed = my_lzw_after_header_parsed;
185 dc->output_len_known = dfctx->dcmpro->len_known;
186 dc->output_expected_len = dfctx->dcmpro->expected_len;
188 setup_delzw_common(dfctx->c, dc, delzwp);
189 done: