Fixed a typo
[deark.git] / modules / ccx.c
blob0b5b456e90d345a5ca97be5cc7e102dc69abb60d
1 // This file is part of Deark.
2 // Copyright (C) 2019 Jason Summers
3 // See the file COPYING for terms of use.
5 // Decompress/convert Corel CCX clip art to Corel CMX
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_corel_ccx);
12 #define CODE_CDRX 0x43445258U
13 #define CODE_CMX1 0x434d5831U
14 #define CODE_CPng 0x43506e67U
15 #define CODE_RIFF 0x52494646U
16 #define CODE_pack 0x7061636bU
18 typedef struct localctx_struct {
19 i64 pack_pos; // 0 = not found
20 i64 pack_dpos;
21 i64 pack_dlen;
22 int wrote_cmx_file;
23 } lctx;
25 static void do_decompress(deark *c, lctx *d)
27 u32 cmprmeth;
28 i64 pos = d->pack_dpos;
29 i64 cmpr_start;
30 i64 cmpr_len;
31 i64 unc_len;
32 i64 unc_len_padded;
33 i64 unc_riff_size;
34 i64 after_pack_pos;
35 i64 after_pack_len;
36 dbuf *outf = NULL;
37 dbuf *unc_data = NULL;
38 struct de_dfilter_in_params dcmpri;
39 struct de_dfilter_out_params dcmpro;
40 struct de_dfilter_results dres;
41 struct de_inflate_params inflparams;
43 de_zeromem(&inflparams, sizeof(struct de_inflate_params));
44 if(d->pack_dlen < 12) goto done;
45 unc_len = de_getu32le_p(&pos);
46 de_dbg(c, "uncompressed len (reported): %"I64_FMT, unc_len);
47 if(unc_len > DE_MAX_SANE_OBJECT_SIZE) goto done;
49 cmprmeth = (u32)de_getu32be_p(&pos);
50 if(cmprmeth != CODE_CPng) {
51 de_err(c, "Unsupported compression method");
52 goto done;
54 pos += 4; // Unknown field
56 unc_len_padded = de_pad_to_2(unc_len);
57 cmpr_start = pos;
58 cmpr_len = d->pack_dpos + d->pack_dlen - cmpr_start;
59 if(cmpr_len<1) goto done;
61 // Decompress the "pack" chunk to a membuf.
62 // We *could* decompress directly to the output file instead, but this way
63 // is more flexible.
64 unc_data = dbuf_create_membuf(c, unc_len_padded, 0x1);
65 de_dfilter_init_objects(c, &dcmpri, &dcmpro, &dres);
66 dcmpri.f = c->infile;
67 dcmpri.pos = cmpr_start;
68 dcmpri.len = cmpr_len;
69 dcmpro.f = unc_data;
70 dcmpro.len_known = 1;
71 dcmpro.expected_len = unc_len;
72 inflparams.flags = DE_DEFLATEFLAG_ISZLIB;
73 fmtutil_decompress_deflate_ex(c, &dcmpri, &dcmpro, &dres, &inflparams);
75 if(dres.errcode) {
76 de_err(c, "%s", dres.errmsg);
77 goto done;
79 if(unc_data->len < unc_len) {
80 de_warn(c, "Decompression may have failed (expected %"I64_FMT" bytes, got %"I64_FMT")",
81 unc_len, unc_data->len);
83 dbuf_truncate(unc_data, unc_len_padded);
85 after_pack_pos = d->pack_dpos + de_pad_to_2(d->pack_dlen);
86 after_pack_len = de_pad_to_2(c->infile->len - after_pack_pos);
87 unc_riff_size = d->pack_pos + unc_data->len + after_pack_len - 8;
89 outf = dbuf_create_output_file(c, "cmx", NULL, 0);
90 d->wrote_cmx_file = 1;
92 dbuf_writeu32be(outf, CODE_RIFF);
93 // Use the new the RIFF size
94 dbuf_writeu32le(outf, unc_riff_size);
95 // Change the RIFF type: CDRX -> CMX1
96 dbuf_writeu32be(outf, CODE_CMX1);
98 // Copy everything else, up to the "pack" chunk
99 dbuf_copy(c->infile, 12, d->pack_pos-12, outf);
101 // Copy the decompressed contents of the "pack" chunk
102 dbuf_copy(unc_data, 0, unc_data->len, outf);
104 // Copy everything after the "pack" chunk
105 dbuf_copy(c->infile, after_pack_pos, after_pack_len, outf);
107 done:
108 dbuf_close(unc_data);
109 dbuf_close(outf);
112 static int my_ccx_chunk_handler(deark *c, struct de_iffctx *ictx)
114 lctx *d = (lctx*)ictx->userdata;
116 switch(ictx->chunkctx->chunk4cc.id) {
117 case CODE_RIFF:
118 ictx->is_std_container = 1;
119 return 1;
120 case CODE_pack:
121 d->pack_pos = ictx->chunkctx->pos;
122 d->pack_dpos = ictx->chunkctx->dpos;
123 d->pack_dlen = ictx->chunkctx->dlen;
124 // We have what we need; tell the RIFF parser to stop.
125 return 0;
128 ictx->handled = 1;
129 return 1;
132 static void de_run_corel_ccx(deark *c, de_module_params *mparams)
134 lctx *d = NULL;
135 struct de_iffctx *ictx = NULL;
137 d = de_malloc(c, sizeof(lctx));
139 ictx = de_malloc(c, sizeof(struct de_iffctx));
140 ictx->is_le = 1;
141 ictx->reversed_4cc = 0;
142 ictx->userdata = (void*)d;
143 ictx->handle_chunk_fn = my_ccx_chunk_handler;
144 ictx->f = c->infile;
146 fmtutil_read_iff_format(c, ictx, 0, c->infile->len);
147 if(d->pack_pos) {
148 de_dbg(c, "pack chunk found at %"I64_FMT, d->pack_pos);
149 de_dbg_indent(c, 1);
150 do_decompress(c, d);
151 de_dbg_indent(c, -1);
154 de_free(c, ictx);
155 if(d) {
156 if(!d->wrote_cmx_file) {
157 de_err(c, "Cannot convert this CCX file. Try \"-m riff\" to decode.");
159 de_free(c, d);
163 static int de_identify_corel_ccx(deark *c)
165 if((de_getu32be(0)==CODE_RIFF) &&
166 (de_getu32be(8)==CODE_CDRX))
168 return 100;
170 return 0;
173 void de_module_corel_ccx(deark *c, struct deark_module_info *mi)
175 mi->id = "corel_ccx";
176 mi->desc = "Corel CCX";
177 mi->desc2 = "Decompress to CMX";
178 mi->run_fn = de_run_corel_ccx;
179 mi->identify_fn = de_identify_corel_ccx;