1 // This file is part of Deark.
2 // Copyright (C) 2021 Jason Summers
3 // See the file COPYING for terms of use.
5 // Misc. Corel / CorelDRAW formats
7 #include <deark-private.h>
8 #include <deark-fmtutil.h>
9 DE_DECLARE_MODULE(de_module_cdr_wl
);
10 DE_DECLARE_MODULE(de_module_corel_clb
);
11 DE_DECLARE_MODULE(de_module_corel_bmf
);
12 DE_DECLARE_MODULE(de_module_corel_ccx
);
14 // **************************************************************************
15 // CorelDRAW CDR - old "WL" format
16 // **************************************************************************
18 static void de_run_cdr_wl(deark
*c
, de_module_params
*mparams
)
22 de_bitmap
*img
= NULL
;
24 de_module_params
*mparams2
= NULL
;
26 de_declare_fmt(c
, "CorelDRAW (WL format)");
27 version
= de_getbyte(2);
28 de_dbg(c
, "version code: 0x%02x", (unsigned int)version
);
29 if(version
<= (u8
)'e') goto done
;
31 pos
= de_getu32le(28);
32 de_dbg(c
, "preview image at %"I64_FMT
, pos
);
34 fi
= de_finfo_create(c
);
35 de_finfo_set_name_from_sz(c
, fi
, "preview", 0, DE_ENCODING_LATIN1
);
38 // Seems to be Windows DDB format, or something like it.
39 mparams2
= de_malloc(c
, sizeof(de_module_params
));
40 mparams2
->in_params
.codes
= "NX";
41 mparams2
->in_params
.fi
= fi
;
42 de_run_module_by_id_on_slice(c
, "ddb", mparams2
, c
->infile
, pos
, c
->infile
->len
-pos
);
46 de_bitmap_destroy(img
);
47 de_finfo_destroy(c
, fi
);
51 static int de_identify_cdr_wl(deark
*c
)
53 if(!dbuf_memcmp(c
->infile
, 0, "WL", 2)) {
54 if(de_input_file_has_ext(c
, "cdr")) return 100;
60 void de_module_cdr_wl(deark
*c
, struct deark_module_info
*mi
)
63 mi
->desc
= "CorelDRAW (old WL format)";
64 mi
->desc2
= "extract preview image";
65 mi
->run_fn
= de_run_cdr_wl
;
66 mi
->identify_fn
= de_identify_cdr_wl
;
69 // **************************************************************************
71 // **************************************************************************
74 de_encoding input_encoding
;
78 static int do_clb_item(deark
*c
, struct clb_ctx
*d
, i64 pos1
)
84 de_ucstring
*name
= NULL
;
87 int saved_indent_level
;
89 de_module_params
*mparams2
= NULL
;
91 de_dbg_indent_save(c
, &saved_indent_level
);
92 de_dbg(c
, "item at %"I64_FMT
, pos1
);
95 nlen
= de_getu16le_p(&pos
);
96 if(nlen
<1 || nlen
>63) goto done
;
97 name
= ucstring_create(c
);
98 dbuf_read_to_ucstring(c
->infile
, pos
, nlen
, name
, DE_CONVFLAG_STOP_AT_NUL
,
100 de_dbg(c
, "name: \"%s\"", ucstring_getpsz_d(name
));
103 imglen
= de_getu32le_p(&pos
);
104 de_dbg(c
, "bitmap size: %"I64_FMT
, imglen
);
106 // Look ahead at the DDB bmBits field.
107 // It seems to be used, and it seems to be an absolute file position.
108 // Bail out if it's not what we expect.
109 n
= de_getu32le(pos
+12);
110 if(n
!=0 && n
!=pos
+16) {
111 de_err(c
, "Unexpected value for bmBits field");
116 de_dbg(c
, "bitmap at %"I64_FMT
, pos
);
118 fi
= de_finfo_create(c
);
119 ucstring_append_sz(name
, ".preview", DE_ENCODING_LATIN1
);
120 de_finfo_set_name_from_ucstring(c
, fi
, name
, 0);
122 mparams2
= de_malloc(c
, sizeof(de_module_params
));
123 mparams2
->in_params
.codes
= "N";
124 mparams2
->in_params
.fi
= fi
;
125 de_run_module_by_id_on_slice(c
, "ddb", mparams2
, c
->infile
, pos
+2, imglen
-2);
126 de_dbg_indent(c
, -1);
131 // There are 9 bytes after the bitmap.
133 n
= de_getu32le_p(&pos
);
134 // This is a reference to the original file from which this preview was derived
135 // (should be in the companion .CLH file).
136 de_dbg(c
, "original file size: %"I64_FMT
, n
);
138 d
->bytes_consumed
= pos
-pos1
;
141 de_free(c
, mparams2
);
142 de_finfo_destroy(c
, fi
);
143 ucstring_destroy(name
);
144 de_dbg_indent_restore(c
, saved_indent_level
);
148 static void de_run_corel_clb(deark
*c
, de_module_params
*mparams
)
150 struct clb_ctx
*d
= NULL
;
153 d
= de_malloc(c
, sizeof(struct clb_ctx
));
154 d
->input_encoding
= de_get_input_encoding(c
, NULL
, DE_ENCODING_ASCII
);
156 if(pos
+18 > c
->infile
->len
) goto done
;
157 d
->bytes_consumed
= 0;
158 if(!do_clb_item(c
, d
, pos
)) goto done
;
159 if(d
->bytes_consumed
<=0) goto done
;
160 pos
+= d
->bytes_consumed
;
166 static int de_identify_corel_clb(deark
*c
)
170 // This might be too strict. Need more samples.
171 if(!de_input_file_has_ext(c
, "clb")) return 0;
172 nlen
= de_getu16le(0);
173 if(nlen
<1 || nlen
>63) return 0;
174 if(de_getbyte(2+nlen
-1)!=0x00) return 0;
175 n
= de_getu32le(2+nlen
+4);
176 if(n
!=0x00000001) return 0;
177 n
= de_getu32le(2+nlen
+16);
178 if(n
!=2+nlen
+20 && n
!=0) return 0;
182 void de_module_corel_clb(deark
*c
, struct deark_module_info
*mi
)
184 mi
->id
= "corel_clb";
185 mi
->desc
= "CorelMOSAIC .CLB library";
186 mi
->run_fn
= de_run_corel_clb
;
187 mi
->identify_fn
= de_identify_corel_clb
;
190 // **************************************************************************
191 // Corel Gallery .BMF
192 // **************************************************************************
194 // Warning: The BMF preview image decoder is based on reverse engineering, may not
197 static void de_run_corel_bmf(deark
*c
, de_module_params
*mparams1
)
199 de_module_params
*mparams2
= NULL
;
200 int saved_indent_level
;
205 de_dbg_indent_save(c
, &saved_indent_level
);
207 seg_size
= de_getu32le_p(&pos
);
208 de_dbg(c
, "preview image segment at %"I64_FMT
", len=%"I64_FMT
, pos
, seg_size
);
211 if(pos
+ seg_size
> c
->infile
->len
) {
212 seg_size
= c
->infile
->len
- pos
;
215 n
= de_getu32le(pos
);
217 de_err(c
, "Unsupported Corel BMF version");
221 mparams2
= de_malloc(c
, sizeof(de_module_params
));
222 mparams2
->in_params
.codes
= "X";
223 mparams2
->in_params
.flags
= 0x81;
224 de_run_module_by_id_on_slice(c
, "dib", mparams2
, c
->infile
, pos
, seg_size
);
227 de_free(c
, mparams2
);
228 de_dbg_indent_restore(c
, saved_indent_level
);
231 static int de_identify_corel_bmf(deark
*c
)
233 if(!dbuf_memcmp(c
->infile
, 0, "@CorelBMF\x0a\x0d", 11)) return 100;
237 void de_module_corel_bmf(deark
*c
, struct deark_module_info
*mi
)
239 mi
->id
= "corel_bmf";
240 mi
->desc
= "Corel Gallery BMF";
241 mi
->run_fn
= de_run_corel_bmf
;
242 mi
->identify_fn
= de_identify_corel_bmf
;
245 // **************************************************************************
247 // Decompress/convert Corel CCX clip art to Corel CMX
248 // **************************************************************************
250 #define CODE_CDRX 0x43445258U
251 #define CODE_CMX1 0x434d5831U
252 #define CODE_CPng 0x43506e67U
253 #define CODE_RIFF 0x52494646U
254 #define CODE_pack 0x7061636bU
256 typedef struct localctx_struct
{
257 i64 pack_pos
; // 0 = not found
263 static void do_decompress(deark
*c
, lctx
*d
)
266 i64 pos
= d
->pack_dpos
;
275 dbuf
*unc_data
= NULL
;
276 struct de_dfilter_in_params dcmpri
;
277 struct de_dfilter_out_params dcmpro
;
278 struct de_dfilter_results dres
;
279 struct de_deflate_params inflparams
;
281 de_zeromem(&inflparams
, sizeof(struct de_deflate_params
));
282 if(d
->pack_dlen
< 12) goto done
;
283 unc_len
= de_getu32le_p(&pos
);
284 de_dbg(c
, "uncompressed len (reported): %"I64_FMT
, unc_len
);
285 if(unc_len
> DE_MAX_SANE_OBJECT_SIZE
) goto done
;
287 cmprmeth
= (u32
)de_getu32be_p(&pos
);
288 if(cmprmeth
!= CODE_CPng
) {
289 de_err(c
, "Unsupported compression method");
292 pos
+= 4; // Unknown field
294 unc_len_padded
= de_pad_to_2(unc_len
);
296 cmpr_len
= d
->pack_dpos
+ d
->pack_dlen
- cmpr_start
;
297 if(cmpr_len
<1) goto done
;
299 // Decompress the "pack" chunk to a membuf.
300 // We *could* decompress directly to the output file instead, but this way
302 unc_data
= dbuf_create_membuf(c
, unc_len_padded
, 0x1);
303 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
304 dcmpri
.f
= c
->infile
;
305 dcmpri
.pos
= cmpr_start
;
306 dcmpri
.len
= cmpr_len
;
308 dcmpro
.len_known
= 1;
309 dcmpro
.expected_len
= unc_len
;
310 inflparams
.flags
= DE_DEFLATEFLAG_ISZLIB
;
311 fmtutil_decompress_deflate_ex(c
, &dcmpri
, &dcmpro
, &dres
, &inflparams
);
314 de_err(c
, "%s", dres
.errmsg
);
317 if(unc_data
->len
< unc_len
) {
318 de_warn(c
, "Decompression may have failed (expected %"I64_FMT
" bytes, got %"I64_FMT
")",
319 unc_len
, unc_data
->len
);
321 dbuf_truncate(unc_data
, unc_len_padded
);
323 after_pack_pos
= d
->pack_dpos
+ de_pad_to_2(d
->pack_dlen
);
324 after_pack_len
= de_pad_to_2(c
->infile
->len
- after_pack_pos
);
325 unc_riff_size
= d
->pack_pos
+ unc_data
->len
+ after_pack_len
- 8;
327 outf
= dbuf_create_output_file(c
, "cmx", NULL
, 0);
328 d
->wrote_cmx_file
= 1;
330 dbuf_writeu32be(outf
, CODE_RIFF
);
331 // Use the new the RIFF size
332 dbuf_writeu32le(outf
, unc_riff_size
);
333 // Change the RIFF type: CDRX -> CMX1
334 dbuf_writeu32be(outf
, CODE_CMX1
);
336 // Copy everything else, up to the "pack" chunk
337 dbuf_copy(c
->infile
, 12, d
->pack_pos
-12, outf
);
339 // Copy the decompressed contents of the "pack" chunk
340 dbuf_copy(unc_data
, 0, unc_data
->len
, outf
);
342 // Copy everything after the "pack" chunk
343 dbuf_copy(c
->infile
, after_pack_pos
, after_pack_len
, outf
);
346 dbuf_close(unc_data
);
350 static int my_ccx_chunk_handler(struct de_iffctx
*ictx
)
352 lctx
*d
= (lctx
*)ictx
->userdata
;
354 switch(ictx
->chunkctx
->chunk4cc
.id
) {
356 ictx
->is_std_container
= 1;
359 d
->pack_pos
= ictx
->chunkctx
->pos
;
360 d
->pack_dpos
= ictx
->chunkctx
->dpos
;
361 d
->pack_dlen
= ictx
->chunkctx
->dlen
;
362 // We have what we need; tell the RIFF parser to stop.
370 static void de_run_corel_ccx(deark
*c
, de_module_params
*mparams
)
373 struct de_iffctx
*ictx
= NULL
;
375 d
= de_malloc(c
, sizeof(lctx
));
377 ictx
= fmtutil_create_iff_decoder(c
);
379 ictx
->reversed_4cc
= 0;
380 ictx
->userdata
= (void*)d
;
381 ictx
->handle_chunk_fn
= my_ccx_chunk_handler
;
384 fmtutil_read_iff_format(ictx
, 0, c
->infile
->len
);
386 de_dbg(c
, "pack chunk found at %"I64_FMT
, d
->pack_pos
);
389 de_dbg_indent(c
, -1);
392 fmtutil_destroy_iff_decoder(ictx
);
394 if(!d
->wrote_cmx_file
) {
395 de_err(c
, "Cannot convert this CCX file. Try \"-m riff\" to decode.");
401 static int de_identify_corel_ccx(deark
*c
)
403 if((de_getu32be(0)==CODE_RIFF
) &&
404 (de_getu32be(8)==CODE_CDRX
))
411 void de_module_corel_ccx(deark
*c
, struct deark_module_info
*mi
)
413 mi
->id
= "corel_ccx";
414 mi
->desc
= "Corel CCX";
415 mi
->desc2
= "Decompress to CMX";
416 mi
->run_fn
= de_run_corel_ccx
;
417 mi
->identify_fn
= de_identify_corel_ccx
;