bmp: Rewrote the RLE decompressor
[deark.git] / modules / pict.c
blob6c649ed5c375b4274e8d57d0e0a95f8cffc05f12
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);
12 struct pict_point {
13 i64 y, x;
16 struct pict_rect {
17 i64 t, l, b, r;
20 struct detection_info {
21 int file_version;
22 int has_fileheader;
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
28 int is_extended_v2;
29 int decode_qt;
30 dbuf *iccprofile_file;
31 } lctx;
33 typedef int (*item_decoder_fn)(deark *c, lctx *d, i64 opcode, i64 data_pos,
34 i64 *bytes_used);
36 struct opcode_info {
37 u16 opcode;
38 #define SZCODE_SPECIAL 0
39 #define SZCODE_EXACT 1
40 #define SZCODE_REGION 2
41 #define SZCODE_POLYGON 3
42 u16 size_code;
43 u32 size; // Data size, not including opcode. Logic depends on size_code.
44 const char *name;
45 item_decoder_fn fn;
48 static double pict_read_fixed(dbuf *f, i64 pos)
50 i64 n;
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);
65 if(dbgname) {
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);
79 if(dbgname) {
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];
88 u8 clr8[3];
89 u32 clr;
90 char csamp[16];
91 i64 pos = data_pos;
92 i64 k;
94 for(k=0; k<3; k++) {
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);
101 return 1;
104 // Version
105 static int handler_11(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
107 i64 ver;
109 *bytes_used = 1;
110 ver = de_getbyte(data_pos);
111 de_dbg(c, "version: %d", (int)ver);
113 if(ver==2) {
114 d->version = 2;
116 else if(ver!=1) {
117 de_err(c, "Unsupported PICT version: %d", (int)ver);
118 return 0;
120 return 1;
123 // LongText
124 static int handler_28(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
126 i64 tlen;
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;
136 ucstring_destroy(s);
137 return 1;
140 // DVText
141 static int handler_DxText(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
143 i64 tlen;
144 i64 dx;
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));
157 ucstring_destroy(s);
158 return 1;
161 // DHDVText
162 static int handler_2b(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
164 i64 tlen;
165 i64 dh, dv;
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));
180 return 1;
183 // fontName
184 static int handler_2c(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
186 i64 n;
187 i64 tlen;
188 i64 id;
189 de_ucstring *s = NULL;
191 n = de_getu16be(data_pos);
192 *bytes_used = 2+n;
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));
199 ucstring_destroy(s);
200 return 1;
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");
208 return 1;
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;
215 i64 n;
217 de_dbg(c, "src/dst/mode part of bitmap header, at %d", (int)pos);
218 de_dbg_indent(c, 1);
220 pict_read_rect(c->infile, pos, &tmprect, "srcRect");
221 pos += 8;
222 pict_read_rect(c->infile, pos, &tmprect, "dstRect");
223 pos += 8;
225 n = de_getu16be(pos);
226 de_dbg(c, "transfer mode: %d", (int)n);
227 //pos += 2;
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)
238 i64 pos;
239 i64 j;
240 i64 bytecount;
241 int retval = 0;
243 pos = pos1;
244 de_dbg(c, "PixData at %d", (int)pos);
245 de_dbg_indent(c, 1);
247 if(bi->height<0 || bi->height>65535) {
248 de_err(c, "Invalid bitmap height (%d)", (int)bi->height);
249 goto done;
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);
256 goto done;
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);
263 pos+=2;
265 else {
266 bytecount = (i64)de_getbyte(pos);
267 pos+=1;
269 pos += bytecount;
272 else if(bi->packing_type==1 || (bi->packing_type==0 && bi->rowbytes<8)) {
273 pos += bi->rowbytes * bi->height; // uncompressed
275 else {
276 de_err(c, "Unsupported packing type: %d", (int)bi->packing_type);
277 goto done;
280 *pixdata_size = pos - pos1;
281 de_dbg(c, "PixData size: %d", (int)*pixdata_size);
282 retval = 1;
284 done:
285 de_dbg_indent(c, -1);
286 return retval;
289 static void decode_bitmap_rgb24(deark *c, lctx *d, struct fmtutil_macbitmap_info *bi,
290 dbuf *unc_pixels, de_bitmap *img, i64 pos)
292 i64 i, j;
293 u8 cr, cg, cb;
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)
308 i64 i, j;
309 u8 c0, c1;
310 u32 clr;
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,
327 bi->pal, img, 0);
330 static int decode_bitmap(deark *c, lctx *d, struct fmtutil_macbitmap_info *bi, i64 pos)
332 i64 j;
333 dbuf *unc_pixels = NULL;
334 de_bitmap *img = NULL;
335 de_finfo *fi = NULL;
336 i64 bytecount;
337 i64 bitmapsize;
338 int dst_nsamples;
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);
363 pos+=2;
365 else {
366 bytecount = (i64)de_getbyte(pos);
367 pos+=1;
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;
378 dcmpri.pos = pos;
379 dcmpri.len = bytecount;
380 fmtutil_decompress_packbits_ex(c, &dcmpri, &dcmpro, &dres, &pbparams);
382 else {
383 dcmpri.pos = pos;
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);
393 pos += bytecount;
395 dbuf_flush(unc_pixels);
397 dst_nsamples = 3;
398 if(bi->uses_pal) {
399 if(de_is_grayscale_palette(bi->pal, bi->num_pal_entries)) {
400 dst_nsamples = 1;
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;
414 if(bi->uses_pal) {
415 decode_bitmap_paletted(c, d, bi, unc_pixels, img, pos);
417 else {
418 if(bi->pixelsize==16) {
419 decode_bitmap_rgb16(c, d, bi, unc_pixels, img, pos);
421 else {
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);
431 return 1;
434 static int decode_pixdata(deark *c, lctx *d, struct fmtutil_macbitmap_info *bi, i64 pos)
436 int retval = 0;
438 de_dbg_indent(c, 1);
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);
443 goto done;
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);
451 goto done;
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);
455 goto done;
457 if(bi->cmpcount!=1 && bi->cmpcount!=3 && bi->cmpcount!=4) {
458 de_err(c, "Component count %d is not supported", (int)bi->cmpcount);
459 goto done;
461 if(bi->cmpsize!=1 && bi->cmpsize!=2 && bi->cmpsize!=4 && bi->cmpsize!=5 &&
462 bi->cmpsize!=8)
464 de_err(c, "%d-bit components are not supported", (int)bi->cmpsize);
465 goto done;
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);
469 goto done;
471 if((bi->uses_pal &&
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))
483 else {
484 de_err(c, "This type of image is not supported");
485 goto done;
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);
494 done:
495 de_dbg_indent(c, -1);
496 return retval;
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;
505 int retval = 0;
506 i64 pos;
508 bi = de_malloc(c, sizeof(struct fmtutil_macbitmap_info));
509 pos = pos1;
511 if(opcode==0x9a || opcode==0x9b) {
512 fmtutil_macbitmap_read_baseaddr(c, c->infile, bi, pos);
513 pos += 4;
516 fmtutil_macbitmap_read_rowbytes_and_bounds(c, c->infile, bi, pos);
517 pos += 10;
519 if(bi->pixmap_flag) {
520 fmtutil_macbitmap_read_pixmap_only_fields(c, c->infile, bi, pos);
521 pos += 36;
524 if((opcode==0x90 || opcode==0x91 || opcode==0x98 || opcode==0x99) && bi->pixmap_flag) {
525 // Prepare to read the palette
526 bi->uses_pal = 1;
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
531 bi->pixelsize = 1;
532 bi->cmpcount = 1;
533 bi->cmpsize = 1;
534 bi->uses_pal = 1;
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");
541 goto done;
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);
550 pos += 18;
552 if(opcode==0x91 || opcode==0x99 || opcode==0x9b) {
553 i64 rgnsize;
555 de_dbg(c, "region at %"I64_FMT, pos);
556 de_dbg_indent(c, 1);
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;
561 pos += rgnsize;
562 if(!c->padpix) {
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)) {
569 goto done;
571 decode_pixdata(c, d, bi, pos);
572 pos += pixdata_size;
574 *bytes_used = pos - pos1;
576 retval = 1;
578 done:
579 de_free(c, bi);
580 return retval;
583 static int handler_pixpat(deark *c, lctx *d, i64 opcode, i64 pos1, i64 *bytes_used)
585 unsigned int pattype;
586 i64 pos = pos1;
587 int needmsg = 1;
588 int retval = 0;
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(?)
598 pos += 6; // RGB
599 retval = 1;
600 goto done;
603 bi = de_malloc(c, sizeof(struct fmtutil_macbitmap_info));
605 fmtutil_macbitmap_read_rowbytes_and_bounds(c, c->infile, bi, pos);
606 pos += 10;
607 fmtutil_macbitmap_read_pixmap_only_fields(c, c->infile, bi, pos);
608 pos += 36;
610 bi->uses_pal = 1;
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)) {
615 goto done;
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.
620 pos += pixdata_size;
621 retval = 1;
623 done:
624 if(!retval && needmsg) {
625 de_err(c, "Failed to parse PixPat data");
627 if(retval) {
628 *bytes_used = pos - pos1;
630 de_free(c, bi);
631 return retval;
634 static void do_iccprofile_item(deark *c, lctx *d, i64 pos, i64 len)
636 i64 selector;
637 i64 data_len;
639 if(len<4) return;
640 selector = de_getu32be(pos);
641 data_len = len-4;
642 de_dbg(c, "ICC profile segment, selector=%d, data len=%d", (int)selector,
643 (int)data_len);
645 if(selector!=1) {
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");
661 return;
663 dbuf_copy(c->infile, pos+4, data_len, d->iccprofile_file);
667 // ShortComment
668 static int handler_a0(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
670 i64 kind;
671 kind = de_getu16be(data_pos);
672 de_dbg(c, "comment kind: %d", (int)kind);
673 return 1;
676 // LongComment
677 static int handler_a1(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
679 i64 kind;
680 i64 len;
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);
685 *bytes_used = 4+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);
695 else if(kind==224) {
696 do_iccprofile_item(c, d, data_pos+4, len);
698 else {
699 de_dbg_hexdump(c, c->infile, data_pos+4, len, 256, NULL, 0x1);
702 return 1;
705 // HeaderOp
706 static int handler_0c00(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
708 i64 hdrver;
709 double hres, vres;
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");
723 return 1;
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;
731 int retval = 0;
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) {
739 retval = 1;
742 de_free(c, mparams);
743 return retval;
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;
750 dbuf *outf = NULL;
751 struct de_fourcc cmpr4cc;
753 if(d->decode_qt) {
754 if(do_decode_qt(c, d, pos, len)) {
755 goto done;
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.
764 idsc_dpos = pos;
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);
775 if(idat_dlen==0) {
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);
792 done:
793 dbuf_close(outf);
796 // CompressedQuickTime (0x8200) & UncompressedQuickTime (0x8201)
797 static int handler_QuickTime(deark *c, lctx *d, i64 opcode, i64 data_pos, i64 *bytes_used)
799 i64 payload_pos;
800 i64 payload_len;
801 i64 endpos;
802 i64 idsc_pos;
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);
816 return 1;
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)
929 size_t i;
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];
936 return NULL;
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;
944 i64 n;
945 struct pict_rect tmprect;
946 int ret = 0;
948 *data_bytes_used = 0;
950 opi = find_opcode_info(opcode);
951 if(opi && opi->name) opcode_name = opi->name;
952 else opcode_name = "?";
954 if(d->version==2)
955 de_dbg(c, "opcode 0x%04x (%s) at %d", (unsigned int)opcode, opcode_name, (int)opcode_pos);
956 else
957 de_dbg(c, "opcode 0x%02x (%s) at %d", (unsigned int)opcode, opcode_name, (int)opcode_pos);
959 if(opi && opi->fn) {
960 de_dbg_indent(c, 1);
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;
967 ret = 1;
969 else if(opi && opi->size_code==SZCODE_REGION) {
970 n = de_getu16be(data_pos);
971 de_dbg_indent(c, 1);
972 de_dbg(c, "region size: %d", (int)n);
973 if(n>=10) {
974 pict_read_rect(c->infile, data_pos+2, &tmprect, "rect");
976 de_dbg_indent(c, -1);
977 *data_bytes_used = n;
978 ret = 1;
980 else if(opi && opi->size_code==SZCODE_POLYGON) {
981 n = de_getu16be(data_pos);
982 de_dbg_indent(c, 1);
983 de_dbg(c, "polygon size: %d", (int)n);
984 de_dbg_indent(c, -1);
985 *data_bytes_used = n;
986 ret = 1;
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;
992 ret = 1;
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;
998 ret = 1;
1000 else {
1001 de_err(c, "Unsupported opcode: 0x%04x", (unsigned int)opcode);
1004 return ret;
1007 static void do_read_items(deark *c, lctx *d, i64 pos)
1009 i64 opcode;
1010 i64 opcode_pos;
1011 i64 bytes_used;
1012 int ret;
1014 while(1) {
1015 if(pos%2 && d->version==2) {
1016 pos++; // 2-byte alignment
1019 if(pos >= c->infile->len) break;
1021 opcode_pos = pos;
1023 if(d->version==2) {
1024 opcode = de_getu16be(pos);
1025 pos+=2;
1027 else {
1028 opcode = (i64)de_getbyte(pos);
1029 pos+=1;
1032 ret = do_handle_item(c, d, opcode_pos, opcode, pos, &bytes_used);
1033 if(!ret) goto done;
1034 if(opcode==0x00ff) goto done; // End of image
1036 pos += bytes_used;
1038 done:
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 };
1047 u8 buf[6];
1048 int v1_nohdr = 0;
1049 int v2_nohdr = 0;
1050 int v1_hdr = 0;
1051 int v2_hdr = 0;
1053 dti->file_version = 0;
1054 dti->has_fileheader = 0;
1056 de_read(buf, 522, sizeof(buf));
1057 if(!de_memcmp(buf, v2pattern, 6)) {
1058 v2_hdr = 1;
1060 else if(!de_memcmp(buf, v1pattern, 2)) {
1061 v1_hdr = 1;
1063 else {
1064 de_read(buf, 10, sizeof(buf));
1065 if(!de_memcmp(buf, v2pattern, 6)) {
1066 v2_nohdr = 1;
1068 else if(!de_memcmp(buf, v1pattern, 2)) {
1069 v1_nohdr = 1;
1073 if(!v1_hdr && !v2_hdr && !v1_nohdr && !v2_nohdr) {
1074 return;
1077 if(v2_hdr) {
1078 dti->file_version = 2;
1079 dti->has_fileheader = 1;
1080 return;
1082 else if(v2_nohdr) {
1083 dti->file_version = 2;
1084 return;
1087 if(mode==0) {
1088 // For v1, check that the file ends as expected
1089 de_read(buf, c->infile->len-2, 2);
1090 if(buf[1]==0xff) {
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
1098 if(v1_hdr) {
1099 dti->file_version = 1;
1100 dti->has_fileheader = 1;
1101 return;
1103 else if(v1_nohdr) {
1104 dti->file_version = 1;
1105 return;
1109 static void de_run_pict(deark *c, de_module_params *mparams)
1111 lctx *d = NULL;
1112 i64 pos = 0;
1113 i64 picsize;
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");
1126 d->version = 1;
1128 if(d->dti.has_fileheader) {
1129 pos += 512;
1132 picsize = de_getu16be(pos);
1133 de_dbg(c, "picSize: %d", (int)picsize);
1134 pos+=2;
1135 pict_read_rect(c->infile, pos, &framerect, "picFrame");
1136 pos+=8;
1138 do_read_items(c, d, pos);
1140 dbuf_close(d->iccprofile_file);
1141 de_free(c, d);
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) {
1150 return 85;
1152 else if(dti.file_version==1) {
1153 if(dti.has_fileheader) return 25;
1154 return 15;
1156 return 0;
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)
1166 mi->id = "pict";
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;