make bmp decoder more robust against corrupt files

This commit is contained in:
Ludwig Nussel 2008-02-14 11:12:42 +00:00
parent f65dbd4351
commit 02d842532e

View file

@ -810,20 +810,20 @@ BMP LOADING
typedef struct typedef struct
{ {
char id[2]; char id[2];
unsigned long fileSize; unsigned fileSize;
unsigned long reserved0; unsigned reserved0;
unsigned long bitmapDataOffset; unsigned bitmapDataOffset;
unsigned long bitmapHeaderSize; unsigned bitmapHeaderSize;
unsigned long width; unsigned width;
unsigned long height; unsigned height;
unsigned short planes; unsigned short planes;
unsigned short bitsPerPixel; unsigned short bitsPerPixel;
unsigned long compression; unsigned compression;
unsigned long bitmapDataSize; unsigned bitmapDataSize;
unsigned long hRes; unsigned hRes;
unsigned long vRes; unsigned vRes;
unsigned long colors; unsigned colors;
unsigned long importantColors; unsigned importantColors;
unsigned char palette[256][4]; unsigned char palette[256][4];
} BMPHeader_t; } BMPHeader_t;
@ -834,58 +834,82 @@ static void LoadBMP( const char *name, byte **pic, int *width, int *height )
byte *pixbuf; byte *pixbuf;
int row, column; int row, column;
byte *buf_p; byte *buf_p;
byte *buffer; byte *end;
byte *buffer = NULL;
int length; int length;
BMPHeader_t bmpHeader; BMPHeader_t bmpHeader;
byte *bmpRGBA; byte *bmpRGBA;
*pic = NULL; *pic = NULL;
if(width)
*width = 0;
if(height)
*height = 0;
// //
// load the file // load the file
// //
length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer); length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer);
if (!buffer) { if (!buffer || length < 0) {
return; return;
} }
if (length < 54)
{
ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
}
buf_p = buffer; buf_p = buffer;
end = buffer + length;
bmpHeader.id[0] = *buf_p++; bmpHeader.id[0] = *buf_p++;
bmpHeader.id[1] = *buf_p++; bmpHeader.id[1] = *buf_p++;
bmpHeader.fileSize = LittleLong( * ( long * ) buf_p ); bmpHeader.fileSize = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.reserved0 = LittleLong( * ( long * ) buf_p ); bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p ); bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p ); bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.width = LittleLong( * ( long * ) buf_p ); bmpHeader.width = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.height = LittleLong( * ( long * ) buf_p ); bmpHeader.height = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.planes = LittleShort( * ( short * ) buf_p ); bmpHeader.planes = LittleShort( * ( short * ) buf_p );
buf_p += 2; buf_p += 2;
bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p ); bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
buf_p += 2; buf_p += 2;
bmpHeader.compression = LittleLong( * ( long * ) buf_p ); bmpHeader.compression = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p ); bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.hRes = LittleLong( * ( long * ) buf_p ); bmpHeader.hRes = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.vRes = LittleLong( * ( long * ) buf_p ); bmpHeader.vRes = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.colors = LittleLong( * ( long * ) buf_p ); bmpHeader.colors = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
bmpHeader.importantColors = LittleLong( * ( long * ) buf_p ); bmpHeader.importantColors = LittleLong( * ( int * ) buf_p );
buf_p += 4; buf_p += 4;
Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
if ( bmpHeader.bitsPerPixel == 8 ) if ( bmpHeader.bitsPerPixel == 8 )
buf_p += 1024; {
if (buf_p + sizeof(bmpHeader.palette) > end)
ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
buf_p += sizeof(bmpHeader.palette);
}
if (buffer + bmpHeader.bitmapDataOffset > end)
{
ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name );
}
buf_p = buffer + bmpHeader.bitmapDataOffset;
if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
{ {
@ -893,7 +917,7 @@ static void LoadBMP( const char *name, byte **pic, int *width, int *height )
} }
if ( bmpHeader.fileSize != length ) if ( bmpHeader.fileSize != length )
{ {
ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name ); ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)\n", bmpHeader.fileSize, length, name );
} }
if ( bmpHeader.compression != 0 ) if ( bmpHeader.compression != 0 )
{ {
@ -904,6 +928,18 @@ static void LoadBMP( const char *name, byte **pic, int *width, int *height )
ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name ); ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
} }
switch ( bmpHeader.bitsPerPixel )
{
case 8:
case 16:
case 24:
case 32:
break;
default:
ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'\n", bmpHeader.bitsPerPixel, name );
break;
}
columns = bmpHeader.width; columns = bmpHeader.width;
rows = bmpHeader.height; rows = bmpHeader.height;
if ( rows < 0 ) if ( rows < 0 )
@ -915,6 +951,10 @@ static void LoadBMP( const char *name, byte **pic, int *width, int *height )
{ {
ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name); ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name);
} }
if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end)
{
ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)\n", name);
}
if ( width ) if ( width )
*width = columns; *width = columns;
@ -972,9 +1012,6 @@ static void LoadBMP( const char *name, byte **pic, int *width, int *height )
*pixbuf++ = blue; *pixbuf++ = blue;
*pixbuf++ = alpha; *pixbuf++ = alpha;
break; break;
default:
ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name );
break;
} }
} }
} }