Made Unix builds more likely to be Y2038-compliant
[deark.git] / modules / colorix.c
blob2299f4cfbf79026e865237e642f9787aebff0276
1 // This file is part of Deark.
2 // Copyright (C) 2023 Jason Summers
3 // See the file COPYING for terms of use.
5 // ColoRIX .SCI, .SCR, etc.
7 #include <deark-private.h>
8 #include <deark-fmtutil.h>
9 DE_DECLARE_MODULE(de_module_colorix);
11 #define RIX_MIN_FILE_SIZE 36
12 #define RIX_UNC_SCR_FILE_SIZE 112016
13 #define RIX_MIN_OLD_SEGMENT_DLEN 100
15 struct colorix_ctx {
16 #define RIXFMT_OLD_U 1
17 #define RIXFMT_OLD_C 2
18 #define RIXFMT_RIX3 3
19 int fmtver;
20 u8 paltype;
21 u8 stgtype;
22 u8 imgtype;
23 u8 is_compressed;
24 u8 is_encrypted;
25 u8 has_extension_block;
26 i64 width, height;
27 i64 rowspan;
28 i64 known_segment_size;
29 i64 pal_nbytes;
30 i64 unc_image_size;
31 de_color pal[256];
34 enum rle_state_type {
35 RIX_RLESTATE_NEUTRAL = 0,
36 RIX_RLESTATE_WAITING_FOR_REPEAT_COUNT
39 struct de_rixdecomp_params {
40 i64 known_segment_size; // Set either this or rowspan
41 i64 rowspan;
42 u8 imgtype;
45 struct rixdecomp_ctx {
46 deark *c;
47 struct de_rixdecomp_params *private_params;
48 struct de_dfilter_in_params *dcmpri;
49 struct de_dfilter_out_params *dcmpro;
50 struct de_dfilter_results *dres;
51 const char *modname;
52 u8 errflag;
53 u8 use_xor_filter;
54 i64 nbytes_written;
55 i64 nodetable_pos;
56 i64 first_cmpr_segment_pos;
57 struct fmtutil_huffman_decoder *ht;
58 struct de_bitreader bitrd;
60 i64 nodetable_dpos;
61 i64 nodetable_dlen;
63 enum rle_state_type rle_state;
64 u8 rle_curr_color;
65 u8 rle_byte_to_repeat;
67 char tmpbuf[72];
70 static void rixdecomp_interpret_nodetable_item(struct rixdecomp_ctx *rhctx,
71 i64 itempos, u64 currcode, UI currcode_nbits)
73 u16 dval;
75 if(rhctx->errflag) return;
76 if((itempos < rhctx->nodetable_dpos) ||
77 (itempos+2 > rhctx->nodetable_dpos+rhctx->nodetable_dlen))
79 rhctx->errflag = 1;
80 return;
82 if(currcode_nbits>=FMTUTIL_HUFFMAN_MAX_CODE_LENGTH) return;
84 dval = (u16)dbuf_getu16le(rhctx->dcmpri->f, itempos);
85 de_dbg2(rhctx->c, "item@%"I64_FMT": 0x%04x", itempos, (UI)dval);
87 if(dval>=2 && dval<0x1000 && (dval%2==0)) { // a "pointer" item
88 // The very next item is the start of the "1" subtree.
89 rixdecomp_interpret_nodetable_item(rhctx, itempos+2, ((currcode<<1) | 1), currcode_nbits+1);
90 if(rhctx->errflag) goto done;
92 // The pointer item tells how many bytes are between the pointer item
93 // and the start of the "0" subtree.
94 rixdecomp_interpret_nodetable_item(rhctx, itempos+2+(i64)dval, currcode<<1, currcode_nbits+1);
95 if(rhctx->errflag) goto done;
97 else if(dval>=0x1000 && dval<=0x10ff) { // a leaf item
98 fmtutil_huffman_valtype adj_value;
100 adj_value = (fmtutil_huffman_valtype)(dval-0x1000);
101 if(rhctx->c->debug_level>=3) {
102 de_dbg3(rhctx->c, "code: \"%s\" = %d",
103 de_print_base2_fixed(rhctx->tmpbuf, sizeof(rhctx->tmpbuf), currcode, currcode_nbits),
104 (int)adj_value);
106 if(!fmtutil_huffman_add_code(rhctx->c, rhctx->ht->bk, currcode, currcode_nbits, adj_value)) {
107 rhctx->errflag = 1;
110 else {
111 rhctx->errflag = 1;
112 goto done;
115 done:
119 // Read node table, construct Huffman codebook.
120 // Uses rhctx->nodetable_pos.
121 // Sets rhctx->first_cmpr_segment_pos.
122 static int rixdecomp_read_nodetable(deark *c, struct rixdecomp_ctx *rhctx)
124 i64 pos1;
125 i64 pos;
126 i64 nodetable_dlen_raw;
127 int retval = 0;
128 int saved_indent_level;
130 de_dbg_indent_save(c, &saved_indent_level);
131 pos1 = rhctx->nodetable_pos;
132 pos = pos1;
133 de_dbg(c, "huffman node table segment at %"I64_FMT, pos1);
134 de_dbg_indent(c, 1);
135 nodetable_dlen_raw = dbuf_getu16le_p(rhctx->dcmpri->f, &pos);
136 rhctx->nodetable_dlen = nodetable_dlen_raw*2;
137 de_dbg(c, "node table dlen: %"I64_FMT, rhctx->nodetable_dlen);
138 rhctx->nodetable_dpos = pos;
139 rhctx->first_cmpr_segment_pos = rhctx->nodetable_dpos + rhctx->nodetable_dlen;
141 rhctx->ht = fmtutil_huffman_create_decoder(c, 256, 256);
143 // We expect a maximum of 513: 256 leaf entries, + 255 pointer entries,
144 // + up to 2 extra zero-valued entries at the end.
145 if(nodetable_dlen_raw < 1) {
146 de_dfilter_set_generic_error(c, rhctx->dres, rhctx->modname);
147 goto done;
150 de_dbg2(c, "node table nodes at %"I64_FMT, rhctx->nodetable_dpos);
151 de_dbg_indent(c, 1);
152 rixdecomp_interpret_nodetable_item(rhctx, rhctx->nodetable_dpos, 0, 0);
153 de_dbg_indent(c, -1);
155 if(c->debug_level>=4) {
156 fmtutil_huffman_dump(c, rhctx->ht);
159 retval = 1;
160 done:
161 de_dbg_indent_restore(c, saved_indent_level);
162 return retval;
165 static void rixdecomp_process_rle_byte(deark *c, struct rixdecomp_ctx *rhctx, u8 n)
167 i64 count = 0;
168 i64 k;
169 u8 val;
171 if(rhctx->nbytes_written >= rhctx->dcmpro->expected_len) {
172 goto done;
175 switch(rhctx->rle_state) {
176 case RIX_RLESTATE_NEUTRAL:
177 if(n==0x00 || n==0xff) {
178 rhctx->rle_state = RIX_RLESTATE_WAITING_FOR_REPEAT_COUNT;
179 rhctx->rle_byte_to_repeat = n;
180 goto done;
182 else {
183 count = 1;
184 val = n;
186 break;
187 case RIX_RLESTATE_WAITING_FOR_REPEAT_COUNT:
188 count = (i64)n + 1;
189 val = rhctx->rle_byte_to_repeat;
190 rhctx->rle_state = RIX_RLESTATE_NEUTRAL;
191 break;
194 for(k = 0; k<count; k++) {
195 if(rhctx->use_xor_filter) {
196 rhctx->rle_curr_color ^= val;
198 else {
199 rhctx->rle_curr_color = val;
201 dbuf_writebyte(rhctx->dcmpro->f, rhctx->rle_curr_color);
203 rhctx->nbytes_written += count;
204 done:
208 static void rixdecomp_process_codes_segment(deark *c, struct rixdecomp_ctx *rhctx, i64 dpos1, i64 dlen)
210 de_zeromem(&rhctx->bitrd, sizeof(struct de_bitreader));
211 rhctx->bitrd.bbll.is_lsb = 0;
212 rhctx->bitrd.f = rhctx->dcmpri->f;
213 rhctx->bitrd.curpos = dpos1;
214 rhctx->bitrd.endpos = dpos1 + dlen;
215 de_bitbuf_lowlevel_empty(&rhctx->bitrd.bbll);
216 fmtutil_huffman_reset_cursor(rhctx->ht->cursor);
218 rhctx->rle_state = RIX_RLESTATE_NEUTRAL;
219 rhctx->rle_curr_color = 0x00;
221 while(1) {
222 int ret;
223 fmtutil_huffman_valtype val = 0;
225 ret = fmtutil_huffman_read_next_value(rhctx->ht->bk, &rhctx->bitrd, &val, NULL);
226 if(!ret || val<0 || val>255) {
227 // We don't always know exactly where the data stops, so don't report
228 // errors here.
229 goto done;
232 rixdecomp_process_rle_byte(c, rhctx, (u8)val);
235 done:
239 static void rixdecomp_codectype1(deark *c, struct de_dfilter_in_params *dcmpri,
240 struct de_dfilter_out_params *dcmpro, struct de_dfilter_results *dres,
241 void *codec_private_params)
243 struct rixdecomp_ctx *rhctx = NULL;
244 i64 pos;
245 i64 endpos;
246 i64 seg_count;
247 int ok = 0;
248 int saved_indent_level;
250 de_dbg_indent_save(c, &saved_indent_level);
251 rhctx = de_malloc(c, sizeof(struct rixdecomp_ctx));
252 rhctx->c = c;
253 rhctx->private_params = (struct de_rixdecomp_params*)codec_private_params;
254 rhctx->modname = "rixdecomp";
255 rhctx->dcmpri = dcmpri;
256 rhctx->dcmpro = dcmpro;
257 rhctx->dres = dres;
258 endpos = dcmpri->pos + rhctx->dcmpri->len;
259 rhctx->use_xor_filter = (rhctx->private_params->imgtype==0);
261 // Currently, we have some restrictions on the output dbuf.
262 if(dcmpro->f->btype!=DBUF_TYPE_MEMBUF || dcmpro->f->len!=0 ||
263 !dcmpro->len_known)
265 goto done;
268 if(rhctx->private_params->rowspan<1) goto done;
270 rhctx->nodetable_pos = dcmpri->pos;
271 if(!rixdecomp_read_nodetable(c, rhctx)) goto done;
273 seg_count = 0;
274 pos = rhctx->first_cmpr_segment_pos;
275 while(1) {
276 i64 saved_len;
277 i64 seg_dcmpr_len;
278 i64 seg_pos;
279 i64 seg_dpos;
280 i64 seg_dlen;
281 i64 num_extra_bytes;
283 if(pos+2 >= endpos) break;
284 rhctx->nbytes_written = rhctx->dcmpro->f->len;
285 if(rhctx->nbytes_written >= rhctx->dcmpro->expected_len) {
286 break;
289 seg_pos = pos;
290 seg_dlen = dbuf_getu16le_p(dcmpri->f, &pos);
291 if(seg_dlen==0) break;
292 seg_dpos = pos;
294 de_dbg(c, "compressed segment at %"I64_FMT", dpos=%"I64_FMT", dlen=%"I64_FMT,
295 seg_pos, seg_dpos, seg_dlen);
296 de_dbg_indent(c, 1);
298 saved_len = rhctx->dcmpro->f->len;
299 dbuf_enable_wbuffer(rhctx->dcmpro->f);
300 rixdecomp_process_codes_segment(c, rhctx, seg_dpos, seg_dlen);
301 dbuf_disable_wbuffer(rhctx->dcmpro->f);
303 seg_dcmpr_len = rhctx->dcmpro->f->len - saved_len;
304 de_dbg(c, "decompressed size: %"I64_FMT, seg_dcmpr_len);
306 if(seg_dcmpr_len < rhctx->private_params->rowspan) {
307 de_dfilter_set_generic_error(c, dres, rhctx->modname);
308 goto done;
311 de_dbg(c, "number of rows: %"I64_FMT, (i64)(seg_dcmpr_len/rhctx->private_params->rowspan));
313 if(rhctx->private_params->known_segment_size) {
314 rhctx->nbytes_written = (seg_count+1) * rhctx->private_params->known_segment_size;
315 dbuf_truncate(rhctx->dcmpro->f, rhctx->nbytes_written);
317 else if(rhctx->dcmpro->f->len < rhctx->dcmpro->expected_len) {
318 // For non-final segments, there is a potential problem.
319 // For a compressed segment, we know neither the (bit-exact) size of the
320 // compressed data, nor the size of the decompressed data. The padding
321 // bits in the final byte can be misinterpreted as compressed data, so
322 // we may have mistakenly decompressed them into garbage pixels that
323 // will mess up the rest of the image.
324 // It's possible that there is a formula that would tell us the size
325 // of the decompressed data. But I don't know what it is.
326 // Anyway, this is a quick and dirty attempt to work around the problem
327 // by detecting and deleting such garbage pixels. It's not foolproof, and
328 // better heuristics are possible.
329 num_extra_bytes = rhctx->dcmpro->f->len % rhctx->private_params->rowspan;
330 if(num_extra_bytes>0) {
331 de_dbg(c, "[ignoring %"I64_FMT" bytes -- assuming garbage caused by padding bits]",
332 num_extra_bytes);
333 rhctx->nbytes_written = rhctx->dcmpro->f->len - num_extra_bytes;
334 dbuf_truncate(rhctx->dcmpro->f, rhctx->nbytes_written);
338 pos += seg_dlen;
339 seg_count++;
340 de_dbg_indent(c, -1);
343 ok = 1;
345 done:
346 if(rhctx) {
347 if(!ok || dres->errcode) {
348 de_dfilter_set_generic_error(c, dres, rhctx->modname);
351 fmtutil_huffman_destroy_decoder(c, rhctx->ht);
352 de_free(c, rhctx);
354 de_dbg_indent_restore(c, saved_indent_level);
357 static int do_colorix_decompress(deark *c, struct colorix_ctx *d, i64 pos1,
358 dbuf *unc_pixels)
360 int retval = 0;
361 struct de_dfilter_in_params dcmpri;
362 struct de_dfilter_out_params dcmpro;
363 struct de_dfilter_results dres;
364 struct de_rixdecomp_params params;
366 de_zeromem(&params, sizeof(struct de_rixdecomp_params));
367 params.known_segment_size = d->known_segment_size;
368 params.rowspan = d->rowspan;
369 params.imgtype = d->imgtype;
371 de_dfilter_init_objects(c, &dcmpri, &dcmpro, &dres);
372 dcmpri.f = c->infile;
373 dcmpri.pos = pos1;
374 dcmpri.len = c->infile->len - pos1;
375 dcmpro.f = unc_pixels;
376 dcmpro.expected_len = d->unc_image_size;
377 dcmpro.len_known = 1;
379 rixdecomp_codectype1(c, &dcmpri, &dcmpro, &dres, (void*)&params);
380 dbuf_flush(dcmpro.f);
382 if(dres.errcode) {
383 de_err(c, "Decompression failed: %s", de_dfilter_get_errmsg(c, &dres));
384 goto done;
387 retval = 1;
388 done:
389 return retval;
392 static void do_colorix_image_RIX3(deark *c, struct colorix_ctx *d, i64 pos1)
394 de_bitmap *img = NULL;
395 dbuf *unc_pixels = 0;
396 dbuf *final_pixels_dbuf; // copy of pointer; do not free
397 i64 final_pixels_pos;
398 int saved_indent_level;
400 de_dbg_indent_save(c, &saved_indent_level);
401 de_dbg(c, "image at %"I64_FMT, pos1);
402 de_dbg_indent(c, 1);
403 if(!de_good_image_dimensions(c, d->width, d->height)) goto done;
405 if(d->imgtype==4) {
406 d->rowspan = de_pad_to_n(d->width, 8) / 2;
408 else {
409 d->rowspan = d->width;
411 if(d->rowspan<1) goto done;
413 d->unc_image_size = d->rowspan * d->height;
414 img = de_bitmap_create(c, d->width, d->height, 3);
416 if(d->is_compressed) {
417 unc_pixels = dbuf_create_membuf(c, d->unc_image_size+256, 0);
418 if(!do_colorix_decompress(c, d, pos1, unc_pixels)) {
419 goto done;
421 final_pixels_dbuf = unc_pixels;
422 final_pixels_pos = 0;
424 else {
425 final_pixels_dbuf = c->infile;
426 final_pixels_pos = pos1;
429 if(d->imgtype==4) {
430 de_convert_image_paletted_planar(final_pixels_dbuf, final_pixels_pos, 4,
431 d->rowspan, d->rowspan/4, d->pal, img, 0x2);
433 else { // assume 0
434 de_convert_image_paletted(final_pixels_dbuf, final_pixels_pos, 8,
435 d->rowspan, d->pal, img, 0);
438 de_bitmap_write_to_file(img, NULL, DE_CREATEFLAG_OPT_IMAGE);
440 done:
441 de_bitmap_destroy(img);
442 dbuf_close(unc_pixels);
443 de_dbg_indent_restore(c, saved_indent_level);
446 // Sets d->pal_nbytes
447 static void read_colorix_palette(deark *c, struct colorix_ctx *d, i64 pos1)
449 if(d->paltype==0xab) {
450 de_read_simple_palette(c, c->infile, pos1, 16, 3, d->pal, 16, DE_RDPALTYPE_VGA18BIT, 0);
451 d->pal_nbytes = 48;
453 else { // assume 0xaf
454 de_read_simple_palette(c, c->infile, pos1, 256, 3, d->pal, 256, DE_RDPALTYPE_VGA18BIT, 0);
455 d->pal_nbytes = 768;
459 static void declare_colorix_fmt(deark *c, struct colorix_ctx *d)
461 de_declare_fmtf(c, "ColoRIX - %s, %scompressed",
462 (d->fmtver==RIXFMT_RIX3 ? "new" : "old"),
463 (d->is_compressed ? "" : "un"));
466 static void do_colorix_RIX3(deark *c, struct colorix_ctx *d)
468 i64 pos;
470 pos = 4;
471 d->width = de_getu16le_p(&pos);
472 d->height = de_getu16le_p(&pos);
473 de_dbg_dimensions(c, d->width, d->height);
475 d->paltype = de_getbyte_p(&pos);
476 de_dbg(c, "palette type: 0x%02x", (UI)d->paltype);
477 if(d->paltype!=0xab && d->paltype!=0xaf) {
478 de_err(c, "Unsupported palette type: 0x%02x", (UI)d->paltype);
479 goto done;
482 d->stgtype = de_getbyte_p(&pos);
483 de_dbg(c, "storage type: 0x%02x", (UI)d->stgtype);
485 if(d->stgtype & 0x80) d->is_compressed = 1;
486 if(d->stgtype & 0x40) d->has_extension_block = 1;
487 if(d->stgtype & 0x20) d->is_encrypted = 1;
488 d->imgtype = d->stgtype & 0x0f; // I guess?
489 de_dbg_indent(c, 1);
490 de_dbg(c, "image type: %u", d->imgtype);
491 de_dbg_indent(c, -1);
492 declare_colorix_fmt(c, d);
494 if(d->is_encrypted) {
495 de_err(c, "Encrypted files not supported");
496 goto done;
499 if(d->has_extension_block) {
500 i64 e_len;
502 e_len = de_getu16le_p(&pos);
503 de_dbg(c, "extension block: dpos=%"I64_FMT", dlen=%"I64_FMT, pos, e_len);
504 // I've found no files with extension blocks, so no reason to parse them.
505 pos += e_len;
508 read_colorix_palette(c, d, pos);
509 pos += d->pal_nbytes;
511 if(d->imgtype==0 || d->imgtype==4) {
514 else {
515 de_err(c, "Unsupported image type: 0x%02x", (UI)d->stgtype);
516 goto done;
519 do_colorix_image_RIX3(c, d, pos);
520 done:
524 static void acquire_palette_ega64idx(deark *c, struct colorix_ctx *d, i64 pos1)
526 i64 k;
527 i64 pos = pos1;
528 char tmps[32];
530 for(k=0; k<16; k++) {
531 int index;
533 index = (int)de_getbyte_p(&pos);
534 index &= 0x3f;
535 d->pal[k] = de_get_std_palette_entry(DE_PALID_EGA64, 0, index);
536 de_snprintf(tmps, sizeof(tmps), "%2d ", index);
537 de_dbg_pal_entry2(c, k, d->pal[k], tmps, NULL, NULL);
541 static void do_colorix_old_SCR(deark *c, struct colorix_ctx *d)
543 de_bitmap *img = NULL;
544 i64 planespan;
545 dbuf *unc_pixels = NULL;
546 dbuf *tmpbuf = NULL;
547 dbuf *final_pixels_dbuf; // copy of pointer; do not free
548 i64 final_pixels_pos;
549 de_finfo *fi = NULL;
551 d->imgtype = 1;
552 d->width = 640;
553 d->height = 350;
554 d->unc_image_size = (d->width*d->height)/2;
555 planespan = d->unc_image_size/4;
556 d->known_segment_size = planespan;
557 d->rowspan = d->width/8;
558 declare_colorix_fmt(c, d);
560 acquire_palette_ega64idx(c, d, 0);
562 if(d->is_compressed) {
563 unc_pixels = dbuf_create_membuf(c, d->unc_image_size+256, 0);
564 if(!do_colorix_decompress(c, d, 16, unc_pixels)) goto done;
565 final_pixels_dbuf = unc_pixels;
566 final_pixels_pos = 0;
568 else {
569 final_pixels_dbuf = c->infile;
570 final_pixels_pos = 16;
573 // TODO?: Improve de_convert_image_paletted_planar to support this plane order.
574 tmpbuf = dbuf_create_membuf(c, d->unc_image_size, 0);
575 dbuf_copy(final_pixels_dbuf, final_pixels_pos+planespan*0, planespan, tmpbuf);
576 dbuf_copy(final_pixels_dbuf, final_pixels_pos+planespan*2, planespan, tmpbuf);
577 dbuf_copy(final_pixels_dbuf, final_pixels_pos+planespan*1, planespan, tmpbuf);
578 dbuf_copy(final_pixels_dbuf, final_pixels_pos+planespan*3, planespan, tmpbuf);
580 img = de_bitmap_create(c, d->width, d->height, 3);
581 de_convert_image_paletted_planar(tmpbuf, 0, 4,
582 d->rowspan, planespan, d->pal, img, 2);
584 fi = de_finfo_create(c);
585 fi->density.code = DE_DENSITY_UNK_UNITS;
586 fi->density.xdens = 480.0;
587 fi->density.ydens = (double)d->height;
588 de_bitmap_write_to_file_finfo(img, fi, DE_CREATEFLAG_OPT_IMAGE);
590 done:
591 de_bitmap_destroy(img);
592 dbuf_close(unc_pixels);
593 dbuf_close(tmpbuf);
594 de_finfo_destroy(c, fi);
597 static int is_RIX3(dbuf *f)
599 if(!dbuf_memcmp(f, 0, (const void*)"RIX3", 4)) {
600 return 1;
602 return 0;
605 // It's a pain to detect old compressed format, but I guess it's worth
606 // the trouble.
607 static int looks_like_compressed_data(dbuf *f, i64 pos1)
609 i64 pos = pos1;
610 i64 first_image_seg_pos;
611 int retval = 0;
612 i64 i;
613 i64 num_codebook_items;
614 i64 num_items_to_check;
616 // Validate the codebook size, and some of the items
617 num_codebook_items = dbuf_getu16le_p(f, &pos);
618 if(num_codebook_items<3 || num_codebook_items>513) goto done;
619 first_image_seg_pos = pos + num_codebook_items*2;
620 if(first_image_seg_pos > f->len) goto done;
622 num_items_to_check = de_min_int(num_codebook_items-2, 16);
623 for(i=0; i<num_items_to_check; i++) {
624 UI item;
626 item = (UI)dbuf_getu16le_p(f, &pos);
627 if(item<0x1000) {
628 if((item&0x1)!=0) goto done;
629 if(pos+item >= first_image_seg_pos) goto done;
631 else if(item<=0x10ff) {
634 else {
635 goto done;
639 // Validate the image segment sizes
640 pos = first_image_seg_pos;
641 for(i=0; i<4; i++) {
642 i64 seg_len;
644 if(pos+3 > f->len) goto done;
645 seg_len = dbuf_getu16le_p(f, &pos);
646 if(seg_len<RIX_MIN_OLD_SEGMENT_DLEN) goto done;
648 pos += seg_len;
651 if(pos==f->len) {
652 retval = 1;
655 done:
656 return retval;
659 // Returns RIXFMT_OLD_U, RIXFMT_OLD_C, or 0.
660 static int detect_old_fmt(dbuf *f, u8 strict)
662 size_t i;
663 u8 cmpr_flag = 0;
664 u8 buf[16];
666 if(f->len<RIX_MIN_FILE_SIZE) return 0;
668 // Check the palette
669 dbuf_read(f, buf, 0, 16);
670 for(i=0; i<16; i++) {
671 if(i==0) {
672 if((buf[i] & 0x80)!=0) {
673 cmpr_flag = 1;
674 buf[i] -= 0x80;
676 else {
677 if(f->len!=RIX_UNC_SCR_FILE_SIZE) return 0;
681 if(buf[i]>0x3f) return 0;
683 if(!cmpr_flag) return RIXFMT_OLD_U;
684 if(!strict) return RIXFMT_OLD_C;
686 if(looks_like_compressed_data(f, 16)) {
687 return RIXFMT_OLD_C;
690 return 0;
693 static void de_run_colorix(deark *c, de_module_params *mparams)
695 struct colorix_ctx *d = NULL;
697 d = de_malloc(c, sizeof(struct colorix_ctx));
699 if(is_RIX3(c->infile)) {
700 d->fmtver = RIXFMT_RIX3;
702 else {
703 d->fmtver = detect_old_fmt(c->infile, 0);
704 if(d->fmtver==RIXFMT_OLD_C) {
705 d->is_compressed = 1;
709 if(d->fmtver==RIXFMT_RIX3) {
710 do_colorix_RIX3(c, d);
712 else if(d->fmtver==RIXFMT_OLD_U || d->fmtver==RIXFMT_OLD_C) {
713 do_colorix_old_SCR(c, d);
715 else {
716 de_err(c, "Unknown or unsupported RIX format");
717 goto done;
720 done:
721 de_free(c, d);
724 static int de_identify_colorix(deark *c)
726 if(c->infile->len < RIX_MIN_FILE_SIZE) return 0;
728 if(is_RIX3(c->infile)) {
729 return 95;
732 if(c->detection_data->best_confidence_so_far >= 55) return 0;
734 if(de_input_file_has_ext(c, "scr")) {
735 int fmt;
737 fmt = detect_old_fmt(c->infile, 1);
738 if(fmt==RIXFMT_OLD_U) {
739 return 35;
741 else if(fmt==RIXFMT_OLD_C) {
742 return 55;
745 // TODO: There is supposedly also an old ".SCP" format, 640x480x16.
746 // But I can't find any samples.
748 return 0;
751 void de_module_colorix(deark *c, struct deark_module_info *mi)
753 mi->id = "colorix";
754 mi->desc = "ColoRIX";
755 mi->run_fn = de_run_colorix;
756 mi->identify_fn = de_identify_colorix;