X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fpcx.c;h=f2dac1d9cfdb266bc669d54bab7a6a3770b4988b;hp=582f4ce52530ac50ac4a7c5292f054d2de403a2d;hb=ab0879a8bcb3e816912bc89b8e21c22cc2a4c0c2;hpb=cfd77b3698baacb01dff3853c96d0be117db1d30 diff --git a/src/pcx.c b/src/pcx.c index 582f4ce5..f2dac1d9 100644 --- a/src/pcx.c +++ b/src/pcx.c @@ -12,15 +12,17 @@ ***********************************************************/ #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_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,48 +44,69 @@ 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 */ +static byte *PCX_ReadBitmap(Image *, byte *, byte *); +static byte *PCX_ReadColormap(Image *, byte *, byte *); 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; if (!(file = fopen(filename, "r"))) return NULL; - /* read PCX header */ - if (fread(buffer, 1, PCX_HEADER_SIZE, file) != PCX_HEADER_SIZE) + if (fseek(file, 0, SEEK_END) == -1) { fclose(file); 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; + file_length = ftell(file); + rewind(file); + + if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE) + { + fclose(file); + return NULL; + } + + file_buffer = checked_malloc(file_length); + + if (fread(file_buffer, 1, file_length, file) != file_length) + { + fclose(file); + return NULL; + } + + 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); return NULL; } @@ -100,27 +123,42 @@ Image *Read_PCX_to_Image(char *filename) } /* 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); + return NULL; } /* read colormap data */ - if (!PCX_LoadColormap(file, image)) + if (!PCX_ReadColormap(image, buffer_ptr, buffer_last)) { - fclose(file); - return image; + free(file_buffer); + freeImage(image); + return NULL; } - fclose(file); - return(image); + free(file_buffer); + + /* determine number of used colormap entries */ + image->rgb.used = 0; + for (i=0; irgb.color_used[i]) + image->rgb.used++; + + if (options.verbose) + printf("Read_PCX_to_Image: %d colors found\n", image->rgb.used); + + return image; } -static boolean PCX_LoadImage(FILE *file, Image *image) +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 @@ -128,60 +166,65 @@ static boolean PCX_LoadImage(FILE *file, Image *image) * not set, then this is the byte to write. */ - register unsigned char *ptr, *ptr_last; - int value, count; + unsigned int bytes_per_pixel = (image->depth + 7) / 8; + register byte *bitmap_ptr, *bitmap_last; + register byte value, count; - ptr = image->data; - ptr_last = ptr + (image->width * image->height * image->pixlen); + bitmap_ptr = image->data; + bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel); - while (ptr < ptr_last) + while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last) { - if ((value = fgetc(file)) == EOF) - return FALSE; + value = *buffer_ptr++; - if ((value & 0xc0) == 0xc0) + if ((value & 0xc0) == 0xc0) /* this is a repeat count byte */ { - count = value & 0x3f; + count = value & 0x3f; /* extract repeat count from byte */ + value = *buffer_ptr++; /* next byte is value to repeat */ - if ((value = fgetc(file)) == EOF) - return FALSE; + for (; count && bitmap_ptr < bitmap_last; count--) + *bitmap_ptr++ = value; - for ( ; count && (ptr < ptr_last); count--) - *ptr++ = (unsigned char)value; - - if (count) - printf("Repeat count spans end of image!\n"); + if (count) /* repeat count spans end of bitmap */ + return NULL; } else - *ptr++ = (unsigned char)value; + *bitmap_ptr++ = value; + + image->rgb.color_used[value] = TRUE; } - return 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 boolean PCX_LoadColormap(FILE *file, Image *image) +static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last) { - unsigned char buffer[PCX_PALETTE_SIZE]; - int i, result, magic; + int i, magic; /* read colormap magic byte */ - if ((magic = fgetc(file)) == EOF) - return FALSE; + magic = *buffer_ptr++; + /* check magic colormap header byte */ if (magic != PCX_256COLORS_MAGIC) - return FALSE; + return NULL; - /* read PCX 256 colors colormap */ - if ((result = fread(buffer, 1, PCX_PALETTE_SIZE, file)) != PCX_PALETTE_SIZE) - return FALSE; + /* 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[i*3 + 0] << 8; - image->rgb.green[i] = buffer[i*3 + 1] << 8; - image->rgb.blue[i] = buffer[i*3 + 2] << 8; + image->rgb.red[i] = *buffer_ptr++ << 8; + image->rgb.green[i] = *buffer_ptr++ << 8; + image->rgb.blue[i] = *buffer_ptr++ << 8; } - image->rgb.used = PCX_MAXCOLORS; - return TRUE; + /* return current buffer position for next decoding function */ + return buffer_ptr; }