windowscodecs: Ignore the length field of RLE compressed bitmaps.

This commit is contained in:
Vincent Povirk 2010-07-16 12:31:49 -05:00 committed by Alexandre Julliard
parent 5fe2fc20fd
commit 4dfcf843aa
1 changed files with 115 additions and 56 deletions

View File

@ -395,32 +395,52 @@ fail:
return hr; return hr;
} }
static HRESULT ReadByte(IStream *stream, BYTE *buffer, ULONG buffer_size,
ULONG *cursor, ULONG *bytesread, BYTE *result)
{
HRESULT hr=S_OK;
if (*bytesread == 0 || *cursor == *bytesread)
{
hr = IStream_Read(stream, buffer, buffer_size, bytesread);
*cursor = 0;
}
if (SUCCEEDED(hr))
{
if (*cursor < *bytesread)
*result = buffer[(*cursor)++];
else
hr = E_FAIL;
}
return hr;
}
static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This) static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This)
{ {
UINT bytesperrow; UINT bytesperrow;
UINT width, height; UINT width, height;
BYTE *rledata, *cursor, *rledataend; BYTE rledata[4096];
UINT rlesize, datasize, palettesize; UINT datasize, palettesize;
DWORD palette[256]; DWORD palette[256];
UINT x, y; UINT x, y;
DWORD *bgrdata; DWORD *bgrdata;
HRESULT hr; HRESULT hr;
LARGE_INTEGER offbits; LARGE_INTEGER offbits;
ULONG bytesread; ULONG cursor=0, bytesread=0;
width = This->bih.bV5Width; width = This->bih.bV5Width;
height = abs(This->bih.bV5Height); height = abs(This->bih.bV5Height);
bytesperrow = width * 4; bytesperrow = width * 4;
datasize = bytesperrow * height; datasize = bytesperrow * height;
rlesize = This->bih.bV5SizeImage;
if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 256) if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 256)
palettesize = 4 * This->bih.bV5ClrUsed; palettesize = 4 * This->bih.bV5ClrUsed;
else else
palettesize = 4 * 256; palettesize = 4 * 256;
rledata = HeapAlloc(GetProcessHeap(), 0, rlesize);
This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
if (!This->imagedata || !rledata) if (!This->imagedata)
{ {
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
goto fail; goto fail;
@ -439,22 +459,26 @@ static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This)
hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) goto fail; if (FAILED(hr)) goto fail;
hr = IStream_Read(This->stream, rledata, rlesize, &bytesread);
if (FAILED(hr) || bytesread != rlesize) goto fail;
/* decode RLE */ /* decode RLE */
bgrdata = (DWORD*)This->imagedata; bgrdata = (DWORD*)This->imagedata;
x = 0; x = 0;
y = 0; y = 0;
rledataend = rledata + rlesize; cursor = 0;
cursor = rledata; bytesread = 0;
while (cursor < rledataend && y < height) while (y < height)
{ {
BYTE length = *cursor++; BYTE length;
if (length == 0) hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length);
if (FAILED(hr))
goto fail;
else if (length == 0)
{ {
/* escape code */ /* escape code */
BYTE escape = *cursor++; BYTE escape;
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape);
if (FAILED(hr))
goto fail;
switch(escape) switch(escape)
{ {
case 0: /* end of line */ case 0: /* end of line */
@ -464,37 +488,53 @@ static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This)
case 1: /* end of bitmap */ case 1: /* end of bitmap */
goto end; goto end;
case 2: /* delta */ case 2: /* delta */
if (cursor < rledataend) {
{ BYTE dx, dy;
x += *cursor++; hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx);
y += *cursor++; if (SUCCEEDED(hr))
} hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy);
if (FAILED(hr))
goto fail;
x += dx;
y += dy;
break; break;
}
default: /* absolute mode */ default: /* absolute mode */
length = escape; length = escape;
while (cursor < rledataend && length-- && x < width) while (length-- && x < width)
bgrdata[y*width + x++] = palette[*cursor++]; {
if (escape & 1) cursor++; /* skip pad byte */ BYTE index;
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index);
if (FAILED(hr))
goto fail;
bgrdata[y*width + x++] = palette[index];
}
if (escape & 1)
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */
if (FAILED(hr))
goto fail;
} }
} }
else else
{ {
DWORD color = palette[*cursor++]; BYTE index;
DWORD color;
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index);
if (FAILED(hr))
goto fail;
color = palette[index];
while (length-- && x < width) while (length-- && x < width)
bgrdata[y*width + x++] = color; bgrdata[y*width + x++] = color;
} }
} }
end: end:
HeapFree(GetProcessHeap(), 0, rledata);
This->imagedatastart = This->imagedata + (height-1) * bytesperrow; This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
This->stride = -bytesperrow; This->stride = -bytesperrow;
return S_OK; return S_OK;
fail: fail:
HeapFree(GetProcessHeap(), 0, rledata);
HeapFree(GetProcessHeap(), 0, This->imagedata); HeapFree(GetProcessHeap(), 0, This->imagedata);
This->imagedata = NULL; This->imagedata = NULL;
if (SUCCEEDED(hr)) hr = E_FAIL; if (SUCCEEDED(hr)) hr = E_FAIL;
@ -505,28 +545,26 @@ static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
{ {
UINT bytesperrow; UINT bytesperrow;
UINT width, height; UINT width, height;
BYTE *rledata, *cursor, *rledataend; BYTE rledata[4096];
UINT rlesize, datasize, palettesize; UINT datasize, palettesize;
DWORD palette[16]; DWORD palette[16];
UINT x, y; UINT x, y;
DWORD *bgrdata; DWORD *bgrdata;
HRESULT hr; HRESULT hr;
LARGE_INTEGER offbits; LARGE_INTEGER offbits;
ULONG bytesread; ULONG cursor=0, bytesread=0;
width = This->bih.bV5Width; width = This->bih.bV5Width;
height = abs(This->bih.bV5Height); height = abs(This->bih.bV5Height);
bytesperrow = width * 4; bytesperrow = width * 4;
datasize = bytesperrow * height; datasize = bytesperrow * height;
rlesize = This->bih.bV5SizeImage;
if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 16) if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 16)
palettesize = 4 * This->bih.bV5ClrUsed; palettesize = 4 * This->bih.bV5ClrUsed;
else else
palettesize = 4 * 16; palettesize = 4 * 16;
rledata = HeapAlloc(GetProcessHeap(), 0, rlesize);
This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
if (!This->imagedata || !rledata) if (!This->imagedata)
{ {
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
goto fail; goto fail;
@ -545,22 +583,26 @@ static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) goto fail; if (FAILED(hr)) goto fail;
hr = IStream_Read(This->stream, rledata, rlesize, &bytesread);
if (FAILED(hr) || bytesread != rlesize) goto fail;
/* decode RLE */ /* decode RLE */
bgrdata = (DWORD*)This->imagedata; bgrdata = (DWORD*)This->imagedata;
x = 0; x = 0;
y = 0; y = 0;
rledataend = rledata + rlesize; cursor = 0;
cursor = rledata; bytesread = 0;
while (cursor < rledataend && y < height) while (y < height)
{ {
BYTE length = *cursor++; BYTE length;
if (length == 0) hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length);
if (FAILED(hr))
goto fail;
else if (length == 0)
{ {
/* escape code */ /* escape code */
BYTE escape = *cursor++; BYTE escape;
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape);
if (FAILED(hr))
goto fail;
switch(escape) switch(escape)
{ {
case 0: /* end of line */ case 0: /* end of line */
@ -570,31 +612,51 @@ static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
case 1: /* end of bitmap */ case 1: /* end of bitmap */
goto end; goto end;
case 2: /* delta */ case 2: /* delta */
if (cursor < rledataend) {
{ BYTE dx, dy;
x += *cursor++; hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx);
y += *cursor++; if (SUCCEEDED(hr))
} hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy);
if (FAILED(hr))
goto fail;
x += dx;
y += dy;
break; break;
}
default: /* absolute mode */ default: /* absolute mode */
{
BYTE realsize=0;
length = escape; length = escape;
while (cursor < rledataend && length-- && x < width) while (length-- && x < width)
{ {
BYTE colors = *cursor++; BYTE colors;
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors);
realsize++;
if (FAILED(hr))
goto fail;
bgrdata[y*width + x++] = palette[colors>>4]; bgrdata[y*width + x++] = palette[colors>>4];
if (length-- && x < width) if (length-- && x < width)
bgrdata[y*width + x++] = palette[colors&0xf]; bgrdata[y*width + x++] = palette[colors&0xf];
else else
break; break;
} }
if ((cursor - rledata) & 1) cursor++; /* skip pad byte */ if (realsize & 1)
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */
if (FAILED(hr))
goto fail;
}
} }
} }
else else
{ {
BYTE colors = *cursor++; BYTE colors;
DWORD color1 = palette[colors>>4]; DWORD color1;
DWORD color2 = palette[colors&0xf]; DWORD color2;
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors);
if (FAILED(hr))
goto fail;
color1 = palette[colors>>4];
color2 = palette[colors&0xf];
while (length-- && x < width) while (length-- && x < width)
{ {
bgrdata[y*width + x++] = color1; bgrdata[y*width + x++] = color1;
@ -607,15 +669,12 @@ static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
} }
end: end:
HeapFree(GetProcessHeap(), 0, rledata);
This->imagedatastart = This->imagedata + (height-1) * bytesperrow; This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
This->stride = -bytesperrow; This->stride = -bytesperrow;
return S_OK; return S_OK;
fail: fail:
HeapFree(GetProcessHeap(), 0, rledata);
HeapFree(GetProcessHeap(), 0, This->imagedata); HeapFree(GetProcessHeap(), 0, This->imagedata);
This->imagedata = NULL; This->imagedata = NULL;
if (SUCCEEDED(hr)) hr = E_FAIL; if (SUCCEEDED(hr)) hr = E_FAIL;