mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-26 14:41:25 +00:00
291 lines
7.5 KiB
C++
291 lines
7.5 KiB
C++
/*
|
|
Copyright (C) 2009 Red Hat, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "glz_decoder_config.h"
|
|
#include "glz_decoder.h"
|
|
|
|
GlzDecoder::GlzDecoder(GlzDecoderWindow &images_window,
|
|
GlzDecodeHandler &usr_handler, GlzDecoderDebug &debug_calls)
|
|
: _images_window (images_window)
|
|
, _usr_handler (usr_handler)
|
|
, _debug_calls (debug_calls)
|
|
{
|
|
}
|
|
|
|
GlzDecoder::~GlzDecoder()
|
|
{
|
|
}
|
|
|
|
void GlzDecoder::decode_header()
|
|
{
|
|
int magic;
|
|
int version;
|
|
uint8_t tmp;
|
|
int stride;
|
|
|
|
magic = decode_32();
|
|
if (magic != LZ_MAGIC) {
|
|
_debug_calls.warn(std::string("bad magic\n"));
|
|
}
|
|
|
|
version = decode_32();
|
|
if (version != LZ_VERSION) {
|
|
_debug_calls.warn(std::string("bad version\n"));
|
|
}
|
|
|
|
tmp = *(_in_now++);
|
|
|
|
_image.type = (LzImageType)(tmp & LZ_IMAGE_TYPE_MASK);
|
|
_image.top_down = (tmp >> LZ_IMAGE_TYPE_LOG) ? true : false;
|
|
_image.width = decode_32();
|
|
_image.height = decode_32();
|
|
stride = decode_32();
|
|
|
|
if (IS_IMAGE_TYPE_PLT[_image.type]) {
|
|
_image.gross_pixels = stride * PLT_PIXELS_PER_BYTE[_image.type] * _image.height;
|
|
} else {
|
|
_image.gross_pixels = _image.width * _image.height;
|
|
}
|
|
|
|
_image.id = decode_64();
|
|
_image.win_head_dist = decode_32();
|
|
}
|
|
|
|
inline uint32_t GlzDecoder::decode_32()
|
|
{
|
|
uint32_t word = 0;
|
|
word |= *(_in_now++);
|
|
word <<= 8;
|
|
word |= *(_in_now++);
|
|
word <<= 8;
|
|
word |= *(_in_now++);
|
|
word <<= 8;
|
|
word |= *(_in_now++);
|
|
return word;
|
|
}
|
|
|
|
inline uint64_t GlzDecoder::decode_64()
|
|
{
|
|
uint64_t long_word = decode_32();
|
|
long_word <<= 32;
|
|
long_word |= decode_32();
|
|
return long_word;
|
|
}
|
|
|
|
// TODO: the code is historically c based. Consider transforming to c++ and use templates
|
|
// - but be sure it won't make it slower!
|
|
|
|
/*
|
|
* Give hints to the compiler for branch prediction optimization.
|
|
*/
|
|
#if defined(__GNUC__) && (__GNUC__ > 2)
|
|
#define LZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
|
|
#define LZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
|
|
#else
|
|
#define LZ_EXPECT_CONDITIONAL(c) (c)
|
|
#define LZ_UNEXPECT_CONDITIONAL(c) (c)
|
|
#endif
|
|
|
|
|
|
#ifdef __GNUC__
|
|
#define ATTR_PACKED __attribute__ ((__packed__))
|
|
#else
|
|
#define ATTR_PACKED
|
|
#pragma pack(push)
|
|
#pragma pack(1)
|
|
#endif
|
|
|
|
|
|
/* the palette images will be treated as one byte pixels. Their width should be transformed
|
|
accordingly.
|
|
*/
|
|
typedef struct ATTR_PACKED one_byte_pixel_t {
|
|
uint8_t a;
|
|
} one_byte_pixel_t;
|
|
|
|
typedef struct ATTR_PACKED rgb32_pixel_t {
|
|
uint8_t b;
|
|
uint8_t g;
|
|
uint8_t r;
|
|
uint8_t pad;
|
|
} rgb32_pixel_t;
|
|
|
|
typedef struct ATTR_PACKED rgb24_pixel_t {
|
|
uint8_t b;
|
|
uint8_t g;
|
|
uint8_t r;
|
|
} rgb24_pixel_t;
|
|
|
|
typedef uint16_t rgb16_pixel_t;
|
|
|
|
#ifndef __GNUC__
|
|
#pragma pack(pop)
|
|
#endif
|
|
|
|
#undef ATTR_PACKED
|
|
|
|
#define LZ_PLT
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#define LZ_PLT
|
|
#define PLT8
|
|
#define TO_RGB32
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#define LZ_PLT
|
|
#define PLT4_BE
|
|
#define TO_RGB32
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#define LZ_PLT
|
|
#define PLT4_LE
|
|
#define TO_RGB32
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#define LZ_PLT
|
|
#define PLT1_BE
|
|
#define TO_RGB32
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#define LZ_PLT
|
|
#define PLT1_LE
|
|
#define TO_RGB32
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
|
|
#define LZ_RGB16
|
|
#include "glz_decode_tmpl.c"
|
|
#define LZ_RGB16
|
|
#define TO_RGB32
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#define LZ_RGB24
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#define LZ_RGB32
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#define LZ_RGB_ALPHA
|
|
#include "glz_decode_tmpl.c"
|
|
|
|
#undef LZ_UNEXPECT_CONDITIONAL
|
|
#undef LZ_EXPECT_CONDITIONAL
|
|
|
|
typedef size_t (*decode_function)(GlzDecoderWindow &window, uint8_t* in_buf,
|
|
uint8_t *out_buf, int size,
|
|
DecodedImageWinId image_win_id, Palette *plt,
|
|
GlzDecoderDebug &debug_calls);
|
|
|
|
// ordered according to LZ_IMAGE_TYPE
|
|
const decode_function DECODE_TO_RGB32[] = {
|
|
NULL,
|
|
glz_plt1_le_to_rgb32_decode,
|
|
glz_plt1_be_to_rgb32_decode,
|
|
glz_plt4_le_to_rgb32_decode,
|
|
glz_plt4_be_to_rgb32_decode,
|
|
glz_plt8_to_rgb32_decode,
|
|
glz_rgb16_to_rgb32_decode,
|
|
glz_rgb32_decode,
|
|
glz_rgb32_decode,
|
|
glz_rgb32_decode
|
|
};
|
|
|
|
const decode_function DECODE_TO_SAME[] = {
|
|
NULL,
|
|
glz_plt_decode,
|
|
glz_plt_decode,
|
|
glz_plt_decode,
|
|
glz_plt_decode,
|
|
glz_plt_decode,
|
|
glz_rgb16_decode,
|
|
glz_rgb24_decode,
|
|
glz_rgb32_decode,
|
|
glz_rgb32_decode
|
|
};
|
|
|
|
void GlzDecoder::decode(uint8_t *data, Palette *palette, void *opaque_usr_info)
|
|
{
|
|
int out_size;
|
|
DecodedImageWinId image_window_id;
|
|
GlzDecodedImage *decoded_image;
|
|
size_t n_in_bytes_decoded;
|
|
int bytes_per_pixel;
|
|
LzImageType decoded_type;
|
|
|
|
_in_start = data;
|
|
_in_now = data;
|
|
|
|
decode_header();
|
|
|
|
#ifdef GLZ_DECODE_TO_RGB32
|
|
out_size = _image.gross_pixels << 2;
|
|
bytes_per_pixel = 4;
|
|
|
|
if (_image.type == LZ_IMAGE_TYPE_RGBA) {
|
|
decoded_type = LZ_IMAGE_TYPE_RGBA;
|
|
} else {
|
|
decoded_type = LZ_IMAGE_TYPE_RGB32;
|
|
}
|
|
|
|
#else
|
|
if (IS_IMAGE_TYPE_PLT[_image.type]) {
|
|
GLZ_ASSERT(_debug_calls, !(_image.gross_pixels % PLT_PIXELS_PER_BYTE[_image.type]));
|
|
out_size = _image.gross_pixels / PLT_PIXELS_PER_BYTE[_image.type];
|
|
} else {
|
|
out_size = _image.gross_pixels * RGB_BYTES_PER_PIXEL[_image.type];
|
|
}
|
|
bytes_per_pixel = RGB_BYTES_PER_PIXEL[_image.type];
|
|
decoded_type = _image.type;
|
|
#endif
|
|
|
|
|
|
image_window_id = _images_window.pre_decode(_image.id, _image.id - _image.win_head_dist);
|
|
|
|
decoded_image = _usr_handler.alloc_image(opaque_usr_info, _image.id,
|
|
_image.id - _image.win_head_dist,
|
|
decoded_type, _image.width, _image.height,
|
|
_image.gross_pixels, bytes_per_pixel,
|
|
_image.top_down);
|
|
|
|
_image.data = decoded_image->get_data();
|
|
|
|
// decode_by_type
|
|
#ifdef GLZ_DECODE_TO_RGB32
|
|
n_in_bytes_decoded = DECODE_TO_RGB32[_image.type](_images_window, _in_now, _image.data,
|
|
_image.gross_pixels, image_window_id,
|
|
palette, _debug_calls);
|
|
#else
|
|
n_in_bytes_decoded = DECODE_TO_SAME[_image.type](_images_window, _in_now, _image.data,
|
|
IS_IMAGE_TYPE_PLT[_image.type] ?
|
|
_image.gross_pixels /
|
|
PLT_PIXELS_PER_BYTE[_image.type] :
|
|
_image.gross_pixels,
|
|
image_window_id, palette, _debug_calls);
|
|
#endif
|
|
|
|
_in_now += n_in_bytes_decoded;
|
|
|
|
if (_image.type == LZ_IMAGE_TYPE_RGBA) {
|
|
glz_rgb_alpha_decode(_images_window, _in_now, _image.data,
|
|
_image.gross_pixels, image_window_id, palette, _debug_calls);
|
|
}
|
|
|
|
_images_window.post_decode(decoded_image);
|
|
}
|
|
|