1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // PCPaint PIC and CLP format
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_pcpaint
);
17 struct localctx_struct
;
18 typedef struct localctx_struct lctx
;
20 enum screen_mode_type_enum
{
21 SCREENMODETYPE_UNKNOWN
= 0,
22 SCREENMODETYPE_BITMAP
,
26 typedef void (*decoder_fn_type
)(deark
*c
, lctx
*d
);
28 struct localctx_struct
{
33 de_encoding input_encoding
;
34 int opt_keep_invis_chars
;
41 u8 video_mode
; // 0 = unknown
42 struct pal_info pal_info_mainfile
;
43 struct pal_info pal_info_palfile
;
44 struct pal_info
*pal_info_to_use
; // Points to _mainfile or _palfile
47 decoder_fn_type decoder_fn
;
48 enum screen_mode_type_enum screen_mode_type
;
51 static void set_density(deark
*c
, lctx
*d
)
55 switch(d
->video_mode
) {
61 d
->fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
62 d
->fi
->density
.xdens
= 240.0;
63 d
->fi
->density
.ydens
= 200.0;
65 case 'H': // 720x348 (Hercules)
67 d
->fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
68 // Various sources suggest aspect ratios of 1.46, 1.55, 1.59, ...
69 d
->fi
->density
.xdens
= 155.0;
70 d
->fi
->density
.ydens
= 100.0;
75 d
->fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
76 d
->fi
->density
.xdens
= 480.0;
77 d
->fi
->density
.ydens
= 350.0;
81 d
->fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
82 d
->fi
->density
.xdens
= 480.0;
83 d
->fi
->density
.ydens
= 400.0;
87 d
->fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
88 d
->fi
->density
.xdens
= 480.0;
89 d
->fi
->density
.ydens
= 200.0;
94 static void decode_text(deark
*c
, lctx
*d
)
97 struct de_char_context
*charctx
= NULL
;
98 struct de_char_screen
*screen
;
101 struct de_encconv_state es
;
103 // TODO: This might not work for monochrome text mode (d->video_mode==0x32).
105 width_in_chars
= d
->npwidth
/ 2;
107 charctx
= de_malloc(c
, sizeof(struct de_char_context
));
108 charctx
->no_density
= 1;
109 charctx
->nscreens
= 1;
110 charctx
->screens
= de_mallocarray(c
, charctx
->nscreens
, sizeof(struct de_char_screen
*));
111 charctx
->screens
[0] = de_malloc(c
, sizeof(struct de_char_screen
));
112 screen
= charctx
->screens
[0];
114 screen
->width
= width_in_chars
;
115 screen
->height
= d
->height
;
117 de_dbg(c
, "dimensions: %d"DE_CHAR_TIMES
"%d characters", (int)screen
->width
, (int)screen
->height
);
119 if(screen
->height
<1) goto done
;
121 screen
->cell_rows
= de_mallocarray(c
, screen
->height
, sizeof(struct de_char_cell
*));
122 de_encconv_init(&es
, d
->input_encoding
);
124 for(j
=0; j
<screen
->height
; j
++) {
127 j2
= screen
->height
-1-j
;
128 screen
->cell_rows
[j2
] = de_mallocarray(c
, screen
->width
, sizeof(struct de_char_cell
));
130 for(i
=0; i
<screen
->width
; i
++) {
131 ch
= dbuf_getbyte(d
->unc_pixels
, j
*d
->npwidth
+ i
*2);
132 attr
= dbuf_getbyte(d
->unc_pixels
, j
*d
->npwidth
+ i
*2 + 1);
134 screen
->cell_rows
[j2
][i
].fgcol
= (u32
)(attr
& 0x0f);
135 screen
->cell_rows
[j2
][i
].bgcol
= (u32
)((attr
& 0xf0) >> 4);
137 // In "blank" regions, some files have nonsense characters, with the fg
138 // and bg colors the same. We turn them into spaces, so that copy/paste
139 // works right with our HTML output.
141 (screen
->cell_rows
[j2
][i
].fgcol
==screen
->cell_rows
[j2
][i
].bgcol
&&
142 !d
->opt_keep_invis_chars
))
144 screen
->cell_rows
[j2
][i
].codepoint
= 32;
145 screen
->cell_rows
[j2
][i
].codepoint_unicode
= 32;
148 screen
->cell_rows
[j2
][i
].codepoint
= (i32
)ch
;
149 screen
->cell_rows
[j2
][i
].codepoint_unicode
= de_char_to_unicode_ex((i32
)ch
, &es
);
154 for(k
=0; k
<16; k
++) {
155 // TODO: Is this always the right palette? Maybe we can't ignore ->edesc
156 charctx
->pal
[k
] = de_palette_pc16((int)k
);
159 de_char_output_to_file(c
, charctx
);
162 de_free_charctx(c
, charctx
);
165 // Create a standard RGB palette from raw RGB palette data
166 static void make_rgb_palette(deark
*c
, lctx
*d
, u32
*pal
, i64 num_entries
)
171 int has_8bit_samples
= 0;
175 for(k
=0; k
<num_entries
; k
++) {
176 if(3*k
+2 >= d
->pal_info_to_use
->esize
) break;
177 cr1
= d
->pal_info_to_use
->data
[3*k
+0];
178 cg1
= d
->pal_info_to_use
->data
[3*k
+1];
179 cb1
= d
->pal_info_to_use
->data
[3*k
+2];
180 if(cr1
>63 || cg1
>63 || cb1
>63) {
181 de_dbg(c
, "detected 8-bit palette samples");
182 has_8bit_samples
= 1;
189 for(k
=0; k
<num_entries
; k
++) {
190 if(3*k
+2 >= d
->pal_info_to_use
->esize
) break;
191 cr1
= d
->pal_info_to_use
->data
[3*k
+0];
192 cg1
= d
->pal_info_to_use
->data
[3*k
+1];
193 cb1
= d
->pal_info_to_use
->data
[3*k
+2];
195 if(has_8bit_samples
) {
196 cr2
= (cr1
<<2) | (cr1
>>6);
197 cg2
= (cg1
<<2) | (cg1
>>6);
198 cb2
= (cb1
<<2) | (cb1
>>6);
199 pal
[k
] = DE_MAKE_RGB(cr2
, cg2
, cb2
);
200 de_dbg_pal_entry(c
, k
, pal
[k
]);
203 cr2
= de_scale_63_to_255(cr1
);
204 cg2
= de_scale_63_to_255(cg1
);
205 cb2
= de_scale_63_to_255(cb1
);
206 pal
[k
] = DE_MAKE_RGB(cr2
, cg2
, cb2
);
207 de_snprintf(tmps
, sizeof(tmps
), "(%2d,%2d,%2d) "DE_CHAR_RIGHTARROW
" ",
208 (int)cr1
, (int)cg1
, (int)cb1
);
209 de_dbg_pal_entry2(c
, k
, pal
[k
], tmps
, NULL
, NULL
);
212 de_dbg_indent(c
, -1);
215 static void decode_egavga16(deark
*c
, lctx
*d
)
225 de_bitmap
*img
= NULL
;
228 de_dbg(c
, "image type: 16-color EGA/VGA");
229 de_zeromem(pal
, sizeof(pal
));
232 if(d
->pal_info_to_use
->edesc
==0) {
233 de_dbg(c
, "palette type: standard 16-color palette (no palette in file)");
234 for(k
=0; k
<16; k
++) {
235 pal
[k
] = de_palette_pc16((int)k
);
238 else if(d
->pal_info_to_use
->edesc
==3) {
239 // An EGA palette. Indexes into the standard EGA
241 de_dbg(c
, "palette type: 16 indices into standard EGA 64-color palette");
242 for(k
=0; k
<16; k
++) {
243 if(k
>= d
->pal_info_to_use
->esize
) break;
244 pal
[k
] = de_palette_ega64(d
->pal_info_to_use
->data
[k
]);
245 de_snprintf(tmps
, sizeof(tmps
), "%2d ", (int)d
->pal_info_to_use
->data
[k
]);
246 de_dbg_pal_entry2(c
, k
, pal
[k
], tmps
, NULL
, NULL
);
249 else { // assuming edesc==5
250 de_dbg(c
, "palette type: 16-color palette (in file)");
251 make_rgb_palette(c
, d
, pal
, 16);
254 if(d
->plane_info
==0x31) {
255 d
->pdwidth
= de_pad_to_n(d
->npwidth
, 8);
256 src_rowspan
= d
->pdwidth
/8;
257 src_planespan
= src_rowspan
*d
->height
;
260 d
->pdwidth
= de_pad_to_2(d
->npwidth
);
261 src_rowspan
= d
->pdwidth
/2;
265 img
= de_bitmap_create2(c
, d
->npwidth
, d
->pdwidth
, d
->height
, 3);
267 for(j
=0; j
<d
->height
; j
++) {
268 for(i
=0; i
<d
->pdwidth
; i
++) {
269 if(d
->plane_info
==0x31) {
270 for(plane
=0; plane
<4; plane
++) {
271 z
[plane
] = de_get_bits_symbol(d
->unc_pixels
, 1, plane
*src_planespan
+ j
*src_rowspan
, i
);
273 palent
= z
[0] + 2*z
[1] + 4*z
[2] + 8*z
[3];
276 palent
= de_get_bits_symbol(d
->unc_pixels
, 4, j
*src_rowspan
, i
);
278 de_bitmap_setpixel_rgb(img
, i
, j
, pal
[palent
]);
282 de_bitmap_write_to_file_finfo(img
, d
->fi
, DE_CREATEFLAG_FLIP_IMAGE
);
284 de_bitmap_destroy(img
);
287 static void decode_vga256(deark
*c
, lctx
*d
)
291 de_bitmap
*img
= NULL
;
293 de_dbg(c
, "image type: 256-color");
294 de_zeromem(pal
, sizeof(pal
));
297 if(d
->pal_info_to_use
->edesc
==0) {
298 de_dbg(c
, "palette type: standard 256-color palette (no palette in file)");
299 for(k
=0; k
<256; k
++) {
300 pal
[k
] = de_palette_vga256((int)k
);
304 de_dbg(c
, "palette type: 256-color palette (in file)");
305 de_dbg(c
, "decoding palette");
306 make_rgb_palette(c
, d
, pal
, 256);
309 img
= de_bitmap_create2(c
, d
->npwidth
, d
->pdwidth
, d
->height
, 3);
311 de_convert_image_paletted(d
->unc_pixels
, 0,
312 8, img
->width
, pal
, img
, 0);
314 de_bitmap_write_to_file_finfo(img
, d
->fi
, DE_CREATEFLAG_FLIP_IMAGE
);
316 de_bitmap_destroy(img
);
319 static void decode_bilevel(deark
*c
, lctx
*d
)
324 i64 edesc
= d
->pal_info_to_use
->edesc
;
325 de_bitmap
*img
= NULL
;
327 de_dbg(c
, "image type: bilevel");
329 if(!d
->unc_pixels
) goto done
;
331 pal
[0] = DE_STOCKCOLOR_BLACK
;
332 pal
[1] = DE_STOCKCOLOR_WHITE
; // default
334 if(edesc
!=0 && edesc
!=4 && edesc
!=5) {
335 de_warn(c
, "The colors in this image might not be handled correctly (edesc=%d)",
339 if(edesc
==4 || edesc
==5) {
340 make_rgb_palette(c
, d
, pal
, 2);
343 // PCPaint's CGA and EGA 2-color modes used gray shade 170 instead of
344 // white (255). Maybe they should be interpreted as white, but for
345 // historical accuracy I'll go with gray170.
346 if(edesc
==0 && (d
->video_mode
==0x43 || d
->video_mode
==0x45)) {
347 pal
[1] = DE_MAKE_GRAY(170);
350 d
->pdwidth
= de_pad_to_n(d
->npwidth
, 8);
351 src_rowspan
= d
->pdwidth
/8;
352 is_grayscale
= de_is_grayscale_palette(pal
, 2);
353 img
= de_bitmap_create2(c
, d
->npwidth
, d
->pdwidth
, d
->height
, is_grayscale
?1:3);
355 de_convert_image_paletted(d
->unc_pixels
, 0,
356 1, src_rowspan
, pal
, img
, 0);
358 de_bitmap_write_to_file_finfo(img
, d
->fi
, DE_CREATEFLAG_FLIP_IMAGE
);
361 de_bitmap_destroy(img
);
364 static void decode_cga4(deark
*c
, lctx
*d
)
371 de_bitmap
*img
= NULL
;
373 de_dbg(c
, "image type: CGA 4-color");
375 if(!d
->unc_pixels
) goto done
;
377 if(d
->pal_info_to_use
->edesc
==1) {
378 // Image includes information about which CGA 4-color palette it uses.
380 // This assumes PIC format. That should be the case, since edesc will
381 // be zero for CLP format (unless we are reading the palette from a separate
383 if(d
->pal_info_to_use
->esize
>= 1)
384 pal_id
= d
->pal_info_to_use
->data
[0];
385 if(d
->pal_info_to_use
->esize
>= 2)
386 border_col
= d
->pal_info_to_use
->data
[1];
387 de_dbg(c
, "pal_id=0x%02x border=0x%02x", pal_id
, border_col
);
390 pal
[k
] = de_palette_pcpaint_cga4(pal_id
, (int)k
);
393 // Replace the first palette color with the border/background color.
394 pal
[0] = de_palette_pc16(border_col
);
397 // No palette specified in the file. Use palette #2 by default.
399 pal
[k
] = de_palette_pcpaint_cga4(2, (int)k
);
403 d
->pdwidth
= de_pad_to_4(d
->npwidth
);
404 src_rowspan
= d
->pdwidth
/4;
405 img
= de_bitmap_create2(c
, d
->npwidth
, d
->pdwidth
, d
->height
, 3);
407 de_convert_image_paletted(d
->unc_pixels
, 0,
408 2, src_rowspan
, pal
, img
, 0);
410 de_bitmap_write_to_file_finfo(img
, d
->fi
, DE_CREATEFLAG_FLIP_IMAGE
);
413 de_bitmap_destroy(img
);
416 // decompress one block
417 // Writes decompressed bytes to d->unc_pixels.
418 // packed_data_size does not include header size.
419 // Returns 0 on error.
420 static int decompress_block(deark
*c
, lctx
*d
,
421 i64 pos1
, i64 packed_data_size
, u8 run_marker
)
424 i64 end_of_this_block
;
428 end_of_this_block
= pos1
+ packed_data_size
;
430 while(pos
<end_of_this_block
) {
431 x
= de_getbyte_p(&pos
);
433 // An non-compressed part of the image
434 dbuf_writebyte(d
->unc_pixels
, x
);
439 x
= de_getbyte_p(&pos
);
441 // If nonzero, this byte is the run length.
445 // If zero, it is followed by a 16-bit run length
446 run_length
= de_getu16le_p(&pos
);
449 // Read the byte value to repeat (run_length) times.
450 x
= de_getbyte_p(&pos
);
451 dbuf_write_run(d
->unc_pixels
, x
, run_length
);
457 // Decompress multiple blocks of compressed pixels.
458 // This is for PIC format only.
459 static int decompress_pixels(deark
*c
, lctx
*d
)
463 i64 packed_block_size
;
464 i64 unpacked_block_size
;
467 i64 end_of_this_block
;
468 int saved_indent_level
;
470 de_dbg_indent_save(c
, &saved_indent_level
);
471 if(d
->num_rle_blocks
<1) {
477 d
->unc_pixels
= dbuf_create_membuf(c
, 16384, 0);
478 dbuf_set_length_limit(d
->unc_pixels
, (d
->pdwidth
+7) * d
->height
);
480 de_dbg(c
, "decompressing image");
482 pos
= d
->header_size
;
484 for(i
=0; i
<d
->num_rle_blocks
; i
++) {
485 de_dbg3(c
, "block #%d at %"I64_FMT
, (int)i
, pos
);
487 // start_of_this_block = pos;
488 packed_block_size
= de_getu16le(pos
);
489 // block size includes the 5-byte header, so it can't be < 5.
490 if(packed_block_size
<5) packed_block_size
=5;
491 end_of_this_block
= pos
+ packed_block_size
; // Remember where this block ends
492 unpacked_block_size
= de_getu16le(pos
+2);
493 run_marker
= de_getbyte(pos
+4);
496 de_dbg3(c
, "packed size: %"I64_FMT
, packed_block_size
);
497 de_dbg3(c
, "unpacked size: %"I64_FMT
, unpacked_block_size
);
498 de_dbg3(c
, "run marker: 0x%02x", (UI
)run_marker
);
500 if(!decompress_block(c
, d
, pos
, packed_block_size
-5, run_marker
)) {
503 de_dbg_indent(c
, -1);
505 pos
= end_of_this_block
;
508 de_dbg_indent(c
, -1);
509 de_dbg(c
, "decompressed to %"I64_FMT
" bytes", d
->unc_pixels
->len
);
513 de_dbg_indent_restore(c
, saved_indent_level
);
517 static int do_read_palette_data(deark
*c
, lctx
*d
, dbuf
*f
, struct pal_info
*palinfo
)
519 palinfo
->edesc
= dbuf_getu16le(f
, 13);
520 palinfo
->esize
= dbuf_getu16le(f
, 15);
521 palinfo
->data
= de_malloc(c
, palinfo
->esize
);
522 dbuf_read(f
, palinfo
->data
, 17, palinfo
->esize
);
526 // Figure out if we're supposed to read the palette from an alternate file.
527 // If so, open it and read a few fields from it. Modify settings so that
528 // we will read the palette from the alternate file.
529 // The palette file is assumed to be in PIC format.
530 static int do_read_alt_palette_file(deark
*c
, lctx
*d
)
533 dbuf
*palfile
= NULL
;
537 palfn
= de_get_ext_option(c
, "palfile");
538 if(!palfn
) palfn
= de_get_ext_option(c
, "file2");
544 de_dbg(c
, "[reading palette from alternate file]");
546 palfile
= dbuf_open_input_file(c
, palfn
);
551 magic
= dbuf_getu16le(palfile
, 0);
553 de_err(c
, "Palette file is not in PIC format.");
557 do_read_palette_data(c
, d
, palfile
, &d
->pal_info_palfile
);
559 if(d
->pal_info_palfile
.edesc
==0) {
560 de_warn(c
, "Palette file does not contain palette information.");
565 d
->pal_info_to_use
= &d
->pal_info_palfile
;
573 // Determine if we can decode this type of image.
574 // Sets d->decoder_fn and d->screen_mode_type.
575 // If image can't be decoded, prints an error and returns 0.
576 static int do_set_up_decoder(deark
*c
, lctx
*d
)
580 edesc
= d
->pal_info_to_use
->edesc
; // For brevity
582 if(d
->video_mode
>='0' && d
->video_mode
<='3') {
583 d
->screen_mode_type
= SCREENMODETYPE_TEXT
;
584 d
->decoder_fn
= decode_text
;
586 else if(d
->plane_info
==0x01) {
587 // Expected video mode(s): 0x43, 0x45, 0x48, 0x4f, 0x50, 0x55
588 // CGA or EGA or VGA or Hercules 2-color
589 d
->screen_mode_type
= SCREENMODETYPE_BITMAP
;
590 d
->decoder_fn
= decode_bilevel
;
592 else if(d
->plane_info
==0x02 && (edesc
==0 || edesc
==1)) {
593 // Expected video mode(s): 0x41
594 d
->screen_mode_type
= SCREENMODETYPE_BITMAP
;
595 d
->decoder_fn
= decode_cga4
;
597 else if(d
->plane_info
==0x04 && edesc
==3) {
598 d
->screen_mode_type
= SCREENMODETYPE_BITMAP
;
599 d
->decoder_fn
= decode_egavga16
;
601 else if((d
->plane_info
==0x04 || d
->plane_info
==0x31) &&
602 (edesc
==0 || edesc
==3 || edesc
==5))
604 // Expected video mode(s): 0x4d, 0x47
605 d
->screen_mode_type
= SCREENMODETYPE_BITMAP
;
606 d
->decoder_fn
= decode_egavga16
;
608 else if(d
->plane_info
==0x08 && (edesc
==0 || edesc
==4)) {
609 // Expected video mode(s): 0x4c
610 d
->screen_mode_type
= SCREENMODETYPE_BITMAP
;
611 d
->decoder_fn
= decode_vga256
;
615 de_dbg2(c
, "image type: evideo=0x%02x, bitsinf=0x%02x, edesc=%d",
616 d
->video_mode
, d
->plane_info
, (int)edesc
);
620 de_err(c
, "This type of PCPaint %s is not supported (evideo=0x%02x, bitsinf=0x%02x, edesc=%d)",
621 (d
->file_fmt
==FMT_CLP
) ? "CLP" : "PIC",
622 d
->video_mode
, d
->plane_info
, (int)edesc
);
627 static void de_run_pcpaint_pic(deark
*c
, lctx
*d
, de_module_params
*mparams
)
629 int saved_indent_level
;
631 de_dbg_indent_save(c
, &saved_indent_level
);
633 de_declare_fmt(c
, "PCPaint PIC");
635 d
->fi
= de_finfo_create(c
);
637 de_dbg(c
, "header at %d", 0);
640 d
->npwidth
= de_getu16le(2);
641 d
->pdwidth
= d
->npwidth
; // default
642 d
->height
= de_getu16le(4);
643 de_dbg_dimensions(c
, d
->npwidth
, d
->height
);
645 d
->plane_info
= de_getbyte(10);
646 d
->palette_flag
= de_getbyte(11);
648 de_dbg(c
, "plane info: 0x%02x", (int)d
->plane_info
);
649 de_dbg(c
, "palette flag: 0x%02x", (int)d
->palette_flag
);
651 if(d
->palette_flag
==0xff) {
656 de_err(c
, "This version of PCPaint PIC is not supported");
660 d
->video_mode
= de_getbyte(12);
661 de_dbg(c
, "video mode: 0x%02x", (int)d
->video_mode
);
663 do_read_palette_data(c
, d
, c
->infile
, &d
->pal_info_mainfile
);
664 de_dbg(c
, "edesc: %d", (int)d
->pal_info_mainfile
.edesc
);
665 de_dbg(c
, "esize: %d", (int)d
->pal_info_mainfile
.esize
);
667 if(d
->pal_info_mainfile
.esize
>0) {
668 de_dbg(c
, "palette or other info at %d", 17);
673 d
->pal_info_to_use
= &d
->pal_info_mainfile
; // tentative
674 if(!do_read_alt_palette_file(c
, d
)) goto done
;
676 d
->num_rle_blocks
= de_getu16le(17+d
->pal_info_mainfile
.esize
);
678 d
->header_size
= 17 + d
->pal_info_mainfile
.esize
+ 2;
680 de_dbg(c
, "num rle blocks: %d", (int)d
->num_rle_blocks
);
681 de_dbg_indent(c
, -1);
683 de_dbg(c
, "image data at %d", (int)d
->header_size
);
685 if(!do_set_up_decoder(c
, d
)) goto done
;
686 if(d
->screen_mode_type
==SCREENMODETYPE_BITMAP
) {
687 if(!de_good_image_dimensions(c
, d
->npwidth
, d
->height
)) goto done
;
690 if(d
->num_rle_blocks
>0) {
691 // Image is compressed.
692 decompress_pixels(c
, d
);
695 // Image is not compressed.
696 d
->unc_pixels
= dbuf_open_input_subfile(c
->infile
, d
->header_size
,
697 c
->infile
->len
-d
->header_size
);
703 de_dbg_indent_restore(c
, saved_indent_level
);
706 static void de_run_pcpaint_clp(deark
*c
, lctx
*d
, de_module_params
*mparams
)
711 int saved_indent_level
;
713 de_dbg_indent_save(c
, &saved_indent_level
);
715 de_declare_fmt(c
, "PCPaint CLP");
717 de_dbg(c
, "header at %d", 0);
720 file_size
= de_getu16le(0);
721 de_dbg(c
, "reported file size: %"I64_FMT
, file_size
);
722 if(file_size
!= c
->infile
->len
) {
723 if(file_size
==0x1234) {
724 de_warn(c
, "This is probably a .PIC file, not a CLIP file.");
727 de_warn(c
, "Reported file size (%"I64_FMT
") does not equal actual file size (%"I64_FMT
"). "
728 "Format may not be correct.", file_size
, c
->infile
->len
);
732 d
->npwidth
= de_getu16le(2);
733 d
->pdwidth
= d
->npwidth
; // default
734 d
->height
= de_getu16le(4);
735 de_dbg_dimensions(c
, d
->npwidth
, d
->height
);
737 d
->plane_info
= de_getbyte(10);
739 is_compressed
= (d
->plane_info
==0xff);
743 d
->plane_info
= de_getbyte(11);
748 de_dbg(c
, "compressed: %d", (int)is_compressed
);
749 de_dbg(c
, "plane info: 0x%02x", (int)d
->plane_info
);
751 de_dbg_indent(c
, -1);
753 // The colors probably won't be right, but we have no way to tell what palette
754 // is used by a CLP image.
756 d
->pal_info_mainfile
.edesc
= 0;
757 d
->pal_info_mainfile
.esize
= 0;
759 d
->pal_info_to_use
= &d
->pal_info_mainfile
; // tentative
760 if(!do_read_alt_palette_file(c
, d
)) goto done
;
762 de_dbg(c
, "image data at %"I64_FMT
, d
->header_size
);
764 if(!do_set_up_decoder(c
, d
)) goto done
;
767 run_marker
= de_getbyte(12);
768 de_dbg3(c
, "run marker: 0x%02x", (UI
)run_marker
);
770 de_dbg(c
, "decompressing image");
772 d
->unc_pixels
= dbuf_create_membuf(c
, 16384, 0);
773 dbuf_set_length_limit(d
->unc_pixels
, (d
->pdwidth
+7) * d
->height
);
775 if(!decompress_block(c
, d
, d
->header_size
,
776 c
->infile
->len
- d
->header_size
, run_marker
))
780 de_dbg_indent(c
, -1);
781 de_dbg(c
, "decompressed to %"I64_FMT
" bytes", d
->unc_pixels
->len
);
784 d
->unc_pixels
= dbuf_open_input_subfile(c
->infile
,
785 d
->header_size
, c
->infile
->len
-d
->header_size
);
791 de_dbg_indent_restore(c
, saved_indent_level
);
794 // Dispatch to either pcpaint_pic or pcpaint_clp.
795 static void de_run_pcpaint(deark
*c
, de_module_params
*mparams
)
797 // 0=unknown, 1=pic, 2=clp
798 const char *pcpaintfmt
;
802 d
= de_malloc(c
, sizeof(lctx
));
804 d
->input_encoding
= de_get_input_encoding(c
, NULL
, DE_ENCODING_CP437_G
);
806 pcpaintfmt
= de_get_ext_option(c
, "pcpaint:fmt");
808 if(!de_strcmp(pcpaintfmt
, "pic")) {
809 d
->file_fmt
= FMT_PIC
;
811 else if(!de_strcmp(pcpaintfmt
, "clp")) {
812 d
->file_fmt
= FMT_CLP
;
814 else if(!de_strcmp(pcpaintfmt
, "clip")) {
815 d
->file_fmt
= FMT_CLP
;
820 // File subtype not given by user. Try to detect it.
822 if(buf
[0]==0x34 && buf
[1]==0x12) {
823 if(c
->infile
->len
==0x1234) {
824 // Pathological case where both formats could start with 0x1234.
825 if(buf
[10]==0xff) { // definitely a compressed CLP
826 d
->file_fmt
= FMT_CLP
;
829 de_warn(c
, "Format can't be reliably identified. Try \"-opt pcpaint:fmt=clp\" if necessary.");
830 d
->file_fmt
= FMT_PIC
;
834 d
->file_fmt
= FMT_PIC
;
838 d
->file_fmt
= FMT_CLP
;
842 d
->opt_keep_invis_chars
= de_get_ext_option_bool(c
, "pcpaint:invistext", 0);
844 if(d
->file_fmt
==FMT_CLP
) {
845 de_run_pcpaint_clp(c
, d
, mparams
);
848 de_run_pcpaint_pic(c
, d
, mparams
);
851 if(d
->unc_pixels
) dbuf_close(d
->unc_pixels
);
852 de_finfo_destroy(c
, d
->fi
);
853 de_free(c
, d
->pal_info_mainfile
.data
);
854 de_free(c
, d
->pal_info_palfile
.data
);
858 static int de_identify_pcpaint(deark
*c
)
861 int pic_ext
, clp_ext
;
864 pic_ext
= de_input_file_has_ext(c
, "pic");
867 if(buf
[0]==0x34 && buf
[1]==0x12 && buf
[11]==0xff) {
868 return pic_ext
? 100 : 50;
871 clp_ext
= de_input_file_has_ext(c
, "clp");
873 x
= de_getu16le_direct(&buf
[0]);
874 if(x
==c
->infile
->len
) {
882 static void de_help_pcpaint(deark
*c
)
884 de_msg(c
, "-file2 <file.pic> : PIC file to read the palette from");
885 de_msg(c
, "-opt pcpaint:fmt=pic : Assume PIC format");
886 de_msg(c
, "-opt pcpaint:fmt=clp : Assume CLP format");
889 void de_module_pcpaint(deark
*c
, struct deark_module_info
*mi
)
892 mi
->desc
= "PCPaint PIC or CLP image";
893 mi
->run_fn
= de_run_pcpaint
;
894 mi
->identify_fn
= de_identify_pcpaint
;
895 mi
->help_fn
= de_help_pcpaint
;