Rework and simplify xrdp_bitmap_load_bmp()

This commit is contained in:
matt335672 2021-07-07 16:48:31 +01:00
parent 2c841d0603
commit f87502872d

View File

@ -25,6 +25,9 @@
#include "xrdp.h"
#include "log.h"
/* Rounds up to the nearest multiple of 4 */
#define ROUND4(x) (((x) + 3) / 4 * 4)
/**************************************************************************//**
* Private routine to swap pixel data between two pixmaps
* @param a First bitmap
@ -153,8 +156,15 @@ xrdp_bitmap_zoom(struct xrdp_bitmap *self, int targ_width, int targ_height)
chop_top_margin = (src_height - chop_height) / 2;
}
/* Only chop the image if there's a need to */
if (chop_top_margin != 0 || chop_left_margin != 0)
/* Only chop the image if there's a need to, and if it will look
* meaningful */
if (chop_width < 1 || chop_height < 1)
{
LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_zoom: Ignoring pathological"
" request (%dx%d) -> (%dx%d)", src_width, src_height,
targ_width, targ_height);
}
else if (chop_top_margin != 0 || chop_left_margin != 0)
{
struct xrdp_bitmap *chopbox;
chopbox = xrdp_bitmap_create(chop_width, chop_height, self->bpp,
@ -206,29 +216,245 @@ xrdp_bitmap_get_index(struct xrdp_bitmap *self, const int *palette, int color)
return (b | g | r);
}
/**************************************************************************//**
* reads the palette from a bmp file with a palette embedded in it
*
* @pre The read position in the file is at the end of the bmp DIB header.
*
* @param filename Name of file
* @param fd File descriptor for file
* @param header Pointer to BMP header info struct
* @param palette output. Must be at least 256 elements
*/
static void
read_palette(const char *filename, int fd,
const struct xrdp_bmp_header *header, int *palette)
{
struct stream *s;
int clr_used;
int palette_size;
int len;
int i;
/* Find the number of colors used in the bitmap */
if (header->clr_used != 0)
{
clr_used = header->clr_used;
/* Is the header value sane? */
if (clr_used < 0 || clr_used > 256)
{
clr_used = 256;
LOG(LOG_LEVEL_WARNING, "%s : Invalid palette size %d in file %s",
__func__, header->clr_used, filename);
}
}
else if (header->bit_count == 4)
{
clr_used = 16;
}
else
{
clr_used = 256;
}
palette_size = clr_used * 4;
make_stream(s);
init_stream(s, palette_size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, palette_size);
s->end = s->data + palette_size;
len = g_file_read(fd, s->data, palette_size);
if (len != palette_size)
{
LOG(LOG_LEVEL_WARNING, "%s: unexpected read length in file %s",
__func__, filename);
}
for (i = 0; i < clr_used; ++i)
{
in_uint32_le(s, palette[i]);
}
free_stream(s);
}
/**************************************************************************//**
* Process a row of data from a 24-bit bmp file
*
* @param self Bitmap we're filling in
* @param s Stream containing bitmap data
* @param in_palette Palette from bmp file (unused)
* @param out_palette Palette for output bitmap
* @param row Row number
*/
static void
process_row_data_24bit(struct xrdp_bitmap *self,
struct stream *s,
const int *in_palette,
const int *out_palette,
int row)
{
int j;
int k;
int color;
for (j = 0; j < self->width; ++j)
{
in_uint8(s, k);
color = k;
in_uint8(s, k);
color |= k << 8;
in_uint8(s, k);
color |= k << 16;
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, out_palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, row, color);
}
}
/**************************************************************************//**
* Process a row of data from an 8-bit bmp file
*
* @param self Bitmap we're filling in
* @param s Stream containing bitmap data
* @param in_palette Palette from bmp file
* @param out_palette Palette for output bitmap
* @param row Row number
*/
static void
process_row_data_8bit(struct xrdp_bitmap *self,
struct stream *s,
const int *in_palette,
const int *out_palette,
int row)
{
int j;
int k;
int color;
for (j = 0; j < self->width; ++j)
{
in_uint8(s, k);
color = in_palette[k];
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, out_palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, row, color);
}
}
/**************************************************************************//**
* Process a row of data from an 4-bit bmp file
*
* @param self Bitmap we're filling in
* @param s Stream containing bitmap data
* @param in_palette Palette from bmp file
* @param out_palette Palette for output bitmap
* @param row Row number
*/
static void
process_row_data_4bit(struct xrdp_bitmap *self,
struct stream *s,
const int *in_palette,
const int *out_palette,
int row)
{
int j;
int k = 0;
int color;
for (j = 0; j < self->width; ++j)
{
if ((j & 1) == 0)
{
in_uint8(s, k);
color = (k >> 4) & 0xf;
}
else
{
color = k & 0xf;
}
color = in_palette[color];
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, out_palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, row, color);
}
}
/*****************************************************************************/
/* load a bmp file */
/* return 0 ok */
/* return 1 error */
static int
xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename,
const int *palette)
const int *out_palette)
{
int fd = 0;
int len = 0;
int i = 0;
int j = 0;
int k = 0;
int color = 0;
int size = 0;
int palette1[256];
char type1[4];
struct xrdp_bmp_header header;
int row = 0;
int row_size = 0;
int bmp_palette[256] = {0};
char fixed_header[14] = {0};
struct xrdp_bmp_header header = {0};
struct stream *s = (struct stream *)NULL;
g_memset(palette1, 0, sizeof(int) * 256);
g_memset(type1, 0, sizeof(char) * 4);
g_memset(&header, 0, sizeof(struct xrdp_bmp_header));
/* Pointer to row data processing function */
void (*process_row_data)(struct xrdp_bitmap * self,
struct stream * s,
const int *in_palette,
const int *out_palette,
int row);
if (!g_file_exist(filename))
{
@ -246,8 +472,8 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename,
return 1;
}
/* read file type */
if (g_file_read(fd, type1, 2) != 2)
/* read the fixed file header */
if (g_file_read(fd, fixed_header, 14) != 14)
{
LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] read error",
__func__, filename);
@ -255,7 +481,7 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename,
return 1;
}
if ((type1[0] != 'B') || (type1[1] != 'M'))
if ((fixed_header[0] != 'B') || (fixed_header[1] != 'M'))
{
LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] not BMP file",
__func__, filename);
@ -263,29 +489,9 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename,
return 1;
}
/* read file size */
/* read information header */
make_stream(s);
init_stream(s, 8192);
if (g_file_read(fd, s->data, 4) != 4)
{
LOG(LOG_LEVEL_ERROR, "%s: missing length in file %s",
__func__, filename);
free_stream(s);
g_file_close(fd);
return 1;
}
s->end = s->data + 4;
in_uint32_le(s, size);
/* read bmp header */
if (g_file_seek(fd, 14) < 0)
{
LOG(LOG_LEVEL_ERROR, "%s: seek error in file %s",
__func__, filename);
free_stream(s);
g_file_close(fd);
return 1;
}
init_stream(s, 8192);
len = g_file_read(fd, s->data, 40); /* size better be 40 */
if (len != 40)
{
@ -308,9 +514,46 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename,
in_uint32_le(s, header.clr_used);
in_uint32_le(s, header.clr_important);
if ((header.bit_count != 4) && (header.bit_count != 8) &&
(header.bit_count != 24))
if (header.compression != 0)
{
LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s]"
" unsupported compression value %d",
__func__, filename, header.compression);
}
if (g_file_seek(fd, 14 + header.size) < 0)
{
LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s",
__func__, filename);
}
/* Validate the bit count for the file, read any palette, and
* dtermine the row size and row processing function */
switch (header.bit_count)
{
case 24:
row_size = ROUND4(header.image_width * 3);
process_row_data = process_row_data_24bit;
break;
case 8:
read_palette(filename, fd, &header, bmp_palette);
row_size = ROUND4(header.image_width);
process_row_data = process_row_data_8bit;
break;
case 4:
read_palette(filename, fd, &header, bmp_palette);
/* The storage for a row is a complex calculation for 4 bit pixels.
* a width of 1-8 pixels takes 4 bytes
* a width of 9-16 pixels takes 8 bytes, etc
* So bytes = (width + 7) / 8 * 4
*/
row_size = ((header.image_width + 7) / 8 * 4);
process_row_data = process_row_data_4bit;
break;
default:
LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] bad bpp %d",
__func__, filename, header.bit_count);
free_stream(s);
@ -318,228 +561,27 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename,
return 1;
}
if (header.bit_count == 24) /* 24 bit bitmap */
{
if (g_file_seek(fd, 14 + header.size) < 0)
{
LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s",
__func__, filename);
}
xrdp_bitmap_resize(self, header.image_width, header.image_height);
size = header.image_width * header.image_height * 3;
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
/* read data */
for (i = header.image_height - 1; i >= 0; i--)
/* Set up the row data buffer. Pre fill it, so if we get short reads
* we're not working with uninitialised data */
init_stream(s, row_size);
g_memset(s->data, 0, row_size);
s->end = s->data + row_size;
/* read and process the pixel data a row at a time */
for (row = header.image_height - 1; row >= 0; row--)
{
size = header.image_width * 3;
k = g_file_read(fd, s->data + i * size, size);
len = g_file_read(fd, s->data, row_size);
if (k != size)
if (len != row_size)
{
LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read",
__func__, filename);
}
}
for (i = 0; i < self->height; i++)
{
for (j = 0; j < self->width; j++)
{
in_uint8(s, k);
color = k;
in_uint8(s, k);
color |= k << 8;
in_uint8(s, k);
color |= k << 16;
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, i, color);
}
}
}
else if (header.bit_count == 8) /* 8 bit bitmap */
{
/* read palette */
if (g_file_seek(fd, 14 + header.size) < 0)
{
LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s",
__func__, filename);
}
size = header.clr_used * sizeof(int);
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
len = g_file_read(fd, s->data, size);
if (len != size)
{
LOG(LOG_LEVEL_ERROR, "%s: unexpected read length in file %s",
__func__, filename);
}
for (i = 0; i < header.clr_used; i++)
{
in_uint32_le(s, palette1[i]);
}
xrdp_bitmap_resize(self, header.image_width, header.image_height);
size = header.image_width * header.image_height;
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
/* read data */
for (i = header.image_height - 1; i >= 0; i--)
{
size = header.image_width;
k = g_file_read(fd, s->data + i * size, size);
if (k != size)
{
LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read",
__func__, filename);
}
}
for (i = 0; i < self->height; i++)
{
for (j = 0; j < self->width; j++)
{
in_uint8(s, k);
color = palette1[k];
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, i, color);
}
}
}
else if (header.bit_count == 4) /* 4 bit bitmap */
{
/* read palette */
if (g_file_seek(fd, 14 + header.size) < 0)
{
LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s",
__func__, filename);
}
size = header.clr_used * sizeof(int);
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
len = g_file_read(fd, s->data, size);
if (len != size)
{
LOG(LOG_LEVEL_ERROR, "%s: unexpected read length in file %s",
__func__, filename);
}
for (i = 0; i < header.clr_used; i++)
{
in_uint32_le(s, palette1[i]);
}
xrdp_bitmap_resize(self, header.image_width, header.image_height);
size = (header.image_width * header.image_height) / 2;
init_stream(s, size);
/* Pre-fill the buffer, so if we get short reads we're
* not working with uninitialised data */
g_memset(s->data, 0, size);
s->end = s->data + size;
/* read data */
for (i = header.image_height - 1; i >= 0; i--)
{
size = header.image_width / 2;
k = g_file_read(fd, s->data + i * size, size);
if (k != size)
{
LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read",
__func__, filename);
}
}
for (i = 0; i < self->height; i++)
{
for (j = 0; j < self->width; j++)
{
if ((j & 1) == 0)
{
in_uint8(s, k);
color = (k >> 4) & 0xf;
}
else
{
color = k & 0xf;
}
color = palette1[color];
if (self->bpp == 8)
{
color = xrdp_bitmap_get_index(self, palette, color);
}
else if (self->bpp == 15)
{
color = COLOR15((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
else if (self->bpp == 16)
{
color = COLOR16((color & 0xff0000) >> 16,
(color & 0x00ff00) >> 8,
(color & 0x0000ff) >> 0);
}
xrdp_bitmap_set_pixel(self, j, i, color);
}
}
s->p = s->data;
(*process_row_data)(self, s, bmp_palette, out_palette, row);
}
g_file_close(fd);