1 /*
2 	gd_bmp.c
3 
4 	Bitmap format support for libgd
5 
6 	* Written 2007, Scott MacVicar
7 	---------------------------------------------------------------------------
8 
9 	Todo:
10 
11 	Bitfield encoding
12 
13 	----------------------------------------------------------------------------
14  */
15 
16 /**
17  * File: BMP IO
18  *
19  * Read and write BMP images.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <stdio.h>
27 #include <limits.h>
28 #include <math.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include "gd.h"
32 #include "gdhelpers.h"
33 #include "bmp.h"
34 
35 static int compress_row(unsigned char *uncompressed_row, int length);
36 static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data);
37 
38 static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
39 static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
40 static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
41 static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
42 static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
43 
44 static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
45 static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
46 static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
47 static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
48 static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
49 
50 static int _gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression);
51 
52 #define BMP_DEBUG(s)
53 
gdBMPPutWord(gdIOCtx * out,int w)54 static int gdBMPPutWord(gdIOCtx *out, int w)
55 {
56 	/* Byte order is little-endian */
57 	gdPutC(w & 0xFF, out);
58 	gdPutC((w >> 8) & 0xFF, out);
59 	return 0;
60 }
61 
gdBMPPutInt(gdIOCtx * out,int w)62 static int gdBMPPutInt(gdIOCtx *out, int w)
63 {
64 	/* Byte order is little-endian */
65 	gdPutC(w & 0xFF, out);
66 	gdPutC((w >> 8) & 0xFF, out);
67 	gdPutC((w >> 16) & 0xFF, out);
68 	gdPutC((w >> 24) & 0xFF, out);
69 	return 0;
70 }
71 
72 /*
73 	Function: gdImageBmpPtr
74 
75 	Outputs the given image as BMP data, but using a <gdIOCtx> instead
76 	of a file. See <gdImageBmp>.
77 
78 	Parameters:
79 		im			- the image to save.
80 		size 		- Output: size in bytes of the result.
81 		compression - whether to apply RLE or not.
82 
83 	Returns:
84 
85 		A pointer to memory containing the image data or NULL on error.
86 */
gdImageBmpPtr(gdImagePtr im,int * size,int compression)87 BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression)
88 {
89 	void *rv;
90 	gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
91 	if (out == NULL) return NULL;
92 	if (!_gdImageBmpCtx(im, out, compression))
93 		rv = gdDPExtractData(out, size);
94 	else
95 		rv = NULL;
96 	out->gd_free(out);
97 	return rv;
98 }
99 
100 /*
101 	Function: gdImageBmp
102 
103     <gdImageBmp> outputs the specified image to the specified file in
104     BMP format. The file must be open for writing. Under MSDOS and all
105     versions of Windows, it is important to use "wb" as opposed to
106     simply "w" as the mode when opening the file, and under Unix there
107     is no penalty for doing so. <gdImageBmp> does not close the file;
108     your code must do so.
109 
110     In addition, <gdImageBmp> allows to specify whether RLE compression
111     should be applied.
112 
113 	Variants:
114 
115 		<gdImageBmpCtx> write via a <gdIOCtx> instead of a file handle.
116 
117 		<gdImageBmpPtr> store the image file to memory.
118 
119 	Parameters:
120 
121 		im			- the image to save.
122 		outFile		- the output FILE* object.
123 		compression - whether to apply RLE or not.
124 
125 	Returns:
126 		nothing
127 */
gdImageBmp(gdImagePtr im,FILE * outFile,int compression)128 BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression)
129 {
130 	gdIOCtx *out = gdNewFileCtx(outFile);
131 	if (out == NULL) return;
132 	gdImageBmpCtx(im, out, compression);
133 	out->gd_free(out);
134 }
135 
136 /*
137 	Function: gdImageBmpCtx
138 
139 	Outputs the given image as BMP data, but using a <gdIOCtx> instead
140 	of a file. See <gdImageBmp>.
141 
142 	Parameters:
143 		im			- the image to save.
144 		out 		- the <gdIOCtx> to write to.
145 		compression - whether to apply RLE or not.
146 */
gdImageBmpCtx(gdImagePtr im,gdIOCtxPtr out,int compression)147 BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
148 {
149 	_gdImageBmpCtx(im, out, compression);
150 }
151 
_gdImageBmpCtx(gdImagePtr im,gdIOCtxPtr out,int compression)152 static int _gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
153 {
154 	int bitmap_size = 0, info_size, total_size, padding;
155 	int i, row, xpos, pixel;
156 	int error = 0;
157 	unsigned char *uncompressed_row = NULL, *uncompressed_row_start = NULL;
158 	FILE *tmpfile_for_compression = NULL;
159 	gdIOCtxPtr out_original = NULL;
160 	int ret = 1;
161 
162 	/* No compression if its true colour or we don't support seek */
163 	if (im->trueColor) {
164 		compression = 0;
165 	}
166 
167 	if (compression && !out->seek) {
168 		/* Try to create a temp file where we can seek */
169 		if ((tmpfile_for_compression = tmpfile()) == NULL) {
170 			compression = 0;
171 		} else {
172 			out_original = out;
173 			if ((out = (gdIOCtxPtr)gdNewFileCtx(tmpfile_for_compression)) == NULL) {
174 				out = out_original;
175 				out_original = NULL;
176 				compression = 0;
177 			}
178 		}
179 	}
180 
181 	bitmap_size = ((im->sx * (im->trueColor ? 24 : 8)) / 8) * im->sy;
182 
183 	/* 40 byte Windows v3 header */
184 	info_size = BMP_WINDOWS_V3;
185 
186 	/* data for the palette */
187 	if (!im->trueColor) {
188 		info_size += im->colorsTotal * 4;
189 		if (compression) {
190 			bitmap_size = 0;
191 		}
192 	}
193 
194 	/* bitmap header + info header + data */
195 	total_size = 14 + info_size + bitmap_size;
196 
197 	/* write bmp header info */
198 	gdPutBuf("BM", 2, out);
199 	gdBMPPutInt(out, total_size);
200 	gdBMPPutWord(out, 0);
201 	gdBMPPutWord(out, 0);
202 	gdBMPPutInt(out, 14 + info_size);
203 
204 	/* write Windows v3 headers */
205 	gdBMPPutInt(out, BMP_WINDOWS_V3); /* header size */
206 	gdBMPPutInt(out, im->sx); /* width */
207 	gdBMPPutInt(out, im->sy); /* height */
208 	gdBMPPutWord(out, 1); /* colour planes */
209 	gdBMPPutWord(out, (im->trueColor ? 24 : 8)); /* bit count */
210 	gdBMPPutInt(out, (compression ? BMP_BI_RLE8 : BMP_BI_RGB)); /* compression */
211 	gdBMPPutInt(out, bitmap_size); /* image size */
212 	gdBMPPutInt(out, 0); /* H resolution */
213 	gdBMPPutInt(out, 0); /* V ressolution */
214 	gdBMPPutInt(out, im->colorsTotal); /* colours used */
215 	gdBMPPutInt(out, 0); /* important colours */
216 
217 	/* The line must be divisible by 4, else its padded with NULLs */
218 	padding = ((int)(im->trueColor ? 3 : 1) * im->sx) % 4;
219 	if (padding) {
220 		padding = 4 - padding;
221 	}
222 
223 	/* 8-bit colours */
224 	if (!im->trueColor) {
225 		for(i = 0; i< im->colorsTotal; ++i) {
226 			gdPutC(gdImageBlue(im, i), out);
227 			gdPutC(gdImageGreen(im, i), out);
228 			gdPutC(gdImageRed(im, i), out);
229 			gdPutC(0, out);
230 		}
231 
232 		if (compression) {
233 			/* Can potentially change this to X + ((X / 128) * 3) */
234 			uncompressed_row = uncompressed_row_start = (unsigned char *) gdCalloc(gdImageSX(im) * 2, sizeof(char));
235 			if (!uncompressed_row) {
236 				/* malloc failed */
237 				goto cleanup;
238 			}
239 		}
240 
241 		for (row = (im->sy - 1); row >= 0; row--) {
242 			if (compression) {
243 				memset (uncompressed_row, 0, gdImageSX(im));
244 			}
245 
246 			for (xpos = 0; xpos < im->sx; xpos++) {
247 				if (compression) {
248 					*uncompressed_row++ = (unsigned char)gdImageGetPixel(im, xpos, row);
249 				} else {
250 					gdPutC(gdImageGetPixel(im, xpos, row), out);
251 				}
252 			}
253 
254 			if (!compression) {
255 				/* Add padding to make sure we have n mod 4 == 0 bytes per row */
256 				for (xpos = padding; xpos > 0; --xpos) {
257 					gdPutC('\0', out);
258 				}
259 			} else {
260 				int compressed_size = 0;
261 				uncompressed_row = uncompressed_row_start;
262 				if ((compressed_size = compress_row(uncompressed_row, gdImageSX(im))) < 0) {
263 					error = 1;
264 					break;
265 				}
266 				bitmap_size += compressed_size;
267 
268 
269 				gdPutBuf(uncompressed_row, compressed_size, out);
270 				gdPutC(BMP_RLE_COMMAND, out);
271 				gdPutC(BMP_RLE_ENDOFLINE, out);
272 				bitmap_size += 2;
273 			}
274 		}
275 
276 		if (compression && uncompressed_row) {
277 			gdFree(uncompressed_row);
278 			if (error != 0) {
279 				goto cleanup;
280 			}
281 			/* Update filesize based on new values and set compression flag */
282 			gdPutC(BMP_RLE_COMMAND, out);
283 			gdPutC(BMP_RLE_ENDOFBITMAP, out);
284 			bitmap_size += 2;
285 
286 			/* Write new total bitmap size */
287 			gdSeek(out, 2);
288 			gdBMPPutInt(out, total_size + bitmap_size);
289 
290 			/* Total length of image data */
291 			gdSeek(out, 34);
292 			gdBMPPutInt(out, bitmap_size);
293 		}
294 
295 	} else {
296 		for (row = (im->sy - 1); row >= 0; row--) {
297 			for (xpos = 0; xpos < im->sx; xpos++) {
298 				pixel = gdImageGetPixel(im, xpos, row);
299 
300 				gdPutC(gdTrueColorGetBlue(pixel), out);
301 				gdPutC(gdTrueColorGetGreen(pixel), out);
302 				gdPutC(gdTrueColorGetRed(pixel), out);
303 			}
304 
305 			/* Add padding to make sure we have n mod 4 == 0 bytes per row */
306 			for (xpos = padding; xpos > 0; --xpos) {
307 				gdPutC('\0', out);
308 			}
309 		}
310 	}
311 
312 
313 	/* If we needed a tmpfile for compression copy it over to out_original */
314 	if (tmpfile_for_compression) {
315 		unsigned char* copy_buffer = NULL;
316 		int buffer_size = 0;
317 
318 		gdSeek(out, 0);
319 		copy_buffer = (unsigned char *) gdMalloc(1024 * sizeof(unsigned char));
320 		if (copy_buffer == NULL) {
321 			goto cleanup;
322 		}
323 
324 		while ((buffer_size = gdGetBuf(copy_buffer, 1024, out)) != EOF) {
325 			if (buffer_size == 0) {
326 				break;
327 			}
328 			gdPutBuf(copy_buffer , buffer_size, out_original);
329 		}
330 		gdFree(copy_buffer);
331 
332 		/* Replace the temp with the original which now has data */
333 		out->gd_free(out);
334 		out = out_original;
335 		out_original = NULL;
336 	}
337 
338 	ret = 0;
339 cleanup:
340 	if (tmpfile_for_compression) {
341 #ifdef _WIN32
342 		_rmtmp();
343 #else
344 		fclose(tmpfile_for_compression);
345 #endif
346 		tmpfile_for_compression = NULL;
347 	}
348 
349 	if (out_original) {
350 		out_original->gd_free(out_original);
351 	}
352 	return ret;
353 }
354 
compress_row(unsigned char * row,int length)355 static int compress_row(unsigned char *row, int length)
356 {
357 	int rle_type = 0;
358 	int compressed_length = 0;
359 	int pixel = 0, compressed_run = 0, rle_compression = 0;
360 	unsigned char *uncompressed_row = NULL, *uncompressed_rowp = NULL, *uncompressed_start = NULL;
361 
362 	uncompressed_row = (unsigned char *) gdMalloc(length);
363 	if (!uncompressed_row) {
364 		return -1;
365 	}
366 
367 	memcpy(uncompressed_row, row, length);
368 	uncompressed_start = uncompressed_rowp = uncompressed_row;
369 
370 	for (pixel = 0; pixel < length; pixel++) {
371 		if (compressed_run == 0) {
372 			uncompressed_row = uncompressed_rowp;
373 			compressed_run++;
374 			uncompressed_rowp++;
375 			rle_type = BMP_RLE_TYPE_RAW;
376 			continue;
377 		}
378 
379 		if (compressed_run == 1) {
380 			/* Compare next byte */
381 			if (memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
382 				rle_type = BMP_RLE_TYPE_RLE;
383 			}
384 		}
385 
386 		if (rle_type == BMP_RLE_TYPE_RLE) {
387 			if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) != 0) {
388 				/* more than what we can store in a single run or run is over due to non match, force write */
389 				rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
390 				row += rle_compression;
391 				compressed_length += rle_compression;
392 				compressed_run = 0;
393 				pixel--;
394 			} else {
395 				compressed_run++;
396 				uncompressed_rowp++;
397 			}
398 		} else {
399 			if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
400 				/* more than what we can store in a single run or run is over due to match, force write */
401 				rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
402 				row += rle_compression;
403 				compressed_length += rle_compression;
404 				compressed_run = 0;
405 				pixel--;
406 			} else {
407 				/* add this pixel to the row */
408 				compressed_run++;
409 				uncompressed_rowp++;
410 			}
411 
412 		}
413 	}
414 
415 	if (compressed_run) {
416 		compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
417 	}
418 
419 	gdFree(uncompressed_start);
420 
421 	return compressed_length;
422 }
423 
build_rle_packet(unsigned char * row,int packet_type,int length,unsigned char * data)424 static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data)
425 {
426 	int compressed_size = 0;
427 	if (length < 1 || length > 128) {
428 		return 0;
429 	}
430 
431 	/* Bitmap specific cases is that we can't have uncompressed rows of length 1 or 2 */
432 	if (packet_type == BMP_RLE_TYPE_RAW && length < 3) {
433 		int i = 0;
434 		for (i = 0; i < length; i++) {
435 			compressed_size += 2;
436 			memset(row, 1, 1);
437 			row++;
438 
439 			memcpy(row, data++, 1);
440 			row++;
441 		}
442 	} else if (packet_type == BMP_RLE_TYPE_RLE) {
443 		compressed_size = 2;
444 		memset(row, length, 1);
445 		row++;
446 
447 		memcpy(row, data, 1);
448 		row++;
449 	} else {
450 		compressed_size = 2 + length;
451 		memset(row, BMP_RLE_COMMAND, 1);
452 		row++;
453 
454 		memset(row, length, 1);
455 		row++;
456 
457 		memcpy(row, data, length);
458 		row += length;
459 
460 		/* Must be an even number for an uncompressed run */
461 		if (length % 2) {
462 			memset(row, 0, 1);
463 			row++;
464 			compressed_size++;
465 		}
466 	}
467 	return compressed_size;
468 }
469 
470 /*
471 	Function: gdImageCreateFromBmp
472 */
gdImageCreateFromBmp(FILE * inFile)473 BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp(FILE * inFile)
474 {
475 	gdImagePtr im = 0;
476 	gdIOCtx *in = gdNewFileCtx(inFile);
477 	if (in == NULL) return NULL;
478 	im = gdImageCreateFromBmpCtx(in);
479 	in->gd_free(in);
480 	return im;
481 }
482 
483 /*
484 	Function: gdImageCreateFromBmpPtr
485 */
gdImageCreateFromBmpPtr(int size,void * data)486 BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr(int size, void *data)
487 {
488 	gdImagePtr im;
489 	gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
490 	if (in == NULL) return NULL;
491 	im = gdImageCreateFromBmpCtx(in);
492 	in->gd_free(in);
493 	return im;
494 }
495 
496 /*
497 	Function: gdImageCreateFromBmpCtx
498 */
gdImageCreateFromBmpCtx(gdIOCtxPtr infile)499 BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
500 {
501 	bmp_hdr_t *hdr;
502 	bmp_info_t *info;
503 	gdImagePtr im = NULL;
504 	int error = 0;
505 
506 	if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
507 		return NULL;
508 	}
509 
510 	if (bmp_read_header(infile, hdr)) {
511 		gdFree(hdr);
512 		return NULL;
513 	}
514 
515 	if (hdr->magic != 0x4d42) {
516 		gdFree(hdr);
517 		return NULL;
518 	}
519 
520 	if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
521 		gdFree(hdr);
522 		return NULL;
523 	}
524 
525 	if (bmp_read_info(infile, info)) {
526 		gdFree(hdr);
527 		gdFree(info);
528 		return NULL;
529 	}
530 
531 	BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
532 	BMP_DEBUG(printf("Width: %d\n", info->width));
533 	BMP_DEBUG(printf("Height: %d\n", info->height));
534 	BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
535 	BMP_DEBUG(printf("Depth: %d\n", info->depth));
536 	BMP_DEBUG(printf("Offset: %d\n", hdr->off));
537 
538 	if (info->depth >= 16) {
539 		im = gdImageCreateTrueColor(info->width, info->height);
540 	} else {
541 		im = gdImageCreate(info->width, info->height);
542 	}
543 
544 	if (!im) {
545 		gdFree(hdr);
546 		gdFree(info);
547 		return NULL;
548 	}
549 
550 	switch (info->depth) {
551 	case 1:
552 		BMP_DEBUG(printf("1-bit image\n"));
553 		error = bmp_read_1bit(im, infile, info, hdr);
554 		break;
555 	case 4:
556 		BMP_DEBUG(printf("4-bit image\n"));
557 		error = bmp_read_4bit(im, infile, info, hdr);
558 		break;
559 	case 8:
560 		BMP_DEBUG(printf("8-bit image\n"));
561 		error = bmp_read_8bit(im, infile, info, hdr);
562 		break;
563 	case 16:
564 	case 24:
565 	case 32:
566 		BMP_DEBUG(printf("Direct BMP image\n"));
567 		error = bmp_read_direct(im, infile, info, hdr);
568 		break;
569 	default:
570 		BMP_DEBUG(printf("Unknown bit count\n"));
571 		error = 1;
572 	}
573 
574 	gdFree(hdr);
575 	gdFree(info);
576 
577 	if (error) {
578 		gdImageDestroy(im);
579 		return NULL;
580 	}
581 
582 	return im;
583 }
584 
bmp_read_header(gdIOCtx * infile,bmp_hdr_t * hdr)585 static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
586 {
587 	if(
588 	    !gdGetWordLSB(&hdr->magic, infile) ||
589 	    !gdGetIntLSB(&hdr->size, infile) ||
590 	    !gdGetWordLSB(&hdr->reserved1, infile) ||
591 	    !gdGetWordLSB(&hdr->reserved2 , infile) ||
592 	    !gdGetIntLSB(&hdr->off , infile)
593 	) {
594 		return 1;
595 	}
596 	return 0;
597 }
598 
bmp_read_info(gdIOCtx * infile,bmp_info_t * info)599 static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
600 {
601 	/* read BMP length so we can work out the version */
602 	if (!gdGetIntLSB(&info->len, infile)) {
603 		return 1;
604 	}
605 
606 	switch (info->len) {
607 		/* For now treat Windows v4 + v5 as v3 */
608 	case BMP_WINDOWS_V3:
609 	case BMP_WINDOWS_V4:
610 	case BMP_WINDOWS_V5:
611 		BMP_DEBUG(printf("Reading Windows Header\n"));
612 		if (bmp_read_windows_v3_info(infile, info)) {
613 			return 1;
614 		}
615 		break;
616 	case BMP_OS2_V1:
617 		if (bmp_read_os2_v1_info(infile, info)) {
618 			return 1;
619 		}
620 		break;
621 	case BMP_OS2_V2:
622 		if (bmp_read_os2_v2_info(infile, info)) {
623 			return 1;
624 		}
625 		break;
626 	default:
627 		BMP_DEBUG(printf("Unhandled bitmap\n"));
628 		return 1;
629 	}
630 	return 0;
631 }
632 
bmp_read_windows_v3_info(gdIOCtxPtr infile,bmp_info_t * info)633 static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
634 {
635 	if (
636 	    !gdGetIntLSB(&info->width, infile) ||
637 	    !gdGetIntLSB(&info->height, infile) ||
638 	    !gdGetWordLSB(&info->numplanes, infile) ||
639 	    !gdGetWordLSB(&info->depth, infile) ||
640 	    !gdGetIntLSB(&info->enctype, infile) ||
641 	    !gdGetIntLSB(&info->size, infile) ||
642 	    !gdGetIntLSB(&info->hres, infile) ||
643 	    !gdGetIntLSB(&info->vres, infile) ||
644 	    !gdGetIntLSB(&info->numcolors, infile) ||
645 	    !gdGetIntLSB(&info->mincolors, infile)
646 	) {
647 		return 1;
648 	}
649 
650 	/* Unlikely, but possible -- largest signed value won't fit in unsigned. */
651 	if (info->height == 0 || info->height == INT_MIN)
652 		return 1;
653 	if (info->height < 0) {
654 		info->topdown = 1;
655 		info->height = -info->height;
656 	} else {
657 		info->topdown = 0;
658 	}
659 
660 	info->type = BMP_PALETTE_4;
661 
662 	/* Height was checked above. */
663 	if (info->width <= 0 || info->numplanes <= 0 || info->depth <= 0 ||
664 	        info->numcolors < 0 || info->mincolors < 0) {
665 		return 1;
666 	}
667 
668 	return 0;
669 }
670 
bmp_read_os2_v1_info(gdIOCtxPtr infile,bmp_info_t * info)671 static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
672 {
673 	if (
674 	    !gdGetWordLSB((signed short int *)&info->width, infile) ||
675 	    !gdGetWordLSB((signed short int *)&info->height, infile) ||
676 	    !gdGetWordLSB(&info->numplanes, infile) ||
677 	    !gdGetWordLSB(&info->depth, infile)
678 	) {
679 		return 1;
680 	}
681 
682 	/* OS2 v1 doesn't support topdown */
683 	info->topdown = 0;
684 
685 	/* The spec says the depth can only be a few value values. */
686 	if (info->depth != 1 && info->depth != 4 && info->depth != 8 &&
687 	        info->depth != 16 && info->depth != 24) {
688 		return 1;
689 	}
690 
691 	info->numcolors = 1 << info->depth;
692 	info->type = BMP_PALETTE_3;
693 
694 	if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0) {
695 		return 1;
696 	}
697 
698 	return 0;
699 }
700 
bmp_read_os2_v2_info(gdIOCtxPtr infile,bmp_info_t * info)701 static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
702 {
703 	char useless_bytes[24];
704 	if (
705 	    !gdGetIntLSB(&info->width, infile) ||
706 	    !gdGetIntLSB(&info->height, infile) ||
707 	    !gdGetWordLSB(&info->numplanes, infile) ||
708 	    !gdGetWordLSB(&info->depth, infile) ||
709 	    !gdGetIntLSB(&info->enctype, infile) ||
710 	    !gdGetIntLSB(&info->size, infile) ||
711 	    !gdGetIntLSB(&info->hres, infile) ||
712 	    !gdGetIntLSB(&info->vres, infile) ||
713 	    !gdGetIntLSB(&info->numcolors, infile) ||
714 	    !gdGetIntLSB(&info->mincolors, infile)
715 	) {
716 		return 1;
717 	}
718 
719 	/* Lets seek the next 24 pointless bytes, we don't care too much about it */
720 	if (!gdGetBuf(useless_bytes, 24, infile)) {
721 		return 1;
722 	}
723 
724 	/* Unlikely, but possible -- largest signed value won't fit in unsigned. */
725 	if (info->height == 0 || info->height == INT_MIN)
726 		return 1;
727 	if (info->height < 0) {
728 		info->topdown = 1;
729 		info->height = -info->height;
730 	} else {
731 		info->topdown = 0;
732 	}
733 
734 	info->type = BMP_PALETTE_4;
735 
736 	/* Height was checked above. */
737 	if (info->width <= 0 || info->numplanes <= 0 || info->depth <= 0 ||
738 	        info->numcolors < 0 || info->mincolors < 0) {
739 		return 1;
740 	}
741 
742 	return 0;
743 }
744 
bmp_read_direct(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info,bmp_hdr_t * header)745 static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
746 {
747 	int ypos = 0, xpos = 0, row = 0;
748 	int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
749 	signed short int data = 0;
750 
751 	switch(info->enctype) {
752 	case BMP_BI_RGB:
753 		/* no-op */
754 		break;
755 
756 	case BMP_BI_BITFIELDS:
757 		if (info->depth == 24) {
758 			BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
759 			return 1;
760 		}
761 		BMP_DEBUG(printf("Currently no bitfield support\n"));
762 		return 1;
763 		break;
764 
765 	case BMP_BI_RLE8:
766 		if (info->depth != 8) {
767 			BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
768 			return 1;
769 		}
770 		break;
771 	case BMP_BI_RLE4:
772 		if (info->depth != 4) {
773 			BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
774 			return 1;
775 		}
776 		break;
777 	case BMP_BI_JPEG:
778 	case BMP_BI_PNG:
779 	default:
780 		BMP_DEBUG(printf("Unsupported BMP compression format\n"));
781 		return 1;
782 	}
783 
784 	/* There is a chance the data isn't until later, would be weird but it is possible */
785 	if (gdTell(infile) != header->off) {
786 		/* Should make sure we don't seek past the file size */
787 		if (!gdSeek(infile, header->off)) {
788 			return 1;
789 		}
790 	}
791 
792 	/* The line must be divisible by 4, else its padded with NULLs */
793 	padding = ((int)(info->depth / 8) * info->width) % 4;
794 	if (padding) {
795 		padding = 4 - padding;
796 	}
797 
798 
799 	for (ypos = 0; ypos < info->height; ++ypos) {
800 		if (info->topdown) {
801 			row = ypos;
802 		} else {
803 			row = info->height - ypos - 1;
804 		}
805 
806 		for (xpos = 0; xpos < info->width; xpos++) {
807 			if (info->depth == 16) {
808 				if (!gdGetWordLSB(&data, infile)) {
809 					return 1;
810 				}
811 				BMP_DEBUG(printf("Data: %X\n", data));
812 				red = ((data & 0x7C00) >> 10) << 3;
813 				green = ((data & 0x3E0) >> 5) << 3;
814 				blue = (data & 0x1F) << 3;
815 				BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
816 			} else if (info->depth == 24) {
817 				if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
818 					return 1;
819 				}
820 			} else {
821 				if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
822 					return 1;
823 				}
824 			}
825 			/*alpha = gdAlphaMax - (alpha >> 1);*/
826 			gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
827 		}
828 		for (xpos = padding; xpos > 0; --xpos) {
829 			if (!gdGetByte(&red, infile)) {
830 				return 1;
831 			}
832 		}
833 	}
834 
835 	return 0;
836 }
837 
bmp_read_palette(gdImagePtr im,gdIOCtxPtr infile,int count,int read_four)838 static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
839 {
840 	int i;
841 	int r, g, b, z;
842 
843 	for (i = 0; i < count; i++) {
844 		if (
845 		    !gdGetByte(&b, infile) ||
846 		    !gdGetByte(&g, infile) ||
847 		    !gdGetByte(&r, infile) ||
848 		    (read_four && !gdGetByte(&z, infile))
849 		) {
850 			return 1;
851 		}
852 		im->red[i] = r;
853 		im->green[i] = g;
854 		im->blue[i] = b;
855 		im->open[i] = 1;
856 	}
857 	return 0;
858 }
859 
bmp_read_1bit(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info,bmp_hdr_t * header)860 static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
861 {
862 	int ypos = 0, xpos = 0, row = 0, index = 0;
863 	int padding = 0, current_byte = 0, bit = 0;
864 
865 	if (info->enctype != BMP_BI_RGB) {
866 		return 1;
867 	}
868 
869 	if (!info->numcolors) {
870 		info->numcolors = 2;
871 	} else if (info->numcolors < 0 || info->numcolors > 2) {
872 		return 1;
873 	}
874 
875 	if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
876 		return 1;
877 	}
878 
879 	im->colorsTotal = info->numcolors;
880 
881 	/* There is a chance the data isn't until later, would be weird but it is possible */
882 	if (gdTell(infile) != header->off) {
883 		/* Should make sure we don't seek past the file size */
884 		if (!gdSeek(infile, header->off)) {
885 			return 1;
886 		}
887 	}
888 
889 	/* The line must be aligned on a 32 bits word, else it is padded with zeros */
890 	padding = (info->width + 7) / 8 % 4;
891 	if (padding) {
892 		padding = 4 - padding;
893 	}
894 
895 	for (ypos = 0; ypos < info->height; ++ypos) {
896 		if (info->topdown) {
897 			row = ypos;
898 		} else {
899 			row = info->height - ypos - 1;
900 		}
901 
902 		for (xpos = 0; xpos < info->width; xpos += 8) {
903 			/* Bitmaps are always aligned in bytes so we'll never overflow */
904 			if (!gdGetByte(&current_byte, infile)) {
905 				return 1;
906 			}
907 
908 			for (bit = 0; bit < 8; bit++) {
909 				index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
910 				if (im->open[index]) {
911 					im->open[index] = 0;
912 				}
913 				gdImageSetPixel(im, xpos + bit, row, index);
914 				/* No need to read anything extra */
915 				if ((xpos + bit) >= info->width) {
916 					break;
917 				}
918 			}
919 		}
920 
921 		for (xpos = padding; xpos > 0; --xpos) {
922 			if (!gdGetByte(&index, infile)) {
923 				return 1;
924 			}
925 		}
926 	}
927 	return 0;
928 }
929 
bmp_read_4bit(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info,bmp_hdr_t * header)930 static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
931 {
932 	int ypos = 0, xpos = 0, row = 0, index = 0;
933 	int padding = 0, current_byte = 0;
934 
935 	if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
936 		return 1;
937 	}
938 
939 	if (!info->numcolors) {
940 		info->numcolors = 16;
941 	} else if (info->numcolors < 0 || info->numcolors > 16) {
942 		return 1;
943 	}
944 
945 	if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
946 		return 1;
947 	}
948 
949 	im->colorsTotal = info->numcolors;
950 
951 	/* There is a chance the data isn't until later, would be weird but it is possible */
952 	if (gdTell(infile) != header->off) {
953 		/* Should make sure we don't seek past the file size */
954 		if (!gdSeek(infile, header->off)) {
955 			return 1;
956 		}
957 	}
958 
959 	/* The line must be divisible by 4, else its padded with NULLs */
960 	padding = ((int)ceil(0.5 * info->width)) % 4;
961 	if (padding) {
962 		padding = 4 - padding;
963 	}
964 
965 	switch (info->enctype) {
966 	case BMP_BI_RGB:
967 		for (ypos = 0; ypos < info->height; ++ypos) {
968 			if (info->topdown) {
969 				row = ypos;
970 			} else {
971 				row = info->height - ypos - 1;
972 			}
973 
974 			for (xpos = 0; xpos < info->width; xpos += 2) {
975 				if (!gdGetByte(&current_byte, infile)) {
976 					return 1;
977 				}
978 
979 				index = (current_byte >> 4) & 0x0f;
980 				if (im->open[index]) {
981 					im->open[index] = 0;
982 				}
983 				gdImageSetPixel(im, xpos, row, index);
984 
985 				/* This condition may get called often, potential optimsations */
986 				if (xpos >= info->width) {
987 					break;
988 				}
989 
990 				index = current_byte & 0x0f;
991 				if (im->open[index]) {
992 					im->open[index] = 0;
993 				}
994 				gdImageSetPixel(im, xpos + 1, row, index);
995 			}
996 
997 			for (xpos = padding; xpos > 0; --xpos) {
998 				if (!gdGetByte(&index, infile)) {
999 					return 1;
1000 				}
1001 			}
1002 		}
1003 		break;
1004 
1005 	case BMP_BI_RLE4:
1006 		if (bmp_read_rle(im, infile, info)) {
1007 			return 1;
1008 		}
1009 		break;
1010 
1011 	default:
1012 		return 1;
1013 	}
1014 	return 0;
1015 }
1016 
bmp_read_8bit(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info,bmp_hdr_t * header)1017 static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
1018 {
1019 	int ypos = 0, xpos = 0, row = 0, index = 0;
1020 	int padding = 0;
1021 
1022 	if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
1023 		return 1;
1024 	}
1025 
1026 	if (!info->numcolors) {
1027 		info->numcolors = 256;
1028 	} else if (info->numcolors < 0 || info->numcolors > 256) {
1029 		return 1;
1030 	}
1031 
1032 	if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
1033 		return 1;
1034 	}
1035 
1036 	im->colorsTotal = info->numcolors;
1037 
1038 	/* There is a chance the data isn't until later, would be weird but it is possible */
1039 	if (gdTell(infile) != header->off) {
1040 		/* Should make sure we don't seek past the file size */
1041 		if (!gdSeek(infile, header->off)) {
1042 			return 1;
1043 		}
1044 	}
1045 
1046 	/* The line must be divisible by 4, else its padded with NULLs */
1047 	padding = (1 * info->width) % 4;
1048 	if (padding) {
1049 		padding = 4 - padding;
1050 	}
1051 
1052 	switch (info->enctype) {
1053 	case BMP_BI_RGB:
1054 		for (ypos = 0; ypos < info->height; ++ypos) {
1055 			if (info->topdown) {
1056 				row = ypos;
1057 			} else {
1058 				row = info->height - ypos - 1;
1059 			}
1060 
1061 			for (xpos = 0; xpos < info->width; ++xpos) {
1062 				if (!gdGetByte(&index, infile)) {
1063 					return 1;
1064 				}
1065 
1066 				if (im->open[index]) {
1067 					im->open[index] = 0;
1068 				}
1069 				gdImageSetPixel(im, xpos, row, index);
1070 			}
1071 			/* Could create a new variable, but it isn't really worth it */
1072 			for (xpos = padding; xpos > 0; --xpos) {
1073 				if (!gdGetByte(&index, infile)) {
1074 					return 1;
1075 				}
1076 			}
1077 		}
1078 		break;
1079 
1080 	case BMP_BI_RLE8:
1081 		if (bmp_read_rle(im, infile, info)) {
1082 			return 1;
1083 		}
1084 		break;
1085 
1086 	default:
1087 		return 1;
1088 	}
1089 	return 0;
1090 }
1091 
bmp_read_rle(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info)1092 static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
1093 {
1094 	int ypos = 0, xpos = 0, row = 0, index = 0;
1095 	int rle_length = 0, rle_data = 0;
1096 	int padding = 0;
1097 	int i = 0, j = 0;
1098 	int pixels_per_byte = 8 / info->depth;
1099 
1100 	for (ypos = 0; ypos < info->height && xpos <= info->width;) {
1101 		if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1102 			return 1;
1103 		}
1104 		row = info->height - ypos - 1;
1105 
1106 		if (rle_length != BMP_RLE_COMMAND) {
1107 			if (im->open[rle_data]) {
1108 				im->open[rle_data] = 0;
1109 			}
1110 
1111 			for (i = 0; (i < rle_length) && (xpos < info->width);) {
1112 				for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
1113 					index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
1114 					if (im->open[index]) {
1115 						im->open[index] = 0;
1116 					}
1117 					gdImageSetPixel(im, xpos, row, index);
1118 				}
1119 			}
1120 		} else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
1121 			/* Uncompressed RLE needs to be even */
1122 			padding = 0;
1123 			for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
1124 				int max_pixels = pixels_per_byte;
1125 
1126 				if (!gdGetByte(&index, infile)) {
1127 					return 1;
1128 				}
1129 				padding++;
1130 
1131 				if (rle_data - i < max_pixels) {
1132 					max_pixels = rle_data - i;
1133 				}
1134 
1135 				for (j = 1; (j <= max_pixels)  && (xpos < info->width); j++, xpos++) {
1136 					int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
1137 					if (im->open[temp]) {
1138 						im->open[temp] = 0;
1139 					}
1140 					gdImageSetPixel(im, xpos, row, temp);
1141 				}
1142 			}
1143 
1144 			/* Make sure the bytes read are even */
1145 			if (padding % 2 && !gdGetByte(&index, infile)) {
1146 				return 1;
1147 			}
1148 		} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
1149 			/* Next Line */
1150 			xpos = 0;
1151 			ypos++;
1152 		} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
1153 			/* Delta Record, used for bmp files that contain other data*/
1154 			if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1155 				return 1;
1156 			}
1157 			xpos += rle_length;
1158 			ypos += rle_data;
1159 		} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
1160 			/* End of bitmap */
1161 			break;
1162 		}
1163 	}
1164 	return 0;
1165 }
1166