Split xrdp_bitmap.c into separate files for testing

This commit is contained in:
matt335672 2021-07-07 09:43:42 +01:00
parent ee79247110
commit 2c841d0603
5 changed files with 1131 additions and 1080 deletions

View File

@ -43,6 +43,8 @@ xrdp_SOURCES = \
xrdp.c \
xrdp.h \
xrdp_bitmap.c \
xrdp_bitmap_load.c \
xrdp_bitmap_common.c \
xrdp_cache.c \
xrdp_encoder.c \
xrdp_encoder.h \

View File

@ -185,7 +185,7 @@ int
xrdp_region_get_rect(struct xrdp_region *self, int index,
struct xrdp_rect *rect);
/* xrdp_bitmap.c */
/* xrdp_bitmap_common.c */
struct xrdp_bitmap *
xrdp_bitmap_create(int width, int height, int bpp,
int type, struct xrdp_wm *wm);
@ -195,39 +195,8 @@ xrdp_bitmap_create_with_data(int width, int height,
struct xrdp_wm *wm);
void
xrdp_bitmap_delete(struct xrdp_bitmap *self);
struct xrdp_bitmap *
xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id);
int
xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused);
int
xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height);
/**
* Loads a bitmap from a file and (optionally) transforms it
*
* @param self from rdp_bitmap_create()
* @param filename Filename to load
* @param[in] palette For 8-bit conversions. Currently unused
* @param background Background color for alpha-blending
* @param transform Transform to apply to the image after loading
* @param twidth target width if transform != XBLT_NONE
* @param theight target height if transform != XBLT_NONE
* @return 0 for success.
*
* The background color is only used if the specified image contains
* an alpha layer
*
* After a successful call, the bitmap is resized to the image file size.
*
* If the call is not successful, the bitmap will be in an indeterminate
* state and should not be used.
*/
int
xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename,
const int *palette,
int background,
enum xrdp_bitmap_load_transform transform,
int twidth,
int theight);
int
xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y);
int
@ -236,6 +205,12 @@ int
xrdp_bitmap_copy_box(struct xrdp_bitmap *self,
struct xrdp_bitmap *dest,
int x, int y, int cx, int cy);
/* xrdp_bitmap.c */
struct xrdp_bitmap *
xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id);
int
xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused);
int
xrdp_bitmap_hash_crc(struct xrdp_bitmap *self);
int
@ -264,6 +239,34 @@ xrdp_bitmap_get_screen_clip(struct xrdp_bitmap *self,
struct xrdp_rect *rect,
int *dx, int *dy);
/* xrdp_bitmap_load.c */
/**
* Loads a bitmap from a file and (optionally) transforms it
*
* @param self from rdp_bitmap_create()
* @param filename Filename to load
* @param[in] palette For 8-bit conversions. Currently unused
* @param background Background color for alpha-blending
* @param transform Transform to apply to the image after loading
* @param twidth target width if transform != XBLT_NONE
* @param theight target height if transform != XBLT_NONE
* @return 0 for success.
*
* The background color is only used if the specified image contains
* an alpha layer
*
* After a successful call, the bitmap is resized to the image file size.
*
* If the call is not successful, the bitmap will be in an indeterminate
* state and should not be used.
*/
int
xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename,
const int *palette,
int background,
enum xrdp_bitmap_load_transform transform,
int twidth,
int theight);
/* xrdp_painter.c */
struct xrdp_painter *
xrdp_painter_create(struct xrdp_wm *wm, struct xrdp_session *session);

File diff suppressed because it is too large Load Diff

509
xrdp/xrdp_bitmap_common.c Normal file
View File

