Minor refactoring of the IFF and box-format parsers
[deark.git] / modules / palmbitmap.c
blob456ca490ba533da3f98b17e1a49cbfe7af1a3b26
1 // This file is part of Deark.
2 // Copyright (C) 2017 Jason Summers
3 // See the file COPYING for terms of use.
5 // Palm BitmapType
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_palmbitmap);
12 #define PALMBMPFLAG_COMPRESSED 0x8000U
13 #define PALMBMPFLAG_HASCOLORTABLE 0x4000U
14 #define PALMBMPFLAG_HASTRNS 0x2000U
15 #define PALMBMPFLAG_DIRECTCOLOR 0x0400U
17 enum palm_cmpr_type {
18 PCMPR_UNKNOWN, PCMPR_NONE, PCMPR_SCANLINE, PCMPR_RLE,
19 PCMPR_PACKBITS8, PCMPR_PACKBITS16
22 #define CMPR_FIELD_SCANLINE 0
23 #define CMPR_FIELD_RLE 1
24 #define CMPR_FIELD_PACKBITS 2
25 #define CMPR_FIELD_NONE 0xff
27 struct page_ctx {
28 i64 w, h;
29 i64 bitsperpixel;
30 i64 rowbytes;
31 int has_trns;
32 u32 trns_value;
33 int is_rgb;
34 u8 bitmapversion;
35 int has_custom_pal;
36 unsigned int cmpr_type_field;
37 enum palm_cmpr_type cmpr_type;
38 u32 custom_pal[256];
41 typedef struct localctx_struct {
42 int is_le;
43 int ignore_color_table_flag;
44 } lctx;
46 static int de_identify_palmbitmap_internal(deark *c, dbuf *f, i64 pos, i64 len)
48 i64 w, h;
49 i64 rowbytes;
50 u8 ver;
51 u8 pixelsize;
53 pixelsize = de_getbyte(pos+8);
54 if(pixelsize==0xff) {
55 pos += 16;
58 ver = de_getbyte(pos+9);
59 if(ver>3) return 0;
60 w = dbuf_getu16be(f, pos+0);
61 h = dbuf_getu16be(f, pos+2);
62 if(w==0 || h==0) return 0;
63 rowbytes = dbuf_getu16be(f, pos+4);
64 pixelsize = de_getbyte(pos+8);
65 if((pixelsize==0 && ver==0) || pixelsize==1 || pixelsize==2 ||
66 pixelsize==4 || pixelsize==8 || pixelsize==16)
70 else {
71 return 0;
73 if(rowbytes==0 || (rowbytes&0x1)) return 0;
74 // TODO: Make sure rowbytes is sensible
75 return 1;
78 static void do_decompress_scanline_compression(deark *c, lctx *d, struct page_ctx *pg,
79 struct de_dfilter_in_params *dcmpri, struct de_dfilter_out_params *dcmpro,
80 struct de_dfilter_results *dres)
82 i64 srcpos = dcmpri->pos;
83 i64 j;
84 i64 blocknum;
85 i64 blocksperrow;
86 u8 bf;
87 u8 dstb;
88 unsigned int k;
90 blocksperrow = (pg->rowbytes+7)/8;
92 for(j=0; j<pg->h; j++) {
93 i64 bytes_written_this_row = 0;
95 for(blocknum=0; blocknum<blocksperrow; blocknum++) {
96 // For each byte-per-row, we expect a lead byte, which is a
97 // bitfield that tells us which of the next 8 bytes are stored
98 // in the file, versus being copied from the previous row.
99 bf = dbuf_getbyte(dcmpri->f, srcpos++);
100 for(k=0; k<8; k++) {
101 if(bytes_written_this_row>=pg->rowbytes) break;
103 if(bf&(1<<(7-k))) {
104 // byte is present
105 dstb = dbuf_getbyte(dcmpri->f, srcpos++);
107 else {
108 // copy from previous row
109 dstb = dbuf_getbyte(dcmpro->f, dcmpro->f->len - pg->rowbytes);
111 dbuf_writebyte(dcmpro->f, dstb);
113 bytes_written_this_row++;
119 // Note that this is distinct from ImageViewer RLE compression.
120 static void do_decompress_rle_compression(deark *c, struct de_dfilter_in_params *dcmpri,
121 struct de_dfilter_out_params *dcmpro, struct de_dfilter_results *dres)
123 i64 srcpos = dcmpri->pos;
125 while(srcpos <= (dcmpri->pos + dcmpri->len - 2)) {
126 i64 count;
127 u8 val;
129 count = (i64)dbuf_getbyte_p(dcmpri->f, &srcpos);
130 val = dbuf_getbyte_p(dcmpri->f, &srcpos);
131 dbuf_write_run(dcmpro->f, val, count);
135 static void make_stdpal256(deark *c, lctx *d, u32 *stdpal)
137 unsigned int k;
138 static const u32 supplpal[15] = {0x111111,
139 0x222222,0x444444,0x555555,0x777777,0x888888,0xaaaaaa,0xbbbbbb,0xdddddd,
140 0xeeeeee,0xc0c0c0,0x800000,0x800080,0x008000,0x008080};
141 static u8 vals[6] = {0xff, 0xcc, 0x99, 0x66, 0x33, 0x00};
143 for(k=0; k<215; k++) {
144 u8 r, g, b;
145 r = vals[(k%108)/18];
146 g = vals[k%6];
147 b = vals[(k/108)*3 + (k%18)/6];
148 stdpal[k] = DE_MAKE_RGB(r, g, b);
150 for(k=215; k<230; k++) {
151 stdpal[k] = DE_MAKE_OPAQUE(supplpal[k-215]);
153 for(k=230; k<256; k++) {
154 stdpal[k] = DE_STOCKCOLOR_BLACK;
158 static void do_generate_unc_image(deark *c, lctx *d, struct page_ctx *pg,
159 dbuf *unc_pixels)
161 i64 i, j;
162 i64 pdwidth;
163 u8 b;
164 u8 b_adj;
165 u32 clr;
166 int has_color;
167 de_bitmap *img = NULL;
168 u32 stdpal[256];
170 has_color = (pg->bitsperpixel>4 || pg->has_custom_pal);
172 if(pg->bitsperpixel==1 && !has_color) {
173 de_convert_and_write_image_bilevel2(unc_pixels, 0, pg->w, pg->h, pg->rowbytes,
174 DE_CVTF_WHITEISZERO, NULL, 0);
175 goto done;
178 make_stdpal256(c, d, stdpal);
180 pdwidth = (pg->rowbytes*8) / pg->bitsperpixel;
181 if(pdwidth<pg->w) pdwidth = pg->w;
183 img = de_bitmap_create2(c, pg->w, pdwidth, pg->h,
184 (has_color?3:1) + (pg->has_trns?1:0));
186 for(j=0; j<pg->h; j++) {
187 for(i=0; i<pdwidth; i++) {
188 if(pg->bitsperpixel==16) {
189 u32 clr1;
190 clr1 = (u32)dbuf_getu16be(unc_pixels, pg->rowbytes*j + 2*i);
191 clr = de_rgb565_to_888(clr1);
192 de_bitmap_setpixel_rgb(img, i, j, clr);
193 if(pg->has_trns && clr1==pg->trns_value) {
194 de_bitmap_setsample(img, i, j, 3, 0);
197 else {
198 b = de_get_bits_symbol(unc_pixels, pg->bitsperpixel, pg->rowbytes*j, i);
199 if(has_color) {
200 if(pg->has_custom_pal)
201 clr = pg->custom_pal[(unsigned int)b];
202 else
203 clr = stdpal[(unsigned int)b];
205 else {
206 // TODO: What are the correct colors (esp. for 4bpp)?
207 b_adj = 255 - de_sample_nbit_to_8bit(pg->bitsperpixel, (unsigned int)b);
208 clr = DE_MAKE_GRAY(b_adj);
211 de_bitmap_setpixel_rgb(img, i, j, clr);
213 if(pg->has_trns && (u32)b==pg->trns_value) {
214 de_bitmap_setsample(img, i, j, 3, 0);
220 de_bitmap_write_to_file(img, NULL, 0);
222 done:
223 de_bitmap_destroy(img);
226 static int de_decompress_image(deark *c, lctx *d, struct page_ctx *pg,
227 dbuf *inf, i64 pos, i64 len, dbuf *unc_pixels)
229 struct de_dfilter_in_params dcmpri;
230 struct de_dfilter_out_params dcmpro;
231 struct de_dfilter_results dres;
232 int retval = 0;
234 de_dfilter_init_objects(c, &dcmpri, &dcmpro, &dres);
235 dcmpri.f = inf;
236 dcmpri.pos = pos;
237 dcmpri.len = len;
238 dcmpro.f = unc_pixels;
240 if(pg->cmpr_type==PCMPR_SCANLINE) {
241 do_decompress_scanline_compression(c, d, pg, &dcmpri, &dcmpro, &dres);
243 else if(pg->cmpr_type==PCMPR_RLE) {
244 do_decompress_rle_compression(c, &dcmpri, &dcmpro, &dres);
246 else if(pg->cmpr_type==PCMPR_PACKBITS8) {
247 fmtutil_decompress_packbits_ex(c, &dcmpri, &dcmpro, &dres, NULL);
249 else if(pg->cmpr_type==PCMPR_PACKBITS16) {
250 struct de_packbits_params pbparams;
252 de_zeromem(&pbparams, sizeof(struct de_packbits_params));
253 pbparams.is_packbits16 = 1;
254 fmtutil_decompress_packbits_ex(c, &dcmpri, &dcmpro, &dres, &pbparams);
256 else {
257 de_err(c, "Unsupported compression type: %u", pg->cmpr_type_field);
258 goto done;
261 if(dres.errcode) {
262 de_err(c, "%s", de_dfilter_get_errmsg(c, &dres));
263 goto done;
266 // TODO: The byte counts in this message are not very accurate.
267 de_dbg(c, "decompressed %"I64_FMT" bytes to %"I64_FMT" bytes", len,
268 unc_pixels->len);
269 retval = 1;
271 done:
272 return retval;
275 // A wrapper that decompresses the image if necessary, then calls do_generate_unc_image().
276 static void do_generate_image(deark *c, lctx *d, struct page_ctx *pg,
277 dbuf *inf, i64 pos, i64 len)
279 dbuf *unc_pixels = NULL;
280 i64 expected_num_uncmpr_image_bytes;
282 expected_num_uncmpr_image_bytes = pg->rowbytes*pg->h;
284 if(pg->cmpr_type==PCMPR_NONE) {
285 if(expected_num_uncmpr_image_bytes > len) {
286 de_warn(c, "Not enough data for image");
288 unc_pixels = dbuf_open_input_subfile(inf, pos, len);
290 else {
291 i64 cmpr_len;
292 i64 hdr_len;
294 if(pg->bitmapversion >= 3) {
295 hdr_len = 4;
296 cmpr_len = dbuf_getu32x(inf, pos, d->is_le);
298 else {
299 hdr_len = 2;
300 cmpr_len = dbuf_getu16x(inf, pos, d->is_le);
302 de_dbg(c, "cmpr len: %d", (int)cmpr_len);
303 if(cmpr_len < len) {
304 // Reduce the number of available bytes, based on the cmpr_len field.
305 len = cmpr_len;
307 // Account for the size of the cmpr_len field.
308 pos += hdr_len;
309 len -= hdr_len;
310 if(len<0) goto done;
312 unc_pixels = dbuf_create_membuf(c, expected_num_uncmpr_image_bytes, 1);
314 if(!de_decompress_image(c, d, pg, inf, pos, len, unc_pixels)) {
315 goto done;
319 do_generate_unc_image(c, d, pg, unc_pixels);
321 done:
322 dbuf_close(unc_pixels);
325 static const char *get_cmpr_type_name(enum palm_cmpr_type cmpr_type)
327 const char *name;
329 switch(cmpr_type) {
330 case PCMPR_NONE: name = "none"; break;
331 case PCMPR_SCANLINE: name = "ScanLine"; break;
332 case PCMPR_RLE: name = "RLE"; break;
333 case PCMPR_PACKBITS8: name = "PackBits"; break;
334 case PCMPR_PACKBITS16: name = "PackBits16"; break;
335 default: name = "?"; break;
337 return name;
340 static int read_BitmapType_colortable(deark *c, lctx *d, struct page_ctx *pg,
341 i64 pos1, i64 *bytes_consumed)
343 i64 num_entries_raw;
344 i64 num_entries;
345 i64 k;
346 i64 pos = pos1;
347 unsigned int idx;
348 char tmps[32];
350 de_dbg(c, "color table at %d", (int)pos1);
351 de_dbg_indent(c, 1);
353 num_entries_raw = dbuf_getu16x(c->infile, pos1, d->is_le);
354 num_entries = num_entries_raw;
355 // TODO: Documentation says "High bits (numEntries > 256) reserved."
356 // What exactly does that mean?
357 if(num_entries_raw>256) {
358 // Files with "4096" entries have been observed, but they actually have 256
359 // entries.
360 if(num_entries_raw!=4096) {
361 de_warn(c, "This image's color table type might not be supported correctly");
363 num_entries = 256;
365 if(num_entries==num_entries_raw) {
366 de_dbg(c, "number of entries: %d", (int)num_entries);
368 else {
369 de_dbg(c, "number of entries: 0x%04x (assuming %d)", (unsigned int)num_entries_raw,
370 (int)num_entries);
373 pos += 2;
375 if(num_entries>0) {
376 // The only custom palettes I've seen in the wild have either 0 (!) or
377 // 256 entries.
378 // TODO: It might be better to treat all <=8 bit images as paletted:
379 // Start with a default palette, then overlay it with any custom
380 // palette entries that exist.
381 pg->has_custom_pal = 1;
384 *bytes_consumed = 2+4*num_entries;
386 for(k=0; k<num_entries && k<256; k++) {
387 idx = (unsigned int)de_getbyte(pos);
388 de_snprintf(tmps, sizeof(tmps), ",idx=%u", idx);
389 // Not entirely sure if we should set entry #k, or entry #idx.
390 // idx is documented as "The index of this color in the color table."
391 pg->custom_pal[idx] = dbuf_getRGB(c->infile, pos+1, 0);
392 de_dbg_pal_entry2(c, k, pg->custom_pal[idx], NULL, tmps, NULL);
393 pos += 4;
396 de_dbg_indent(c, -1);
397 return 1;
400 static void do_BitmapDirectInfoType(deark *c, lctx *d, struct page_ctx *pg,
401 i64 pos)
403 u8 cbits[3];
404 u8 t[4];
406 de_dbg(c, "BitmapDirectInfoType structure at %d", (int)pos);
407 de_dbg_indent(c, 1);
408 cbits[0] = de_getbyte(pos);
409 cbits[1] = de_getbyte(pos+1);
410 cbits[2] = de_getbyte(pos+2);
411 de_dbg(c, "bits/component: %d,%d,%d", (int)cbits[0], (int)cbits[1], (int)cbits[2]);
413 t[0] = de_getbyte(pos+4);
414 t[1] = de_getbyte(pos+5);
415 t[2] = de_getbyte(pos+6);
416 t[3] = de_getbyte(pos+7);
417 de_dbg(c, "transparentColor: (%d,%d,%d,idx=%d)", (int)t[1], (int)t[2],
418 (int)t[3], (int)t[0]);
419 if(pg->has_trns) {
420 // The format of this field (RGBColorType) is not the same as that of
421 // the actual pixels, and I can't find documentation that says how the
422 // mapping is done.
423 // This appears to work (though it's quick & dirty, and only supports
424 // RGB565).
425 pg->trns_value =
426 ((((u32)t[1])&0xf8)<<8) |
427 ((((u32)t[2])&0xfc)<<3) |
428 ((((u32)t[3])&0xf8)>>3);
430 de_dbg_indent(c, -1);
433 static void do_palm_BitmapType_internal(deark *c, lctx *d, i64 pos1, i64 len,
434 i64 *pnextbitmapoffset)
436 i64 x;
437 i64 pos;
438 u32 bitmapflags;
439 u8 pixelsize_raw;
440 u8 pixelformat = 0; // V3 only
441 i64 headersize;
442 i64 needed_rowbytes;
443 i64 bytes_consumed;
444 i64 nextbitmapoffs_in_bytes = 0;
445 const char *cmpr_type_src_name = "";
446 const char *bpp_src_name = "";
447 struct page_ctx *pg = NULL;
448 int saved_indent_level;
449 de_ucstring *flagsdescr;
450 char tmps[80];
452 de_dbg_indent_save(c, &saved_indent_level);
453 pg = de_malloc(c, sizeof(struct page_ctx));
455 de_dbg(c, "BitmapType at %d, len"DE_CHAR_LEQ"%d", (int)pos1, (int)len);
456 de_dbg_indent(c, 1);
457 de_dbg(c, "bitmap header at %d", (int)pos1);
458 de_dbg_indent(c, 1);
460 // Look ahead to get the version
461 pg->bitmapversion = de_getbyte(pos1+9);
462 de_dbg(c, "bitmap version: %d", (int)pg->bitmapversion);
464 if(pg->bitmapversion>3) {
465 // Note that V3 allows the high bit of the version field to
466 // be set (to mean little-endian), but we don't support that.
467 de_err(c, "Unsupported bitmap version: %d", (int)pg->bitmapversion);
468 goto done;
471 pg->w = dbuf_geti16x(c->infile, pos1, d->is_le);
472 pg->h = dbuf_geti16x(c->infile, pos1+2, d->is_le);
473 de_dbg_dimensions(c, pg->w, pg->h);
475 pg->rowbytes = dbuf_getu16x(c->infile, pos1+4, d->is_le);
476 de_dbg(c, "rowBytes: %d", (int)pg->rowbytes);
478 bitmapflags = (u32)dbuf_getu16x(c->infile, pos1+6, d->is_le);
479 flagsdescr = ucstring_create(c);
480 if(bitmapflags&PALMBMPFLAG_COMPRESSED) ucstring_append_flags_item(flagsdescr, "compressed");
481 if(bitmapflags&PALMBMPFLAG_HASCOLORTABLE) ucstring_append_flags_item(flagsdescr, "hasColorTable");
482 if(bitmapflags&PALMBMPFLAG_HASTRNS) ucstring_append_flags_item(flagsdescr, "hasTransparency");
483 if(bitmapflags&PALMBMPFLAG_DIRECTCOLOR) ucstring_append_flags_item(flagsdescr, "directColor");
484 if(bitmapflags==0) ucstring_append_flags_item(flagsdescr, "none");
485 de_dbg(c, "bitmap flags: 0x%04x (%s)", (unsigned int)bitmapflags,
486 ucstring_getpsz(flagsdescr));
487 ucstring_destroy(flagsdescr);
488 if((bitmapflags&PALMBMPFLAG_HASCOLORTABLE) && d->ignore_color_table_flag) {
489 bitmapflags -= PALMBMPFLAG_HASCOLORTABLE;
491 if((bitmapflags&PALMBMPFLAG_HASCOLORTABLE) && pg->bitmapversion<1) {
492 de_warn(c, "BitmapTypeV%d with a color table is not standard", (int)pg->bitmapversion);
495 if(pg->bitmapversion>=1) {
496 pixelsize_raw = de_getbyte(pos1+8);
497 de_dbg(c, "pixelSize: %d", (int)pixelsize_raw);
498 bpp_src_name = "based on pixelSize field";
499 if(pg->bitmapversion<2 && pixelsize_raw==8) {
500 de_warn(c, "BitmapTypeV%d with pixelSize=%d is not standard",
501 (int)pg->bitmapversion, (int)pixelsize_raw);
504 else {
505 pixelsize_raw = 0;
507 if(pixelsize_raw==0) {
508 pg->bitsperpixel = 1;
509 bpp_src_name = "default";
511 else pg->bitsperpixel = (i64)pixelsize_raw;
512 de_dbg(c, "bits/pixel: %d (%s)", (int)pg->bitsperpixel, bpp_src_name);
514 if(pg->bitmapversion==1 || pg->bitmapversion==2) {
515 x = dbuf_getu16x(c->infile, pos1+10, d->is_le);
516 nextbitmapoffs_in_bytes = 4*x;
517 if(x==0) {
518 de_snprintf(tmps, sizeof(tmps), "none");
520 else {
521 de_snprintf(tmps, sizeof(tmps), "%d + 4"DE_CHAR_TIMES"%d = %d", (int)pos1, (int)x, (int)(pos1+nextbitmapoffs_in_bytes));
523 de_dbg(c, "nextDepthOffset: %d (%s)", (int)x, tmps);
526 if(pg->bitmapversion<3) {
527 headersize = 16;
529 else {
530 headersize = (i64)de_getbyte(pos1+10);
531 de_dbg(c, "header size: %d", (int)headersize);
534 if(pg->bitmapversion==3) {
535 pixelformat = de_getbyte(pos1+11);
536 de_dbg(c, "pixel format: %d", (int)pixelformat);
539 if(pg->bitmapversion==2 && (bitmapflags&PALMBMPFLAG_HASTRNS)) {
540 pg->has_trns = 1;
541 pg->trns_value = (u32)de_getbyte(pos1+12);
542 de_dbg(c, "transparent color: %u", (unsigned int)pg->trns_value);
545 cmpr_type_src_name = "flags";
546 if(bitmapflags&PALMBMPFLAG_COMPRESSED) {
547 if(pg->bitmapversion>=2) {
548 pg->cmpr_type_field = (unsigned int)de_getbyte(pos1+13);
549 cmpr_type_src_name = "flags + compression type field";
550 de_dbg(c, "compression type field: 0x%02x", pg->cmpr_type_field);
551 switch(pg->cmpr_type_field) {
552 case CMPR_FIELD_SCANLINE:
553 pg->cmpr_type = PCMPR_SCANLINE;
554 break;
555 case CMPR_FIELD_RLE:
556 pg->cmpr_type = PCMPR_RLE;
557 break;
558 case CMPR_FIELD_PACKBITS:
559 cmpr_type_src_name = "flags + compression type field + pixelSize";
560 if(pg->bitsperpixel==16) {
561 pg->cmpr_type = PCMPR_PACKBITS16;
563 else {
564 pg->cmpr_type = PCMPR_PACKBITS8;
566 break;
567 default:
568 pg->cmpr_type = PCMPR_UNKNOWN;
571 else {
572 // V1 & V2 have no cmpr_type field, but can still be compressed.
573 pg->cmpr_type = PCMPR_SCANLINE;
576 else {
577 pg->cmpr_type = PCMPR_NONE;
580 de_dbg(c, "compression type: %s (based on %s)", get_cmpr_type_name(pg->cmpr_type), cmpr_type_src_name);
582 if(pg->bitmapversion==3) {
583 i64 densitycode;
584 densitycode = dbuf_getu16x(c->infile, pos1+14, d->is_le);
585 de_dbg(c, "density: %d", (int)densitycode);
586 // The density is an indication of the target screen density.
587 // It's tempting to interpet it as pixels per inch, and copy it to the
588 // output image -- though the documentation says it "should not be
589 // interpreted as representing pixels per inch".
592 if(pg->bitmapversion==3 && (bitmapflags&PALMBMPFLAG_HASTRNS) && headersize>=20) {
593 // I'm assuming the flag affects this field. The spec is ambiguous.
594 pg->has_trns = 1;
595 pg->trns_value = (u32)dbuf_getu32x(c->infile, pos1+16, d->is_le);
596 de_dbg(c, "transparent color: 0x%08x", (unsigned int)pg->trns_value);
599 if(pg->bitmapversion==3 && headersize>=24) {
600 // Documented as the "number of bytes to the next bitmap", but it doesn't
601 // say where it is measured *from*. I'll assume it's the same logic as
602 // the "nextDepthOffset" field.
603 nextbitmapoffs_in_bytes = dbuf_getu32x(c->infile, pos1+20, d->is_le);
604 if(nextbitmapoffs_in_bytes==0) {
605 de_snprintf(tmps, sizeof(tmps), "none");
607 else {
608 de_snprintf(tmps, sizeof(tmps), "%u + %u = %u", (unsigned int)pos1,
609 (unsigned int)nextbitmapoffs_in_bytes, (unsigned int)(pos1+nextbitmapoffs_in_bytes));
611 de_dbg(c, "nextBitmapOffset: %u (%s)", (unsigned int)nextbitmapoffs_in_bytes, tmps);
614 // Now that we've read the nextBitmapOffset fields, we can stop processing this
615 // image if it's invalid or unsupported.
617 needed_rowbytes = (pg->w * pg->bitsperpixel +7)/8;
618 if(pg->rowbytes < needed_rowbytes) {
619 de_err(c, "Bad rowBytes value (is %d, need at least %d) or unsupported format version",
620 (int)pg->rowbytes, (int)needed_rowbytes);
621 goto done;
624 if(!de_good_image_dimensions(c, pg->w, pg->h)) goto done;
626 de_dbg_indent(c, -1);
628 if(bitmapflags&PALMBMPFLAG_DIRECTCOLOR) {
629 pg->is_rgb = 1;
630 if(pg->bitmapversion<2) {
631 de_warn(c, "BitmapTypeV%d with RGB color is not standard", (int)pg->bitmapversion);
635 if(pg->bitmapversion>=3) {
636 if(pixelformat>1 ||
637 (pixelformat==0 && pg->bitsperpixel>8) ||
638 (pixelformat==1 && pg->bitsperpixel!=16))
640 de_err(c, "Unsupported pixelFormat (%d) for this image", (int)pixelformat);
641 goto done;
644 if(pixelformat==1 && pg->bitsperpixel==16) {
645 // This should have already been set, by PALMBMPFLAG_DIRECTCOLOR,
646 // but that flag seems kind of obsolete in V3.
647 pg->is_rgb = 1;
651 if(pg->bitmapversion==2 && pg->bitsperpixel==16 &&
652 !(bitmapflags&PALMBMPFLAG_DIRECTCOLOR) && !(bitmapflags&PALMBMPFLAG_HASCOLORTABLE))
654 // I have some images like this. I guess they are standard RGB565, with no
655 // BitmapDirectInfoType header.
656 pg->is_rgb = 1;
657 de_warn(c, "This type of image (16-bit, without directColor flag) might "
658 "not be decoded correctly");
661 if(pg->bitsperpixel!=1 && pg->bitsperpixel!=2 && pg->bitsperpixel!=4 &&
662 pg->bitsperpixel!=8 && pg->bitsperpixel!=16)
664 de_err(c, "Unsupported bits/pixel: %d", (int)pg->bitsperpixel);
665 goto done;
668 if((pg->is_rgb && pg->bitsperpixel!=16) ||
669 (!pg->is_rgb && pg->bitsperpixel>8))
671 de_err(c, "This type of image is not supported");
672 goto done;
675 pos = pos1;
676 pos += headersize;
677 if(pos >= pos1+len) goto done;
679 if(bitmapflags&PALMBMPFLAG_HASCOLORTABLE) {
680 if(!read_BitmapType_colortable(c, d, pg, pos, &bytes_consumed)) goto done;
681 pos += bytes_consumed;
684 // If there is both a color table and a DirectInfo struct, I don't know which
685 // one appears first. But that shouldn't happen.
686 if((bitmapflags&PALMBMPFLAG_DIRECTCOLOR) && (pg->bitmapversion<=2)) {
687 do_BitmapDirectInfoType(c, d, pg, pos);
688 pos += 8;
691 if(pos >= pos1+len) {
692 de_err(c, "Unexpected end of file");
693 goto done;
696 de_dbg(c, "image data at %d", (int)pos);
697 de_dbg_indent(c, 1);
698 do_generate_image(c, d, pg, c->infile, pos, pos1+len-pos);
699 de_dbg_indent(c, -1);
701 done:
702 *pnextbitmapoffset = nextbitmapoffs_in_bytes;
703 de_dbg_indent_restore(c, saved_indent_level);
704 if(pg) {
705 de_free(c, pg);
709 static void do_palm_BitmapType(deark *c, lctx *d, i64 pos1, i64 len)
711 i64 nextbitmapoffs = 0;
712 i64 pos = pos1;
714 while(1) {
715 if(de_getbyte(pos+8) == 0xff) {
716 de_dbg(c, "[skipping dummy bitmap header at %d]", (int)pos);
717 pos += 16;
720 if(pos > pos1+len-16) {
721 de_err(c, "Bitmap exceeds its bounds");
722 break;
724 do_palm_BitmapType_internal(c, d, pos, pos1+len-pos, &nextbitmapoffs);
725 if(nextbitmapoffs<=0) break;
726 pos += nextbitmapoffs;
730 static void de_run_palmbitmap(deark *c, de_module_params *mparams)
732 lctx *d = NULL;
734 d = de_malloc(c, sizeof(lctx));
735 if(de_get_ext_option(c, "palm:le")) {
736 d->is_le = 1;
738 if(de_get_ext_option(c, "palm:nocolortable")) {
739 // Enables a hack, for files that apparently set the hasColorTable flag
740 // incorrectly
741 d->ignore_color_table_flag = 1;
743 do_palm_BitmapType(c, d, 0, c->infile->len);
744 de_free(c, d);
747 static int de_identify_palmbitmap(deark *c)
749 if(de_input_file_has_ext(c, "palm")) {
750 int x;
751 x = de_identify_palmbitmap_internal(c, c->infile, 0, c->infile->len);
752 if(x) return 90;
754 return 0;
757 static void de_help_palmbitmap(deark *c)
759 de_msg(c, "-opt palm:le : Assume little-endian byte order");
760 de_msg(c, "-opt palm:nocolortable : Ignore the hasColorTable flag, if set");
763 void de_module_palmbitmap(deark *c, struct deark_module_info *mi)
765 mi->id = "palmbitmap";
766 mi->desc = "Palm BitmapType";
767 mi->run_fn = de_run_palmbitmap;
768 mi->identify_fn = de_identify_palmbitmap;
769 mi->help_fn = de_help_palmbitmap;