r1258 - trunk/code/renderer
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Thu Feb 14 06:13:32 EST 2008
Author: ludwig
Date: 2008-02-14 06:13:30 -0500 (Thu, 14 Feb 2008)
New Revision: 1258
Modified:
trunk/code/renderer/tr_image_pcx.c
Log:
make pcx decoder more robust against corrupt files
Modified: trunk/code/renderer/tr_image_pcx.c
===================================================================
--- trunk/code/renderer/tr_image_pcx.c 2008-02-14 11:13:18 UTC (rev 1257)
+++ trunk/code/renderer/tr_image_pcx.c 2008-02-14 11:13:30 UTC (rev 1258)
@@ -1,6 +1,7 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
+ 2008 Ludwig Nussel
This file is part of Quake III Arena source code.
@@ -31,136 +32,140 @@
*/
typedef struct {
- char manufacturer;
- char version;
- char encoding;
- char bits_per_pixel;
- unsigned short xmin,ymin,xmax,ymax;
- unsigned short hres,vres;
- unsigned char palette[48];
- char reserved;
- char color_planes;
- unsigned short bytes_per_line;
- unsigned short palette_type;
- char filler[58];
- unsigned char data; // unbounded
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ unsigned short xmin,ymin,xmax,ymax;
+ unsigned short hres,vres;
+ unsigned char palette[48];
+ char reserved;
+ char color_planes;
+ unsigned short bytes_per_line;
+ unsigned short palette_type;
+ unsigned short hscreensize, vscreensize;
+ char filler[54];
+ unsigned char data[];
} pcx_t;
-
-static void _LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height)
+void LoadPCX ( const char *filename, byte **pic, int *width, int *height)
{
byte *raw;
+ byte *end;
pcx_t *pcx;
- int x, y;
int len;
- int dataByte, runLength;
+ unsigned char dataByte = 0, runLength = 0;
byte *out, *pix;
- unsigned xmax, ymax;
+ unsigned short w, h;
+ byte *pic8;
+ byte *palette;
+ int i;
+ unsigned size = 0;
+ if (width)
+ *width = 0;
+ if (height)
+ *height = 0;
*pic = NULL;
- *palette = NULL;
//
// load the file
//
len = ri.FS_ReadFile( ( char * ) filename, (void **)&raw);
- if (!raw) {
+ if (!raw || len < 0) {
return;
}
+ if((unsigned)len < sizeof(pcx_t))
+ {
+ ri.Printf (PRINT_ALL, "PCX truncated: %s\n", filename);
+ ri.FS_FreeFile (raw);
+ return;
+ }
+
//
// parse the PCX file
//
pcx = (pcx_t *)raw;
- raw = &pcx->data;
+ end = raw+len;
- xmax = LittleShort(pcx->xmax);
- ymax = LittleShort(pcx->ymax);
+ w = LittleShort(pcx->xmax)+1;
+ h = LittleShort(pcx->ymax)+1;
if (pcx->manufacturer != 0x0a
|| pcx->version != 5
|| pcx->encoding != 1
+ || pcx->color_planes != 1
|| pcx->bits_per_pixel != 8
- || xmax >= 1024
- || ymax >= 1024)
+ || w >= 1024
+ || h >= 1024)
{
- ri.Printf (PRINT_ALL, "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax);
+ ri.Printf (PRINT_ALL, "Bad or unsupported pcx file %s (%dx%d@%d)\n", filename, w, h, pcx->bits_per_pixel);
return;
}
- out = ri.Malloc ( (ymax+1) * (xmax+1) );
+ pix = pic8 = ri.Malloc ( size );
- *pic = out;
-
- pix = out;
-
- if (palette)
+ raw = pcx->data;
+ // FIXME: should use bytes_per_line but original q3 didn't do that either
+ while(pix < pic8+size)
{
- *palette = ri.Malloc(768);
- Com_Memcpy (*palette, (byte *)pcx + len - 768, 768);
- }
+ if(runLength > 0) {
+ *pix++ = dataByte;
+ --runLength;
+ continue;
+ }
- if (width)
- *width = xmax+1;
- if (height)
- *height = ymax+1;
-// FIXME: use bytes_per_line here?
+ if(raw+1 > end)
+ break;
+ dataByte = *raw++;
- for (y=0 ; y<=ymax ; y++, pix += xmax+1)
- {
- for (x=0 ; x<=xmax ; )
+ if((dataByte & 0xC0) == 0xC0)
{
+ if(raw+1 > end)
+ break;
+ runLength = dataByte & 0x3F;
dataByte = *raw++;
-
- if((dataByte & 0xC0) == 0xC0)
- {
- runLength = dataByte & 0x3F;
- dataByte = *raw++;
- }
- else
- runLength = 1;
-
- while(runLength-- > 0)
- pix[x++] = dataByte;
}
+ else
+ runLength = 1;
+ }
+ if(pix < pic8+size)
+ {
+ ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename);
+ ri.FS_FreeFile (pcx);
+ ri.Free (pic8);
}
- if ( raw - (byte *)pcx > len)
+ if (raw-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
{
- ri.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
- ri.Free (*pic);
- *pic = NULL;
+ ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename);
+ ri.FS_FreeFile (pcx);
+ ri.Free (pic8);
+ return;
}
- ri.FS_FreeFile (pcx);
-}
+ palette = end-768;
+ pix = out = ri.Malloc(4 * size );
+ for (i = 0 ; i < size ; i++)
+ {
+ unsigned char p = pic8[i];
+ pix[0] = palette[p*3];
+ pix[1] = palette[p*3 + 1];
+ pix[2] = palette[p*3 + 2];
+ pix[3] = 255;
+ pix += 4;
+ }
-void LoadPCX ( const char *filename, byte **pic, int *width, int *height) {
- byte *palette;
- byte *pic8;
- int i, c, p;
- byte *pic32;
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
- _LoadPCX (filename, &pic8, &palette, width, height);
- if (!pic8) {
- *pic = NULL;
- return;
- }
+ *pic = out;
- // LoadPCX32 ensures width, height < 1024
- c = (*width) * (*height);
- pic32 = *pic = ri.Malloc(4 * c );
- for (i = 0 ; i < c ; i++) {
- p = pic8[i];
- pic32[0] = palette[p*3];
- pic32[1] = palette[p*3 + 1];
- pic32[2] = palette[p*3 + 2];
- pic32[3] = 255;
- pic32 += 4;
- }
-
+ ri.FS_FreeFile (pcx);
ri.Free (pic8);
- ri.Free (palette);
}
More information about the quake3-commits
mailing list