added more error checking to prevent corrupt BMPs from crashing the translator, change the RLE decoder to allocate one row of dynamic memory for the bits output rather than allocating memory for the entire bits file, hopefully improved the performance of the RLE decoder
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@545 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -325,7 +325,7 @@ identify_bits_header(BPositionIO *inSource, translator_info *outInfo,
|
||||
header.colors != B_CMYA32 &&
|
||||
header.colors != B_CMY24)
|
||||
return B_NO_TRANSLATOR;
|
||||
if (header.rowBytes * (header.bounds.Height() + 1) > header.dataSize)
|
||||
if (header.rowBytes * (header.bounds.Height() + 1) != header.dataSize)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
if (outInfo) {
|
||||
@@ -442,6 +442,8 @@ identify_bmp_header(BPositionIO *inSource, translator_info *outInfo,
|
||||
return B_ERROR;
|
||||
|
||||
// check if msheader is valid
|
||||
if (msheader.width == 0 || msheader.height == 0)
|
||||
return B_NO_TRANSLATOR;
|
||||
if (msheader.planes != 1)
|
||||
return B_NO_TRANSLATOR;
|
||||
if ((msheader.bitsperpixel != 1 ||
|
||||
@@ -459,6 +461,8 @@ identify_bmp_header(BPositionIO *inSource, translator_info *outInfo,
|
||||
(msheader.bitsperpixel != 32 ||
|
||||
msheader.compression != BMP_NO_COMPRESS))
|
||||
return B_NO_TRANSLATOR;
|
||||
if (msheader.imagesize == 0 && msheader.compression)
|
||||
return B_NO_TRANSLATOR;
|
||||
if (msheader.colorsimportant > msheader.colorsused)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
@@ -513,6 +517,8 @@ identify_bmp_header(BPositionIO *inSource, translator_info *outInfo,
|
||||
return B_ERROR;
|
||||
|
||||
// check if msheader is valid
|
||||
if (os2header.width == 0 || os2header.height == 0)
|
||||
return B_NO_TRANSLATOR;
|
||||
if (os2header.planes != 1)
|
||||
return B_NO_TRANSLATOR;
|
||||
if (os2header.bitsperpixel != 1 &&
|
||||
@@ -551,7 +557,6 @@ identify_bmp_header(BPositionIO *inSource, translator_info *outInfo,
|
||||
int32 padding = 0;
|
||||
// determine fileSize / imagesize
|
||||
switch (pmsheader->bitsperpixel) {
|
||||
case 32:
|
||||
case 24:
|
||||
{
|
||||
if (pos2skip && fileHeader.dataOffset > 26)
|
||||
@@ -1616,129 +1621,151 @@ translate_from_bmppalr_to_bits(BPositionIO *inSource,
|
||||
uint8 mask = (1 << bitsPerPixel) - 1;
|
||||
|
||||
uint8 count, indices, index;
|
||||
// assumes datasize is relatively small
|
||||
uint8 *bitspixels = new uint8[datasize];
|
||||
if (!bitspixels)
|
||||
return B_ERROR;
|
||||
// Setup outDestination so that it can be written to
|
||||
// from the end of the file to the beginning instead of
|
||||
// the other way around
|
||||
int32 bitsRowBytes = msheader.width * 4;
|
||||
off_t bitsFileSize = (bitsRowBytes * msheader.height) +
|
||||
sizeof(TranslatorBitmap);
|
||||
if (outDestination->SetSize(bitsFileSize) != B_OK)
|
||||
// This call should work for BFile and BMallocIO objects,
|
||||
// but may not work for other BPositionIO based types
|
||||
return B_ERROR;
|
||||
uint8 *bitsRowData = new uint8[bitsRowBytes];
|
||||
if (!bitsRowData)
|
||||
return B_ERROR;
|
||||
uint32 bmppixcol = 0, bmppixrow = 0;
|
||||
int32 bitsoffset = 0;
|
||||
uint32 defaultcolor = 0;
|
||||
memcpy(&defaultcolor, palette, 4);
|
||||
// set bits output to last row in the image
|
||||
off_t bitsoffset = ((msheader.height - (bmppixrow + 1)) * bitsRowBytes) +
|
||||
(bmppixcol * 4);
|
||||
outDestination->Seek(bitsoffset, SEEK_CUR);
|
||||
ssize_t rd = inSource->Read(&count, 1);
|
||||
while (rd > 0) {
|
||||
// repeated color
|
||||
if (count) {
|
||||
rd = inSource->Read(&indices, 1);
|
||||
if (rd != 1)
|
||||
// abort if count is greater than the number of
|
||||
// pixels remaining in the current row
|
||||
if (count + bmppixcol > msheader.width) {
|
||||
rd = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
rd = inSource->Read(&indices, 1);
|
||||
if (rd != 1) {
|
||||
rd = -1;
|
||||
break;
|
||||
}
|
||||
for (uint8 i = 0; i < count; i++) {
|
||||
bitsoffset = ((msheader.height -
|
||||
(bmppixrow + 1)) * bitsRowBytes) +
|
||||
(bmppixcol * 4);
|
||||
index = (indices >> (bitsPerPixel * ((pixelsPerByte - 1) -
|
||||
(i % pixelsPerByte)))) & mask;
|
||||
memcpy(bitspixels + bitsoffset, palette + (index * 4), 3);
|
||||
memcpy(bitsRowData + (bmppixcol*4), palette + (index*4), 4);
|
||||
bmppixcol++;
|
||||
}
|
||||
// special code
|
||||
} else {
|
||||
uint8 code;
|
||||
rd = inSource->Read(&code, 1);
|
||||
if (rd != 1)
|
||||
if (rd != 1) {
|
||||
rd = -1;
|
||||
break;
|
||||
}
|
||||
switch (code) {
|
||||
// end of line
|
||||
case 0:
|
||||
// end of line
|
||||
// if there are columns remaing on this
|
||||
// line, set them to the color at index zero
|
||||
while (bmppixcol != msheader.width) {
|
||||
bitsoffset = ((msheader.height -
|
||||
(bmppixrow + 1)) *
|
||||
bitsRowBytes) +
|
||||
(bmppixcol * 4);
|
||||
memcpy(bitspixels + bitsoffset, palette, 3);
|
||||
bmppixcol++;
|
||||
}
|
||||
if (bmppixcol != msheader.width)
|
||||
memset(bitsRowData + (bmppixcol * 4), defaultcolor,
|
||||
(msheader.width - bmppixcol) * 4);
|
||||
outDestination->Write(bitsRowData, bitsRowBytes);
|
||||
bmppixcol = 0;
|
||||
bmppixrow++;
|
||||
if (bmppixrow < msheader.height)
|
||||
outDestination->Seek(-(bitsRowBytes * 2), SEEK_CUR);
|
||||
break;
|
||||
|
||||
|
||||
// end of bitmap
|
||||
case 1:
|
||||
// end of bitmap
|
||||
// if at the end of a row
|
||||
if (bmppixcol == msheader.width) {
|
||||
outDestination->Write(bitsRowData, bitsRowBytes);
|
||||
bmppixcol = 0;
|
||||
bmppixrow++;
|
||||
if (bmppixrow < msheader.height)
|
||||
outDestination->Seek(-(bitsRowBytes * 2),
|
||||
SEEK_CUR);
|
||||
}
|
||||
|
||||
while (bmppixrow < msheader.height) {
|
||||
bitsoffset = ((msheader.height -
|
||||
(bmppixrow + 1)) *
|
||||
bitsRowBytes) +
|
||||
(bmppixcol * 4);
|
||||
memcpy(bitspixels + bitsoffset, palette, 3);
|
||||
bmppixcol++;
|
||||
|
||||
if (bmppixcol == msheader.width) {
|
||||
bmppixcol = 0;
|
||||
bmppixrow++;
|
||||
}
|
||||
memset(bitsRowData + (bmppixcol * 4), defaultcolor,
|
||||
(msheader.width - bmppixcol) * 4);
|
||||
outDestination->Write(bitsRowData, bitsRowBytes);
|
||||
bmppixcol = 0;
|
||||
bmppixrow++;
|
||||
if (bmppixrow < msheader.height)
|
||||
outDestination->Seek(-(bitsRowBytes * 2),
|
||||
SEEK_CUR);
|
||||
}
|
||||
rd = 0;
|
||||
// break out of while loop
|
||||
break;
|
||||
|
||||
|
||||
// delta, skip several rows and/or columns and
|
||||
// fill the skipped pixels with the default color
|
||||
case 2:
|
||||
{
|
||||
// delta, wierd feature
|
||||
uint8 x, dx, dy;
|
||||
inSource->Read(&dx, 1);
|
||||
inSource->Read(&dy, 1);
|
||||
uint8 da[2], lastcol, dx, dy;
|
||||
rd = inSource->Read(da, 2);
|
||||
if (rd != 2) {
|
||||
rd = -1;
|
||||
break;
|
||||
}
|
||||
dx = da[0];
|
||||
dy = da[1];
|
||||
|
||||
// abort if dx or dy is too large
|
||||
if ((dx + bmppixcol >= msheader.width) ||
|
||||
(dy + bmppixrow >= msheader.height)) {
|
||||
rd = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
x = bmppixcol;
|
||||
lastcol = bmppixcol;
|
||||
|
||||
// set all pixels to the first entry in
|
||||
// the palette, for the number of rows skipped
|
||||
while (dy > 0) {
|
||||
bitsoffset = ((msheader.height -
|
||||
(bmppixrow + 1)) *
|
||||
bitsRowBytes) +
|
||||
(bmppixcol * 4);
|
||||
memcpy(bitspixels + bitsoffset, palette, 3);
|
||||
bmppixcol++;
|
||||
|
||||
if (bmppixcol == msheader.width) {
|
||||
bmppixcol = 0;
|
||||
bmppixrow++;
|
||||
dy--;
|
||||
}
|
||||
memset(bitsRowData + (bmppixcol * 4), defaultcolor,
|
||||
(msheader.width - bmppixcol) * 4);
|
||||
outDestination->Write(bitsRowData, bitsRowBytes);
|
||||
bmppixcol = 0;
|
||||
bmppixrow++;
|
||||
dy--;
|
||||
outDestination->Seek(-(bitsRowBytes * 2), SEEK_CUR);
|
||||
}
|
||||
|
||||
// get to the same column as where we started
|
||||
while (x != bmppixcol) {
|
||||
bitsoffset = ((msheader.height -
|
||||
(bmppixrow + 1)) *
|
||||
bitsRowBytes) +
|
||||
(bmppixcol * 4);
|
||||
memcpy(bitspixels + bitsoffset, palette, 3);
|
||||
bmppixcol++;
|
||||
}
|
||||
|
||||
// move over dx pixels
|
||||
for (uint8 i = 0; i < dx; i++) {
|
||||
bitsoffset = ((msheader.height -
|
||||
(bmppixrow + 1)) *
|
||||
bitsRowBytes) +
|
||||
(bmppixcol * 4);
|
||||
memcpy(bitspixels + bitsoffset, palette, 3);
|
||||
bmppixcol++;
|
||||
if (bmppixcol < (uint32) lastcol + dx) {
|
||||
memset(bitsRowData + (bmppixcol * 4), defaultcolor,
|
||||
(dx + lastcol - bmppixcol) * 4);
|
||||
bmppixcol = dx + lastcol;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// code >= 3
|
||||
// read code uncompressed indices
|
||||
default:
|
||||
// read code uncompressed indices
|
||||
// abort if number of uncompressed pixels
|
||||
// is larger than the number of pixels remaining
|
||||
// in the current row
|
||||
if (code + bmppixcol > msheader.width) {
|
||||
rd = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8 uncomp[256];
|
||||
int32 padding;
|
||||
if (!(code % pixelsPerByte))
|
||||
@@ -1750,20 +1777,16 @@ translate_from_bmppalr_to_bits(BPositionIO *inSource,
|
||||
((code % pixelsPerByte) ? 1 : 0) + padding;
|
||||
rd = inSource->Read(uncomp, uncompBytes);
|
||||
if (rd != uncompBytes) {
|
||||
rd = 0;
|
||||
rd = -1;
|
||||
break;
|
||||
}
|
||||
for (uint8 i = 0; i < code; i++) {
|
||||
bitsoffset = ((msheader.height -
|
||||
(bmppixrow + 1)) *
|
||||
bitsRowBytes) +
|
||||
(bmppixcol * 4);
|
||||
indices = (uncomp + (i / pixelsPerByte))[0];
|
||||
index = (indices >>
|
||||
(bitsPerPixel * ((pixelsPerByte - 1) -
|
||||
(i % pixelsPerByte)))) & mask;
|
||||
memcpy(bitspixels + bitsoffset,
|
||||
palette + (index * 4), 3);
|
||||
memcpy(bitsRowData + (bmppixcol * 4),
|
||||
palette + (index * 4), 4);
|
||||
bmppixcol++;
|
||||
}
|
||||
|
||||
@@ -1773,10 +1796,13 @@ translate_from_bmppalr_to_bits(BPositionIO *inSource,
|
||||
if (rd > 0)
|
||||
rd = inSource->Read(&count, 1);
|
||||
}
|
||||
outDestination->Write(bitspixels, datasize);
|
||||
|
||||
delete[] bitspixels;
|
||||
return B_OK;
|
||||
|
||||
delete[] bitsRowData;
|
||||
|
||||
if (!rd)
|
||||
return B_OK;
|
||||
else
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
@@ -1905,7 +1931,8 @@ translate_from_bmp(BPositionIO *inSource, ssize_t amtread, uint8 *read,
|
||||
msheader.colorsused = 1 << msheader.bitsperpixel;
|
||||
|
||||
if (inSource->Read(bmppalette, msheader.colorsused *
|
||||
palBytesPerPixel) != (off_t) msheader.colorsused * palBytesPerPixel)
|
||||
palBytesPerPixel) !=
|
||||
(off_t) msheader.colorsused * palBytesPerPixel)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
// skip over non-BMP data
|
||||
@@ -2107,7 +2134,7 @@ BMPTranslator::MakeConfigurationView(BMessage *ioExtension, BView **outView,
|
||||
if (!outView || !outExtent)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BMPView *view = new BMPView(BRect(0,0,225,175),
|
||||
BMPView *view = new BMPView(BRect(0, 0, 225, 175),
|
||||
"BMPTranslator Settings", B_FOLLOW_ALL, B_WILL_DRAW);
|
||||
*outView = view;
|
||||
*outExtent = view->Bounds();
|
||||
|
||||
Reference in New Issue
Block a user