@ -0,0 +1,509 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Common bitmap functions for all xrdp_bitmap*.c files
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <limits.h>
#include "xrdp.h"
/*****************************************************************************/
/* Allocate bitmap for specified dimensions, checking for int overflow */
static char *
alloc_bitmap_data(int width, int height, int Bpp)
{
char *result = NULL;
if (width > 0 && height > 0 && Bpp > 0)
{
int len = width;
/* g_malloc() currently takes an 'int' size */
if (len < INT_MAX / height)
{
len *= height;
if (len < INT_MAX / Bpp)
{
len *= Bpp;
result = (char *)malloc(len);
}
}
}
return result;
}
/*****************************************************************************/
struct xrdp_bitmap *
xrdp_bitmap_create(int width, int height, int bpp,
int type, struct xrdp_wm *wm)
{
struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL;
int Bpp = 0;
self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1);
if (self == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: no memory");
return self;
}
self->type = type;
self->width = width;
self->height = height;
self->bpp = bpp;
Bpp = 4;
switch (bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE)
{
self->data = alloc_bitmap_data(width, height, Bpp);
if (self->data == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d",
width, height, Bpp);
g_free(self);
return NULL;
}
}
#if defined(XRDP_PAINTER)
if (self->type == WND_TYPE_SCREEN) /* noorders */
{
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_bitmap_create: noorders");
self->data = alloc_bitmap_data(width, height, Bpp);
if (self->data == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d",
width, height, Bpp);
g_free(self);
return NULL;
}
}
#endif
if (self->type != WND_TYPE_BITMAP)
{
self->child_list = list_create();
}
self->line_size = width * Bpp;
if (self->type == WND_TYPE_COMBO)
{
self->string_list = list_create();
self->string_list->auto_free = 1;
self->data_list = list_create();
self->data_list->auto_free = 1;
}
self->wm = wm;
return self;
}
/*****************************************************************************/
struct xrdp_bitmap *
xrdp_bitmap_create_with_data(int width, int height,
int bpp, char *data,
struct xrdp_wm *wm)
{
struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL;
int Bpp;
#if defined(NEED_ALIGN)
tintptr data_as_int;
#endif
self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1);
self->type = WND_TYPE_BITMAP;
self->width = width;
self->height = height;
self->bpp = bpp;
self->wm = wm;
Bpp = 4;
switch (bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
self->line_size = width * Bpp;
#if defined(NEED_ALIGN)
data_as_int = (tintptr) data;
if (((bpp >= 24) && (data_as_int & 3)) ||
(((bpp == 15) || (bpp == 16)) && (data_as_int & 1)))
{
/* got to copy data here, it's not aligned
other calls in this file assume alignment */
self->data = (char *)g_malloc(width * height * Bpp, 0);
g_memcpy(self->data, data, width * height * Bpp);
return self;
}
#endif
self->data = data;
self->do_not_free_data = 1;
return self;
}
/*****************************************************************************/
void
xrdp_bitmap_delete(struct xrdp_bitmap *self)
{
int i = 0;
struct xrdp_mod_data *mod_data = (struct xrdp_mod_data *)NULL;
if (self == 0)
{
return;
}
if (self->wm != 0)
{
if (self->wm->focused_window != 0)
{
if (self->wm->focused_window->focused_control == self)
{
self->wm->focused_window->focused_control = 0;
}
}
if (self->wm->focused_window == self)
{
self->wm->focused_window = 0;
}
if (self->wm->dragging_window == self)
{
self->wm->dragging_window = 0;
}
if (self->wm->button_down == self)
{
self->wm->button_down = 0;
}
if (self->wm->popup_wnd == self)
{
self->wm->popup_wnd = 0;
}
if (self->wm->login_window == self)
{
self->wm->login_window = 0;
}
if (self->wm->log_wnd == self)
{
self->wm->log_wnd = 0;
}
}
if (self->child_list != 0)
{
for (i = self->child_list->count - 1; i >= 0; i--)
{
xrdp_bitmap_delete((struct xrdp_bitmap *)self->child_list->items[i]);
}
list_delete(self->child_list);
}
if (self->parent != 0)
{
i = list_index_of(self->parent->child_list, (long)self);
if (i >= 0)
{
list_remove_item(self->parent->child_list, i);
}
}
if (self->string_list != 0) /* for combo */
{
list_delete(self->string_list);
}
if (self->data_list != 0) /* for combo */
{
for (i = 0; i < self->data_list->count; i++)
{
mod_data = (struct xrdp_mod_data *)list_get_item(self->data_list, i);
if (mod_data != 0)
{
list_delete(mod_data->names);
list_delete(mod_data->values);
}
}
list_delete(self->data_list);
}
if (!self->do_not_free_data)
{
g_free(self->data);
}
g_free(self->caption1);
g_free(self);
}
/*****************************************************************************/
/* returns error */
int
xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
{
int Bpp = 0;
if ((width == self->width) && (height == self->height))
{
return 0;
}
if (self->do_not_free_data)
{
return 1;
}
self->width = width;
self->height = height;
Bpp = 4;
switch (self->bpp)
{
case 8:
Bpp = 1;
break;
case 15:
Bpp = 2;
break;
case 16:
Bpp = 2;
break;
}
g_free(self->data);
self->data = (char *)g_malloc(width * height * Bpp, 0);
self->line_size = width * Bpp;
return 0;
}
/*****************************************************************************/
int
xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y)
{
if (self == 0)
{
return 0;
}
if (self->data == 0)
{
return 0;
}
if (x >= 0 && x < self->width && y >= 0 && y < self->height)
{
if (self->bpp == 8)
{
return GETPIXEL8(self->data, x, y, self->width);
}
else if (self->bpp == 15 || self->bpp == 16)
{
return GETPIXEL16(self->data, x, y, self->width);
}
else if (self->bpp >= 24)
{
return GETPIXEL32(self->data, x, y, self->width);
}
}
return 0;
}
/*****************************************************************************/
int
xrdp_bitmap_set_pixel(struct xrdp_bitmap *self, int x, int y, int pixel)
{
if (self == 0)
{
return 0;
}
if (self->data == 0)
{
return 0;
}
if (x >= 0 && x < self->width && y >= 0 && y < self->height)
{
if (self->bpp == 8)
{
SETPIXEL8(self->data, x, y, self->width, pixel);
}
else if (self->bpp == 15 || self->bpp == 16)
{
SETPIXEL16(self->data, x, y, self->width, pixel);
}
else if (self->bpp >= 24)
{
SETPIXEL32(self->data, x, y, self->width, pixel);
}
}
return 0;
}
/*****************************************************************************/
/* copy part of self at x, y to 0, 0 in dest */
/* returns error */
int
xrdp_bitmap_copy_box(struct xrdp_bitmap *self,
struct xrdp_bitmap *dest,
int x, int y, int cx, int cy)
{
int i;
int destx;
int desty;
int incs;
int incd;
tui8 *s8;
tui8 *d8;
tui16 *s16;
tui16 *d16;
tui32 *s32;
tui32 *d32;
if (self == 0)
{
return 1;
}
if (dest == 0)
{
return 1;
}
if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE)
{
return 1;
}
if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE)
{
return 1;
}
if (self->bpp != dest->bpp)
{
return 1;
}
destx = 0;
desty = 0;
if (!check_bounds(self, &x, &y, &cx, &cy))
{
return 1;
}
if (!check_bounds(dest, &destx, &desty, &cx, &cy))
{
return 1;
}
if (self->bpp >= 24)
{
s32 = ((tui32 *)(self->data)) + (self->width * y + x);
d32 = ((tui32 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d32, s32, cx * 4);
s32 += cx;
d32 += cx;
s32 += incs;
d32 += incd;
}
}
else if (self->bpp == 15 || self->bpp == 16)
{
s16 = ((tui16 *)(self->data)) + (self->width * y + x);
d16 = ((tui16 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d16, s16, cx * 2);
s16 += cx;
d16 += cx;
s16 += incs;
d16 += incd;
}
}
else if (self->bpp == 8)
{
s8 = ((tui8 *)(self->data)) + (self->width * y + x);
d8 = ((tui8 *)(dest->data)) + (dest->width * desty + destx);
incs = self->width - cx;
incd = dest->width - cx;
for (i = 0; i < cy; i++)
{
g_memcpy(d8, s8, cx);
s8 += cx;
d8 += cx;
s8 += incs;
d8 += incd;
}
}
else
{
return 1;
}
return 0;
}

