1 /*
2 
3 Copyright Andy Key, Heiko Nitzsche
4 
5 gbmbmp.c - OS/2 1.1, 1.2, 2.0 and Windows 3.0 support
6 
7 Reads and writes any OS/2 1.x bitmap.
8 Will also read uncompressed, RLE4 and RLE8 Windows 3.x bitmaps too.
9 There are horrific file structure alignment considerations hence each
10 word,dword is read individually.
11 
12 */
13 
14 #include "img.h"
15 #include "Image.h"
16 
17 static char * bmpext[] = {
18 	"bmp", "vga", "bga",
19 	"rle", "dib", "rl4",
20 	"rl8", NULL,
21 };
22 
23 static int    bmpbpp[] = {
24 	imRGB,
25 	imbpp8 | imGrayScale, imbpp8,
26 	imbpp4 | imGrayScale, imbpp4,
27 	imbpp1 | imGrayScale, imbpp1,
28 	0
29 };
30 static char * bmpfeat[] = {
31 	"OS/2 BMP 1.0",
32 	"Windows BMP 1.0",
33 	"Windows BMP 2.0",
34 	"Windows BMP 3.0",
35 	"Windows BMP 3.0 RLE4",
36 	"Windows BMP 3.0 RLE8",
37 	NULL
38 };
39 
40 static char * loadOutput[] = {
41 	"HotSpotX",
42 	"HotSpotY",
43 	"OS2",
44 	"Compression",
45 	"ImportantColors",
46 	"XResolution",
47 	"YResolution",
48 	"BitDepth",
49 	NULL
50 };
51 
52 static char * mime[] = {
53 	"image/bmp",
54 	"image/x-bmp",
55 	"image/x-MS-bmp",
56 	"image/x-win-bitmap",
57 	NULL
58 };
59 
60 static ImgCodecInfo codec_info = {
61 	"Windows Bitmap",
62 	"GBM by Andy Key",
63 	1, 7,		      /* version */
64 	bmpext,		      /* extension */
65 	"Windows Bitmap",     /* file type */
66 	"BMP",		      /* short type */
67 	bmpfeat,	      /* features  */
68 	"",		      /* module */
69 	"",		      /* package */
70 	IMG_LOAD_FROM_FILE | IMG_LOAD_MULTIFRAME | IMG_LOAD_FROM_STREAM |
71 	IMG_SAVE_TO_FILE   | IMG_SAVE_TO_STREAM,
72 	bmpbpp,		      /* save types */
73 	loadOutput,
74 	mime
75 };
76 
77 static void *
init(PImgCodecInfo * info,void * param)78 init( PImgCodecInfo * info, void * param)
79 {
80 	*info = &codec_info;
81 	return (void*)1;
82 }
83 
84 #ifndef min
85 #define min(a,b)    (((a)<(b))?(a):(b))
86 #endif
87 
88 typedef uint32_t dword;
89 typedef uint16_t word;
90 typedef uint8_t  byte;
91 
92 #define low_byte(w) ((byte)  ((w)&0x00ff)    )
93 #define high_byte(w)	((byte) (((w)&0xff00)>>8))
94 #define make_word(a,b)	(((word)a) + (((word)b) << 8))
95 
96 static Bool
read_word(PImgIORequest req,word * w)97 read_word( PImgIORequest req, word *w)
98 {
99 	Byte low = 0, high = 0;
100 
101 	if ( req_read(req, 1, &low) != 1 )
102 		return false;
103 	if ( req_read(req, 1, &high) != 1 )
104 		return false;
105 	*w = (word) (low + ((word) high << 8));
106 	return true;
107 }
108 
109 static Bool
read_dword(PImgIORequest fd,dword * d)110 read_dword(PImgIORequest fd, dword *d)
111 {
112 	word low, high;
113 	if ( !read_word(fd, &low) )
114 		return false;
115 	if ( !read_word(fd, &high) )
116 		return false;
117 	*d = low + ((dword) high << 16);
118 	return true;
119 }
120 
121 
122 static Bool
write_word(PImgIORequest fd,word w)123 write_word(PImgIORequest fd, word w)
124 {
125 	byte	low  = (byte) (w & 0xFF);
126 	byte	high = (byte) (w >> 8);
127 
128 	req_write( fd, 1, &low);
129 	req_write( fd, 1, &high);
130 
131 	return true;
132 }
133 
134 static Bool
write_dword(PImgIORequest req,dword d)135 write_dword(PImgIORequest req, dword d)
136 {
137 	write_word(req, (word) (d & 0xFFFF));
138 	write_word(req, (word) (d >> 16));
139 	return true;
140 }
141 
142 #define BFT_BMAP    0x4d42
143 #define BFT_BITMAPARRAY 0x4142
144 #define BCA_UNCOMP  0x00000000L
145 #define BCA_RLE8    0x00000001L
146 #define BCA_RLE4    0x00000002L
147 #define BCA_BITFIELDS	0x00000003L
148 #define BCA_RLE24   0x00000004L
149 #define BCA_MAX     BCA_RLE24
150 #define MSWCC_EOL   0
151 #define MSWCC_EOB   1
152 #define MSWCC_DELTA 2
153 
154 static char * bca_sets[] = {
155 	"Uncompressed",
156 	"RLE8",
157 	"RLE4",
158 	"Raw bits",
159 	"RLE24"
160 };
161 
162 static void
swap_pal(RGBColor * p)163 swap_pal( RGBColor * p)
164 {
165 	RGBColor tmp = p[0];
166 	p[0] = p[1];
167 	p[1] = tmp;
168 }
169 
170 #define outc(x){ strncpy( fi-> errbuf, x, 256); return false;}
171 #define outr(fd) { snprintf( fi-> errbuf, 256, "Read error:%s",strerror( req_error( fd))); return false; }
172 #define outw(fd) { snprintf( fi-> errbuf, 256, "Write error:%s",strerror( req_error( fd))); return false; }
173 #define outs(fd) { snprintf( fi-> errbuf, 256, "Seek error:%s",strerror( req_error( fd))); return false; }
174 #define outcm(dd){ snprintf( fi-> errbuf, 256, "Not enough memory (%d bytes)", (int)(dd)); return false;}
175 #define outcd(x,dd){ snprintf( fi-> errbuf, 256, x, (int)(dd)); return false;}
176 
177 
178 #define BUFSIZE 16384
179 
180 typedef struct {
181 	byte buf[BUFSIZE];
182 	int inx, cnt, y, lasty;
183 	unsigned long ls, read;
184 	PImgLoadFileInstance fi;
185 	Bool error;
186 } AHEAD;
187 
188 static AHEAD *
create_ahead(PImgLoadFileInstance fi,unsigned long lineSize)189 create_ahead(PImgLoadFileInstance fi, unsigned long lineSize)
190 {
191 	AHEAD *ahead;
192 
193 	if ( (ahead = malloc((size_t) sizeof(AHEAD))) == NULL )
194 		return NULL;
195 
196 	ahead-> inx   = 0;
197 	ahead-> cnt   = 0;
198 	ahead-> fi    = fi;
199 	ahead-> error = false;
200 	ahead-> y     = 0;
201 	ahead-> lasty = 0;
202 	ahead-> read  = 0;
203 	ahead-> ls    = lineSize;
204 
205 	return ahead;
206 }
207 
208 /* returns true on hard failure */
209 static Bool
destroy_ahead(AHEAD * ahead)210 destroy_ahead(AHEAD *ahead)
211 {
212 	Bool error = ahead-> error;
213 	free(ahead);
214 	if (error & ahead-> fi-> wasTruncated) error = false;
215 	return error;
216 }
217 
218 static byte
read_ahead(AHEAD * ahead)219 read_ahead(AHEAD *ahead)
220 {
221 	if ( ahead-> inx >= ahead-> cnt ) {
222 		if ( ahead-> error) return 0;
223 
224 		ahead-> cnt = req_read( ahead->fi->req, BUFSIZE, ahead->buf);
225 		if ( ahead-> cnt <= 0 ) {
226 			snprintf( ahead->fi-> errbuf, 256,
227 				"Read error:%s",
228 				(( ahead-> cnt == 0) ?
229 					"unexpected end of file" :
230 					strerror( req_error( ahead-> fi-> req))
231 			));
232 			ahead-> error = 1;
233 			if ( !ahead-> fi-> noIncomplete && ahead-> cnt >= 0)
234 				ahead-> fi-> wasTruncated = true;
235 			return 0;
236 		}
237 
238 		ahead-> read += ahead-> cnt;
239 		ahead-> lasty = ahead-> y;
240 		ahead-> y	  = ahead-> read / ahead-> ls;
241 		ahead-> inx = 0;
242 		EVENT_SCANLINES_READY(ahead-> fi, ahead-> y - ahead-> lasty, SCANLINES_DIR_BOTTOM_TO_TOP);
243 	}
244 
245 	return ahead->buf[ahead->inx++];
246 }
247 
248 typedef struct _RGBTriplet {
249 	dword r;
250 	dword g;
251 	dword b;
252 } RGBTriplet;
253 
254 typedef struct _LoadRec {
255 	long base;
256 	Bool windows;
257 	dword cbFix;
258 	dword ulCompression;
259 	dword cclrUsed;
260 	dword cclrImportant;
261 	dword offBits;
262 	word  xHotspot;
263 	word  yHotspot;
264 	Point resolution;
265 	Bool multiframe;
266 	int w, h, bpp;
267 	int passed;
268 	size_t passed_frame_offset;
269 	size_t file_start_offset;
270 	RGBTriplet rgb_offset;
271 	RGBTriplet rgb_mask;
272 	RGBTriplet rgb_valid_bits;
273 } LoadRec;
274 
275 
276 static void *
open_load(PImgCodec instance,PImgLoadFileInstance fi)277 open_load( PImgCodec instance, PImgLoadFileInstance fi)
278 {
279 	LoadRec * l;
280 	PImgIORequest fd;
281 	word usType;
282 
283 	if ( req_seek( fi-> req, 0, SEEK_SET) < 0) return NULL;
284 
285 	fd = fi-> req;
286 	if ( !read_word( fd, &usType)) outr(fd);
287 
288 	if ( usType != BFT_BMAP && usType != BFT_BITMAPARRAY)
289 		return NULL;
290 
291 	fi-> stop = true;
292 	l = malloc( sizeof( LoadRec));
293 	if ( !l) outcm( sizeof( LoadRec));
294 	memset( l, 0, sizeof( LoadRec));
295 	fi-> instance = l;
296 
297 	l-> multiframe = usType == BFT_BITMAPARRAY;
298 	l-> passed = -1;
299 	l-> file_start_offset = l-> passed_frame_offset = req_tell( fi-> req);
300 	if ( !l-> multiframe) fi-> frameCount = 1;
301 
302 	return l;
303 }
304 
305 static Bool
rewind_to_frame(PImgLoadFileInstance fi)306 rewind_to_frame( PImgLoadFileInstance fi)
307 {
308 	LoadRec * l = ( LoadRec *) fi-> instance;
309 	PImgIORequest fd = fi-> req;
310 	word usType;
311 	dword cbSize2, offNext, dummy;
312 
313 	if ( !l-> multiframe)
314 		return true;
315 
316 	if ( l-> passed >= fi-> frame) {
317 		/* reset to first frame */
318 		l-> passed = -1;
319 		l-> passed_frame_offset = l-> file_start_offset;
320 	}
321 
322 	if ( req_seek( fd, l-> passed_frame_offset, SEEK_CUR) < 0)
323 		outs(fd);
324 
325 	while ( ++l-> passed < fi-> frame ) {
326 		if ( !read_dword( fd, &cbSize2) )
327 			outr(fd);
328 		if ( !read_dword( fd, &offNext) )
329 			outr(fd);
330 		if ( offNext == 0L ) {
331 			fi-> frameCount = l-> passed;
332 			snprintf( fi-> errbuf, 256, "Index %d is out of range", fi-> frame);
333 			return false;
334 		}
335 		if ( req_seek( fd, (long )offNext, SEEK_SET) < 0)
336 		 	outs(fd);
337 		if ( !read_word( fi-> req, &usType) )
338 			outr(fd);
339 		if ( usType != BFT_BITMAPARRAY ) {
340 			snprintf( fi-> errbuf, 256, "Bad array magic at index %d", l-> passed);
341 			return false;
342 		}
343 	}
344 	if ( !read_dword( fd, &cbSize2) )
345 		outr(fd);
346 	if ( !read_dword( fd, &offNext) )
347 		outr(fd);
348 	if ( !read_dword( fd, &dummy) )
349 		outr(fd);
350 	if ( !read_word(fd, &usType) )
351 		outr(fd);
352 	if ( usType != BFT_BMAP ) {
353 		snprintf( fi-> errbuf, 256, "Bad magic at index %d", l-> passed);
354 		return false;
355 	}
356 	l-> passed_frame_offset = offNext;
357 
358 	return true;
359 }
360 
361 static dword
count_mask_bits(dword mask,dword * bitoffset)362 count_mask_bits(dword mask, dword * bitoffset)
363 {
364 	dword testmask = 1; /* start with the least significant bit */
365 	dword counter  = 0;
366 	dword index    = 0;
367 
368 	/* find offset of first bit */
369 	while (((mask & testmask) == 0) && (index < 31)) {
370 		index++;
371 		testmask <<= 1;
372 	}
373 	*bitoffset = index;
374 
375 	/* count the bits set in the rest of the mask */
376 	while ((testmask <= mask) && (index < 31)) {
377 		if (mask & testmask) {
378 			counter++;
379 		}
380 		index++;
381 		testmask <<= 1;
382 	}
383 
384 	return counter;
385 }
386 
387 
388 static Bool
read_bmp_header(PImgLoadFileInstance fi)389 read_bmp_header( PImgLoadFileInstance fi)
390 {
391 	LoadRec * l = ( LoadRec *) fi-> instance;
392 	PImgIORequest fd = fi-> req;
393 	dword cbSize, cbFix;
394 
395 	l-> base = req_tell(fd) - 2L; /* BM */
396 	if ( l-> base < 0)
397 		outs(fd);
398 	if ( !read_dword(fd, &cbSize) )
399 		outr(fd);
400 	if ( !read_word(fd, &l-> xHotspot) )
401 		outr(fd);
402 	if ( !read_word(fd, &l-> yHotspot) )
403 		outr(fd);
404 	if ( !read_dword(fd, &l-> offBits) )
405 		outr(fd);
406 	if ( !read_dword(fd, &cbFix) )
407 		outr(fd);
408 
409 	if ( cbFix == 12 ) {
410 		/* OS/2 1.x uncompressed bitmap */
411 		word cx, cy, cPlanes, cBitCount;
412 
413 		if ( !read_word(fd, &cx) )
414 			outr(fd);
415 		if ( !read_word(fd, &cy) )
416 			outr(fd);
417 		if ( !read_word(fd, &cPlanes) )
418 			outr(fd);
419 		if ( !read_word(fd, &cBitCount) )
420 			outr(fd);
421 
422 		if ( cx == 0 || cy == 0 )
423 			outc("Bad size");
424 		if ( cPlanes != 1 )
425 			outcd("Number of bitmap planes is %d, must be 1", cPlanes);
426 		if ( cBitCount != 1 && cBitCount != 4 && cBitCount != 8 && cBitCount != 24 )
427 			outcd("Bit count is %d, must be 1, 4, 8 or 24", cBitCount);
428 
429 		l-> w   = (int) cx;
430 		l-> h   = (int) cy;
431 		l-> bpp = (int) cBitCount;
432 		l-> windows = false;
433 	}
434 	else if (
435 		cbFix >= 16 && cbFix <= 64 &&
436 		((cbFix & 3) == 0 || cbFix == 42 || cbFix == 46)
437 	) {
438 		/* OS/2 and Windows 3 */
439 		word cPlanes = 0, cBitCount = 0, usUnits = 0, usReserved, usRecording, usRendering = 0;
440 		dword ulWidth = 0, ulHeight = 0, ulCompression = 0;
441 		dword ulSizeImage, ulXPelsPerMeter = 0, ulYPelsPerMeter = 0;
442 		dword cclrUsed = 0, cclrImportant = 0, cSize1, cSize2, ulColorEncoding, ulIdentifier;
443 		Bool ok;
444 
445 		ok	= read_dword(fd, &ulWidth);
446 		ok &= read_dword(fd, &ulHeight);
447 		ok &= read_word(fd, &cPlanes);
448 		ok &= read_word(fd, &cBitCount);
449 		if ( cbFix > 16 )
450 			ok &= read_dword(fd, &ulCompression);
451 		else
452 			ulCompression = BCA_UNCOMP;
453 
454 		if ( cbFix > 20 )
455 			ok &= read_dword(fd, &ulSizeImage);
456 		if ( cbFix > 24 )
457 			ok &= read_dword(fd, &ulXPelsPerMeter);
458 		if ( cbFix > 28 )
459 			ok &= read_dword(fd, &ulYPelsPerMeter);
460 		if ( cbFix > 32 )
461 			ok &= read_dword(fd, &cclrUsed);
462 		else
463 			cclrUsed = ( (dword)1 << cBitCount );
464 		if ( cBitCount != 24 && cclrUsed == 0 )
465 			cclrUsed = ( (dword)1 << cBitCount );
466 
467 		/* Protect against badly written bitmaps! */
468 		if ( cclrUsed > ( (dword)1 << cBitCount ) )
469 			cclrUsed = ( (dword)1 << cBitCount );
470 
471 		if ( cbFix > 36 )
472 			ok &= read_dword(fd, &cclrImportant);
473 		if ( cbFix > 40 )
474 			ok &= read_word(fd, &usUnits);
475 		if ( cbFix > 42 )
476 			ok &= read_word(fd, &usReserved);
477 		if ( cbFix > 44 )
478 			ok &= read_word(fd, &usRecording);
479 		if ( cbFix > 46 )
480 			ok &= read_word(fd, &usRendering);
481 		if ( cbFix > 48 )
482 			ok &= read_dword(fd, &cSize1);
483 		if ( cbFix > 52 )
484 			ok &= read_dword(fd, &cSize2);
485 		if ( cbFix > 56 )
486 			ok &= read_dword(fd, &ulColorEncoding);
487 		if ( cbFix > 60 )
488 			ok &= read_dword(fd, &ulIdentifier);
489 
490 		if ( !ok )
491 			outr(fd);
492 
493 		if ( ulWidth == 0L || ulHeight == 0L )
494 			outc("Bad image size");
495 		if ( cPlanes != 1 )
496 			outcd("Number of bitmap planes is %d, must be 1", cPlanes);
497 		if (
498 			cBitCount != 1 &&
499 			cBitCount != 4 &&
500 			cBitCount != 8 &&
501 			cBitCount != 16 &&
502 			cBitCount != 24 &&
503 			cBitCount != 32
504 		)
505 			outcd("Bit count is %d, must be 1, 4, 8, 16, 24 or 32", cBitCount);
506 
507 		l-> w   = (int) ulWidth;
508 		l-> h   = (int) ulHeight;
509 		l-> bpp = (int) cBitCount;
510 		l-> windows       = true;
511 		l-> cbFix	  = cbFix;
512 		l-> ulCompression = ulCompression;
513 		l-> cclrUsed      = cclrUsed;
514 		l-> cclrImportant = cclrImportant;
515 		l-> resolution.x  = ulXPelsPerMeter;
516 		l-> resolution.y  = ulYPelsPerMeter;
517 	} else
518 		outc("cbFix is bad");
519 
520 	if ( l-> bpp == 16 || l-> bpp == 32 ) {
521 		switch ( l-> ulCompression) {
522 		case BCA_UNCOMP:
523 			l-> rgb_offset. b = 0;
524 			l-> rgb_offset. g = (l->bpp == 16) ?  5 :  8;
525 			l-> rgb_offset. r = (l->bpp == 16) ? 10 : 16;
526 
527 			/* set color masks to either 16bpp (5,5,5) or 32bpp (8,8,8) */
528 			l-> rgb_mask. b = (l-> bpp == 16) ? 0x001f : 0x000000ff;
529 			l-> rgb_mask. g = (l-> bpp == 16) ? 0x03e0 : 0x0000ff00;
530 			l-> rgb_mask. r = (l-> bpp == 16) ? 0x7c00 : 0x00ff0000;
531 
532 			l-> rgb_valid_bits. b =
533 			l-> rgb_valid_bits. g =
534 			l-> rgb_valid_bits. r = (l->bpp == 16) ?  5 :  8;
535 			break;
536 
537 		case BCA_BITFIELDS: {
538 			Bool ok = 1;
539 
540 			/* Read BI_BITFIELDS color masks from the header (where usually the palette is) */
541 			/* These are strangely stored as dwords in the order of R-G-B. */
542 			if ( req_seek(fd, (long) (l-> base + 14L + l-> cbFix), SEEK_SET) < 0)
543 				outs(fd);
544 			ok &= read_dword(fd, &l-> rgb_mask. r);
545 			ok &= read_dword(fd, &l-> rgb_mask. g);
546 			ok &= read_dword(fd, &l-> rgb_mask. b);
547 			if ( !ok )
548 				outr(fd);
549 
550 			/* count the bits used in each mask */
551 			l-> rgb_valid_bits. b = count_mask_bits( l-> rgb_mask. b, &l-> rgb_offset. b);
552 			l-> rgb_valid_bits. g = count_mask_bits( l-> rgb_mask. g, &l-> rgb_offset. g);
553 			l-> rgb_valid_bits. r = count_mask_bits( l-> rgb_mask. r, &l-> rgb_offset. r);
554 
555 			/* Only up to 8 bit per mask are allowed */
556 			if (
557 				l-> rgb_valid_bits. b > 8 ||
558 				l-> rgb_valid_bits. g > 8 ||
559 				l-> rgb_valid_bits. r > 8
560 			)
561 				outc("Bad bit masks for non-24bits RGB data");
562 
563 			/* check for non-overlapping bits */
564 			if (
565 				l-> rgb_valid_bits. b +
566 				l-> rgb_valid_bits. g +
567 				l-> rgb_valid_bits. r > l-> bpp
568 			)
569 				outc("Bad bit masks for non-24bits RGB data");
570 
571 
572 			if (
573 				l-> rgb_offset. b + l-> rgb_valid_bits. b > l-> rgb_offset. g ||
574 				l-> rgb_offset. g + l-> rgb_valid_bits. g > l-> rgb_offset. r ||
575 				l-> rgb_offset. r + l-> rgb_valid_bits. r > l-> bpp
576 			)
577 				outc("Bad bit masks for non-24bits RGB data");
578 
579 			l-> rgb_valid_bits. r = 8 - l-> rgb_valid_bits. r;
580 			l-> rgb_valid_bits. g = 8 - l-> rgb_valid_bits. g;
581 			l-> rgb_valid_bits. b = 8 - l-> rgb_valid_bits. b;
582 			break;
583 		}
584 
585 		default:
586 			outcd("compression type is %d, expected 0 or 3", l->ulCompression);
587 	}}
588 	return true;
589 }
590 
591 static Bool
req_read_big(PImgLoadFileInstance fi,int h,unsigned long lineSize,Byte * data)592 req_read_big( PImgLoadFileInstance fi, int h, unsigned long lineSize, Byte * data)
593 {
594 	unsigned long size = h * lineSize, read = 0;
595 	int lasty = 0, y = 0;
596 
597 	if ( fi-> eventMask & IMG_EVENTS_DATA_READY) {
598 		/* read and notify */
599 		while ( size > 0) {
600 			ssize_t r = req_read(
601 				fi-> req,
602 				( BUFSIZE > size) ? size : BUFSIZE,
603 				data
604 			);
605 			if ( r < 0)
606 				outr( fi-> req);
607 			if ( r == 0) {
608 				if ( fi-> noIncomplete)
609 					outc("Read error: unexpected end of file")
610 				else
611 					size = 0;
612 			}
613 			read += r;
614 			size -= r;
615 			data += r;
616 			lasty = y;
617 			y = read / lineSize;
618 			EVENT_SCANLINES_READY(fi, y - lasty, SCANLINES_DIR_BOTTOM_TO_TOP);
619 		}
620 	} else {
621 		/* just read */
622 		ssize_t r = req_read( fi-> req, size, data);
623 		if ( r < 0)
624 			outr( fi-> req);
625 		if ( r != size && fi-> noIncomplete)
626 			outc( "Read error: unexpected end of file");
627 	}
628 
629 	return true;
630 }
631 
632 /* Read 16bpp data with compression BI_RGB or BI_BITFIELDS (will be mapped to 24bpp, lossless) */
633 static Bool
read_16_32_bpp(PImgLoadFileInstance fi,PImage i,int bpp,unsigned long stride_dst)634 read_16_32_bpp( PImgLoadFileInstance fi, PImage i, int bpp, unsigned long stride_dst)
635 {
636 	LoadRec * l = ( LoadRec *) fi-> instance;
637 	int h, stride_src = ((i-> w * 16 + 31) / 32) * 4;
638 	Byte *src, *dst;
639 
640 	if ( !( src = (Byte*) malloc(stride_src)))
641 		outcm(stride_src);
642 
643 	dst = i-> data; /* write pointer */
644 	for (h = 0; h < i-> h; h++) {
645 		int block_count = i-> w;
646 		const word *  src16  = (const word *)  src;
647 		const dword * src32  = (const dword *) src;
648 		Byte * line  = dst;
649 		ssize_t r = req_read( fi-> req, stride_src, src);
650 
651 		if ( r != stride_src ) {
652 			free( src);
653 			if ( r < 0)
654 				outr( fi-> req);
655 			if ( fi-> noIncomplete)
656 				outc("Read error: unexpected end of file");
657 			h = i->h;
658 			fi-> wasTruncated = true;
659 		}
660 
661 		/* Extract red, green, blue. */
662 		/* Encoding starts at least significant bit, then xB,yG,zR (most significant bit is unused). */
663 		/* Map these into 24bpp BGR. */
664 #define GetX(X,SRC) (((SRC & l-> rgb_mask.X) >> l->rgb_offset.X) << l->rgb_valid_bits.X)
665 		if ( bpp == 16 ) {
666 			while (block_count > 0) {
667 				register word data16 = *src16++;
668 				*line++ = GetX(b,data16);
669 				*line++ = GetX(g,data16);
670 				*line++ = GetX(r,data16);
671 				--block_count;
672 			}
673 		} else {
674 			while (block_count > 0) {
675 				register dword data32 = *src32++;
676 				*line++ = GetX(b,data32);
677 				*line++ = GetX(g,data32);
678 				*line++ = GetX(r,data32);
679 				--block_count;
680 			}
681 		}
682 #undef GetX
683 		dst += stride_dst;
684 		EVENT_SCANLINES_READY(fi, 1, SCANLINES_DIR_BOTTOM_TO_TOP);
685 	}
686 
687 	free(src);
688 	return true;
689 }
690 
691 
692 static Bool
load(PImgCodec instance,PImgLoadFileInstance fi)693 load( PImgCodec instance, PImgLoadFileInstance fi)
694 {
695 	HV * profile = fi-> frameProperties;
696 	LoadRec * l = ( LoadRec *) fi-> instance;
697 	PImgIORequest fd = fi-> req;
698 	PImage img;
699 	int cLinesWorth; /* bmp alignment and prima alignment are identical, by 4-byte boundary */
700 	int bpp;
701 	Byte * data;
702 
703 	if ( !rewind_to_frame(fi))
704 		return false;
705 	if ( !read_bmp_header(fi))
706 		return false;
707 
708 	img = PImage( fi-> object);
709 	bpp = ( l-> bpp == 16 || l-> bpp == 32 ) ? 24 : l-> bpp;
710 	if ( fi-> noImageData) {
711 		pset_i( width,	l-> w);
712 		pset_i( height, l-> h);
713 		CImage( fi-> object)-> create_empty( fi-> object, 1, 1, bpp);
714 	} else {
715 		CImage( fi-> object)-> create_empty( fi-> object, l-> w, l-> h, bpp);
716 		EVENT_HEADER_READY( fi);
717 	}
718 	data = img-> data;
719 
720 	/* read palette */
721 	if ( bpp != 24) {
722 		int i;
723 		byte b[4];
724 		PRGBColor pal;
725 
726 		pal = img-> palette;
727 		if ( l-> windows ) { /* Windows */
728 			if ( req_seek(fd, (long) (l-> base + 14L + l-> cbFix), SEEK_SET) < 0)
729 				outs(fd);
730 			img-> palSize = (int) l-> cclrUsed;
731 			for ( i = 0; i < (int) l-> cclrUsed; i++, pal++ ) {
732 				if ( req_read( fd, 4, b) != 4)
733 					outr(fd);
734 				pal-> b = b[0];
735 				pal-> g = b[1];
736 				pal-> r = b[2];
737 			}
738 		} else { /* OS/2 */
739 			if ( req_seek(fd, (long) (l-> base + 26L), SEEK_SET) < 0)
740 				outs(fd);
741 			img-> palSize = 1 << l-> bpp;
742 			for ( i = 0; i < img-> palSize; i++, pal++ ) {
743 				if ( req_read( fd, 3, b) != 3)
744 					outr(fd);
745 				pal-> b = b[0];
746 				pal-> g = b[1];
747 				pal-> r = b[2];
748 			}
749 		}
750 	} else {
751 		img-> palSize = 0;
752 	}
753 
754 	if ( bpp == 1)
755 		swap_pal( img-> palette);
756 
757 	if ( fi-> loadExtras) {
758 		char * c;
759 		if ( !l-> windows)
760 		pset_i( OS2, 1);
761 		pset_i( HotSpotX, l-> xHotspot);
762 		pset_i( HotSpotY, l-> yHotspot);
763 		pset_i( BitDepth, l-> bpp);
764 
765 		c = ( l-> ulCompression > BCA_MAX) ?
766 			"Unknown" : bca_sets[ l-> ulCompression];
767 		pset_c( Compression, c);
768 		if ( l-> windows) {
769 			pset_i( ImportantColors, l-> cclrImportant);
770 			pset_i( XResolution, l-> resolution.x);
771 			pset_i( YResolution, l-> resolution.y);
772 		}
773 	}
774 
775 	if ( fi-> noImageData)
776 		return true;
777 
778 	/* read data */
779 	cLinesWorth = ((bpp * l->w + 31) / 32) * 4;
780 
781 	if ( l-> windows ) {
782 		if ( req_seek( fd, (long) l-> offBits, SEEK_SET) < 0)
783 	   		outs(fd);
784 
785 		switch ( (int) l-> ulCompression ) {
786 
787 		case BCA_UNCOMP:
788 			switch ( l-> bpp) {
789 			case 1:
790 			case 4:
791 			case 8:
792 			case 24:
793 				if ( !req_read_big(fi, l-> h, cLinesWorth, data))
794 					return false;
795 				break;
796 			case 16:
797 				if ( !read_16_32_bpp(fi, PImage(fi-> object), 16, cLinesWorth))
798 					return false;
799 				break;
800 			case 32:
801 				if ( !read_16_32_bpp(fi, PImage(fi-> object), 32, cLinesWorth))
802 					return false;
803 				break;
804 			default:
805 				outc("Unsupported bit depth");
806 			}
807 			break;
808 
809 		case BCA_RLE8: {
810 			AHEAD *ahead;
811 			int x = 0, y = 0;
812 			Bool eof8 = false;
813 
814 			if ( (ahead = create_ahead(fi, cLinesWorth)) == NULL )
815 				outcm(sizeof(AHEAD));
816 
817 			while ( !eof8 ) {
818 				byte c = read_ahead(ahead);
819 				byte d = read_ahead(ahead);
820 
821 				if ( c ) {
822 					memset(data, d, c);
823 					x += c;
824 					data += c;
825 				} else switch ( d ) {
826 					 case MSWCC_EOL: {
827 						int to_eol = cLinesWorth - x;
828 
829 						memset( data, 0, (size_t) to_eol);
830 						data += to_eol;
831 						x = 0;
832 						if ( ++y == l->h )
833 							eof8 = true;
834 						}
835 						break;
836 					 case MSWCC_EOB:
837 						if ( y < l->h ) {
838 							int to_eol = cLinesWorth - x;
839 
840 							memset(data, 0, (size_t) to_eol);
841 							x = 0; y++;
842 							data += to_eol;
843 							while ( y < l->h ) {
844 								memset(data, 0, (size_t) cLinesWorth);
845 								data += cLinesWorth;
846 								y++;
847 							}
848 						}
849 						eof8 = true;
850 						break;
851 					 case MSWCC_DELTA: {
852 					 	byte dx = read_ahead(ahead);
853 					 	byte dy = read_ahead(ahead);
854 					 	int fill = dx + dy * cLinesWorth;
855 					 	memset(data, 0, (size_t) fill);
856 					 	data += fill;
857 					 	x += dx; y += dy;
858 					 	if ( y == l->h )
859 					 		eof8 = true;
860 					 	}
861 					 	break;
862 
863 					 default: {
864 					 	int n = (int) d;
865 
866 					 	while ( n-- > 0 )
867 					 		*data++ = read_ahead(ahead);
868 					 	x += d;
869 					 	if ( d & 1 )
870 					 		read_ahead(ahead); /* Align */
871 					 	}
872 					 	break;
873 					 }
874 				}
875 				if ( destroy_ahead(ahead))
876 					return false;
877 			}
878 			break;
879 
880 		case BCA_RLE4: {
881 			AHEAD *ahead;
882 			int x = 0, y = 0;
883 			Bool eof4 = false;
884 			int inx = 0;
885 
886 			if ( (ahead = create_ahead(fi, cLinesWorth)) == NULL )
887 				outcm(sizeof(AHEAD));
888 
889 			memset(data, 0, l->h * cLinesWorth);
890 
891 			while ( !eof4 ) {
892 				byte c = read_ahead(ahead);
893 				byte d = read_ahead(ahead);
894 
895 				if ( c ) {
896 					byte h, l;
897 					int i;
898 					if ( x & 1 ) {
899 						h = (byte) (d >> 4);
900 						l = (byte) (d << 4);
901 					} else {
902 						h = (byte) (d&0xf0);
903 						l = (byte) (d & 0x0f);
904 					}
905 					for ( i = 0; i < (int) c; i++, x++ ) {
906 						if ( x & 1U )
907 							data[inx++] |= l;
908 						else
909 							data[inx]   |= h;
910 					}
911 				} else switch ( d ) {
912 					case MSWCC_EOL:
913 							x = 0;
914 							if ( ++y == l->h )
915 								eof4 = true;
916 							inx = cLinesWorth * y;
917 							break;
918 
919 					case MSWCC_EOB:
920 							eof4 = true;
921 							break;
922 
923 					case MSWCC_DELTA: {
924 							byte dx = read_ahead(ahead);
925 							byte dy = read_ahead(ahead);
926 
927 							x += dx; y += dy;
928 							inx = y * cLinesWorth + (x/2);
929 
930 							if ( y == l->h )
931 								eof4 = true;
932 							}
933 							break;
934 
935 					default: {
936 							int i, nr = 0;
937 
938 							if ( x & 1 ) {
939 								for ( i = 0; i+2 <= (int) d; i += 2 ) {
940 									byte b = read_ahead(ahead);
941 									data[inx++] |= (b >> 4);
942 									data[inx  ] |= (b << 4);
943 									nr++;
944 								}
945 								if ( i < (int) d ) {
946 									data[inx++] |= (read_ahead(ahead) >> 4);
947 									nr++;
948 								}
949 							} else {
950 								for ( i = 0; i+2 <= (int) d; i += 2 ) {
951 									data[inx++] = read_ahead(ahead);
952 									nr++;
953 								}
954 								if ( i < (int) d ) {
955 									data[inx] = read_ahead(ahead);
956 									nr++;
957 								}
958 							}
959 							x += d;
960 
961 							if ( nr & 1 )
962 								read_ahead(ahead); /* Align input stream to next word */
963 							}
964 							break;
965 					}
966 				}
967 
968 				if ( destroy_ahead(ahead))
969 					return false;
970 			}
971 			break;
972 		case BCA_BITFIELDS:
973 			switch ( l-> bpp) {
974 			case 16:
975 				if ( !read_16_32_bpp(fi, PImage(fi-> object), 16, cLinesWorth))
976 					return false;
977 				break;
978 			case 32:
979 				if ( !read_16_32_bpp(fi, PImage(fi-> object), 32, cLinesWorth))
980 					return false;
981 				break;
982 			default:
983 				outcd("Unsupported bit depth %d, expected 16 or 32", l-> bpp);
984 			}
985 			break;
986 		default:
987 			outc("compression type not uncompressed, RLE4 or RLE8");
988 		}
989 	} else {
990 		/* OS/2 */
991 		if ( req_seek(fd, l-> offBits, SEEK_SET) < 0)
992 				outs(fd);
993 		if ( !req_read_big(fi, cLinesWorth, l->h, data))
994 				return false;
995 	}
996 	EVENT_SCANLINES_FINISHED(fi, SCANLINES_DIR_BOTTOM_TO_TOP);
997 
998 	return true;
999 }
1000 
1001 static void
close_load(PImgCodec instance,PImgLoadFileInstance fi)1002 close_load( PImgCodec instance, PImgLoadFileInstance fi)
1003 {
1004 	LoadRec * l = ( LoadRec *) fi-> instance;
1005 	free( l);
1006 }
1007 
1008 static HV *
save_defaults(PImgCodec c)1009 save_defaults( PImgCodec c)
1010 {
1011 	HV * profile = newHV();
1012 	pset_i( OS2, 0);
1013 	pset_i( HotSpotX, 0);
1014 	pset_i( HotSpotY, 0);
1015 	pset_i( ImportantColors, 0);
1016 	pset_i( XResolution, 0);
1017 	pset_i( YResolution, 0);
1018 	return profile;
1019 }
1020 
1021 static void *
open_save(PImgCodec instance,PImgSaveFileInstance fi)1022 open_save( PImgCodec instance, PImgSaveFileInstance fi)
1023 {
1024 	return (void*)1;
1025 }
1026 
1027 static Bool
save(PImgCodec instance,PImgSaveFileInstance fi)1028 save( PImgCodec instance, PImgSaveFileInstance fi)
1029 {
1030 	dPROFILE;
1031 	PImage i = ( PImage) fi-> object;
1032 	HV * profile = fi-> objectExtras;
1033 	int cRGB;
1034 	PImgIORequest fd = fi-> req;
1035 	RGBColor rgb_1bpp[2], * palette = i-> palette;
1036 
1037 	Bool os2	= false;
1038 	word xHotspot	= 0;
1039 	word yHotspot	= 0;
1040 	dword cclrImportant = 0;
1041 	dword cxResolution  = 0;
1042 	dword cyResolution  = 0;
1043 
1044 	if ( pexist( OS2))
1045 		os2 = pget_B( OS2);
1046 	if ( pexist( HotSpotX))
1047 		xHotspot = pget_i( HotSpotX);
1048 	if ( pexist( HotSpotY))
1049 		yHotspot = pget_i( HotSpotY);
1050 	if ( pexist( ImportantColors))
1051 		cclrImportant = pget_i( ImportantColors);
1052 	if ( pexist( XResolution))
1053 		cxResolution = pget_i( XResolution);
1054 	if ( pexist( YResolution))
1055 		cyResolution = pget_i( YResolution);
1056 
1057 	cRGB = ( (1 << (i-> type & imBPP)) & 0x1ff ); /* 1->2, 4->16, 8->256, 24->0 */
1058 
1059 	/* ...handle messy 1bpp case */
1060 	if ( cRGB == 2 ) {
1061 		/*
1062 		The palette entries inside a 1bpp PM bitmap are not honored, or handled
1063 		correctly by most programs. Current thinking is that they have no actual
1064 		meaning. Under OS/2 PM, bitmap 1's re fg and 0's are bg, and it is the job of
1065 		the displayer to pick fg and bg. We will pick fg=black, bg=white in the bitmap
1066 		file we save. If we do not write black and white, we find that most programs
1067 		will incorrectly honor these entries giving unpredicatable (and often black on
1068 		a black background!) results.
1069 		*/
1070 
1071 		/* DK adds: since we swap OS/2 mono palette on load, we do the same
1072 		on save. The reason is that if the programmed doesn't care about OS/2
1073 		problems (which is most probable), we simply restore the status quo.
1074 		If he does (surprise!) then he can also swap the palette manually
1075 		*/
1076 		memcpy( &rgb_1bpp, palette, sizeof(RGBColor) * 2);
1077 		swap_pal( rgb_1bpp);
1078 		palette = rgb_1bpp;
1079 	}
1080 
1081 	if ( os2 ) {
1082 		word usType = BFT_BMAP;
1083 		dword cbFix     = (dword) 12;
1084 		word cx	    = (word) i->w;
1085 		word cy	    = (word) i->h;
1086 		word cPlanes    = (word) 1;
1087 		word cBitCount  = (word) i->type & imBPP;
1088 		    int cLinesWorth = (((cBitCount * cx + 31) / 32) * cPlanes) * 4;
1089 		dword offBits   = (dword) 26 + cRGB * (dword) 3;
1090 		    dword cbSize    = offBits + (dword) cy * (dword) cLinesWorth;
1091 		int j, total, actual;
1092 
1093 		write_word(fd, usType);
1094 		write_dword(fd, cbSize);
1095 		write_word(fd, xHotspot);
1096 		write_word(fd, yHotspot);
1097 		write_dword(fd, offBits);
1098 		write_dword(fd, cbFix);
1099 		write_word(fd, cx);
1100 		write_word(fd, cy);
1101 		write_word(fd, cPlanes);
1102 		write_word(fd, cBitCount);
1103 
1104 		for ( j = 0; j < cRGB; j++, palette++ ) {
1105 			byte b[3];
1106 			b[0] = palette-> b;
1107 			b[1] = palette-> g;
1108 			b[2] = palette-> r;
1109 			if ( req_write(fd, 3, b) != 3 )
1110 				outw(fd);
1111 		}
1112 
1113 		total = i->h * cLinesWorth;
1114 		actual = req_write(fd, total, i-> data);
1115 		if ( actual != total )
1116 				outw(fd);
1117 	} else {
1118 		/* Windows */
1119 		word usType		= BFT_BMAP;
1120 		dword cbFix		= (dword) 40;
1121 		dword cx		= (dword) i->w;
1122 		dword cy		= (dword) i->h;
1123 		word cPlanes	        = (word) 1;
1124 		word cBitCount	        = (word) i->type & imBPP;
1125 		int cLinesWorth	        = (((cBitCount * (int) cx + 31) / 32) * cPlanes) * 4;
1126 		dword offBits	        = (dword) 54 + cRGB * (dword) 4;
1127 		dword cbSize	        = offBits + (dword) cy * (dword) cLinesWorth;
1128 		dword ulCompression     = BCA_UNCOMP;
1129 		dword cbImage	        = (dword) cLinesWorth * (dword) i->h;
1130 		dword cclrUsed	        = i-> palSize;
1131 		int j, total, actual;
1132 
1133 		write_word(fd, usType);
1134 		write_dword(fd, cbSize);
1135 		write_word(fd, xHotspot);
1136 		write_word(fd, yHotspot);
1137 		write_dword(fd, offBits);
1138 
1139 		write_dword(fd, cbFix);
1140 		write_dword(fd, cx);
1141 		write_dword(fd, cy);
1142 		write_word(fd, cPlanes);
1143 		write_word(fd, cBitCount);
1144 		write_dword(fd, ulCompression);
1145 		write_dword(fd, cbImage);
1146 		write_dword(fd, cxResolution);
1147 		write_dword(fd, cyResolution);
1148 		write_dword(fd, cclrUsed);
1149 		write_dword(fd, cclrImportant);
1150 
1151 		for ( j = 0; j < cRGB; j++, palette++ ) {
1152 			byte b[4];
1153 
1154 			b[0] = palette-> b;
1155 			b[1] = palette-> g;
1156 			b[2] = palette-> r;
1157 			b[3] = 0;
1158 			if ( req_write(fd, 4, b) != 4 )
1159 				outw(fd);
1160 		}
1161 
1162 		total = i-> h * cLinesWorth;
1163 		actual = req_write(fd, total, i-> data);
1164 		if ( actual != total )
1165 			outw(fd);
1166 	}
1167 
1168 	return true;
1169 }
1170 
1171 static void
close_save(PImgCodec instance,PImgSaveFileInstance fi)1172 close_save( PImgCodec instance, PImgSaveFileInstance fi)
1173 {
1174 }
1175 
1176 void
apc_img_codec_bmp(void)1177 apc_img_codec_bmp( void )
1178 {
1179 	struct ImgCodecVMT vmt;
1180 	memcpy( &vmt, &CNullImgCodecVMT, sizeof( CNullImgCodecVMT));
1181 	vmt. init	   = init;
1182 	vmt. open_load	   = open_load;
1183 	vmt. load	   = load;
1184 	vmt. close_load    = close_load;
1185 	vmt. save_defaults = save_defaults;
1186 	vmt. open_save	   = open_save;
1187 	vmt. save	   = save;
1188 	vmt. close_save    = close_save;
1189 	apc_img_register( &vmt, NULL);
1190 }
1191 
1192 #ifdef __cplusplus
1193 }
1194 #endif
1195