make pcx decoder more robust against corrupt files
This commit is contained in:
parent
85ba66e7e8
commit
c77f537ae3
1 changed files with 96 additions and 91 deletions
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
===========================================================================
|
===========================================================================
|
||||||
Copyright (C) 1999-2005 Id Software, Inc.
|
Copyright (C) 1999-2005 Id Software, Inc.
|
||||||
|
2008 Ludwig Nussel
|
||||||
|
|
||||||
This file is part of Quake III Arena source code.
|
This file is part of Quake III Arena source code.
|
||||||
|
|
||||||
|
@ -42,29 +43,43 @@ typedef struct {
|
||||||
char color_planes;
|
char color_planes;
|
||||||
unsigned short bytes_per_line;
|
unsigned short bytes_per_line;
|
||||||
unsigned short palette_type;
|
unsigned short palette_type;
|
||||||
char filler[58];
|
unsigned short hscreensize, vscreensize;
|
||||||
unsigned char data; // unbounded
|
char filler[54];
|
||||||
|
unsigned char data[];
|
||||||
} pcx_t;
|
} pcx_t;
|
||||||
|
|
||||||
|
void LoadPCX ( const char *filename, byte **pic, int *width, int *height)
|
||||||
static void _LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height)
|
|
||||||
{
|
{
|
||||||
byte *raw;
|
byte *raw;
|
||||||
|
byte *end;
|
||||||
pcx_t *pcx;
|
pcx_t *pcx;
|
||||||
int x, y;
|
|
||||||
int len;
|
int len;
|
||||||
int dataByte, runLength;
|
unsigned char dataByte = 0, runLength = 0;
|
||||||
byte *out, *pix;
|
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;
|
*pic = NULL;
|
||||||
*palette = NULL;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// load the file
|
// load the file
|
||||||
//
|
//
|
||||||
len = ri.FS_ReadFile( ( char * ) filename, (void **)&raw);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,95 +87,85 @@ static void _LoadPCX ( const char *filename, byte **pic, byte **palette, int *wi
|
||||||
// parse the PCX file
|
// parse the PCX file
|
||||||
//
|
//
|
||||||
pcx = (pcx_t *)raw;
|
pcx = (pcx_t *)raw;
|
||||||
raw = &pcx->data;
|
end = raw+len;
|
||||||
|
|
||||||
xmax = LittleShort(pcx->xmax);
|
w = LittleShort(pcx->xmax)+1;
|
||||||
ymax = LittleShort(pcx->ymax);
|
h = LittleShort(pcx->ymax)+1;
|
||||||
|
|
||||||
if (pcx->manufacturer != 0x0a
|
if (pcx->manufacturer != 0x0a
|
||||||
|| pcx->version != 5
|
|| pcx->version != 5
|
||||||
|| pcx->encoding != 1
|
|| pcx->encoding != 1
|
||||||
|
|| pcx->color_planes != 1
|
||||||
|| pcx->bits_per_pixel != 8
|
|| pcx->bits_per_pixel != 8
|
||||||
|| xmax >= 1024
|
|| w >= 1024
|
||||||
|| ymax >= 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
out = ri.Malloc ( (ymax+1) * (xmax+1) );
|
pix = pic8 = ri.Malloc ( size );
|
||||||
|
|
||||||
*pic = out;
|
raw = pcx->data;
|
||||||
|
// FIXME: should use bytes_per_line but original q3 didn't do that either
|
||||||
pix = out;
|
while(pix < pic8+size)
|
||||||
|
|
||||||
if (palette)
|
|
||||||
{
|
{
|
||||||
*palette = ri.Malloc(768);
|
if(runLength > 0) {
|
||||||
Com_Memcpy (*palette, (byte *)pcx + len - 768, 768);
|
*pix++ = dataByte;
|
||||||
|
--runLength;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width)
|
if(raw+1 > end)
|
||||||
*width = xmax+1;
|
break;
|
||||||
if (height)
|
|
||||||
*height = ymax+1;
|
|
||||||
// FIXME: use bytes_per_line here?
|
|
||||||
|
|
||||||
for (y=0 ; y<=ymax ; y++, pix += xmax+1)
|
|
||||||
{
|
|
||||||
for (x=0 ; x<=xmax ; )
|
|
||||||
{
|
|
||||||
dataByte = *raw++;
|
dataByte = *raw++;
|
||||||
|
|
||||||
if((dataByte & 0xC0) == 0xC0)
|
if((dataByte & 0xC0) == 0xC0)
|
||||||
{
|
{
|
||||||
|
if(raw+1 > end)
|
||||||
|
break;
|
||||||
runLength = dataByte & 0x3F;
|
runLength = dataByte & 0x3F;
|
||||||
dataByte = *raw++;
|
dataByte = *raw++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
runLength = 1;
|
runLength = 1;
|
||||||
|
|
||||||
while(runLength-- > 0)
|
|
||||||
pix[x++] = dataByte;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if(pix < pic8+size)
|
||||||
|
|
||||||
if ( raw - (byte *)pcx > len)
|
|
||||||
{
|
{
|
||||||
ri.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
|
ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename);
|
||||||
ri.Free (*pic);
|
ri.FS_FreeFile (pcx);
|
||||||
*pic = NULL;
|
ri.Free (pic8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.FS_FreeFile (pcx);
|
||||||
}
|
ri.Free (pic8);
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadPCX32 ensures width, height < 1024
|
palette = end-768;
|
||||||
c = (*width) * (*height);
|
|
||||||
pic32 = *pic = ri.Malloc(4 * c );
|
pix = out = ri.Malloc(4 * size );
|
||||||
for (i = 0 ; i < c ; i++) {
|
for (i = 0 ; i < size ; i++)
|
||||||
p = pic8[i];
|
{
|
||||||
pic32[0] = palette[p*3];
|
unsigned char p = pic8[i];
|
||||||
pic32[1] = palette[p*3 + 1];
|
pix[0] = palette[p*3];
|
||||||
pic32[2] = palette[p*3 + 2];
|
pix[1] = palette[p*3 + 1];
|
||||||
pic32[3] = 255;
|
pix[2] = palette[p*3 + 2];
|
||||||
pic32 += 4;
|
pix[3] = 255;
|
||||||
|
pix += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (width)
|
||||||
|
*width = w;
|
||||||
|
if (height)
|
||||||
|
*height = h;
|
||||||
|
|
||||||
|
*pic = out;
|
||||||
|
|
||||||
|
ri.FS_FreeFile (pcx);
|
||||||
ri.Free (pic8);
|
ri.Free (pic8);
|
||||||
ri.Free (palette);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue