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
25 static void do_decompress(deark
*c
, lctx
*d
)
28 i64 pos
= d
->pack_dpos
;
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");
54 pos
+= 4; // Unknown field
56 unc_len_padded
= de_pad_to_2(unc_len
);
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
64 unc_data
= dbuf_create_membuf(c
, unc_len_padded
, 0x1);
65 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
67 dcmpri
.pos
= cmpr_start
;
68 dcmpri
.len
= cmpr_len
;
71 dcmpro
.expected_len
= unc_len
;
72 inflparams
.flags
= DE_DEFLATEFLAG_ISZLIB
;
73 fmtutil_decompress_deflate_ex(c
, &dcmpri
, &dcmpro
, &dres
, &inflparams
);
76 de_err(c
, "%s", dres
.errmsg
);
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
);
108 dbuf_close(unc_data
);
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
) {
118 ictx
->is_std_container
= 1;
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.
132 static void de_run_corel_ccx(deark
*c
, de_module_params
*mparams
)
135 struct de_iffctx
*ictx
= NULL
;
137 d
= de_malloc(c
, sizeof(lctx
));
139 ictx
= de_malloc(c
, sizeof(struct de_iffctx
));
141 ictx
->reversed_4cc
= 0;
142 ictx
->userdata
= (void*)d
;
143 ictx
->handle_chunk_fn
= my_ccx_chunk_handler
;
146 fmtutil_read_iff_format(c
, ictx
, 0, c
->infile
->len
);
148 de_dbg(c
, "pack chunk found at %"I64_FMT
, d
->pack_pos
);
151 de_dbg_indent(c
, -1);
156 if(!d
->wrote_cmx_file
) {
157 de_err(c
, "Cannot convert this CCX file. Try \"-m riff\" to decode.");
163 static int de_identify_corel_ccx(deark
*c
)
165 if((de_getu32be(0)==CODE_RIFF
) &&
166 (de_getu32be(8)==CODE_CDRX
))
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
;