aboutsummaryrefslogtreecommitdiffstats
path: root/code
diff options
context:
space:
mode:
authorludwig <ludwig@edf5b092-35ff-0310-97b2-ce42778d08ea>2008-02-14 11:13:30 +0000
committerludwig <ludwig@edf5b092-35ff-0310-97b2-ce42778d08ea>2008-02-14 11:13:30 +0000
commit0365c92dcb7fbaf7d98e28883d37453d5fb96670 (patch)
treeb9aaf64e69b4bb36c4ecde4b4c68c45fb73a77f4 /code
parent2acf691603cb0fb7c8b580befbc7be49b9300e53 (diff)
downloadioquake3-aero-0365c92dcb7fbaf7d98e28883d37453d5fb96670.tar.gz
ioquake3-aero-0365c92dcb7fbaf7d98e28883d37453d5fb96670.zip
make pcx decoder more robust against corrupt files
git-svn-id: svn://svn.icculus.org/quake3/trunk@1258 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code')
-rw-r--r--code/renderer/tr_image_pcx.c171
1 files changed, 88 insertions, 83 deletions
diff --git a/code/renderer/tr_image_pcx.c b/code/renderer/tr_image_pcx.c
index f369b76..216543e 100644
--- a/code/renderer/tr_image_pcx.c
+++ b/code/renderer/tr_image_pcx.c
@@ -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,40 +32,54 @@ PCX files are used for 8 bit images
*/
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;
}
@@ -72,95 +87,85 @@ static void _LoadPCX ( const char *filename, byte **pic, byte **palette, int *wi
// 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 ( raw - (byte *)pcx > len)
+ if(pix < pic8+size)
{
- ri.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
- ri.Free (*pic);
- *pic = NULL;
+ ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename);
+ ri.FS_FreeFile (pcx);
+ ri.Free (pic8);
}
- ri.FS_FreeFile (pcx);
-}
-
-
-void LoadPCX ( const char *filename, byte **pic, int *width, int *height) {
- byte *palette;
- byte *pic8;
- int i, c, p;
- byte *pic32;
-
- _LoadPCX (filename, &pic8, &palette, width, height);
- if (!pic8) {
- *pic = NULL;
+ if (raw-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
+ {
+ ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename);
+ ri.FS_FreeFile (pcx);
+ ri.Free (pic8);
return;
}
- // 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;
+ 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;
}
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+
+ *pic = out;
+
+ ri.FS_FreeFile (pcx);
ri.Free (pic8);
- ri.Free (palette);
}