1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Macintosh PICT graphics
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_pict
);
20 struct detection_info
{
25 typedef struct localctx_struct
{
26 struct detection_info dti
;
27 int version
; // 1 or 2: The version mode that the parser is currently using
30 dbuf
*iccprofile_file
;
33 typedef int (*item_decoder_fn
)(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
,
38 #define SZCODE_SPECIAL 0
39 #define SZCODE_EXACT 1
40 #define SZCODE_REGION 2
41 #define SZCODE_POLYGON 3
43 u32 size
; // Data size, not including opcode. Logic depends on size_code.
48 static double pict_read_fixed(dbuf
*f
, i64 pos
)
52 // I think QuickDraw's "Fixed point" numbers are signed, but I don't know
53 // how negative numbers are handled.
54 n
= dbuf_geti32be(f
, pos
);
55 return ((double)n
)/65536.0;
58 // Read a QuickDraw Point. Caller supplies point struct.
59 static void pict_read_point(dbuf
*f
, i64 pos
,
60 struct pict_point
*point
, const char *dbgname
)
62 point
->y
= dbuf_geti16be(f
, pos
);
63 point
->x
= dbuf_geti16be(f
, pos
+2);
66 de_dbg(f
->c
, "%s: (%d,%d)", dbgname
, (int)point
->x
, (int)point
->y
);
70 // Read a QuickDraw Rectangle. Caller supplies rect struct.
71 static void pict_read_rect(dbuf
*f
, i64 pos
,
72 struct pict_rect
*rect
, const char *dbgname
)
74 rect
->t
= dbuf_geti16be(f
, pos
);
75 rect
->l
= dbuf_geti16be(f
, pos
+2);
76 rect
->b
= dbuf_geti16be(f
, pos
+4);
77 rect
->r
= dbuf_geti16be(f
, pos
+6);
80 de_dbg(f
->c
, "%s: (%d,%d)-(%d,%d)", dbgname
, (int)rect
->l
, (int)rect
->t
,
81 (int)rect
->r
, (int)rect
->b
);
85 static int handler_RGBColor(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
87 unsigned int clr16
[3];
95 clr16
[k
] = (unsigned int)de_getu16be_p(&pos
);
96 clr8
[k
] = (u8
)(clr16
[k
]>>8);
98 clr
= DE_MAKE_RGB(clr8
[0], clr8
[1], clr8
[2]);
99 de_get_colorsample_code(c
, clr
, csamp
, sizeof(csamp
));
100 de_dbg(c
, "color: (0x%04x,0x%04x,0x%04x)%s", clr16
[0], clr16
[1], clr16
[2], csamp
);
105 static int handler_11(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
110 ver
= de_getbyte(data_pos
);
111 de_dbg(c
, "version: %d", (int)ver
);
117 de_err(c
, "Unsupported PICT version: %d", (int)ver
);
124 static int handler_28(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
127 de_ucstring
*s
= NULL
;
128 struct pict_point pt
;
130 pict_read_point(c
->infile
, data_pos
, &pt
, "txLoc");
131 tlen
= (i64
)de_getbyte(data_pos
+4);
132 s
= ucstring_create(c
);
133 dbuf_read_to_ucstring(c
->infile
, data_pos
+5, tlen
, s
, 0, DE_ENCODING_MACROMAN
);
134 de_dbg(c
, "text: \"%s\"", ucstring_getpsz(s
));
135 *bytes_used
= 5+tlen
;
141 static int handler_DxText(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
145 de_ucstring
*s
= NULL
;
147 dx
= (i64
)de_getbyte(data_pos
);
148 de_dbg(c
, "%s: %d", opcode
==0x2a?"dv":"dh", (int)dx
);
150 tlen
= (i64
)de_getbyte(data_pos
+1);
151 *bytes_used
= 2+tlen
;
153 s
= ucstring_create(c
);
154 dbuf_read_to_ucstring(c
->infile
, data_pos
+2, tlen
, s
, 0, DE_ENCODING_MACROMAN
);
155 de_dbg(c
, "text: \"%s\"", ucstring_getpsz(s
));
162 static int handler_2b(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
166 de_ucstring
*s
= NULL
;
168 dh
= (i64
)de_getbyte(data_pos
);
169 dv
= (i64
)de_getbyte(data_pos
+1);
170 de_dbg(c
, "dh,dv: (%d,%d)", (int)dh
, (int)dv
);
172 tlen
= (i64
)de_getbyte(data_pos
+2);
173 de_dbg(c
, "text size: %d", (int)tlen
);
174 *bytes_used
= 3+tlen
;
176 s
= ucstring_create(c
);
177 dbuf_read_to_ucstring(c
->infile
, data_pos
+3, tlen
, s
, 0, DE_ENCODING_MACROMAN
);
178 de_dbg(c
, "text: \"%s\"", ucstring_getpsz(s
));
184 static int handler_2c(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
189 de_ucstring
*s
= NULL
;
191 n
= de_getu16be(data_pos
);
193 id
= de_getu16be(data_pos
+2);
194 de_dbg(c
, "old font id: %d", (int)id
);
195 tlen
= (i64
)de_getbyte(data_pos
+4);
196 s
= ucstring_create(c
);
197 dbuf_read_to_ucstring(c
->infile
, data_pos
+5, tlen
, s
, 0, DE_ENCODING_MACROMAN
);
198 de_dbg(c
, "font name: \"%s\"", ucstring_getpsz(s
));
203 static int handler_Rectangle(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
205 struct pict_rect rect
;
207 pict_read_rect(c
->infile
, data_pos
, &rect
, "rect");
211 // final few bitmap header fields (18 bytes)
212 static void read_src_dst_mode(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
, i64 pos
)
214 struct pict_rect tmprect
;
217 de_dbg(c
, "src/dst/mode part of bitmap header, at %d", (int)pos
);
220 pict_read_rect(c
->infile
, pos
, &tmprect
, "srcRect");
222 pict_read_rect(c
->infile
, pos
, &tmprect
, "dstRect");
225 n
= de_getu16be(pos
);
226 de_dbg(c
, "transfer mode: %d", (int)n
);
228 de_dbg_indent(c
, -1);
231 // Pre-scan the pixel data to figure out its size.
232 // (We could instead scan and decode it at the same time, but error handling
233 // would get really messy.)
234 // Returns 0 on fatal error (if we could not even parse the data).
235 static int get_pixdata_size(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
,
236 i64 pos1
, i64
*pixdata_size
)
244 de_dbg(c
, "PixData at %d", (int)pos
);
247 if(bi
->height
<0 || bi
->height
>65535) {
248 de_err(c
, "Invalid bitmap height (%d)", (int)bi
->height
);
252 // Make sure rowbytes is sane. We use it to decide how much memory to allocate.
253 // Note: I've seen valid bitmaps with as many as 284 extra bytes per row.
254 if(bi
->rowbytes
> (bi
->npwidth
* bi
->pixelsize
)/8 + 1000) {
255 de_err(c
, "Bad rowBytes value (%d)", (int)bi
->rowbytes
);
259 if(bi
->packing_type
>=3 || (bi
->packing_type
==0 && bi
->rowbytes
>=8)) {
260 for(j
=0; j
<bi
->height
; j
++) {
261 if(bi
->rowbytes
> 250) {
262 bytecount
= de_getu16be(pos
);
266 bytecount
= (i64
)de_getbyte(pos
);
272 else if(bi
->packing_type
==1 || (bi
->packing_type
==0 && bi
->rowbytes
<8)) {
273 pos
+= bi
->rowbytes
* bi
->height
; // uncompressed
276 de_err(c
, "Unsupported packing type: %d", (int)bi
->packing_type
);
280 *pixdata_size
= pos
- pos1
;
281 de_dbg(c
, "PixData size: %d", (int)*pixdata_size
);
285 de_dbg_indent(c
, -1);
289 static void decode_bitmap_rgb24(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
,
290 dbuf
*unc_pixels
, de_bitmap
*img
, i64 pos
)
295 for(j
=0; j
<bi
->height
; j
++) {
296 for(i
=0; i
<bi
->pdwidth
; i
++) {
297 cr
= dbuf_getbyte(unc_pixels
, j
*bi
->rowspan
+ (bi
->cmpcount
-3+0)*bi
->pdwidth
+ i
);
298 cg
= dbuf_getbyte(unc_pixels
, j
*bi
->rowspan
+ (bi
->cmpcount
-3+1)*bi
->pdwidth
+ i
);
299 cb
= dbuf_getbyte(unc_pixels
, j
*bi
->rowspan
+ (bi
->cmpcount
-3+2)*bi
->pdwidth
+ i
);
300 de_bitmap_setpixel_rgb(img
, i
, j
, DE_MAKE_RGB(cr
,cg
,cb
));
305 static void decode_bitmap_rgb16(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
,
306 dbuf
*unc_pixels
, de_bitmap
*img
, i64 pos
)
312 for(j
=0; j
<bi
->height
; j
++) {
313 for(i
=0; i
<bi
->pdwidth
; i
++) {
314 c0
= dbuf_getbyte(unc_pixels
, j
*bi
->rowspan
+ i
*2);
315 c1
= dbuf_getbyte(unc_pixels
, j
*bi
->rowspan
+ i
*2+1);
316 clr
= ((u32
)c0
<< 8)|c1
;
317 clr
= de_rgb555_to_888(clr
);
318 de_bitmap_setpixel_rgb(img
, i
, j
, clr
);
323 static void decode_bitmap_paletted(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
,
324 dbuf
*unc_pixels
, de_bitmap
*img
, i64 pos
)
326 de_convert_image_paletted(unc_pixels
, 0, bi
->pixelsize
, bi
->rowspan
,
330 static int decode_bitmap(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
, i64 pos
)
333 dbuf
*unc_pixels
= NULL
;
334 de_bitmap
*img
= NULL
;
339 struct de_dfilter_in_params dcmpri
;
340 struct de_dfilter_out_params dcmpro
;
341 struct de_dfilter_results dres
;
343 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
345 bi
->rowspan
= bi
->rowbytes
;
346 if(bi
->pixelsize
==32 && bi
->cmpcount
==3 && bi
->cmpsize
==8) {
347 bi
->rowspan
= (bi
->rowbytes
/4)*3;
350 bitmapsize
= bi
->height
* bi
->rowspan
;
351 unc_pixels
= dbuf_create_membuf(c
, bitmapsize
, 1);
352 dbuf_enable_wbuffer(unc_pixels
);
354 dcmpri
.f
= c
->infile
;
355 dcmpro
.f
= unc_pixels
;
357 for(j
=0; j
<bi
->height
; j
++) {
358 if(bi
->packing_type
==1 || bi
->rowbytes
<8) {
359 bytecount
= bi
->rowbytes
;
361 else if(bi
->rowbytes
> 250) {
362 bytecount
= de_getu16be(pos
);
366 bytecount
= (i64
)de_getbyte(pos
);
370 if(bi
->packing_type
==1 || bi
->rowbytes
<8) {
371 dbuf_copy(c
->infile
, pos
, bytecount
, unc_pixels
);
373 else if(bi
->packing_type
==3 && bi
->pixelsize
==16) {
374 struct de_packbits_params pbparams
;
376 de_zeromem(&pbparams
, sizeof(struct de_packbits_params
));
377 pbparams
.nbytes_per_unit
= 2;
379 dcmpri
.len
= bytecount
;
380 fmtutil_decompress_packbits_ex(c
, &dcmpri
, &dcmpro
, &dres
, &pbparams
);
384 dcmpri
.len
= bytecount
;
385 fmtutil_decompress_packbits_ex(c
, &dcmpri
, &dcmpro
, &dres
, NULL
);
388 // Make sure the data decompressed to the right number of bytes.
389 if(dbuf_get_length(unc_pixels
) != (j
+1)*bi
->rowspan
) {
390 dbuf_truncate(unc_pixels
, (j
+1)*bi
->rowspan
);
395 dbuf_flush(unc_pixels
);
399 if(de_is_grayscale_palette(bi
->pal
, bi
->num_pal_entries
)) {
404 img
= de_bitmap_create2(c
, bi
->npwidth
, bi
->pdwidth
, bi
->height
, dst_nsamples
);
406 fi
= de_finfo_create(c
);
408 if(bi
->hdpi
>=1.0 && bi
->vdpi
>=1.0) {
409 fi
->density
.code
= DE_DENSITY_DPI
;
410 fi
->density
.xdens
= bi
->hdpi
;
411 fi
->density
.ydens
= bi
->vdpi
;
415 decode_bitmap_paletted(c
, d
, bi
, unc_pixels
, img
, pos
);
418 if(bi
->pixelsize
==16) {
419 decode_bitmap_rgb16(c
, d
, bi
, unc_pixels
, img
, pos
);
422 decode_bitmap_rgb24(c
, d
, bi
, unc_pixels
, img
, pos
);
426 de_bitmap_write_to_file_finfo(img
, fi
, DE_CREATEFLAG_OPT_IMAGE
);
428 de_bitmap_destroy(img
);
429 de_finfo_destroy(c
, fi
);
430 dbuf_close(unc_pixels
);
434 static int decode_pixdata(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
, i64 pos
)
440 if(bi
->npwidth
==0 || bi
->height
==0) {
441 de_warn(c
, "Ignoring zero-size bitmap (%d"DE_CHAR_TIMES
"%d)",
442 (int)bi
->npwidth
, (int)bi
->height
);
445 if(!de_good_image_dimensions(c
, bi
->npwidth
, bi
->height
)) goto done
;
447 if(bi
->pixelsize
!=1 && bi
->pixelsize
!=2 && bi
->pixelsize
!=4 && bi
->pixelsize
!=8 &&
448 bi
->pixelsize
!=16 && bi
->pixelsize
!=24 && bi
->pixelsize
!=32)
450 de_err(c
, "%d bits/pixel images are not supported", (int)bi
->pixelsize
);
453 if((bi
->uses_pal
&& bi
->pixeltype
!=0) || (!bi
->uses_pal
&& bi
->pixeltype
!=16)) {
454 de_err(c
, "Pixel type %d is not supported", (int)bi
->pixeltype
);
457 if(bi
->cmpcount
!=1 && bi
->cmpcount
!=3 && bi
->cmpcount
!=4) {
458 de_err(c
, "Component count %d is not supported", (int)bi
->cmpcount
);
461 if(bi
->cmpsize
!=1 && bi
->cmpsize
!=2 && bi
->cmpsize
!=4 && bi
->cmpsize
!=5 &&
464 de_err(c
, "%d-bit components are not supported", (int)bi
->cmpsize
);
467 if(bi
->packing_type
!=0 && bi
->packing_type
!=1 && bi
->packing_type
!=3 && bi
->packing_type
!=4) {
468 de_err(c
, "Packing type %d is not supported", (int)bi
->packing_type
);
472 (bi
->packing_type
==0 || bi
->packing_type
==1) &&
473 (bi
->pixelsize
==1 || bi
->pixelsize
==2 || bi
->pixelsize
==4 || bi
->pixelsize
==8) &&
474 bi
->cmpcount
==1 && bi
->cmpsize
==bi
->pixelsize
) ||
475 (!bi
->uses_pal
&& (bi
->packing_type
==1 || bi
->packing_type
==3) && bi
->pixelsize
==16
476 && bi
->cmpcount
==3 && bi
->cmpsize
==5) ||
477 (!bi
->uses_pal
&& bi
->packing_type
==1 && bi
->pixelsize
==16 && bi
->cmpcount
==3 && bi
->cmpsize
==5) ||
478 (!bi
->uses_pal
&& bi
->packing_type
==4 && bi
->pixelsize
==32 && bi
->cmpcount
==3 && bi
->cmpsize
==8) ||
479 (!bi
->uses_pal
&& bi
->packing_type
==4 && bi
->pixelsize
==32 && bi
->cmpcount
==4 && bi
->cmpsize
==8))
484 de_err(c
, "This type of image is not supported");
488 if(bi
->cmpcount
==4) {
489 de_warn(c
, "This image might have transparency, which is not supported.");
492 decode_bitmap(c
, d
, bi
, pos
);
495 de_dbg_indent(c
, -1);
499 // For opcodes 0x90, 0x91, 0x98, 0x99, 0x9a, 0x9b
500 static int handler_98_9a(deark
*c
, lctx
*d
, i64 opcode
, i64 pos1
, i64
*bytes_used
)
502 struct fmtutil_macbitmap_info
*bi
= NULL
;
503 i64 pixdata_size
= 0;
504 i64 colortable_size
= 0;
508 bi
= de_malloc(c
, sizeof(struct fmtutil_macbitmap_info
));
511 if(opcode
==0x9a || opcode
==0x9b) {
512 fmtutil_macbitmap_read_baseaddr(c
, c
->infile
, bi
, pos
);
516 fmtutil_macbitmap_read_rowbytes_and_bounds(c
, c
->infile
, bi
, pos
);
519 if(bi
->pixmap_flag
) {
520 fmtutil_macbitmap_read_pixmap_only_fields(c
, c
->infile
, bi
, pos
);
524 if((opcode
==0x90 || opcode
==0x91 || opcode
==0x98 || opcode
==0x99) && bi
->pixmap_flag
) {
525 // Prepare to read the palette
527 bi
->has_colortable
= 1;
529 else if((opcode
==0x90 || opcode
==0x91 || opcode
==0x98 || opcode
==0x99) && !bi
->pixmap_flag
) {
530 // Settings implied by the lack of a PixMap header
535 bi
->num_pal_entries
= 2;
536 bi
->pal
[0] = DE_STOCKCOLOR_WHITE
;
537 bi
->pal
[1] = DE_STOCKCOLOR_BLACK
;
539 else if((opcode
==0x9a || opcode
==0x9b) && !bi
->pixmap_flag
) {
540 de_err(c
, "DirectBitsRect image without PixMap flag is not supported");
544 if(bi
->has_colortable
) {
545 if(!fmtutil_macbitmap_read_colortable(c
, c
->infile
, bi
, pos
, &colortable_size
)) goto done
;
546 pos
+= colortable_size
;
549 read_src_dst_mode(c
, d
, bi
, pos
);
552 if(opcode
==0x91 || opcode
==0x99 || opcode
==0x9b) {
555 de_dbg(c
, "region at %"I64_FMT
, pos
);
557 rgnsize
= de_getu16be(pos
);
558 de_dbg(c
, "region size: %d", (int)rgnsize
);
559 de_dbg_indent(c
, -1);
560 if(rgnsize
<2) goto done
;
563 de_info(c
, "Note: Ignoring clipping region. Output image might have "
564 "extraneous pixels.");
568 if(!get_pixdata_size(c
, d
, bi
, pos
, &pixdata_size
)) {
571 decode_pixdata(c
, d
, bi
, pos
);
574 *bytes_used
= pos
- pos1
;
583 static int handler_pixpat(deark
*c
, lctx
*d
, i64 opcode
, i64 pos1
, i64
*bytes_used
)
585 unsigned int pattype
;
589 i64 colortable_size
= 0;
590 i64 pixdata_size
= 0;
591 struct fmtutil_macbitmap_info
*bi
= NULL
;
593 pattype
= (unsigned int)de_getu16be_p(&pos
);
594 de_dbg(c
, "PatType: %u", pattype
);
595 pos
+= 8; // Pat1Data
597 if(pattype
==2) { // ditherPat(?)
603 bi
= de_malloc(c
, sizeof(struct fmtutil_macbitmap_info
));
605 fmtutil_macbitmap_read_rowbytes_and_bounds(c
, c
->infile
, bi
, pos
);
607 fmtutil_macbitmap_read_pixmap_only_fields(c
, c
->infile
, bi
, pos
);
611 if(!fmtutil_macbitmap_read_colortable(c
, c
->infile
, bi
, pos
, &colortable_size
)) goto done
;
612 pos
+= colortable_size
;
614 if(!get_pixdata_size(c
, d
, bi
, pos
, &pixdata_size
)) {
617 // Note: We could extract the "PixMap" pattern easily enough here, by calling
618 // decode_pixdata(). But if we do that, maybe we should also extract the
619 // Pat1Data data above, as well as other opcodes like BkPat.
624 if(!retval
&& needmsg
) {
625 de_err(c
, "Failed to parse PixPat data");
628 *bytes_used
= pos
- pos1
;
634 static void do_iccprofile_item(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
640 selector
= de_getu32be(pos
);
642 de_dbg(c
, "ICC profile segment, selector=%d, data len=%d", (int)selector
,
646 // If this is not a Continuation segment, close any current file.
647 dbuf_close(d
->iccprofile_file
);
648 d
->iccprofile_file
= NULL
;
651 if(selector
==0) { // Beginning segment
652 d
->iccprofile_file
= dbuf_create_output_file(c
, "icc", NULL
, DE_CREATEFLAG_IS_AUX
);
655 if(selector
==0 || selector
==1) {
656 // Beginning and Continuation segments normally have profile data.
657 // End segments (selector==2) are not allowed to include data.
659 if(!d
->iccprofile_file
) {
660 de_warn(c
, "Bad ICC profile segment");
663 dbuf_copy(c
->infile
, pos
+4, data_len
, d
->iccprofile_file
);
668 static int handler_a0(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
671 kind
= de_getu16be(data_pos
);
672 de_dbg(c
, "comment kind: %d", (int)kind
);
677 static int handler_a1(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
682 kind
= de_getu16be(data_pos
);
683 len
= de_getu16be(data_pos
+2);
684 de_dbg(c
, "comment kind: %d, size: %d", (int)kind
, (int)len
);
687 if(kind
==100 && len
>=4) {
688 struct de_fourcc sig4cc
;
690 dbuf_read_fourcc(c
->infile
, data_pos
+4, &sig4cc
, 4, 0x0);
691 de_dbg(c
, "application comment, signature=0x%08x '%s'",
692 (unsigned int)sig4cc
.id
, sig4cc
.id_dbgstr
);
693 de_dbg_hexdump(c
, c
->infile
, data_pos
+8, len
-4, 256, NULL
, 0x1);
696 do_iccprofile_item(c
, d
, data_pos
+4, len
);
699 de_dbg_hexdump(c
, c
->infile
, data_pos
+4, len
, 256, NULL
, 0x1);
706 static int handler_0c00(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
710 struct pict_rect srcrect
;
712 hdrver
= de_getu16be(data_pos
);
713 d
->is_extended_v2
= (hdrver
==0xfffe);
715 de_dbg(c
, "extended v2: %s", d
->is_extended_v2
?"yes":"no");
716 if(d
->is_extended_v2
) {
717 hres
= pict_read_fixed(c
->infile
, data_pos
+4);
718 vres
= pict_read_fixed(c
->infile
, data_pos
+8);
719 de_dbg(c
, "dpi: %.2f"DE_CHAR_TIMES
"%.2f", hres
, vres
);
720 pict_read_rect(c
->infile
, data_pos
+12, &srcrect
, "srcRect");
726 // Returns 1 if image decoding was successful,
727 // 0 if (e.g.) unsupported compression type.
728 static int do_decode_qt(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
730 de_module_params
*mparams
= NULL
;
733 mparams
= de_malloc(c
, sizeof(de_module_params
));
734 mparams
->in_params
.codes
= "I";
735 mparams
->in_params
.flags
|= 0x01;
737 de_run_module_by_id_on_slice(c
, "qtif", mparams
, c
->infile
, pos
, len
);
738 if(mparams
->out_params
.flags
& 0x1) {
746 static void do_handle_qtif_idsc(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
748 i64 idsc_dpos
, idsc_dlen
;
749 i64 idat_dpos
, idat_dlen
;
751 struct de_fourcc cmpr4cc
;
754 if(do_decode_qt(c
, d
, pos
, len
)) {
757 de_dbg(c
, "[failed to decode QuickTime image, extracting to .qtif instead]");
760 // Try to construct a .qtif file.
761 // This way, we do something potentially useful even if the image has
762 // a compression scheme that our qtif module doesn't support.
765 idsc_dlen
= de_getu32be(idsc_dpos
);
766 de_dbg(c
, "idsc: pos=%"I64_FMT
", len=%"I64_FMT
, idsc_dpos
, idsc_dlen
);
767 if(idsc_dpos
+idsc_dlen
> pos
+len
) goto done
;
769 dbuf_read_fourcc(c
->infile
, idsc_dpos
+4, &cmpr4cc
, 4, 0x0);
770 de_dbg(c
, "compression type: \"%s\"", cmpr4cc
.id_dbgstr
);
772 idat_dpos
= idsc_dpos
+ idsc_dlen
;
773 idat_dlen
= de_getu32be(idsc_dpos
+44);
774 de_dbg(c
, "idat: pos=%"I64_FMT
", len=%"I64_FMT
, idat_dpos
, idat_dlen
);
776 idat_dlen
= pos
+len
-idat_dpos
; // ??
778 if(idat_dpos
+idat_dlen
> pos
+len
) goto done
;
780 #define CODE_idat 0x69646174U
781 #define CODE_idsc 0x69647363U
782 outf
= dbuf_create_output_file(c
, "qtif", NULL
, 0);
784 dbuf_writeu32be(outf
, 8+idsc_dlen
);
785 dbuf_writeu32be(outf
, CODE_idsc
);
786 dbuf_copy(c
->infile
, idsc_dpos
, idsc_dlen
, outf
);
788 dbuf_writeu32be(outf
, 8+idat_dlen
);
789 dbuf_writeu32be(outf
, CODE_idat
);
790 dbuf_copy(c
->infile
, idat_dpos
, idat_dlen
, outf
);
796 // CompressedQuickTime (0x8200) & UncompressedQuickTime (0x8201)
797 static int handler_QuickTime(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
804 payload_len
= de_getu32be(data_pos
);
805 payload_pos
= data_pos
+4;
806 de_dbg(c
, "payload: pos=%"I64_FMT
", len=%"I64_FMT
, payload_pos
, payload_len
);
807 endpos
= payload_pos
+payload_len
;
808 if(endpos
> c
->infile
->len
) return 0;
809 *bytes_used
= 4+payload_len
;
811 // Following the size field seems to be 68 or 50 bytes of data,
812 // followed by QuickTime "idsc" data, followed by image data.
813 idsc_pos
= payload_pos
+ ((opcode
==0x8201) ? 50 : 68);
815 do_handle_qtif_idsc(c
, d
, idsc_pos
, endpos
-idsc_pos
);
819 static const struct opcode_info opcode_info_arr
[] = {
820 // TODO: This list might not be complete, and it needs to be complete in
821 // order to parse all PICT files.
822 // Note that some opcode ranges are handled in do_handle_item().
823 { 0x0000, SZCODE_EXACT
, 0, "NOP", NULL
},
824 { 0x0001, SZCODE_REGION
, 0, "Clip", NULL
},
825 { 0x0002, SZCODE_EXACT
, 8, "BkPat", NULL
},
826 { 0x0003, SZCODE_EXACT
, 2, "TxFont", NULL
},
827 { 0x0004, SZCODE_EXACT
, 1, "TxFace", NULL
},
828 { 0x0005, SZCODE_EXACT
, 2, "TxMode", NULL
},
829 { 0x0006, SZCODE_EXACT
, 4, "SpExtra", NULL
},
830 { 0x0007, SZCODE_EXACT
, 4, "PnSize", NULL
},
831 { 0x0008, SZCODE_EXACT
, 2, "PnMode", NULL
},
832 { 0x0009, SZCODE_EXACT
, 8, "PnPat", NULL
},
833 { 0x000a, SZCODE_EXACT
, 8, "FillPat", NULL
},
834 { 0x000b, SZCODE_EXACT
, 4, "OvSize", NULL
},
835 { 0x000c, SZCODE_EXACT
, 4, "Origin", NULL
},
836 { 0x000d, SZCODE_EXACT
, 2, "TxSize", NULL
},
837 { 0x000e, SZCODE_EXACT
, 4, "FgColor", NULL
},
838 { 0x000f, SZCODE_EXACT
, 4, "BkColor", NULL
},
839 { 0x0010, SZCODE_EXACT
, 8, "TxRatio", NULL
},
840 { 0x0011, SZCODE_EXACT
, 1, "Version", handler_11
},
841 { 0x0012, SZCODE_SPECIAL
, 0, "BkPixPat", handler_pixpat
},
842 { 0x0013, SZCODE_SPECIAL
, 0, "PnPixPat", handler_pixpat
},
843 { 0x0014, SZCODE_SPECIAL
, 0, "FillPixPat", handler_pixpat
},
844 { 0x0015, SZCODE_EXACT
, 2, "PnLocHFrac", NULL
},
845 { 0x0016, SZCODE_EXACT
, 2, "ChExtra", NULL
},
846 { 0x001a, SZCODE_EXACT
, 6, "RGBFgCol", handler_RGBColor
},
847 { 0x001b, SZCODE_EXACT
, 6, "RGBBkCol", handler_RGBColor
},
848 { 0x001c, SZCODE_EXACT
, 0, "HiliteMode", NULL
},
849 { 0x001d, SZCODE_EXACT
, 6, "HiliteColor", handler_RGBColor
},
850 { 0x001e, SZCODE_EXACT
, 0, "DefHilite", NULL
},
851 { 0x001f, SZCODE_EXACT
, 6, "OpColor", handler_RGBColor
},
852 { 0x0020, SZCODE_EXACT
, 8, "Line", NULL
},
853 { 0x0021, SZCODE_EXACT
, 4, "LineFrom", NULL
},
854 { 0x0022, SZCODE_EXACT
, 6, "ShortLine", NULL
},
855 { 0x0023, SZCODE_EXACT
, 2, "ShortLineFrom", NULL
},
856 { 0x0028, SZCODE_SPECIAL
, 0, "LongText", handler_28
},
857 { 0x0029, SZCODE_SPECIAL
, 0, "DHText", handler_DxText
},
858 { 0x002a, SZCODE_SPECIAL
, 0, "DVText", handler_DxText
},
859 { 0x002b, SZCODE_SPECIAL
, 0, "DHDVText", handler_2b
},
860 { 0x002c, SZCODE_SPECIAL
, 0, "fontName", handler_2c
},
861 { 0x002d, SZCODE_SPECIAL
, 0, "lineJustify", NULL
},
862 { 0x002e, SZCODE_SPECIAL
, 0, "glyphState", NULL
},
863 { 0x0030, SZCODE_EXACT
, 8, "frameRect", handler_Rectangle
},
864 { 0x0031, SZCODE_EXACT
, 8, "paintRect", handler_Rectangle
},
865 { 0x0032, SZCODE_EXACT
, 8, "eraseRect", handler_Rectangle
},
866 { 0x0033, SZCODE_EXACT
, 8, "invertRect", handler_Rectangle
},
867 { 0x0034, SZCODE_EXACT
, 8, "fillRect", handler_Rectangle
},
868 { 0x0038, SZCODE_EXACT
, 0, "frameSameRect", NULL
},
869 { 0x0039, SZCODE_EXACT
, 0, "paintSameRect", NULL
},
870 { 0x003a, SZCODE_EXACT
, 0, "eraseSameRect", NULL
},
871 { 0x003b, SZCODE_EXACT
, 0, "invertSameRect", NULL
},
872 { 0x003c, SZCODE_EXACT
, 0, "fillSameRect", NULL
},
873 { 0x0040, SZCODE_EXACT
, 8, "frameRRect", handler_Rectangle
},
874 { 0x0041, SZCODE_EXACT
, 8, "paintRRect", handler_Rectangle
},
875 { 0x0042, SZCODE_EXACT
, 8, "eraseRRect", handler_Rectangle
},
876 { 0x0043, SZCODE_EXACT
, 8, "invertRRect", handler_Rectangle
},
877 { 0x0044, SZCODE_EXACT
, 8, "fillRRect", handler_Rectangle
},
878 { 0x0048, SZCODE_EXACT
, 0, "frameSameRRect", NULL
},
879 { 0x0049, SZCODE_EXACT
, 0, "paintSameRRect", NULL
},
880 { 0x004a, SZCODE_EXACT
, 0, "eraseSameRRect", NULL
},
881 { 0x004b, SZCODE_EXACT
, 0, "invertSameRRect", NULL
},
882 { 0x004c, SZCODE_EXACT
, 0, "fillSameRRect", NULL
},
883 { 0x0050, SZCODE_EXACT
, 8, "frameOval", handler_Rectangle
},
884 { 0x0051, SZCODE_EXACT
, 8, "paintOval", handler_Rectangle
},
885 { 0x0052, SZCODE_EXACT
, 8, "eraseOval", handler_Rectangle
},
886 { 0x0053, SZCODE_EXACT
, 8, "invertOval", handler_Rectangle
},
887 { 0x0054, SZCODE_EXACT
, 8, "fillOval", handler_Rectangle
},
888 { 0x0058, SZCODE_EXACT
, 0, "frameSameOval", NULL
},
889 { 0x0059, SZCODE_EXACT
, 0, "paintSameOval", NULL
},
890 { 0x005a, SZCODE_EXACT
, 0, "eraseSameOval", NULL
},
891 { 0x005b, SZCODE_EXACT
, 0, "invertSameOval", NULL
},
892 { 0x005c, SZCODE_EXACT
, 0, "fillSameOval", NULL
},
893 { 0x0060, SZCODE_EXACT
, 12, "frameArc", NULL
},
894 { 0x0061, SZCODE_EXACT
, 12, "paintArc", NULL
},
895 { 0x0062, SZCODE_EXACT
, 12, "eraseArc", NULL
},
896 { 0x0063, SZCODE_EXACT
, 12, "invertArc", NULL
},
897 { 0x0064, SZCODE_EXACT
, 12, "fillArc", NULL
},
898 { 0x0068, SZCODE_EXACT
, 4, "frameSameArc", NULL
},
899 { 0x0069, SZCODE_EXACT
, 4, "paintSameArc", NULL
},
900 { 0x006a, SZCODE_EXACT
, 4, "eraseSameArc", NULL
},
901 { 0x006b, SZCODE_EXACT
, 4, "invertSameArc", NULL
},
902 { 0x006c, SZCODE_EXACT
, 4, "fillSameArc", NULL
},
903 { 0x0080, SZCODE_REGION
, 0, "frameRgn", NULL
},
904 { 0x0081, SZCODE_REGION
, 0, "paintRgn", NULL
},
905 { 0x0082, SZCODE_REGION
, 0, "eraseRgn", NULL
},
906 { 0x0083, SZCODE_REGION
, 0, "invertRgn", NULL
},
907 { 0x0084, SZCODE_REGION
, 0, "fillRgn", NULL
},
908 { 0x0070, SZCODE_POLYGON
, 0, "framePoly", NULL
},
909 { 0x0071, SZCODE_POLYGON
, 0, "paintPoly", NULL
},
910 { 0x0072, SZCODE_POLYGON
, 0, "erasePoly", NULL
},
911 { 0x0073, SZCODE_POLYGON
, 0, "invertPoly", NULL
},
912 { 0x0074, SZCODE_POLYGON
, 0, "fillPoly", NULL
},
913 { 0x0090, SZCODE_SPECIAL
, 0, "BitsRect", handler_98_9a
},
914 { 0x0091, SZCODE_SPECIAL
, 0, "BitsRgn", handler_98_9a
},
915 { 0x0098, SZCODE_SPECIAL
, 0, "PackBitsRect", handler_98_9a
},
916 { 0x0099, SZCODE_SPECIAL
, 0, "PackBitsRgn", handler_98_9a
},
917 { 0x009a, SZCODE_SPECIAL
, 0, "DirectBitsRect", handler_98_9a
},
918 { 0x009b, SZCODE_SPECIAL
, 0, "DirectBitsRgn", handler_98_9a
},
919 { 0x00a0, SZCODE_EXACT
, 2, "ShortComment", handler_a0
},
920 { 0x00a1, SZCODE_SPECIAL
, 0, "LongComment", handler_a1
},
921 { 0x00ff, SZCODE_EXACT
, 2, "opEndPic", NULL
},
922 { 0x0c00, SZCODE_EXACT
, 24, "HeaderOp", handler_0c00
},
923 { 0x8200, SZCODE_SPECIAL
, 0, "CompressedQuickTime", handler_QuickTime
},
924 { 0x8201, SZCODE_SPECIAL
, 0, "UncompressedQuickTime", handler_QuickTime
}
927 static const struct opcode_info
*find_opcode_info(i64 opcode
)
931 for(i
=0; i
<DE_ARRAYCOUNT(opcode_info_arr
); i
++) {
932 if(opcode_info_arr
[i
].opcode
== opcode
) {
933 return &opcode_info_arr
[i
];
939 static int do_handle_item(deark
*c
, lctx
*d
, i64 opcode_pos
, i64 opcode
,
940 i64 data_pos
, i64
*data_bytes_used
)
942 const char *opcode_name
;
943 const struct opcode_info
*opi
;
945 struct pict_rect tmprect
;
948 *data_bytes_used
= 0;
950 opi
= find_opcode_info(opcode
);
951 if(opi
&& opi
->name
) opcode_name
= opi
->name
;
952 else opcode_name
= "?";
955 de_dbg(c
, "opcode 0x%04x (%s) at %d", (unsigned int)opcode
, opcode_name
, (int)opcode_pos
);
957 de_dbg(c
, "opcode 0x%02x (%s) at %d", (unsigned int)opcode
, opcode_name
, (int)opcode_pos
);
961 *data_bytes_used
= opi
->size
; // Default to the size in the table.
962 ret
= opi
->fn(c
, d
, opcode
, data_pos
, data_bytes_used
);
963 de_dbg_indent(c
, -1);
965 else if(opi
&& opi
->size_code
==SZCODE_EXACT
) {
966 *data_bytes_used
= opi
->size
;
969 else if(opi
&& opi
->size_code
==SZCODE_REGION
) {
970 n
= de_getu16be(data_pos
);
972 de_dbg(c
, "region size: %d", (int)n
);
974 pict_read_rect(c
->infile
, data_pos
+2, &tmprect
, "rect");
976 de_dbg_indent(c
, -1);
977 *data_bytes_used
= n
;
980 else if(opi
&& opi
->size_code
==SZCODE_POLYGON
) {
981 n
= de_getu16be(data_pos
);
983 de_dbg(c
, "polygon size: %d", (int)n
);
984 de_dbg_indent(c
, -1);
985 *data_bytes_used
= n
;
988 else if(opcode
>=0x2c && opcode
<=0x2f) {
989 // Starts with 2-byte size, size does not include the "size" field.
990 n
= de_getu16be(data_pos
);
991 *data_bytes_used
= 2+n
;
994 else if(opcode
>=0x8100 && opcode
<=0xffff) {
995 // Starts with 4-byte size, size does not include the "size" field.
996 n
= de_getu32be(data_pos
);
997 *data_bytes_used
= 4+n
;
1001 de_err(c
, "Unsupported opcode: 0x%04x", (unsigned int)opcode
);
1007 static void do_read_items(deark
*c
, lctx
*d
, i64 pos
)
1015 if(pos
%2 && d
->version
==2) {
1016 pos
++; // 2-byte alignment
1019 if(pos
>= c
->infile
->len
) break;
1024 opcode
= de_getu16be(pos
);
1028 opcode
= (i64
)de_getbyte(pos
);
1032 ret
= do_handle_item(c
, d
, opcode_pos
, opcode
, pos
, &bytes_used
);
1034 if(opcode
==0x00ff) goto done
; // End of image
1042 // mode: 0=called from de_identify..., 1=called from de_run...
1043 static void do_detect_version(deark
*c
, struct detection_info
*dti
, int mode
)
1045 static const u8 v1pattern
[2] = { 0x11, 0x01 };
1046 static const u8 v2pattern
[6] = { 0x00, 0x11, 0x02, 0xff, 0x0c, 0x00 };
1053 dti
->file_version
= 0;
1054 dti
->has_fileheader
= 0;
1056 de_read(buf
, 522, sizeof(buf
));
1057 if(!de_memcmp(buf
, v2pattern
, 6)) {
1060 else if(!de_memcmp(buf
, v1pattern
, 2)) {
1064 de_read(buf
, 10, sizeof(buf
));
1065 if(!de_memcmp(buf
, v2pattern
, 6)) {
1068 else if(!de_memcmp(buf
, v1pattern
, 2)) {
1073 if(!v1_hdr
&& !v2_hdr
&& !v1_nohdr
&& !v2_nohdr
) {
1078 dti
->file_version
= 2;
1079 dti
->has_fileheader
= 1;
1083 dti
->file_version
= 2;
1088 // For v1, check that the file ends as expected
1089 de_read(buf
, c
->infile
->len
-2, 2);
1091 ; // v1 files should end with 0xff
1093 else if(buf
[0]==0xff && buf
[1]==0x00) {
1094 ; // But a few have an extra NUL byte at the end
1099 dti
->file_version
= 1;
1100 dti
->has_fileheader
= 1;
1104 dti
->file_version
= 1;
1109 static void de_run_pict(deark
*c
, de_module_params
*mparams
)
1114 struct pict_rect framerect
;
1116 d
= de_malloc(c
, sizeof(lctx
));
1118 d
->decode_qt
= de_get_ext_option_bool(c
, "pict:decodeqt", 0);
1120 do_detect_version(c
, &d
->dti
, 1);
1121 if(d
->dti
.file_version
>0) {
1122 de_declare_fmtf(c
, "PICT v%d%s", d
->dti
.file_version
,
1123 d
->dti
.has_fileheader
?"":", without file header");
1128 if(d
->dti
.has_fileheader
) {
1132 picsize
= de_getu16be(pos
);
1133 de_dbg(c
, "picSize: %d", (int)picsize
);
1135 pict_read_rect(c
->infile
, pos
, &framerect
, "picFrame");
1138 do_read_items(c
, d
, pos
);
1140 dbuf_close(d
->iccprofile_file
);
1144 static int de_identify_pict(deark
*c
)
1146 struct detection_info dti
;
1148 do_detect_version(c
, &dti
, 0);
1149 if(dti
.file_version
==2) {
1152 else if(dti
.file_version
==1) {
1153 if(dti
.has_fileheader
) return 25;
1159 static void de_help_pict(deark
*c
)
1161 de_msg(c
, "-opt pict:decodeqt : Try to decode QuickTime images directly");
1164 void de_module_pict(deark
*c
, struct deark_module_info
*mi
)
1167 mi
->desc
= "Macintosh PICT";
1168 mi
->run_fn
= de_run_pict
;
1169 mi
->identify_fn
= de_identify_pict
;
1170 mi
->help_fn
= de_help_pict
;