bmp: Rewrote the RLE decompressor
[deark.git] / modules / palmbitmap.c
blob264db12de255daed7d47f91eeb403fef9f1a3711
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 i64 endpos;
39 i64 expected_num_uncmpr_image_bytes;
40 u32 custom_pal[256];
43 typedef struct localctx_struct {
44 int is_le;
45 int ignore_color_table_flag;
46 } lctx;
48 static int de_identify_palmbitmap_internal(deark *c, dbuf *f, i64 pos, i64 len)
50 i64 w, h;
51 i64 rowbytes;
52 u8 ver;
53 u8 pixelsize;
55 pixelsize = de_getbyte(pos+8);
56 if(pixelsize==0xff) {
57 pos += 16;
60 ver = de_getbyte(pos+9);
61 if(ver>3) return 0;
62 w = dbuf_getu16be(f, pos+0);
63 h = dbuf_getu16be(f, pos+2);
64 if(w==0 || h==0) return 0;
65 rowbytes = dbuf_getu16be(f, pos+4);
66 pixelsize = de_getbyte(pos+8);
67 if((pixelsize==0 && ver==0) || pixelsize==1 || pixelsize==2 ||
68 pixelsize==4 || pixelsize==8 || pixelsize==16)
72 else {
73 return 0;
75 if(rowbytes==0 || (rowbytes&0x1)) return 0;
76 // TODO: Make sure rowbytes is sensible
77 return 1;
80 static void do_decompress_scanline_compression(deark *c, lctx *d, struct page_ctx *pg,
81 struct de_dfilter_in_params *dcmpri, struct de_dfilter_out_params *dcmpro,
82 struct de_dfilter_results *dres)
84 i64 srcpos = dcmpri->pos;
85 i64 j;
86 i64 blocknum;
87 i64 blocksperrow;
88 i64 nbytes_written = 0;
89 u8 bf;
90 u8 dstb;
91 unsigned int k;
93 blocksperrow = (pg->rowbytes+7)/8;
95 for(j=0; j<pg->h; j++) {
96 i64 bytes_written_this_row = 0;
98 if(nbytes_written >= dcmpro->expected_len) goto done;
100 for(blocknum=0; blocknum<blocksperrow; blocknum++) {
101 // For each byte-per-row, we expect a lead byte, which is a
102 // bitfield that tells us which of the next 8 bytes are stored
103 // in the file, versus being copied from the previous row.
104 bf = dbuf_getbyte(dcmpri->f, srcpos++);
105 for(k=0; k<8; k++) {
106 if(bytes_written_this_row>=pg->rowbytes) break;
108 if(bf&(1<<(7-k))) {
109 // byte is present
110 dstb = dbuf_getbyte(dcmpri->f, srcpos++);
112 else {
113 // copy from previous row
114 dstb = dbuf_getbyte(dcmpro->f, dcmpro->f->len - pg->rowbytes);
116 dbuf_writebyte(dcmpro->f, dstb);
118 bytes_written_this_row++;
119 nbytes_written++;
123 done:
124 dres->bytes_consumed = srcpos - dcmpri->pos;
125 dres->bytes_consumed_valid = 1;
128 // Note that this is distinct from ImageViewer RLE compression.
129 static void do_decompress_rle_compression(deark *c, struct de_dfilter_in_params *dcmpri,
130 struct de_dfilter_out_params *dcmpro, struct de_dfilter_results *dres)
132 i64 srcpos = dcmpri->pos;
133 i64 nbytes_written = 0;
135 while(srcpos <= (dcmpri->pos + dcmpri->len - 2)) {
136 i64 count;
137 u8 val;
139 if(nbytes_written > dcmpro->expected_len) goto done;
140 count = (i64)dbuf_getbyte_p(dcmpri->f, &srcpos);
141 val = dbuf_getbyte_p(dcmpri->f, &srcpos);
142 dbuf_write_run(dcmpro->f, val, count);
143 nbytes_written += count;
145 done:
146 dres->bytes_consumed = srcpos - dcmpri->pos;
147 dres->bytes_consumed_valid = 1;
150 static void make_stdpal256(deark *c, lctx *d, u32 *stdpal)
152 unsigned int k;
153 static const u32 supplpal[15] = {0x111111,
154 0x222222,0x444444,0x555555,0x777777,0x888888,0xaaaaaa,0xbbbbbb,0xdddddd,
155 0xeeeeee,0xc0c0c0,0x800000,0x800080,0x008000,0x008080};
156 static u8 vals[6] = {0xff, 0xcc, 0x99, 0x66, 0x33, 0x00};
158 for(k=0; k<215; k++) {
159 u8 r, g, b;
160 r = vals[(k%108)/18];
161 g = vals[k%6];
162 b = vals[(k/108)*3 + (k%18)/6];
163 stdpal[k] = DE_MAKE_RGB(r, g, b);
165 for(k=215; k<230; k++) {
166 stdpal[k] = DE_MAKE_OPAQUE(supplpal[k-215]);
168 for(k=230; k<256; k++) {
169 stdpal[k] = DE_STOCKCOLOR_BLACK;
173 static void do_generate_img_from_unc_pixels(deark *c, lctx *d, struct page_ctx *pg,
174 dbuf *unc_pixels)
176 i64 i, j;
177 i64 pdwidth;
178 u32 clr;
179 int has_color;
180 de_bitmap *img = NULL;
181 u32 pal[256];
183 de_zeromem(pal, sizeof(pal));
184 has_color = (pg->bitsperpixel>4 || pg->has_custom_pal);
186 if(pg->bitsperpixel==1 && !has_color) {
187 de_convert_and_write_image_bilevel2(unc_pixels, 0, pg->w, pg->h, pg->rowbytes,
188 DE_CVTF_WHITEISZERO, NULL, 0);
189 goto done;
192 pdwidth = (pg->rowbytes*8) / pg->bitsperpixel;
193 if(pdwidth<pg->w) pdwidth = pg->w;
195 img = de_bitmap_create2(c, pg->w, pdwidth, pg->h,
196 (has_color?3:1) + (pg->has_trns?1:0));
198 if(pg->bitsperpixel==16) {
199 for(j=0; j<pg->h; j++) {
200 for(i=0; i<pdwidth; i++) {
201 u32 clr1;
202 clr1 = (u32)dbuf_getu16be(unc_pixels, pg->rowbytes*j + 2*i);
203 clr = de_rgb565_to_888(clr1);
204 de_bitmap_setpixel_rgb(img, i, j, clr);
205 if(pg->has_trns && clr1==pg->trns_value) {
206 de_bitmap_setsample(img, i, j, 3, 0);
211 else {
212 if(!has_color) {
213 if(pg->bitsperpixel>8) goto done;
214 // TODO: What are the correct colors (esp. for 4bpp)?
215 de_make_grayscale_palette(pal, 1ULL<<pg->bitsperpixel, 0x1);
217 else if(pg->has_custom_pal) {
218 de_memcpy(pal, pg->custom_pal, sizeof(pg->custom_pal));
220 else {
221 make_stdpal256(c, d, pal);
224 if(pg->has_trns && pg->trns_value<256) {
225 pal[pg->trns_value] = DE_SET_ALPHA(pal[pg->trns_value], 0);
228 de_convert_image_paletted(unc_pixels, 0,pg->bitsperpixel, pg->rowbytes,
229 pal, img, 0);
232 de_bitmap_write_to_file(img, NULL, DE_CREATEFLAG_OPT_IMAGE);
234 done:
235 de_bitmap_destroy(img);
238 static int de_decompress_image(deark *c, lctx *d, struct page_ctx *pg,
239 dbuf *inf, i64 pos, i64 len, dbuf *unc_pixels)
241 struct de_dfilter_in_params dcmpri;
242 struct de_dfilter_out_params dcmpro;
243 struct de_dfilter_results dres;
244 int retval = 0;
245 i64 n;
247 de_dfilter_init_objects(c, &dcmpri, &dcmpro, &dres);
248 dcmpri.f = inf;
249 dcmpri.pos = pos;
250 dcmpri.len = len;
251 dcmpro.f = unc_pixels;
252 dcmpro.expected_len = pg->expected_num_uncmpr_image_bytes;
253 dcmpro.len_known = 1;
255 if(pg->cmpr_type==PCMPR_SCANLINE) {
256 do_decompress_scanline_compression(c, d, pg, &dcmpri, &dcmpro, &dres);
258 else if(pg->cmpr_type==PCMPR_RLE) {
259 dbuf_enable_wbuffer(unc_pixels);
260 do_decompress_rle_compression(c, &dcmpri, &dcmpro, &dres);
262 else if(pg->cmpr_type==PCMPR_PACKBITS8) {
263 dbuf_enable_wbuffer(unc_pixels);
264 fmtutil_decompress_packbits_ex(c, &dcmpri, &dcmpro, &dres, NULL);
266 else if(pg->cmpr_type==PCMPR_PACKBITS16) {
267 struct de_packbits_params pbparams;
269 de_zeromem(&pbparams, sizeof(struct de_packbits_params));
270 pbparams.nbytes_per_unit = 2;
271 dbuf_enable_wbuffer(unc_pixels);
272 fmtutil_decompress_packbits_ex(c, &dcmpri, &dcmpro, &dres, &pbparams);
274 else {
275 de_err(c, "Unsupported compression type: %u", pg->cmpr_type_field);
276 goto done;
279 dbuf_flush(unc_pixels);
281 if(dres.errcode) {
282 de_err(c, "%s", de_dfilter_get_errmsg(c, &dres));
283 goto done;
286 if(dres.bytes_consumed_valid) {
287 n = dres.bytes_consumed;
289 else {
290 n = len;
293 de_dbg(c, "decompressed %"I64_FMT" bytes to %"I64_FMT" bytes", n,
294 unc_pixels->len);
295 retval = 1;
297 done:
298 return retval;
301 // A wrapper that decompresses the image if necessary, then calls
302 // do_generate_img_from_unc_pixels().
303 static void do_generate_image(deark *c, lctx *d, struct page_ctx *pg,
304 dbuf *inf, i64 pos, i64 len)
306 dbuf *unc_pixels = NULL;
308 pg->expected_num_uncmpr_image_bytes = pg->rowbytes*pg->h;
310 if(pg->cmpr_type==PCMPR_NONE) {
311 if(pg->expected_num_uncmpr_image_bytes > len) {
312 de_err(c, "Not enough data for image");
313 goto done;
315 unc_pixels = dbuf_open_input_subfile(inf, pos, len);
317 else {
318 i64 cmpr_len;
319 i64 hdr_len;
321 if(pg->bitmapversion >= 3) {
322 hdr_len = 4;
323 cmpr_len = dbuf_getu32x(inf, pos, d->is_le);
325 else {
326 hdr_len = 2;
327 cmpr_len = dbuf_getu16x(inf, pos, d->is_le);
329 de_dbg(c, "cmpr len: %d", (int)cmpr_len); // Note - We don't trust this field
331 // Account for the size of the cmpr_len field.
332 pos += hdr_len;
333 len -= hdr_len;
334 if(len<0) goto done;
336 unc_pixels = dbuf_create_membuf(c, pg->expected_num_uncmpr_image_bytes, 1);
338 if(!de_decompress_image(c, d, pg, inf, pos, len, unc_pixels)) {
339 goto done;
343 do_generate_img_from_unc_pixels(c, d, pg, unc_pixels);
345 done:
346 dbuf_close(unc_pixels);
349 static const char *get_cmpr_type_name(enum palm_cmpr_type cmpr_type)
351 const char *name;
353 switch(cmpr_type) {
354 case PCMPR_NONE: name = "none"; break;
355 case PCMPR_SCANLINE: name = "ScanLine"; break;
356 case PCMPR_RLE: name = "RLE"; break;
357 case PCMPR_PACKBITS8: name = "PackBits"; break;
358 case PCMPR_PACKBITS16: name = "PackBits16"; break;
359 default: name = "?"; break;
361 return name;
364 static int read_BitmapType_colortable(deark *c, lctx *d, struct page_ctx *pg,
365 i64 pos1, i64 *bytes_consumed)
367 i64 num_entries_raw;
368 i64 num_entries;
369 i64 k;
370 i64 pos = pos1;
371 unsigned int idx;
372 char tmps[32];
374 de_dbg(c, "color table at %d", (int)pos1);
375 de_dbg_indent(c, 1);
377 num_entries_raw = dbuf_getu16x(c->infile, pos1, d->is_le);
378 num_entries = num_entries_raw;
379 // TODO: Documentation says "High bits (numEntries > 256) reserved."
380 // What exactly does that mean?
381 if(num_entries_raw>256) {
382 // Files with "4096" entries have been observed, but they actually have 256
383 // entries.
384 if(num_entries_raw!=4096) {
385 de_warn(c, "This image's color table type might not be supported correctly");
387 num_entries = 256;
389 if(num_entries==num_entries_raw) {
390 de_dbg(c, "number of entries: %d", (int)num_entries);
392 else {
393 de_dbg(c, "number of entries: 0x%04x (assuming %d)", (unsigned int)num_entries_raw,
394 (int)num_entries);
397 pos += 2;
399 if(num_entries>0) {
400 // The only custom palettes I've seen in the wild have either 0 (!) or
401 // 256 entries.
402 // TODO: It might be better to treat all <=8 bit images as paletted:
403 // Start with a default palette, then overlay it with any custom
404 // palette entries that exist.
405 pg->has_custom_pal = 1;
408 *bytes_consumed = 2+4*num_entries;
410 for(k=0; k<num_entries && k<256; k++) {
411 idx = (unsigned int)de_getbyte(pos);
412 de_snprintf(tmps, sizeof(tmps), ",idx=%u", idx);
413 // Not entirely sure if we should set entry #k, or entry #idx.
414 // idx is documented as "The index of this color in the color table."
415 pg->custom_pal[idx] = dbuf_getRGB(c->infile, pos+1, 0);
416 de_dbg_pal_entry2(c, k, pg->custom_pal[idx], NULL, tmps, NULL);
417 pos += 4;
420 de_dbg_indent(c, -1);
421 return 1;
424 static void do_BitmapDirectInfoType(deark *c, lctx *d, struct page_ctx *pg,
425 i64 pos)
427 u8 cbits[3];
428 u8 t[4];
430 de_dbg(c, "BitmapDirectInfoType structure at %d", (int)pos);
431 de_dbg_indent(c, 1);
432 cbits[0] = de_getbyte(pos);
433 cbits[1] = de_getbyte(pos+1);
434 cbits[2] = de_getbyte(pos+2);
435 de_dbg(c, "bits/component: %d,%d,%d", (int)cbits[0], (int)cbits[1], (int)cbits[2]);
437 t[0] = de_getbyte(pos+4);
438 t[1] = de_getbyte(pos+5);
439 t[2] = de_getbyte(pos+6);
440 t[3] = de_getbyte(pos+7);
441 de_dbg(c, "transparentColor: (%d,%d,%d,idx=%d)", (int)t[1], (int)t[2],
442 (int)t[3], (int)t[0]);
443 if(pg->has_trns) {
444 // The format of this field (RGBColorType) is not the same as that of
445 // the actual pixels, and I can't find documentation that says how the
446 // mapping is done.
447 // This appears to work (though it's quick & dirty, and only supports
448 // RGB565).
449 pg->trns_value =
450 ((((u32)t[1])&0xf8)<<8) |
451 ((((u32)t[2])&0xfc)<<3) |
452 ((((u32)t[3])&0xf8)>>3);
454 de_dbg_indent(c, -1);
457 static void do_palm_BitmapType_internal(deark *c, lctx *d, i64 pos1, i64 len,
458 i64 *pnextbitmapoffset)
460 i64 x;
461 i64 pos;
462 u32 bitmapflags;
463 u8 pixelsize_raw;
464 u8 pixelformat = 0; // V3 only
465 i64 headersize;
466 i64 needed_rowbytes;
467 i64 bytes_consumed;
468 i64 nextbitmapoffs_in_bytes = 0;
469 const char *cmpr_type_src_name = "";
470 const char *bpp_src_name = "";
471 struct page_ctx *pg = NULL;
472 int saved_indent_level;
473 de_ucstring *flagsdescr;
474 char tmps[80];
476 de_dbg_indent_save(c, &saved_indent_level);
477 pg = de_malloc(c, sizeof(struct page_ctx));
479 de_dbg(c, "BitmapType at %"I64_FMT, pos1);
480 de_dbg_indent(c, 1);
481 de_dbg(c, "bitmap header at %"I64_FMT, pos1);
482 de_dbg_indent(c, 1);
484 // Look ahead to get the version
485 pg->bitmapversion = de_getbyte(pos1+9);
486 de_dbg(c, "bitmap version: %d", (int)pg->bitmapversion);
488 if(pg->bitmapversion>3) {
489 // Note that V3 allows the high bit of the version field to
490 // be set (to mean little-endian), but we don't support that.
491 de_err(c, "Unsupported bitmap version: %d", (int)pg->bitmapversion);
492 goto done;
495 pg->w = dbuf_geti16x(c->infile, pos1, d->is_le);
496 pg->h = dbuf_geti16x(c->infile, pos1+2, d->is_le);
497 de_dbg_dimensions(c, pg->w, pg->h);
499 pg->rowbytes = dbuf_getu16x(c->infile, pos1+4, d->is_le);
500 de_dbg(c, "rowBytes: %d", (int)pg->rowbytes);
502 bitmapflags = (u32)dbuf_getu16x(c->infile, pos1+6, d->is_le);
503 flagsdescr = ucstring_create(c);
504 if(bitmapflags&PALMBMPFLAG_COMPRESSED) ucstring_append_flags_item(flagsdescr, "compressed");
505 if(bitmapflags&PALMBMPFLAG_HASCOLORTABLE) ucstring_append_flags_item(flagsdescr, "hasColorTable");
506 if(bitmapflags&PALMBMPFLAG_HASTRNS) ucstring_append_flags_item(flagsdescr, "hasTransparency");
507 if(bitmapflags&PALMBMPFLAG_DIRECTCOLOR) ucstring_append_flags_item(flagsdescr, "directColor");
508 if(bitmapflags==0) ucstring_append_flags_item(flagsdescr, "none");
509 de_dbg(c, "bitmap flags: 0x%04x (%s)", (unsigned int)bitmapflags,
510 ucstring_getpsz(flagsdescr));
511 ucstring_destroy(flagsdescr);
512 if((bitmapflags&PALMBMPFLAG_HASCOLORTABLE) && d->ignore_color_table_flag) {
513 bitmapflags -= PALMBMPFLAG_HASCOLORTABLE;
515 if((bitmapflags&PALMBMPFLAG_HASCOLORTABLE) && pg->bitmapversion<1) {
516 de_warn(c, "BitmapTypeV%d with a color table is not standard", (int)pg->bitmapversion);
519 if(pg->bitmapversion>=1) {
520 pixelsize_raw = de_getbyte(pos1+8);
521 de_dbg(c, "pixelSize: %d", (int)pixelsize_raw);
522 bpp_src_name = "based on pixelSize field";
523 if(pg->bitmapversion<2 && pixelsize_raw==8) {
524 de_warn(c, "BitmapTypeV%d with pixelSize=%d is not standard",
525 (int)pg->bitmapversion, (int)pixelsize_raw);
528 else {
529 pixelsize_raw = 0;
531 if(pixelsize_raw==0) {
532 pg->bitsperpixel = 1;
533 bpp_src_name = "default";
535 else pg->bitsperpixel = (i64)pixelsize_raw;
536 de_dbg(c, "bits/pixel: %d (%s)", (int)pg->bitsperpixel, bpp_src_name);
538 if(pg->bitmapversion==1 || pg->bitmapversion==2) {
539 x = dbuf_getu16x(c->infile, pos1+10, d->is_le);
540 nextbitmapoffs_in_bytes = 4*x;
541 if(x==0) {
542 de_snprintf(tmps, sizeof(tmps), "none");
544 else {
545 de_snprintf(tmps, sizeof(tmps), "%d + 4"DE_CHAR_TIMES"%d = %d", (int)pos1, (int)x, (int)(pos1+nextbitmapoffs_in_bytes));
547 de_dbg(c, "nextDepthOffset: %d (%s)", (int)x, tmps);
550 if(pg->bitmapversion<3) {
551 headersize = 16;
553 else {
554 headersize = (i64)de_getbyte(pos1+10);
555 de_dbg(c, "header size: %d", (int)headersize);
558 if(pg->bitmapversion==3) {
559 pixelformat = de_getbyte(pos1+11);
560 de_dbg(c, "pixel format: %d", (int)pixelformat);
563 if(pg->bitmapversion==2 && (bitmapflags&PALMBMPFLAG_HASTRNS)) {
564 pg->has_trns = 1;
565 pg->trns_value = (u32)de_getbyte(pos1+12);
566 de_dbg(c, "transparent color: %u", (unsigned int)pg->trns_value);
569 cmpr_type_src_name = "flags";
570 if(bitmapflags&PALMBMPFLAG_COMPRESSED) {
571 if(pg->bitmapversion>=2) {
572 pg->cmpr_type_field = (unsigned int)de_getbyte(pos1+13);
573 cmpr_type_src_name = "flags + compression type field";
574 de_dbg(c, "compression type field: 0x%02x", pg->cmpr_type_field);
575 switch(pg->cmpr_type_field) {
576 case CMPR_FIELD_SCANLINE:
577 pg->cmpr_type = PCMPR_SCANLINE;
578 break;
579 case CMPR_FIELD_RLE:
580 pg->cmpr_type = PCMPR_RLE;
581 break;
582 case CMPR_FIELD_PACKBITS:
583 cmpr_type_src_name = "flags + compression type field + pixelSize";
584 if(pg->bitsperpixel==16) {
585 pg->cmpr_type = PCMPR_PACKBITS16;
587 else {
588 pg->cmpr_type = PCMPR_PACKBITS8;
590 break;
591 default:
592 pg->cmpr_type = PCMPR_UNKNOWN;
595 else {
596 // V1 & V2 have no cmpr_type field, but can still be compressed.
597 pg->cmpr_type = PCMPR_SCANLINE;
600 else {
601 pg->cmpr_type = PCMPR_NONE;
604 de_dbg(c, "compression type: %s (based on %s)", get_cmpr_type_name(pg->cmpr_type), cmpr_type_src_name);
606 if(pg->bitmapversion==3) {
607 i64 densitycode;
608 densitycode = dbuf_getu16x(c->infile, pos1+14, d->is_le);
609 de_dbg(c, "density: %d", (int)densitycode);
610 // The density is an indication of the target screen density.
611 // It's tempting to interpret it as pixels per inch, and copy it to the
612 // output image -- though the documentation says it "should not be
613 // interpreted as representing pixels per inch".
616 if(pg->bitmapversion==3 && (bitmapflags&PALMBMPFLAG_HASTRNS) && headersize>=20) {
617 // I'm assuming the flag affects this field. The spec is ambiguous.
618 pg->has_trns = 1;
619 pg->trns_value = (u32)dbuf_getu32x(c->infile, pos1+16, d->is_le);
620 de_dbg(c, "transparent color: 0x%08x", (unsigned int)pg->trns_value);
623 if(pg->bitmapversion==3 && headersize>=24) {
624 // Documented as the "number of bytes to the next bitmap", but it doesn't
625 // say where it is measured *from*. I'll assume it's the same logic as
626 // the "nextDepthOffset" field.
627 nextbitmapoffs_in_bytes = dbuf_getu32x(c->infile, pos1+20, d->is_le);
628 if(nextbitmapoffs_in_bytes==0) {
629 de_snprintf(tmps, sizeof(tmps), "none");
631 else {
632 de_snprintf(tmps, sizeof(tmps), "%u + %u = %u", (unsigned int)pos1,
633 (unsigned int)nextbitmapoffs_in_bytes, (unsigned int)(pos1+nextbitmapoffs_in_bytes));
635 de_dbg(c, "nextBitmapOffset: %u (%s)", (unsigned int)nextbitmapoffs_in_bytes, tmps);
638 // Now that we've read the nextBitmapOffset fields, we can stop processing this
639 // image if it's invalid or unsupported.
641 needed_rowbytes = (pg->w * pg->bitsperpixel +7)/8;
642 if(pg->rowbytes < needed_rowbytes) {
643 de_err(c, "Bad rowBytes value (is %d, need at least %d) or unsupported format version",
644 (int)pg->rowbytes, (int)needed_rowbytes);
645 goto done;
648 if(!de_good_image_dimensions(c, pg->w, pg->h)) goto done;
650 de_dbg_indent(c, -1);
652 if(bitmapflags&PALMBMPFLAG_DIRECTCOLOR) {
653 pg->is_rgb = 1;
654 if(pg->bitmapversion<2) {
655 de_warn(c, "BitmapTypeV%d with RGB color is not standard", (int)pg->bitmapversion);
659 if(pg->bitmapversion>=3) {
660 if(pixelformat>1 ||
661 (pixelformat==0 && pg->bitsperpixel>8) ||
662 (pixelformat==1 && pg->bitsperpixel!=16))
664 de_err(c, "Unsupported pixelFormat (%d) for this image", (int)pixelformat);
665 goto done;
668 if(pixelformat==1 && pg->bitsperpixel==16) {
669 // This should have already been set, by PALMBMPFLAG_DIRECTCOLOR,
670 // but that flag seems kind of obsolete in V3.
671 pg->is_rgb = 1;
675 if(pg->bitmapversion==2 && pg->bitsperpixel==16 &&
676 !(bitmapflags&PALMBMPFLAG_DIRECTCOLOR) && !(bitmapflags&PALMBMPFLAG_HASCOLORTABLE))
678 // I have some images like this. I guess they are standard RGB565, with no
679 // BitmapDirectInfoType header.
680 pg->is_rgb = 1;
681 de_warn(c, "This type of image (16-bit, without directColor flag) might "
682 "not be decoded correctly");
685 if(pg->bitsperpixel!=1 && pg->bitsperpixel!=2 && pg->bitsperpixel!=4 &&
686 pg->bitsperpixel!=8 && pg->bitsperpixel!=16)
688 de_err(c, "Unsupported bits/pixel: %d", (int)pg->bitsperpixel);
689 goto done;
692 if((pg->is_rgb && pg->bitsperpixel!=16) ||
693 (!pg->is_rgb && pg->bitsperpixel>8))
695 de_err(c, "This type of image is not supported");
696 goto done;
699 pos = pos1;
700 pos += headersize;
701 if(pos >= pos1+len) goto done;
703 if(bitmapflags&PALMBMPFLAG_HASCOLORTABLE) {
704 if(!read_BitmapType_colortable(c, d, pg, pos, &bytes_consumed)) goto done;
705 pos += bytes_consumed;
708 // If there is both a color table and a DirectInfo struct, I don't know which
709 // one appears first. But that shouldn't happen.
710 if((bitmapflags&PALMBMPFLAG_DIRECTCOLOR) && (pg->bitmapversion<=2)) {
711 do_BitmapDirectInfoType(c, d, pg, pos);
712 pos += 8;
715 if(pos >= pos1+len) {
716 de_err(c, "Unexpected end of file");
717 goto done;
720 if(nextbitmapoffs_in_bytes>0) {
721 pg->endpos = pos1 + nextbitmapoffs_in_bytes;
723 else {
724 pg->endpos = c->infile->len;
727 de_dbg(c, "image data at %d", (int)pos);
728 de_dbg_indent(c, 1);
729 do_generate_image(c, d, pg, c->infile, pos, pg->endpos-pos);
730 de_dbg_indent(c, -1);
732 done:
733 *pnextbitmapoffset = nextbitmapoffs_in_bytes;
734 de_dbg_indent_restore(c, saved_indent_level);
735 if(pg) {
736 de_free(c, pg);
740 static void do_palm_BitmapType(deark *c, lctx *d, i64 pos1, i64 len)
742 i64 nextbitmapoffs = 0;
743 i64 pos = pos1;
745 while(1) {
746 if(de_getbyte(pos+8) == 0xff) {
747 de_dbg(c, "[skipping dummy bitmap header at %d]", (int)pos);
748 pos += 16;
751 if(pos > pos1+len-16) {
752 de_err(c, "Bitmap exceeds its bounds");
753 break;
755 do_palm_BitmapType_internal(c, d, pos, pos1+len-pos, &nextbitmapoffs);
756 if(nextbitmapoffs<=0) break;
757 pos += nextbitmapoffs;
761 static void de_run_palmbitmap(deark *c, de_module_params *mparams)
763 lctx *d = NULL;
765 d = de_malloc(c, sizeof(lctx));
766 if(de_get_ext_option(c, "palm:le")) {
767 d->is_le = 1;
769 if(de_get_ext_option(c, "palm:nocolortable")) {
770 // Enables a hack, for files that apparently set the hasColorTable flag
771 // incorrectly
772 d->ignore_color_table_flag = 1;
774 do_palm_BitmapType(c, d, 0, c->infile->len);
775 de_free(c, d);
778 static int de_identify_palmbitmap(deark *c)
780 if(de_input_file_has_ext(c, "palm")) {
781 int x;
782 x = de_identify_palmbitmap_internal(c, c->infile, 0, c->infile->len);
783 if(x) return 90;
785 return 0;
788 static void de_help_palmbitmap(deark *c)
790 de_msg(c, "-opt palm:le : Assume little-endian byte order");
791 de_msg(c, "-opt palm:nocolortable : Ignore the hasColorTable flag, if set");
794 void de_module_palmbitmap(deark *c, struct deark_module_info *mi)
796 mi->id = "palmbitmap";
797 mi->desc = "Palm BitmapType";
798 mi->run_fn = de_run_palmbitmap;
799 mi->identify_fn = de_identify_palmbitmap;
800 mi->help_fn = de_help_palmbitmap;