585
xrdp/xrdp_bitmap_load.c Normal file
View File

@ -0,0 +1,585 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Load xrdp_bitmap from file
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include "xrdp.h"
#include "log.h"
/**************************************************************************//**
* Private routine to swap pixel data between two pixmaps
* @param a First bitmap
* @param b Second bitmap
*
* The main use-case for this routine is to modify an existing bitmap using
* the following logic:-
* - Create a temporary WND_TYPE_BITMAP
* - Process the data in a bitmap in some way, moving it to the temporary
* - Call this routine
* - Delete the temporary
*
*/
static void
swap_pixel_data(struct xrdp_bitmap *a, struct xrdp_bitmap *b)
{
int tmp_width = a->width;
int tmp_height = a->height;
int tmp_bpp = a->bpp;
int tmp_line_size = a->line_size;
char *tmp_data = a->data;
int tmp_do_not_free_data = a->do_not_free_data;
a->width = b->width;
a->height = b->height;
a->bpp = b->bpp;
a->line_size = b->line_size;
a->data = b->data;
a->do_not_free_data = b->do_not_free_data;
b->width = tmp_width;
b->height = tmp_height;
b->bpp = tmp_bpp;
b->line_size = tmp_line_size;
b->data = tmp_data;
b->do_not_free_data = tmp_do_not_free_data;
}
/**************************************************************************//**
* Scales a bitmap image
*
* @param self Bitmap to scale
* @param target_width target width
* @param target_height target height
* @return 0 for success
*/
static int
xrdp_bitmap_scale(struct xrdp_bitmap *self, int targ_width, int targ_height)
{
int src_width = self->width;
int src_height = self->height;
if (src_width != targ_width || src_height != targ_height)
{
struct xrdp_bitmap *target =
xrdp_bitmap_create(targ_width, targ_height,
self->bpp, WND_TYPE_BITMAP, 0);
int targ_x, targ_y;
if (target == NULL)
{
/* Error is logged */
return 1;
}
/* For each pixel in the target pixmap, scale to one in the source */
for (targ_x = 0 ; targ_x < targ_width; ++targ_x)
{
int src_x = targ_x * src_width / targ_width;
for (targ_y = 0 ; targ_y < targ_height; ++targ_y)
{
int src_y = targ_y * src_height / targ_height;
int pixel = xrdp_bitmap_get_pixel(self, src_x, src_y);
xrdp_bitmap_set_pixel(target, targ_x, targ_y, pixel);
}
}
swap_pixel_data(self, target);
xrdp_bitmap_delete(target);
}
return 0;
}
/**************************************************************************//**
* Zooms a bitmap image
*
* @param self Bitmap to zoom
* @param target_width target width
* @param target_height target height
* @return 0 for success
*
* This works the same way as a scaled image, but the aspect ratio is
* maintained by removing pixels from the top-and-bottom,
* or the left-and-right before scaling.
*/
static int
xrdp_bitmap_zoom(struct xrdp_bitmap *self, int targ_width, int targ_height)
{
int src_width = self->width;
int src_height = self->height;
double targ_ratio = (double)targ_width / targ_height;
double src_ratio = (double)src_width / src_height;
unsigned int chop_width;
unsigned int chop_left_margin;
unsigned int chop_height;
unsigned int chop_top_margin;
int result = 0;
if (src_ratio > targ_ratio)
{
/* Source is relatively wider than source. Select a box
* narrower than the source, but the same height */
chop_width = (int)(targ_ratio * src_height + .5);
chop_left_margin = (src_width - chop_width) / 2;
chop_height = src_height;
chop_top_margin = 0;
}
else
{
/* Source is relatively taller than source (or same shape) */
chop_width = src_width;
chop_left_margin = 0;
chop_height = (int)(src_width / targ_ratio + .5);
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)
{
struct xrdp_bitmap *chopbox;
chopbox = xrdp_bitmap_create(chop_width, chop_height, self->bpp,
WND_TYPE_BITMAP, 0);
if (chopbox == NULL)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: no memory");
result = 1;
}
else
{
result = xrdp_bitmap_copy_box(self, chopbox,
chop_left_margin, chop_top_margin,
chop_width, chop_height);
if (result != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: can't copy box");
}
else
{
swap_pixel_data(self, chopbox);
}
xrdp_bitmap_delete(chopbox);
}
}
if (result == 0)
{
result = xrdp_bitmap_scale(self, targ_width, targ_height);
}
return result;
}
/*****************************************************************************/
static int
xrdp_bitmap_get_index(struct xrdp_bitmap *self, const int *palette, int color)
{
int r = 0;
int g = 0;
int b = 0;
r = (color & 0xff0000) >> 16;
g = (color & 0x00ff00) >> 8;
b = (color & 0x0000ff) >> 0;
r = (r >> 5) << 0;
g = (g >> 5) << 3;
b = (b >> 6) << 6;
return (b | g | r);
}
/*****************************************************************************/
/* 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)
{
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;
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));
if (!g_file_exist(filename))
{
LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] does not exist",
__func__, filename);
return 1;
}
fd = g_file_open(filename);
if (fd == -1)
{
LOG(LOG_LEVEL_ERROR, "%s: error loading bitmap from file [%s]",
__func__, filename);
return 1;
}
/* read file type */
if (g_file_read(fd, type1, 2) != 2)
{
LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] read error",
__func__, filename);
g_file_close(fd);
return 1;
}
if ((type1[0] != 'B') || (type1[1] != 'M'))
{
LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] not BMP file",
__func__, filename);
g_file_close(fd);
return 1;
}
/* read file size */
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)
{
LOG(LOG_LEVEL_ERROR, "%s: unexpected read length %d in file %s",
__func__, len, filename);
free_stream(s);
g_file_close(fd);
return 1;
}
s->end = s->data + len;
in_uint32_le(s, header.size);
in_uint32_le(s, header.image_width);
in_uint32_le(s, header.image_height);
in_uint16_le(s, header.planes);
in_uint16_le(s, header.bit_count);
in_uint32_le(s, header.compression);
in_uint32_le(s, header.image_size);
in_uint32_le(s, header.x_pels_per_meter);
in_uint32_le(s, header.y_pels_per_meter);
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))
{
LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] bad bpp %d",
__func__, filename, header.bit_count);
free_stream(s);
g_file_close(fd);
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--)
{
size = header.image_width * 3;
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 = 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);
}
}
}
g_file_close(fd);
free_stream(s);
return 0;
}
/*****************************************************************************/
int
xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename,
const int *palette,
int background,
enum xrdp_bitmap_load_transform transform,
int twidth,
int theight)
{
/* this is the default bmp-only implementation if a graphics library
* isn't built in */
int result = xrdp_bitmap_load_bmp(self, filename, palette);
if (result == 0)
{
switch (transform)
{
case XBLT_NONE:
break;
case XBLT_SCALE:
result = xrdp_bitmap_scale(self, twidth, theight);
break;
case XBLT_ZOOM:
result = xrdp_bitmap_zoom(self, twidth, theight);
break;
default:
LOG(LOG_LEVEL_WARNING, "Invalid bitmap transform %d specified",
transform);
}
}
return result;
}