Blame src/gd_bmp.c

Packit Service df60bb
/*
Packit Service df60bb
	gd_bmp.c
Packit Service df60bb
Packit Service df60bb
	Bitmap format support for libgd
Packit Service df60bb
Packit Service df60bb
	* Written 2007, Scott MacVicar
Packit Service df60bb
	---------------------------------------------------------------------------
Packit Service df60bb
Packit Service df60bb
	Todo:
Packit Service df60bb
Packit Service df60bb
	Bitfield encoding
Packit Service df60bb
Packit Service df60bb
	----------------------------------------------------------------------------
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
/**
Packit Service df60bb
 * File: BMP IO
Packit Service df60bb
 *
Packit Service df60bb
 * Read and write BMP images.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
/* $Id$ */
Packit Service df60bb
#ifdef HAVE_CONFIG_H
Packit Service df60bb
#include "config.h"
Packit Service df60bb
#endif
Packit Service df60bb
Packit Service df60bb
#include <stdio.h>
Packit Service df60bb
#include <math.h>
Packit Service df60bb
#include <string.h>
Packit Service df60bb
#include <stdlib.h>
Packit Service df60bb
#include "gd.h"
Packit Service df60bb
#include "gdhelpers.h"
Packit Service df60bb
#include "bmp.h"
Packit Service df60bb
Packit Service df60bb
static int compress_row(unsigned char *uncompressed_row, int length);
Packit Service df60bb
static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data);
Packit Service df60bb
Packit Service df60bb
static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
Packit Service df60bb
static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
Packit Service df60bb
static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
Packit Service df60bb
static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
Packit Service df60bb
static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
Packit Service df60bb
Packit Service df60bb
static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
Packit Service df60bb
static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
Packit Service df60bb
static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
Packit Service df60bb
static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
Packit Service df60bb
static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
Packit Service df60bb
Packit Service bc3754
static int _gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression);
Packit Service bc3754
Packit Service df60bb
#define BMP_DEBUG(s)
Packit Service df60bb
Packit Service df60bb
static int gdBMPPutWord(gdIOCtx *out, int w)
Packit Service df60bb
{
Packit Service df60bb
	/* Byte order is little-endian */
Packit Service df60bb
	gdPutC(w & 0xFF, out);
Packit Service df60bb
	gdPutC((w >> 8) & 0xFF, out);
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int gdBMPPutInt(gdIOCtx *out, int w)
Packit Service df60bb
{
Packit Service df60bb
	/* Byte order is little-endian */
Packit Service df60bb
	gdPutC(w & 0xFF, out);
Packit Service df60bb
	gdPutC((w >> 8) & 0xFF, out);
Packit Service df60bb
	gdPutC((w >> 16) & 0xFF, out);
Packit Service df60bb
	gdPutC((w >> 24) & 0xFF, out);
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageBmpPtr
Packit Service df60bb
Packit Service df60bb
	Outputs the given image as BMP data, but using a <gdIOCtx> instead
Packit Service df60bb
	of a file. See <gdImageBmp>.
Packit Service df60bb
Packit Service df60bb
	Parameters:
Packit Service df60bb
		im			- the image to save.
Packit Service df60bb
		size 		- Output: size in bytes of the result.
Packit Service df60bb
		compression - whether to apply RLE or not.
Packit Service df60bb
Packit Service df60bb
	Returns:
Packit Service df60bb
Packit Service df60bb
		A pointer to memory containing the image data or NULL on error.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression)
Packit Service df60bb
{
Packit Service df60bb
	void *rv;
Packit Service df60bb
	gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
Packit Service df60bb
	if (out == NULL) return NULL;
Packit Service bc3754
	if (!_gdImageBmpCtx(im, out, compression))
Packit Service bc3754
		rv = gdDPExtractData(out, size);
Packit Service bc3754
	else
Packit Service bc3754
		rv = NULL;
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
	return rv;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageBmp
Packit Service df60bb
Packit Service df60bb
    <gdImageBmp> outputs the specified image to the specified file in
Packit Service df60bb
    BMP format. The file must be open for writing. Under MSDOS and all
Packit Service df60bb
    versions of Windows, it is important to use "wb" as opposed to
Packit Service df60bb
    simply "w" as the mode when opening the file, and under Unix there
Packit Service df60bb
    is no penalty for doing so. <gdImageBmp> does not close the file;
Packit Service df60bb
    your code must do so.
Packit Service df60bb
Packit Service df60bb
    In addition, <gdImageBmp> allows to specify whether RLE compression
Packit Service df60bb
    should be applied.
Packit Service df60bb
Packit Service df60bb
	Variants:
Packit Service df60bb
Packit Service df60bb
		<gdImageBmpCtx> write via a <gdIOCtx> instead of a file handle.
Packit Service df60bb
Packit Service df60bb
		<gdImageBmpPtr> store the image file to memory.
Packit Service df60bb
Packit Service df60bb
	Parameters:
Packit Service df60bb
Packit Service df60bb
		im			- the image to save.
Packit Service df60bb
		outFile		- the output FILE* object.
Packit Service df60bb
		compression - whether to apply RLE or not.
Packit Service df60bb
Packit Service df60bb
	Returns:
Packit Service df60bb
		nothing
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression)
Packit Service df60bb
{
Packit Service df60bb
	gdIOCtx *out = gdNewFileCtx(outFile);
Packit Service df60bb
	if (out == NULL) return;
Packit Service df60bb
	gdImageBmpCtx(im, out, compression);
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageBmpCtx
Packit Service df60bb
Packit Service df60bb
	Outputs the given image as BMP data, but using a <gdIOCtx> instead
Packit Service df60bb
	of a file. See <gdImageBmp>.
Packit Service df60bb
Packit Service df60bb
	Parameters:
Packit Service df60bb
		im			- the image to save.
Packit Service df60bb
		out 		- the <gdIOCtx> to write to.
Packit Service df60bb
		compression - whether to apply RLE or not.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
Packit Service df60bb
{
Packit Service bc3754
	_gdImageBmpCtx(im, out, compression);
Packit Service bc3754
}
Packit Service bc3754
Packit Service bc3754
static int _gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
Packit Service bc3754
{
Packit Service df60bb
	int bitmap_size = 0, info_size, total_size, padding;
Packit Service df60bb
	int i, row, xpos, pixel;
Packit Service df60bb
	int error = 0;
Packit Service df60bb
	unsigned char *uncompressed_row = NULL, *uncompressed_row_start = NULL;
Packit Service df60bb
	FILE *tmpfile_for_compression = NULL;
Packit Service df60bb
	gdIOCtxPtr out_original = NULL;
Packit Service bc3754
	int ret = 1;
Packit Service df60bb
Packit Service df60bb
	/* No compression if its true colour or we don't support seek */
Packit Service df60bb
	if (im->trueColor) {
Packit Service df60bb
		compression = 0;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (compression && !out->seek) {
Packit Service df60bb
		/* Try to create a temp file where we can seek */
Packit Service df60bb
		if ((tmpfile_for_compression = tmpfile()) == NULL) {
Packit Service df60bb
			compression = 0;
Packit Service df60bb
		} else {
Packit Service df60bb
			out_original = out;
Packit Service df60bb
			if ((out = (gdIOCtxPtr)gdNewFileCtx(tmpfile_for_compression)) == NULL) {
Packit Service df60bb
				out = out_original;
Packit Service df60bb
				out_original = NULL;
Packit Service df60bb
				compression = 0;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	bitmap_size = ((im->sx * (im->trueColor ? 24 : 8)) / 8) * im->sy;
Packit Service df60bb
Packit Service df60bb
	/* 40 byte Windows v3 header */
Packit Service df60bb
	info_size = BMP_WINDOWS_V3;
Packit Service df60bb
Packit Service df60bb
	/* data for the palette */
Packit Service df60bb
	if (!im->trueColor) {
Packit Service df60bb
		info_size += im->colorsTotal * 4;
Packit Service df60bb
		if (compression) {
Packit Service df60bb
			bitmap_size = 0;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* bitmap header + info header + data */
Packit Service df60bb
	total_size = 14 + info_size + bitmap_size;
Packit Service df60bb
Packit Service df60bb
	/* write bmp header info */
Packit Service df60bb
	gdPutBuf("BM", 2, out);
Packit Service df60bb
	gdBMPPutInt(out, total_size);
Packit Service df60bb
	gdBMPPutWord(out, 0);
Packit Service df60bb
	gdBMPPutWord(out, 0);
Packit Service df60bb
	gdBMPPutInt(out, 14 + info_size);
Packit Service df60bb
Packit Service df60bb
	/* write Windows v3 headers */
Packit Service df60bb
	gdBMPPutInt(out, BMP_WINDOWS_V3); /* header size */
Packit Service df60bb
	gdBMPPutInt(out, im->sx); /* width */
Packit Service df60bb
	gdBMPPutInt(out, im->sy); /* height */
Packit Service df60bb
	gdBMPPutWord(out, 1); /* colour planes */
Packit Service df60bb
	gdBMPPutWord(out, (im->trueColor ? 24 : 8)); /* bit count */
Packit Service df60bb
	gdBMPPutInt(out, (compression ? BMP_BI_RLE8 : BMP_BI_RGB)); /* compression */
Packit Service df60bb
	gdBMPPutInt(out, bitmap_size); /* image size */
Packit Service df60bb
	gdBMPPutInt(out, 0); /* H resolution */
Packit Service df60bb
	gdBMPPutInt(out, 0); /* V ressolution */
Packit Service df60bb
	gdBMPPutInt(out, im->colorsTotal); /* colours used */
Packit Service df60bb
	gdBMPPutInt(out, 0); /* important colours */
Packit Service df60bb
Packit Service df60bb
	/* The line must be divisible by 4, else its padded with NULLs */
Packit Service df60bb
	padding = ((int)(im->trueColor ? 3 : 1) * im->sx) % 4;
Packit Service df60bb
	if (padding) {
Packit Service df60bb
		padding = 4 - padding;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* 8-bit colours */
Packit Service df60bb
	if (!im->trueColor) {
Packit Service df60bb
		for(i = 0; i< im->colorsTotal; ++i) {
Packit Service df60bb
			Putchar(gdImageBlue(im, i), out);
Packit Service df60bb
			Putchar(gdImageGreen(im, i), out);
Packit Service df60bb
			Putchar(gdImageRed(im, i), out);
Packit Service df60bb
			Putchar(0, out);
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		if (compression) {
Packit Service df60bb
			/* Can potentially change this to X + ((X / 128) * 3) */
Packit Service df60bb
			uncompressed_row = uncompressed_row_start = (unsigned char *) gdCalloc(gdImageSX(im) * 2, sizeof(char));
Packit Service df60bb
			if (!uncompressed_row) {
Packit Service df60bb
				/* malloc failed */
Packit Service df60bb
				goto cleanup;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		for (row = (im->sy - 1); row >= 0; row--) {
Packit Service df60bb
			if (compression) {
Packit Service df60bb
				memset (uncompressed_row, 0, gdImageSX(im));
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			for (xpos = 0; xpos < im->sx; xpos++) {
Packit Service df60bb
				if (compression) {
Packit Service df60bb
					*uncompressed_row++ = (unsigned char)gdImageGetPixel(im, xpos, row);
Packit Service df60bb
				} else {
Packit Service df60bb
					Putchar(gdImageGetPixel(im, xpos, row), out);
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			if (!compression) {
Packit Service df60bb
				/* Add padding to make sure we have n mod 4 == 0 bytes per row */
Packit Service df60bb
				for (xpos = padding; xpos > 0; --xpos) {
Packit Service df60bb
					Putchar('\0', out);
Packit Service df60bb
				}
Packit Service df60bb
			} else {
Packit Service df60bb
				int compressed_size = 0;
Packit Service df60bb
				uncompressed_row = uncompressed_row_start;
Packit Service df60bb
				if ((compressed_size = compress_row(uncompressed_row, gdImageSX(im))) < 0) {
Packit Service df60bb
					error = 1;
Packit Service df60bb
					break;
Packit Service df60bb
				}
Packit Service df60bb
				bitmap_size += compressed_size;
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
				gdPutBuf(uncompressed_row, compressed_size, out);
Packit Service df60bb
				Putchar(BMP_RLE_COMMAND, out);
Packit Service df60bb
				Putchar(BMP_RLE_ENDOFLINE, out);
Packit Service df60bb
				bitmap_size += 2;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		if (compression && uncompressed_row) {
Packit Service df60bb
			gdFree(uncompressed_row);
Packit Service df60bb
			if (error != 0) {
Packit Service df60bb
				goto cleanup;
Packit Service df60bb
			}
Packit Service df60bb
			/* Update filesize based on new values and set compression flag */
Packit Service df60bb
			Putchar(BMP_RLE_COMMAND, out);
Packit Service df60bb
			Putchar(BMP_RLE_ENDOFBITMAP, out);
Packit Service df60bb
			bitmap_size += 2;
Packit Service df60bb
Packit Service df60bb
			/* Write new total bitmap size */
Packit Service df60bb
			gdSeek(out, 2);
Packit Service df60bb
			gdBMPPutInt(out, total_size + bitmap_size);
Packit Service df60bb
Packit Service df60bb
			/* Total length of image data */
Packit Service df60bb
			gdSeek(out, 34);
Packit Service df60bb
			gdBMPPutInt(out, bitmap_size);
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
	} else {
Packit Service df60bb
		for (row = (im->sy - 1); row >= 0; row--) {
Packit Service df60bb
			for (xpos = 0; xpos < im->sx; xpos++) {
Packit Service df60bb
				pixel = gdImageGetPixel(im, xpos, row);
Packit Service df60bb
Packit Service df60bb
				Putchar(gdTrueColorGetBlue(pixel), out);
Packit Service df60bb
				Putchar(gdTrueColorGetGreen(pixel), out);
Packit Service df60bb
				Putchar(gdTrueColorGetRed(pixel), out);
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			/* Add padding to make sure we have n mod 4 == 0 bytes per row */
Packit Service df60bb
			for (xpos = padding; xpos > 0; --xpos) {
Packit Service df60bb
				Putchar('\0', out);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
	/* If we needed a tmpfile for compression copy it over to out_original */
Packit Service df60bb
	if (tmpfile_for_compression) {
Packit Service df60bb
		unsigned char* copy_buffer = NULL;
Packit Service df60bb
		int buffer_size = 0;
Packit Service df60bb
Packit Service df60bb
		gdSeek(out, 0);
Packit Service df60bb
		copy_buffer = (unsigned char *) gdMalloc(1024 * sizeof(unsigned char));
Packit Service df60bb
		if (copy_buffer == NULL) {
Packit Service df60bb
			goto cleanup;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		while ((buffer_size = gdGetBuf(copy_buffer, 1024, out)) != EOF) {
Packit Service df60bb
			if (buffer_size == 0) {
Packit Service df60bb
				break;
Packit Service df60bb
			}
Packit Service df60bb
			gdPutBuf(copy_buffer , buffer_size, out_original);
Packit Service df60bb
		}
Packit Service df60bb
		gdFree(copy_buffer);
Packit Service df60bb
Packit Service df60bb
		/* Replace the temp with the original which now has data */
Packit Service df60bb
		out->gd_free(out);
Packit Service df60bb
		out = out_original;
Packit Service df60bb
		out_original = NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service bc3754
	ret = 0;
Packit Service df60bb
cleanup:
Packit Service df60bb
	if (tmpfile_for_compression) {
Packit Service df60bb
#ifdef _WIN32
Packit Service df60bb
		_rmtmp();
Packit Service df60bb
#else
Packit Service df60bb
		fclose(tmpfile_for_compression);
Packit Service df60bb
#endif
Packit Service df60bb
		tmpfile_for_compression = NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (out_original) {
Packit Service df60bb
		out_original->gd_free(out_original);
Packit Service df60bb
	}
Packit Service bc3754
	return ret;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int compress_row(unsigned char *row, int length)
Packit Service df60bb
{
Packit Service df60bb
	int rle_type = 0;
Packit Service df60bb
	int compressed_length = 0;
Packit Service df60bb
	int pixel = 0, compressed_run = 0, rle_compression = 0;
Packit Service df60bb
	unsigned char *uncompressed_row = NULL, *uncompressed_rowp = NULL, *uncompressed_start = NULL;
Packit Service df60bb
Packit Service df60bb
	uncompressed_row = (unsigned char *) gdMalloc(length);
Packit Service df60bb
	if (!uncompressed_row) {
Packit Service df60bb
		return -1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	memcpy(uncompressed_row, row, length);
Packit Service df60bb
	uncompressed_start = uncompressed_rowp = uncompressed_row;
Packit Service df60bb
Packit Service df60bb
	for (pixel = 0; pixel < length; pixel++) {
Packit Service df60bb
		if (compressed_run == 0) {
Packit Service df60bb
			uncompressed_row = uncompressed_rowp;
Packit Service df60bb
			compressed_run++;
Packit Service df60bb
			uncompressed_rowp++;
Packit Service df60bb
			rle_type = BMP_RLE_TYPE_RAW;
Packit Service df60bb
			continue;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		if (compressed_run == 1) {
Packit Service df60bb
			/* Compare next byte */
Packit Service df60bb
			if (memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
Packit Service df60bb
				rle_type = BMP_RLE_TYPE_RLE;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		if (rle_type == BMP_RLE_TYPE_RLE) {
Packit Service df60bb
			if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) != 0) {
Packit Service df60bb
				/* more than what we can store in a single run or run is over due to non match, force write */
Packit Service df60bb
				rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
Packit Service df60bb
				row += rle_compression;
Packit Service df60bb
				compressed_length += rle_compression;
Packit Service df60bb
				compressed_run = 0;
Packit Service df60bb
				pixel--;
Packit Service df60bb
			} else {
Packit Service df60bb
				compressed_run++;
Packit Service df60bb
				uncompressed_rowp++;
Packit Service df60bb
			}
Packit Service df60bb
		} else {
Packit Service df60bb
			if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
Packit Service df60bb
				/* more than what we can store in a single run or run is over due to match, force write */
Packit Service df60bb
				rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
Packit Service df60bb
				row += rle_compression;
Packit Service df60bb
				compressed_length += rle_compression;
Packit Service df60bb
				compressed_run = 0;
Packit Service df60bb
				pixel--;
Packit Service df60bb
			} else {
Packit Service df60bb
				/* add this pixel to the row */
Packit Service df60bb
				compressed_run++;
Packit Service df60bb
				uncompressed_rowp++;
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (compressed_run) {
Packit Service df60bb
		compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	gdFree(uncompressed_start);
Packit Service df60bb
Packit Service df60bb
	return compressed_length;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data)
Packit Service df60bb
{
Packit Service df60bb
	int compressed_size = 0;
Packit Service df60bb
	if (length < 1 || length > 128) {
Packit Service df60bb
		return 0;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* Bitmap specific cases is that we can't have uncompressed rows of length 1 or 2 */
Packit Service df60bb
	if (packet_type == BMP_RLE_TYPE_RAW && length < 3) {
Packit Service df60bb
		int i = 0;
Packit Service df60bb
		for (i = 0; i < length; i++) {
Packit Service df60bb
			compressed_size += 2;
Packit Service df60bb
			memset(row, 1, 1);
Packit Service df60bb
			row++;
Packit Service df60bb
Packit Service df60bb
			memcpy(row, data++, 1);
Packit Service df60bb
			row++;
Packit Service df60bb
		}
Packit Service df60bb
	} else if (packet_type == BMP_RLE_TYPE_RLE) {
Packit Service df60bb
		compressed_size = 2;
Packit Service df60bb
		memset(row, length, 1);
Packit Service df60bb
		row++;
Packit Service df60bb
Packit Service df60bb
		memcpy(row, data, 1);
Packit Service df60bb
		row++;
Packit Service df60bb
	} else {
Packit Service df60bb
		compressed_size = 2 + length;
Packit Service df60bb
		memset(row, BMP_RLE_COMMAND, 1);
Packit Service df60bb
		row++;
Packit Service df60bb
Packit Service df60bb
		memset(row, length, 1);
Packit Service df60bb
		row++;
Packit Service df60bb
Packit Service df60bb
		memcpy(row, data, length);
Packit Service df60bb
		row += length;
Packit Service df60bb
Packit Service df60bb
		/* Must be an even number for an uncompressed run */
Packit Service df60bb
		if (length % 2) {
Packit Service df60bb
			memset(row, 0, 1);
Packit Service df60bb
			row++;
Packit Service df60bb
			compressed_size++;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	return compressed_size;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageCreateFromBmp
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp(FILE * inFile)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im = 0;
Packit Service df60bb
	gdIOCtx *in = gdNewFileCtx(inFile);
Packit Service df60bb
	if (in == NULL) return NULL;
Packit Service df60bb
	im = gdImageCreateFromBmpCtx(in);
Packit Service df60bb
	in->gd_free(in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageCreateFromBmpPtr
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr(int size, void *data)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
Packit Service df60bb
	if (in == NULL) return NULL;
Packit Service df60bb
	im = gdImageCreateFromBmpCtx(in);
Packit Service df60bb
	in->gd_free(in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageCreateFromBmpCtx
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
Packit Service df60bb
{
Packit Service df60bb
	bmp_hdr_t *hdr;
Packit Service df60bb
	bmp_info_t *info;
Packit Service df60bb
	gdImagePtr im = NULL;
Packit Service df60bb
	int error = 0;
Packit Service df60bb
Packit Service df60bb
	if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (bmp_read_header(infile, hdr)) {
Packit Service df60bb
		gdFree(hdr);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (hdr->magic != 0x4d42) {
Packit Service df60bb
		gdFree(hdr);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
Packit Service df60bb
		gdFree(hdr);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (bmp_read_info(infile, info)) {
Packit Service df60bb
		gdFree(hdr);
Packit Service df60bb
		gdFree(info);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
Packit Service df60bb
	BMP_DEBUG(printf("Width: %d\n", info->width));
Packit Service df60bb
	BMP_DEBUG(printf("Height: %d\n", info->height));
Packit Service df60bb
	BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
Packit Service df60bb
	BMP_DEBUG(printf("Depth: %d\n", info->depth));
Packit Service df60bb
	BMP_DEBUG(printf("Offset: %d\n", hdr->off));
Packit Service df60bb
Packit Service df60bb
	if (info->depth >= 16) {
Packit Service df60bb
		im = gdImageCreateTrueColor(info->width, info->height);
Packit Service df60bb
	} else {
Packit Service df60bb
		im = gdImageCreate(info->width, info->height);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!im) {
Packit Service df60bb
		gdFree(hdr);
Packit Service df60bb
		gdFree(info);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	switch (info->depth) {
Packit Service df60bb
	case 1:
Packit Service df60bb
		BMP_DEBUG(printf("1-bit image\n"));
Packit Service df60bb
		error = bmp_read_1bit(im, infile, info, hdr);
Packit Service df60bb
		break;
Packit Service df60bb
	case 4:
Packit Service df60bb
		BMP_DEBUG(printf("4-bit image\n"));
Packit Service df60bb
		error = bmp_read_4bit(im, infile, info, hdr);
Packit Service df60bb
		break;
Packit Service df60bb
	case 8:
Packit Service df60bb
		BMP_DEBUG(printf("8-bit image\n"));
Packit Service df60bb
		error = bmp_read_8bit(im, infile, info, hdr);
Packit Service df60bb
		break;
Packit Service df60bb
	case 16:
Packit Service df60bb
	case 24:
Packit Service df60bb
	case 32:
Packit Service df60bb
		BMP_DEBUG(printf("Direct BMP image\n"));
Packit Service df60bb
		error = bmp_read_direct(im, infile, info, hdr);
Packit Service df60bb
		break;
Packit Service df60bb
	default:
Packit Service df60bb
		BMP_DEBUG(printf("Unknown bit count\n"));
Packit Service df60bb
		error = 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	gdFree(hdr);
Packit Service df60bb
	gdFree(info);
Packit Service df60bb
Packit Service df60bb
	if (error) {
Packit Service df60bb
		gdImageDestroy(im);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
Packit Service df60bb
{
Packit Service df60bb
	if(
Packit Service df60bb
	    !gdGetWordLSB(&hdr->magic, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&hdr->size, infile) ||
Packit Service df60bb
	    !gdGetWordLSB(&hdr->reserved1, infile) ||
Packit Service df60bb
	    !gdGetWordLSB(&hdr->reserved2 , infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&hdr->off , infile)
Packit Service df60bb
	) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
Packit Service df60bb
{
Packit Service df60bb
	/* read BMP length so we can work out the version */
Packit Service df60bb
	if (!gdGetIntLSB(&info->len, infile)) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	switch (info->len) {
Packit Service df60bb
		/* For now treat Windows v4 + v5 as v3 */
Packit Service df60bb
	case BMP_WINDOWS_V3:
Packit Service df60bb
	case BMP_WINDOWS_V4:
Packit Service df60bb
	case BMP_WINDOWS_V5:
Packit Service df60bb
		BMP_DEBUG(printf("Reading Windows Header\n"));
Packit Service df60bb
		if (bmp_read_windows_v3_info(infile, info)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
	case BMP_OS2_V1:
Packit Service df60bb
		if (bmp_read_os2_v1_info(infile, info)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
	case BMP_OS2_V2:
Packit Service df60bb
		if (bmp_read_os2_v2_info(infile, info)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
	default:
Packit Service df60bb
		BMP_DEBUG(printf("Unhandled bitmap\n"));
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
Packit Service df60bb
{
Packit Service df60bb
	if (
Packit Service df60bb
	    !gdGetIntLSB(&info->width, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->height, infile) ||
Packit Service df60bb
	    !gdGetWordLSB(&info->numplanes, infile) ||
Packit Service df60bb
	    !gdGetWordLSB(&info->depth, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->enctype, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->size, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->hres, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->vres, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->numcolors, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->mincolors, infile)
Packit Service df60bb
	) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (info->height < 0) {
Packit Service df60bb
		info->topdown = 1;
Packit Service df60bb
		info->height = -info->height;
Packit Service df60bb
	} else {
Packit Service df60bb
		info->topdown = 0;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	info->type = BMP_PALETTE_4;
Packit Service df60bb
Packit Service df60bb
	if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
Packit Service df60bb
	        info->depth <= 0  || info->numcolors < 0 || info->mincolors < 0) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
Packit Service df60bb
{
Packit Service df60bb
	if (
Packit Service df60bb
	    !gdGetWordLSB((signed short int *)&info->width, infile) ||
Packit Service df60bb
	    !gdGetWordLSB((signed short int *)&info->height, infile) ||
Packit Service df60bb
	    !gdGetWordLSB(&info->numplanes, infile) ||
Packit Service df60bb
	    !gdGetWordLSB(&info->depth, infile)
Packit Service df60bb
	) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* OS2 v1 doesn't support topdown */
Packit Service df60bb
	info->topdown = 0;
Packit Service df60bb
Packit Service df60bb
	info->numcolors = 1 << info->depth;
Packit Service df60bb
	info->type = BMP_PALETTE_3;
Packit Service df60bb
Packit Service df60bb
	if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
Packit Service df60bb
	        info->depth <= 0 || info->numcolors < 0) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
Packit Service df60bb
{
Packit Service df60bb
	char useless_bytes[24];
Packit Service df60bb
	if (
Packit Service df60bb
	    !gdGetIntLSB(&info->width, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->height, infile) ||
Packit Service df60bb
	    !gdGetWordLSB(&info->numplanes, infile) ||
Packit Service df60bb
	    !gdGetWordLSB(&info->depth, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->enctype, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->size, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->hres, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->vres, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->numcolors, infile) ||
Packit Service df60bb
	    !gdGetIntLSB(&info->mincolors, infile)
Packit Service df60bb
	) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* Lets seek the next 24 pointless bytes, we don't care too much about it */
Packit Service df60bb
	if (!gdGetBuf(useless_bytes, 24, infile)) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (info->height < 0) {
Packit Service df60bb
		info->topdown = 1;
Packit Service df60bb
		info->height = -info->height;
Packit Service df60bb
	} else {
Packit Service df60bb
		info->topdown = 0;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	info->type = BMP_PALETTE_4;
Packit Service df60bb
Packit Service df60bb
	if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
Packit Service df60bb
	        info->depth <= 0  || info->numcolors < 0 || info->mincolors < 0) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
Packit Service df60bb
{
Packit Service df60bb
	int ypos = 0, xpos = 0, row = 0;
Packit Service df60bb
	int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
Packit Service df60bb
	signed short int data = 0;
Packit Service df60bb
Packit Service df60bb
	switch(info->enctype) {
Packit Service df60bb
	case BMP_BI_RGB:
Packit Service df60bb
		/* no-op */
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case BMP_BI_BITFIELDS:
Packit Service df60bb
		if (info->depth == 24) {
Packit Service df60bb
			BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		BMP_DEBUG(printf("Currently no bitfield support\n"));
Packit Service df60bb
		return 1;
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case BMP_BI_RLE8:
Packit Service df60bb
		if (info->depth != 8) {
Packit Service df60bb
			BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
	case BMP_BI_RLE4:
Packit Service df60bb
		if (info->depth != 4) {
Packit Service df60bb
			BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
	case BMP_BI_JPEG:
Packit Service df60bb
	case BMP_BI_PNG:
Packit Service df60bb
	default:
Packit Service df60bb
		BMP_DEBUG(printf("Unsupported BMP compression format\n"));
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* There is a chance the data isn't until later, would be wierd but it is possible */
Packit Service df60bb
	if (gdTell(infile) != header->off) {
Packit Service df60bb
		/* Should make sure we don't seek past the file size */
Packit Service df60bb
		if (!gdSeek(infile, header->off)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* The line must be divisible by 4, else its padded with NULLs */
Packit Service df60bb
	padding = ((int)(info->depth / 8) * info->width) % 4;
Packit Service df60bb
	if (padding) {
Packit Service df60bb
		padding = 4 - padding;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
	for (ypos = 0; ypos < info->height; ++ypos) {
Packit Service df60bb
		if (info->topdown) {
Packit Service df60bb
			row = ypos;
Packit Service df60bb
		} else {
Packit Service df60bb
			row = info->height - ypos - 1;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		for (xpos = 0; xpos < info->width; xpos++) {
Packit Service df60bb
			if (info->depth == 16) {
Packit Service df60bb
				if (!gdGetWordLSB(&data, infile)) {
Packit Service df60bb
					return 1;
Packit Service df60bb
				}
Packit Service df60bb
				BMP_DEBUG(printf("Data: %X\n", data));
Packit Service df60bb
				red = ((data & 0x7C00) >> 10) << 3;
Packit Service df60bb
				green = ((data & 0x3E0) >> 5) << 3;
Packit Service df60bb
				blue = (data & 0x1F) << 3;
Packit Service df60bb
				BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
Packit Service df60bb
			} else if (info->depth == 24) {
Packit Service df60bb
				if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
Packit Service df60bb
					return 1;
Packit Service df60bb
				}
Packit Service df60bb
			} else {
Packit Service df60bb
				if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
Packit Service df60bb
					return 1;
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
			/*alpha = gdAlphaMax - (alpha >> 1);*/
Packit Service df60bb
			gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
Packit Service df60bb
		}
Packit Service df60bb
		for (xpos = padding; xpos > 0; --xpos) {
Packit Service df60bb
			if (!gdGetByte(&red, infile)) {
Packit Service df60bb
				return 1;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
Packit Service df60bb
{
Packit Service df60bb
	int i;
Packit Service df60bb
	int r, g, b, z;
Packit Service df60bb
Packit Service df60bb
	for (i = 0; i < count; i++) {
Packit Service df60bb
		if (
Packit Service df60bb
		    !gdGetByte(&b, infile) ||
Packit Service df60bb
		    !gdGetByte(&g, infile) ||
Packit Service df60bb
		    !gdGetByte(&r, infile) ||
Packit Service df60bb
		    (read_four && !gdGetByte(&z, infile))
Packit Service df60bb
		) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		im->red[i] = r;
Packit Service df60bb
		im->green[i] = g;
Packit Service df60bb
		im->blue[i] = b;
Packit Service df60bb
		im->open[i] = 1;
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
Packit Service df60bb
{
Packit Service df60bb
	int ypos = 0, xpos = 0, row = 0, index = 0;
Packit Service df60bb
	int padding = 0, current_byte = 0, bit = 0;
Packit Service df60bb
Packit Service df60bb
	if (info->enctype != BMP_BI_RGB) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!info->numcolors) {
Packit Service df60bb
		info->numcolors = 2;
Packit Service df60bb
	} else if (info->numcolors < 0 || info->numcolors > 2) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	im->colorsTotal = info->numcolors;
Packit Service df60bb
Packit Service df60bb
	/* There is a chance the data isn't until later, would be wierd but it is possible */
Packit Service df60bb
	if (gdTell(infile) != header->off) {
Packit Service df60bb
		/* Should make sure we don't seek past the file size */
Packit Service df60bb
		if (!gdSeek(infile, header->off)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* The line must be divisible by 4, else its padded with NULLs */
Packit Service df60bb
	padding = ((int)ceil(0.1 * info->width)) % 4;
Packit Service df60bb
	if (padding) {
Packit Service df60bb
		padding = 4 - padding;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	for (ypos = 0; ypos < info->height; ++ypos) {
Packit Service df60bb
		if (info->topdown) {
Packit Service df60bb
			row = ypos;
Packit Service df60bb
		} else {
Packit Service df60bb
			row = info->height - ypos - 1;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		for (xpos = 0; xpos < info->width; xpos += 8) {
Packit Service df60bb
			/* Bitmaps are always aligned in bytes so we'll never overflow */
Packit Service df60bb
			if (!gdGetByte(&current_byte, infile)) {
Packit Service df60bb
				return 1;
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			for (bit = 0; bit < 8; bit++) {
Packit Service df60bb
				index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
Packit Service df60bb
				if (im->open[index]) {
Packit Service df60bb
					im->open[index] = 0;
Packit Service df60bb
				}
Packit Service df60bb
				gdImageSetPixel(im, xpos + bit, row, index);
Packit Service df60bb
				/* No need to read anything extra */
Packit Service df60bb
				if ((xpos + bit) >= info->width) {
Packit Service df60bb
					break;
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		for (xpos = padding; xpos > 0; --xpos) {
Packit Service df60bb
			if (!gdGetByte(&index, infile)) {
Packit Service df60bb
				return 1;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
Packit Service df60bb
{
Packit Service df60bb
	int ypos = 0, xpos = 0, row = 0, index = 0;
Packit Service df60bb
	int padding = 0, current_byte = 0;
Packit Service df60bb
Packit Service df60bb
	if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!info->numcolors) {
Packit Service df60bb
		info->numcolors = 16;
Packit Service df60bb
	} else if (info->numcolors < 0 || info->numcolors > 16) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	im->colorsTotal = info->numcolors;
Packit Service df60bb
Packit Service df60bb
	/* There is a chance the data isn't until later, would be wierd but it is possible */
Packit Service df60bb
	if (gdTell(infile) != header->off) {
Packit Service df60bb
		/* Should make sure we don't seek past the file size */
Packit Service df60bb
		if (!gdSeek(infile, header->off)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* The line must be divisible by 4, else its padded with NULLs */
Packit Service df60bb
	padding = ((int)ceil(0.5 * info->width)) % 4;
Packit Service df60bb
	if (padding) {
Packit Service df60bb
		padding = 4 - padding;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	switch (info->enctype) {
Packit Service df60bb
	case BMP_BI_RGB:
Packit Service df60bb
		for (ypos = 0; ypos < info->height; ++ypos) {
Packit Service df60bb
			if (info->topdown) {
Packit Service df60bb
				row = ypos;
Packit Service df60bb
			} else {
Packit Service df60bb
				row = info->height - ypos - 1;
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			for (xpos = 0; xpos < info->width; xpos += 2) {
Packit Service df60bb
				if (!gdGetByte(&current_byte, infile)) {
Packit Service df60bb
					return 1;
Packit Service df60bb
				}
Packit Service df60bb
Packit Service df60bb
				index = (current_byte >> 4) & 0x0f;
Packit Service df60bb
				if (im->open[index]) {
Packit Service df60bb
					im->open[index] = 0;
Packit Service df60bb
				}
Packit Service df60bb
				gdImageSetPixel(im, xpos, row, index);
Packit Service df60bb
Packit Service df60bb
				/* This condition may get called often, potential optimsations */
Packit Service df60bb
				if (xpos >= info->width) {
Packit Service df60bb
					break;
Packit Service df60bb
				}
Packit Service df60bb
Packit Service df60bb
				index = current_byte & 0x0f;
Packit Service df60bb
				if (im->open[index]) {
Packit Service df60bb
					im->open[index] = 0;
Packit Service df60bb
				}
Packit Service df60bb
				gdImageSetPixel(im, xpos + 1, row, index);
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			for (xpos = padding; xpos > 0; --xpos) {
Packit Service df60bb
				if (!gdGetByte(&index, infile)) {
Packit Service df60bb
					return 1;
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case BMP_BI_RLE4:
Packit Service df60bb
		if (bmp_read_rle(im, infile, info)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	default:
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
Packit Service df60bb
{
Packit Service df60bb
	int ypos = 0, xpos = 0, row = 0, index = 0;
Packit Service df60bb
	int padding = 0;
Packit Service df60bb
Packit Service df60bb
	if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!info->numcolors) {
Packit Service df60bb
		info->numcolors = 256;
Packit Service df60bb
	} else if (info->numcolors < 0 || info->numcolors > 256) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	im->colorsTotal = info->numcolors;
Packit Service df60bb
Packit Service df60bb
	/* There is a chance the data isn't until later, would be wierd but it is possible */
Packit Service df60bb
	if (gdTell(infile) != header->off) {
Packit Service df60bb
		/* Should make sure we don't seek past the file size */
Packit Service df60bb
		if (!gdSeek(infile, header->off)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* The line must be divisible by 4, else its padded with NULLs */
Packit Service df60bb
	padding = (1 * info->width) % 4;
Packit Service df60bb
	if (padding) {
Packit Service df60bb
		padding = 4 - padding;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	switch (info->enctype) {
Packit Service df60bb
	case BMP_BI_RGB:
Packit Service df60bb
		for (ypos = 0; ypos < info->height; ++ypos) {
Packit Service df60bb
			if (info->topdown) {
Packit Service df60bb
				row = ypos;
Packit Service df60bb
			} else {
Packit Service df60bb
				row = info->height - ypos - 1;
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			for (xpos = 0; xpos < info->width; ++xpos) {
Packit Service df60bb
				if (!gdGetByte(&index, infile)) {
Packit Service df60bb
					return 1;
Packit Service df60bb
				}
Packit Service df60bb
Packit Service df60bb
				if (im->open[index]) {
Packit Service df60bb
					im->open[index] = 0;
Packit Service df60bb
				}
Packit Service df60bb
				gdImageSetPixel(im, xpos, row, index);
Packit Service df60bb
			}
Packit Service df60bb
			/* Could create a new variable, but it isn't really worth it */
Packit Service df60bb
			for (xpos = padding; xpos > 0; --xpos) {
Packit Service df60bb
				if (!gdGetByte(&index, infile)) {
Packit Service df60bb
					return 1;
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case BMP_BI_RLE8:
Packit Service df60bb
		if (bmp_read_rle(im, infile, info)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	default:
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
Packit Service df60bb
{
Packit Service df60bb
	int ypos = 0, xpos = 0, row = 0, index = 0;
Packit Service df60bb
	int rle_length = 0, rle_data = 0;
Packit Service df60bb
	int padding = 0;
Packit Service df60bb
	int i = 0, j = 0;
Packit Service df60bb
	int pixels_per_byte = 8 / info->depth;
Packit Service df60bb
Packit Service df60bb
	for (ypos = 0; ypos < info->height && xpos <= info->width;) {
Packit Service df60bb
		if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
Packit Service df60bb
			return 1;
Packit Service df60bb
		}
Packit Service df60bb
		row = info->height - ypos - 1;
Packit Service df60bb
Packit Service df60bb
		if (rle_length != BMP_RLE_COMMAND) {
Packit Service df60bb
			if (im->open[rle_data]) {
Packit Service df60bb
				im->open[rle_data] = 0;
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			for (i = 0; (i < rle_length) && (xpos < info->width);) {
Packit Service df60bb
				for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
Packit Service df60bb
					index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
Packit Service df60bb
					if (im->open[index]) {
Packit Service df60bb
						im->open[index] = 0;
Packit Service df60bb
					}
Packit Service df60bb
					gdImageSetPixel(im, xpos, row, index);
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
		} else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
Packit Service df60bb
			/* Uncompressed RLE needs to be even */
Packit Service df60bb
			padding = 0;
Packit Service df60bb
			for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
Packit Service df60bb
				int max_pixels = pixels_per_byte;
Packit Service df60bb
Packit Service df60bb
				if (!gdGetByte(&index, infile)) {
Packit Service df60bb
					return 1;
Packit Service df60bb
				}
Packit Service df60bb
				padding++;
Packit Service df60bb
Packit Service df60bb
				if (rle_data - i < max_pixels) {
Packit Service df60bb
					max_pixels = rle_data - i;
Packit Service df60bb
				}
Packit Service df60bb
Packit Service df60bb
				for (j = 1; (j <= max_pixels)  && (xpos < info->width); j++, xpos++) {
Packit Service df60bb
					int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
Packit Service df60bb
					if (im->open[temp]) {
Packit Service df60bb
						im->open[temp] = 0;
Packit Service df60bb
					}
Packit Service df60bb
					gdImageSetPixel(im, xpos, row, temp);
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			/* Make sure the bytes read are even */
Packit Service df60bb
			if (padding % 2 && !gdGetByte(&index, infile)) {
Packit Service df60bb
				return 1;
Packit Service df60bb
			}
Packit Service df60bb
		} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
Packit Service df60bb
			/* Next Line */
Packit Service df60bb
			xpos = 0;
Packit Service df60bb
			ypos++;
Packit Service df60bb
		} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
Packit Service df60bb
			/* Delta Record, used for bmp files that contain other data*/
Packit Service df60bb
			if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
Packit Service df60bb
				return 1;
Packit Service df60bb
			}
Packit Service df60bb
			xpos += rle_length;
Packit Service df60bb
			ypos += rle_data;
Packit Service df60bb
		} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
Packit Service df60bb
			/* End of bitmap */
Packit Service df60bb
			break;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
}