1 // This file is part of Deark.
2 // Copyright (C) 2021 Jason Summers
3 // See the file COPYING for terms of use.
5 // DL animation format, used by DL MAKER / DL VIEWER
6 // by Davide Tome' & Luca De Gregorio
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_dlmaker
);
11 #define V12_SCREEN_WIDTH 320
12 #define V12_SCREEN_HEIGHT 200
13 #define V12_SCREEN_SIZE_IN_BYTES 64000
18 i64 img_xsize
, img_ysize
;
19 // A "screen" is a 320x200 aggregate image containing 1 or more real images.
22 de_bitmap
*screen_img
;
26 typedef struct localctx_struct
{
27 de_ext_encoding input_encoding
;
29 struct v12_fields v12
; // fields only used in v1 and v2
31 i64 num_anim_code_units
;
32 i64 anim_code_unit_size
;
33 i64 num_audio_components
;
39 static void read_name(deark
*c
, lctx
*d
, i64 pos
, de_ucstring
*s
, size_t nsize
)
45 de_read(buf
, pos
, nsize
);
46 for(i
=0; i
<nsize
; i
++) {
47 if(buf
[i
]) buf
[i
] ^= 0xff;
49 ucstring_append_bytes(s
, buf
, nsize
, DE_CONVFLAG_STOP_AT_NUL
, d
->input_encoding
);
52 static void do_v12screen(deark
*c
, lctx
*d
, i64 pos
)
54 if(!d
->v12
.screen_img
) {
55 d
->v12
.screen_img
= de_bitmap_create(c
, V12_SCREEN_WIDTH
, V12_SCREEN_HEIGHT
, 3);
57 de_convert_image_paletted(c
->infile
, pos
, 8, V12_SCREEN_WIDTH
, d
->pal
, d
->v12
.screen_img
, 0);
58 if(d
->v12
.imgs_per_screen
<=1 || d
->v12
.opt_montage
) {
59 de_bitmap_write_to_file_finfo(d
->v12
.screen_img
, d
->fi
, 0);
67 d
->v12
.img
= de_bitmap_create(c
, d
->v12
.img_xsize
, d
->v12
.img_ysize
, 3);
70 for(i
=0; i
<d
->v12
.imgs_per_screen
; i
++) {
71 de_bitmap_copy_rect(d
->v12
.screen_img
, d
->v12
.img
, xpos
, ypos
, d
->v12
.img_xsize
, d
->v12
.img_ysize
,
73 de_bitmap_write_to_file_finfo(d
->v12
.img
, d
->fi
, 0);
75 xpos
+= d
->v12
.img_xsize
;
76 if(xpos
>= V12_SCREEN_WIDTH
) {
78 ypos
+= d
->v12
.img_ysize
;
84 static void do_extract_v3_image(deark
*c
, lctx
*d
, i64 pos
, i64 xsize
, i64 ysize
)
86 de_bitmap
*img
= NULL
;
88 if(!de_good_image_dimensions(c
, xsize
, ysize
)) goto done
;
90 img
= de_bitmap_create(c
, xsize
, ysize
, 3);
91 de_convert_image_paletted(c
->infile
, pos
, 8, xsize
, d
->pal
, img
, 0);
92 de_bitmap_write_to_file_finfo(img
, d
->fi
, 0);
95 de_bitmap_destroy(img
);
98 static void do_extract_audio_component(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
102 if(pos
+len
> c
->infile
->len
) goto done
;
103 if(len
<= 26) goto done
;
104 outf
= dbuf_create_output_file(c
, "voc", NULL
, 0);
105 dbuf_write(outf
, (const u8
*)"Creative Voice File\x1a", 20);
106 dbuf_copy(c
->infile
, pos
+20, len
-20, outf
);
111 static void do_audio(deark
*c
, lctx
*d
, i64 pos1
)
116 for(i
=0; i
<d
->num_audio_components
; i
++) {
119 if(pos
+5 > c
->infile
->len
) goto done
;
120 de_dbg(c
, "audio component at %"I64_FMT
, pos
);
122 dlen
= de_getu32le_p(&pos
);
123 de_dbg(c
, "len: %"I64_FMT
, dlen
);
125 do_extract_audio_component(c
, d
, pos
, dlen
);
126 de_dbg_indent(c
, -1);
134 static void do_read_palette(deark
*c
, lctx
*d
, i64 pos1
)
139 de_dbg(c
, "palette at %"I64_FMT
, pos1
);
141 for(k
=0; k
<256; k
++) {
146 cr1
= de_getbyte_p(&pos
);
147 cg1
= de_getbyte_p(&pos
);
148 cb1
= de_getbyte_p(&pos
);
149 cr2
= de_scale_63_to_255(cr1
& 0x3f);
150 cg2
= de_scale_63_to_255(cg1
& 0x3f);
151 cb2
= de_scale_63_to_255(cb1
& 0x3f);
152 d
->pal
[k
] = DE_MAKE_RGB(cr2
, cg2
, cb2
);
153 de_snprintf(tmps
, sizeof(tmps
), "(%2d,%2d,%2d) "DE_CHAR_RIGHTARROW
" ",
154 (int)cr1
, (int)cg1
, (int)cb1
);
155 de_dbg_pal_entry2(c
, k
, d
->pal
[k
], tmps
, NULL
, NULL
);
157 de_dbg_indent(c
, -1);
160 static int do_read_header(deark
*c
, lctx
*d
)
165 de_ucstring
*s
= NULL
;
167 d
->ver
= de_getbyte_p(&pos
);
168 de_dbg(c
, "version: %u", (UI
)d
->ver
);
169 if(d
->ver
<1 || d
->ver
>3) {
170 de_err(c
, "Not a DL file");
175 d
->v12
.screen_format
= 1;
178 d
->v12
.screen_format
= de_getbyte_p(&pos
);
179 de_dbg(c
, "screen format: %u", (UI
)d
->v12
.screen_format
);
186 switch(d
->v12
.screen_format
) {
188 d
->v12
.img_xsize
= 320;
189 d
->v12
.img_ysize
= 200;
192 d
->v12
.img_xsize
= 160;
193 d
->v12
.img_ysize
= 100;
196 d
->v12
.img_xsize
= 80;
197 d
->v12
.img_ysize
= 50;
200 de_err(c
, "Invalid/unsupported DL format");
204 d
->v12
.imgs_per_screen
= (V12_SCREEN_WIDTH
/d
->v12
.img_xsize
) *
205 (V12_SCREEN_HEIGHT
/d
->v12
.img_ysize
);
208 de_dbg_dimensions(c
, d
->v12
.img_xsize
, d
->v12
.img_ysize
);
209 de_dbg(c
, "images/screen: %u", (UI
)d
->v12
.imgs_per_screen
);
210 de_dbg_indent(c
, -1);
214 if(d
->ver
==3) pos
+= 50;
216 s
= ucstring_create(c
);
217 nsize
= (d
->ver
==3) ? 40 : 20;
218 read_name(c
, d
, pos
, s
, nsize
);
219 de_dbg(c
, "title: \"%s\"", ucstring_getpsz_d(s
));
224 read_name(c
, d
, pos
, s
, nsize
);
225 de_dbg(c
, "author: \"%s\"", ucstring_getpsz_d(s
));
230 d
->num_images
= de_getu16le_p(&pos
);
231 de_dbg(c
, "num images: %u", (UI
)d
->num_images
);
234 d
->v12
.num_screens
= (i64
)de_getbyte_p(&pos
);
235 de_dbg(c
, "num screens: %u", (UI
)d
->v12
.num_screens
);
236 d
->num_images
= d
->v12
.num_screens
* d
->v12
.imgs_per_screen
;
237 de_dbg(c
, "num images (calculated): %"I64_FMT
, d
->num_images
);
241 d
->num_anim_code_units
= de_getu16le_p(&pos
);
242 d
->anim_code_unit_size
= 1;
245 d
->num_anim_code_units
= de_getu16le_p(&pos
);
246 d
->anim_code_unit_size
= 2;
249 d
->num_anim_code_units
= de_getu32le_p(&pos
);
250 d
->anim_code_unit_size
= 2;
252 de_dbg(c
, "num frames: %"I64_FMT
, d
->num_anim_code_units
);
255 d
->num_audio_components
= de_getu16le_p(&pos
);
256 de_dbg(c
, "num audio components: %"I64_FMT
, d
->num_audio_components
);
259 do_read_palette(c
, d
, pos
);
269 static void de_run_dlmaker(deark
*c
, de_module_params
*mparams
)
275 int saved_indent_level
;
277 de_dbg_indent_save(c
, &saved_indent_level
);
278 d
= de_malloc(c
, sizeof(lctx
));
279 d
->input_encoding
= de_get_input_encoding(c
, NULL
, DE_ENCODING_CP437
);
280 d
->input_encoding
= DE_EXTENC_MAKE(d
->input_encoding
, DE_ENCSUBTYPE_HYBRID
);
281 d
->v12
.opt_montage
= de_get_ext_option_bool(c
, "dlmaker:montage", 0);
283 d
->fi
= de_finfo_create(c
);
284 d
->fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
285 d
->fi
->density
.xdens
= 6.0;
286 d
->fi
->density
.ydens
= 5.0;
288 if(!do_read_header(c
, d
)) goto done
;
292 for(k
=0; k
<d
->num_images
; k
++) {
295 if(pos
>= c
->infile
->len
) goto done
;
296 de_dbg(c
, "image #%u at %"I64_FMT
, (UI
)k
, pos
);
298 xsize
= de_getu16le_p(&pos
);
299 ysize
= de_getu16le_p(&pos
);
300 de_dbg_dimensions(c
, xsize
, ysize
);
301 do_extract_v3_image(c
, d
, pos
, xsize
, ysize
);
303 de_dbg_indent(c
, -1);
307 for(k
=0; k
<d
->v12
.num_screens
; k
++) {
308 if(pos
>= c
->infile
->len
) goto done
;
309 de_dbg(c
, "screen #%u at %"I64_FMT
, (UI
)k
, pos
);
311 if(pos
+V12_SCREEN_SIZE_IN_BYTES
> c
->infile
->len
) goto done
;
312 do_v12screen(c
, d
, pos
);
313 pos
+= V12_SCREEN_SIZE_IN_BYTES
;
314 de_dbg_indent(c
, -1);
318 anim_cmds_size
= d
->num_anim_code_units
* d
->anim_code_unit_size
;
319 de_dbg(c
, "anim commands at %"I64_FMT
", len=%"I64_FMT
, pos
, anim_cmds_size
);
320 pos
+= anim_cmds_size
;
326 de_dbg_indent_restore(c
, saved_indent_level
);
328 de_bitmap_destroy(d
->v12
.screen_img
);
329 de_bitmap_destroy(d
->v12
.img
);
330 de_finfo_destroy(c
, d
->fi
);
335 static int de_identify_dlmaker(deark
*c
)
341 i64 expected_filesize
;
343 if(!de_input_file_has_ext(c
, "dl")) return 0;
346 nscrn
= (i64
)de_getbyte(21);
347 ctlsize
= de_getu16le(22); // num frames * 1 byte
351 if(de_getbyte(1)>2) return 0;
352 nscrn
= (i64
)de_getbyte(42);
353 ctlsize
= de_getu32le(43) * 2;
357 nscrn
= (i64
)de_getbyte(132);
358 ctlsize
= de_getu16le(134) * 2;
365 if(nscrn
==0 || ctlsize
==0) return 0;
367 // This is just a minimum file size. v3 is hard to identify.
368 expected_filesize
= hsize
+ nscrn
*5 + ctlsize
;
369 if(c
->infile
->len
< expected_filesize
) return 0;
372 expected_filesize
= hsize
+ V12_SCREEN_SIZE_IN_BYTES
*nscrn
+ ctlsize
;
373 if(c
->infile
->len
== expected_filesize
) return 90;
374 if(c
->infile
->len
< expected_filesize
) return 0;
375 // Allow for some padding or other unknown data at EOF.
376 if(c
->infile
->len
> expected_filesize
+511) return 0;
380 static void de_help_dlmaker(deark
*c
)
382 de_msg(c
, "-opt dlmaker:montage : Output the \"screens\", instead of the "
383 "individual images");
386 void de_module_dlmaker(deark
*c
, struct deark_module_info
*mi
)
389 mi
->desc
= "DL animation (DL MAKER)";
390 mi
->run_fn
= de_run_dlmaker
;
391 mi
->identify_fn
= de_identify_dlmaker
;
392 mi
->help_fn
= de_help_dlmaker
;