forked from AuroraMiddleware/gtk
Handle offsets more carefully. (#172188, David Costanzo)
2006-12-22 Matthias Clasen <mclasen@redhat.com> * io-bmp.c: Handle offsets more carefully. (#172188, David Costanzo) * io-bmp.c: Handle v5 and OS/2 v2 bmps. * io-bmp.c: Handle alpha masks in v4 and v5 bmps.
This commit is contained in:
parent
1db5905b38
commit
21e120cc44
@ -1,3 +1,12 @@
|
||||
2006-12-22 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* io-bmp.c: Handle offsets more carefully. (#172188,
|
||||
David Costanzo)
|
||||
|
||||
* io-bmp.c: Handle v5 and OS/2 v2 bmps.
|
||||
|
||||
* io-bmp.c: Handle alpha masks in v4 and v5 bmps.
|
||||
|
||||
2006-12-21 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* gdk-pixbuf-loader.c (gdk_pixbuf_loader_write): Emit
|
||||
|
@ -159,6 +159,7 @@ struct bmp_progressive_state {
|
||||
|
||||
guchar *buff;
|
||||
guint BufferSize;
|
||||
guint BufferPadding;
|
||||
guint BufferDone;
|
||||
|
||||
guchar (*Colormap)[3];
|
||||
@ -181,6 +182,7 @@ struct bmp_progressive_state {
|
||||
int r_mask, r_shift, r_bits;
|
||||
int g_mask, g_shift, g_bits;
|
||||
int b_mask, b_shift, b_bits;
|
||||
int a_mask, a_shift, a_bits;
|
||||
|
||||
GdkPixbuf *pixbuf; /* Our "target" */
|
||||
};
|
||||
@ -245,6 +247,11 @@ static gboolean grow_buffer (struct bmp_progressive_state *State,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
decode_bitmasks (guchar *buf,
|
||||
struct bmp_progressive_state *State,
|
||||
GError **error);
|
||||
|
||||
static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
|
||||
struct bmp_progressive_state *State,
|
||||
GError **error)
|
||||
@ -252,7 +259,6 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
|
||||
gint clrUsed;
|
||||
|
||||
/* FIXME this is totally unrobust against bogus image data. */
|
||||
|
||||
if (State->BufferSize < lsb_32 (&BIH[0]) + 14) {
|
||||
State->BufferSize = lsb_32 (&BIH[0]) + 14;
|
||||
if (!grow_buffer (State, error))
|
||||
@ -265,17 +271,32 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
|
||||
#endif
|
||||
|
||||
State->Header.size = lsb_32 (&BIH[0]);
|
||||
if (State->Header.size == 108) {
|
||||
if (State->Header.size == 124) {
|
||||
/* BMP v5 */
|
||||
State->Header.width = lsb_32 (&BIH[4]);
|
||||
State->Header.height = lsb_32 (&BIH[8]);
|
||||
State->Header.depth = lsb_16 (&BIH[14]);
|
||||
State->Compressed = lsb_32 (&BIH[16]);
|
||||
} else if (State->Header.size == 108) {
|
||||
/* BMP v4 */
|
||||
State->Header.width = lsb_32 (&BIH[4]);
|
||||
State->Header.height = lsb_32 (&BIH[8]);
|
||||
State->Header.depth = lsb_16 (&BIH[14]);
|
||||
State->Compressed = lsb_32 (&BIH[16]);
|
||||
} else if (State->Header.size == 64) {
|
||||
/* BMP OS/2 v2 */
|
||||
State->Header.width = lsb_32 (&BIH[4]);
|
||||
State->Header.height = lsb_32 (&BIH[8]);
|
||||
State->Header.depth = lsb_16 (&BIH[14]);
|
||||
State->Compressed = lsb_32 (&BIH[16]);
|
||||
} else if (State->Header.size == 40) {
|
||||
/* BMP v3 */
|
||||
State->Header.width = lsb_32 (&BIH[4]);
|
||||
State->Header.height = lsb_32 (&BIH[8]);
|
||||
State->Header.depth = lsb_16 (&BIH[14]);
|
||||
State->Compressed = lsb_32 (&BIH[16]);
|
||||
} else if (State->Header.size == 12) {
|
||||
/* BMP OS/2 */
|
||||
State->Header.width = lsb_16 (&BIH[4]);
|
||||
State->Header.height = lsb_16 (&BIH[6]);
|
||||
State->Header.depth = lsb_16 (&BIH[10]);
|
||||
@ -297,9 +318,9 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
|
||||
if (clrUsed != 0)
|
||||
State->Header.n_colors = clrUsed;
|
||||
else
|
||||
State->Header.n_colors = 1 << State->Header.depth;
|
||||
State->Header.n_colors = (1 << State->Header.depth);
|
||||
|
||||
if (State->Header.n_colors > 1 << State->Header.depth) {
|
||||
if (State->Header.n_colors > (1 << State->Header.depth)) {
|
||||
g_set_error (error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
||||
@ -417,8 +438,19 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
|
||||
|
||||
State->BufferDone = 0;
|
||||
if (State->Type <= 8) {
|
||||
gint samples;
|
||||
|
||||
State->read_state = READ_STATE_PALETTE;
|
||||
State->BufferSize = lsb_32 (&BFH[10]) - 14 - State->Header.size;
|
||||
|
||||
/* Allocate enough to hold the palette */
|
||||
samples = (State->Header.size == 12 ? 3 : 4);
|
||||
State->BufferSize = State->Header.n_colors * samples;
|
||||
|
||||
/* Skip over everything between the palette and the data.
|
||||
This protects us against a malicious BFH[10] value.
|
||||
*/
|
||||
State->BufferPadding = (lsb_32 (&BFH[10]) - 14 - State->Header.size) - State->BufferSize;
|
||||
|
||||
} else if (State->Compressed == BI_RGB) {
|
||||
if (State->BufferSize < lsb_32 (&BFH[10]))
|
||||
{
|
||||
@ -433,8 +465,19 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
|
||||
State->BufferSize = State->LineWidth;
|
||||
}
|
||||
} else if (State->Compressed == BI_BITFIELDS) {
|
||||
State->read_state = READ_STATE_BITMASKS;
|
||||
State->BufferSize = 12;
|
||||
if (State->Header.size == 108 || State->Header.size == 124)
|
||||
{
|
||||
/* v4 and v5 have the bitmasks in the header */
|
||||
if (!decode_bitmasks (&BIH[40], State, error)) {
|
||||
State->read_state = READ_STATE_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
State->read_state = READ_STATE_BITMASKS;
|
||||
State->BufferSize = 12;
|
||||
}
|
||||
} else {
|
||||
g_set_error (error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
@ -511,12 +554,13 @@ find_bits (int n, int *lowest, int *n_set)
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes the 3 shorts that follow for the bitmasks for BI_BITFIELDS coding */
|
||||
/* Decodes the bitmasks for BI_BITFIELDS coding */
|
||||
static gboolean
|
||||
decode_bitmasks (guchar *buf,
|
||||
struct bmp_progressive_state *State,
|
||||
GError **error)
|
||||
{
|
||||
State->a_mask = State->a_shift = State->a_bits = 0;
|
||||
State->r_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
buf += 4;
|
||||
|
||||
@ -529,15 +573,36 @@ decode_bitmasks (guchar *buf,
|
||||
find_bits (State->g_mask, &State->g_shift, &State->g_bits);
|
||||
find_bits (State->b_mask, &State->b_shift, &State->b_bits);
|
||||
|
||||
if (State->r_bits == 0 || State->g_bits == 0 || State->b_bits == 0) {
|
||||
State->r_mask = 0x7c00;
|
||||
State->r_shift = 10;
|
||||
State->g_mask = 0x03e0;
|
||||
State->g_shift = 5;
|
||||
State->b_mask = 0x001f;
|
||||
State->b_shift = 0;
|
||||
/* v4 and v5 have an alpha mask */
|
||||
if (State->Header.size == 108 || State->Header.size == 124) {
|
||||
buf += 4;
|
||||
State->a_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
find_bits (State->a_mask, &State->a_shift, &State->a_bits);
|
||||
}
|
||||
|
||||
State->r_bits = State->g_bits = State->b_bits = 5;
|
||||
if (State->r_bits == 0 || State->g_bits == 0 || State->b_bits == 0) {
|
||||
if (State->Type == 16) {
|
||||
State->r_mask = 0x7c00;
|
||||
State->r_shift = 10;
|
||||
State->g_mask = 0x03e0;
|
||||
State->g_shift = 5;
|
||||
State->b_mask = 0x001f;
|
||||
State->b_shift = 0;
|
||||
|
||||
State->r_bits = State->g_bits = State->b_bits = 5;
|
||||
}
|
||||
else {
|
||||
State->r_mask = 0x00ff0000;
|
||||
State->r_shift = 16;
|
||||
State->g_mask = 0x0000ff00;
|
||||
State->g_shift = 8;
|
||||
State->b_mask = 0x000000ff;
|
||||
State->b_shift = 0;
|
||||
State->a_mask = 0xff000000;
|
||||
State->a_shift = 24;
|
||||
|
||||
State->r_bits = State->g_bits = State->b_bits = State->a_bits = 8;
|
||||
}
|
||||
}
|
||||
|
||||
State->read_state = READ_STATE_DATA;
|
||||
@ -573,6 +638,7 @@ gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
|
||||
context->read_state = READ_STATE_HEADERS;
|
||||
|
||||
context->BufferSize = 26;
|
||||
context->BufferPadding = 0;
|
||||
context->buff = g_malloc(26);
|
||||
context->BufferDone = 0;
|
||||
/* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */
|
||||
@ -644,28 +710,35 @@ static void OneLine32(struct bmp_progressive_state *context)
|
||||
int r_lshift, r_rshift;
|
||||
int g_lshift, g_rshift;
|
||||
int b_lshift, b_rshift;
|
||||
int a_lshift, a_rshift;
|
||||
|
||||
r_lshift = 8 - context->r_bits;
|
||||
g_lshift = 8 - context->g_bits;
|
||||
b_lshift = 8 - context->b_bits;
|
||||
a_lshift = 8 - context->a_bits;
|
||||
|
||||
r_rshift = context->r_bits - r_lshift;
|
||||
g_rshift = context->g_bits - g_lshift;
|
||||
b_rshift = context->b_bits - b_lshift;
|
||||
a_rshift = context->a_bits - a_lshift;
|
||||
|
||||
for (i = 0; i < context->Header.width; i++) {
|
||||
int v, r, g, b;
|
||||
int v, r, g, b, a;
|
||||
|
||||
v = src[0] | (src[1] << 8) | (src[2] << 16);
|
||||
v = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
||||
|
||||
r = (v & context->r_mask) >> context->r_shift;
|
||||
g = (v & context->g_mask) >> context->g_shift;
|
||||
b = (v & context->b_mask) >> context->b_shift;
|
||||
a = (v & context->a_mask) >> context->a_shift;
|
||||
|
||||
*pixels++ = (r << r_lshift) | (r >> r_rshift);
|
||||
*pixels++ = (g << g_lshift) | (g >> g_rshift);
|
||||
*pixels++ = (b << b_lshift) | (b >> b_rshift);
|
||||
*pixels++ = 0xff;
|
||||
if (context->a_bits)
|
||||
*pixels++ = 0xff - (a << a_lshift) | (a >> a_rshift);
|
||||
else
|
||||
*pixels++ = 0xff;
|
||||
|
||||
src += 4;
|
||||
}
|
||||
@ -1078,6 +1151,7 @@ gdk_pixbuf__bmp_image_load_increment(gpointer data,
|
||||
(struct bmp_progressive_state *) data;
|
||||
|
||||
gint BytesToCopy;
|
||||
gint BytesToRemove;
|
||||
|
||||
if (context->read_state == READ_STATE_DONE)
|
||||
return TRUE;
|
||||
@ -1103,6 +1177,19 @@ gdk_pixbuf__bmp_image_load_increment(gpointer data,
|
||||
break;
|
||||
}
|
||||
|
||||
/* context->buff is full. Now we discard all "padding" */
|
||||
if (context->BufferPadding != 0) {
|
||||
BytesToRemove = context->BufferPadding - size;
|
||||
if (BytesToRemove > size) {
|
||||
BytesToRemove = size;
|
||||
}
|
||||
size -= BytesToRemove;
|
||||
context->BufferPadding -= BytesToRemove;
|
||||
|
||||
if (context->BufferPadding != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
switch (context->read_state) {
|
||||
case READ_STATE_HEADERS:
|
||||
if (!DecodeHeader (context->buff,
|
||||
|
Loading…
Reference in New Issue
Block a user