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
)
309 u8 c0
, c1
; //, cg, cb;
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
)
330 for(j
=0; j
<bi
->height
; j
++) {
331 for(i
=0; i
<bi
->pdwidth
; i
++) {
332 b
= de_get_bits_symbol(unc_pixels
, bi
->pixelsize
, j
*bi
->rowspan
, i
);
333 clr
= bi
->pal
[(unsigned int)b
];
334 de_bitmap_setpixel_rgb(img
, i
, j
, clr
);
339 static int decode_bitmap(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
, i64 pos
)
342 dbuf
*unc_pixels
= NULL
;
343 de_bitmap
*img
= NULL
;
348 struct de_dfilter_in_params dcmpri
;
349 struct de_dfilter_out_params dcmpro
;
350 struct de_dfilter_results dres
;
352 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
354 bi
->rowspan
= bi
->rowbytes
;
355 if(bi
->pixelsize
==32 && bi
->cmpcount
==3 && bi
->cmpsize
==8) {
356 bi
->rowspan
= (bi
->rowbytes
/4)*3;
359 bitmapsize
= bi
->height
* bi
->rowspan
;
360 unc_pixels
= dbuf_create_membuf(c
, bitmapsize
, 1);
362 dcmpri
.f
= c
->infile
;
363 dcmpro
.f
= unc_pixels
;
365 for(j
=0; j
<bi
->height
; j
++) {
366 if(bi
->packing_type
==1 || bi
->rowbytes
<8) {
367 bytecount
= bi
->rowbytes
;
369 else if(bi
->rowbytes
> 250) {
370 bytecount
= de_getu16be(pos
);
374 bytecount
= (i64
)de_getbyte(pos
);
378 if(bi
->packing_type
==1 || bi
->rowbytes
<8) {
379 dbuf_copy(c
->infile
, pos
, bytecount
, unc_pixels
);
381 else if(bi
->packing_type
==3 && bi
->pixelsize
==16) {
382 struct de_packbits_params pbparams
;
384 de_zeromem(&pbparams
, sizeof(struct de_packbits_params
));
385 pbparams
.is_packbits16
= 1;
387 dcmpri
.len
= bytecount
;
388 fmtutil_decompress_packbits_ex(c
, &dcmpri
, &dcmpro
, &dres
, &pbparams
);
392 dcmpri
.len
= bytecount
;
393 fmtutil_decompress_packbits_ex(c
, &dcmpri
, &dcmpro
, &dres
, NULL
);
396 // Make sure the data decompressed to the right number of bytes.
397 if(unc_pixels
->len
!= (j
+1)*bi
->rowspan
) {
398 dbuf_truncate(unc_pixels
, (j
+1)*bi
->rowspan
);
406 if(de_is_grayscale_palette(bi
->pal
, bi
->num_pal_entries
)) {
411 img
= de_bitmap_create2(c
, bi
->npwidth
, bi
->pdwidth
, bi
->height
, dst_nsamples
);
413 fi
= de_finfo_create(c
);
415 if(bi
->hdpi
>=1.0 && bi
->vdpi
>=1.0) {
416 fi
->density
.code
= DE_DENSITY_DPI
;
417 fi
->density
.xdens
= bi
->hdpi
;
418 fi
->density
.ydens
= bi
->vdpi
;
422 decode_bitmap_paletted(c
, d
, bi
, unc_pixels
, img
, pos
);
425 if(bi
->pixelsize
==16) {
426 decode_bitmap_rgb16(c
, d
, bi
, unc_pixels
, img
, pos
);
429 decode_bitmap_rgb24(c
, d
, bi
, unc_pixels
, img
, pos
);
433 de_bitmap_write_to_file_finfo(img
, fi
, 0);
435 de_bitmap_destroy(img
);
436 de_finfo_destroy(c
, fi
);
437 dbuf_close(unc_pixels
);
441 static int decode_pixdata(deark
*c
, lctx
*d
, struct fmtutil_macbitmap_info
*bi
, i64 pos
)
447 if(bi
->npwidth
==0 || bi
->height
==0) {
448 de_warn(c
, "Ignoring zero-size bitmap (%d"DE_CHAR_TIMES
"%d)",
449 (int)bi
->npwidth
, (int)bi
->height
);
452 if(!de_good_image_dimensions(c
, bi
->npwidth
, bi
->height
)) goto done
;
454 if(bi
->pixelsize
!=1 && bi
->pixelsize
!=2 && bi
->pixelsize
!=4 && bi
->pixelsize
!=8 &&
455 bi
->pixelsize
!=16 && bi
->pixelsize
!=24 && bi
->pixelsize
!=32)
457 de_err(c
, "%d bits/pixel images are not supported", (int)bi
->pixelsize
);
460 if((bi
->uses_pal
&& bi
->pixeltype
!=0) || (!bi
->uses_pal
&& bi
->pixeltype
!=16)) {
461 de_err(c
, "Pixel type %d is not supported", (int)bi
->pixeltype
);
464 if(bi
->cmpcount
!=1 && bi
->cmpcount
!=3 && bi
->cmpcount
!=4) {
465 de_err(c
, "Component count %d is not supported", (int)bi
->cmpcount
);
468 if(bi
->cmpsize
!=1 && bi
->cmpsize
!=2 && bi
->cmpsize
!=4 && bi
->cmpsize
!=5 &&
471 de_err(c
, "%d-bit components are not supported", (int)bi
->cmpsize
);
474 if(bi
->packing_type
!=0 && bi
->packing_type
!=1 && bi
->packing_type
!=3 && bi
->packing_type
!=4) {
475 de_err(c
, "Packing type %d is not supported", (int)bi
->packing_type
);
479 (bi
->packing_type
==0 || bi
->packing_type
==1) &&
480 (bi
->pixelsize
==1 || bi
->pixelsize
==2 || bi
->pixelsize
==4 || bi
->pixelsize
==8) &&
481 bi
->cmpcount
==1 && bi
->cmpsize
==bi
->pixelsize
) ||
482 (!bi
->uses_pal
&& bi
->packing_type
==3 && bi
->pixelsize
==16 && bi
->cmpcount
==3 && bi
->cmpsize
==5) ||
483 (!bi
->uses_pal
&& bi
->packing_type
==4 && bi
->pixelsize
==32 && bi
->cmpcount
==3 && bi
->cmpsize
==8) ||
484 (!bi
->uses_pal
&& bi
->packing_type
==4 && bi
->pixelsize
==32 && bi
->cmpcount
==4 && bi
->cmpsize
==8))
489 de_err(c
, "This type of image is not supported");
493 if(bi
->cmpcount
==4) {
494 de_warn(c
, "This image might have transparency, which is not supported.");
497 decode_bitmap(c
, d
, bi
, pos
);
500 de_dbg_indent(c
, -1);
504 // For opcodes 0x90, 0x91, 0x98, 0x99, 0x9a, 0x9b
505 static int handler_98_9a(deark
*c
, lctx
*d
, i64 opcode
, i64 pos1
, i64
*bytes_used
)
507 struct fmtutil_macbitmap_info
*bi
= NULL
;
508 i64 pixdata_size
= 0;
509 i64 colortable_size
= 0;
513 bi
= de_malloc(c
, sizeof(struct fmtutil_macbitmap_info
));
516 if(opcode
==0x9a || opcode
==0x9b) {
517 fmtutil_macbitmap_read_baseaddr(c
, c
->infile
, bi
, pos
);
521 fmtutil_macbitmap_read_rowbytes_and_bounds(c
, c
->infile
, bi
, pos
);
524 if(bi
->pixmap_flag
) {
525 fmtutil_macbitmap_read_pixmap_only_fields(c
, c
->infile
, bi
, pos
);
529 if((opcode
==0x90 || opcode
==0x91 || opcode
==0x98 || opcode
==0x99) && bi
->pixmap_flag
) {
530 // Prepare to read the palette
532 bi
->has_colortable
= 1;
534 else if((opcode
==0x90 || opcode
==0x91 || opcode
==0x98 || opcode
==0x99) && !bi
->pixmap_flag
) {
535 // Settings implied by the lack of a PixMap header
540 bi
->num_pal_entries
= 2;
541 bi
->pal
[0] = DE_STOCKCOLOR_WHITE
;
542 bi
->pal
[1] = DE_STOCKCOLOR_BLACK
;
544 else if((opcode
==0x9a || opcode
==0x9b) && !bi
->pixmap_flag
) {
545 de_err(c
, "DirectBitsRect image without PixMap flag is not supported");
549 if(bi
->has_colortable
) {
550 if(!fmtutil_macbitmap_read_colortable(c
, c
->infile
, bi
, pos
, &colortable_size
)) goto done
;
551 pos
+= colortable_size
;
554 read_src_dst_mode(c
, d
, bi
, pos
);
557 if(opcode
==0x91 || opcode
==0x99 || opcode
==0x9b) {
560 de_dbg(c
, "region at %"I64_FMT
, pos
);
562 rgnsize
= de_getu16be(pos
);
563 de_dbg(c
, "region size: %d", (int)rgnsize
);
564 de_dbg_indent(c
, -1);
565 if(rgnsize
<2) goto done
;
568 de_info(c
, "Note: Ignoring clipping region. Output image might have "
569 "extraneous pixels.");
573 if(!get_pixdata_size(c
, d
, bi
, pos
, &pixdata_size
)) {
576 decode_pixdata(c
, d
, bi
, pos
);
579 *bytes_used
= pos
- pos1
;
588 static int handler_pixpat(deark
*c
, lctx
*d
, i64 opcode
, i64 pos1
, i64
*bytes_used
)
590 unsigned int pattype
;
594 i64 colortable_size
= 0;
595 i64 pixdata_size
= 0;
596 struct fmtutil_macbitmap_info
*bi
= NULL
;
598 pattype
= (unsigned int)de_getu16be_p(&pos
);
599 de_dbg(c
, "PatType: %u", pattype
);
600 pos
+= 8; // Pat1Data
602 if(pattype
==2) { // ditherPat(?)
608 bi
= de_malloc(c
, sizeof(struct fmtutil_macbitmap_info
));
610 fmtutil_macbitmap_read_rowbytes_and_bounds(c
, c
->infile
, bi
, pos
);
612 fmtutil_macbitmap_read_pixmap_only_fields(c
, c
->infile
, bi
, pos
);
616 if(!fmtutil_macbitmap_read_colortable(c
, c
->infile
, bi
, pos
, &colortable_size
)) goto done
;
617 pos
+= colortable_size
;
619 if(!get_pixdata_size(c
, d
, bi
, pos
, &pixdata_size
)) {
622 // Note: We could extract the "PixMap" pattern easily enough here, by calling
623 // decode_pixdata(). But if we do that, maybe we should also extract the
624 // Pat1Data data above, as well as other opcodes like BkPat.
629 if(!retval
&& needmsg
) {
630 de_err(c
, "Failed to parse PixPat data");
633 *bytes_used
= pos
- pos1
;
639 static void do_iccprofile_item(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
645 selector
= de_getu32be(pos
);
647 de_dbg(c
, "ICC profile segment, selector=%d, data len=%d", (int)selector
,
651 // If this is not a Continuation segment, close any current file.
652 dbuf_close(d
->iccprofile_file
);
653 d
->iccprofile_file
= NULL
;
656 if(selector
==0) { // Beginning segment
657 d
->iccprofile_file
= dbuf_create_output_file(c
, "icc", NULL
, DE_CREATEFLAG_IS_AUX
);
660 if(selector
==0 || selector
==1) {
661 // Beginning and Continuation segments normally have profile data.
662 // End segments (selector==2) are not allowed to include data.
664 if(!d
->iccprofile_file
) {
665 de_warn(c
, "Bad ICC profile segment");
668 dbuf_copy(c
->infile
, pos
+4, data_len
, d
->iccprofile_file
);
673 static int handler_a0(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
676 kind
= de_getu16be(data_pos
);
677 de_dbg(c
, "comment kind: %d", (int)kind
);
682 static int handler_a1(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
687 kind
= de_getu16be(data_pos
);
688 len
= de_getu16be(data_pos
+2);
689 de_dbg(c
, "comment kind: %d, size: %d", (int)kind
, (int)len
);
692 if(kind
==100 && len
>=4) {
693 struct de_fourcc sig4cc
;
695 dbuf_read_fourcc(c
->infile
, data_pos
+4, &sig4cc
, 4, 0x0);
696 de_dbg(c
, "application comment, signature=0x%08x '%s'",
697 (unsigned int)sig4cc
.id
, sig4cc
.id_dbgstr
);
698 de_dbg_hexdump(c
, c
->infile
, data_pos
+8, len
-4, 256, NULL
, 0x1);
701 do_iccprofile_item(c
, d
, data_pos
+4, len
);
704 de_dbg_hexdump(c
, c
->infile
, data_pos
+4, len
, 256, NULL
, 0x1);
711 static int handler_0c00(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
715 struct pict_rect srcrect
;
717 hdrver
= de_getu16be(data_pos
);
718 d
->is_extended_v2
= (hdrver
==0xfffe);
720 de_dbg(c
, "extended v2: %s", d
->is_extended_v2
?"yes":"no");
721 if(d
->is_extended_v2
) {
722 hres
= pict_read_fixed(c
->infile
, data_pos
+4);
723 vres
= pict_read_fixed(c
->infile
, data_pos
+8);
724 de_dbg(c
, "dpi: %.2f"DE_CHAR_TIMES
"%.2f", hres
, vres
);
725 pict_read_rect(c
->infile
, data_pos
+12, &srcrect
, "srcRect");
731 static void do_handle_qtif_idsc(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
733 i64 idsc_dpos
, idsc_dlen
;
734 i64 idat_dpos
, idat_dlen
;
736 struct de_fourcc cmpr4cc
;
739 de_run_module_by_id_on_slice2(c
, "qtif", "I", c
->infile
, pos
, len
);
743 // Try to construct a .qtif file.
744 // This way, we do something potentially useful even if the image has
745 // a compression scheme that our qtif module doesn't support.
748 idsc_dlen
= de_getu32be(idsc_dpos
);
749 de_dbg(c
, "idsc: pos=%"I64_FMT
", len=%"I64_FMT
, idsc_dpos
, idsc_dlen
);
750 if(idsc_dpos
+idsc_dlen
> pos
+len
) goto done
;
752 dbuf_read_fourcc(c
->infile
, idsc_dpos
+4, &cmpr4cc
, 4, 0x0);
753 de_dbg(c
, "compression type: \"%s\"", cmpr4cc
.id_dbgstr
);
755 idat_dpos
= idsc_dpos
+ idsc_dlen
;
756 idat_dlen
= de_getu32be(idsc_dpos
+44);
757 de_dbg(c
, "idat: pos=%"I64_FMT
", len=%"I64_FMT
, idat_dpos
, idat_dlen
);
759 idat_dlen
= pos
+len
-idat_dpos
; // ??
761 if(idat_dpos
+idat_dlen
> pos
+len
) goto done
;
763 #define CODE_idat 0x69646174U
764 #define CODE_idsc 0x69647363U
765 outf
= dbuf_create_output_file(c
, "qtif", NULL
, 0);
767 dbuf_writeu32be(outf
, 8+idsc_dlen
);
768 dbuf_writeu32be(outf
, CODE_idsc
);
769 dbuf_copy(c
->infile
, idsc_dpos
, idsc_dlen
, outf
);
771 dbuf_writeu32be(outf
, 8+idat_dlen
);
772 dbuf_writeu32be(outf
, CODE_idat
);
773 dbuf_copy(c
->infile
, idat_dpos
, idat_dlen
, outf
);
779 // CompressedQuickTime (0x8200) & UncompressedQuickTime (0x8201)
780 static int handler_QuickTime(deark
*c
, lctx
*d
, i64 opcode
, i64 data_pos
, i64
*bytes_used
)
787 payload_len
= de_getu32be(data_pos
);
788 payload_pos
= data_pos
+4;
789 de_dbg(c
, "payload: pos=%"I64_FMT
", len=%"I64_FMT
, payload_pos
, payload_len
);
790 endpos
= payload_pos
+payload_len
;
791 if(endpos
> c
->infile
->len
) return 0;
792 *bytes_used
= 4+payload_len
;
794 // Following the size field seems to be 68 or 50 bytes of data,
795 // followed by QuickTime "idsc" data, followed by image data.
796 idsc_pos
= payload_pos
+ ((opcode
==0x8201) ? 50 : 68);
798 do_handle_qtif_idsc(c
, d
, idsc_pos
, endpos
-idsc_pos
);
802 static const struct opcode_info opcode_info_arr
[] = {
803 // TODO: This list might not be complete, and it needs to be complete in
804 // order to parse all PICT files.
805 // Note that some opcode ranges are handled in do_handle_item().
806 { 0x0000, SZCODE_EXACT
, 0, "NOP", NULL
},
807 { 0x0001, SZCODE_REGION
, 0, "Clip", NULL
},
808 { 0x0002, SZCODE_EXACT
, 8, "BkPat", NULL
},
809 { 0x0003, SZCODE_EXACT
, 2, "TxFont", NULL
},
810 { 0x0004, SZCODE_EXACT
, 1, "TxFace", NULL
},
811 { 0x0005, SZCODE_EXACT
, 2, "TxMode", NULL
},
812 { 0x0006, SZCODE_EXACT
, 4, "SpExtra", NULL
},
813 { 0x0007, SZCODE_EXACT
, 4, "PnSize", NULL
},
814 { 0x0008, SZCODE_EXACT
, 2, "PnMode", NULL
},
815 { 0x0009, SZCODE_EXACT
, 8, "PnPat", NULL
},
816 { 0x000a, SZCODE_EXACT
, 8, "FillPat", NULL
},
817 { 0x000b, SZCODE_EXACT
, 4, "OvSize", NULL
},
818 { 0x000c, SZCODE_EXACT
, 4, "Origin", NULL
},
819 { 0x000d, SZCODE_EXACT
, 2, "TxSize", NULL
},
820 { 0x000e, SZCODE_EXACT
, 4, "FgColor", NULL
},
821 { 0x000f, SZCODE_EXACT
, 4, "BkColor", NULL
},
822 { 0x0010, SZCODE_EXACT
, 8, "TxRatio", NULL
},
823 { 0x0011, SZCODE_EXACT
, 1, "Version", handler_11
},
824 { 0x0012, SZCODE_SPECIAL
, 0, "BkPixPat", handler_pixpat
},
825 { 0x0013, SZCODE_SPECIAL
, 0, "PnPixPat", handler_pixpat
},
826 { 0x0014, SZCODE_SPECIAL
, 0, "FillPixPat", handler_pixpat
},
827 { 0x0015, SZCODE_EXACT
, 2, "PnLocHFrac", NULL
},
828 { 0x0016, SZCODE_EXACT
, 2, "ChExtra", NULL
},
829 { 0x001a, SZCODE_EXACT
, 6, "RGBFgCol", handler_RGBColor
},
830 { 0x001b, SZCODE_EXACT
, 6, "RGBBkCol", handler_RGBColor
},
831 { 0x001c, SZCODE_EXACT
, 0, "HiliteMode", NULL
},
832 { 0x001d, SZCODE_EXACT
, 6, "HiliteColor", handler_RGBColor
},
833 { 0x001e, SZCODE_EXACT
, 0, "DefHilite", NULL
},
834 { 0x001f, SZCODE_EXACT
, 6, "OpColor", handler_RGBColor
},
835 { 0x0020, SZCODE_EXACT
, 8, "Line", NULL
},
836 { 0x0021, SZCODE_EXACT
, 4, "LineFrom", NULL
},
837 { 0x0022, SZCODE_EXACT
, 6, "ShortLine", NULL
},
838 { 0x0023, SZCODE_EXACT
, 2, "ShortLineFrom", NULL
},
839 { 0x0028, SZCODE_SPECIAL
, 0, "LongText", handler_28
},
840 { 0x0029, SZCODE_SPECIAL
, 0, "DHText", handler_DxText
},
841 { 0x002a, SZCODE_SPECIAL
, 0, "DVText", handler_DxText
},
842 { 0x002b, SZCODE_SPECIAL
, 0, "DHDVText", handler_2b
},
843 { 0x002c, SZCODE_SPECIAL
, 0, "fontName", handler_2c
},
844 { 0x002d, SZCODE_SPECIAL
, 0, "lineJustify", NULL
},
845 { 0x002e, SZCODE_SPECIAL
, 0, "glyphState", NULL
},
846 { 0x0030, SZCODE_EXACT
, 8, "frameRect", handler_Rectangle
},
847 { 0x0031, SZCODE_EXACT
, 8, "paintRect", handler_Rectangle
},
848 { 0x0032, SZCODE_EXACT
, 8, "eraseRect", handler_Rectangle
},
849 { 0x0033, SZCODE_EXACT
, 8, "invertRect", handler_Rectangle
},
850 { 0x0034, SZCODE_EXACT
, 8, "fillRect", handler_Rectangle
},
851 { 0x0038, SZCODE_EXACT
, 0, "frameSameRect", NULL
},
852 { 0x0039, SZCODE_EXACT
, 0, "paintSameRect", NULL
},
853 { 0x003a, SZCODE_EXACT
, 0, "eraseSameRect", NULL
},
854 { 0x003b, SZCODE_EXACT
, 0, "invertSameRect", NULL
},
855 { 0x003c, SZCODE_EXACT
, 0, "fillSameRect", NULL
},
856 { 0x0040, SZCODE_EXACT
, 8, "frameRRect", handler_Rectangle
},
857 { 0x0041, SZCODE_EXACT
, 8, "paintRRect", handler_Rectangle
},
858 { 0x0042, SZCODE_EXACT
, 8, "eraseRRect", handler_Rectangle
},
859 { 0x0043, SZCODE_EXACT
, 8, "invertRRect", handler_Rectangle
},
860 { 0x0044, SZCODE_EXACT
, 8, "fillRRect", handler_Rectangle
},
861 { 0x0048, SZCODE_EXACT
, 0, "frameSameRRect", NULL
},
862 { 0x0049, SZCODE_EXACT
, 0, "paintSameRRect", NULL
},
863 { 0x004a, SZCODE_EXACT
, 0, "eraseSameRRect", NULL
},
864 { 0x004b, SZCODE_EXACT
, 0, "invertSameRRect", NULL
},
865 { 0x004c, SZCODE_EXACT
, 0, "fillSameRRect", NULL
},
866 { 0x0050, SZCODE_EXACT
, 8, "frameOval", handler_Rectangle
},
867 { 0x0051, SZCODE_EXACT
, 8, "paintOval", handler_Rectangle
},
868 { 0x0052, SZCODE_EXACT
, 8, "eraseOval", handler_Rectangle
},
869 { 0x0053, SZCODE_EXACT
, 8, "invertOval", handler_Rectangle
},
870 { 0x0054, SZCODE_EXACT
, 8, "fillOval", handler_Rectangle
},
871 { 0x0058, SZCODE_EXACT
, 0, "frameSameOval", NULL
},
872 { 0x0059, SZCODE_EXACT
, 0, "paintSameOval", NULL
},
873 { 0x005a, SZCODE_EXACT
, 0, "eraseSameOval", NULL
},
874 { 0x005b, SZCODE_EXACT
, 0, "invertSameOval", NULL
},
875 { 0x005c, SZCODE_EXACT
, 0, "fillSameOval", NULL
},
876 { 0x0060, SZCODE_EXACT
, 12, "frameArc", NULL
},
877 { 0x0061, SZCODE_EXACT
, 12, "paintArc", NULL
},
878 { 0x0062, SZCODE_EXACT
, 12, "eraseArc", NULL
},
879 { 0x0063, SZCODE_EXACT
, 12, "invertArc", NULL
},
880 { 0x0064, SZCODE_EXACT
, 12, "fillArc", NULL
},
881 { 0x0068, SZCODE_EXACT
, 4, "frameSameArc", NULL
},
882 { 0x0069, SZCODE_EXACT
, 4, "paintSameArc", NULL
},
883 { 0x006a, SZCODE_EXACT
, 4, "eraseSameArc", NULL
},
884 { 0x006b, SZCODE_EXACT
, 4, "invertSameArc", NULL
},
885 { 0x006c, SZCODE_EXACT
, 4, "fillSameArc", NULL
},
886 { 0x0080, SZCODE_REGION
, 0, "frameRgn", NULL
},
887 { 0x0081, SZCODE_REGION
, 0, "paintRgn", NULL
},
888 { 0x0082, SZCODE_REGION
, 0, "eraseRgn", NULL
},
889 { 0x0083, SZCODE_REGION
, 0, "invertRgn", NULL
},
890 { 0x0084, SZCODE_REGION
, 0, "fillRgn", NULL
},
891 { 0x0070, SZCODE_POLYGON
, 0, "framePoly", NULL
},
892 { 0x0071, SZCODE_POLYGON
, 0, "paintPoly", NULL
},
893 { 0x0072, SZCODE_POLYGON
, 0, "erasePoly", NULL
},
894 { 0x0073, SZCODE_POLYGON
, 0, "invertPoly", NULL
},
895 { 0x0074, SZCODE_POLYGON
, 0, "fillPoly", NULL
},
896 { 0x0090, SZCODE_SPECIAL
, 0, "BitsRect", handler_98_9a
},
897 { 0x0091, SZCODE_SPECIAL
, 0, "BitsRgn", handler_98_9a
},
898 { 0x0098, SZCODE_SPECIAL
, 0, "PackBitsRect", handler_98_9a
},
899 { 0x0099, SZCODE_SPECIAL
, 0, "PackBitsRgn", handler_98_9a
},
900 { 0x009a, SZCODE_SPECIAL
, 0, "DirectBitsRect", handler_98_9a
},
901 { 0x009b, SZCODE_SPECIAL
, 0, "DirectBitsRgn", handler_98_9a
},
902 { 0x00a0, SZCODE_EXACT
, 2, "ShortComment", handler_a0
},
903 { 0x00a1, SZCODE_SPECIAL
, 0, "LongComment", handler_a1
},
904 { 0x00ff, SZCODE_EXACT
, 2, "opEndPic", NULL
},
905 { 0x0c00, SZCODE_EXACT
, 24, "HeaderOp", handler_0c00
},
906 { 0x8200, SZCODE_SPECIAL
, 0, "CompressedQuickTime", handler_QuickTime
},
907 { 0x8201, SZCODE_SPECIAL
, 0, "UncompressedQuickTime", handler_QuickTime
}
910 static const struct opcode_info
*find_opcode_info(i64 opcode
)
914 for(i
=0; i
<DE_ARRAYCOUNT(opcode_info_arr
); i
++) {
915 if(opcode_info_arr
[i
].opcode
== opcode
) {
916 return &opcode_info_arr
[i
];
922 static int do_handle_item(deark
*c
, lctx
*d
, i64 opcode_pos
, i64 opcode
,
923 i64 data_pos
, i64
*data_bytes_used
)
925 const char *opcode_name
;
926 const struct opcode_info
*opi
;
928 struct pict_rect tmprect
;
931 *data_bytes_used
= 0;
933 opi
= find_opcode_info(opcode
);
934 if(opi
&& opi
->name
) opcode_name
= opi
->name
;
935 else opcode_name
= "?";
938 de_dbg(c
, "opcode 0x%04x (%s) at %d", (unsigned int)opcode
, opcode_name
, (int)opcode_pos
);
940 de_dbg(c
, "opcode 0x%02x (%s) at %d", (unsigned int)opcode
, opcode_name
, (int)opcode_pos
);
944 *data_bytes_used
= opi
->size
; // Default to the size in the table.
945 ret
= opi
->fn(c
, d
, opcode
, data_pos
, data_bytes_used
);
946 de_dbg_indent(c
, -1);
948 else if(opi
&& opi
->size_code
==SZCODE_EXACT
) {
949 *data_bytes_used
= opi
->size
;
952 else if(opi
&& opi
->size_code
==SZCODE_REGION
) {
953 n
= de_getu16be(data_pos
);
955 de_dbg(c
, "region size: %d", (int)n
);
957 pict_read_rect(c
->infile
, data_pos
+2, &tmprect
, "rect");
959 de_dbg_indent(c
, -1);
960 *data_bytes_used
= n
;
963 else if(opi
&& opi
->size_code
==SZCODE_POLYGON
) {
964 n
= de_getu16be(data_pos
);
966 de_dbg(c
, "polygon size: %d", (int)n
);
967 de_dbg_indent(c
, -1);
968 *data_bytes_used
= n
;
971 else if(opcode
>=0x2c && opcode
<=0x2f) {
972 // Starts with 2-byte size, size does not include the "size" field.
973 n
= de_getu16be(data_pos
);
974 *data_bytes_used
= 2+n
;
977 else if(opcode
>=0x8100 && opcode
<=0xffff) {
978 // Starts with 4-byte size, size does not include the "size" field.
979 n
= de_getu32be(data_pos
);
980 *data_bytes_used
= 4+n
;
984 de_err(c
, "Unsupported opcode: 0x%04x", (unsigned int)opcode
);
990 static void do_read_items(deark
*c
, lctx
*d
, i64 pos
)
998 if(pos
%2 && d
->version
==2) {
999 pos
++; // 2-byte alignment
1002 if(pos
>= c
->infile
->len
) break;
1007 opcode
= de_getu16be(pos
);
1011 opcode
= (i64
)de_getbyte(pos
);
1015 ret
= do_handle_item(c
, d
, opcode_pos
, opcode
, pos
, &bytes_used
);
1017 if(opcode
==0x00ff) goto done
; // End of image
1025 // mode: 0=called from de_identify..., 1=called from de_run...
1026 static void do_detect_version(deark
*c
, struct detection_info
*dti
, int mode
)
1028 static const u8 v1pattern
[2] = { 0x11, 0x01 };
1029 static const u8 v2pattern
[6] = { 0x00, 0x11, 0x02, 0xff, 0x0c, 0x00 };
1036 dti
->file_version
= 0;
1037 dti
->has_fileheader
= 0;
1039 de_read(buf
, 522, sizeof(buf
));
1040 if(!de_memcmp(buf
, v2pattern
, 6)) {
1043 else if(!de_memcmp(buf
, v1pattern
, 2)) {
1047 de_read(buf
, 10, sizeof(buf
));
1048 if(!de_memcmp(buf
, v2pattern
, 6)) {
1051 else if(!de_memcmp(buf
, v1pattern
, 2)) {
1056 if(!v1_hdr
&& !v2_hdr
&& !v1_nohdr
&& !v2_nohdr
) {
1061 dti
->file_version
= 2;
1062 dti
->has_fileheader
= 1;
1066 dti
->file_version
= 2;
1071 // For v1, check that the file ends as expected
1072 de_read(buf
, c
->infile
->len
-2, 2);
1074 ; // v1 files should end with 0xff
1076 else if(buf
[0]==0xff && buf
[1]==0x00) {
1077 ; // But a few have an extra NUL byte at the end
1082 dti
->file_version
= 1;
1083 dti
->has_fileheader
= 1;
1087 dti
->file_version
= 1;
1092 static void de_run_pict(deark
*c
, de_module_params
*mparams
)
1097 struct pict_rect framerect
;
1099 d
= de_malloc(c
, sizeof(lctx
));
1101 do_detect_version(c
, &d
->dti
, 1);
1102 if(d
->dti
.file_version
>0) {
1103 de_declare_fmtf(c
, "PICT v%d%s", d
->dti
.file_version
,
1104 d
->dti
.has_fileheader
?"":", without file header");
1109 if(d
->dti
.has_fileheader
) {
1113 picsize
= de_getu16be(pos
);
1114 de_dbg(c
, "picSize: %d", (int)picsize
);
1116 pict_read_rect(c
->infile
, pos
, &framerect
, "picFrame");
1119 do_read_items(c
, d
, pos
);
1121 dbuf_close(d
->iccprofile_file
);
1125 static int de_identify_pict(deark
*c
)
1127 struct detection_info dti
;
1129 do_detect_version(c
, &dti
, 0);
1130 if(dti
.file_version
==2) {
1133 else if(dti
.file_version
==1) {
1134 if(dti
.has_fileheader
) return 25;
1140 void de_module_pict(deark
*c
, struct deark_module_info
*mi
)
1143 mi
->desc
= "Macintosh PICT";
1144 mi
->run_fn
= de_run_pict
;
1145 mi
->identify_fn
= de_identify_pict
;