1 // This file is part of Deark.
2 // Copyright (C) 2017 Jason Summers
3 // See the file COPYING for terms of use.
5 // Spectrum 512 Uncompressed (.SPU)
6 // Spectrum 512 Compressed (.SPC)
7 // Spectrum 512 Smooshed (.SPS)
9 #include <deark-config.h>
10 #include <deark-private.h>
11 #include <deark-fmtutil.h>
12 DE_DECLARE_MODULE(de_module_spectrum512u
);
13 DE_DECLARE_MODULE(de_module_spectrum512c
);
14 DE_DECLARE_MODULE(de_module_spectrum512s
);
16 // **************************************************************************
18 static void do_spu_internal(deark
*c
, dbuf
*inf
, int is_enhanced
)
20 struct atari_img_decode_data
*adata
= NULL
;
22 static const i64 num_colors
= 199*48;
24 adata
= de_malloc(c
, sizeof(struct atari_img_decode_data
));
25 adata
->is_spectrum512
= 1;
26 adata
->pal
= de_mallocarray(c
, num_colors
, sizeof(u32
));
30 adata
->ncolors
= num_colors
;
32 fmtutil_read_atari_palette(c
, inf
, 32000, adata
->pal
, num_colors
, num_colors
,
33 is_enhanced
?DE_FLAG_ATARI_15BIT_PAL
:0);
35 adata
->unc_pixels
= dbuf_open_input_subfile(inf
, 160, inf
->len
-160);
36 adata
->img
= de_bitmap_create(c
, adata
->w
, adata
->h
, 3);
37 fi
= de_finfo_create(c
);
38 fmtutil_atari_set_standard_density(c
, adata
, fi
);
39 fmtutil_atari_decode_image(c
, adata
);
40 de_bitmap_write_to_file_finfo(adata
->img
, fi
, 0);
43 de_bitmap_destroy(adata
->img
);
44 de_free(c
, adata
->pal
);
45 dbuf_close(adata
->unc_pixels
);
48 de_finfo_destroy(c
, fi
);
51 static void de_run_spectrum512u(deark
*c
, de_module_params
*mparams
)
55 if(!dbuf_memcmp(c
->infile
, 0, (const void*)"5BIT", 4)) {
57 de_declare_fmt(c
, "Spectrum 512 Uncompressed Enhanced");
60 de_declare_fmt(c
, "Spectrum 512 Uncompressed");
63 do_spu_internal(c
, c
->infile
, is_enhanced
);
66 static int de_identify_spectrum512u(deark
*c
)
68 if(c
->infile
->len
!=51104 && c
->infile
->len
!=51200)
71 if(de_input_file_has_ext(c
, "spu")) {
72 return (c
->infile
->len
==51104) ? 90 : 10;
77 static void de_help_spectrum512u(deark
*c
)
79 fmtutil_atari_help_palbits(c
);
82 void de_module_spectrum512u(deark
*c
, struct deark_module_info
*mi
)
84 mi
->id
= "spectrum512u";
85 mi
->desc
= "Spectrum 512 Uncompressed";
86 mi
->run_fn
= de_run_spectrum512u
;
87 mi
->identify_fn
= de_identify_spectrum512u
;
88 mi
->help_fn
= de_help_spectrum512u
;
91 // **************************************************************************
93 // This is almost PackBits, but not quite.
94 static void spc_uncompress_pixels(dbuf
*f
, i64 pos1
, i64 len
,
106 if(unc_pixels
->has_len_limit
&& unc_pixels
->len
>=unc_pixels
->len_limit
) {
107 break; // Decompressed the requested amount of dst data.
111 break; // Reached the end of source data
113 b
= dbuf_getbyte(f
, pos
++);
115 if(b
>=128) { // A compressed run
116 count
= 258 - (i64
)b
;
117 b2
= dbuf_getbyte(f
, pos
++);
118 dbuf_write_run(unc_pixels
, b2
, count
);
120 else { // An uncompressed run
122 dbuf_copy(f
, pos
, count
, unc_pixels
);
128 static void sps_uncompress_pixels(dbuf
*f
, i64 pos1
, i64 len
,
140 if(unc_pixels
->has_len_limit
&& unc_pixels
->len
>=unc_pixels
->len_limit
) {
141 break; // Decompressed the requested amount of dst data.
145 break; // Reached the end of source data
147 b
= dbuf_getbyte(f
, pos
++);
149 if(b
<=127) { // A compressed run
151 b2
= dbuf_getbyte(f
, pos
++);
152 dbuf_write_run(unc_pixels
, b2
, count
);
154 else { // An uncompressed run
155 count
= (i64
)b
- 127;
156 dbuf_copy(f
, pos
, count
, unc_pixels
);
163 // After SPC decompression, we have a 320x199 image, but with the
164 // bytes in an inconvenient order, different from SPU format.
165 // This converts an SPC after-decompression byte offset (from 0 to 31839)
166 // to the corresponding SPU file offset (from 160 to 31999).
167 static i64
reorderfn_spc(i64 a
)
172 b
= 160 + (a
-1)*4 + 1; // if odd
174 b
= 160 + a
*4; // if even
177 b
-= (32000-(160+2));
182 // For SPS type 0. See reorderfn_spc() comments for details.
183 static i64
reorderfn_sps0(i64 a
)
186 b
= 160 + (a
%199)*160 + ((a
%7960)/398)*8 + (a
/7960)*2 + (a
%398)/199;
190 typedef i64 (*reorder_fn
)(i64 a
);
192 static void reorder_img_bytes(deark
*c
, dbuf
*src
, dbuf
*dst
, reorder_fn rfn
)
197 for(i
=0; i
<src
->len
; i
++) {
198 b
= dbuf_getbyte(src
, i
);
199 dbuf_writebyte_at(dst
, rfn(i
), b
);
203 // Read from c->infile at offset pos1, append to uncmpr_pal
204 static void spc_uncompress_pal(deark
*c
, i64 pos1
, dbuf
*uncmpr_pal
)
206 static const i64 num_pals
= 199*3;
211 for(i
=0; i
<num_pals
; i
++) {
212 code
= (unsigned int)de_getu16be(pos
);
214 for(k
=0; k
<16; k
++) {
215 // Bit 15 is ignored. The corresponding pal entry will always be black.
216 if(k
<=14 && (code
&0x1)) {
217 dbuf_copy(c
->infile
, pos
, 2, uncmpr_pal
);
221 dbuf_write_zeroes(uncmpr_pal
, 2);
228 // Read from c->infile at offset pos1, append to uncmpr_pal
229 static void sps_uncompress_pal(deark
*c
, i64 pos1
, dbuf
*uncmpr_pal
)
231 static const i64 num_pals
= 199*3;
235 struct de_bitreader bitrd
;
237 de_zeromem(&bitrd
, sizeof(struct de_bitreader
));
240 bitrd
.endpos
= c
->infile
->len
;
242 for(i
=0; i
<num_pals
; i
++) {
243 code
= (UI
)de_bitreader_getbits(&bitrd
, 14);
245 for(k
=0; k
<16; k
++) {
246 // Palette entries 0 and 15 are always black
247 if(k
>=1 && k
<=14 && (code
&(1<<(14-k
)))) {
248 unsigned int cr
, cg
, cb
;
249 unsigned int palcode
;
251 cr
= (UI
)de_bitreader_getbits(&bitrd
, 3);
252 cg
= (UI
)de_bitreader_getbits(&bitrd
, 3);
253 cb
= (UI
)de_bitreader_getbits(&bitrd
, 3);
254 palcode
= (cr
<<8)|(cg
<<4)|cb
;
255 dbuf_writeu16be(uncmpr_pal
, palcode
);
258 dbuf_write_zeroes(uncmpr_pal
, 2);
264 static void do_run_spectrum512c_s_internal(deark
*c
, de_module_params
*mparams
, int is_sps
)
270 dbuf
*unc_pixels_planar
= NULL
;
271 dbuf
*spufile
= NULL
;
273 unsigned int sps_format_code
= 0;
275 if(de_get_ext_option(c
, "spectrum512:tospu")) {
280 pixels_cmpr_len
= de_getu32be(pos
);
281 de_dbg(c
, "pixels compressed len: %d", (int)pixels_cmpr_len
);
283 pal_cmpr_len
= de_getu32be(pos
);
284 de_dbg(c
, "palette compressed len: %d", (int)pal_cmpr_len
);
287 pal_pos
= pos
+ pixels_cmpr_len
;
289 if(pal_pos
+ pal_cmpr_len
> c
->infile
->len
) {
290 de_err(c
, "Invalid or truncated file");
295 sps_format_code
= de_getbyte(pal_pos
+ pal_cmpr_len
-1);
296 sps_format_code
&= 0x1;
297 de_dbg(c
, "format code: %u", sps_format_code
);
300 de_dbg(c
, "pixels at %d", (int)pos
);
301 // Decompress the pixel data into an in-memory buffer.
302 unc_pixels_planar
= dbuf_create_membuf(c
, 32000, 1);
304 sps_uncompress_pixels(c
->infile
, pos
, pixels_cmpr_len
, unc_pixels_planar
);
307 spc_uncompress_pixels(c
->infile
, pos
, pixels_cmpr_len
, unc_pixels_planar
);
309 //pos += pixels_cmpr_len;
311 // We'll construct an in-memory SPU file, then (usually) use our
312 // SPU module's decoder to process it.
313 spufile
= dbuf_create_membuf(c
, 51104, 0x1);
315 // Rearrange the bytes in the image data, as we write them to our
316 // in-memory image of an SPU file.
317 // (This could be done more efficiently during decompression,
318 // but the code would be messier.)
319 if(is_sps
&& sps_format_code
==0) {
320 reorder_img_bytes(c
, unc_pixels_planar
, spufile
, reorderfn_sps0
);
323 reorder_img_bytes(c
, unc_pixels_planar
, spufile
, reorderfn_spc
);
326 // Make sure we write the uncompressed palette at exactly offset 32000.
327 dbuf_truncate(spufile
, 32000);
330 de_dbg(c
, "palette at %d", (int)pos
);
332 sps_uncompress_pal(c
, pos
, spufile
);
335 spc_uncompress_pal(c
, pos
, spufile
);
339 // Instead of decoding the image, write it in .SPU format
341 outf
= dbuf_create_output_file(c
, "spu", NULL
, 0);
342 dbuf_copy(spufile
, 0, spufile
->len
, outf
);
346 do_spu_internal(c
, spufile
, 0);
350 dbuf_close(unc_pixels_planar
);
354 static void de_run_spectrum512c(deark
*c
, de_module_params
*mparams
)
356 do_run_spectrum512c_s_internal(c
, mparams
, 0);
359 static int de_identify_spectrum512c(deark
*c
)
361 if(dbuf_memcmp(c
->infile
, 0, "\x53\x50\x00\x00", 4))
364 if(de_input_file_has_ext(c
, "spc")) {
368 if(de_input_file_has_ext(c
, "sps")) {
375 static void de_help_spectrum512cs(deark
*c
)
377 de_msg(c
, "-opt spectrum512:tospu : Output to an .spu file");
378 fmtutil_atari_help_palbits(c
);
381 void de_module_spectrum512c(deark
*c
, struct deark_module_info
*mi
)
383 mi
->id
= "spectrum512c";
384 mi
->desc
= "Spectrum 512 Compressed";
385 mi
->run_fn
= de_run_spectrum512c
;
386 mi
->identify_fn
= de_identify_spectrum512c
;
387 mi
->help_fn
= de_help_spectrum512cs
;
390 static void de_run_spectrum512s(deark
*c
, de_module_params
*mparams
)
392 do_run_spectrum512c_s_internal(c
, mparams
, 1);
395 static int de_identify_spectrum512s(deark
*c
)
397 if(dbuf_memcmp(c
->infile
, 0, "\x53\x50\x00\x00", 4))
400 if(de_input_file_has_ext(c
, "sps")) {
404 // No reason to return anything but 0. The file will be identified as SPC.
408 void de_module_spectrum512s(deark
*c
, struct deark_module_info
*mi
)
410 mi
->id
= "spectrum512s";
411 mi
->desc
= "Spectrum 512 Smooshed";
412 mi
->run_fn
= de_run_spectrum512s
;
413 mi
->identify_fn
= de_identify_spectrum512s
;
414 mi
->help_fn
= de_help_spectrum512cs
;