X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fpcx.c;h=b26e44274c4c99d8f7dbfa18857cf5bedd20af6b;hp=582f4ce52530ac50ac4a7c5292f054d2de403a2d;hb=8d46c5298f0fcce7bdb52f3835b2fbbdc403dfe0;hpb=cfd77b3698baacb01dff3853c96d0be117db1d30 diff --git a/src/pcx.c b/src/pcx.c index 582f4ce5..b26e4427 100644 --- a/src/pcx.c +++ b/src/pcx.c @@ -11,16 +11,21 @@ * pcx.c * ***********************************************************/ +#include "pcx.h" #include "image.h" +#include "misc.h" -#define PCX_MAGIC 0x0a /* first byte in a PCX image file */ -#define PCX_LAST_VERSION 5 /* last acceptable version number */ -#define PCX_ENCODING 1 /* PCX encoding method */ +#define PCX_DEBUG FALSE + +#define PCX_MAGIC 0x0a /* first byte in a PCX image file */ +#define PCX_LAST_VERSION 5 /* last acceptable version number */ +#define PCX_ENCODING 1 /* PCX encoding method */ #define PCX_256COLORS_MAGIC 0x0c /* first byte of a PCX 256 color map */ -#define PCX_MAXDEPTH 8 /* supports up to 8 bits per pixel */ -#define PCX_MAXCOLORS 256 /* maximum number of colors */ +#define PCX_MAXDEPTH 8 /* supports up to 8 bits per pixel */ +#define PCX_MAXCOLORS 256 /* maximum number of colors */ + #define PCX_HEADER_SIZE 128 -#define PCX_PALETTE_SIZE (3 * PCX_MAXCOLORS) +#define PCX_COLORMAP_SIZE (3 * PCX_MAXCOLORS) struct PCX_Header { @@ -42,146 +47,215 @@ struct PCX_Header unsigned char filler[58]; /* fill to struct size of 128 */ }; -static boolean PCX_LoadImage(); /* Routine to load PCX bitmap */ -static boolean PCX_LoadColormap(); /* Routine to load PCX colormap */ +/* global PCX error value */ +int errno_pcx = PCX_Success; + +static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last) +{ + /* Run Length Encoding: If the two high bits are set, + * then the low 6 bits contain a repeat count, and the byte to + * repeat is the next byte in the file. If the two high bits are + * not set, then this is the byte to write. + */ + + unsigned int bytes_per_pixel = (image->depth + 7) / 8; + register byte *bitmap_ptr, *bitmap_last; + register byte value, count; + + bitmap_ptr = image->data; + bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel); + + while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last) + { + value = *buffer_ptr++; + + if ((value & 0xc0) == 0xc0) /* this is a repeat count byte */ + { + count = value & 0x3f; /* extract repeat count from byte */ + value = *buffer_ptr++; /* next byte is value to repeat */ + + for (; count && bitmap_ptr < bitmap_last; count--) + *bitmap_ptr++ = value; + + if (count) /* repeat count spans end of bitmap */ + return NULL; + } + else + *bitmap_ptr++ = value; + + image->rgb.color_used[value] = TRUE; + } + + /* check if end of buffer was reached before end of bitmap */ + if (bitmap_ptr < bitmap_last) + return NULL; + + /* return current buffer position for next decoding function */ + return buffer_ptr; +} + +static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last) +{ + int i, magic; + + /* read colormap magic byte */ + magic = *buffer_ptr++; + + /* check magic colormap header byte */ + if (magic != PCX_256COLORS_MAGIC) + return NULL; + + /* check if enough bytes left for a complete colormap */ + if (buffer_ptr + PCX_COLORMAP_SIZE > buffer_last) + return NULL; + + /* read 256 colors from PCX colormap */ + for (i=0; irgb.red[i] = *buffer_ptr++ << 8; + image->rgb.green[i] = *buffer_ptr++ << 8; + image->rgb.blue[i] = *buffer_ptr++ << 8; + } + + /* return current buffer position for next decoding function */ + return buffer_ptr; +} Image *Read_PCX_to_Image(char *filename) { FILE *file; - unsigned char buffer[PCX_HEADER_SIZE]; + byte *file_buffer; + byte *buffer_ptr, *buffer_last; + unsigned int file_length; struct PCX_Header pcx; Image *image; int width, height, depth; + int i; + + errno_pcx = PCX_Success; if (!(file = fopen(filename, "r"))) + { + errno_pcx = PCX_OpenFailed; + return NULL; + } + + if (fseek(file, 0, SEEK_END) == -1) + { + fclose(file); + errno_pcx = PCX_ReadFailed; + return NULL; + } + + file_length = ftell(file); + rewind(file); + + if (file_length < PCX_HEADER_SIZE) + { + /* PCX file is too short to contain a valid PCX header */ + fclose(file); + + errno_pcx = PCX_FileInvalid; return NULL; + } + + file_buffer = checked_malloc(file_length); - /* read PCX header */ - if (fread(buffer, 1, PCX_HEADER_SIZE, file) != PCX_HEADER_SIZE) + if (fread(file_buffer, 1, file_length, file) != file_length) { fclose(file); + errno_pcx = PCX_ReadFailed; return NULL; } - pcx.signature = buffer[0]; - pcx.version = buffer[1]; - pcx.encoding = buffer[2]; - pcx.bits_per_pixel = buffer[3]; - pcx.xmin = buffer[4] + 256 * buffer[5]; - pcx.ymin = buffer[6] + 256 * buffer[7]; - pcx.xmax = buffer[8] + 256 * buffer[9]; - pcx.ymax = buffer[10] + 256 * buffer[11]; - pcx.color_planes = buffer[65]; - pcx.bytes_per_line = buffer[66] + 256 * buffer[67]; - pcx.palette_type = buffer[68] + 256 * buffer[69]; - - width = pcx.xmax - pcx.xmin + 1; + fclose(file); + + pcx.signature = file_buffer[0]; + pcx.version = file_buffer[1]; + pcx.encoding = file_buffer[2]; + pcx.bits_per_pixel = file_buffer[3]; + pcx.xmin = file_buffer[4] + 256 * file_buffer[5]; + pcx.ymin = file_buffer[6] + 256 * file_buffer[7]; + pcx.xmax = file_buffer[8] + 256 * file_buffer[9]; + pcx.ymax = file_buffer[10] + 256 * file_buffer[11]; + pcx.color_planes = file_buffer[65]; + pcx.bytes_per_line = file_buffer[66] + 256 * file_buffer[67]; + pcx.palette_type = file_buffer[68] + 256 * file_buffer[69]; + + width = pcx.xmax - pcx.xmin + 1; height = pcx.ymax - pcx.ymin + 1; - depth = pcx.bits_per_pixel; + depth = pcx.bits_per_pixel; if (pcx.signature != PCX_MAGIC || pcx.version > PCX_LAST_VERSION || pcx.encoding != PCX_ENCODING || pcx.color_planes > PCX_MAXDEPTH || width < 0 || height < 0) { - fclose(file); + free(file_buffer); + + errno_pcx = PCX_FileInvalid; return NULL; } +#if PCX_DEBUG if (options.verbose) { printf("%s is a %dx%d PC Paintbrush image with %d bitplanes\n", - filename, pcx.xmax, pcx.ymax, + filename, width, height, pcx.color_planes); printf("depth: %d\n", pcx.bits_per_pixel); + printf("color_planes: %d\n", pcx.color_planes); printf("bytes_per_line: %d\n", pcx.bytes_per_line); printf("palette type: %s\n", (pcx.palette_type == 1 ? "color" : pcx.palette_type == 2 ? "grayscale" : "undefined")); } +#endif /* allocate new image structure */ - image = newRGBImage(width, height, depth); + image = newImage(width, height, depth); + + buffer_ptr = file_buffer + PCX_HEADER_SIZE; + buffer_last = file_buffer + file_length; /* read compressed bitmap data */ - if (!PCX_LoadImage(file, image)) + if ((buffer_ptr = PCX_ReadBitmap(image, buffer_ptr, buffer_last)) == NULL) { - fclose(file); - return image; + free(file_buffer); + freeImage(image); + + errno_pcx = PCX_FileInvalid; + return NULL; } - /* read colormap data */ - if (!PCX_LoadColormap(file, image)) + if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE) { + /* PCX file is too short to contain a valid 256 colors colormap */ fclose(file); - return image; + errno_pcx = PCX_ColorFailed; + return NULL; } - fclose(file); - return(image); -} - -static boolean PCX_LoadImage(FILE *file, Image *image) -{ - /* Run Length Encoding: If the two high bits are set, - * then the low 6 bits contain a repeat count, and the byte to - * repeat is the next byte in the file. If the two high bits are - * not set, then this is the byte to write. - */ - - register unsigned char *ptr, *ptr_last; - int value, count; - - ptr = image->data; - ptr_last = ptr + (image->width * image->height * image->pixlen); - - while (ptr < ptr_last) + /* read colormap data */ + if (!PCX_ReadColormap(image, buffer_ptr, buffer_last)) { - if ((value = fgetc(file)) == EOF) - return FALSE; - - if ((value & 0xc0) == 0xc0) - { - count = value & 0x3f; - - if ((value = fgetc(file)) == EOF) - return FALSE; - - for ( ; count && (ptr < ptr_last); count--) - *ptr++ = (unsigned char)value; - - if (count) - printf("Repeat count spans end of image!\n"); - } - else - *ptr++ = (unsigned char)value; + free(file_buffer); + freeImage(image); + errno_pcx = PCX_ColorFailed; + return NULL; } - return TRUE; -} - -static boolean PCX_LoadColormap(FILE *file, Image *image) -{ - unsigned char buffer[PCX_PALETTE_SIZE]; - int i, result, magic; - - /* read colormap magic byte */ - if ((magic = fgetc(file)) == EOF) - return FALSE; - - if (magic != PCX_256COLORS_MAGIC) - return FALSE; - - /* read PCX 256 colors colormap */ - if ((result = fread(buffer, 1, PCX_PALETTE_SIZE, file)) != PCX_PALETTE_SIZE) - return FALSE; + free(file_buffer); + /* determine number of used colormap entries */ + image->rgb.used = 0; for (i=0; irgb.red[i] = buffer[i*3 + 0] << 8; - image->rgb.green[i] = buffer[i*3 + 1] << 8; - image->rgb.blue[i] = buffer[i*3 + 2] << 8; - } - image->rgb.used = PCX_MAXCOLORS; + if (image->rgb.color_used[i]) + image->rgb.used++; + +#if PCX_DEBUG + if (options.verbose) + printf("Read_PCX_to_Image: %d colors found\n", image->rgb.used); +#endif - return TRUE; + return image; }