Use the spice-common submodule

This patch will replace the common/ directory with the spice-common
project. It is for now a simple project subdirectory shared with
spice-gtk, but the goal is to make it a proper library later on.

With this change, the spice-server build is broken. The following
commits fix the build, and have been seperated to ease the review.

v2
- moves all the generated marshallers to spice-common library
- don't attempt to fix windows VS build, which should somehow be
  splitted with spice-common (or built from tarball only to avoid
  generation tools/libs deps)
v3
- uses libspice-common-client
- fix a mutex.h inclusion reported by Alon
This commit is contained in:
Marc-André Lureau 2012-03-21 14:42:35 +01:00
parent 4df135c858
commit 359fc1cb5d
126 changed files with 255 additions and 27876 deletions

6
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "spice-protocol"]
path = spice-protocol
url = ../spice-protocol
[submodule "spice-common"]
path = spice-common
url = ../spice-common

View File

@ -1,7 +1,7 @@
NULL =
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = common server python_modules
DIST_SUBDIRS = spice-protocol $(SUBDIRS)
SUBDIRS = spice-common server
if SUPPORT_CLIENT
SUBDIRS += client
@ -10,9 +10,11 @@ endif
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = spice-server.pc
DISTCLEANFILES = \
spice-server.pc
EXTRA_DIST = spice.proto spice1.proto spice_codegen.py
DISTCHECK_CONFIGURE_FLAGS=--enable-opengl --enable-gui --enable-tunnel --enable-smartcard --with-sasl --enable-automated-tests
DISTCHECK_CONFIGURE_FLAGS = \
--enable-automated-tests \
--enable-gui \
--enable-opengl \
--enable-smartcard \
--enable-tunnel \
--with-sasl \
$(NULL)

View File

@ -8,8 +8,7 @@ test -z "$srcdir" && srcdir=.
olddir=`pwd`
cd "$srcdir"
git submodule init
git submodule update
git submodule update --init --recursive
mkdir -p m4
autoreconf --verbose --force --install

View File

@ -2,27 +2,6 @@ NULL =
bin_PROGRAMS = spicec
BUILT_SOURCES = \
generated_demarshallers.cpp \
generated_marshallers.cpp \
generated_demarshallers1.cpp \
generated_marshallers1.cpp \
$(NULL)
generated_demarshallers.cpp: $(top_srcdir)/spice.proto
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h --include messages.h $(top_srcdir)/spice.proto generated_demarshallers.cpp
generated_demarshallers1.cpp: $(top_srcdir)/spice1.proto
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h --include messages.h --prefix 1 --ptrsize 8 $(top_srcdir)/spice1.proto generated_demarshallers1.cpp
generated_marshallers.cpp: $(top_srcdir)/spice.proto
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P --include "common.h" --include messages.h --include marshallers.h --client $(top_srcdir)/spice.proto generated_marshallers.cpp
generated_marshallers1.cpp: $(top_srcdir)/spice1.proto
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P --include "common.h" --include messages.h --include marshallers.h --client --prefix 1 --ptrsize 8 $(top_srcdir)/spice1.proto generated_marshallers1.cpp
MAINTAINERCLEANFILES = $(BUILT_SOURCES)
spicec_SOURCES = \
application.cpp \
application.h \
@ -43,7 +22,6 @@ spicec_SOURCES = \
cursor_channel.cpp \
cursor_channel.h \
debug.h \
demarshallers.h \
display_channel.cpp \
display_channel.h \
event_sources.h \
@ -63,7 +41,6 @@ spicec_SOURCES = \
inputs_handler.h \
jpeg_decoder.cpp \
jpeg_decoder.h \
marshallers.h \
menu.cpp \
menu.h \
mjpeg_decoder.cpp \
@ -230,7 +207,7 @@ INCLUDES = \
$(GL_CFLAGS) \
$(MISC_X_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(PROTOCOL_CFLAGS) \
$(COMMON_CFLAGS) \
$(SPICE_NONPKGCONFIG_CFLAGS) \
$(SMARTCARD_CFLAGS) \
$(SSL_CFLAGS) \
@ -243,24 +220,25 @@ INCLUDES = \
spicec_LDFLAGS = $(SPICEC_STATIC_LINKAGE_BSTATIC)
spicec_LDADD = \
$(top_builddir)/common/libspice-common.la \
$(ALSA_LIBS) \
$(CEGUI_LIBS) \
$(CEGUI06_LIBS) \
$(CELT051_LIBS) \
$(GL_LIBS) \
$(JPEG_LIBS) \
$(MISC_X_LIBS) \
$(PIXMAN_LIBS) \
$(SMARTCARD_LIBS) \
$(SPICE_NONPKGCONFIG_LIBS) \
$(SSL_LIBS) \
$(XFIXES_LIBS) \
$(XRANDR_LIBS) \
$(Z_LIBS) \
$(XINERAMA_LIBS) \
$(spicec_resource_LDADD) \
spicec_LDADD = \
$(top_builddir)/spice-common/common/libspice-common.la \
$(top_builddir)/spice-common/common/libspice-common-client.la \
$(ALSA_LIBS) \
$(CEGUI_LIBS) \
$(CEGUI06_LIBS) \
$(CELT051_LIBS) \
$(GL_LIBS) \
$(JPEG_LIBS) \
$(MISC_X_LIBS) \
$(PIXMAN_LIBS) \
$(SMARTCARD_LIBS) \
$(SPICE_NONPKGCONFIG_LIBS) \
$(SSL_LIBS) \
$(XFIXES_LIBS) \
$(XRANDR_LIBS) \
$(Z_LIBS) \
$(XINERAMA_LIBS) \
$(spicec_resource_LDADD) \
$(NULL)
EXTRA_DIST = \

View File

@ -23,6 +23,10 @@
#include <io.h>
#endif
#include "common/quic.h"
#include "common/mutex.h"
#include "common/rect.h"
#include "application.h"
#include "screen.h"
#include "utils.h"
@ -38,13 +42,10 @@
#ifdef USE_OPENGL
#include "red_gl_canvas.h"
#endif
#include "quic.h"
#include "mutex.h"
#include "cmd_line_parser.h"
#ifdef USE_TUNNEL
#include "tunnel_channel.h"
#endif
#include "rect.h"
#ifdef USE_GUI
#include "gui/gui.h"
#endif

View File

@ -19,18 +19,20 @@
#ifndef _H_CANVAS
#define _H_CANVAS
#include <map>
#include "common/region.h"
#include "common/messages.h"
#include "common/canvas_utils.h"
#include "common.h"
#include "debug.h"
#include "region.h"
#include "messages.h"
#include "cache.hpp"
#include "shared_cache.hpp"
#include "canvas_utils.h"
#include "glz_decoded_image.h"
#include "glz_decoder.h"
#include "jpeg_decoder.h"
#include "zlib_decoder.h"
#include <map>
enum CanvasType {
CANVAS_TYPE_INVALID,

View File

@ -18,8 +18,8 @@
#ifndef _H_CURSOR_
#define _H_CURSOR_
#include "common/messages.h"
#include "threads.h"
#include "messages.h"
#include "red_window_p.h"
class CursorOpaque {

View File

@ -18,6 +18,8 @@
#include <config.h>
#endif
#include "common/rect.h"
#include "common.h"
#include "cursor_channel.h"
#include "display_channel.h"
@ -28,7 +30,6 @@
#include "utils.h"
#include "screen.h"
#include "red_pixmap_sw.h"
#include "rect.h"
static inline uint8_t revers_bits(uint8_t byte)
{

View File

@ -1,27 +0,0 @@
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_DEMARSHAL
#define _H_DEMARSHAL
typedef void (*message_destructor_t)(uint8_t *message);
typedef uint8_t * (*spice_parse_channel_func_t)(uint8_t *message_start, uint8_t *message_end, uint16_t message_type, int minor,
size_t *size_out, message_destructor_t *free_message);
spice_parse_channel_func_t spice_get_server_channel_parser(uint32_t channel, unsigned int *max_message_type);
spice_parse_channel_func_t spice_get_server_channel_parser1(uint32_t channel, unsigned int *max_message_type);
#endif

View File

@ -20,7 +20,6 @@
#endif
#include "common.h"
#include "canvas.h"
#include "red_pixmap.h"
#ifdef USE_OPENGL
#include "red_pixmap_gl.h"

View File

@ -19,9 +19,10 @@
#ifndef _H_DISPLAY_CHANNEL
#define _H_DISPLAY_CHANNEL
#include "common/region.h"
#include "common.h"
#include "canvas.h"
#include "region.h"
#include "red_channel.h"
#include "cache.hpp"
#include "screen_layer.h"

View File

@ -19,7 +19,7 @@
#ifndef _H_GLZ_DECODER
#define _H_GLZ_DECODER
#include "lz_common.h"
#include "common/lz_common.h"
#include "glz_decoder_config.h"
#include "glz_decoder_window.h"
#include "red_canvas_base.h"

View File

@ -20,13 +20,11 @@
#include <exception>
#include <sstream>
#include "lz_common.h"
#include <stdio.h>
#include <spice/types.h>
#include <spice/macros.h>
#include "common/lz_common.h"
class GlzException: public std::exception {
public:

View File

@ -30,6 +30,11 @@
extern "C" {
#include <jpeglib.h>
#ifdef HAVE_STDLIB_H
/* on mingw, there is a hack,
and we also include config.h from spice-common, which redefine it */
#undef HAVE_STDLIB_H
#endif
}
class RGBConverter {

View File

@ -1,63 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MARSHALLERS
#define _H_MARSHALLERS
#include <spice/protocol.h>
#include <marshaller.h>
#include <messages.h>
typedef struct {
void (*msg_SpiceMsgEmpty)(SpiceMarshaller *m, SpiceMsgEmpty *msg);
void (*msg_SpiceMsgData)(SpiceMarshaller *m, SpiceMsgData *msg);
void (*msg_SpiceMsgAudioVolume)(SpiceMarshaller *m, SpiceMsgAudioVolume *msg);
void (*msg_SpiceMsgAudioMute)(SpiceMarshaller *m, SpiceMsgAudioMute *msg);
void (*msgc_ack_sync)(SpiceMarshaller *m, SpiceMsgcAckSync *msg);
void (*msgc_pong)(SpiceMarshaller *m, SpiceMsgPing *msg);
void (*msgc_disconnecting)(SpiceMarshaller *m, SpiceMsgDisconnect *msg);
void (*msgc_main_client_info)(SpiceMarshaller *m, SpiceMsgcClientInfo *msg);
void (*msgc_main_mouse_mode_request)(SpiceMarshaller *m, SpiceMsgcMainMouseModeRequest *msg);
void (*msgc_main_agent_start)(SpiceMarshaller *m, SpiceMsgcMainAgentStart *msg);
void (*msgc_main_agent_token)(SpiceMarshaller *m, SpiceMsgcMainAgentTokens *msg);
void (*msgc_display_init)(SpiceMarshaller *m, SpiceMsgcDisplayInit *msg);
void (*msgc_inputs_key_down)(SpiceMarshaller *m, SpiceMsgcKeyDown *msg);
void (*msgc_inputs_key_up)(SpiceMarshaller *m, SpiceMsgcKeyUp *msg);
void (*msgc_inputs_key_modifiers)(SpiceMarshaller *m, SpiceMsgcKeyModifiers *msg);
void (*msgc_inputs_mouse_motion)(SpiceMarshaller *m, SpiceMsgcMouseMotion *msg);
void (*msgc_inputs_mouse_position)(SpiceMarshaller *m, SpiceMsgcMousePosition *msg);
void (*msgc_inputs_mouse_press)(SpiceMarshaller *m, SpiceMsgcMousePress *msg);
void (*msgc_inputs_mouse_release)(SpiceMarshaller *m, SpiceMsgcMouseRelease *msg);
void (*msgc_record_data)(SpiceMarshaller *m, SpiceMsgcRecordPacket *msg);
void (*msgc_record_mode)(SpiceMarshaller *m, SpiceMsgcRecordMode *msg);
void (*msgc_record_start_mark)(SpiceMarshaller *m, SpiceMsgcRecordStartMark *msg);
void (*msgc_tunnel_service_add)(SpiceMarshaller *m, SpiceMsgcTunnelAddGenericService *msg, SpiceMarshaller **name_out, SpiceMarshaller **description_out);
void (*msgc_tunnel_service_remove)(SpiceMarshaller *m, SpiceMsgcTunnelRemoveService *msg);
void (*msgc_tunnel_socket_open_ack)(SpiceMarshaller *m, SpiceMsgcTunnelSocketOpenAck *msg);
void (*msgc_tunnel_socket_open_nack)(SpiceMarshaller *m, SpiceMsgcTunnelSocketOpenNack *msg);
void (*msgc_tunnel_socket_fin)(SpiceMarshaller *m, SpiceMsgcTunnelSocketFin *msg);
void (*msgc_tunnel_socket_closed)(SpiceMarshaller *m, SpiceMsgcTunnelSocketClosed *msg);
void (*msgc_tunnel_socket_closed_ack)(SpiceMarshaller *m, SpiceMsgcTunnelSocketClosedAck *msg);
void (*msgc_tunnel_socket_data)(SpiceMarshaller *m, SpiceMsgcTunnelSocketData *msg);
void (*msgc_tunnel_socket_token)(SpiceMarshaller *m, SpiceMsgcTunnelSocketTokens *msg);
} SpiceMessageMarshallers;
SpiceMessageMarshallers *spice_message_marshallers_get(void);
SpiceMessageMarshallers *spice_message_marshallers_get1(void);
#endif

View File

@ -18,7 +18,7 @@
#ifndef _H_MONITOR
#define _H_MONITOR
#include "draw.h"
#include "common/draw.h"
class Monitor {
public:

View File

@ -18,7 +18,7 @@
#ifndef _H_PIXELS_SOURCE
#define _H_PIXELS_SOURCE
#include "draw.h"
#include "common/draw.h"
#define PIXELES_SOURCE_OPAQUE_SIZE (20 * sizeof(void*))

View File

@ -19,7 +19,7 @@
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "canvas_base.h"
#include "common/canvas_base.h"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL

View File

@ -18,14 +18,15 @@
#ifndef _H_REDCHANNEL
#define _H_REDCHANNEL
#include "common/client_demarshallers.h"
#include "common/client_marshallers.h"
#include "common.h"
#include "utils.h"
#include "threads.h"
#include "red_peer.h"
#include "platform.h"
#include "process_loop.h"
#include "demarshallers.h"
#include "marshallers.h"
enum {
PASSIVE_STATE,

View File

@ -18,15 +18,16 @@
#include <config.h>
#endif
#include "common.h"
#include <algorithm>
#include <math.h>
#include "common/client_marshallers.h"
#include "common.h"
#include "red_client.h"
#include "application.h"
#include "process_loop.h"
#include "utils.h"
#include "debug.h"
#include "marshallers.h"
#include <algorithm>
#ifndef INFINITY
#define INFINITY HUGE

View File

@ -19,6 +19,7 @@
#define _H_REDCLIENT
#include <list>
#include "common/messages.h"
#include "common.h"
#include "red_peer.h"
@ -27,7 +28,6 @@
#include "inputs_channel.h"
#include "cursor_channel.h"
#include "audio_channels.h"
#include "messages.h"
#include <spice/vd_agent.h>
#include "process_loop.h"

View File

@ -18,7 +18,7 @@
#ifndef _H_RED_DRAWABLE
#define _H_RED_DRAWABLE
#include <pixman_utils.h>
#include "common/pixman_utils.h"
#include "pixels_source.h"
#include "utils.h"

View File

@ -21,20 +21,24 @@
#include <config.h>
#endif
#include "common.h"
#ifdef WIN32
#include <winsock2.h>
#endif
#include <stdint.h>
#include "common/region.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/gdi_canvas.c"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "common.h"
#include "red_gdi_canvas.h"
#include "utils.h"
#include "debug.h"
#include "region.h"
#include "red_pixmap_gdi.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "gdi_canvas.c"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
GDICanvas::GDICanvas(int width, int height, uint32_t format,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache &csurfaces)

View File

@ -21,7 +21,7 @@
#include "canvas.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "gdi_canvas.h"
#include "common/gdi_canvas.h"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "red_pixmap_gdi.h"

View File

@ -18,21 +18,22 @@
#include <config.h>
#endif
#include "common.h"
#include <stdint.h>
#include "red_gl_canvas.h"
#include "utils.h"
#include "debug.h"
#include "region.h"
#include "red_pixmap_gl.h"
#include <GL/glx.h>
#include "common/region.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "gl_canvas.c"
#include "common/gl_canvas.c"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "common.h"
#include "red_gl_canvas.h"
#include "utils.h"
#include "debug.h"
#include "red_pixmap_gl.h"
GCanvas::GCanvas(int width, int height, uint32_t format, RedWindow *win,
RenderType rendertype,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,

View File

@ -21,8 +21,8 @@
#include "canvas.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "sw_canvas.h"
#include "gl_canvas.h"
#include "common/sw_canvas.h"
#include "common/gl_canvas.h"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL

View File

@ -19,15 +19,19 @@
#include <config.h>
#endif
#include "common.h"
#ifdef WIN32
#include <winsock2.h>
#endif
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <spice/protocol.h>
#include "common/ssl_verify.h"
#include "common.h"
#include "red_peer.h"
#include "utils.h"
#include "debug.h"
#include "platform_utils.h"
#include "ssl_verify.h"
static void ssl_error()
{

View File

@ -21,14 +21,15 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "common.h"
#include <spice/protocol.h>
#include "common/marshaller.h"
#include "common/ssl_verify.h"
#include "common.h"
#include "process_loop.h"
#include "threads.h"
#include "platform_utils.h"
#include "marshaller.h"
#include "debug.h"
#include "ssl_verify.h"
class RedPeer: protected EventSources::Socket {
public:

View File

@ -19,21 +19,25 @@
#include <config.h>
#endif
#include "common.h"
#include <stdint.h>
#ifdef WIN32
#include <winsock2.h>
#endif
#include "common/region.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/sw_canvas.c"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "common.h"
#include "red_window.h"
#include "red_sw_canvas.h"
#include "utils.h"
#include "debug.h"
#include "region.h"
#include "red_pixmap_sw.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "sw_canvas.c"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
SCanvas::SCanvas(bool onscreen,
int width, int height, uint32_t format, RedWindow *win,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,

View File

@ -22,7 +22,7 @@
#include "canvas.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "sw_canvas.h"
#include "common/sw_canvas.h"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL

View File

@ -18,8 +18,9 @@
#ifndef _H_SCREEN
#define _H_SCREEN
#include "common/region.h"
#include "common.h"
#include "region.h"
#include "red_key.h"
#ifdef USE_OPENGL
#include "GL/gl.h"

View File

@ -18,8 +18,8 @@
#ifndef _H_SCREEN_LAYER
#define _H_SCREEN_LAYER
#include "common/region.h"
#include "threads.h"
#include "region.h"
class RedScreen;
class Application;

View File

@ -19,9 +19,9 @@
#endif
#include <spice/enums.h>
#include "common/mutex.h"
#include "red_client.h"
#include "mutex.h"
extern "C" {
#include <vscard_common.h>

View File

@ -29,7 +29,8 @@
#ifdef USE_OPENGL
#include "red_pixmap_gl.h"
#endif // USE_OPENGL
#include "pixman_utils.h"
#include "common/pixman_utils.h"
enum {
PIXELS_SOURCE_TYPE_INVALID,

View File

@ -48,20 +48,21 @@
#include <sys/time.h>
#endif
#include <spice/vd_agent.h>
#include "common/rect.h"
#include "platform.h"
#include "application.h"
#include "utils.h"
#include "x_platform.h"
#include "debug.h"
#include "monitor.h"
#include "rect.h"
#include "record.h"
#include "playback.h"
#include "resource.h"
#include "res.h"
#include "cursor.h"
#include "process_loop.h"
#include <spice/vd_agent.h>
#define DWORD uint32_t
#define BOOL bool

View File

@ -26,7 +26,7 @@
#include "utils.h"
#ifdef USE_OPENGL
#include "gl_utils.h"
#include "common/gl_utils.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>

View File

@ -22,12 +22,12 @@
#include <GL/glu.h>
#include <GL/glext.h>
#include <X11/Xlib.h>
#include "common/gl_utils.h"
#include "common.h"
#include "red_pixmap_gl.h"
#include "debug.h"
#include "utils.h"
#include "gl_utils.h"
#include "pixels_source_p.h"
#include "x_platform.h"
#include "red_window_p.h"

View File

@ -33,21 +33,22 @@
#endif // USE_OPENGL
#include <stdio.h>
#include <spice/protocol.h>
#include "common/region.h"
#ifdef USE_OPENGL
#include "common/gl_utils.h"
#include "red_pixmap_gl.h"
#endif // USE_OPENGL
#include "red_window.h"
#include "utils.h"
#include "debug.h"
#include "platform.h"
#include "x_platform.h"
#include "pixels_source_p.h"
#include <spice/protocol.h>
#include "region.h"
#ifdef USE_OPENGL
#include "gl_utils.h"
#include "red_pixmap_gl.h"
#endif // USE_OPENGL
#include "x_icon.h"
#define X_RETRIES 10
#define X_RETRY_DELAY_MICRO (1000 * 100)
#define RAISE_RETRIES X_RETRIES

9
common/.gitignore vendored
View File

@ -1,9 +0,0 @@
*.la
*.lo
*.loT
*.o
.deps
.dirstamp
.libs
Makefile
Makefile.in

View File

@ -1,76 +0,0 @@
if OS_WIN32
SUBDIRS = win
endif
NULL =
noinst_LTLIBRARIES = libspice-common.la
libspice_common_la_SOURCES = \
bitops.h \
canvas_utils.c \
canvas_utils.h \
draw.h \
lines.c \
lines.h \
lz.c \
lz.h \
lz_common.h \
lz_config.h \
marshaller.c \
marshaller.h \
mem.c \
mem.h \
messages.h \
mutex.h \
pixman_utils.c \
pixman_utils.h \
quic.c \
quic.h \
quic_config.h \
rect.h \
region.c \
region.h \
ring.h \
rop3.c \
rop3.h \
spice_common.h \
ssl_verify.c \
ssl_verify.h \
backtrace.c \
backtrace.h \
$(NULL)
if SUPPORT_GL
libspice_common_la_SOURCES += \
gl_utils.h \
glc.h \
glc.c \
ogl_ctx.h \
ogl_ctx.c \
$(NULL)
endif
INCLUDES = \
$(GL_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(PROTOCOL_CFLAGS) \
$(VISIBILITY_HIDDEN_CFLAGS) \
$(WARN_CFLAGS) \
-std=gnu99 \
$(NULL)
EXTRA_DIST = \
canvas_base.c \
canvas_base.h \
gdi_canvas.c \
gdi_canvas.h \
gl_canvas.c \
gl_canvas.h \
sw_canvas.c \
sw_canvas.h \
lz_compress_tmpl.c \
lz_decompress_tmpl.c \
quic_family_tmpl.c \
quic_rgb_tmpl.c \
quic_tmpl.c \
$(NULL)

View File

@ -1,133 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2011 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Taken from xserver os/backtrace.c:
* Copyright (C) 2008 Red Hat, Inc.
*/
#include <config.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#ifndef __MINGW32__
#include <sys/wait.h>
#endif
#include "spice_common.h"
#define GSTACK_PATH "/usr/bin/gstack"
#if HAVE_EXECINFO_H
#include <execinfo.h>
static void spice_backtrace_backtrace(void)
{
void *array[100];
int size;
size = backtrace(array, sizeof(array)/sizeof(array[0]));
backtrace_symbols_fd(array, size, STDERR_FILENO);
}
#else
static void spice_backtrace_backtrace(void)
{
}
#endif
/* XXX perhaps gstack can be available in windows but pipe/waitpid isn't,
* so until it is ported properly just compile it out, we lose the
* backtrace only. */
#ifndef __MINGW32__
static int spice_backtrace_gstack(void)
{
pid_t kidpid;
int pipefd[2];
if (pipe(pipefd) != 0) {
return -1;
}
kidpid = fork();
if (kidpid == -1) {
/* ERROR */
return -1;
} else if (kidpid == 0) {
/* CHILD */
char parent[16];
seteuid(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
dup2(pipefd[1],STDOUT_FILENO);
close(STDERR_FILENO);
snprintf(parent, sizeof(parent), "%d", getppid());
execle(GSTACK_PATH, "gstack", parent, NULL, NULL);
exit(1);
} else {
/* PARENT */
char btline[256];
int kidstat;
int bytesread;
int done = 0;
close(pipefd[1]);
while (!done) {
bytesread = read(pipefd[0], btline, sizeof(btline) - 1);
if (bytesread > 0) {
btline[bytesread] = 0;
fprintf(stderr, "%s", btline);
}
else if ((bytesread == 0) ||
((errno != EINTR) && (errno != EAGAIN))) {
done = 1;
}
}
close(pipefd[0]);
waitpid(kidpid, &kidstat, 0);
if (kidstat != 0)
return -1;
}
return 0;
}
#else
static int spice_backtrace_gstack(void)
{
/* empty failing implementation */
return -1;
}
#endif
void spice_backtrace(void)
{
int ret = -1;
if (!access(GSTACK_PATH, X_OK)) {
ret = spice_backtrace_gstack();
}
if (ret != 0) {
spice_backtrace_backtrace();
}
}

View File

@ -1,34 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2011 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BACKTRACE_H
#define BACKTRACE_H
#include <spice/macros.h>
SPICE_BEGIN_DECLS
#if defined(WIN32) && !defined(__MINGW32__)
#define spice_backtrace()
#else
void spice_backtrace(void);
#endif
SPICE_END_DECLS
#endif // BACKTRACE_H

View File

@ -1,91 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef BITOPS_H
#define BITOPS_H
#include <spice/macros.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
static inline int spice_bit_find_msb(unsigned int val)
{
int ret;
asm ("bsrl %1,%0\n\t"
"jnz 1f\n\t"
"movl $-1,%0\n"
"1:"
: "=r"(ret) : "r"(val));
return ret + 1;
}
#elif defined(WIN32) && !defined(_WIN64)
static INLINE int spice_bit_find_msb(uint32_t val)
{
uint32_t r;
__asm {
bsr eax, val
jnz found
mov eax, -1
found:
mov r, eax
}
return r + 1;
}
#else
static INLINE int spice_bit_find_msb(unsigned int val)
{
signed char index = 31;
if(val == 0) {
return 0;
}
do {
if(val & 0x80000000) {
break;
}
val <<= 1;
} while(--index >= 0);
return index+1;
}
#endif
static INLINE int spice_bit_next_pow2(unsigned int val)
{
if ((val & (val - 1)) == 0) {
return val;
}
return 1 << spice_bit_find_msb(val);
}
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,327 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CANVAS_BASE
#define _H_CANVAS_BASE
#ifndef SPICE_CANVAS_INTERNAL
#error "This header shouldn't be included directly"
#endif
#include "pixman_utils.h"
#include "lz.h"
#include "region.h"
#include "draw.h"
#ifdef WIN32
#include <windows.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*spice_destroy_fn_t)(void *data);
typedef struct _SpiceImageCache SpiceImageCache;
typedef struct _SpiceImageSurfaces SpiceImageSurfaces;
typedef struct _SpicePaletteCache SpicePaletteCache;
typedef struct _SpiceGlzDecoder SpiceGlzDecoder;
typedef struct _SpiceJpegDecoder SpiceJpegDecoder;
typedef struct _SpiceZlibDecoder SpiceZlibDecoder;
typedef struct _SpiceCanvas SpiceCanvas;
typedef struct {
void (*put)(SpiceImageCache *cache,
uint64_t id,
pixman_image_t *surface);
pixman_image_t *(*get)(SpiceImageCache *cache,
uint64_t id);
#ifdef SW_CANVAS_CACHE
void (*put_lossy)(SpiceImageCache *cache,
uint64_t id,
pixman_image_t *surface);
void (*replace_lossy)(SpiceImageCache *cache,
uint64_t id,
pixman_image_t *surface);
pixman_image_t *(*get_lossless)(SpiceImageCache *cache,
uint64_t id);
#endif
} SpiceImageCacheOps;
struct _SpiceImageCache {
SpiceImageCacheOps *ops;
};
typedef struct {
SpiceCanvas *(*get)(SpiceImageSurfaces *surfaces,
uint32_t surface_id);
} SpiceImageSurfacesOps;
struct _SpiceImageSurfaces {
SpiceImageSurfacesOps *ops;
};
typedef struct {
void (*put)(SpicePaletteCache *cache,
SpicePalette *palette);
SpicePalette *(*get)(SpicePaletteCache *cache,
uint64_t id);
void (*release)(SpicePaletteCache *cache,
SpicePalette *palette);
} SpicePaletteCacheOps;
struct _SpicePaletteCache {
SpicePaletteCacheOps *ops;
};
typedef struct {
void (*decode)(SpiceGlzDecoder *decoder,
uint8_t *data,
SpicePalette *plt,
void *usr_data);
} SpiceGlzDecoderOps;
struct _SpiceGlzDecoder {
SpiceGlzDecoderOps *ops;
};
typedef struct SpiceJpegDecoderOps {
void (*begin_decode)(SpiceJpegDecoder *decoder,
uint8_t* data,
int data_size,
int* out_width,
int* out_height);
void (*decode)(SpiceJpegDecoder *decoder,
uint8_t* dest,
int stride,
int format);
} SpiceJpegDecoderOps;
struct _SpiceJpegDecoder {
SpiceJpegDecoderOps *ops;
};
typedef struct {
void (*decode)(SpiceZlibDecoder *decoder,
uint8_t *data,
int data_size,
uint8_t *dest,
int dest_size);
} SpiceZlibDecoderOps;
struct _SpiceZlibDecoder {
SpiceZlibDecoderOps *ops;
};
typedef struct {
void (*draw_fill)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill);
void (*draw_copy)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy);
void (*draw_opaque)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque);
void (*copy_bits)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos);
void (*draw_text)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text);
void (*draw_stroke)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke);
void (*draw_rop3)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3);
void (*draw_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend);
void (*draw_blackness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness);
void (*draw_whiteness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness);
void (*draw_invers)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers);
void (*draw_transparent)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent);
void (*draw_alpha_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend* alpha_blend);
void (*put_image)(SpiceCanvas *canvas,
#ifdef WIN32
HDC dc,
#endif
const SpiceRect *dest, const uint8_t *src_data,
uint32_t src_width, uint32_t src_height, int src_stride,
const QRegion *clip);
void (*clear)(SpiceCanvas *canvas);
void (*read_bits)(SpiceCanvas *canvas, uint8_t *dest, int dest_stride, const SpiceRect *area);
void (*group_start)(SpiceCanvas *canvas, QRegion *region);
void (*group_end)(SpiceCanvas *canvas);
void (*destroy)(SpiceCanvas *canvas);
/* Implementation vfuncs */
void (*fill_solid_spans)(SpiceCanvas *canvas,
SpicePoint *points,
int *widths,
int n_spans,
uint32_t color);
void (*fill_solid_rects)(SpiceCanvas *canvas,
pixman_box32_t *rects,
int n_rects,
uint32_t color);
void (*fill_solid_rects_rop)(SpiceCanvas *canvas,
pixman_box32_t *rects,
int n_rects,
uint32_t color,
SpiceROP rop);
void (*fill_tiled_rects)(SpiceCanvas *canvas,
pixman_box32_t *rects,
int n_rects,
pixman_image_t *tile,
int offset_x, int offset_y);
void (*fill_tiled_rects_from_surface)(SpiceCanvas *canvas,
pixman_box32_t *rects,
int n_rects,
SpiceCanvas *tile,
int offset_x, int offset_y);
void (*fill_tiled_rects_rop)(SpiceCanvas *canvas,
pixman_box32_t *rects,
int n_rects,
pixman_image_t *tile,
int offset_x, int offset_y,
SpiceROP rop);
void (*fill_tiled_rects_rop_from_surface)(SpiceCanvas *canvas,
pixman_box32_t *rects,
int n_rects,
SpiceCanvas *tile,
int offset_x, int offset_y,
SpiceROP rop);
void (*blit_image)(SpiceCanvas *canvas,
pixman_region32_t *region,
pixman_image_t *src_image,
int offset_x, int offset_y);
void (*blit_image_from_surface)(SpiceCanvas *canvas,
pixman_region32_t *region,
SpiceCanvas *src_image,
int offset_x, int offset_y);
void (*blit_image_rop)(SpiceCanvas *canvas,
pixman_region32_t *region,
pixman_image_t *src_image,
int offset_x, int offset_y,
SpiceROP rop);
void (*blit_image_rop_from_surface)(SpiceCanvas *canvas,
pixman_region32_t *region,
SpiceCanvas *src_image,
int offset_x, int offset_y,
SpiceROP rop);
void (*scale_image)(SpiceCanvas *canvas,
pixman_region32_t *region,
pixman_image_t *src_image,
int src_x, int src_y,
int src_width, int src_height,
int dest_x, int dest_y,
int dest_width, int dest_height,
int scale_mode);
void (*scale_image_from_surface)(SpiceCanvas *canvas,
pixman_region32_t *region,
SpiceCanvas *src_image,
int src_x, int src_y,
int src_width, int src_height,
int dest_x, int dest_y,
int dest_width, int dest_height,
int scale_mode);
void (*scale_image_rop)(SpiceCanvas *canvas,
pixman_region32_t *region,
pixman_image_t *src_image,
int src_x, int src_y,
int src_width, int src_height,
int dest_x, int dest_y,
int dest_width, int dest_height,
int scale_mode, SpiceROP rop);
void (*scale_image_rop_from_surface)(SpiceCanvas *canvas,
pixman_region32_t *region,
SpiceCanvas *src_image,
int src_x, int src_y,
int src_width, int src_height,
int dest_x, int dest_y,
int dest_width, int dest_height,
int scale_mode, SpiceROP rop);
void (*blend_image)(SpiceCanvas *canvas,
pixman_region32_t *region,
int dest_has_alpha,
pixman_image_t *src_image,
int src_x, int src_y,
int dest_x, int dest_y,
int width, int height,
int overall_alpha);
void (*blend_image_from_surface)(SpiceCanvas *canvas,
pixman_region32_t *region,
int dest_has_alpha,
SpiceCanvas *src_image,
int src_has_alpha,
int src_x, int src_y,
int dest_x, int dest_y,
int width, int height,
int overall_alpha);
void (*blend_scale_image)(SpiceCanvas *canvas,
pixman_region32_t *region,
int dest_has_alpha,
pixman_image_t *src_image,
int src_x, int src_y,
int src_width, int src_height,
int dest_x, int dest_y,
int dest_width, int dest_height,
int scale_mode,
int overall_alpha);
void (*blend_scale_image_from_surface)(SpiceCanvas *canvas,
pixman_region32_t *region,
int dest_has_alpha,
SpiceCanvas *src_image,
int src_has_alpha,
int src_x, int src_y,
int src_width, int src_height,
int dest_x, int dest_y,
int dest_width, int dest_height,
int scale_mode,
int overall_alpha);
void (*colorkey_image)(SpiceCanvas *canvas,
pixman_region32_t *region,
pixman_image_t *src_image,
int offset_x, int offset_y,
uint32_t transparent_color);
void (*colorkey_image_from_surface)(SpiceCanvas *canvas,
pixman_region32_t *region,
SpiceCanvas *src_image,
int offset_x, int offset_y,
uint32_t transparent_color);
void (*colorkey_scale_image)(SpiceCanvas *canvas,
pixman_region32_t *region,
pixman_image_t *src_image,
int src_x, int src_y,
int src_width, int src_height,
int dest_x, int dest_y,
int dest_width, int dest_height,
uint32_t transparent_color);
void (*colorkey_scale_image_from_surface)(SpiceCanvas *canvas,
pixman_region32_t *region,
SpiceCanvas *src_image,
int src_x, int src_y,
int src_width, int src_height,
int dest_x, int dest_y,
int dest_width, int dest_height,
uint32_t transparent_color);
void (*copy_region)(SpiceCanvas *canvas,
pixman_region32_t *dest_region,
int dx, int dy);
pixman_image_t *(*get_image)(SpiceCanvas *canvas);
} SpiceCanvasOps;
void spice_canvas_set_usr_data(SpiceCanvas *canvas, void *data, spice_destroy_fn_t destroy_fn);
void *spice_canvas_get_usr_data(SpiceCanvas *canvas);
struct _SpiceCanvas {
SpiceCanvasOps *ops;
};
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,299 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "canvas_utils.h"
#include <spice/macros.h>
#ifdef __GNUC__
#include <stdlib.h>
#include <stdio.h>
#endif
#include "mem.h"
#ifdef WIN32
static int gdi_handlers = 0;
#endif
#ifndef CANVAS_ERROR
#define CANVAS_ERROR(format, ...) { \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__); \
abort(); \
}
#endif
static void release_data(pixman_image_t *image, void *release_data)
{
PixmanData *data = (PixmanData *)release_data;
#ifdef WIN32
if (data->bitmap) {
DeleteObject((HBITMAP)data->bitmap);
CloseHandle(data->mutex);
gdi_handlers--;
}
#endif
free(data->data);
free(data);
}
static PixmanData *
pixman_image_add_data(pixman_image_t *image)
{
PixmanData *data;
data = (PixmanData *)pixman_image_get_destroy_data(image);
if (data == NULL) {
data = (PixmanData *)calloc(1, sizeof(PixmanData));
if (data == NULL) {
CANVAS_ERROR("out of memory");
}
pixman_image_set_destroy_function(image,
release_data,
data);
}
return data;
}
void
spice_pixman_image_set_format(pixman_image_t *image,
pixman_format_code_t format)
{
PixmanData *data;
data = pixman_image_add_data(image);
data->format = format;
}
pixman_format_code_t
spice_pixman_image_get_format(pixman_image_t *image)
{
PixmanData *data;
data = (PixmanData *)pixman_image_get_destroy_data(image);
if (data != NULL &&
data->format != 0)
return data->format;
CANVAS_ERROR("Unknown pixman image type");
}
static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t format, int width, int height,
int stride)
{
uint8_t *data;
uint8_t *stride_data;
pixman_image_t *surface;
PixmanData *pixman_data;
data = (uint8_t *)spice_malloc_n(abs(stride), height);
if (stride < 0) {
stride_data = data + (-stride) * (height - 1);
} else {
stride_data = data;
}
surface = pixman_image_create_bits(format, width, height, (uint32_t *)stride_data, stride);
if (surface == NULL) {
free(data);
CANVAS_ERROR("create surface failed, out of memory");
}
pixman_data = pixman_image_add_data(surface);
pixman_data->data = data;
pixman_data->format = format;
return surface;
}
#ifdef WIN32
pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
int width, int height, int top_down)
#else
pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
#endif
{
#ifdef WIN32
/*
* Windows xp allow only 10,000 of gdi handlers, considering the fact that
* we limit here the number to 5000, we dont use atomic operations to sync
* this calculation against the other canvases (in case of multiple
* monitors), in worst case there will be little more than 5000 gdi
* handlers.
*/
if (dc && gdi_handlers < 5000) {
uint8_t *data;
uint8_t *src;
struct {
BITMAPINFO inf;
RGBQUAD palette[255];
} bitmap_info;
int nstride;
pixman_image_t *surface;
PixmanData *pixman_data;
HBITMAP bitmap;
HANDLE mutex;
memset(&bitmap_info, 0, sizeof(bitmap_info));
bitmap_info.inf.bmiHeader.biSize = sizeof(bitmap_info.inf.bmiHeader);
bitmap_info.inf.bmiHeader.biWidth = width;
bitmap_info.inf.bmiHeader.biHeight = (!top_down) ? height : -height;
bitmap_info.inf.bmiHeader.biPlanes = 1;
switch (format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
bitmap_info.inf.bmiHeader.biBitCount = 32;
nstride = width * 4;
break;
case PIXMAN_x1r5g5b5:
case PIXMAN_r5g6b5:
bitmap_info.inf.bmiHeader.biBitCount = 16;
nstride = SPICE_ALIGN(width * 2, 4);
break;
case PIXMAN_a8:
bitmap_info.inf.bmiHeader.biBitCount = 8;
nstride = SPICE_ALIGN(width, 4);
break;
case PIXMAN_a1:
bitmap_info.inf.bmiHeader.biBitCount = 1;
nstride = SPICE_ALIGN(width, 32) / 8;
break;
default:
CANVAS_ERROR("invalid format");
}
bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
mutex = CreateMutex(NULL, 0, NULL);
if (!mutex) {
CANVAS_ERROR("Unable to CreateMutex");
}
bitmap = CreateDIBSection(dc, &bitmap_info.inf, 0, (VOID **)&data, NULL, 0);
if (!bitmap) {
CloseHandle(mutex);
CANVAS_ERROR("Unable to CreateDIBSection");
}
if (top_down) {
src = data;
} else {
src = data + nstride * (height - 1);
nstride = -nstride;
}
surface = pixman_image_create_bits(format, width, height, (uint32_t *)src, nstride);
if (surface == NULL) {
CloseHandle(mutex);
DeleteObject(bitmap);
CANVAS_ERROR("create surface failed, out of memory");
}
pixman_data = pixman_image_add_data(surface);
pixman_data->format = format;
pixman_data->bitmap = bitmap;
pixman_data->mutex = mutex;
gdi_handlers++;
return surface;
} else {
#endif
if (top_down) {
pixman_image_t *surface;
PixmanData *data;
surface = pixman_image_create_bits(format, width, height, NULL, 0);
data = pixman_image_add_data(surface);
data->format = format;
return surface;
} else {
// NOTE: we assume here that the lz decoders always decode to RGB32.
int stride = 0;
switch (format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
stride = width * 4;
break;
case PIXMAN_x1r5g5b5:
case PIXMAN_r5g6b5:
stride = SPICE_ALIGN(width * 2, 4);
break;
case PIXMAN_a8:
stride = SPICE_ALIGN(width, 4);
break;
case PIXMAN_a1:
stride = SPICE_ALIGN(width, 32) / 8;
break;
default:
CANVAS_ERROR("invalid format");
}
stride = -stride;
return __surface_create_stride(format, width, height, stride);
}
#ifdef WIN32
}
#endif
}
#ifdef WIN32
pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
int stride)
#else
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
int stride)
#endif
{
#ifdef WIN32
if (dc) {
if (abs(stride) == (width * 4)) {
return surface_create(dc, format, width, height, (stride > 0));
}
}
#endif
return __surface_create_stride(format, width, height, stride);
}
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
pixman_format_code_t pixman_format, int width,
int height, int gross_pixels, int top_down)
{
int stride;
pixman_image_t *surface = NULL;
stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);
if (!top_down) {
stride = -stride;
}
surface = surface_create_stride(
#ifdef WIN32
canvas_data->dc,
#endif
pixman_format, width, height, stride);
canvas_data->out_surface = surface;
return surface;
}

View File

@ -1,80 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CANVAS_UTILS
#define _H_CANVAS_UTILS
#ifdef WIN32
#include <windows.h>
#endif
#include <spice/types.h>
#include "pixman_utils.h"
#include "lz.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct PixmanData {
#ifdef WIN32
HBITMAP bitmap;
HANDLE mutex;
#endif
uint8_t *data;
pixman_format_code_t format;
} PixmanData;
void spice_pixman_image_set_format(pixman_image_t *image,
pixman_format_code_t format);
pixman_format_code_t spice_pixman_image_get_format(pixman_image_t *image);
#ifdef WIN32
pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
int width, int height, int top_down);
#else
pixman_image_t *surface_create(pixman_format_code_t format, int width, int height, int top_down);
#endif
#ifdef WIN32
pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
int stride);
#else
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
int stride);
#endif
typedef struct LzDecodeUsrData {
#ifdef WIN32
HDC dc;
#endif
pixman_image_t *out_surface;
} LzDecodeUsrData;
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
pixman_format_code_t pixman_format, int width,
int height, int gross_pixels, int top_down);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,281 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _H_SPICE_DRAW
#define _H_SPICE_DRAW
#include <spice/types.h>
#include <spice/enums.h>
#include "mem.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SPICE_GET_ADDRESS(addr) ((void *)(uintptr_t)(addr))
#define SPICE_SET_ADDRESS(addr, val) ((addr) = (uintptr_t)(val))
typedef int32_t SPICE_FIXED28_4;
typedef struct SpicePointFix {
SPICE_FIXED28_4 x;
SPICE_FIXED28_4 y;
} SpicePointFix;
typedef struct SpicePoint {
int32_t x;
int32_t y;
} SpicePoint;
typedef struct SpicePoint16 {
int16_t x;
int16_t y;
} SpicePoint16;
typedef struct SpiceRect {
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
} SpiceRect;
typedef struct SpicePathSeg {
uint32_t flags;
uint32_t count;
SpicePointFix points[0];
} SpicePathSeg;
typedef struct SpicePath {
uint32_t num_segments;
SpicePathSeg *segments[0];
} SpicePath;
typedef struct SpiceClipRects {
uint32_t num_rects;
SpiceRect rects[0];
} SpiceClipRects;
typedef struct SpiceClip {
uint32_t type;
SpiceClipRects *rects;
} SpiceClip;
typedef struct SpicePalette {
uint64_t unique;
uint16_t num_ents;
uint32_t ents[0];
} SpicePalette;
#define SPICE_SURFACE_FMT_DEPTH(_d) ((_d) & 0x3f)
typedef struct SpiceImageDescriptor {
uint64_t id;
uint8_t type;
uint8_t flags;
uint32_t width;
uint32_t height;
} SpiceImageDescriptor;
typedef struct SpiceBitmap {
uint8_t format;
uint8_t flags;
uint32_t x;
uint32_t y;
uint32_t stride;
SpicePalette *palette;
uint64_t palette_id;
SpiceChunks *data;
} SpiceBitmap;
typedef struct SpiceSurface {
uint32_t surface_id;
} SpiceSurface;
typedef struct SpiceQUICData {
uint32_t data_size;
SpiceChunks *data;
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData;
typedef struct SpiceLZPLTData {
uint8_t flags;
uint32_t data_size;
SpicePalette *palette;
uint64_t palette_id;
SpiceChunks *data;
} SpiceLZPLTData;
typedef struct SpiceZlibGlzRGBData {
uint32_t glz_data_size;
uint32_t data_size;
SpiceChunks *data;
} SpiceZlibGlzRGBData;
typedef struct SpiceJPEGAlphaData {
uint8_t flags;
uint32_t jpeg_size;
uint32_t data_size;
SpiceChunks *data;
} SpiceJPEGAlphaData;
typedef struct SpiceImage {
SpiceImageDescriptor descriptor;
union {
SpiceBitmap bitmap;
SpiceQUICData quic;
SpiceSurface surface;
SpiceLZRGBData lz_rgb;
SpiceLZPLTData lz_plt;
SpiceJPEGData jpeg;
SpiceZlibGlzRGBData zlib_glz;
SpiceJPEGAlphaData jpeg_alpha;
} u;
} SpiceImage;
typedef struct SpicePattern {
SpiceImage *pat;
SpicePoint pos;
} SpicePattern;
typedef struct SpiceBrush {
uint32_t type;
union {
uint32_t color;
SpicePattern pattern;
} u;
} SpiceBrush;
typedef struct SpiceQMask {
uint8_t flags;
SpicePoint pos;
SpiceImage *bitmap;
} SpiceQMask;
typedef struct SpiceFill {
SpiceBrush brush;
uint16_t rop_descriptor;
SpiceQMask mask;
} SpiceFill;
typedef struct SpiceOpaque {
SpiceImage *src_bitmap;
SpiceRect src_area;
SpiceBrush brush;
uint16_t rop_descriptor;
uint8_t scale_mode;
SpiceQMask mask;
} SpiceOpaque;
typedef struct SpiceCopy {
SpiceImage *src_bitmap;
SpiceRect src_area;
uint16_t rop_descriptor;
uint8_t scale_mode;
SpiceQMask mask;
} SpiceCopy, SpiceBlend;
typedef struct SpiceTransparent {
SpiceImage *src_bitmap;
SpiceRect src_area;
uint32_t src_color;
uint32_t true_color;
} SpiceTransparent;
typedef struct SpiceAlphaBlend {
uint16_t alpha_flags;
uint8_t alpha;
SpiceImage *src_bitmap;
SpiceRect src_area;
} SpiceAlphaBlend;
typedef struct SpiceRop3 {
SpiceImage *src_bitmap;
SpiceRect src_area;
SpiceBrush brush;
uint8_t rop3;
uint8_t scale_mode;
SpiceQMask mask;
} SpiceRop3;
typedef struct SpiceBlackness {
SpiceQMask mask;
} SpiceBlackness, SpiceInvers, SpiceWhiteness;
typedef struct SpiceLineAttr {
uint8_t flags;
uint8_t style_nseg;
SPICE_FIXED28_4 *style;
} SpiceLineAttr;
typedef struct SpiceStroke {
SpicePath *path;
SpiceLineAttr attr;
SpiceBrush brush;
uint16_t fore_mode;
uint16_t back_mode;
} SpiceStroke;
typedef struct SpiceRasterGlyph {
SpicePoint render_pos;
SpicePoint glyph_origin;
uint16_t width;
uint16_t height;
uint8_t data[0];
} SpiceRasterGlyph;
typedef struct SpiceString {
uint16_t length;
uint16_t flags;
SpiceRasterGlyph *glyphs[0];
} SpiceString;
typedef struct SpiceText {
SpiceString *str;
SpiceRect back_area;
SpiceBrush fore_brush;
SpiceBrush back_brush;
uint16_t fore_mode;
uint16_t back_mode;
} SpiceText;
typedef struct SpiceCursorHeader {
uint64_t unique;
uint16_t type;
uint16_t width;
uint16_t height;
uint16_t hot_spot_x;
uint16_t hot_spot_y;
} SpiceCursorHeader;
#ifdef __cplusplus
}
#endif
#endif /* _H_SPICE_DRAW */

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H__GDI_CANVAS
#define _H__GDI_CANVAS
#ifndef SPICE_CANVAS_INTERNAL
#error "This header shouldn't be included directly"
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "pixman_utils.h"
#include "canvas_base.h"
#include "region.h"
SpiceCanvas *gdi_canvas_create(int width, int height,
HDC dc, class RecurciveMutex *lock, uint32_t format,
SpiceImageCache *bits_cache,
SpicePaletteCache *palette_cache,
SpiceImageSurfaces *surfaces,
SpiceGlzDecoder *glz_decoder,
SpiceJpegDecoder *jpeg_decoder,
SpiceZlibDecoder *zlib_decoder);
void gdi_canvas_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,906 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef SPICE_CANVAS_INTERNAL
#error "This file shouldn't be compiled directly"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "quic.h"
#include "rop3.h"
#include "region.h"
#define GL_CANVAS
#include "canvas_base.c"
typedef struct GLCanvas GLCanvas;
struct GLCanvas {
CanvasBase base;
GLCCtx glc;
void *private_data;
int private_data_size;
int textures_lost;
};
static inline uint8_t *copy_opposite_image(GLCanvas *canvas, void *data, int stride, int height)
{
uint8_t *ret_data = (uint8_t *)data;
uint8_t *dest;
uint8_t *src;
int i;
if (!canvas->private_data) {
canvas->private_data = spice_malloc_n(height, stride);
if (!canvas->private_data) {
return ret_data;
}
canvas->private_data_size = stride * height;
}
if (canvas->private_data_size < (stride * height)) {
free(canvas->private_data);
canvas->private_data = spice_malloc_n(height, stride);
if (!canvas->private_data) {
return ret_data;
}
canvas->private_data_size = stride * height;
}
dest = (uint8_t *)canvas->private_data;
src = (uint8_t *)data + (height - 1) * stride;
for (i = 0; i < height; ++i) {
memcpy(dest, src, stride);
dest += stride;
src -= stride;
}
return (uint8_t *)canvas->private_data;
}
static pixman_image_t *canvas_surf_to_trans_surf(GLCImage *image,
uint32_t trans_color)
{
int width = image->width;
int height = image->height;
uint8_t *src_line;
uint8_t *end_src_line;
int src_stride;
uint8_t *dest_line;
int dest_stride;
pixman_image_t *ret;
int i;
ret = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, 0);
if (ret == NULL) {
CANVAS_ERROR("create surface failed");
}
src_line = image->pixels;
src_stride = image->stride;
end_src_line = src_line + src_stride * height;
dest_line = (uint8_t *)pixman_image_get_data(ret);
dest_stride = pixman_image_get_stride(ret);
for (; src_line < end_src_line; src_line += src_stride, dest_line += dest_stride) {
for (i = 0; i < width; i++) {
if ((((uint32_t*)src_line)[i] & 0x00ffffff) == trans_color) {
((uint32_t*)dest_line)[i] = 0;
} else {
((uint32_t*)dest_line)[i] = (((uint32_t*)src_line)[i]) | 0xff000000;
}
}
}
return ret;
}
static GLCPath get_path(GLCanvas *canvas, SpicePath *s)
{
GLCPath path = glc_path_create(canvas->glc);
int i;
for (i = 0; i < s->num_segments; i++) {
SpicePathSeg* seg = s->segments[i];
SpicePointFix* point = seg->points;
SpicePointFix* end_point = point + seg->count;
if (seg->flags & SPICE_PATH_BEGIN) {
glc_path_move_to(path, fix_to_double(point->x), fix_to_double(point->y));
point++;
}
if (seg->flags & SPICE_PATH_BEZIER) {
ASSERT((point - end_point) % 3 == 0);
for (; point + 2 < end_point; point += 3) {
glc_path_curve_to(path,
fix_to_double(point[0].x), fix_to_double(point[0].y),
fix_to_double(point[1].x), fix_to_double(point[1].y),
fix_to_double(point[2].x), fix_to_double(point[2].y));
}
} else {
for (; point < end_point; point++) {
glc_path_line_to(path, fix_to_double(point->x), fix_to_double(point->y));
}
}
if (seg->flags & SPICE_PATH_END) {
if (seg->flags & SPICE_PATH_CLOSE) {
glc_path_close(path);
}
}
}
return path;
}
#define SET_GLC_RECT(dest, src) { \
(dest)->x = (src)->left; \
(dest)->y = (src)->top; \
(dest)->width = (src)->right - (src)->left; \
(dest)->height = (src)->bottom - (src)->top; \
}
#define SET_GLC_BOX(dest, src) { \
(dest)->x = (src)->x1; \
(dest)->y = (src)->y1; \
(dest)->width = (src)->x2 - (src)->x1; \
(dest)->height = (src)->y2 - (src)->y1; \
}
static void set_clip(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip)
{
GLCRect rect;
glc_clip_reset(canvas->glc);
switch (clip->type) {
case SPICE_CLIP_TYPE_NONE:
break;
case SPICE_CLIP_TYPE_RECTS: {
uint32_t n = clip->rects->num_rects;
SpiceRect *now = clip->rects->rects;
SpiceRect *end = now + n;
if (n == 0) {
rect.x = rect.y = 0;
rect.width = rect.height = 0;
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
break;
} else {
SET_GLC_RECT(&rect, now);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
}
for (now++; now < end; now++) {
SET_GLC_RECT(&rect, now);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
}
break;
}
default:
CANVAS_ERROR("invalid clip type");
}
}
static void set_mask(GLCanvas *canvas, SpiceQMask *mask, int x, int y)
{
pixman_image_t *image;
if (!(image = canvas_get_mask(&canvas->base, mask, NULL))) {
glc_clear_mask(canvas->glc, GLC_MASK_A);
return;
}
glc_set_mask(canvas->glc, x - mask->pos.x, y - mask->pos.y,
pixman_image_get_width(image),
pixman_image_get_height(image),
pixman_image_get_stride(image),
(uint8_t *)pixman_image_get_data(image), GLC_MASK_A);
}
static inline void surface_to_image(GLCanvas *canvas, pixman_image_t *surface, GLCImage *image,
int ignore_stride)
{
int depth = pixman_image_get_depth(surface);
ASSERT(depth == 32 || depth == 24);
image->format = (depth == 24) ? GLC_IMAGE_RGB32 : GLC_IMAGE_ARGB32;
image->width = pixman_image_get_width(surface);
image->height = pixman_image_get_height(surface);
image->stride = pixman_image_get_stride(surface);
image->pixels = (uint8_t *)pixman_image_get_data(surface);
image->pallet = NULL;
if (ignore_stride) {
return;
}
if (image->stride < 0) {
image->stride = -image->stride;
image->pixels = image->pixels - (image->height - 1) * image->stride;
} else {
image->pixels = copy_opposite_image(canvas, image->pixels, image->stride, image->height);
}
}
static void set_brush(GLCanvas *canvas, SpiceBrush *brush)
{
switch (brush->type) {
case SPICE_BRUSH_TYPE_SOLID: {
uint32_t color = brush->u.color;
double r, g, b;
b = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
color >>= canvas->base.color_shift;
g = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
color >>= canvas->base.color_shift;
r = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
glc_set_rgb(canvas->glc, r, g, b);
break;
}
case SPICE_BRUSH_TYPE_PATTERN: {
GLCImage image;
GLCPattern pattern;
pixman_image_t *surface;
surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
surface_to_image(canvas, surface, &image, 0);
pattern = glc_pattern_create(canvas->glc, -brush->u.pattern.pos.x,
-brush->u.pattern.pos.y, &image);
glc_set_pattern(canvas->glc, pattern);
glc_pattern_destroy(pattern);
pixman_image_unref (surface);
}
case SPICE_BRUSH_TYPE_NONE:
return;
default:
CANVAS_ERROR("invalid brush type");
}
}
static void set_op(GLCanvas *canvas, uint16_t rop_decriptor)
{
GLCOp op;
switch (rop_decriptor) {
case SPICE_ROPD_OP_PUT:
op = GLC_OP_COPY;
break;
case SPICE_ROPD_OP_XOR:
op = GLC_OP_XOR;
break;
case SPICE_ROPD_OP_BLACKNESS:
op = GLC_OP_CLEAR;
break;
case SPICE_ROPD_OP_WHITENESS:
op = GLC_OP_SET;
break;
case SPICE_ROPD_OP_PUT | SPICE_ROPD_INVERS_BRUSH:
case SPICE_ROPD_OP_PUT | SPICE_ROPD_INVERS_SRC:
op = GLC_OP_COPY_INVERTED;
break;
case SPICE_ROPD_OP_INVERS:
op = GLC_OP_INVERT;
break;
case SPICE_ROPD_OP_AND:
op = GLC_OP_AND;
break;
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_RES:
op = GLC_OP_NAND;
break;
case SPICE_ROPD_OP_OR:
op = GLC_OP_OR;
break;
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_RES:
op = GLC_OP_NOR;
break;
case SPICE_ROPD_OP_XOR | SPICE_ROPD_INVERS_RES:
op = GLC_OP_EQUIV;
break;
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_DEST:
op = GLC_OP_AND_REVERSE;
break;
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_BRUSH:
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_SRC:
op = GLC_OP_AND_INVERTED;
break;
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_DEST:
op = GLC_OP_OR_REVERSE;
break;
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_BRUSH:
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_SRC:
op = GLC_OP_OR_INVERTED;
break;
default:
WARN("GLC_OP_NOOP");
op = GLC_OP_NOOP;
}
glc_set_op(canvas->glc, op);
}
static void gl_canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCRect rect;
set_clip(canvas, bbox, clip);
set_mask(canvas, &fill->mask, bbox->left, bbox->top);
set_brush(canvas, &fill->brush);
set_op(canvas, fill->rop_descriptor);
SET_GLC_RECT(&rect, bbox);
glc_fill_rect(canvas->glc, &rect);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
GLCRecti src;
GLCRecti dest;
GLCImage image;
set_clip(canvas, bbox, clip);
set_mask(canvas, &copy->mask, bbox->left, bbox->top);
set_op(canvas, copy->rop_descriptor);
//todo: optimize get_image (use ogl conversion + remove unnecessary copy of 32bpp)
surface = canvas_get_image(&canvas->base, copy->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &copy->src_area);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(surface);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
GLCRecti src;
GLCRecti dest;
GLCRect fill_rect;
GLCImage image;
set_clip(canvas, bbox, clip);
set_mask(canvas, &opaque->mask, bbox->left, bbox->top);
glc_set_op(canvas->glc, (opaque->rop_descriptor & SPICE_ROPD_INVERS_SRC) ? GLC_OP_COPY_INVERTED :
GLC_OP_COPY);
surface = canvas_get_image(&canvas->base, opaque->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &opaque->src_area);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(surface);
set_brush(canvas, &opaque->brush);
set_op(canvas, opaque->rop_descriptor & ~SPICE_ROPD_INVERS_SRC);
SET_GLC_RECT(&fill_rect, bbox);
glc_fill_rect(canvas->glc, &fill_rect);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend *alpha_blend)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
GLCRecti src;
GLCRecti dest;
GLCImage image;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
glc_set_op(canvas->glc, GLC_OP_COPY);
surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &alpha_blend->src_area);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, (double)alpha_blend->alpha / 0xff);
pixman_image_unref(surface);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
GLCRecti src;
GLCRecti dest;
GLCImage image;
set_clip(canvas, bbox, clip);
set_mask(canvas, &blend->mask, bbox->left, bbox->top);
set_op(canvas, blend->rop_descriptor);
surface = canvas_get_image(&canvas->base, blend->src_bitmap, FALSE);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &blend->src_area);
surface_to_image(canvas, surface, &image, 0);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(surface);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent *transparent)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
pixman_image_t *trans_surf;
GLCImage image;
GLCRecti src;
GLCRecti dest;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
glc_set_op(canvas->glc, GLC_OP_COPY);
surface = canvas_get_image(&canvas->base, transparent->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
trans_surf = canvas_surf_to_trans_surf(&image, transparent->true_color);
pixman_image_unref(surface);
surface_to_image(canvas, trans_surf, &image, 1);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &transparent->src_area);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(trans_surf);
glc_flush(canvas->glc);
}
static inline void fill_common(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceQMask * mask, GLCOp op)
{
GLCRect rect;
set_clip(canvas, bbox, clip);
set_mask(canvas, mask, bbox->left, bbox->top);
glc_set_op(canvas->glc, op);
SET_GLC_RECT(&rect, bbox);
glc_fill_rect(canvas->glc, &rect);
}
static void gl_canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
fill_common(canvas, bbox, clip, &whiteness->mask, GLC_OP_SET);
}
static void gl_canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
fill_common(canvas, bbox, clip, &blackness->mask, GLC_OP_CLEAR);
}
static void gl_canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
fill_common(canvas, bbox, clip, &invers->mask, GLC_OP_INVERT);
}
static void gl_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *d;
pixman_image_t *s;
GLCImage image;
SpicePoint src_pos;
uint8_t *data_opp;
int src_stride;
set_clip(canvas, bbox, clip);
set_mask(canvas, &rop3->mask, bbox->left, bbox->top);
glc_set_op(canvas->glc, GLC_OP_COPY);
image.format = GLC_IMAGE_RGB32;
image.width = bbox->right - bbox->left;
image.height = bbox->bottom - bbox->top;
image.pallet = NULL;
d = pixman_image_create_bits(PIXMAN_x8r8g8b8, image.width, image.height, NULL, 0);
if (d == NULL) {
CANVAS_ERROR("create surface failed");
}
image.pixels = (uint8_t *)pixman_image_get_data(d);
image.stride = pixman_image_get_stride(d);
glc_read_pixels(canvas->glc, bbox->left, bbox->top, &image);
data_opp = copy_opposite_image(canvas, image.pixels,
image.stride,
pixman_image_get_height(d));
memcpy(image.pixels, data_opp,
image.stride * pixman_image_get_height(d));
s = canvas_get_image(&canvas->base, rop3->src_bitmap, FALSE);
src_stride = pixman_image_get_stride(s);
if (src_stride > 0) {
data_opp = copy_opposite_image(canvas, (uint8_t *)pixman_image_get_data(s),
src_stride, pixman_image_get_height(s));
memcpy((uint8_t *)pixman_image_get_data(s), data_opp,
src_stride * pixman_image_get_height(s));
}
if (!rect_is_same_size(bbox, &rop3->src_area)) {
pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, image.width,
image.height, rop3->scale_mode);
pixman_image_unref(s);
s = scaled_s;
src_pos.x = 0;
src_pos.y = 0;
} else {
src_pos.x = rop3->src_area.left;
src_pos.y = rop3->src_area.top;
}
if (pixman_image_get_width(s) - src_pos.x < image.width ||
pixman_image_get_height(s) - src_pos.y < image.height) {
CANVAS_ERROR("bad src bitmap size");
}
if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat, FALSE);
SpicePoint pat_pos;
pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p);
//for now (bottom-top)
if (pat_pos.y < 0) {
pat_pos.y = pixman_image_get_height(p) + pat_pos.y;
}
pat_pos.y = (image.height + pat_pos.y) % pixman_image_get_height(p);
pat_pos.y = pixman_image_get_height(p) - pat_pos.y;
do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
pixman_image_unref(p);
} else {
uint32_t color = (canvas->base.color_shift) == 8 ? rop3->brush.u.color :
canvas_16bpp_to_32bpp(rop3->brush.u.color);
do_rop3_with_color(rop3->rop3, d, s, &src_pos, color);
}
pixman_image_unref(s);
GLCRecti dest;
GLCRecti src;
dest.x = bbox->left;
dest.y = bbox->top;
image.pixels = copy_opposite_image(canvas, image.pixels, pixman_image_get_stride(d),
pixman_image_get_height(d));
src.x = src.y = 0;
dest.width = src.width = image.width;
dest.height = src.height = image.height;
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(d);
}
static void gl_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCPath path;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
set_op(canvas, stroke->fore_mode);
set_brush(canvas, &stroke->brush);
if (stroke->attr.flags & SPICE_LINE_FLAGS_STYLED) {
WARN("SPICE_LINE_FLAGS_STYLED");
}
glc_set_line_width(canvas->glc, 1.0);
path = get_path(canvas, stroke->path);
glc_stroke_path(canvas->glc, path);
glc_path_destroy(path);
}
static void gl_canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCRect rect;
SpiceString *str;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
if (!rect_is_empty(&text->back_area)) {
set_brush(canvas, &text->back_brush);
set_op(canvas, text->back_mode);
SET_GLC_RECT(&rect, bbox);
glc_fill_rect(canvas->glc, &rect);
}
str = (SpiceString *)SPICE_GET_ADDRESS(text->str);
set_brush(canvas, &text->fore_brush);
set_op(canvas, text->fore_mode);
if (str->flags & SPICE_STRING_FLAGS_RASTER_A1) {
SpicePoint pos;
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 1, &pos);
_glc_fill_mask(canvas->glc, pos.x, pos.y,
pixman_image_get_width(mask),
pixman_image_get_height(mask),
pixman_image_get_stride(mask),
(uint8_t *)pixman_image_get_data(mask));
pixman_image_unref(mask);
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
SpicePoint pos;
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 4, &pos);
glc_fill_alpha(canvas->glc, pos.x, pos.y,
pixman_image_get_width(mask),
pixman_image_get_height(mask),
pixman_image_get_stride(mask),
(uint8_t *)pixman_image_get_data(mask));
pixman_image_unref(mask);
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
WARN("untested path A8 glyphs, doing nothing");
if (0) {
SpicePoint pos;
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 8, &pos);
glc_fill_alpha(canvas->glc, pos.x, pos.y,
pixman_image_get_width(mask),
pixman_image_get_height(mask),
pixman_image_get_stride(mask),
(uint8_t *)pixman_image_get_data(mask));
pixman_image_unref(mask);
}
} else {
WARN("untested path vector glyphs, doing nothing");
if (0) {
//draw_vector_str(canvas, str, &text->fore_brush, text->fore_mode);
}
}
glc_flush(canvas->glc);
}
static void gl_canvas_clear(SpiceCanvas *spice_canvas)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
glc_clear(canvas->glc);
glc_flush(canvas->glc);
}
static void gl_canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
glc_set_op(canvas->glc, GLC_OP_COPY);
glc_copy_pixels(canvas->glc, bbox->left, bbox->top, src_pos->x, src_pos->y,
bbox->right - bbox->left, bbox->bottom - bbox->top);
}
static void gl_canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest, int dest_stride, const SpiceRect *area)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCImage image;
ASSERT(dest_stride > 0);
image.format = GLC_IMAGE_RGB32;
image.height = area->bottom - area->top;
image.width = area->right - area->left;
image.pixels = dest;
image.stride = dest_stride;
glc_read_pixels(canvas->glc, area->left, area->top, &image);
}
static void gl_canvas_group_start(SpiceCanvas *spice_canvas, QRegion *region)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCRect *glc_rects;
GLCRect *now, *end;
int num_rect;
pixman_box32_t *rects;
canvas_base_group_start(spice_canvas, region);
rects = pixman_region32_rectangles(region, &num_rect);
glc_rects = spice_new(GLCRect, num_rect);
now = glc_rects;
end = glc_rects + num_rect;
for (; now < end; now++, rects++) {
SET_GLC_BOX(now, rects);
}
glc_mask_rects(canvas->glc, num_rect, glc_rects, GLC_MASK_B);
free(glc_rects);
}
static void gl_canvas_put_image(SpiceCanvas *spice_canvas, const SpiceRect *dest, const uint8_t *src_data,
uint32_t src_width, uint32_t src_height, int src_stride,
const QRegion *clip)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCRecti src;
GLCRecti gldest;
GLCImage image;
uint32_t i;
ASSERT(src_stride <= 0)
glc_clip_reset(canvas->glc);
if (clip) {
int num_rects;
pixman_box32_t *rects = pixman_region32_rectangles((pixman_region32_t *)clip,
&num_rects);
GLCRect rect;
if (num_rects == 0) {
rect.x = rect.y = rect.width = rect.height = 0;
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
} else {
SET_GLC_BOX(&rect, rects);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
for (i = 1; i < num_rects; i++) {
SET_GLC_BOX(&rect, rects + i);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
}
}
}
SET_GLC_RECT(&gldest, dest);
src.x = src.y = 0;
src.width = src_width;
src.height = src_height;
image.format = GLC_IMAGE_RGB32;
image.width = src_width;
image.height = src_height;
src_stride = -src_stride;
image.stride = src_stride;
image.pixels = (uint8_t *)src_data - (src_height - 1) * src_stride;
image.pallet = NULL;
glc_draw_image(canvas->glc, &gldest, &src, &image, 0, 1);
glc_flush(canvas->glc);
}
static void gl_canvas_group_end(SpiceCanvas *spice_canvas)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
canvas_base_group_end(spice_canvas);
glc_clear_mask(canvas->glc, GLC_MASK_B);
}
static int need_init = 1;
static SpiceCanvasOps gl_canvas_ops;
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
)
{
GLCanvas *canvas;
int init_ok;
if (need_init) {
return NULL;
}
canvas = spice_new0(GLCanvas, 1);
if (!(canvas->glc = glc_create(width, height))) {
goto error_1;
}
canvas->private_data = NULL;
init_ok = canvas_base_init(&canvas->base, &gl_canvas_ops,
width, height, format
#ifdef SW_CANVAS_CACHE
, bits_cache
, palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, bits_cache
#endif
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
);
if (!init_ok) {
goto error_2;
}
return (SpiceCanvas *)canvas;
error_2:
glc_destroy(canvas->glc, 0);
error_1:
free(canvas);
return NULL;
}
void gl_canvas_set_textures_lost(SpiceCanvas *spice_canvas,
int textures_lost)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
canvas->textures_lost = textures_lost;
}
static void gl_canvas_destroy(SpiceCanvas *spice_canvas)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
if (!canvas) {
return;
}
canvas_base_destroy(&canvas->base);
glc_destroy(canvas->glc, canvas->textures_lost);
free(canvas->private_data);
free(canvas);
}
void gl_canvas_init(void) //unsafe global function
{
if (!need_init) {
return;
}
need_init = 0;
canvas_base_init_ops(&gl_canvas_ops);
gl_canvas_ops.draw_fill = gl_canvas_draw_fill;
gl_canvas_ops.draw_copy = gl_canvas_draw_copy;
gl_canvas_ops.draw_opaque = gl_canvas_draw_opaque;
gl_canvas_ops.copy_bits = gl_canvas_copy_bits;
gl_canvas_ops.draw_text = gl_canvas_draw_text;
gl_canvas_ops.draw_stroke = gl_canvas_draw_stroke;
gl_canvas_ops.draw_rop3 = gl_canvas_draw_rop3;
gl_canvas_ops.draw_blend = gl_canvas_draw_blend;
gl_canvas_ops.draw_blackness = gl_canvas_draw_blackness;
gl_canvas_ops.draw_whiteness = gl_canvas_draw_whiteness;
gl_canvas_ops.draw_invers = gl_canvas_draw_invers;
gl_canvas_ops.draw_transparent = gl_canvas_draw_transparent;
gl_canvas_ops.draw_alpha_blend = gl_canvas_draw_alpha_blend;
gl_canvas_ops.put_image = gl_canvas_put_image;
gl_canvas_ops.clear = gl_canvas_clear;
gl_canvas_ops.read_bits = gl_canvas_read_bits;
gl_canvas_ops.group_start = gl_canvas_group_start;
gl_canvas_ops.group_end = gl_canvas_group_end;
gl_canvas_ops.destroy = gl_canvas_destroy;
rop3_init();
}

View File

@ -1,53 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "glc.h"
#include "canvas_base.h"
#include "region.h"
#ifndef SPICE_CANVAS_INTERNAL
#error "This header shouldn't be included directly"
#endif
#ifndef _H__GL_CANVAS
#define _H__GL_CANVAS
#ifdef __cplusplus
extern "C" {
#endif
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
);
void gl_canvas_set_textures_lost(SpiceCanvas *canvas, int textures_lost);
void gl_canvas_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,61 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef GL_UTILS_H
#define GL_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef RED_DEBUG
#define GLC_ERROR_TEST_FLUSH { \
GLenum gl_err; glFlush(); \
if ((gl_err = glGetError()) != GL_NO_ERROR) { \
printf("%s[%d]: opengl error: %s\n", __FUNCTION__, __LINE__, \
gluErrorString(gl_err)); \
abort(); \
} \
}
#define GLC_ERROR_TEST_FINISH { \
GLenum gl_err; glFinish(); \
if ((gl_err = glGetError()) != GL_NO_ERROR) { \
printf("%s[%d]: opengl error: %s\n", __FUNCTION__, __LINE__, \
gluErrorString(gl_err)); \
abort(); \
} \
}
#else
#define GLC_ERROR_TEST_FLUSH ;
#define GLC_ERROR_TEST_FINISH ;
#endif
#include "bitops.h"
#define find_msb spice_bit_find_msb
#define gl_get_to_power_two spice_bit_next_pow2
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,167 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _H_GL_CANVASE
#define _H_GL_CANVASE
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void * GLCCtx;
typedef void * GLCPattern;
typedef void * GLCPath;
typedef struct GLCRect {
double x;
double y;
double width;
double height;
} GLCRect;
typedef struct GLCRecti {
int x;
int y;
int width;
int height;
} GLCRecti;
typedef enum {
GLC_IMAGE_RGB32,
GLC_IMAGE_ARGB32,
} GLCImageFormat;
typedef struct GLCPImage {
GLCImageFormat format;
int width;
int height;
int stride;
uint8_t *pixels;
uint32_t *pallet;
} GLCImage;
GLCPattern glc_pattern_create(GLCCtx glc, int x_orign, int y_orign, const GLCImage *image);
void glc_pattern_set(GLCPattern pattern, int x_orign, int y_orign, const GLCImage *image);
void glc_pattern_destroy(GLCPattern pattern);
void glc_path_move_to(GLCPath path, double x, double y);
void glc_path_line_to(GLCPath path, double x, double y);
void glc_path_curve_to(GLCPath path, double p1_x, double p1_y, double p2_x, double p2_y,
double p3_x, double p3_y);
void glc_path_rel_move_to(GLCPath path, double x, double y);
void glc_path_rel_line_to(GLCPath path, double x, double y);
void glc_path_rel_curve_to(GLCPath path, double p1_x, double p1_y, double p2_x, double p2_y,
double p3_x, double p3_y);
void glc_path_close(GLCPath path);
void glc_path_cleare(GLCPath);
GLCPath glc_path_create(GLCCtx glc);
void glc_path_destroy(GLCPath path);
void glc_set_rgb(GLCCtx glc, double red, double green, double blue);
void glc_set_rgba(GLCCtx glc, double red, double green, double blue, double alpha);
void glc_set_pattern(GLCCtx glc, GLCPattern pattern);
typedef enum {
GLC_OP_CLEAR = 0x1500,
GLC_OP_SET = 0x150F,
GLC_OP_COPY = 0x1503,
GLC_OP_COPY_INVERTED = 0x150C,
GLC_OP_NOOP = 0x1505,
GLC_OP_INVERT = 0x150A,
GLC_OP_AND = 0x1501,
GLC_OP_NAND = 0x150E,
GLC_OP_OR = 0x1507,
GLC_OP_NOR = 0x1508,
GLC_OP_XOR = 0x1506,
GLC_OP_EQUIV = 0x1509,
GLC_OP_AND_REVERSE = 0x1502,
GLC_OP_AND_INVERTED = 0x1504,
GLC_OP_OR_REVERSE = 0x150B,
GLC_OP_OR_INVERTED = 0x150D,
} GLCOp;
void glc_set_op(GLCCtx glc, GLCOp op);
void glc_set_alpha_factor(GLCCtx glc, double alpah);
typedef enum {
GLC_FILL_MODE_WINDING_ODD,
GLC_FILL_MODE_WINDING_NONZERO,
} GLCFillMode;
void glc_set_fill_mode(GLCCtx glc, GLCFillMode mode);
void glc_set_line_width(GLCCtx glc, double width);
void glc_set_line_end_cap(GLCCtx glc, int style);
void glc_set_line_join(GLCCtx glc, int style);
void glc_set_miter_limit(GLCCtx glc, int limit);
void glc_set_line_dash(GLCCtx glc, const double *dashes, int num_dashes, double offset);
typedef enum {
GLC_MASK_A,
GLC_MASK_B,
} GLCMaskID;
void glc_set_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height,
int stride, const uint8_t *bitmap, GLCMaskID id);
void glc_mask_rects(GLCCtx glc, int num_rect, GLCRect *rects, GLCMaskID id);
void glc_clear_mask(GLCCtx glc, GLCMaskID id);
typedef enum {
GLC_CLIP_OP_SET,
GLC_CLIP_OP_OR,
GLC_CLIP_OP_AND,
GLC_CLIP_OP_EXCLUDE,
} GLCClipOp;
void glc_clip_rect(GLCCtx glc, const GLCRect *rect, GLCClipOp op);
void glc_clip_path(GLCCtx glc, GLCPath path, GLCClipOp op);
void glc_clip_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
const uint8_t *bitmap, GLCClipOp op);
void glc_clip_reset(GLCCtx glc);
void glc_fill_rect(GLCCtx glc, const GLCRect *rect);
void glc_fill_path(GLCCtx glc, GLCPath path);
void _glc_fill_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
const uint8_t *bitmap);
void glc_fill_alpha(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
const uint8_t *alpha_mask);
void glc_stroke_rect(GLCCtx glc, const GLCRect *rect);
void glc_stroke_path(GLCCtx glc, GLCPath path);
void glc_draw_image(GLCCtx glc, const GLCRecti *dest, const GLCRecti *src, const GLCImage *image,
int scale_mode, double alpha);
void glc_copy_pixels(GLCCtx glc, int x_dest, int y_dest, int x_src, int y_src, int width,
int height);
void glc_read_pixels(GLCCtx glc, int x, int y, GLCImage *image);
void glc_flush(GLCCtx glc);
void glc_clear(GLCCtx glc);
GLCCtx glc_create(int width, int height);
void glc_destroy(GLCCtx glc, int textures_lost);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,138 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/***********************************************************
Copyright 1987, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
#ifndef LINES_H
#define LINES_H
#include <pixman_utils.h>
#include <stdlib.h>
#include <string.h>
#include "draw.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct lineGC lineGC;
typedef struct {
void (*FillSpans)(lineGC * pGC,
int num_spans, SpicePoint * points, int *widths,
int sorted, int foreground);
void (*FillRects)(lineGC * pGC,
int nun_rects, pixman_rectangle32_t * rects,
int foreground);
} lineGCOps;
struct lineGC {
int width;
int height;
unsigned char alu;
unsigned short lineWidth;
unsigned short dashOffset;
unsigned short numInDashList;
unsigned char *dash;
unsigned int lineStyle:2;
unsigned int capStyle:2;
unsigned int joinStyle:2;
lineGCOps *ops;
};
/* CoordinateMode for drawing routines */
#define CoordModeOrigin 0 /* relative to the origin */
#define CoordModePrevious 1 /* relative to previous point */
/* LineStyle */
#define LineSolid 0
#define LineOnOffDash 1
#define LineDoubleDash 2
/* capStyle */
#define CapNotLast 0
#define CapButt 1
#define CapRound 2
#define CapProjecting 3
/* joinStyle */
#define JoinMiter 0
#define JoinRound 1
#define JoinBevel 2
extern void spice_canvas_zero_line(lineGC *pgc,
int mode,
int num_points,
SpicePoint * points);
extern void spice_canvas_zero_dash_line(lineGC * pgc,
int mode,
int n_points,
SpicePoint * points);
extern void spice_canvas_wide_dash_line(lineGC * pGC,
int mode,
int num_points,
SpicePoint * points);
extern void spice_canvas_wide_line(lineGC *pGC,
int mode,
int num_points,
SpicePoint * points);
extern int spice_canvas_clip_spans(pixman_region32_t *clip_region,
SpicePoint *points,
int *widths,
int num_spans,
SpicePoint *new_points,
int *new_widths,
int sorted);
#ifdef __cplusplus
}
#endif
#endif /* LINES_H */

View File

@ -1,740 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc. and/or its affiliates.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
This file incorporates work covered by the following copyright and
permission notice:
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "lz.h"
#define DEBUG
#ifdef DEBUG
#define ASSERT(usr, x) \
if (!(x)) (usr)->error(usr, "%s: ASSERT %s failed\n", __FUNCTION__, #x);
#else
#define ASSERT(usr, x)
#endif
#define HASH_LOG 13
#define HASH_SIZE (1 << HASH_LOG)
#define HASH_MASK (HASH_SIZE - 1)
typedef struct LzImageSegment LzImageSegment;
struct LzImageSegment {
uint8_t *lines;
uint8_t *lines_end;
unsigned int size_delta; // total size of the previous segments in units of
// pixels for rgb and bytes for plt.
LzImageSegment *next;
};
// TODO: pack?
typedef struct HashEntry {
LzImageSegment *image_seg;
uint8_t *ref;
} HashEntry;
typedef struct Encoder {
LzUsrContext *usr;
LzImageType type;
const SpicePalette *palette; // for decoding images with palettes to rgb
int stride; // stride is in bytes. For rgb must be equal to
// width*bytes_per_pix.
// For palettes stride can be bigger than width/pixels_per_byte by 1 only if
// width%pixels_per_byte != 0.
int height;
int width; // the original width (in pixels)
LzImageSegment *head_image_segs;
LzImageSegment *tail_image_segs;
LzImageSegment *free_image_segs;
// the dictionary hash table is composed (1) a pointer to the segment the word was found in
// (2) a pointer to the first byte in the segment that matches the word
HashEntry htab[HASH_SIZE];
uint8_t *io_start;
uint8_t *io_now;
uint8_t *io_end;
size_t io_bytes_count;
uint8_t *io_last_copy; // pointer to the last byte in which copy count was written
} Encoder;
/****************************************************/
/* functions for managing the pool of image segments*/
/****************************************************/
static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder);
static void lz_reset_image_seg(Encoder *encoder);
static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
unsigned int num_first_lines);
// return a free image segment if one exists. Make allocation if needed. adds it to the
// tail of the image segments lists
static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
{
LzImageSegment *ret;
if (encoder->free_image_segs) {
ret = encoder->free_image_segs;
encoder->free_image_segs = ret->next;
} else {
if (!(ret = (LzImageSegment *)encoder->usr->malloc(encoder->usr, sizeof(*ret)))) {
return NULL;
}
}
ret->next = NULL;
if (encoder->tail_image_segs) {
encoder->tail_image_segs->next = ret;
}
encoder->tail_image_segs = ret;
if (!encoder->head_image_segs) {
encoder->head_image_segs = ret;
}
return ret;
}
// adding seg to the head of free segments (lz_reset_image_seg removes it from used ones)
static INLINE void __lz_free_image_seg(Encoder *encoder, LzImageSegment *seg)
{
seg->next = encoder->free_image_segs;
encoder->free_image_segs = seg;
}
// moves all the used image segments to the free pool
static void lz_reset_image_seg(Encoder *encoder)
{
while (encoder->head_image_segs) {
LzImageSegment *seg = encoder->head_image_segs;
encoder->head_image_segs = seg->next;
__lz_free_image_seg(encoder, seg);
}
encoder->tail_image_segs = NULL;
}
static void lz_dealloc_free_segments(Encoder *encoder)
{
while (encoder->free_image_segs) {
LzImageSegment *seg = encoder->free_image_segs;
encoder->free_image_segs = seg->next;
encoder->usr->free(encoder->usr, seg);
}
}
// return FALSE when operation fails (due to failure in allocation)
static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
unsigned int num_first_lines)
{
LzImageSegment *image_seg;
uint32_t size_delta = 0;
unsigned int num_lines = num_first_lines;
uint8_t* lines = first_lines;
int row;
ASSERT(encoder->usr, !encoder->head_image_segs);
image_seg = lz_alloc_image_seg(encoder);
if (!image_seg) {
goto error_1;
}
image_seg->lines = lines;
image_seg->lines_end = lines + num_lines * encoder->stride;
image_seg->size_delta = size_delta;
size_delta += num_lines * encoder->stride / RGB_BYTES_PER_PIXEL[encoder->type];
for (row = num_first_lines; row < encoder->height; row += num_lines) {
num_lines = encoder->usr->more_lines(encoder->usr, &lines);
if (num_lines <= 0) {
encoder->usr->error(encoder->usr, "more lines failed\n");
}
image_seg = lz_alloc_image_seg(encoder);
if (!image_seg) {
goto error_1;
}
image_seg->lines = lines;
image_seg->lines_end = lines + num_lines * encoder->stride;
image_seg->size_delta = size_delta;
size_delta += num_lines * encoder->stride / RGB_BYTES_PER_PIXEL[encoder->type];
}
return TRUE;
error_1:
lz_reset_image_seg(encoder);
return FALSE;
}
/**************************************************************************
* Handling encoding and decoding of a byte
***************************************************************************/
static INLINE int more_io_bytes(Encoder *encoder)
{
uint8_t *io_ptr;
int num_io_bytes = encoder->usr->more_space(encoder->usr, &io_ptr);
encoder->io_bytes_count += num_io_bytes;
encoder->io_now = io_ptr;
encoder->io_end = encoder->io_now + num_io_bytes;
return num_io_bytes;
}
static INLINE void encode(Encoder *encoder, uint8_t byte)
{
if (encoder->io_now == encoder->io_end) {
if (more_io_bytes(encoder) <= 0) {
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
}
ASSERT(encoder->usr, encoder->io_now);
}
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
*(encoder->io_now++) = byte;
}
static INLINE void encode_32(Encoder *encoder, unsigned int word)
{
encode(encoder, (uint8_t)(word >> 24));
encode(encoder, (uint8_t)(word >> 16) & 0x0000ff);
encode(encoder, (uint8_t)(word >> 8) & 0x0000ff);
encode(encoder, (uint8_t)(word & 0x0000ff));
}
static INLINE void encode_copy_count(Encoder *encoder, uint8_t copy_count)
{
encode(encoder, copy_count);
encoder->io_last_copy = encoder->io_now - 1; // io_now cannot be the first byte of the buffer
}
static INLINE void update_copy_count(Encoder *encoder, uint8_t copy_count)
{
ASSERT(encoder->usr, encoder->io_last_copy);
*(encoder->io_last_copy) = copy_count;
}
static INLINE void encode_level(Encoder *encoder, uint8_t level_code)
{
*(encoder->io_start) |= level_code;
}
// decrease the io ptr by 1
static INLINE void compress_output_prev(Encoder *encoder)
{
// io_now cannot be the first byte of the buffer
encoder->io_now--;
// the function should be called only when copy count is written unnecessarily by lz_compress
ASSERT(encoder->usr, encoder->io_now == encoder->io_last_copy)
}
static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
{
ASSERT(encoder->usr, io_ptr <= io_ptr_end);
encoder->io_bytes_count = io_ptr_end - io_ptr;
encoder->io_start = io_ptr;
encoder->io_now = io_ptr;
encoder->io_end = io_ptr_end;
encoder->io_last_copy = NULL;
return TRUE;
}
static INLINE uint8_t decode(Encoder *encoder)
{
if (encoder->io_now == encoder->io_end) {
int num_io_bytes = more_io_bytes(encoder);
if (num_io_bytes <= 0) {
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
}
ASSERT(encoder->usr, encoder->io_now);
}
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
return *(encoder->io_now++);
}
static INLINE uint32_t decode_32(Encoder *encoder)
{
uint32_t word = 0;
word |= decode(encoder);
word <<= 8;
word |= decode(encoder);
word <<= 8;
word |= decode(encoder);
word <<= 8;
word |= decode(encoder);
return word;
}
static INLINE int is_io_to_decode_end(Encoder *encoder)
{
if (encoder->io_now != encoder->io_end) {
return FALSE;
} else {
int num_io_bytes = more_io_bytes(encoder); //disable inline optimizations
return (num_io_bytes <= 0);
}
}
/*******************************************************************
* intialization and finalization of lz
********************************************************************/
static int init_encoder(Encoder *encoder, LzUsrContext *usr)
{
encoder->usr = usr;
encoder->free_image_segs = NULL;
encoder->head_image_segs = NULL;
encoder->tail_image_segs = NULL;
return TRUE;
}
LzContext *lz_create(LzUsrContext *usr)
{
Encoder *encoder;
if (!usr || !usr->error || !usr->warn || !usr->info || !usr->malloc ||
!usr->free || !usr->more_space || !usr->more_lines) {
return NULL;
}
if (!(encoder = (Encoder *)usr->malloc(usr, sizeof(Encoder)))) {
return NULL;
}
if (!init_encoder(encoder, usr)) {
usr->free(usr, encoder);
return NULL;
}
return (LzContext *)encoder;
}
void lz_destroy(LzContext *lz)
{
Encoder *encoder = (Encoder *)lz;
if (!lz) {
return;
}
if (encoder->head_image_segs) {
encoder->usr->error(encoder->usr, "%s: used_image_segments not empty\n", __FUNCTION__);
lz_reset_image_seg(encoder);
}
lz_dealloc_free_segments(encoder);
encoder->usr->free(encoder->usr, encoder);
}
/*******************************************************************
* encoding and decoding the image
********************************************************************/
/*
* 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 MAX_COPY 32
#define MAX_LEN 264 /* 256 + 8 */
#define BOUND_OFFSET 2
#define LIMIT_OFFSET 6
#define MIN_FILE_SIZE 4
#define COMP_LEVEL_SIZE_LIMIT 65536
// TODO: implemented lz2. should lz1 be an option (no RLE + distance limitation of MAX_DISTANCE)
// TODO: I think MAX_FARDISTANCE can be changed easily to 2^29
// (and maybe even more when pixel > byte).
// i.e. we can support 512M Bytes/Pixels distance instead of only ~68K.
#define MAX_DISTANCE 8191 // 2^13
#define MAX_FARDISTANCE (65535 + MAX_DISTANCE - 1) // ~2^16+2^13
#define LZ_PLT
#include "lz_compress_tmpl.c"
#define LZ_PLT
#include "lz_decompress_tmpl.c"
#define LZ_PLT
#define PLT8
#define TO_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_PLT
#define PLT4_BE
#define TO_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_PLT
#define PLT4_LE
#define TO_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_PLT
#define PLT1_BE
#define TO_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_PLT
#define PLT1_LE
#define TO_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_RGB16
#include "lz_compress_tmpl.c"
#define LZ_RGB16
#include "lz_decompress_tmpl.c"
#define LZ_RGB16
#define TO_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_RGB24
#include "lz_compress_tmpl.c"
#define LZ_RGB24
#include "lz_decompress_tmpl.c"
#define LZ_RGB32
#include "lz_compress_tmpl.c"
#define LZ_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_RGB_ALPHA
#include "lz_compress_tmpl.c"
#define LZ_RGB_ALPHA
#include "lz_decompress_tmpl.c"
#undef LZ_UNEXPECT_CONDITIONAL
#undef LZ_EXPECT_CONDITIONAL
int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
uint8_t *lines, unsigned int num_lines, int stride,
uint8_t *io_ptr, unsigned int num_io_bytes)
{
Encoder *encoder = (Encoder *)lz;
uint8_t *io_ptr_end = io_ptr + num_io_bytes;
encoder->type = type;
encoder->width = width;
encoder->height = height;
encoder->stride = stride;
if (IS_IMAGE_TYPE_PLT[encoder->type]) {
if (encoder->stride > (width / PLT_PIXELS_PER_BYTE[encoder->type])) {
if (((width % PLT_PIXELS_PER_BYTE[encoder->type]) == 0) || (
(encoder->stride - (width / PLT_PIXELS_PER_BYTE[encoder->type])) > 1)) {
encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
}
}
} else {
if (encoder->stride != width * RGB_BYTES_PER_PIXEL[encoder->type]) {
encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb)\n");
}
}
// assign the output buffer
if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
encoder->usr->error(encoder->usr, "lz encoder io reset failed\n");
}
// first read the list of the image segments
if (!lz_read_image_segments(encoder, lines, num_lines)) {
encoder->usr->error(encoder->usr, "lz encoder reading image segments failed\n");
}
encode_32(encoder, LZ_MAGIC);
encode_32(encoder, LZ_VERSION);
encode_32(encoder, type);
encode_32(encoder, width);
encode_32(encoder, height);
encode_32(encoder, stride);
encode_32(encoder, top_down); // TODO: maybe compress type and top_down to one byte
switch (encoder->type) {
case LZ_IMAGE_TYPE_PLT1_BE:
case LZ_IMAGE_TYPE_PLT1_LE:
case LZ_IMAGE_TYPE_PLT4_BE:
case LZ_IMAGE_TYPE_PLT4_LE:
case LZ_IMAGE_TYPE_PLT8:
lz_plt_compress(encoder);
break;
case LZ_IMAGE_TYPE_RGB16:
lz_rgb16_compress(encoder);
break;
case LZ_IMAGE_TYPE_RGB24:
lz_rgb24_compress(encoder);
break;
case LZ_IMAGE_TYPE_RGB32:
lz_rgb32_compress(encoder);
break;
case LZ_IMAGE_TYPE_RGBA:
lz_rgb32_compress(encoder);
lz_rgb_alpha_compress(encoder);
break;
case LZ_IMAGE_TYPE_XXXA:
lz_rgb_alpha_compress(encoder);
break;
case LZ_IMAGE_TYPE_INVALID:
default:
encoder->usr->error(encoder->usr, "bad image type\n");
}
// move all the used segments to the free ones
lz_reset_image_seg(encoder);
encoder->io_bytes_count -= (encoder->io_end - encoder->io_now);
return encoder->io_bytes_count;
}
/*
initialize and read lz magic
*/
void lz_decode_begin(LzContext *lz, uint8_t *io_ptr, unsigned int num_io_bytes,
LzImageType *out_type, int *out_width, int *out_height,
int *out_n_pixels, int *out_top_down, const SpicePalette *palette)
{
Encoder *encoder = (Encoder *)lz;
uint8_t *io_ptr_end = io_ptr + num_io_bytes;
uint32_t magic;
uint32_t version;
if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
encoder->usr->error(encoder->usr, "io reset failed");
}
magic = decode_32(encoder);
if (magic != LZ_MAGIC) {
encoder->usr->error(encoder->usr, "bad magic\n");
}
version = decode_32(encoder);
if (version != LZ_VERSION) {
encoder->usr->error(encoder->usr, "bad version\n");
}
encoder->type = (LzImageType)decode_32(encoder);
encoder->width = decode_32(encoder);
encoder->height = decode_32(encoder);
encoder->stride = decode_32(encoder);
*out_top_down = decode_32(encoder);
*out_width = encoder->width;
*out_height = encoder->height;
// *out_stride = encoder->stride;
*out_type = encoder->type;
// TODO: maybe instead of stride we can encode out_n_pixels
// (if stride is not necessary in decoding).
if (IS_IMAGE_TYPE_PLT[encoder->type]) {
encoder->palette = palette;
*out_n_pixels = encoder->stride * PLT_PIXELS_PER_BYTE[encoder->type] * encoder->height;
} else {
*out_n_pixels = encoder->width * encoder->height;
}
}
void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
{
Encoder *encoder = (Encoder *)lz;
size_t out_size = 0;
size_t alpha_size = 0;
size_t size = 0;
if (IS_IMAGE_TYPE_PLT[encoder->type]) {
if (to_type == encoder->type) {
size = encoder->height * encoder->stride;
out_size = lz_plt_decompress(encoder, (one_byte_pixel_t *)buf, size);
} else if (to_type == LZ_IMAGE_TYPE_RGB32) {
size = encoder->height * encoder->stride * PLT_PIXELS_PER_BYTE[encoder->type];
if (!encoder->palette) {
encoder->usr->error(encoder->usr,
"a palette is missing (for bpp to rgb decoding)\n");
}
switch (encoder->type) {
case LZ_IMAGE_TYPE_PLT1_BE:
out_size = lz_plt1_be_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
break;
case LZ_IMAGE_TYPE_PLT1_LE:
out_size = lz_plt1_le_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
break;
case LZ_IMAGE_TYPE_PLT4_BE:
out_size = lz_plt4_be_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
break;
case LZ_IMAGE_TYPE_PLT4_LE:
out_size = lz_plt4_le_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
break;
case LZ_IMAGE_TYPE_PLT8:
out_size = lz_plt8_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
break;
case LZ_IMAGE_TYPE_RGB16:
case LZ_IMAGE_TYPE_RGB24:
case LZ_IMAGE_TYPE_RGB32:
case LZ_IMAGE_TYPE_RGBA:
case LZ_IMAGE_TYPE_XXXA:
case LZ_IMAGE_TYPE_INVALID:
default:
encoder->usr->error(encoder->usr, "bad image type\n");
}
} else {
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
} else {
size = encoder->height * encoder->width;
switch (encoder->type) {
case LZ_IMAGE_TYPE_RGB16:
if (encoder->type == to_type) {
out_size = lz_rgb16_decompress(encoder, (rgb16_pixel_t *)buf, size);
} else if (to_type == LZ_IMAGE_TYPE_RGB32) {
out_size = lz_rgb16_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
} else {
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
break;
case LZ_IMAGE_TYPE_RGB24:
if (encoder->type == to_type) {
out_size = lz_rgb24_decompress(encoder, (rgb24_pixel_t *)buf, size);
} else if (to_type == LZ_IMAGE_TYPE_RGB32) {
out_size = lz_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
} else {
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
break;
case LZ_IMAGE_TYPE_RGB32:
if (encoder->type == to_type) {
out_size = lz_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
} else {
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
break;
case LZ_IMAGE_TYPE_RGBA:
if (encoder->type == to_type) {
out_size = lz_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
alpha_size = lz_rgb_alpha_decompress(encoder, (rgb32_pixel_t *)buf, size);
ASSERT(encoder->usr, alpha_size == size);
} else {
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
break;
case LZ_IMAGE_TYPE_XXXA:
if (encoder->type == to_type) {
alpha_size = lz_rgb_alpha_decompress(encoder, (rgb32_pixel_t *)buf, size);
out_size = alpha_size;
} else {
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
break;
case LZ_IMAGE_TYPE_PLT1_LE:
case LZ_IMAGE_TYPE_PLT1_BE:
case LZ_IMAGE_TYPE_PLT4_LE:
case LZ_IMAGE_TYPE_PLT4_BE:
case LZ_IMAGE_TYPE_PLT8:
case LZ_IMAGE_TYPE_INVALID:
default:
encoder->usr->error(encoder->usr, "bad image type\n");
}
}
ASSERT(encoder->usr, is_io_to_decode_end(encoder));
ASSERT(encoder->usr, out_size == size);
if (out_size != size) {
encoder->usr->error(encoder->usr, "bad decode size\n");
}
}

View File

@ -1,82 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
dictionary compression for images based on fastlz (http://www.fastlz.org/)
(Distributed under MIT license).
*/
#ifndef __LZ_H
#define __LZ_H
#include "lz_common.h"
#include "lz_config.h"
#include "draw.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *LzContext;
typedef struct LzUsrContext LzUsrContext;
struct LzUsrContext {
void (*error)(LzUsrContext *usr, const char *fmt, ...);
void (*warn)(LzUsrContext *usr, const char *fmt, ...);
void (*info)(LzUsrContext *usr, const char *fmt, ...);
void *(*malloc)(LzUsrContext *usr, int size);
void (*free)(LzUsrContext *usr, void *ptr);
int (*more_space)(LzUsrContext *usr, uint8_t **io_ptr); // get the next chunk of the
// compressed buffer. return
// number of bytes in the chunk.
int (*more_lines)(LzUsrContext *usr, uint8_t **lines); // get the next chunk of the
// original image. If the image
// is down to top, return it from
// the last line to the first one
// (stride should always be
// positive)
};
/*
assumes width is in pixels and stride is in bytes
return: the number of bytes in the compressed data
TODO : determine size limit for the first segment and each chunk. check validity
of the segment or go to literal copy.
TODO : currently support only rgb images in which width*bytes_per_pixel = stride OR
palette images in which stride equals the min number of bytes to
hold a line. stride is not necessary for now. just for sanity check.
stride should be > 0
*/
int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
uint8_t *lines, unsigned int num_lines, int stride,
uint8_t *io_ptr, unsigned int num_io_bytes);
/*
prepare encoder and read lz magic.
out_n_pixels number of compressed pixels. May differ from Width*height in plt1/4.
Use it for allocation the decompressed buffer.
*/
void lz_decode_begin(LzContext *lz, uint8_t *io_ptr, unsigned int num_io_bytes,
LzImageType *out_type, int *out_width, int *out_height,
int *out_n_pixels, int *out_top_down, const SpicePalette *palette);
/*
to_type = the image output type.
We assume the buffer is consecutive. i.e. width = stride
Important: if the image is plt1/4 and to_type is rgb32, the image
will decompressed including the last bits in each line. This means buffer should be
larger than width*height if needed and you should use stride to fix it.
Note: If the image is down to top, set the stride in the sw surface to negative.
use alloc_lz_image_surface create the surface.
*/
void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf);
LzContext *lz_create(LzUsrContext *usr);
void lz_destroy(LzContext *lz);
#ifdef __cplusplus
}
#endif
#endif // __LZ_H

View File

@ -1,69 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*common header for encoder and decoder*/
#ifndef _LZ_COMMON_H
#define _LZ_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
//#define DEBUG
/* change the max window size will require change in the encoding format*/
#define LZ_MAX_WINDOW_SIZE (1 << 25)
#define MAX_COPY 32
typedef enum {
LZ_IMAGE_TYPE_INVALID,
LZ_IMAGE_TYPE_PLT1_LE,
LZ_IMAGE_TYPE_PLT1_BE, // PLT stands for palette
LZ_IMAGE_TYPE_PLT4_LE,
LZ_IMAGE_TYPE_PLT4_BE,
LZ_IMAGE_TYPE_PLT8,
LZ_IMAGE_TYPE_RGB16,
LZ_IMAGE_TYPE_RGB24,
LZ_IMAGE_TYPE_RGB32,
LZ_IMAGE_TYPE_RGBA,
LZ_IMAGE_TYPE_XXXA
} LzImageType;
#define LZ_IMAGE_TYPE_MASK 0x0f
#define LZ_IMAGE_TYPE_LOG 4 // number of bits required for coding the image type
/* access to the arrays is based on the image types */
static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1};
static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4};
#define LZ_MAGIC (*(uint32_t *)"LZ ")
#define LZ_VERSION_MAJOR 1U
#define LZ_VERSION_MINOR 1U
#define LZ_VERSION ((LZ_VERSION_MAJOR << 16) | (LZ_VERSION_MINOR & 0xffff))
#ifdef __cplusplus
}
#endif
#endif // _LZ_COMMON_H

View File

@ -1,529 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc. and/or its affiliates.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
This file incorporates work covered by the following copyright and
permission notice:
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define DJB2_START 5381;
#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;}
/*
For each pixel type the following macros are defined:
PIXEL : input type
FNAME(name)
ENCODE_PIXEL(encoder, pixel) : writing a pixel to the compressed buffer (byte by byte)
SAME_PIXEL(pix1, pix2) : comparing two pixels
HASH_FUNC(value, pix_ptr) : hash func of 3 consecutive pixels
*/
#ifdef LZ_PLT
#define PIXEL one_byte_pixel_t
#define FNAME(name) lz_plt_##name
#define ENCODE_PIXEL(e, pix) encode(e, (pix).a) // gets the pixel and write only the needed bytes
// from the pixel
#define SAME_PIXEL(pix1, pix2) ((pix1).a == (pix2).a)
#define HASH_FUNC(v, p) { \
v = DJB2_START; \
DJB2_HASH(v, p[0].a); \
DJB2_HASH(v, p[1].a); \
DJB2_HASH(v, p[2].a); \
v &= HASH_MASK; \
}
#endif
#ifdef LZ_RGB_ALPHA
//#undef LZ_RGB_ALPHA
#define PIXEL rgb32_pixel_t
#define FNAME(name) lz_rgb_alpha_##name
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).pad);}
#define SAME_PIXEL(pix1, pix2) ((pix1).pad == (pix2).pad)
#define HASH_FUNC(v, p) { \
v = DJB2_START; \
DJB2_HASH(v, p[0].pad); \
DJB2_HASH(v, p[1].pad); \
DJB2_HASH(v, p[2].pad); \
v &= HASH_MASK; \
}
#endif
#ifdef LZ_RGB16
#define PIXEL rgb16_pixel_t
#define FNAME(name) lz_rgb16_##name
#define GET_r(pix) (((pix) >> 10) & 0x1f)
#define GET_g(pix) (((pix) >> 5) & 0x1f)
#define GET_b(pix) ((pix) & 0x1f)
#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);}
#define HASH_FUNC(v, p) { \
v = DJB2_START; \
DJB2_HASH(v, p[0] & (0x00ff)); \
DJB2_HASH(v, (p[0] >> 8) & (0x007f)); \
DJB2_HASH(v, p[1]&(0x00ff)); \
DJB2_HASH(v, (p[1] >> 8) & (0x007f)); \
DJB2_HASH(v, p[2] & (0x00ff)); \
DJB2_HASH(v, (p[2] >> 8) & (0x007f)); \
v &= HASH_MASK; \
}
#endif
#ifdef LZ_RGB24
#define PIXEL rgb24_pixel_t
#define FNAME(name) lz_rgb24_##name
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
#endif
#ifdef LZ_RGB32
#define PIXEL rgb32_pixel_t
#define FNAME(name) lz_rgb32_##name
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
#endif
#if defined(LZ_RGB24) || defined(LZ_RGB32)
#define GET_r(pix) ((pix).r)
#define GET_g(pix) ((pix).g)
#define GET_b(pix) ((pix).b)
#define HASH_FUNC(v, p) { \
v = DJB2_START; \
DJB2_HASH(v, p[0].r); \
DJB2_HASH(v, p[0].g); \
DJB2_HASH(v, p[0].b); \
DJB2_HASH(v, p[1].r); \
DJB2_HASH(v, p[1].g); \
DJB2_HASH(v, p[1].b); \
DJB2_HASH(v, p[2].r); \
DJB2_HASH(v, p[2].g); \
DJB2_HASH(v, p[2].b); \
v &= HASH_MASK; \
}
#endif
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
#define SAME_PIXEL(p1, p2) (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
GET_b(p1) == GET_b(p2))
#endif
#define PIXEL_ID(pix_ptr, seg_ptr) (pix_ptr - ((PIXEL *)seg_ptr->lines) + seg_ptr->size_delta)
// when encoding, the ref can be in previous segment, and we should check that it doesn't
// exceeds its bounds.
// TODO: optimization: when only one chunk exists or when the reference is in the same segment,
// don't make checks if we reach end of segments
// TODO: optimize to continue match between segments?
// TODO: check hash function
// TODO: check times
/* compresses one segment starting from 'from'.*/
static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *from, int copied)
{
const PIXEL *ip = from;
const PIXEL *ip_bound = (PIXEL *)(seg->lines_end) - BOUND_OFFSET;
const PIXEL *ip_limit = (PIXEL *)(seg->lines_end) - LIMIT_OFFSET;
HashEntry *hslot;
int hval;
int copy = copied;
if (copy == 0) {
encode_copy_count(encoder, MAX_COPY - 1);
}
while (LZ_EXPECT_CONDITIONAL(ip < ip_limit)) { // TODO: maybe change ip_limit and enabling
// moving to the next seg
const PIXEL *ref;
const PIXEL *ref_limit;
size_t distance;
/* minimum match length */
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
size_t len = 3;
#elif defined(LZ_RGB16)
size_t len = 2;
#else
size_t len = 1;
#endif
/* comparison starting-point */
const PIXEL *anchor = ip;
// TODO: RLE without checking if not first byte.
// TODO: optimize comparisons
/* check for a run */ // TODO for RGB we can use less pixels
if (LZ_EXPECT_CONDITIONAL(ip > (PIXEL *)(seg->lines))) {
if (SAME_PIXEL(ip[-1], ip[0]) && SAME_PIXEL(ip[0], ip[1]) && SAME_PIXEL(ip[1], ip[2])) {
distance = 1;
ip += 3;
ref = anchor + 2;
ref_limit = (PIXEL *)(seg->lines_end);
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
len = 3;
#endif
goto match;
}
}
/* find potential match */
HASH_FUNC(hval, ip);
hslot = encoder->htab + hval;
ref = (PIXEL *)(hslot->ref);
ref_limit = (PIXEL *)(hslot->image_seg->lines_end);
/* calculate distance to the match */
distance = PIXEL_ID(anchor, seg) - PIXEL_ID(ref, hslot->image_seg);
/* update hash table */
hslot->image_seg = seg;
hslot->ref = (uint8_t *)anchor;
/* is this a match? check the first 3 pixels */
if (distance == 0 || (distance >= MAX_FARDISTANCE)) {
goto literal;
}
/* check if the hval key identical*/
// no need to check ref limit here because the word size in the htab is 3 pixels
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
goto literal;
}
ref++;
ip++;
/* minimum match length for rgb16 is 2 and for plt and alpha is 3 */
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16)
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
goto literal;
}
ref++;
ip++;
#endif
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
goto literal;
}
ref++;
ip++;
#endif
/* far, needs at least 5-byte match */
if (distance >= MAX_DISTANCE) {
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
if (ref >= (ref_limit - 1)) {
goto literal;
}
#else
if (ref > (ref_limit - 1)) {
goto literal;
}
#endif
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
goto literal;
}
ref++;
ip++;
len++;
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
goto literal;
}
ref++;
ip++;
len++;
#endif
}
match: // RLE or dictionary (both are encoded by distance from ref (-1) and length)
/* distance is biased */
distance--;
// ip is located now at the position of the second mismatch.
// later it will be subtracted by 3
if (!distance) {
/* zero distance means a run */
PIXEL x = *ref;
while ((ip < ip_bound) && (ref < ref_limit)) { // TODO: maybe separate a run from
// the same seg or from different
// ones in order to spare
// ref < ref_limit
if (!SAME_PIXEL(*ref, x)) {
ref++;
break;
} else {
ref++;
ip++;
}
}
} else {
// TODO: maybe separate a run from the same seg or from different ones in order
// to spare ref < ref_limit and that way we can also perform 8 calls of
// (ref++ != ip++) outside a loop
for (;;) {
while ((ip < ip_bound) && (ref < ref_limit)) {
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
break;
} else {
ref++;
ip++;
}
}
break;
}
}
/* if we have copied something, adjust the copy count */
if (copy) {
/* copy is biased, '0' means 1 byte copy */
update_copy_count(encoder, copy - 1);
} else {
/* back, to overwrite the copy count */
compress_output_prev(encoder);
}
/* reset literal counter */
copy = 0;
/* length is biased, '1' means a match of 3 pixels for PLT and alpha*/
/* for RGB 16 1 means 2 */
/* for RGB24/32 1 means 1...*/
ip -= 3;
len = ip - anchor;
#if defined(LZ_RGB16)
len++;
#elif defined(LZ_RGB24) || defined(LZ_RGB32)
len += 2;
#endif
/* encode the match (like fastlz level 2)*/
if (distance < MAX_DISTANCE) { // MAX_DISTANCE is 2^13 - 1
// when copy is performed, the byte that holds the copy count is smaller than 32.
// When there is a reference, the first byte is always larger then 32
// 3 bits = length, 5 bits = 5 MSB of distance, 8 bits = 8 LSB of distance
if (len < 7) {
encode(encoder, (uint8_t)((len << 5) + (distance >> 8)));
encode(encoder, (uint8_t)(distance & 255));
} else { // more than 3 bits are needed for length
// 3 bits 7, 5 bits = 5 MSB of distance, next bytes are 255 till we
// receive a smaller number, last byte = 8 LSB of distance
encode(encoder, (uint8_t)((7 << 5) + (distance >> 8)));
for (len -= 7; len >= 255; len -= 255) {
encode(encoder, 255);
}
encode(encoder, (uint8_t)len);
encode(encoder, (uint8_t)(distance & 255));
}
} else {
/* far away */
if (len < 7) { // the max_far_distance is ~2^16+2^13 so two more bytes are needed
// 3 bits = length, 5 bits = 5 MSB of MAX_DISTANCE, 8 bits = 8 LSB of MAX_DISTANCE,
// 8 bits = 8 MSB distance-MAX_distance (smaller than 2^16),8 bits=8 LSB of
// distance-MAX_distance
distance -= MAX_DISTANCE;
encode(encoder, (uint8_t)((len << 5) + 31));
encode(encoder, (uint8_t)255);
encode(encoder, (uint8_t)(distance >> 8));
encode(encoder, (uint8_t)(distance & 255));
} else {
// same as before, but the first byte is followed by the left overs of len
distance -= MAX_DISTANCE;
encode(encoder, (uint8_t)((7 << 5) + 31));
for (len -= 7; len >= 255; len -= 255) {
encode(encoder, 255);
}
encode(encoder, (uint8_t)len);
encode(encoder, 255);
encode(encoder, (uint8_t)(distance >> 8));
encode(encoder, (uint8_t)(distance & 255));
}
}
/* update the hash at match boundary */
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
if (ip > anchor) {
#endif
HASH_FUNC(hval, ip);
encoder->htab[hval].ref = (uint8_t *)ip;
ip++;
encoder->htab[hval].image_seg = seg;
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
} else {ip++;
}
#endif
#if defined(LZ_RGB24) || defined(LZ_RGB32)
if (ip > anchor) {
#endif
HASH_FUNC(hval, ip);
encoder->htab[hval].ref = (uint8_t *)ip;
ip++;
encoder->htab[hval].image_seg = seg;
#if defined(LZ_RGB24) || defined(LZ_RGB32)
} else {ip++;
}
#endif
/* assuming literal copy */
encode_copy_count(encoder, MAX_COPY - 1);
continue;
literal:
ENCODE_PIXEL(encoder, *anchor);
anchor++;
ip = anchor;
copy++;
if (LZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) {
copy = 0;
encode_copy_count(encoder, MAX_COPY - 1);
}
} // END LOOP (ip < ip_limit)
/* left-over as literal copy */
ip_bound++;
while (ip <= ip_bound) {
ENCODE_PIXEL(encoder, *ip);
ip++;
copy++;
if (copy == MAX_COPY) {
copy = 0;
encode_copy_count(encoder, MAX_COPY - 1);
}
}
/* if we have copied something, adjust the copy length */
if (copy) {
update_copy_count(encoder, copy - 1);
} else {
compress_output_prev(encoder); // in case we created a new buffer for copy, check that
// red_worker could handle size that do not contain the
// ne buffer
}
}
/* initializes the hash table. if the file is very small, copies it.
copies the first two pixels of the first segment, and sends the segments
one by one to compress_seg.
the number of bytes compressed are stored inside encoder.
*/
static void FNAME(compress)(Encoder *encoder)
{
LzImageSegment *cur_seg = encoder->head_image_segs;
HashEntry *hslot;
PIXEL *ip;
// fetch the first image segment that is not too small
while (cur_seg && ((((PIXEL *)cur_seg->lines_end) - ((PIXEL *)cur_seg->lines)) < 4)) {
// coping the segment
if (cur_seg->lines != cur_seg->lines_end) {
ip = (PIXEL *)cur_seg->lines;
// Note: we assume MAX_COPY > 3
encode_copy_count(encoder, (uint8_t)(
(((PIXEL *)cur_seg->lines_end) - ((PIXEL *)cur_seg->lines)) - 1));
while (ip < (PIXEL *)cur_seg->lines_end) {
ENCODE_PIXEL(encoder, *ip);
ip++;
}
}
cur_seg = cur_seg->next;
}
if (!cur_seg) {
return;
}
ip = (PIXEL *)cur_seg->lines;
/* initialize hash table */
for (hslot = encoder->htab; hslot < encoder->htab + HASH_SIZE; hslot++) {
hslot->ref = (uint8_t*)ip;
hslot->image_seg = cur_seg;
}
encode_copy_count(encoder, MAX_COPY - 1);
ENCODE_PIXEL(encoder, *ip);
ip++;
ENCODE_PIXEL(encoder, *ip);
ip++;
// compressing the first segment
FNAME(compress_seg)(encoder, cur_seg, ip, 2);
// compressing the next segments
for (cur_seg = cur_seg->next; cur_seg; cur_seg = cur_seg->next) {
FNAME(compress_seg)(encoder, cur_seg, (PIXEL *)cur_seg->lines, 0);
}
}
#undef FNAME
#undef PIXEL_ID
#undef PIXEL
#undef ENCODE_PIXEL
#undef SAME_PIXEL
#undef LZ_READU16
#undef HASH_FUNC
#undef BYTES_TO_16
#undef HASH_FUNC_16
#undef GET_r
#undef GET_g
#undef GET_b
#undef GET_CODE
#undef LZ_PLT
#undef LZ_RGB_ALPHA
#undef LZ_RGB16
#undef LZ_RGB24
#undef LZ_RGB32
#undef HASH_FUNC2

View File

@ -1,39 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __LZ_CONFIG_H
#define __LZ_CONFIG_H
#include <spice/types.h>
#include <spice/macros.h>
#ifdef __GNUC__
#include <string.h>
#else
#ifdef QXLDD
#include <windef.h>
#include "os_dep.h"
#else
#include <stddef.h>
#include <string.h>
#endif // QXLDD
#endif //__GNUC__
#endif //__LZ_CONFIG_H

View File

@ -1,326 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc. and/or its affiliates.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
This file incorporates work covered by the following copyright and
permission notice:
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// External defines: PLT, RGBX/PLTXX/ALPHA, TO_RGB32.
// If PLT4/1 and TO_RGB32 are defined, we need CAST_PLT_DISTANCE (because then the number of
// pixels differ from the units used in the compression)
/*
For each output pixel type the following macros are defined:
OUT_PIXEL - the output pixel type
COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and increases
out. Used in RLE. Need special handling because in alpha we
copy only the pad byte.
COPY_REF_PIXEL(ref, out) - copies the pixel pointed by ref to the pixel pointed by out.
Increases ref and out.
COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
buffer. Increases out.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if !defined(LZ_RGB_ALPHA)
#define COPY_PIXEL(p, out) (*out++ = p)
#define COPY_REF_PIXEL(ref, out) (*out++ = *ref++)
#endif
// decompressing plt to plt
#ifdef LZ_PLT
#ifndef TO_RGB32
#define OUT_PIXEL one_byte_pixel_t
#define FNAME(name) lz_plt_##name
#define COPY_COMP_PIXEL(encoder, out) {out->a = decode(encoder); out++;}
#else // TO_RGB32
#define OUT_PIXEL rgb32_pixel_t
#define COPY_PLT_ENTRY(ent, out) { \
(out)->b = ent; \
(out)->g = (ent >> 8); \
(out)->r = (ent >> 16); \
(out)->pad = 0; \
}
#ifdef PLT8
#define FNAME(name) lz_plt8_to_rgb32_##name
#define COPY_COMP_PIXEL(encoder, out) { \
uint32_t rgb = encoder->palette->ents[decode(encoder)]; \
COPY_PLT_ENTRY(rgb, out); \
out++;}
#elif defined(PLT4_BE)
#define FNAME(name) lz_plt4_be_to_rgb32_##name
#define COPY_COMP_PIXEL(encoder, out){ \
uint8_t byte = decode(encoder); \
uint32_t rgb = encoder->palette->ents[((byte >> 4) & 0x0f) % (encoder->palette->num_ents)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
rgb = encoder->palette->ents[(byte & 0x0f) % (encoder->palette->num_ents)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
}
#define CAST_PLT_DISTANCE(dist) (dist*2)
#elif defined(PLT4_LE)
#define FNAME(name) lz_plt4_le_to_rgb32_##name
#define COPY_COMP_PIXEL(encoder, out){ \
uint8_t byte = decode(encoder); \
uint32_t rgb = encoder->palette->ents[(byte & 0x0f) % (encoder->palette->num_ents)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
rgb = encoder->palette->ents[((byte >> 4) & 0x0f) % (encoder->palette->num_ents)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
}
#define CAST_PLT_DISTANCE(dist) (dist*2)
#elif defined(PLT1_BE) // TODO store palette entries for direct access
#define FNAME(name) lz_plt1_be_to_rgb32_##name
#define COPY_COMP_PIXEL(encoder, out){ \
uint8_t byte = decode(encoder); \
int i; \
uint32_t fore = encoder->palette->ents[1]; \
uint32_t back = encoder->palette->ents[0]; \
for (i = 7; i >= 0; i--) \
{ \
if ((byte >> i) & 1) { \
COPY_PLT_ENTRY(fore, out); \
} else { \
COPY_PLT_ENTRY(back, out); \
} \
out++; \
} \
}
#define CAST_PLT_DISTANCE(dist) (dist*8)
#elif defined(PLT1_LE)
#define FNAME(name) lz_plt1_le_to_rgb32_##name
#define COPY_COMP_PIXEL(encoder, out){ \
uint8_t byte = decode(encoder); \
int i; \
uint32_t fore = encoder->palette->ents[1]; \
uint32_t back = encoder->palette->ents[0]; \
for (i = 0; i < 8; i++) \
{ \
if ((byte >> i) & 1) { \
COPY_PLT_ENTRY(fore, out); \
} else { \
COPY_PLT_ENTRY(back, out); \
} \
out++; \
} \
}
#define CAST_PLT_DISTANCE(dist) (dist*8)
#endif // PLT Type
#endif // TO_RGB32
#endif
#ifdef LZ_RGB16
#ifndef TO_RGB32
#define OUT_PIXEL rgb16_pixel_t
#define FNAME(name) lz_rgb16_##name
#define COPY_COMP_PIXEL(e, out) {*out = ((decode(e) << 8) | decode(e)); out++;}
#else
#define OUT_PIXEL rgb32_pixel_t
#define FNAME(name) lz_rgb16_to_rgb32_##name
#define COPY_COMP_PIXEL(e, out) { \
out->r = decode(e); \
out->b = decode(e); \
out->g = (((out->r) << 6) | ((out->b) >> 2)) & ~0x07; \
out->g |= (out->g >> 5); \
out->r = ((out->r << 1) & ~0x07)| ((out->r >> 4) & 0x07); \
out->b = (out->b << 3) | ((out->b >> 2) & 0x07); \
out->pad = 0; \
out++; \
}
#endif
#endif
#ifdef LZ_RGB24
#define OUT_PIXEL rgb24_pixel_t
#define FNAME(name) lz_rgb24_##name
#define COPY_COMP_PIXEL(e, out) {out->b = decode(e); out->g = decode(e); out->r = decode(e); out++;}
#endif
#ifdef LZ_RGB32
#define OUT_PIXEL rgb32_pixel_t
#define FNAME(name) lz_rgb32_##name
#define COPY_COMP_PIXEL(e, out) { \
out->b = decode(e); \
out->g = decode(e); \
out->r = decode(e); \
out->pad = 0; \
out++; \
}
#endif
#ifdef LZ_RGB_ALPHA
#define OUT_PIXEL rgb32_pixel_t
#define FNAME(name) lz_rgb_alpha_##name
#define COPY_PIXEL(p, out) {out->pad = p.pad; out++;}
#define COPY_REF_PIXEL(ref, out) {out->pad = ref->pad; out++; ref++;}
#define COPY_COMP_PIXEL(e, out) {out->pad = decode(e); out++;}
#endif
// return num of bytes in out_buf
static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
{
OUT_PIXEL *op = out_buf;
OUT_PIXEL *op_limit = out_buf + size;
uint32_t ctrl = decode(encoder);
int loop = TRUE;
do {
const OUT_PIXEL *ref = op;
uint32_t len = ctrl >> 5;
uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
/* retrieving the reference and the match length */
uint8_t code;
len--;
//ref -= ofs;
if (len == 7 - 1) { // match length is bigger than 7
do {
code = decode(encoder);
len += code;
} while (code == 255); // remaining of len
}
code = decode(encoder);
ofs += code;
/* match from 16-bit distance */
if (LZ_UNEXPECT_CONDITIONAL(code == 255)) {
if (LZ_EXPECT_CONDITIONAL((ofs - code) == (31 << 8))) {
ofs = decode(encoder) << 8;
ofs += decode(encoder);
ofs += MAX_DISTANCE;
}
}
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
len += 3; // length is biased by 2 + 1 (fixing bias)
#elif defined(LZ_RGB16)
len += 2; // length is biased by 1 + 1 (fixing bias)
#else
len += 1;
#endif
ofs += 1; // offset is biased by 1 (fixing bias)
#if defined(TO_RGB32)
#if defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || defined(PLT1_LE)
ofs = CAST_PLT_DISTANCE(ofs);
len = CAST_PLT_DISTANCE(len);
#endif
#endif
ref -= ofs;
ASSERT(encoder->usr, op + len <= op_limit);
ASSERT(encoder->usr, ref + len <= op_limit);
ASSERT(encoder->usr, ref >= out_buf);
// TODO: optimize by not calling loop at least 3 times when not PLT_TO_RGB32 (len is
// always >=3). in PLT_TO_RGB32 len >= 3*number_of_pixels_per_byte
/* copying the match*/
if (ref == (op - 1)) { // run // TODO: this will never be called in PLT4/1_TO_RGB
// because the number of pixel copied is larger
// then one...
/* optimize copy for a run */
OUT_PIXEL b = *ref;
for (; len; --len) {
COPY_PIXEL(b, op);
ASSERT(encoder->usr, op <= op_limit);
}
} else {
for (; len; --len) {
COPY_REF_PIXEL(ref, op);
ASSERT(encoder->usr, op <= op_limit);
}
}
} else { // copy
ctrl++; // copy count is biased by 1
#if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \
defined(PLT1_LE))
ASSERT(encoder->usr, op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
#else
ASSERT(encoder->usr, op + ctrl <= op_limit);
#endif
COPY_COMP_PIXEL(encoder, op);
ASSERT(encoder->usr, op <= op_limit);
for (--ctrl; ctrl; ctrl--) {
COPY_COMP_PIXEL(encoder, op);
ASSERT(encoder->usr, op <= op_limit);
}
}
if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
ctrl = decode(encoder);
} else {
loop = FALSE;
}
} while (LZ_EXPECT_CONDITIONAL(loop));
return (op - out_buf);
}
#undef LZ_PLT
#undef PLT8
#undef PLT4_BE
#undef PLT4_LE
#undef PLT1_BE
#undef PLT1_LE
#undef LZ_RGB16
#undef LZ_RGB24
#undef LZ_RGB32
#undef LZ_RGB_ALPHA
#undef TO_RGB32
#undef OUT_PIXEL
#undef FNAME
#undef COPY_PIXEL
#undef COPY_REF_PIXEL
#undef COPY_COMP_PIXEL
#undef COPY_PLT_ENTRY
#undef CAST_PLT_DISTANCE

View File

@ -1,615 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "marshaller.h"
#include "mem.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#ifdef WORDS_BIGENDIAN
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = SPICE_BYTESWAP64((uint64_t)(v)))
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = SPICE_BYTESWAP64((uint64_t)(v)))
#else
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = v)
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = v)
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = v)
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = v)
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = v)
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = v)
#endif
typedef struct {
uint8_t *data;
size_t len;
spice_marshaller_item_free_func free_data;
void *opaque;
} MarshallerItem;
/* Try to fit in 4k page with 2*pointer-size overhead (next ptr and malloc size) */
#define MARSHALLER_BUFFER_SIZE (4096 - sizeof(void *) * 2)
typedef struct MarshallerBuffer MarshallerBuffer;
struct MarshallerBuffer {
MarshallerBuffer *next;
uint8_t data[MARSHALLER_BUFFER_SIZE];
};
#define N_STATIC_ITEMS 4
typedef struct SpiceMarshallerData SpiceMarshallerData;
typedef struct {
SpiceMarshaller *marshaller;
int item_nr;
int is_64bit;
size_t offset;
} MarshallerRef;
struct SpiceMarshaller {
size_t total_size;
SpiceMarshallerData *data;
SpiceMarshaller *next;
MarshallerRef pointer_ref;
int n_items;
int items_size; /* number of items availible in items */
MarshallerItem *items;
MarshallerItem static_items[N_STATIC_ITEMS];
};
struct SpiceMarshallerData {
size_t total_size;
size_t base;
SpiceMarshaller *marshallers;
SpiceMarshaller *last_marshaller;
size_t current_buffer_position;
MarshallerBuffer *current_buffer;
MarshallerItem *current_buffer_item;
MarshallerBuffer *buffers;
SpiceMarshaller static_marshaller;
MarshallerBuffer static_buffer;
};
static void spice_marshaller_init(SpiceMarshaller *m,
SpiceMarshallerData *data)
{
m->data = data;
m->next = NULL;
m->total_size = 0;
m->pointer_ref.marshaller = NULL;
m->n_items = 0;
m->items_size = N_STATIC_ITEMS;
m->items = m->static_items;
}
SpiceMarshaller *spice_marshaller_new(void)
{
SpiceMarshallerData *d;
SpiceMarshaller *m;
d = spice_new(SpiceMarshallerData, 1);
d->last_marshaller = d->marshallers = &d->static_marshaller;
d->total_size = 0;
d->base = 0;
d->buffers = &d->static_buffer;
d->buffers->next = NULL;
d->current_buffer = d->buffers;
d->current_buffer_position = 0;
d->current_buffer_item = NULL;
m = &d->static_marshaller;
spice_marshaller_init(m, d);
return m;
}
static void free_item_data(SpiceMarshaller *m)
{
MarshallerItem *item;
int i;
/* Free all user data */
for (i = 0; i < m->n_items; i++) {
item = &m->items[i];
if (item->free_data != NULL) {
item->free_data(item->data, item->opaque);
}
}
}
static void free_items(SpiceMarshaller *m)
{
if (m->items != m->static_items) {
free(m->items);
}
}
void spice_marshaller_reset(SpiceMarshaller *m)
{
SpiceMarshaller *m2, *next;
SpiceMarshallerData *d;
/* Only supported for root marshaller */
assert(m->data->marshallers == m);
for (m2 = m; m2 != NULL; m2 = next) {
next = m2->next;
free_item_data(m2);
/* Free non-root marshallers */
if (m2 != m) {
free_items(m2);
free(m2);
}
}
m->next = NULL;
m->n_items = 0;
m->total_size = 0;
d = m->data;
d->last_marshaller = d->marshallers;
d->total_size = 0;
d->base = 0;
d->current_buffer_item = NULL;
d->current_buffer = d->buffers;
d->current_buffer_position = 0;
}
void spice_marshaller_destroy(SpiceMarshaller *m)
{
MarshallerBuffer *buf, *next;
SpiceMarshallerData *d;
/* Only supported for root marshaller */
assert(m->data->marshallers == m);
spice_marshaller_reset(m);
free_items(m);
d = m->data;
buf = d->buffers->next;
while (buf != NULL) {
next = buf->next;
free(buf);
buf = next;
}
free(d);
}
static MarshallerItem *spice_marshaller_add_item(SpiceMarshaller *m)
{
MarshallerItem *item;
if (m->n_items == m->items_size) {
int items_size = m->items_size * 2;
if (m->items == m->static_items) {
m->items = spice_new(MarshallerItem, items_size);
memcpy(m->items, m->static_items, sizeof(MarshallerItem) * m->n_items);
} else {
m->items = spice_renew(MarshallerItem, m->items, items_size);
}
m->items_size = items_size;
}
item = &m->items[m->n_items++];
item->free_data = NULL;
return item;
}
static size_t remaining_buffer_size(SpiceMarshallerData *d)
{
return MARSHALLER_BUFFER_SIZE - d->current_buffer_position;
}
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
{
MarshallerItem *item;
SpiceMarshallerData *d;
uint8_t *res;
if (size == 0) {
return NULL;
}
d = m->data;
/* Check current item */
item = &m->items[m->n_items - 1];
if (item == d->current_buffer_item &&
remaining_buffer_size(d) >= size) {
assert(m->n_items >= 1);
/* We can piggy back on existing item+buffer */
res = item->data + item->len;
item->len += size;
d->current_buffer_position += size;
d->total_size += size;
m->total_size += size;
return res;
}
item = spice_marshaller_add_item(m);
if (remaining_buffer_size(d) >= size) {
/* Fits in current buffer */
item->data = d->current_buffer->data + d->current_buffer_position;
item->len = size;
d->current_buffer_position += size;
d->current_buffer_item = item;
} else if (size > MARSHALLER_BUFFER_SIZE / 2) {
/* Large item, allocate by itself */
item->data = (uint8_t *)spice_malloc(size);
item->len = size;
item->free_data = (spice_marshaller_item_free_func)free;
item->opaque = NULL;
} else {
/* Use next buffer */
if (d->current_buffer->next == NULL) {
d->current_buffer->next = spice_new(MarshallerBuffer, 1);
d->current_buffer->next->next = NULL;
}
d->current_buffer = d->current_buffer->next;
d->current_buffer_position = size;
d->current_buffer_item = item;
item->data = d->current_buffer->data;
item->len = size;
}
d->total_size += size;
m->total_size += size;
return item->data;
}
void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size)
{
MarshallerItem *item;
if (size == 0) {
return;
}
item = &m->items[m->n_items - 1];
assert(item->len >= size);
item->len -= size;
}
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
spice_marshaller_item_free_func free_data, void *opaque)
{
MarshallerItem *item;
SpiceMarshallerData *d;
if (data == NULL || size == 0) {
return NULL;
}
item = spice_marshaller_add_item(m);
item->data = data;
item->len = size;
item->free_data = free_data;
item->opaque = opaque;
d = m->data;
m->total_size += size;
d->total_size += size;
return data;
}
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, size);
memcpy(ptr, data, size);
return ptr;
}
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size)
{
return spice_marshaller_add_ref_full(m, data, size, NULL, NULL);
}
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks)
{
unsigned int i;
for (i = 0; i < chunks->num_chunks; i++) {
spice_marshaller_add_ref(m, chunks->chunk[i].data,
chunks->chunk[i].len);
}
}
SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m)
{
SpiceMarshallerData *d;
SpiceMarshaller *m2;
d = m->data;
m2 = spice_new(SpiceMarshaller, 1);
spice_marshaller_init(m2, d);
d->last_marshaller->next = m2;
d->last_marshaller = m2;
return m2;
}
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit)
{
SpiceMarshaller *m2;
uint8_t *p;
int size;
size = is_64bit ? 8 : 4;
p = spice_marshaller_reserve_space(m, size);
memset(p, 0, size);
m2 = spice_marshaller_get_submarshaller(m);
m2->pointer_ref.marshaller = m;
m2->pointer_ref.item_nr = m->n_items - 1;
m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
m2->pointer_ref.is_64bit = is_64bit;
return m2;
}
uint8_t *lookup_ref(MarshallerRef *ref)
{
MarshallerItem *item;
item = &ref->marshaller->items[ref->item_nr];
return item->data + ref->offset;
}
void spice_marshaller_set_base(SpiceMarshaller *m, size_t base)
{
/* Only supported for root marshaller */
assert(m->data->marshallers == m);
m->data->base = base;
}
uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip_bytes,
size_t *len, int *free_res)
{
MarshallerItem *item;
uint8_t *res, *p;
int i;
/* Only supported for root marshaller */
assert(m->data->marshallers == m);
if (m->n_items == 1) {
*free_res = FALSE;
if (m->items[0].len <= skip_bytes) {
*len = 0;
return NULL;
}
*len = m->items[0].len - skip_bytes;
return m->items[0].data + skip_bytes;
}
*free_res = TRUE;
res = (uint8_t *)spice_malloc(m->data->total_size - skip_bytes);
*len = m->data->total_size - skip_bytes;
p = res;
do {
for (i = 0; i < m->n_items; i++) {
item = &m->items[i];
if (item->len <= skip_bytes) {
skip_bytes -= item->len;
continue;
}
memcpy(p, item->data + skip_bytes, item->len - skip_bytes);
p += item->len - skip_bytes;
skip_bytes = 0;
}
m = m->next;
} while (m != NULL);
return res;
}
uint8_t *spice_marshaller_get_ptr(SpiceMarshaller *m)
{
return m->items[0].data;
}
size_t spice_marshaller_get_offset(SpiceMarshaller *m)
{
SpiceMarshaller *m2;
size_t offset;
offset = 0;
m2 = m->data->marshallers;
while (m2 != m) {
offset += m2->total_size;
m2 = m2->next;
}
return offset - m->data->base;
}
size_t spice_marshaller_get_size(SpiceMarshaller *m)
{
return m->total_size;
}
size_t spice_marshaller_get_total_size(SpiceMarshaller *m)
{
return m->data->total_size;
}
void spice_marshaller_flush(SpiceMarshaller *m)
{
SpiceMarshaller *m2;
uint8_t *ptr_pos;
/* Only supported for root marshaller */
assert(m->data->marshallers == m);
for (m2 = m; m2 != NULL; m2 = m2->next) {
if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
ptr_pos = lookup_ref(&m2->pointer_ref);
if (m2->pointer_ref.is_64bit) {
write_uint64(ptr_pos,
spice_marshaller_get_offset(m2));
} else {
write_uint32(ptr_pos,
spice_marshaller_get_offset(m2));
}
}
}
}
#ifndef WIN32
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
int n_vec, size_t skip_bytes)
{
MarshallerItem *item;
int v, i;
/* Only supported for root marshaller */
assert(m->data->marshallers == m);
v = 0;
do {
for (i = 0; i < m->n_items; i++) {
item = &m->items[i];
if (item->len <= skip_bytes) {
skip_bytes -= item->len;
continue;
}
if (v == n_vec) {
return v; /* Not enough space in vec */
}
vec[v].iov_base = (void *)item->data + skip_bytes;
vec[v].iov_len = item->len - skip_bytes;
skip_bytes = 0;
v++;
}
m = m->next;
} while (m != NULL);
return v;
}
#endif
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, sizeof(uint64_t));
write_uint64(ptr, v);
return (void *)ptr;
}
void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, sizeof(int64_t));
write_int64(ptr, v);
return (void *)ptr;
}
void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, sizeof(uint32_t));
write_uint32(ptr, v);
return (void *)ptr;
}
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v)
{
write_uint32((uint8_t *)ref, v);
}
void *spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, sizeof(int32_t));
write_int32(ptr, v);
return (void *)ptr;
}
void *spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, sizeof(uint16_t));
write_uint16(ptr, v);
return (void *)ptr;
}
void *spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, sizeof(int16_t));
write_int16(ptr, v);
return (void *)ptr;
}
void *spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, sizeof(uint8_t));
write_uint8(ptr, v);
return (void *)ptr;
}
void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
{
uint8_t *ptr;
ptr = spice_marshaller_reserve_space(m, sizeof(int8_t));
write_int8(ptr, v);
return (void *)ptr;
}

View File

@ -1,74 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MARSHALLER
#define _H_MARSHALLER
#include <spice/types.h>
#include "mem.h"
#ifndef WIN32
#include <sys/uio.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct SpiceMarshaller SpiceMarshaller;
typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
SpiceMarshaller *spice_marshaller_new(void);
void spice_marshaller_reset(SpiceMarshaller *m);
void spice_marshaller_destroy(SpiceMarshaller *m);
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size);
void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size);
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size);
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size);
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
spice_marshaller_item_free_func free_data, void *opaque);
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks);
void spice_marshaller_flush(SpiceMarshaller *m);
void spice_marshaller_set_base(SpiceMarshaller *m, size_t base);
uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip,
size_t *len, int *free_res);
uint8_t *spice_marshaller_get_ptr(SpiceMarshaller *m);
size_t spice_marshaller_get_offset(SpiceMarshaller *m);
size_t spice_marshaller_get_size(SpiceMarshaller *m);
size_t spice_marshaller_get_total_size(SpiceMarshaller *m);
SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m);
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit);
#ifndef WIN32
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
int n_vec, size_t skip_bytes);
#endif
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
void *spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v);
void *spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v);
void *spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v);
void *spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v);
void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v);
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,297 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "mem.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef MALLOC_ERROR
#define MALLOC_ERROR(format, ...) { \
printf(format "\n", ## __VA_ARGS__); \
abort(); \
}
#endif
size_t spice_strnlen(const char *str, size_t max_len)
{
size_t len = 0;
while (len < max_len && *str != 0) {
len++;
str++;
}
return len;
}
char *spice_strdup(const char *str)
{
char *copy;
if (str == NULL) {
return NULL;
}
copy = (char *)spice_malloc(strlen(str) + 1);
strcpy(copy, str);
return copy;
}
char *spice_strndup(const char *str, size_t n_bytes)
{
char *copy;
if (str == NULL) {
return NULL;
}
copy = (char *)spice_malloc(n_bytes + 1);
strncpy(copy, str, n_bytes);
copy[n_bytes] = 0;
return copy;
}
void *spice_memdup(const void *mem, size_t n_bytes)
{
void *copy;
if (mem == NULL) {
return NULL;
}
copy = spice_malloc(n_bytes);
memcpy(copy, mem, n_bytes);
return copy;
}
void *spice_malloc(size_t n_bytes)
{
void *mem;
if (SPICE_LIKELY(n_bytes)) {
mem = malloc(n_bytes);
if (SPICE_LIKELY(mem != NULL)) {
return mem;
}
MALLOC_ERROR("spice_malloc: panic: unable to allocate %lu bytes\n",
(unsigned long)n_bytes);
}
return NULL;
}
void *spice_malloc0(size_t n_bytes)
{
void *mem;
if (SPICE_LIKELY(n_bytes)) {
mem = calloc(1, n_bytes);
if (SPICE_LIKELY(mem != NULL)) {
return mem;
}
MALLOC_ERROR("spice_malloc0: panic: unable to allocate %lu bytes\n",
(unsigned long)n_bytes);
}
return NULL;
}
void *spice_realloc(void *mem, size_t n_bytes)
{
if (SPICE_LIKELY(n_bytes)) {
mem = realloc(mem, n_bytes);
if (SPICE_LIKELY(mem != NULL)) {
return mem;
}
MALLOC_ERROR("spice_realloc: panic: unable to allocate %lu bytes\n",
(unsigned long)n_bytes);
}
free(mem);
return NULL;
}
#define SIZE_OVERFLOWS(a,b) (SPICE_UNLIKELY ((a) > SIZE_MAX / (b)))
void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes)
{
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
MALLOC_ERROR("spice_malloc_n: overflow allocating %lu*%lu bytes",
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
}
return spice_malloc(n_blocks * n_block_bytes);
}
void *spice_malloc_n_m(size_t n_blocks, size_t n_block_bytes, size_t extra_size)
{
size_t size1, size2;
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
MALLOC_ERROR("spice_malloc_n: overflow allocating %lu*%lu + %lubytes",
(unsigned long)n_blocks, (unsigned long)n_block_bytes, (unsigned long)extra_size);
}
size1 = n_blocks * n_block_bytes;
size2 = size1 + extra_size;
if (size2 < size1) {
MALLOC_ERROR("spice_malloc_n: overflow allocating %lu*%lu + %lubytes",
(unsigned long)n_blocks, (unsigned long)n_block_bytes, (unsigned long)extra_size);
}
return spice_malloc(size2);
}
void *spice_malloc0_n(size_t n_blocks, size_t n_block_bytes)
{
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
MALLOC_ERROR("spice_malloc0_n: overflow allocating %lu*%lu bytes",
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
}
return spice_malloc0 (n_blocks * n_block_bytes);
}
void *spice_realloc_n(void *mem, size_t n_blocks, size_t n_block_bytes)
{
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
MALLOC_ERROR("spice_realloc_n: overflow allocating %lu*%lu bytes",
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
}
return spice_realloc(mem, n_blocks * n_block_bytes);
}
SpiceChunks *spice_chunks_new(uint32_t count)
{
SpiceChunks *chunks;
chunks = (SpiceChunks *)spice_malloc_n_m(count, sizeof(SpiceChunk), sizeof(SpiceChunks));
chunks->flags = 0;
chunks->num_chunks = count;
return chunks;
}
SpiceChunks *spice_chunks_new_linear(uint8_t *data, uint32_t len)
{
SpiceChunks *chunks;
chunks = spice_chunks_new(1);
chunks->data_size = chunks->chunk[0].len = len;
chunks->chunk[0].data = data;
return chunks;
}
void spice_chunks_destroy(SpiceChunks *chunks)
{
unsigned int i;
if (chunks->flags & SPICE_CHUNKS_FLAGS_FREE) {
for (i = 0; i < chunks->num_chunks; i++) {
free(chunks->chunk[i].data);
}
}
free(chunks);
}
void spice_chunks_linearize(SpiceChunks *chunks)
{
uint8_t *data, *p;
unsigned int i;
if (chunks->num_chunks > 1) {
data = (uint8_t*)spice_malloc(chunks->data_size);
for (p = data, i = 0; i < chunks->num_chunks; i++) {
memcpy(p, chunks->chunk[i].data,
chunks->chunk[i].len);
p += chunks->chunk[i].len;
}
if (chunks->flags & SPICE_CHUNKS_FLAGS_FREE) {
for (i = 0; i < chunks->num_chunks; i++) {
free(chunks->chunk[i].data);
}
}
chunks->num_chunks = 1;
chunks->flags |= SPICE_CHUNKS_FLAGS_FREE;
chunks->flags &= ~SPICE_CHUNKS_FLAGS_UNSTABLE;
chunks->chunk[0].data = data;
chunks->chunk[0].len = chunks->data_size;
}
}
void spice_buffer_reserve(SpiceBuffer *buffer, size_t len)
{
if ((buffer->capacity - buffer->offset) < len) {
buffer->capacity += (len + 1024);
buffer->buffer = (uint8_t*)spice_realloc(buffer->buffer, buffer->capacity);
}
}
int spice_buffer_empty(SpiceBuffer *buffer)
{
return buffer->offset == 0;
}
uint8_t *spice_buffer_end(SpiceBuffer *buffer)
{
return buffer->buffer + buffer->offset;
}
void spice_buffer_reset(SpiceBuffer *buffer)
{
buffer->offset = 0;
}
void spice_buffer_free(SpiceBuffer *buffer)
{
free(buffer->buffer);
buffer->offset = 0;
buffer->capacity = 0;
buffer->buffer = NULL;
}
void spice_buffer_append(SpiceBuffer *buffer, const void *data, size_t len)
{
spice_buffer_reserve(buffer, len);
memcpy(buffer->buffer + buffer->offset, data, len);
buffer->offset += len;
}
size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len)
{
len = MIN(buffer->offset, len);
memcpy(dest, buffer->buffer, len);
return len;
}
size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len)
{
len = MIN(buffer->offset, len);
memmove(buffer->buffer, buffer->buffer + len, buffer->offset - len);
buffer->offset -= len;
return len;
}

View File

@ -1,162 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MEM
#define _H_MEM
#include <stdlib.h>
#include <spice/macros.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#elif defined __GNUC__
#if !defined alloca
# define alloca __builtin_alloca
#endif
#elif defined _AIX
# define alloca __alloca
#elif defined _MSC_VER
# include <malloc.h>
# define alloca _alloca
#else
# ifndef HAVE_ALLOCA
# ifdef __cplusplus
extern "C"
# endif
void *alloca (size_t);
# endif
#endif
typedef struct SpiceChunk {
uint8_t *data;
uint32_t len;
} SpiceChunk;
enum {
SPICE_CHUNKS_FLAGS_UNSTABLE = (1<<0),
SPICE_CHUNKS_FLAGS_FREE = (1<<1)
};
typedef struct SpiceChunks {
uint32_t data_size;
uint32_t num_chunks;
uint32_t flags;
SpiceChunk chunk[0];
} SpiceChunks;
typedef struct SpiceBuffer
{
size_t capacity;
size_t offset;
uint8_t *buffer;
} SpiceBuffer;
char *spice_strdup(const char *str) SPICE_GNUC_MALLOC;
char *spice_strndup(const char *str, size_t n_bytes) SPICE_GNUC_MALLOC;
void *spice_memdup(const void *mem, size_t n_bytes) SPICE_GNUC_MALLOC;
void *spice_malloc(size_t n_bytes) SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE(1);
void *spice_malloc0(size_t n_bytes) SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE(1);
void *spice_realloc(void *mem, size_t n_bytes) SPICE_GNUC_WARN_UNUSED_RESULT;
void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes) SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE2(1,2);
void *spice_malloc_n_m(size_t n_blocks, size_t n_block_bytes, size_t extra_size) SPICE_GNUC_MALLOC;
void *spice_malloc0_n(size_t n_blocks, size_t n_block_bytes) SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE2(1,2);
void *spice_realloc_n(void *mem, size_t n_blocks, size_t n_block_bytes) SPICE_GNUC_WARN_UNUSED_RESULT;
SpiceChunks *spice_chunks_new(uint32_t count) SPICE_GNUC_MALLOC;
SpiceChunks *spice_chunks_new_linear(uint8_t *data, uint32_t len) SPICE_GNUC_MALLOC;
void spice_chunks_destroy(SpiceChunks *chunks);
void spice_chunks_linearize(SpiceChunks *chunks);
size_t spice_strnlen(const char *str, size_t max_len);
/* Optimize: avoid the call to the (slower) _n function if we can
* determine at compile-time that no overflow happens.
*/
#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__)
# define _SPICE_NEW(struct_type, n_structs, func) \
(struct_type *) (__extension__ ({ \
size_t __n = (size_t) (n_structs); \
size_t __s = sizeof (struct_type); \
void *__p; \
if (__s == 1) \
__p = spice_##func (__n); \
else if (__builtin_constant_p (__n) && \
__n <= SIZE_MAX / __s) \
__p = spice_##func (__n * __s); \
else \
__p = spice_##func##_n (__n, __s); \
__p; \
}))
# define _SPICE_RENEW(struct_type, mem, n_structs, func) \
(struct_type *) (__extension__ ({ \
size_t __n = (size_t) (n_structs); \
size_t __s = sizeof (struct_type); \
void *__p = (void *) (mem); \
if (__s == 1) \
__p = spice_##func (__p, __n); \
else if (__builtin_constant_p (__n) && \
__n <= SIZE_MAX / __s) \
__p = spice_##func (__p, __n * __s); \
else \
__p = spice_##func##_n (__p, __n, __s); \
__p; \
}))
#else
/* Unoptimized version: always call the _n() function. */
#define _SPICE_NEW(struct_type, n_structs, func) \
((struct_type *) spice_##func##_n ((n_structs), sizeof (struct_type)))
#define _SPICE_RENEW(struct_type, mem, n_structs, func) \
((struct_type *) spice_##func##_n (mem, (n_structs), sizeof (struct_type)))
#endif
#define spice_new(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc)
#define spice_new0(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc0)
#define spice_renew(struct_type, mem, n_structs) _SPICE_RENEW(struct_type, mem, n_structs, realloc)
/* Buffer management */
void spice_buffer_reserve(SpiceBuffer *buffer, size_t len);
int spice_buffer_empty(SpiceBuffer *buffer);
uint8_t *spice_buffer_end(SpiceBuffer *buffer);
void spice_buffer_reset(SpiceBuffer *buffer);
void spice_buffer_free(SpiceBuffer *buffer);
void spice_buffer_append(SpiceBuffer *buffer, const void *data, size_t len);
size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len);
size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,525 +0,0 @@
/*
Copyright (C) 2009-2010 Red Hat, Inc.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _H_MESSAGES
#define _H_MESSAGES
#include <spice/protocol.h>
#include "draw.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct SpiceMsgData {
uint32_t data_size;
uint8_t data[0];
} SpiceMsgData;
typedef struct SpiceMsgEmpty {
} SpiceMsgEmpty;
typedef struct SpiceMsgInputsInit {
uint32_t keyboard_modifiers;
} SpiceMsgInputsInit;
typedef struct SpiceMsgInputsKeyModifiers {
uint32_t modifiers;
} SpiceMsgInputsKeyModifiers;
typedef struct SpiceMsgMainMultiMediaTime {
uint32_t time;
} SpiceMsgMainMultiMediaTime;
typedef struct SpiceMsgMainMigrationBegin {
uint16_t port;
uint16_t sport;
uint32_t host_size;
uint8_t *host_data;
uint16_t pub_key_type;
uint32_t pub_key_size;
uint8_t *pub_key_data;
uint32_t cert_subject_size;
uint8_t *cert_subject_data;
} SpiceMsgMainMigrationBegin;
typedef struct SpiceMsgMainMigrationSwitchHost {
uint16_t port;
uint16_t sport;
uint32_t host_size;
uint8_t *host_data;
uint32_t cert_subject_size;
uint8_t *cert_subject_data;
} SpiceMsgMainMigrationSwitchHost;
typedef struct SpiceMsgMigrate {
uint32_t flags;
} SpiceMsgMigrate;
typedef struct SpiceResourceID {
uint8_t type;
uint64_t id;
} SpiceResourceID;
typedef struct SpiceResourceList {
uint16_t count;
SpiceResourceID resources[0];
} SpiceResourceList;
typedef struct SpiceMsgSetAck {
uint32_t generation;
uint32_t window;
} SpiceMsgSetAck;
typedef struct SpiceMsgcAckSync {
uint32_t generation;
} SpiceMsgcAckSync;
typedef struct SpiceWaitForChannel {
uint8_t channel_type;
uint8_t channel_id;
uint64_t message_serial;
} SpiceWaitForChannel;
typedef struct SpiceMsgWaitForChannels {
uint8_t wait_count;
SpiceWaitForChannel wait_list[0];
} SpiceMsgWaitForChannels;
typedef struct SpiceChannelId {
uint8_t type;
uint8_t id;
} SpiceChannelId;
typedef struct SpiceMsgMainInit {
uint32_t session_id;
uint32_t display_channels_hint;
uint32_t supported_mouse_modes;
uint32_t current_mouse_mode;
uint32_t agent_connected;
uint32_t agent_tokens;
uint32_t multi_media_time;
uint32_t ram_hint;
} SpiceMsgMainInit;
typedef struct SpiceMsgDisconnect {
uint64_t time_stamp;
uint32_t reason; // SPICE_ERR_?
} SpiceMsgDisconnect;
typedef struct SpiceMsgNotify {
uint64_t time_stamp;
uint32_t severity;
uint32_t visibilty;
uint32_t what;
uint32_t message_len;
uint8_t message[0];
} SpiceMsgNotify;
typedef struct SpiceMsgChannels {
uint32_t num_of_channels;
SpiceChannelId channels[0];
} SpiceMsgChannels;
typedef struct SpiceMsgMainName {
uint32_t name_len;
uint8_t name[0];
} SpiceMsgMainName;
typedef struct SpiceMsgMainUuid {
uint8_t uuid[16];
} SpiceMsgMainUuid;
typedef struct SpiceMsgMainMouseMode {
uint32_t supported_modes;
uint32_t current_mode;
} SpiceMsgMainMouseMode;
typedef struct SpiceMsgPing {
uint32_t id;
uint64_t timestamp;
void *data;
uint32_t data_len;
} SpiceMsgPing;
typedef struct SpiceMsgMainAgentDisconnect {
uint32_t error_code; // SPICE_ERR_?
} SpiceMsgMainAgentDisconnect;
#define SPICE_AGENT_MAX_DATA_SIZE 2048
typedef struct SpiceMsgMainAgentTokens {
uint32_t num_tokens;
} SpiceMsgMainAgentTokens, SpiceMsgcMainAgentTokens, SpiceMsgcMainAgentStart;
typedef struct SpiceMsgcClientInfo {
uint64_t cache_size;
} SpiceMsgcClientInfo;
typedef struct SpiceMsgcMainMouseModeRequest {
uint32_t mode;
} SpiceMsgcMainMouseModeRequest;
typedef struct SpiceCursor {
uint32_t flags;
SpiceCursorHeader header;
uint32_t data_size;
uint8_t *data;
} SpiceCursor;
typedef struct SpiceMsgDisplayMode {
uint32_t x_res;
uint32_t y_res;
uint32_t bits;
} SpiceMsgDisplayMode;
typedef struct SpiceMsgSurfaceCreate {
uint32_t surface_id;
uint32_t width;
uint32_t height;
uint32_t format;
uint32_t flags;
} SpiceMsgSurfaceCreate;
typedef struct SpiceMsgSurfaceDestroy {
uint32_t surface_id;
} SpiceMsgSurfaceDestroy;
typedef struct SpiceMsgDisplayBase {
uint32_t surface_id;
SpiceRect box;
SpiceClip clip;
} SpiceMsgDisplayBase;
typedef struct SpiceMsgDisplayDrawFill {
SpiceMsgDisplayBase base;
SpiceFill data;
} SpiceMsgDisplayDrawFill;
typedef struct SpiceMsgDisplayDrawOpaque {
SpiceMsgDisplayBase base;
SpiceOpaque data;
} SpiceMsgDisplayDrawOpaque;
typedef struct SpiceMsgDisplayDrawCopy {
SpiceMsgDisplayBase base;
SpiceCopy data;
} SpiceMsgDisplayDrawCopy;
typedef struct SpiceMsgDisplayDrawTransparent {
SpiceMsgDisplayBase base;
SpiceTransparent data;
} SpiceMsgDisplayDrawTransparent;
typedef struct SpiceMsgDisplayDrawAlphaBlend {
SpiceMsgDisplayBase base;
SpiceAlphaBlend data;
} SpiceMsgDisplayDrawAlphaBlend;
typedef struct SpiceMsgDisplayCopyBits {
SpiceMsgDisplayBase base;
SpicePoint src_pos;
} SpiceMsgDisplayCopyBits;
typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
typedef struct SpiceMsgDisplayDrawRop3 {
SpiceMsgDisplayBase base;
SpiceRop3 data;
} SpiceMsgDisplayDrawRop3;
typedef struct SpiceMsgDisplayDrawBlackness {
SpiceMsgDisplayBase base;
SpiceBlackness data;
} SpiceMsgDisplayDrawBlackness;
typedef struct SpiceMsgDisplayDrawWhiteness {
SpiceMsgDisplayBase base;
SpiceWhiteness data;
} SpiceMsgDisplayDrawWhiteness;
typedef struct SpiceMsgDisplayDrawInvers {
SpiceMsgDisplayBase base;
SpiceInvers data;
} SpiceMsgDisplayDrawInvers;
typedef struct SpiceMsgDisplayDrawStroke {
SpiceMsgDisplayBase base;
SpiceStroke data;
} SpiceMsgDisplayDrawStroke;
typedef struct SpiceMsgDisplayDrawText {
SpiceMsgDisplayBase base;
SpiceText data;
} SpiceMsgDisplayDrawText;
typedef struct SpiceMsgDisplayInvalOne {
uint64_t id;
} SpiceMsgDisplayInvalOne;
typedef struct SpiceMsgDisplayStreamCreate {
uint32_t surface_id;
uint32_t id;
uint32_t flags;
uint32_t codec_type;
uint64_t stamp;
uint32_t stream_width;
uint32_t stream_height;
uint32_t src_width;
uint32_t src_height;
SpiceRect dest;
SpiceClip clip;
} SpiceMsgDisplayStreamCreate;
typedef struct SpiceMsgDisplayStreamData {
uint32_t id;
uint32_t multi_media_time;
uint32_t data_size;
uint8_t data[0];
} SpiceMsgDisplayStreamData;
typedef struct SpiceMsgDisplayStreamClip {
uint32_t id;
SpiceClip clip;
} SpiceMsgDisplayStreamClip;
typedef struct SpiceMsgDisplayStreamDestroy {
uint32_t id;
} SpiceMsgDisplayStreamDestroy;
typedef struct SpiceMsgCursorInit {
SpicePoint16 position;
uint16_t trail_length;
uint16_t trail_frequency;
uint8_t visible;
SpiceCursor cursor;
} SpiceMsgCursorInit;
typedef struct SpiceMsgCursorSet {
SpicePoint16 position;
uint8_t visible;
SpiceCursor cursor;
} SpiceMsgCursorSet;
typedef struct SpiceMsgCursorMove {
SpicePoint16 position;
} SpiceMsgCursorMove;
typedef struct SpiceMsgCursorTrail {
uint16_t length;
uint16_t frequency;
} SpiceMsgCursorTrail;
typedef struct SpiceMsgcDisplayInit {
uint8_t pixmap_cache_id;
int64_t pixmap_cache_size; //in pixels
uint8_t glz_dictionary_id;
int32_t glz_dictionary_window_size; // in pixels
} SpiceMsgcDisplayInit;
typedef struct SpiceMsgcKeyDown {
uint32_t code;
} SpiceMsgcKeyDown;
typedef struct SpiceMsgcKeyUp {
uint32_t code;
} SpiceMsgcKeyUp;
typedef struct SpiceMsgcKeyModifiers {
uint32_t modifiers;
} SpiceMsgcKeyModifiers;
typedef struct SpiceMsgcMouseMotion {
int32_t dx;
int32_t dy;
uint32_t buttons_state;
} SpiceMsgcMouseMotion;
typedef struct SpiceMsgcMousePosition {
uint32_t x;
uint32_t y;
uint32_t buttons_state;
uint8_t display_id;
} SpiceMsgcMousePosition;
typedef struct SpiceMsgcMousePress {
int32_t button;
int32_t buttons_state;
} SpiceMsgcMousePress;
typedef struct SpiceMsgcMouseRelease {
int32_t button;
int32_t buttons_state;
} SpiceMsgcMouseRelease;
typedef struct SpiceMsgAudioVolume {
uint8_t nchannels;
uint16_t volume[0];
} SpiceMsgAudioVolume;
typedef struct SpiceMsgAudioMute {
uint8_t mute;
} SpiceMsgAudioMute;
typedef struct SpiceMsgPlaybackMode {
uint32_t time;
uint32_t mode; //SPICE_AUDIO_DATA_MODE_?
uint8_t *data;
uint32_t data_size;
} SpiceMsgPlaybackMode, SpiceMsgcRecordMode;
typedef struct SpiceMsgPlaybackStart {
uint32_t channels;
uint32_t format; //SPICE_AUDIO_FMT_?
uint32_t frequency;
uint32_t time;
} SpiceMsgPlaybackStart;
typedef struct SpiceMsgPlaybackPacket {
uint32_t time;
uint8_t *data;
uint32_t data_size;
} SpiceMsgPlaybackPacket, SpiceMsgcRecordPacket;
typedef struct SpiceMsgRecordStart {
uint32_t channels;
uint32_t format; //SPICE_AUDIO_FMT_?
uint32_t frequency;
} SpiceMsgRecordStart;
typedef struct SpiceMsgcRecordStartMark {
uint32_t time;
} SpiceMsgcRecordStartMark;
typedef struct SpiceMsgTunnelInit {
uint16_t max_num_of_sockets;
uint32_t max_socket_data_size;
} SpiceMsgTunnelInit;
typedef uint8_t SpiceTunnelIPv4[4];
typedef struct SpiceMsgTunnelIpInfo {
uint16_t type;
union {
SpiceTunnelIPv4 ipv4;
} u;
uint8_t data[0];
} SpiceMsgTunnelIpInfo;
typedef struct SpiceMsgTunnelServiceIpMap {
uint32_t service_id;
SpiceMsgTunnelIpInfo virtual_ip;
} SpiceMsgTunnelServiceIpMap;
typedef struct SpiceMsgTunnelSocketOpen {
uint16_t connection_id;
uint32_t service_id;
uint32_t tokens;
} SpiceMsgTunnelSocketOpen;
/* connection id must be the first field in msgs directed to a specific connection */
typedef struct SpiceMsgTunnelSocketFin {
uint16_t connection_id;
} SpiceMsgTunnelSocketFin;
typedef struct SpiceMsgTunnelSocketClose {
uint16_t connection_id;
} SpiceMsgTunnelSocketClose;
typedef struct SpiceMsgTunnelSocketData {
uint16_t connection_id;
uint8_t data[0];
} SpiceMsgTunnelSocketData;
typedef struct SpiceMsgTunnelSocketTokens {
uint16_t connection_id;
uint32_t num_tokens;
} SpiceMsgTunnelSocketTokens;
typedef struct SpiceMsgTunnelSocketClosedAck {
uint16_t connection_id;
} SpiceMsgTunnelSocketClosedAck;
typedef struct SpiceMsgcTunnelAddGenericService {
uint32_t type;
uint32_t id;
uint32_t group;
uint32_t port;
uint64_t name;
uint64_t description;
union {
SpiceMsgTunnelIpInfo ip;
} u;
} SpiceMsgcTunnelAddGenericService;
typedef struct SpiceMsgcTunnelRemoveService {
uint32_t id;
} SpiceMsgcTunnelRemoveService;
/* connection id must be the first field in msgs directed to a specific connection */
typedef struct SpiceMsgcTunnelSocketOpenAck {
uint16_t connection_id;
uint32_t tokens;
} SpiceMsgcTunnelSocketOpenAck;
typedef struct SpiceMsgcTunnelSocketOpenNack {
uint16_t connection_id;
} SpiceMsgcTunnelSocketOpenNack;
typedef struct SpiceMsgcTunnelSocketData {
uint16_t connection_id;
uint8_t data[0];
} SpiceMsgcTunnelSocketData;
typedef struct SpiceMsgcTunnelSocketFin {
uint16_t connection_id;
} SpiceMsgcTunnelSocketFin;
typedef struct SpiceMsgcTunnelSocketClosed {
uint16_t connection_id;
} SpiceMsgcTunnelSocketClosed;
typedef struct SpiceMsgcTunnelSocketClosedAck {
uint16_t connection_id;
} SpiceMsgcTunnelSocketClosedAck;
typedef struct SpiceMsgcTunnelSocketTokens {
uint16_t connection_id;
uint32_t num_tokens;
} SpiceMsgcTunnelSocketTokens;
#ifdef __cplusplus
}
#endif
#endif /* _H_SPICE_PROTOCOL */

View File

@ -1,44 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MUTEX
#define _H_MUTEX
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#include <windows.h>
typedef CRITICAL_SECTION mutex_t;
#define MUTEX_INIT(mutex) InitializeCriticalSection(&mutex)
#define MUTEX_LOCK(mutex) EnterCriticalSection(&mutex)
#define MUTEX_UNLOCK(mutex) LeaveCriticalSection(&mutex)
#else
#include <pthread.h>
typedef pthread_mutex_t mutex_t;
#define MUTEX_INIT(mutex) pthread_mutex_init(&mutex, NULL);
#define MUTEX_LOCK(mutex) pthread_mutex_lock(&mutex)
#define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
#endif
#ifdef __cplusplus
}
#endif
#endif // _H_MUTEX

View File

@ -1,251 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include "ogl_ctx.h"
#include "spice_common.h"
enum {
OGLCTX_TYPE_PBUF,
OGLCTX_TYPE_PIXMAP,
};
struct OGLCtx {
int type;
Display *x_display;
GLXContext glx_context;
GLXDrawable drawable;
};
typedef struct OGLPixmapCtx {
OGLCtx base;
Pixmap pixmap;
} OGLPixmapCtx;
const char *oglctx_type_str(OGLCtx *ctx)
{
static const char *pbuf_str = "pbuf";
static const char *pixmap_str = "pixmap";
static const char *invalid_str = "invalid";
switch (ctx->type) {
case OGLCTX_TYPE_PBUF:
return pbuf_str;
case OGLCTX_TYPE_PIXMAP:
return pixmap_str;
default:
return invalid_str;
}
}
void oglctx_make_current(OGLCtx *ctx)
{
if (!glXMakeCurrent(ctx->x_display, ctx->drawable, ctx->glx_context)) {
printf("%s: failed\n", __FUNCTION__);
}
}
OGLCtx *pbuf_create(int width, int heigth)
{
OGLCtx *ctx;
Display *x_display;
int num_configs;
GLXFBConfig *fb_config;
GLXPbuffer glx_pbuf;
GLXContext glx_context;
const int glx_attributes[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_STENCIL_SIZE, 4,
0 };
int pbuf_attrib[] = { GLX_PRESERVED_CONTENTS, True,
GLX_PBUFFER_WIDTH, width,
GLX_PBUFFER_HEIGHT, heigth,
GLX_LARGEST_PBUFFER, False,
0, 0 };
if (!(ctx = calloc(1, sizeof(*ctx)))) {
printf("%s: alloc pbuf failed\n", __FUNCTION__);
return NULL;
}
if (!(x_display = XOpenDisplay(NULL))) {
printf("%s: open display failed\n", __FUNCTION__);
goto error_1;
}
if (!(fb_config = glXChooseFBConfig(x_display, 0, glx_attributes, &num_configs)) ||
!num_configs) {
printf("%s: choose fb config failed\n", __FUNCTION__);
goto error_2;
}
if (!(glx_pbuf = glXCreatePbuffer(x_display, fb_config[0], pbuf_attrib))) {
goto error_3;
}
if (!(glx_context = glXCreateNewContext(x_display, fb_config[0], GLX_RGBA_TYPE, NULL, True))) {
printf("%s: create context failed\n", __FUNCTION__);
goto error_4;
}
XFree(fb_config);
ctx->type = OGLCTX_TYPE_PBUF;
ctx->drawable = glx_pbuf;
ctx->glx_context = glx_context;
ctx->x_display = x_display;
return ctx;
error_4:
glXDestroyPbuffer(x_display, glx_pbuf);
error_3:
XFree(fb_config);
error_2:
XCloseDisplay(x_display);
error_1:
free(ctx);
return NULL;
}
OGLCtx *pixmap_create(int width, int heigth)
{
Display *x_display;
int num_configs;
GLXFBConfig *fb_config;
GLXPixmap glx_pixmap;
GLXContext glx_context;
Pixmap pixmap;
int screen;
Window root_window;
OGLPixmapCtx *pix;
const int glx_attributes[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_STENCIL_SIZE, 4,
0 };
if (!(pix = calloc(1, sizeof(*pix)))) {
printf("%s: alloc pix failed\n", __FUNCTION__);
return NULL;
}
if (!(x_display = XOpenDisplay(NULL))) {
printf("%s: open display failed\n", __FUNCTION__);
goto error_1;
}
screen = DefaultScreen(x_display);
root_window = RootWindow(x_display, screen);
if (!(fb_config = glXChooseFBConfig(x_display, 0, glx_attributes, &num_configs)) ||
!num_configs) {
printf("%s: choose fb config failed\n", __FUNCTION__);
goto error_2;
}
if (!(pixmap = XCreatePixmap(x_display, root_window, width, heigth, 32 /*use fb config*/))) {
printf("%s: create x pixmap failed\n", __FUNCTION__);
goto error_3;
}
if (!(glx_pixmap = glXCreatePixmap(x_display, fb_config[0], pixmap, NULL))) {
printf("%s: create glx pixmap failed\n", __FUNCTION__);
goto error_4;
}
if (!(glx_context = glXCreateNewContext(x_display, fb_config[0], GLX_RGBA_TYPE, NULL, True))) {
printf("%s: create context failed\n", __FUNCTION__);
goto error_5;
}
XFree(fb_config);
pix->base.type = OGLCTX_TYPE_PIXMAP;
pix->base.x_display = x_display;
pix->base.drawable = glx_pixmap;
pix->base.glx_context = glx_context;
pix->pixmap = pixmap;
return &pix->base;
error_5:
glXDestroyPixmap(x_display, glx_pixmap);
error_4:
XFreePixmap(x_display, pixmap);
error_3:
XFree(fb_config);
error_2:
XCloseDisplay(x_display);
error_1:
free(pix);
return NULL;
}
void oglctx_destroy(OGLCtx *ctx)
{
if (!ctx) {
return;
}
// test is current ?
glXDestroyContext(ctx->x_display, ctx->glx_context);
switch (ctx->type) {
case OGLCTX_TYPE_PBUF:
glXDestroyPbuffer(ctx->x_display, ctx->drawable);
break;
case OGLCTX_TYPE_PIXMAP:
glXDestroyPixmap(ctx->x_display, ctx->drawable);
XFreePixmap(ctx->x_display, ((OGLPixmapCtx *)ctx)->pixmap);
break;
default:
PANIC("invalid ogl ctx type");
}
XCloseDisplay(ctx->x_display);
free(ctx);
}

View File

@ -1,38 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GLCTX
#define _H_GLCTX
#ifdef __cplusplus
extern "C" {
#endif
typedef struct OGLCtx OGLCtx;
const char *oglctx_type_str(OGLCtx *ctx);
void oglctx_make_current(OGLCtx *ctx);
OGLCtx *pbuf_create(int width, int heigth);
OGLCtx *pixmap_create(int width, int heigth);
void oglctx_destroy(OGLCtx *ctx);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,136 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H__PIXMAN_UTILS
#define _H__PIXMAN_UTILS
#include <spice/types.h>
#include <stdlib.h>
#define PIXMAN_DONT_DEFINE_STDINT
#include <pixman.h>
#include "draw.h"
#ifdef __cplusplus
extern "C" {
#endif
/* This lists all possible 2 argument binary raster ops.
* This enum has the same values as the X11 GXcopy type
* and same as the GL constants (GL_AND etc) if you
* or it with 0x1500. However it is not exactly the
* same as the win32 ROP2 type (they use another order).
*/
typedef enum {
SPICE_ROP_CLEAR, /* 0x0 0 */
SPICE_ROP_AND, /* 0x1 src AND dst */
SPICE_ROP_AND_REVERSE, /* 0x2 src AND NOT dst */
SPICE_ROP_COPY, /* 0x3 src */
SPICE_ROP_AND_INVERTED, /* 0x4 (NOT src) AND dst */
SPICE_ROP_NOOP, /* 0x5 dst */
SPICE_ROP_XOR, /* 0x6 src XOR dst */
SPICE_ROP_OR, /* 0x7 src OR dst */
SPICE_ROP_NOR, /* 0x8 (NOT src) AND (NOT dst) */
SPICE_ROP_EQUIV, /* 0x9 (NOT src) XOR dst */
SPICE_ROP_INVERT, /* 0xa NOT dst */
SPICE_ROP_OR_REVERSE, /* 0xb src OR (NOT dst) */
SPICE_ROP_COPY_INVERTED, /* 0xc NOT src */
SPICE_ROP_OR_INVERTED, /* 0xd (NOT src) OR dst */
SPICE_ROP_NAND, /* 0xe (NOT src) OR (NOT dst) */
SPICE_ROP_SET /* 0xf 1 */
} SpiceROP;
int spice_pixman_image_get_bpp(pixman_image_t *image);
pixman_format_code_t spice_surface_format_to_pixman(uint32_t surface_format);
pixman_format_code_t spice_bitmap_format_to_pixman(int bitmap_format,
uint32_t palette_surface_format);
pixman_image_t *spice_bitmap_try_as_pixman(int src_format, int flags,
int width, int height,
uint8_t *data, int stride);
pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
int src_format, int flags,
int width, int height,
uint8_t *src, int src_stride,
uint32_t palette_surface_format,
SpicePalette *palette);
pixman_image_t *spice_bitmap_convert_to_pixman(pixman_format_code_t dest_format,
pixman_image_t *dest_image,
int src_format, int flags,
int width, int height,
uint8_t *src, int src_stride,
uint32_t palette_surface_format,
SpicePalette *palette);
void spice_pixman_region32_init_from_bitmap(pixman_region32_t *region,
uint32_t *data,
int width, int height,
int stride);
pixman_bool_t spice_pixman_region32_init_rects(pixman_region32_t *region,
const SpiceRect *rects,
int count);
void spice_pixman_fill_rect(pixman_image_t *dest,
int x, int y,
int w, int h,
uint32_t value);
void spice_pixman_fill_rect_rop(pixman_image_t *dest,
int x, int y,
int w, int h,
uint32_t value,
SpiceROP rop);
void spice_pixman_tile_rect(pixman_image_t *dest,
int x, int y,
int w, int h,
pixman_image_t *tile,
int offset_x,
int offset_y);
void spice_pixman_tile_rect_rop(pixman_image_t *dest,
int x, int y,
int w, int h,
pixman_image_t *tile,
int offset_x,
int offset_y,
SpiceROP rop);
void spice_pixman_blit(pixman_image_t *dest,
pixman_image_t *src,
int src_x, int src_y,
int dest_x, int dest_y,
int w, int h);
void spice_pixman_blit_rop(pixman_image_t *dest,
pixman_image_t *src,
int src_x, int src_y,
int dest_x, int dest_y,
int w, int h,
SpiceROP rop);
void spice_pixman_blit_colorkey(pixman_image_t *dest,
pixman_image_t *src,
int src_x, int src_y,
int dest_x, int dest_y,
int width, int height,
uint32_t transparent_color);
void spice_pixman_copy_rect(pixman_image_t *image,
int src_x, int src_y,
int w, int h,
int dest_x, int dest_y);
#ifdef __cplusplus
}
#endif
#endif /* _H__PIXMAN_UTILS */

File diff suppressed because it is too large Load Diff

View File

@ -1,72 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __QUIC_H
#define __QUIC_H
#include "quic_config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
QUIC_IMAGE_TYPE_INVALID,
QUIC_IMAGE_TYPE_GRAY,
QUIC_IMAGE_TYPE_RGB16,
QUIC_IMAGE_TYPE_RGB24,
QUIC_IMAGE_TYPE_RGB32,
QUIC_IMAGE_TYPE_RGBA
} QuicImageType;
#define QUIC_ERROR -1
#define QUIC_OK 0
typedef void *QuicContext;
typedef struct QuicUsrContext QuicUsrContext;
struct QuicUsrContext {
void (*error)(QuicUsrContext *usr, const char *fmt, ...);
void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
void (*info)(QuicUsrContext *usr, const char *fmt, ...);
void *(*malloc)(QuicUsrContext *usr, int size);
void (*free)(QuicUsrContext *usr, void *ptr);
int (*more_space)(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed);
int (*more_lines)(QuicUsrContext *usr, uint8_t **lines); // on return the last line of previous
// lines bunch must still be valid
};
int quic_encode(QuicContext *quic, QuicImageType type, int width, int height,
uint8_t *lines, unsigned int num_lines, int stride,
uint32_t *io_ptr, unsigned int num_io_words);
int quic_decode_begin(QuicContext *quic, uint32_t *io_ptr, unsigned int num_io_words,
QuicImageType *type, int *width, int *height);
int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride);
QuicContext *quic_create(QuicUsrContext *usr);
void quic_destroy(QuicContext *quic);
void quic_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,48 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __QUIC_CONFIG_H
#define __QUIC_CONFIG_H
#include <spice/types.h>
#include <spice/macros.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __GNUC__
#include <string.h>
#define MEMCLEAR(ptr, size) memset(ptr, 0, size)
#else
#ifdef QXLDD
#include <windef.h>
#include "os_dep.h"
#define MEMCLEAR(ptr, size) RtlZeroMemory(ptr, size)
#else
#include <stddef.h>
#include <string.h>
#define MEMCLEAR(ptr, size) memset(ptr, 0, size)
#endif // QXLDD
#endif //__GNUC__
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,117 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef QUIC_FAMILY_8BPC
#undef QUIC_FAMILY_8BPC
#define FNAME(name) name##_8bpc
#define VNAME(name) name##_8bpc
#define BPC 8
#endif
#ifdef QUIC_FAMILY_5BPC
#undef QUIC_FAMILY_5BPC
#define FNAME(name) name##_5bpc
#define VNAME(name) name##_5bpc
#define BPC 5
#endif
static unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
{
if (n < VNAME(family).nGRcodewords[l]) {
return (n >> l) + 1 + l;
} else {
return VNAME(family).notGRcwlen[l];
}
}
static void FNAME(golomb_coding)(const BYTE n, const unsigned int l, unsigned int * const codeword,
unsigned int * const codewordlen)
{
if (n < VNAME(family).nGRcodewords[l]) {
(*codeword) = bitat[l] | (n & bppmask[l]);
(*codewordlen) = (n >> l) + l + 1;
} else {
(*codeword) = n - VNAME(family).nGRcodewords[l];
(*codewordlen) = VNAME(family).notGRcwlen[l];
}
}
static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned int bits,
unsigned int * const codewordlen)
{
if (bits > VNAME(family).notGRprefixmask[l]) { /*GR*/
const unsigned int zeroprefix = cnt_l_zeroes(bits); /* leading zeroes in codeword */
const unsigned int cwlen = zeroprefix + 1 + l; /* codeword length */
(*codewordlen) = cwlen;
return (zeroprefix << l) | ((bits >> (32 - cwlen)) & bppmask[l]);
} else { /* not-GR */
const unsigned int cwlen = VNAME(family).notGRcwlen[l];
(*codewordlen) = cwlen;
return VNAME(family).nGRcodewords[l] + ((bits) >> (32 - cwlen) &
bppmask[VNAME(family).notGRsuffixlen[l]]);
}
}
/* update the bucket using just encoded curval */
static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
const BYTE curval, unsigned int bpp)
{
COUNTER * const pcounters = bucket->pcounters;
unsigned int i;
unsigned int bestcode;
unsigned int bestcodelen;
//unsigned int bpp = encoder->bpp;
/* update counters, find minimum */
bestcode = bpp - 1;
bestcodelen = (pcounters[bestcode] += FNAME(golomb_code_len)(curval, bestcode));
for (i = bpp - 2; i < bpp; i--) { /* NOTE: expression i<bpp for signed int i would be: i>=0 */
const unsigned int ithcodelen = (pcounters[i] += FNAME(golomb_code_len)(curval, i));
if (ithcodelen < bestcodelen) {
bestcode = i;
bestcodelen = ithcodelen;
}
}
bucket->bestcode = bestcode; /* store the found minimum */
if (bestcodelen > state->wm_trigger) { /* halving counters? */
for (i = 0; i < bpp; i++) {
pcounters[i] >>= 1;
}
}
}
static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
{
ASSERT(channel->encoder->usr, val < (0x1U << BPC));
return channel->_buckets_ptrs[val];
}
#undef FNAME
#undef VNAME
#undef BPC

View File

@ -1,765 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef QUIC_RGB32
#undef QUIC_RGB32
#define PIXEL rgb32_pixel_t
#define FNAME(name) quic_rgb32_##name
#define golomb_coding golomb_coding_8bpc
#define golomb_decoding golomb_decoding_8bpc
#define update_model update_model_8bpc
#define find_bucket find_bucket_8bpc
#define family family_8bpc
#define BPC 8
#define BPC_MASK 0xffU
#define COMPRESS_IMP
#define SET_r(pix, val) ((pix)->r = val)
#define GET_r(pix) ((pix)->r)
#define SET_g(pix, val) ((pix)->g = val)
#define GET_g(pix) ((pix)->g)
#define SET_b(pix, val) ((pix)->b = val)
#define GET_b(pix) ((pix)->b)
#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
#endif
#ifdef QUIC_RGB24
#undef QUIC_RGB24
#define PIXEL rgb24_pixel_t
#define FNAME(name) quic_rgb24_##name
#define golomb_coding golomb_coding_8bpc
#define golomb_decoding golomb_decoding_8bpc
#define update_model update_model_8bpc
#define find_bucket find_bucket_8bpc
#define family family_8bpc
#define BPC 8
#define BPC_MASK 0xffU
#define COMPRESS_IMP
#define SET_r(pix, val) ((pix)->r = val)
#define GET_r(pix) ((pix)->r)
#define SET_g(pix, val) ((pix)->g = val)
#define GET_g(pix) ((pix)->g)
#define SET_b(pix, val) ((pix)->b = val)
#define GET_b(pix) ((pix)->b)
#define UNCOMPRESS_PIX_START(pix)
#endif
#ifdef QUIC_RGB16
#undef QUIC_RGB16
#define PIXEL rgb16_pixel_t
#define FNAME(name) quic_rgb16_##name
#define golomb_coding golomb_coding_5bpc
#define golomb_decoding golomb_decoding_5bpc
#define update_model update_model_5bpc
#define find_bucket find_bucket_5bpc
#define family family_5bpc
#define BPC 5
#define BPC_MASK 0x1fU
#define COMPRESS_IMP
#define SET_r(pix, val) (*(pix) = (*(pix) & ~(0x1f << 10)) | ((val) << 10))
#define GET_r(pix) ((*(pix) >> 10) & 0x1f)
#define SET_g(pix, val) (*(pix) = (*(pix) & ~(0x1f << 5)) | ((val) << 5))
#define GET_g(pix) ((*(pix) >> 5) & 0x1f)
#define SET_b(pix, val) (*(pix) = (*(pix) & ~0x1f) | (val))
#define GET_b(pix) (*(pix) & 0x1f)
#define UNCOMPRESS_PIX_START(pix) (*(pix) = 0)
#endif
#ifdef QUIC_RGB16_TO_32
#undef QUIC_RGB16_TO_32
#define PIXEL rgb32_pixel_t
#define FNAME(name) quic_rgb16_to_32_##name
#define golomb_coding golomb_coding_5bpc
#define golomb_decoding golomb_decoding_5bpc
#define update_model update_model_5bpc
#define find_bucket find_bucket_5bpc
#define family family_5bpc
#define BPC 5
#define BPC_MASK 0x1fU
#define SET_r(pix, val) ((pix)->r = ((val) << 3) | (((val) & 0x1f) >> 2))
#define GET_r(pix) ((pix)->r >> 3)
#define SET_g(pix, val) ((pix)->g = ((val) << 3) | (((val) & 0x1f) >> 2))
#define GET_g(pix) ((pix)->g >> 3)
#define SET_b(pix, val) ((pix)->b = ((val) << 3) | (((val) & 0x1f) >> 2))
#define GET_b(pix) ((pix)->b >> 3)
#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
#endif
#define SAME_PIXEL(p1, p2) \
(GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
GET_b(p1) == GET_b(p2))
#define _PIXEL_A(channel, curr) ((unsigned int)GET_##channel((curr) - 1))
#define _PIXEL_B(channel, prev) ((unsigned int)GET_##channel(prev))
#define _PIXEL_C(channel, prev) ((unsigned int)GET_##channel((prev) - 1))
/* a */
#define DECORELATE_0(channel, curr, bpc_mask)\
family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)_PIXEL_A(channel, curr)) & bpc_mask]
#define CORELATE_0(channel, curr, correlate, bpc_mask)\
((family.xlatL2U[correlate] + _PIXEL_A(channel, curr)) & bpc_mask)
#ifdef PRED_1
/* (a+b)/2 */
#define DECORELATE(channel, prev, curr, bpc_mask, r) \
r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)((_PIXEL_A(channel, curr) + \
_PIXEL_B(channel, prev)) >> 1)) & bpc_mask]
#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) \
SET_##channel(r, ((family.xlatL2U[correlate] + \
(int)((_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev)) >> 1)) & bpc_mask))
#endif
#ifdef PRED_2
/* .75a+.75b-.5c */
#define DECORELATE(channel, prev, curr, bpc_mask, r) { \
int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) - \
(int)(_PIXEL_C(channel, prev) << 1)) >> 2; \
if (p < 0) { \
p = 0; \
} else if ((unsigned)p > bpc_mask) { \
p = bpc_mask; \
} \
r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - p) & bpc_mask]; \
}
#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) { \
const int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) - \
(int)(_PIXEL_C(channel, prev) << 1) ) >> 2; \
const unsigned int s = family.xlatL2U[correlate]; \
if (!(p & ~bpc_mask)) { \
SET_##channel(r, (s + (unsigned)p) & bpc_mask); \
} else if (p < 0) { \
SET_##channel(r, s); \
} else { \
SET_##channel(r, (s + bpc_mask) & bpc_mask); \
} \
}
#endif
#define COMPRESS_ONE_ROW0_0(channel) \
correlate_row_##channel[0] = family.xlatU2L[GET_##channel(cur_row)]; \
golomb_coding(correlate_row_##channel[0], find_bucket(channel_##channel, \
correlate_row_##channel[-1])->bestcode, \
&codeword, &codewordlen); \
encode(encoder, codeword, codewordlen);
#define COMPRESS_ONE_ROW0(channel, index) \
correlate_row_##channel[index] = DECORELATE_0(channel, &cur_row[index], bpc_mask); \
golomb_coding(correlate_row_##channel[index], find_bucket(channel_##channel, \
correlate_row_##channel[index -1])->bestcode, \
&codeword, &codewordlen); \
encode(encoder, codeword, codewordlen);
#define UPDATE_MODEL(index) \
update_model(&encoder->rgb_state, find_bucket(channel_r, correlate_row_r[index - 1]), \
correlate_row_r[index], bpc); \
update_model(&encoder->rgb_state, find_bucket(channel_g, correlate_row_g[index - 1]), \
correlate_row_g[index], bpc); \
update_model(&encoder->rgb_state, find_bucket(channel_b, correlate_row_b[index - 1]), \
correlate_row_b[index], bpc);
#ifdef RLE_PRED_1
#define RLE_PRED_1_IMP \
if (SAME_PIXEL(&cur_row[i - 1], &prev_row[i])) { \
if (run_index != i && SAME_PIXEL(&prev_row[i - 1], &prev_row[i]) && \
i + 1 < end && SAME_PIXEL(&prev_row[i], &prev_row[i + 1])) { \
goto do_run; \
} \
}
#else
#define RLE_PRED_1_IMP
#endif
#ifdef RLE_PRED_2
#define RLE_PRED_2_IMP \
if (SAME_PIXEL(&prev_row[i - 1], &prev_row[i])) { \
if (run_index != i && i > 2 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2])) { \
goto do_run; \
} \
}
#else
#define RLE_PRED_2_IMP
#endif
#ifdef RLE_PRED_3
#define RLE_PRED_3_IMP \
if (i > 1 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2]) && i != run_index) { \
goto do_run; \
}
#else
#define RLE_PRED_3_IMP
#endif
#ifdef COMPRESS_IMP
static void FNAME(compress_row0_seg)(Encoder *encoder, int i,
const PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
Channel * const channel_r = encoder->channels;
Channel * const channel_g = channel_r + 1;
Channel * const channel_b = channel_g + 1;
BYTE * const correlate_row_r = channel_r->correlate_row;
BYTE * const correlate_row_g = channel_g->correlate_row;
BYTE * const correlate_row_b = channel_b->correlate_row;
int stopidx;
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codeword, codewordlen;
COMPRESS_ONE_ROW0_0(r);
COMPRESS_ONE_ROW0_0(g);
COMPRESS_ONE_ROW0_0(b);
if (encoder->rgb_state.waitcnt) {
encoder->rgb_state.waitcnt--;
} else {
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
UPDATE_MODEL(0);
}
stopidx = ++i + encoder->rgb_state.waitcnt;
} else {
stopidx = i + encoder->rgb_state.waitcnt;
}
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codeword, codewordlen;
COMPRESS_ONE_ROW0(r, i);
COMPRESS_ONE_ROW0(g, i);
COMPRESS_ONE_ROW0(b, i);
}
UPDATE_MODEL(stopidx);
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codeword, codewordlen;
COMPRESS_ONE_ROW0(r, i);
COMPRESS_ONE_ROW0(g, i);
COMPRESS_ONE_ROW0(b, i);
}
encoder->rgb_state.waitcnt = stopidx - end;
}
static void FNAME(compress_row0)(Encoder *encoder, const PIXEL *cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
int pos = 0;
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
if (encoder->rgb_state.wmileft) {
FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + encoder->rgb_state.wmileft,
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
width -= encoder->rgb_state.wmileft;
pos += encoder->rgb_state.wmileft;
}
encoder->rgb_state.wmidx++;
set_wm_trigger(&encoder->rgb_state);
encoder->rgb_state.wmileft = wminext;
}
if (width) {
FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + width,
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
if (wmimax > (int)encoder->rgb_state.wmidx) {
encoder->rgb_state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#define COMPRESS_ONE_0(channel) \
correlate_row_##channel[0] = family.xlatU2L[(unsigned)((int)GET_##channel(cur_row) - \
(int)GET_##channel(prev_row) ) & bpc_mask]; \
golomb_coding(correlate_row_##channel[0], \
find_bucket(channel_##channel, correlate_row_##channel[-1])->bestcode, \
&codeword, &codewordlen); \
encode(encoder, codeword, codewordlen);
#define COMPRESS_ONE(channel, index) \
DECORELATE(channel, &prev_row[index], &cur_row[index],bpc_mask, \
correlate_row_##channel[index]); \
golomb_coding(correlate_row_##channel[index], \
find_bucket(channel_##channel, correlate_row_##channel[index - 1])->bestcode, \
&codeword, &codewordlen); \
encode(encoder, codeword, codewordlen);
static void FNAME(compress_row_seg)(Encoder *encoder, int i,
const PIXEL * const prev_row,
const PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
Channel * const channel_r = encoder->channels;
Channel * const channel_g = channel_r + 1;
Channel * const channel_b = channel_g + 1;
BYTE * const correlate_row_r = channel_r->correlate_row;
BYTE * const correlate_row_g = channel_g->correlate_row;
BYTE * const correlate_row_b = channel_b->correlate_row;
int stopidx;
#ifdef RLE
int run_index = 0;
int run_size;
#endif
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codeword, codewordlen;
COMPRESS_ONE_0(r);
COMPRESS_ONE_0(g);
COMPRESS_ONE_0(b);
if (encoder->rgb_state.waitcnt) {
encoder->rgb_state.waitcnt--;
} else {
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
UPDATE_MODEL(0);
}
stopidx = ++i + encoder->rgb_state.waitcnt;
} else {
stopidx = i + encoder->rgb_state.waitcnt;
}
for (;;) {
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codeword, codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
COMPRESS_ONE(r, i);
COMPRESS_ONE(g, i);
COMPRESS_ONE(b, i);
}
UPDATE_MODEL(stopidx);
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codeword, codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
COMPRESS_ONE(r, i);
COMPRESS_ONE(g, i);
COMPRESS_ONE(b, i);
}
encoder->rgb_state.waitcnt = stopidx - end;
return;
#ifdef RLE
do_run:
run_index = i;
encoder->rgb_state.waitcnt = stopidx - i;
run_size = 0;
while (SAME_PIXEL(&cur_row[i], &cur_row[i - 1])) {
run_size++;
if (++i == end) {
encode_run(encoder, run_size);
return;
}
}
encode_run(encoder, run_size);
stopidx = i + encoder->rgb_state.waitcnt;
#endif
}
}
static void FNAME(compress_row)(Encoder *encoder,
const PIXEL * const prev_row,
const PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
unsigned int pos = 0;
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
if (encoder->rgb_state.wmileft) {
FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row,
pos + encoder->rgb_state.wmileft,
bppmask[encoder->rgb_state.wmidx],
bpc, bpc_mask);
width -= encoder->rgb_state.wmileft;
pos += encoder->rgb_state.wmileft;
}
encoder->rgb_state.wmidx++;
set_wm_trigger(&encoder->rgb_state);
encoder->rgb_state.wmileft = wminext;
}
if (width) {
FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row, pos + width,
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
if (wmimax > (int)encoder->rgb_state.wmidx) {
encoder->rgb_state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#endif
#define UNCOMPRESS_ONE_ROW0_0(channel) \
correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
correlate_row_##channel[-1])->bestcode, \
encoder->io_word, &codewordlen); \
SET_##channel(&cur_row[0], (BYTE)family.xlatL2U[correlate_row_##channel[0]]); \
decode_eatbits(encoder, codewordlen);
#define UNCOMPRESS_ONE_ROW0(channel) \
correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
correlate_row_##channel[i - 1])->bestcode, \
encoder->io_word, \
&codewordlen); \
SET_##channel(&cur_row[i], CORELATE_0(channel, &cur_row[i], correlate_row_##channel[i], \
bpc_mask)); \
decode_eatbits(encoder, codewordlen);
static void FNAME(uncompress_row0_seg)(Encoder *encoder, int i,
PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
Channel * const channel_r = encoder->channels;
Channel * const channel_g = channel_r + 1;
Channel * const channel_b = channel_g + 1;
BYTE * const correlate_row_r = channel_r->correlate_row;
BYTE * const correlate_row_g = channel_g->correlate_row;
BYTE * const correlate_row_b = channel_b->correlate_row;
int stopidx;
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codewordlen;
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE_ROW0_0(r);
UNCOMPRESS_ONE_ROW0_0(g);
UNCOMPRESS_ONE_ROW0_0(b);
if (encoder->rgb_state.waitcnt) {
--encoder->rgb_state.waitcnt;
} else {
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
UPDATE_MODEL(0);
}
stopidx = ++i + encoder->rgb_state.waitcnt;
} else {
stopidx = i + encoder->rgb_state.waitcnt;
}
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codewordlen;
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE_ROW0(r);
UNCOMPRESS_ONE_ROW0(g);
UNCOMPRESS_ONE_ROW0(b);
}
UPDATE_MODEL(stopidx);
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codewordlen;
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE_ROW0(r);
UNCOMPRESS_ONE_ROW0(g);
UNCOMPRESS_ONE_ROW0(b);
}
encoder->rgb_state.waitcnt = stopidx - end;
}
static void FNAME(uncompress_row0)(Encoder *encoder,
PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
unsigned int pos = 0;
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
if (encoder->rgb_state.wmileft) {
FNAME(uncompress_row0_seg)(encoder, pos, cur_row,
pos + encoder->rgb_state.wmileft,
bppmask[encoder->rgb_state.wmidx],
bpc, bpc_mask);
pos += encoder->rgb_state.wmileft;
width -= encoder->rgb_state.wmileft;
}
encoder->rgb_state.wmidx++;
set_wm_trigger(&encoder->rgb_state);
encoder->rgb_state.wmileft = wminext;
}
if (width) {
FNAME(uncompress_row0_seg)(encoder, pos, cur_row, pos + width,
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
if (wmimax > (int)encoder->rgb_state.wmidx) {
encoder->rgb_state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#define UNCOMPRESS_ONE_0(channel) \
correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
correlate_row_##channel[-1])->bestcode, \
encoder->io_word, &codewordlen); \
SET_##channel(&cur_row[0], (family.xlatL2U[correlate_row_##channel[0]] + \
GET_##channel(prev_row)) & bpc_mask); \
decode_eatbits(encoder, codewordlen);
#define UNCOMPRESS_ONE(channel) \
correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
correlate_row_##channel[i - 1])->bestcode, \
encoder->io_word, \
&codewordlen); \
CORELATE(channel, &prev_row[i], &cur_row[i], correlate_row_##channel[i], bpc_mask, \
&cur_row[i]); \
decode_eatbits(encoder, codewordlen);
static void FNAME(uncompress_row_seg)(Encoder *encoder,
const PIXEL * const prev_row,
PIXEL * const cur_row,
int i,
const int end,
const unsigned int bpc,
const unsigned int bpc_mask)
{
Channel * const channel_r = encoder->channels;
Channel * const channel_g = channel_r + 1;
Channel * const channel_b = channel_g + 1;
BYTE * const correlate_row_r = channel_r->correlate_row;
BYTE * const correlate_row_g = channel_g->correlate_row;
BYTE * const correlate_row_b = channel_b->correlate_row;
const unsigned int waitmask = bppmask[encoder->rgb_state.wmidx];
int stopidx;
#ifdef RLE
int run_index = 0;
int run_end;
#endif
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codewordlen;
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE_0(r);
UNCOMPRESS_ONE_0(g);
UNCOMPRESS_ONE_0(b);
if (encoder->rgb_state.waitcnt) {
--encoder->rgb_state.waitcnt;
} else {
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
UPDATE_MODEL(0);
}
stopidx = ++i + encoder->rgb_state.waitcnt;
} else {
stopidx = i + encoder->rgb_state.waitcnt;
}
for (;;) {
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE(r);
UNCOMPRESS_ONE(g);
UNCOMPRESS_ONE(b);
}
UPDATE_MODEL(stopidx);
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE(r);
UNCOMPRESS_ONE(g);
UNCOMPRESS_ONE(b);
}
encoder->rgb_state.waitcnt = stopidx - end;
return;
#ifdef RLE
do_run:
encoder->rgb_state.waitcnt = stopidx - i;
run_index = i;
run_end = i + decode_run(encoder);
for (; i < run_end; i++) {
UNCOMPRESS_PIX_START(&cur_row[i]);
SET_r(&cur_row[i], GET_r(&cur_row[i - 1]));
SET_g(&cur_row[i], GET_g(&cur_row[i - 1]));
SET_b(&cur_row[i], GET_b(&cur_row[i - 1]));
}
if (i == end) {
return;
}
stopidx = i + encoder->rgb_state.waitcnt;
#endif
}
}
static void FNAME(uncompress_row)(Encoder *encoder,
const PIXEL * const prev_row,
PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
unsigned int pos = 0;
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
if (encoder->rgb_state.wmileft) {
FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
pos + encoder->rgb_state.wmileft, bpc, bpc_mask);
pos += encoder->rgb_state.wmileft;
width -= encoder->rgb_state.wmileft;
}
encoder->rgb_state.wmidx++;
set_wm_trigger(&encoder->rgb_state);
encoder->rgb_state.wmileft = wminext;
}
if (width) {
FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
pos + width, bpc, bpc_mask);
if (wmimax > (int)encoder->rgb_state.wmidx) {
encoder->rgb_state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#undef PIXEL
#undef FNAME
#undef _PIXEL_A
#undef _PIXEL_B
#undef _PIXEL_C
#undef SAME_PIXEL
#undef RLE_PRED_1_IMP
#undef RLE_PRED_2_IMP
#undef RLE_PRED_3_IMP
#undef UPDATE_MODEL
#undef DECORELATE_0
#undef DECORELATE
#undef COMPRESS_ONE_ROW0_0
#undef COMPRESS_ONE_ROW0
#undef COMPRESS_ONE_0
#undef COMPRESS_ONE
#undef CORELATE_0
#undef CORELATE
#undef UNCOMPRESS_ONE_ROW0_0
#undef UNCOMPRESS_ONE_ROW0
#undef UNCOMPRESS_ONE_0
#undef UNCOMPRESS_ONE
#undef golomb_coding
#undef golomb_decoding
#undef update_model
#undef find_bucket
#undef family
#undef BPC
#undef BPC_MASK
#undef COMPRESS_IMP
#undef SET_r
#undef GET_r
#undef SET_g
#undef GET_g
#undef SET_b
#undef GET_b
#undef UNCOMPRESS_PIX_START

View File

@ -1,635 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef ONE_BYTE
#undef ONE_BYTE
#define FNAME(name) quic_one_##name
#define PIXEL one_byte_t
#endif
#ifdef THREE_BYTE
#undef THREE_BYTE
#define FNAME(name) quic_three_##name
#define PIXEL three_bytes_t
#endif
#ifdef FOUR_BYTE
#undef FOUR_BYTE
#define FNAME(name) quic_four_##name
#define PIXEL four_bytes_t
#endif
#define golomb_coding golomb_coding_8bpc
#define golomb_decoding golomb_decoding_8bpc
#define update_model update_model_8bpc
#define find_bucket find_bucket_8bpc
#define family family_8bpc
#define BPC 8
#define BPC_MASK 0xffU
#define _PIXEL_A ((unsigned int)curr[-1].a)
#define _PIXEL_B ((unsigned int)prev[0].a)
#define _PIXEL_C ((unsigned int)prev[-1].a)
#ifdef RLE_PRED_1
#define RLE_PRED_1_IMP \
if (cur_row[i - 1].a == prev_row[i].a) { \
if (run_index != i && prev_row[i - 1].a == prev_row[i].a && \
i + 1 < end && prev_row[i].a == prev_row[i + 1].a) { \
goto do_run; \
} \
}
#else
#define RLE_PRED_1_IMP
#endif
#ifdef RLE_PRED_2
#define RLE_PRED_2_IMP \
if (prev_row[i - 1].a == prev_row[i].a) { \
if (run_index != i && i > 2 && cur_row[i - 1].a == cur_row[i - 2].a) { \
goto do_run; \
} \
}
#else
#define RLE_PRED_2_IMP
#endif
#ifdef RLE_PRED_3
#define RLE_PRED_3_IMP \
if (i > 1 && cur_row[i - 1].a == cur_row[i - 2].a && i != run_index) { \
goto do_run; \
}
#else
#define RLE_PRED_3_IMP
#endif
/* a */
static INLINE BYTE FNAME(decorelate_0)(const PIXEL * const curr, const unsigned int bpc_mask)
{
return family.xlatU2L[(unsigned)((int)curr[0].a - (int)_PIXEL_A) & bpc_mask];
}
static INLINE void FNAME(corelate_0)(PIXEL *curr, const BYTE corelate,
const unsigned int bpc_mask)
{
curr->a = (family.xlatL2U[corelate] + _PIXEL_A) & bpc_mask;
}
#ifdef PRED_1
/* (a+b)/2 */
static INLINE BYTE FNAME(decorelate)(const PIXEL *const prev, const PIXEL * const curr,
const unsigned int bpc_mask)
{
return family.xlatU2L[(unsigned)((int)curr->a - (int)((_PIXEL_A + _PIXEL_B) >> 1)) & bpc_mask];
}
static INLINE void FNAME(corelate)(const PIXEL *prev, PIXEL *curr, const BYTE corelate,
const unsigned int bpc_mask)
{
curr->a = (family.xlatL2U[corelate] + (int)((_PIXEL_A + _PIXEL_B) >> 1)) & bpc_mask;
}
#endif
#ifdef PRED_2
/* .75a+.75b-.5c */
static INLINE BYTE FNAME(decorelate)(const PIXEL *const prev, const PIXEL * const curr,
const unsigned int bpc_mask)
{
int p = ((int)(3 * (_PIXEL_A + _PIXEL_B)) - (int)(_PIXEL_C << 1)) >> 2;
if (p < 0) {
p = 0;
} else if ((unsigned)p > bpc_mask) {
p = bpc_mask;
}
{
return family.xlatU2L[(unsigned)((int)curr->a - p) & bpc_mask];
}
}
static INLINE void FNAME(corelate)(const PIXEL *prev, PIXEL *curr, const BYTE corelate,
const unsigned int bpc_mask)
{
const int p = ((int)(3 * (_PIXEL_A + _PIXEL_B)) - (int)(_PIXEL_C << 1)) >> 2;
const unsigned int s = family.xlatL2U[corelate];
if (!(p & ~bpc_mask)) {
curr->a = (s + (unsigned)p) & bpc_mask;
} else if (p < 0) {
curr->a = s;
} else {
curr->a = (s + bpc_mask) & bpc_mask;
}
}
#endif
static void FNAME(compress_row0_seg)(Encoder *encoder, Channel *channel, int i,
const PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
BYTE * const decorelate_drow = channel->correlate_row;
int stopidx;
ASSERT(encoder->usr, end - i > 0);
if (i == 0) {
unsigned int codeword, codewordlen;
decorelate_drow[0] = family.xlatU2L[cur_row->a];
golomb_coding(decorelate_drow[0], find_bucket(channel, decorelate_drow[-1])->bestcode,
&codeword, &codewordlen);
encode(encoder, codeword, codewordlen);
if (channel->state.waitcnt) {
channel->state.waitcnt--;
} else {
channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
update_model(&channel->state, find_bucket(channel, decorelate_drow[-1]),
decorelate_drow[i], bpc);
}
stopidx = ++i + channel->state.waitcnt;
} else {
stopidx = i + channel->state.waitcnt;
}
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codeword, codewordlen;
decorelate_drow[i] = FNAME(decorelate_0)(&cur_row[i], bpc_mask);
golomb_coding(decorelate_drow[i],
find_bucket(channel, decorelate_drow[i - 1])->bestcode, &codeword,
&codewordlen);
encode(encoder, codeword, codewordlen);
}
update_model(&channel->state, find_bucket(channel, decorelate_drow[stopidx - 1]),
decorelate_drow[stopidx], bpc);
stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codeword, codewordlen;
decorelate_drow[i] = FNAME(decorelate_0)(&cur_row[i], bpc_mask);
golomb_coding(decorelate_drow[i], find_bucket(channel, decorelate_drow[i - 1])->bestcode,
&codeword, &codewordlen);
encode(encoder, codeword, codewordlen);
}
channel->state.waitcnt = stopidx - end;
}
static void FNAME(compress_row0)(Encoder *encoder, Channel *channel, const PIXEL *cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
int pos = 0;
while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
if (channel->state.wmileft) {
FNAME(compress_row0_seg)(encoder, channel, pos, cur_row, pos + channel->state.wmileft,
bppmask[channel->state.wmidx], bpc, bpc_mask);
width -= channel->state.wmileft;
pos += channel->state.wmileft;
}
channel->state.wmidx++;
set_wm_trigger(&channel->state);
channel->state.wmileft = wminext;
}
if (width) {
FNAME(compress_row0_seg)(encoder, channel, pos, cur_row, pos + width,
bppmask[channel->state.wmidx], bpc, bpc_mask);
if (wmimax > (int)channel->state.wmidx) {
channel->state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
ASSERT(encoder->usr, channel->state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
static void FNAME(compress_row_seg)(Encoder *encoder, Channel *channel, int i,
const PIXEL * const prev_row,
const PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
BYTE * const decorelate_drow = channel->correlate_row;
int stopidx;
#ifdef RLE
int run_index = 0;
int run_size;
#endif
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codeword, codewordlen;
decorelate_drow[0] = family.xlatU2L[(unsigned)((int)cur_row->a -
(int)prev_row->a) & bpc_mask];
golomb_coding(decorelate_drow[0],
find_bucket(channel, decorelate_drow[-1])->bestcode,
&codeword,
&codewordlen);
encode(encoder, codeword, codewordlen);
if (channel->state.waitcnt) {
channel->state.waitcnt--;
} else {
channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
update_model(&channel->state, find_bucket(channel, decorelate_drow[-1]),
decorelate_drow[0], bpc);
}
stopidx = ++i + channel->state.waitcnt;
} else {
stopidx = i + channel->state.waitcnt;
}
for (;;) {
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codeword, codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
decorelate_drow[i] = FNAME(decorelate)(&prev_row[i], &cur_row[i], bpc_mask);
golomb_coding(decorelate_drow[i],
find_bucket(channel, decorelate_drow[i - 1])->bestcode, &codeword,
&codewordlen);
encode(encoder, codeword, codewordlen);
}
update_model(&channel->state, find_bucket(channel, decorelate_drow[stopidx - 1]),
decorelate_drow[stopidx], bpc);
stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codeword, codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
decorelate_drow[i] = FNAME(decorelate)(&prev_row[i], &cur_row[i], bpc_mask);
golomb_coding(decorelate_drow[i], find_bucket(channel,
decorelate_drow[i - 1])->bestcode,
&codeword, &codewordlen);
encode(encoder, codeword, codewordlen);
}
channel->state.waitcnt = stopidx - end;
return;
#ifdef RLE
do_run:
run_index = i;
channel->state.waitcnt = stopidx - i;
run_size = 0;
while (cur_row[i].a == cur_row[i - 1].a) {
run_size++;
if (++i == end) {
#ifdef RLE_STAT
encode_channel_run(encoder, channel, run_size);
#else
encode_run(encoder, run_size);
#endif
return;
}
}
#ifdef RLE_STAT
encode_channel_run(encoder, channel, run_size);
#else
encode_run(encoder, run_size);
#endif
stopidx = i + channel->state.waitcnt;
#endif
}
}
static void FNAME(compress_row)(Encoder *encoder, Channel *channel,
const PIXEL * const prev_row,
const PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
unsigned int pos = 0;
while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
if (channel->state.wmileft) {
FNAME(compress_row_seg)(encoder, channel, pos, prev_row, cur_row,
pos + channel->state.wmileft, bppmask[channel->state.wmidx],
bpc, bpc_mask);
width -= channel->state.wmileft;
pos += channel->state.wmileft;
}
channel->state.wmidx++;
set_wm_trigger(&channel->state);
channel->state.wmileft = wminext;
}
if (width) {
FNAME(compress_row_seg)(encoder, channel, pos, prev_row, cur_row, pos + width,
bppmask[channel->state.wmidx], bpc, bpc_mask);
if (wmimax > (int)channel->state.wmidx) {
channel->state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
ASSERT(encoder->usr, channel->state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
static void FNAME(uncompress_row0_seg)(Encoder *encoder, Channel *channel, int i,
BYTE * const correlate_row,
PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
int stopidx;
ASSERT(encoder->usr, end - i > 0);
if (i == 0) {
unsigned int codewordlen;
correlate_row[0] = (BYTE)golomb_decoding(find_bucket(channel,
correlate_row[-1])->bestcode,
encoder->io_word, &codewordlen);
cur_row[0].a = (BYTE)family.xlatL2U[correlate_row[0]];
decode_eatbits(encoder, codewordlen);
if (channel->state.waitcnt) {
--channel->state.waitcnt;
} else {
channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
update_model(&channel->state, find_bucket(channel, correlate_row[-1]),
correlate_row[0], bpc);
}
stopidx = ++i + channel->state.waitcnt;
} else {
stopidx = i + channel->state.waitcnt;
}
while (stopidx < end) {
struct s_bucket * pbucket = NULL;
for (; i <= stopidx; i++) {
unsigned int codewordlen;
pbucket = find_bucket(channel, correlate_row[i - 1]);
correlate_row[i] = (BYTE)golomb_decoding(pbucket->bestcode, encoder->io_word,
&codewordlen);
FNAME(corelate_0)(&cur_row[i], correlate_row[i], bpc_mask);
decode_eatbits(encoder, codewordlen);
}
update_model(&channel->state, pbucket, correlate_row[stopidx], bpc);
stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codewordlen;
correlate_row[i] = (BYTE)golomb_decoding(find_bucket(channel,
correlate_row[i - 1])->bestcode,
encoder->io_word, &codewordlen);
FNAME(corelate_0)(&cur_row[i], correlate_row[i], bpc_mask);
decode_eatbits(encoder, codewordlen);
}
channel->state.waitcnt = stopidx - end;
}
static void FNAME(uncompress_row0)(Encoder *encoder, Channel *channel,
PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
BYTE * const correlate_row = channel->correlate_row;
unsigned int pos = 0;
while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
if (channel->state.wmileft) {
FNAME(uncompress_row0_seg)(encoder, channel, pos, correlate_row, cur_row,
pos + channel->state.wmileft, bppmask[channel->state.wmidx],
bpc, bpc_mask);
pos += channel->state.wmileft;
width -= channel->state.wmileft;
}
channel->state.wmidx++;
set_wm_trigger(&channel->state);
channel->state.wmileft = wminext;
}
if (width) {
FNAME(uncompress_row0_seg)(encoder, channel, pos, correlate_row, cur_row, pos + width,
bppmask[channel->state.wmidx], bpc, bpc_mask);
if (wmimax > (int)channel->state.wmidx) {
channel->state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
ASSERT(encoder->usr, channel->state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
static void FNAME(uncompress_row_seg)(Encoder *encoder, Channel *channel,
BYTE *correlate_row,
const PIXEL * const prev_row,
PIXEL * const cur_row,
int i,
const int end,
const unsigned int bpc,
const unsigned int bpc_mask)
{
const unsigned int waitmask = bppmask[channel->state.wmidx];
int stopidx;
#ifdef RLE
int run_index = 0;
int run_end;
#endif
ASSERT(encoder->usr, end - i > 0);
if (i == 0) {
unsigned int codewordlen;
correlate_row[0] = (BYTE)golomb_decoding(find_bucket(channel, correlate_row[-1])->bestcode,
encoder->io_word, &codewordlen);
cur_row[0].a = (family.xlatL2U[correlate_row[0]] + prev_row[0].a) & bpc_mask;
decode_eatbits(encoder, codewordlen);
if (channel->state.waitcnt) {
--channel->state.waitcnt;
} else {
channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
update_model(&channel->state, find_bucket(channel, correlate_row[-1]),
correlate_row[0], bpc);
}
stopidx = ++i + channel->state.waitcnt;
} else {
stopidx = i + channel->state.waitcnt;
}
for (;;) {
while (stopidx < end) {
struct s_bucket * pbucket = NULL;
for (; i <= stopidx; i++) {
unsigned int codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
pbucket = find_bucket(channel, correlate_row[i - 1]);
correlate_row[i] = (BYTE)golomb_decoding(pbucket->bestcode, encoder->io_word,
&codewordlen);
FNAME(corelate)(&prev_row[i], &cur_row[i], correlate_row[i], bpc_mask);
decode_eatbits(encoder, codewordlen);
}
update_model(&channel->state, pbucket, correlate_row[stopidx], bpc);
stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
correlate_row[i] = (BYTE)golomb_decoding(find_bucket(channel,
correlate_row[i - 1])->bestcode,
encoder->io_word, &codewordlen);
FNAME(corelate)(&prev_row[i], &cur_row[i], correlate_row[i], bpc_mask);
decode_eatbits(encoder, codewordlen);
}
channel->state.waitcnt = stopidx - end;
return;
#ifdef RLE
do_run:
channel->state.waitcnt = stopidx - i;
run_index = i;
#ifdef RLE_STAT
run_end = i + decode_channel_run(encoder, channel);
#else
run_end = i + decode_run(encoder);
#endif
for (; i < run_end; i++) {
cur_row[i].a = cur_row[i - 1].a;
}
if (i == end) {
return;
}
stopidx = i + channel->state.waitcnt;
#endif
}
}
static void FNAME(uncompress_row)(Encoder *encoder, Channel *channel,
const PIXEL * const prev_row,
PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
BYTE * const correlate_row = channel->correlate_row;
unsigned int pos = 0;
while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
if (channel->state.wmileft) {
FNAME(uncompress_row_seg)(encoder, channel, correlate_row, prev_row, cur_row, pos,
pos + channel->state.wmileft, bpc, bpc_mask);
pos += channel->state.wmileft;
width -= channel->state.wmileft;
}
channel->state.wmidx++;
set_wm_trigger(&channel->state);
channel->state.wmileft = wminext;
}
if (width) {
FNAME(uncompress_row_seg)(encoder, channel, correlate_row, prev_row, cur_row, pos,
pos + width, bpc, bpc_mask);
if (wmimax > (int)channel->state.wmidx) {
channel->state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
ASSERT(encoder->usr, channel->state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#undef PIXEL
#undef FNAME
#undef _PIXEL_A
#undef _PIXEL_B
#undef _PIXEL_C
#undef RLE_PRED_1_IMP
#undef RLE_PRED_2_IMP
#undef RLE_PRED_3_IMP
#undef golomb_coding
#undef golomb_deoding
#undef update_model
#undef find_bucket
#undef family
#undef BPC
#undef BPC_MASK

View File

@ -1,122 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RECT
#define _H_RECT
#include "draw.h"
#include <spice/macros.h>
#ifdef __cplusplus
extern "C" {
#endif
static INLINE void rect_sect(SpiceRect* r, const SpiceRect* bounds)
{
r->left = MAX(r->left, bounds->left);
r->right = MIN(r->right, bounds->right);
r->right = MAX(r->left, r->right);
r->top = MAX(r->top, bounds->top);
r->bottom = MIN(r->bottom, bounds->bottom);
r->bottom = MAX(r->top, r->bottom);
}
static INLINE void rect_offset(SpiceRect* r, int dx, int dy)
{
r->left += dx;
r->right += dx;
r->top += dy;
r->bottom += dy;
}
static INLINE int rect_is_empty(const SpiceRect* r)
{
return r->top == r->bottom || r->left == r->right;
}
static INLINE int rect_intersects(const SpiceRect* r1, const SpiceRect* r2)
{
return r1->left < r2->right && r1->right > r2->left &&
r1->top < r2->bottom && r1->bottom > r2->top;
}
static INLINE int rect_is_equal(const SpiceRect *r1, const SpiceRect *r2)
{
return r1->top == r2->top && r1->left == r2->left &&
r1->bottom == r2->bottom && r1->right == r2->right;
}
static INLINE void rect_union(SpiceRect *dest, const SpiceRect *r)
{
dest->top = MIN(dest->top, r->top);
dest->left = MIN(dest->left, r->left);
dest->bottom = MAX(dest->bottom, r->bottom);
dest->right = MAX(dest->right, r->right);
}
static INLINE int rect_is_same_size(const SpiceRect *r1, const SpiceRect *r2)
{
return r1->right - r1->left == r2->right - r2->left &&
r1->bottom - r1->top == r2->bottom - r2->top;
}
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
static inline void rect_sect(SpiceRect& r, const SpiceRect& bounds)
{
rect_sect(&r, &bounds);
}
static inline void rect_offset(SpiceRect& r, int dx, int dy)
{
rect_offset(&r, dx, dy);
}
static inline int rect_is_empty(const SpiceRect& r)
{
return rect_is_empty(&r);
}
static inline int rect_intersects(const SpiceRect& r1, const SpiceRect& r2)
{
return rect_intersects(&r1, &r2);
}
static inline int rect_is_equal(const SpiceRect& r1, const SpiceRect& r2)
{
return rect_is_equal(&r1, &r2);
}
static inline void rect_union(SpiceRect& dest, const SpiceRect& r)
{
rect_union(&dest, &r);
}
static inline int rect_is_same_size(const SpiceRect& r1, const SpiceRect& r2)
{
return rect_is_same_size(&r1, &r2);
}
#endif
#endif

View File

@ -1,890 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <spice/macros.h>
#include "region.h"
#include "rect.h"
#include "mem.h"
/* true iff two Boxes overlap */
#define EXTENTCHECK(r1, r2) \
(!( ((r1)->x2 <= (r2)->x1) || \
((r1)->x1 >= (r2)->x2) || \
((r1)->y2 <= (r2)->y1) || \
((r1)->y1 >= (r2)->y2) ) )
/* true iff Box r1 contains Box r2 */
#define SUBSUMES(r1, r2) \
( ((r1)->x1 <= (r2)->x1) && \
((r1)->x2 >= (r2)->x2) && \
((r1)->y1 <= (r2)->y1) && \
((r1)->y2 >= (r2)->y2) )
void region_init(QRegion *rgn)
{
pixman_region32_init(rgn);
}
void region_clear(QRegion *rgn)
{
pixman_region32_fini(rgn);
pixman_region32_init(rgn);
}
void region_destroy(QRegion *rgn)
{
pixman_region32_fini(rgn);
}
void region_clone(QRegion *dest, const QRegion *src)
{
pixman_region32_init(dest);
pixman_region32_copy(dest, (pixman_region32_t *)src);
}
#define FIND_BAND(r, r_band_end, r_end, ry1) \
do { \
ry1 = r->y1; \
r_band_end = r + 1; \
while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \
r_band_end++; \
} \
} while (0)
static int test_band(int query,
int res,
pixman_box32_t *r1,
pixman_box32_t *r1_end,
pixman_box32_t *r2,
pixman_box32_t *r2_end)
{
int x1;
int x2;
do {
x1 = MAX(r1->x1, r2->x1);
x2 = MIN(r1->x2, r2->x2);
/*
* Is there any overlap between the two rectangles?
*/
if (x1 < x2) {
res |= REGION_TEST_SHARED;
if (r1->x1 < r2->x1 || r1->x2 > r2->x2) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
}
if (r2->x1 < r1->x1 || r2->x2 > r1->x2) {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
} else {
/* No overlap at all, the leftmost is exclusive */
if (r1->x1 < r2->x1) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
} else {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
}
if ((res & query) == query) {
return res;
}
/*
* Advance the pointer(s) with the leftmost right side, since the next
* rectangle on that list may still overlap the other region's
* current rectangle.
*/
if (r1->x2 == x2) {
r1++;
}
if (r2->x2 == x2) {
r2++;
}
} while ((r1 != r1_end) && (r2 != r2_end));
/*
* Deal with whichever band (if any) still has rectangles left.
*/
if (r1 != r1_end) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
} else if (r2 != r2_end) {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
return res;
}
static int test_generic (pixman_region32_t *reg1,
pixman_region32_t *reg2,
int query)
{
pixman_box32_t *r1; /* Pointer into first region */
pixman_box32_t *r2; /* Pointer into 2d region */
pixman_box32_t *r1_end; /* End of 1st region */
pixman_box32_t *r2_end; /* End of 2d region */
int ybot; /* Bottom of intersection */
int ytop; /* Top of intersection */
pixman_box32_t * r1_band_end; /* End of current band in r1 */
pixman_box32_t * r2_band_end; /* End of current band in r2 */
int top; /* Top of non-overlapping band */
int bot; /* Bottom of non-overlapping band*/
int r1y1; /* Temps for r1->y1 and r2->y1 */
int r2y1;
int r1_num_rects;
int r2_num_rects;
int res;
r1 = pixman_region32_rectangles(reg1, &r1_num_rects);
r1_end = r1 + r1_num_rects;
r2 = pixman_region32_rectangles(reg2, &r2_num_rects);
r2_end = r2 + r2_num_rects;
res = 0;
/*
* Initialize ybot.
* In the upcoming loop, ybot and ytop serve different functions depending
* on whether the band being handled is an overlapping or non-overlapping
* band.
* In the case of a non-overlapping band (only one of the regions
* has points in the band), ybot is the bottom of the most recent
* intersection and thus clips the top of the rectangles in that band.
* ytop is the top of the next intersection between the two regions and
* serves to clip the bottom of the rectangles in the current band.
* For an overlapping band (where the two regions intersect), ytop clips
* the top of the rectangles of both regions and ybot clips the bottoms.
*/
ybot = MIN(r1->y1, r2->y1);
do {
/*
* This algorithm proceeds one source-band (as opposed to a
* destination band, which is determined by where the two regions
* intersect) at a time. r1_band_end and r2_band_end serve to mark the
* rectangle after the last one in the current band for their
* respective regions.
*/
FIND_BAND(r1, r1_band_end, r1_end, r1y1);
FIND_BAND(r2, r2_band_end, r2_end, r2y1);
/*
* First handle the band that doesn't intersect, if any.
*
* Note that attention is restricted to one band in the
* non-intersecting region at once, so if a region has n
* bands between the current position and the next place it overlaps
* the other, this entire loop will be passed through n times.
*/
if (r1y1 < r2y1) {
top = MAX (r1y1, ybot);
bot = MIN (r1->y2, r2y1);
if (top != bot) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
if ((res & query) == query) {
return res & query;
}
}
ytop = r2y1;
} else if (r2y1 < r1y1) {
top = MAX (r2y1, ybot);
bot = MIN (r2->y2, r1y1);
if (top != bot) {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
if ((res & query) == query) {
return res & query;
}
}
ytop = r1y1;
} else {
ytop = r1y1;
}
/*
* Now see if we've hit an intersecting band. The two bands only
* intersect if ybot > ytop
*/
ybot = MIN (r1->y2, r2->y2);
if (ybot > ytop) {
res = test_band(query, res,
r1, r1_band_end,
r2, r2_band_end);
if ((res & query) == query) {
return res & query;
}
}
/*
* If we've finished with a band (y2 == ybot) we skip forward
* in the region to the next band.
*/
if (r1->y2 == ybot) {
r1 = r1_band_end;
}
if (r2->y2 == ybot) {
r2 = r2_band_end;
}
}
while (r1 != r1_end && r2 != r2_end);
/*
* Deal with whichever region (if any) still has rectangles left.
*/
if (r1 != r1_end) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
} else if (r2 != r2_end) {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
return res & query;
}
int region_test(const QRegion *_reg1, const QRegion *_reg2, int query)
{
int res;
pixman_region32_t *reg1 = (pixman_region32_t *)_reg1;
pixman_region32_t *reg2 = (pixman_region32_t *)_reg2;
query = (query) ? query & REGION_TEST_ALL : REGION_TEST_ALL;
res = 0;
if (!pixman_region32_not_empty(reg1) || !pixman_region32_not_empty(reg2) ||
!EXTENTCHECK (&reg1->extents, &reg2->extents)) {
/* One or more regions are empty or they are disjoint */
if (pixman_region32_not_empty(reg1)) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
}
if (pixman_region32_not_empty(reg2)) {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
return res & query;
} else if (!reg1->data && !reg2->data) {
/* Just two rectangles that intersect */
res |= REGION_TEST_SHARED;
if (!SUBSUMES(&reg1->extents, &reg2->extents)) {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
if (!SUBSUMES(&reg2->extents, &reg1->extents)) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
}
return res & query;
} else if (!reg2->data && SUBSUMES (&reg2->extents, &reg1->extents)) {
/* reg2 is just a rect that contains all of reg1 */
res |= REGION_TEST_SHARED; /* some piece must be shared, because reg is not empty */
res |= REGION_TEST_RIGHT_EXCLUSIVE; /* reg2 contains all of reg1 and then some */
return res & query;
} else if (!reg1->data && SUBSUMES (&reg1->extents, &reg2->extents)) {
/* reg1 is just a rect that contains all of reg2 */
res |= REGION_TEST_SHARED; /* some piece must be shared, because reg is not empty */
res |= REGION_TEST_LEFT_EXCLUSIVE; /* reg1 contains all of reg2 and then some */
return res & query;
} else if (reg1 == reg2) {
res |= REGION_TEST_SHARED;
return res & query;
} else {
/* General purpose intersection */
return test_generic (reg1, reg2, query);
}
}
int region_is_valid(const QRegion *rgn)
{
return pixman_region32_selfcheck((pixman_region32_t *)rgn);
}
int region_is_empty(const QRegion *rgn)
{
return !pixman_region32_not_empty((pixman_region32_t *)rgn);
}
SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects)
{
pixman_box32_t *boxes;
SpiceRect *rects;
int n, i;
boxes = pixman_region32_rectangles((pixman_region32_t *)rgn, &n);
if (num_rects) {
*num_rects = n;
}
rects = spice_new(SpiceRect, n);
for (i = 0; i < n; i++) {
rects[i].left = boxes[i].x1;
rects[i].top = boxes[i].y1;
rects[i].right = boxes[i].x2;
rects[i].bottom = boxes[i].y2;
}
return rects;
}
void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects)
{
pixman_box32_t *boxes;
unsigned int n, i;
boxes = pixman_region32_rectangles((pixman_region32_t *)rgn, (int *)&n);
for (i = 0; i < n && i < num_rects; i++) {
rects[i].left = boxes[i].x1;
rects[i].top = boxes[i].y1;
rects[i].right = boxes[i].x2;
rects[i].bottom = boxes[i].y2;
}
if (i && i != n) {
unsigned int x;
for (x = 0; x < (n - num_rects); ++x) {
rects[i - 1].left = MIN(rects[i - 1].left, boxes[i + x].x1);
rects[i - 1].top = MIN(rects[i - 1].top, boxes[i + x].y1);
rects[i - 1].right = MAX(rects[i - 1].right, boxes[i + x].x2);
rects[i - 1].bottom = MAX(rects[i - 1].bottom, boxes[i + x].y2);
}
}
}
int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
{
return pixman_region32_equal((pixman_region32_t *)rgn1, (pixman_region32_t *)rgn2);
}
int region_intersects(const QRegion *rgn1, const QRegion *rgn2)
{
int test_res;
if (!region_bounds_intersects(rgn1, rgn2)) {
return FALSE;
}
test_res = region_test(rgn1, rgn2, REGION_TEST_SHARED);
return !!test_res;
}
int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2)
{
pixman_box32_t *extents1, *extents2;
extents1 = pixman_region32_extents((pixman_region32_t *)rgn1);
extents2 = pixman_region32_extents((pixman_region32_t *)rgn1);
return EXTENTCHECK(extents1, extents2);
}
int region_contains(const QRegion *rgn, const QRegion *other)
{
int test_res;
test_res = region_test(rgn, other, REGION_TEST_RIGHT_EXCLUSIVE);
return !test_res;
}
int region_contains_point(const QRegion *rgn, int32_t x, int32_t y)
{
return pixman_region32_contains_point((pixman_region32_t *)rgn, x, y, NULL);
}
void region_or(QRegion *rgn, const QRegion *other_rgn)
{
pixman_region32_union(rgn, rgn, (pixman_region32_t *)other_rgn);
}
void region_and(QRegion *rgn, const QRegion *other_rgn)
{
pixman_region32_intersect(rgn, rgn, (pixman_region32_t *)other_rgn);
}
void region_xor(QRegion *rgn, const QRegion *other_rgn)
{
pixman_region32_t intersection;
pixman_region32_copy(&intersection, rgn);
pixman_region32_intersect(&intersection,
&intersection,
(pixman_region32_t *)other_rgn);
pixman_region32_union(rgn, rgn, (pixman_region32_t *)other_rgn);
pixman_region32_subtract(rgn, rgn, &intersection);
pixman_region32_fini(&intersection);
}
void region_exclude(QRegion *rgn, const QRegion *other_rgn)
{
pixman_region32_subtract(rgn, rgn, (pixman_region32_t *)other_rgn);
}
void region_add(QRegion *rgn, const SpiceRect *r)
{
pixman_region32_union_rect(rgn, rgn, r->left, r->top,
r->right - r->left,
r->bottom - r->top);
}
void region_remove(QRegion *rgn, const SpiceRect *r)
{
pixman_region32_t rg;
pixman_region32_init_rect(&rg, r->left, r->top,
r->right - r->left,
r->bottom - r->top);
pixman_region32_subtract(rgn, rgn, &rg);
pixman_region32_fini(&rg);
}
void region_offset(QRegion *rgn, int32_t dx, int32_t dy)
{
pixman_region32_translate(rgn, dx, dy);
}
void region_dump(const QRegion *rgn, const char *prefix)
{
pixman_box32_t *rects, *extents;
int n_rects, i;
printf("%sREGION: %p, ", prefix, rgn);
if (!pixman_region32_not_empty((pixman_region32_t *)rgn)) {
printf("EMPTY\n");
return;
}
extents = pixman_region32_extents((pixman_region32_t *)rgn);
rects = pixman_region32_rectangles((pixman_region32_t *)rgn, &n_rects);
printf("num %u bounds (%d, %d, %d, %d)\n",
n_rects,
extents->x1,
extents->y1,
extents->x2,
extents->y2);
for (i = 0; i < n_rects; i++) {
printf("%*s %12d %12d %12d %12d\n",
(int)strlen(prefix), "",
rects[i].x1,
rects[i].y1,
rects[i].x2,
rects[i].y2);
}
}
#ifdef REGION_TEST
static int slow_region_test(const QRegion *rgn, const QRegion *other_rgn, int query)
{
pixman_region32_t intersection;
int res;
pixman_region32_init(&intersection);
pixman_region32_intersect(&intersection,
(pixman_region32_t *)rgn,
(pixman_region32_t *)other_rgn);
res = 0;
if (query & REGION_TEST_SHARED &&
pixman_region32_not_empty(&intersection)) {
res |= REGION_TEST_SHARED;
}
if (query & REGION_TEST_LEFT_EXCLUSIVE &&
!pixman_region32_equal(&intersection, (pixman_region32_t *)rgn)) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
}
if (query & REGION_TEST_RIGHT_EXCLUSIVE &&
!pixman_region32_equal(&intersection, (pixman_region32_t *)other_rgn)) {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
pixman_region32_fini(&intersection);
return res;
}
static int rect_is_valid(const SpiceRect *r)
{
if (r->top > r->bottom || r->left > r->right) {
printf("%s: invalid rect\n", __FUNCTION__);
return FALSE;
}
return TRUE;
}
static void rect_set(SpiceRect *r, int32_t top, int32_t left, int32_t bottom, int32_t right)
{
r->top = top;
r->left = left;
r->bottom = bottom;
r->right = right;
ASSERT(rect_is_valid(r));
}
static void random_region(QRegion *reg)
{
int i;
int num_rects;
int x, y, w, h;
SpiceRect _r;
SpiceRect *r = &_r;
region_clear(reg);
num_rects = rand() % 20;
for (i = 0; i < num_rects; i++) {
x = rand()%100;
y = rand()%100;
w = rand()%100;
h = rand()%100;
rect_set(r,
x, y,
x+w, y+h);
region_add(reg, r);
}
}
static void test(const QRegion *r1, const QRegion *r2, int *expected)
{
printf("r1 is_empty %s [%s]\n",
region_is_empty(r1) ? "TRUE" : "FALSE",
(region_is_empty(r1) == *(expected++)) ? "OK" : "ERR");
printf("r2 is_empty %s [%s]\n",
region_is_empty(r2) ? "TRUE" : "FALSE",
(region_is_empty(r2) == *(expected++)) ? "OK" : "ERR");
printf("is_equal %s [%s]\n",
region_is_equal(r1, r2) ? "TRUE" : "FALSE",
(region_is_equal(r1, r2) == *(expected++)) ? "OK" : "ERR");
printf("intersects %s [%s]\n",
region_intersects(r1, r2) ? "TRUE" : "FALSE",
(region_intersects(r1, r2) == *(expected++)) ? "OK" : "ERR");
printf("contains %s [%s]\n",
region_contains(r1, r2) ? "TRUE" : "FALSE",
(region_contains(r1, r2) == *(expected++)) ? "OK" : "ERR");
}
enum {
EXPECT_R1_EMPTY,
EXPECT_R2_EMPTY,
EXPECT_EQUAL,
EXPECT_SECT,
EXPECT_CONT,
};
int main(void)
{
QRegion _r1, _r2, _r3;
QRegion *r1 = &_r1;
QRegion *r2 = &_r2;
QRegion *r3 = &_r3;
SpiceRect _r;
SpiceRect *r = &_r;
int expected[5];
int i, j;
region_init(r1);
region_init(r2);
printf("dump r1 empty rgn [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = TRUE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clone(r3, r1);
printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID");
region_dump(r3, "");
expected[EXPECT_R1_EMPTY] = TRUE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r3, expected);
region_destroy(r3);
printf("\n");
rect_set(r, 0, 0, 100, 100);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r1);
rect_set(r, 0, 0, 0, 0);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = TRUE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
rect_set(r, -100, -100, 0, 0);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r1);
rect_set(r, -100, -100, 100, 100);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r1);
region_clear(r2);
rect_set(r, 100, 100, 200, 200);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
rect_set(r, 300, 300, 400, 400);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
rect_set(r, 500, 500, 600, 600);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = FALSE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, 100, 100, 200, 200);
region_add(r2, r);
rect_set(r, 300, 300, 400, 400);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, 100, 100, 200, 200);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, -2000, -2000, -1000, -1000);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = FALSE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, -2000, -2000, 1000, 1000);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = FALSE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, 150, 150, 175, 175);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, 150, 150, 350, 350);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = FALSE;
test(r1, r2, expected);
printf("\n");
region_and(r2, r1);
printf("dump r2 and r1 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = FALSE;
test(r2, r1, expected);
printf("\n");
region_clone(r3, r1);
printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID");
region_dump(r3, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = TRUE;
test(r1, r3, expected);
printf("\n");
j = 0;
for (i = 0; i < 1000000; i++) {
int res1, res2, test;
int tests[] = {
REGION_TEST_LEFT_EXCLUSIVE,
REGION_TEST_RIGHT_EXCLUSIVE,
REGION_TEST_SHARED,
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE,
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_SHARED,
REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED,
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED
};
random_region(r1);
random_region(r2);
for (test = 0; test < 7; test++) {
res1 = region_test(r1, r2, tests[test]);
res2 = slow_region_test(r1, r2, tests[test]);
if (res1 != res2) {
printf ("Error in region_test %d, got %d, expected %d, query=%d\n",
j, res1, res2, tests[test]);
printf ("r1:\n");
region_dump(r1, "");
printf ("r2:\n");
region_dump(r2, "");
}
j++;
}
}
region_destroy(r3);
region_destroy(r1);
region_destroy(r2);
return 0;
}
#endif

View File

@ -1,70 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_REGION
#define _H_REGION
#include <stdint.h>
#include "draw.h"
#include <pixman_utils.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef pixman_region32_t QRegion;
#define REGION_TEST_LEFT_EXCLUSIVE (1 << 0)
#define REGION_TEST_RIGHT_EXCLUSIVE (1 << 1)
#define REGION_TEST_SHARED (1 << 2)
#define REGION_TEST_ALL \
(REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED)
void region_init(QRegion *rgn);
void region_clear(QRegion *rgn);
void region_destroy(QRegion *rgn);
void region_clone(QRegion *dest, const QRegion *src);
SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects);
void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects);
int region_test(const QRegion *rgn, const QRegion *other_rgn, int query);
int region_is_valid(const QRegion *rgn);
int region_is_empty(const QRegion *rgn);
int region_is_equal(const QRegion *rgn1, const QRegion *rgn2);
int region_intersects(const QRegion *rgn1, const QRegion *rgn2);
int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2);
int region_contains(const QRegion *rgn, const QRegion *other);
int region_contains_point(const QRegion *rgn, int32_t x, int32_t y);
void region_or(QRegion *rgn, const QRegion *other_rgn);
void region_and(QRegion *rgn, const QRegion *other_rgn);
void region_xor(QRegion *rgn, const QRegion *other_rgn);
void region_exclude(QRegion *rgn, const QRegion *other_rgn);
void region_add(QRegion *rgn, const SpiceRect *r);
void region_remove(QRegion *rgn, const SpiceRect *r);
void region_offset(QRegion *rgn, int32_t dx, int32_t dy);
void region_dump(const QRegion *rgn, const char *prefix);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,172 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RING2
#define _H_RING2
#include "spice_common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Ring RingItem;
typedef struct Ring {
RingItem *prev;
RingItem *next;
} Ring;
static inline void ring_init(Ring *ring)
{
ring->next = ring->prev = ring;
}
static inline void ring_item_init(RingItem *item)
{
item->next = item->prev = NULL;
}
static inline int ring_item_is_linked(RingItem *item)
{
return !!item->next;
}
static inline int ring_is_empty(Ring *ring)
{
ASSERT(ring->next != NULL && ring->prev != NULL);
return ring == ring->next;
}
static inline void ring_add(Ring *ring, RingItem *item)
{
ASSERT(ring->next != NULL && ring->prev != NULL);
ASSERT(item->next == NULL && item->prev == NULL);
item->next = ring->next;
item->prev = ring;
ring->next = item->next->prev = item;
}
static inline void ring_add_after(RingItem *item, RingItem *pos)
{
ring_add(pos, item);
}
static inline void ring_add_before(RingItem *item, RingItem *pos)
{
ring_add(pos->prev, item);
}
static inline void __ring_remove(RingItem *item)
{
item->next->prev = item->prev;
item->prev->next = item->next;
item->prev = item->next = 0;
}
static inline void ring_remove(RingItem *item)
{
ASSERT(item->next != NULL && item->prev != NULL);
ASSERT(item->next != item);
__ring_remove(item);
}
static inline RingItem *ring_get_head(Ring *ring)
{
RingItem *ret;
ASSERT(ring->next != NULL && ring->prev != NULL);
if (ring_is_empty(ring)) {
return NULL;
}
ret = ring->next;
return ret;
}
static inline RingItem *ring_get_tail(Ring *ring)
{
RingItem *ret;
ASSERT(ring->next != NULL && ring->prev != NULL);
if (ring_is_empty(ring)) {
return NULL;
}
ret = ring->prev;
return ret;
}
static inline RingItem *ring_next(Ring *ring, RingItem *pos)
{
RingItem *ret;
ASSERT(ring->next != NULL && ring->prev != NULL);
ASSERT(pos);
ASSERT(pos->next != NULL && pos->prev != NULL);
ret = pos->next;
return (ret == ring) ? NULL : ret;
}
static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
{
RingItem *ret;
ASSERT(ring->next != NULL && ring->prev != NULL);
ASSERT(pos);
ASSERT(pos->next != NULL && pos->prev != NULL);
ret = pos->prev;
return (ret == ring) ? NULL : ret;
}
#define RING_FOREACH_SAFE(var, next, ring) \
for ((var) = ring_get_head(ring); \
(var) && ((next) = ring_next(ring, (var)), 1); \
(var) = (next))
#define RING_FOREACH(var, ring) \
for ((var) = ring_get_head(ring); \
(var); \
(var) = ring_next(ring, var))
#define RING_FOREACH_REVERSED(var, ring) \
for ((var) = ring_get_tail(ring); \
(var); \
(var) = ring_prev(ring, var))
static inline unsigned int ring_get_length(Ring *ring)
{
RingItem *i;
unsigned int ret = 0;
for (i = ring_get_head(ring);
i != NULL;
i = ring_next(ring, i))
ret++;
return ret;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,650 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include "rop3.h"
#include "spice_common.h"
typedef void (*rop3_with_pattern_handler_t)(pixman_image_t *d, pixman_image_t *s,
SpicePoint *src_pos, pixman_image_t *p,
SpicePoint *pat_pos);
typedef void (*rop3_with_color_handler_t)(pixman_image_t *d, pixman_image_t *s,
SpicePoint *src_pos, uint32_t rgb);
typedef void (*rop3_test_handler_t)(void);
#define ROP3_NUM_OPS 256
static rop3_with_pattern_handler_t rop3_with_pattern_handlers_32[ROP3_NUM_OPS];
static rop3_with_pattern_handler_t rop3_with_pattern_handlers_16[ROP3_NUM_OPS];
static rop3_with_color_handler_t rop3_with_color_handlers_32[ROP3_NUM_OPS];
static rop3_with_color_handler_t rop3_with_color_handlers_16[ROP3_NUM_OPS];
static rop3_test_handler_t rop3_test_handlers_32[ROP3_NUM_OPS];
static rop3_test_handler_t rop3_test_handlers_16[ROP3_NUM_OPS];
static void default_rop3_with_pattern_handler(pixman_image_t *d, pixman_image_t *s,
SpicePoint *src_pos, pixman_image_t *p,
SpicePoint *pat_pos)
{
WARN("not implemented");
}
static void default_rop3_withe_color_handler(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
uint32_t rgb)
{
WARN("not implemented");
}
static void default_rop3_test_handler(void)
{
}
#define ROP3_HANDLERS_DEPTH(name, formula, index, depth) \
static void rop3_handle_p##depth##_##name(pixman_image_t *d, pixman_image_t *s, \
SpicePoint *src_pos, \
pixman_image_t *p, SpicePoint *pat_pos) \
{ \
int width = pixman_image_get_width(d); \
int height = pixman_image_get_height(d); \
uint8_t *dest_line = (uint8_t *)pixman_image_get_data(d); \
int dest_stride = pixman_image_get_stride(d); \
uint8_t *end_line = dest_line + height * dest_stride; \
\
int pat_width = pixman_image_get_width(p); \
int pat_height = pixman_image_get_height(p); \
uint8_t *pat_base = (uint8_t *)pixman_image_get_data(p); \
int pat_stride = pixman_image_get_stride(p); \
int pat_v_offset = pat_pos->y; \
\
int src_stride = pixman_image_get_stride(s); \
uint8_t *src_line; \
src_line = (uint8_t *)pixman_image_get_data(s) + src_pos->y * src_stride + (src_pos->x * depth / 8); \
\
for (; dest_line < end_line; dest_line += dest_stride, src_line += src_stride) { \
uint##depth##_t *dest = (uint##depth##_t *)dest_line; \
uint##depth##_t *end = dest + width; \
uint##depth##_t *src = (uint##depth##_t *)src_line; \
\
int pat_h_offset = pat_pos->x; \
\
for (; dest < end; dest++, src++) { \
uint##depth##_t *pat; \
pat = (uint##depth##_t *) \
(pat_base + pat_v_offset * pat_stride + (pat_h_offset * depth / 8)); \
*dest = formula; \
pat_h_offset = (pat_h_offset + 1) % pat_width; \
} \
\
pat_v_offset = (pat_v_offset + 1) % pat_height; \
} \
} \
\
static void rop3_handle_c##depth##_##name(pixman_image_t *d, pixman_image_t *s, \
SpicePoint *src_pos, \
uint32_t rgb) \
{ \
int width = pixman_image_get_width(d); \
int height = pixman_image_get_height(d); \
uint8_t *dest_line = (uint8_t *)pixman_image_get_data(d); \
int dest_stride = pixman_image_get_stride(d); \
uint8_t *end_line = dest_line + height * dest_stride; \
uint##depth##_t _pat = rgb; \
uint##depth##_t *pat = &_pat; \
\
int src_stride = pixman_image_get_stride(s); \
uint8_t *src_line; \
src_line = (uint8_t *) \
pixman_image_get_data(s) + src_pos->y * src_stride + (src_pos->x * depth / 8); \
\
for (; dest_line < end_line; dest_line += dest_stride, src_line += src_stride) { \
uint##depth##_t *dest = (uint##depth##_t *)dest_line; \
uint##depth##_t *end = dest + width; \
uint##depth##_t *src = (uint##depth##_t *)src_line; \
for (; dest < end; dest++, src++) { \
*dest = formula; \
} \
} \
} \
\
static void rop3_test##depth##_##name(void) \
{ \
uint8_t d = 0xaa; \
uint8_t s = 0xcc; \
uint8_t p = 0xf0; \
uint8_t *pat = &p; \
uint8_t *src = &s; \
uint8_t *dest = &d; \
\
d = formula; \
if (d != index) { \
printf("%s: failed, result is 0x%x expect 0x%x\n", __FUNCTION__, d, index); \
} \
}
#define ROP3_HANDLERS(name, formula, index) \
ROP3_HANDLERS_DEPTH(name, formula, index, 32) \
ROP3_HANDLERS_DEPTH(name, formula, index, 16)
ROP3_HANDLERS(DPSoon, ~(*pat | *src | *dest), 0x01);
ROP3_HANDLERS(DPSona, ~(*pat | *src) & *dest, 0x02);
ROP3_HANDLERS(SDPona, ~(*pat | *dest) & *src, 0x04);
ROP3_HANDLERS(PDSxnon, ~(~(*src ^ *dest) | *pat), 0x06);
ROP3_HANDLERS(PDSaon, ~((*src & *dest) | *pat), 0x07);
ROP3_HANDLERS(SDPnaa, ~*pat & *dest & *src, 0x08);
ROP3_HANDLERS(PDSxon, ~((*src ^ *dest) | *pat), 0x09);
ROP3_HANDLERS(PSDnaon, ~((~*dest & *src) | *pat), 0x0b);
ROP3_HANDLERS(PDSnaon, ~((~*src & *dest) | *pat), 0x0d);
ROP3_HANDLERS(PDSonon, ~(~(*src | *dest) | *pat), 0x0e);
ROP3_HANDLERS(PDSona, ~(*src | *dest) & *pat, 0x10);
ROP3_HANDLERS(SDPxnon, ~(~(*pat ^ *dest) | *src), 0x12);
ROP3_HANDLERS(SDPaon, ~((*pat & *dest) | *src), 0x13);
ROP3_HANDLERS(DPSxnon, ~(~(*pat ^ *src) | *dest), 0x14);
ROP3_HANDLERS(DPSaon, ~((*pat & *src) | *dest), 0x15);
ROP3_HANDLERS(PSDPSanaxx, (~(*pat & *src) & *dest) ^ *src ^ *pat, 0x16);
ROP3_HANDLERS(SSPxDSxaxn, ~(((*src ^ *dest) & (*src ^ *pat)) ^ *src), 0x17);
ROP3_HANDLERS(SPxPDxa, (*src ^ *pat) & (*pat ^ *dest), 0x18);
ROP3_HANDLERS(SDPSanaxn, ~((~(*pat & *src) & *dest) ^ *src), 0x19);
ROP3_HANDLERS(PDSPaox, ((*pat & *src) | *dest) ^ *pat, 0x1a);
ROP3_HANDLERS(SDPSxaxn, ~(((*pat ^ *src) & *dest) ^ *src), 0x1b);
ROP3_HANDLERS(PSDPaox, ((*pat & *dest) | *src) ^ *pat, 0x1c);
ROP3_HANDLERS(DSPDxaxn, ~(((*pat ^ *dest) & *src) ^ *dest), 0x1d);
ROP3_HANDLERS(PDSox, (*dest | *src) ^ *pat, 0x1e);
ROP3_HANDLERS(PDSoan, ~((*src | *dest) & *pat), 0x1f);
ROP3_HANDLERS(DPSnaa, ~*src & *pat & *dest, 0x20);
ROP3_HANDLERS(SDPxon, ~((*pat ^ *dest) | *src), 0x21);
ROP3_HANDLERS(SPDnaon, ~((~*dest & *pat) | *src), 0x23);
ROP3_HANDLERS(SPxDSxa, (*src ^ *pat) & (*dest ^ *src), 0x24);
ROP3_HANDLERS(PDSPanaxn, ~((~(*src & *pat) & *dest) ^ *pat), 0x25);
ROP3_HANDLERS(SDPSaox, ((*src & *pat) | *dest) ^ *src, 0x26);
ROP3_HANDLERS(SDPSxnox, (~(*src ^ *pat) | *dest) ^ *src, 0x27);
ROP3_HANDLERS(DPSxa, (*pat ^ *src) & *dest, 0x28);
ROP3_HANDLERS(PSDPSaoxxn, ~(((*src & *pat) | *dest) ^ *src ^ *pat), 0x29);
ROP3_HANDLERS(DPSana, ~(*src & *pat) & *dest, 0x2a);
ROP3_HANDLERS(SSPxPDxaxn, ~(((*pat ^ *dest) & (*src ^ *pat)) ^ *src), 0x2b);
ROP3_HANDLERS(SPDSoax, ((*src | *dest) & *pat) ^ *src, 0x2c);
ROP3_HANDLERS(PSDnox, (~*dest | *src) ^ *pat, 0x2d);
ROP3_HANDLERS(PSDPxox, ((*pat ^ *dest) | *src) ^ *pat, 0x2e);
ROP3_HANDLERS(PSDnoan, ~((~*dest | *src) & *pat), 0x2f);
ROP3_HANDLERS(SDPnaon, ~((~*pat & *dest) | *src), 0x31);
ROP3_HANDLERS(SDPSoox, (*src | *pat | *dest) ^ *src, 0x32);
ROP3_HANDLERS(SPDSaox, ((*src & *dest) | *pat) ^ *src, 0x34);
ROP3_HANDLERS(SPDSxnox, (~(*src ^ *dest) | *pat) ^ *src, 0x35);
ROP3_HANDLERS(SDPox, (*pat | *dest) ^ *src, 0x36);
ROP3_HANDLERS(SDPoan, ~((*pat | *dest) & *src), 0x37);
ROP3_HANDLERS(PSDPoax, ((*pat | *dest) & *src) ^ *pat, 0x38);
ROP3_HANDLERS(SPDnox, (~*dest | *pat) ^ *src, 0x39);
ROP3_HANDLERS(SPDSxox, ((*src ^ *dest) | *pat) ^ *src, 0x3a);
ROP3_HANDLERS(SPDnoan, ~((~*dest | *pat) & *src), 0x3b);
ROP3_HANDLERS(SPDSonox, (~(*src | *dest) | *pat) ^ *src, 0x3d);
ROP3_HANDLERS(SPDSnaox, ((~*src & *dest) | *pat) ^ *src, 0x3e);
ROP3_HANDLERS(PSDnaa, ~*dest & *src & *pat, 0x40);
ROP3_HANDLERS(DPSxon, ~((*src ^ *pat) | *dest), 0x41);
ROP3_HANDLERS(SDxPDxa, (*src ^ *dest) & (*pat ^ *dest), 0x42);
ROP3_HANDLERS(SPDSanaxn, ~((~(*src & *dest) & *pat) ^ *src), 0x43);
ROP3_HANDLERS(DPSnaon, ~((~*src & *pat) | *dest), 0x45);
ROP3_HANDLERS(DSPDaox, ((*dest & *pat) | *src) ^ *dest, 0x46);
ROP3_HANDLERS(PSDPxaxn, ~(((*pat ^ *dest) & *src) ^ *pat), 0x47);
ROP3_HANDLERS(SDPxa, (*pat ^ *dest) & *src, 0x48);
ROP3_HANDLERS(PDSPDaoxxn, ~(((*dest & *pat) | *src) ^ *dest ^ *pat), 0x49);
ROP3_HANDLERS(DPSDoax, ((*dest | *src) & *pat) ^ *dest, 0x4a);
ROP3_HANDLERS(PDSnox, (~*src | *dest) ^ *pat, 0x4b);
ROP3_HANDLERS(SDPana, ~(*pat & *dest) & *src, 0x4c);
ROP3_HANDLERS(SSPxDSxoxn, ~(((*src ^ *dest) | (*src ^ *pat)) ^ *src), 0x4d);
ROP3_HANDLERS(PDSPxox, ((*pat ^ *src) | *dest) ^ *pat, 0x4e);
ROP3_HANDLERS(PDSnoan, ~((~*src | *dest) & *pat), 0x4f);
ROP3_HANDLERS(DSPnaon, ~((~*pat & *src) | *dest), 0x51);
ROP3_HANDLERS(DPSDaox, ((*dest & *src) | *pat) ^ *dest, 0x52);
ROP3_HANDLERS(SPDSxaxn, ~(((*src ^ *dest) & *pat) ^ *src), 0x53);
ROP3_HANDLERS(DPSonon, ~(~(*src | *pat) | *dest), 0x54);
ROP3_HANDLERS(DPSox, (*src | *pat) ^ *dest, 0x56);
ROP3_HANDLERS(DPSoan, ~((*src | *pat) & *dest), 0x57);
ROP3_HANDLERS(PDSPoax, ((*pat | *src) & *dest) ^ *pat, 0x58);
ROP3_HANDLERS(DPSnox, (~*src | *pat) ^ *dest, 0x59);
ROP3_HANDLERS(DPSDonox, (~(*dest | *src) | *pat) ^ *dest, 0x5b);
ROP3_HANDLERS(DPSDxox, ((*dest ^ *src) | *pat) ^ *dest, 0x5c);
ROP3_HANDLERS(DPSnoan, ~((~*src | *pat) & *dest), 0x5d);
ROP3_HANDLERS(DPSDnaox, ((~*dest & *src) | *pat) ^ *dest, 0x5e);
ROP3_HANDLERS(PDSxa, (*src ^ *dest) & *pat, 0x60);
ROP3_HANDLERS(DSPDSaoxxn, ~(((*src & *dest) | *pat) ^ *src ^ *dest), 0x61);
ROP3_HANDLERS(DSPDoax, ((*dest | *pat) & *src) ^ *dest, 0x62);
ROP3_HANDLERS(SDPnox, (~*pat | *dest) ^ *src, 0x63);
ROP3_HANDLERS(SDPSoax, ((*src | *pat) & *dest) ^ *src, 0x64);
ROP3_HANDLERS(DSPnox, (~*pat | *src) ^ *dest, 0x65);
ROP3_HANDLERS(SDPSonox, (~(*src | *pat) | *dest) ^ *src, 0x67);
ROP3_HANDLERS(DSPDSonoxxn, ~((~(*src | *dest) | *pat) ^ *src ^ *dest), 0x68);
ROP3_HANDLERS(PDSxxn, ~(*src ^ *dest ^ *pat), 0x69);
ROP3_HANDLERS(DPSax, (*src & *pat) ^ *dest, 0x6a);
ROP3_HANDLERS(PSDPSoaxxn, ~(((*src | *pat) & *dest) ^ *src ^ *pat), 0x6b);
ROP3_HANDLERS(SDPax, (*pat & *dest) ^ *src, 0x6c);
ROP3_HANDLERS(PDSPDoaxxn, ~(((*dest | *pat) & *src) ^ *dest ^ *pat), 0x6d);
ROP3_HANDLERS(SDPSnoax, ((~*src | *pat) & *dest) ^ *src, 0x6e);
ROP3_HANDLERS(PDSxnan, ~(~(*src ^ *dest) & *pat), 0x6f);
ROP3_HANDLERS(PDSana, ~(*src & *dest) & *pat, 0x70);
ROP3_HANDLERS(SSDxPDxaxn, ~(((*dest ^ *pat) & (*src ^ *dest)) ^ *src), 0x71);
ROP3_HANDLERS(SDPSxox, ((*src ^ *pat) | *dest) ^ *src, 0x72);
ROP3_HANDLERS(SDPnoan, ~((~*pat | *dest) & *src), 0x73);
ROP3_HANDLERS(DSPDxox, ((*dest ^ *pat) | *src) ^ *dest, 0x74);
ROP3_HANDLERS(DSPnoan, ~((~*pat | *src) & *dest), 0x75);
ROP3_HANDLERS(SDPSnaox, ((~*src & *pat) | *dest) ^ *src, 0x76);
ROP3_HANDLERS(PDSax, (*src & *dest) ^ *pat, 0x78);
ROP3_HANDLERS(DSPDSoaxxn, ~(((*src | *dest) & *pat) ^ *src ^ *dest), 0x79);
ROP3_HANDLERS(DPSDnoax, ((~*dest | *src) & *pat) ^ *dest, 0x7a);
ROP3_HANDLERS(SDPxnan, ~(~(*pat ^ *dest) & *src), 0x7b);
ROP3_HANDLERS(SPDSnoax, ((~*src | *dest) & *pat) ^ *src, 0x7c);
ROP3_HANDLERS(DPSxnan, ~(~(*src ^ *pat) & *dest), 0x7d);
ROP3_HANDLERS(SPxDSxo, (*src ^ *dest) | (*pat ^ *src), 0x7e);
ROP3_HANDLERS(DPSaan, ~(*src & *pat & *dest), 0x7f);
ROP3_HANDLERS(DPSaa, *src & *pat & *dest, 0x80);
ROP3_HANDLERS(SPxDSxon, ~((*src ^ *dest) | (*pat ^ *src)), 0x81);
ROP3_HANDLERS(DPSxna, ~(*src ^ *pat) & *dest, 0x82);
ROP3_HANDLERS(SPDSnoaxn, ~(((~*src | *dest) & *pat) ^ *src), 0x83);
ROP3_HANDLERS(SDPxna, ~(*pat ^ *dest) & *src, 0x84);
ROP3_HANDLERS(PDSPnoaxn, ~(((~*pat | *src) & *dest) ^ *pat), 0x85);
ROP3_HANDLERS(DSPDSoaxx, ((*src | *dest) & *pat) ^ *src ^ *dest, 0x86);
ROP3_HANDLERS(PDSaxn, ~((*src & *dest) ^ *pat), 0x87);
ROP3_HANDLERS(SDPSnaoxn, ~(((~*src & *pat) | *dest) ^ *src), 0x89);
ROP3_HANDLERS(DSPnoa, (~*pat | *src) & *dest, 0x8a);
ROP3_HANDLERS(DSPDxoxn, ~(((*dest ^ *pat) | *src) ^ *dest), 0x8b);
ROP3_HANDLERS(SDPnoa, (~*pat | *dest) & *src, 0x8c);
ROP3_HANDLERS(SDPSxoxn, ~(((*src ^ *pat) | *dest) ^ *src), 0x8d);
ROP3_HANDLERS(SSDxPDxax, ((*dest ^ *pat) & (*dest ^ *src)) ^ *src, 0x8e);
ROP3_HANDLERS(PDSanan, ~(~(*src & *dest) & *pat), 0x8f);
ROP3_HANDLERS(PDSxna, ~(*src ^ *dest) & *pat, 0x90);
ROP3_HANDLERS(SDPSnoaxn, ~(((~*src | *pat) & *dest) ^ *src), 0x91);
ROP3_HANDLERS(DPSDPoaxx, ((*pat | *dest) & *src) ^ *pat ^ *dest, 0x92);
ROP3_HANDLERS(SPDaxn, ~((*dest & *pat) ^ *src), 0x93);
ROP3_HANDLERS(PSDPSoaxx, ((*src | *pat) & *dest) ^ *src ^ *pat, 0x94);
ROP3_HANDLERS(DPSaxn, ~((*src & *pat) ^ *dest), 0x95);
ROP3_HANDLERS(DPSxx, *src ^ *pat ^ *dest, 0x96);
ROP3_HANDLERS(PSDPSonoxx, (~(*src | *pat) | *dest) ^ *src ^ *pat, 0x97);
ROP3_HANDLERS(SDPSonoxn, ~((~(*src | *pat) | *dest) ^ *src), 0x98);
ROP3_HANDLERS(DPSnax, (~*src & *pat) ^ *dest, 0x9a);
ROP3_HANDLERS(SDPSoaxn, ~(((*src | *pat) & *dest) ^ *src), 0x9b);
ROP3_HANDLERS(SPDnax, (~*dest & *pat) ^ *src, 0x9c);
ROP3_HANDLERS(DSPDoaxn, ~(((*dest | *pat) & *src) ^ *dest), 0x9d);
ROP3_HANDLERS(DSPDSaoxx, ((*src & *dest) | *pat) ^ *src ^ *dest, 0x9e);
ROP3_HANDLERS(PDSxan, ~((*src ^ *dest) & *pat), 0x9f);
ROP3_HANDLERS(PDSPnaoxn, ~(((~*pat & *src) | *dest) ^ *pat), 0xa1);
ROP3_HANDLERS(DPSnoa, (~*src | *pat) & *dest, 0xa2);
ROP3_HANDLERS(DPSDxoxn, ~(((*dest ^ *src) | *pat) ^ *dest), 0xa3);
ROP3_HANDLERS(PDSPonoxn, ~((~(*pat | *src) | *dest) ^ *pat), 0xa4);
ROP3_HANDLERS(DSPnax, (~*pat & *src) ^ *dest, 0xa6);
ROP3_HANDLERS(PDSPoaxn, ~(((*pat | *src) & *dest) ^ *pat), 0xa7);
ROP3_HANDLERS(DPSoa, (*src | *pat) & *dest, 0xa8);
ROP3_HANDLERS(DPSoxn, ~((*src | *pat) ^ *dest), 0xa9);
ROP3_HANDLERS(DPSono, ~(*src | *pat) | *dest, 0xab);
ROP3_HANDLERS(SPDSxax, ((*src ^ *dest) & *pat) ^ *src, 0xac);
ROP3_HANDLERS(DPSDaoxn, ~(((*dest & *src) | *pat) ^ *dest), 0xad);
ROP3_HANDLERS(DSPnao, (~*pat & *src) | *dest, 0xae);
ROP3_HANDLERS(PDSnoa, (~*src | *dest) & *pat, 0xb0);
ROP3_HANDLERS(PDSPxoxn, ~(((*pat ^ *src) | *dest) ^ *pat), 0xb1);
ROP3_HANDLERS(SSPxDSxox, ((*src ^ *dest) | (*pat ^ *src)) ^ *src, 0xb2);
ROP3_HANDLERS(SDPanan, ~(~(*pat & *dest) & *src), 0xb3);
ROP3_HANDLERS(PSDnax, (~*dest & *src) ^ *pat, 0xb4);
ROP3_HANDLERS(DPSDoaxn, ~(((*dest | *src) & *pat) ^ *dest), 0xb5);
ROP3_HANDLERS(DPSDPaoxx, ((*pat & *dest) | *src) ^ *pat ^ *dest, 0xb6);
ROP3_HANDLERS(SDPxan, ~((*pat ^ *dest) & *src), 0xb7);
ROP3_HANDLERS(PSDPxax, ((*dest ^ *pat) & *src) ^ *pat, 0xb8);
ROP3_HANDLERS(DSPDaoxn, ~(((*dest & *pat) | *src) ^ *dest), 0xb9);
ROP3_HANDLERS(DPSnao, (~*src & *pat) | *dest, 0xba);
ROP3_HANDLERS(SPDSanax, (~(*src & *dest) & *pat) ^ *src, 0xbc);
ROP3_HANDLERS(SDxPDxan, ~((*dest ^ *pat) & (*dest ^ *src)), 0xbd);
ROP3_HANDLERS(DPSxo, (*src ^ *pat) | *dest, 0xbe);
ROP3_HANDLERS(DPSano, ~(*src & *pat) | *dest, 0xbf);
ROP3_HANDLERS(SPDSnaoxn, ~(((~*src & *dest) | *pat) ^ *src), 0xc1);
ROP3_HANDLERS(SPDSonoxn, ~((~(*src | *dest) | *pat) ^ *src), 0xc2);
ROP3_HANDLERS(SPDnoa, (~*dest | *pat) & *src, 0xc4);
ROP3_HANDLERS(SPDSxoxn, ~(((*src ^ *dest) | *pat) ^ *src), 0xc5);
ROP3_HANDLERS(SDPnax, (~*pat & *dest) ^ *src, 0xc6);
ROP3_HANDLERS(PSDPoaxn, ~(((*pat | *dest) & *src) ^ *pat), 0xc7);
ROP3_HANDLERS(SDPoa, (*pat | *dest) & *src, 0xc8);
ROP3_HANDLERS(SPDoxn, ~((*dest | *pat) ^ *src), 0xc9);
ROP3_HANDLERS(DPSDxax, ((*dest ^ *src) & *pat) ^ *dest, 0xca);
ROP3_HANDLERS(SPDSaoxn, ~(((*src & *dest) | *pat) ^ *src), 0xcb);
ROP3_HANDLERS(SDPono, ~(*pat | *dest) | *src, 0xcd);
ROP3_HANDLERS(SDPnao, (~*pat & *dest) | *src, 0xce);
ROP3_HANDLERS(PSDnoa, (~*dest | *src) & *pat, 0xd0);
ROP3_HANDLERS(PSDPxoxn, ~(((*pat ^ *dest) | *src) ^ *pat), 0xd1);
ROP3_HANDLERS(PDSnax, (~*src & *dest) ^ *pat, 0xd2);
ROP3_HANDLERS(SPDSoaxn, ~(((*src | *dest) & *pat) ^ *src), 0xd3);
ROP3_HANDLERS(SSPxPDxax, ((*dest ^ *pat) & (*pat ^ *src)) ^ *src, 0xd4);
ROP3_HANDLERS(DPSanan, ~(~(*src & *pat) & *dest), 0xd5);
ROP3_HANDLERS(PSDPSaoxx, ((*src & *pat) | *dest) ^ *src ^ *pat, 0xd6);
ROP3_HANDLERS(DPSxan, ~((*src ^ *pat) & *dest), 0xd7);
ROP3_HANDLERS(PDSPxax, ((*pat ^ *src) & *dest) ^ *pat, 0xd8);
ROP3_HANDLERS(SDPSaoxn, ~(((*src & *pat) | *dest) ^ *src), 0xd9);
ROP3_HANDLERS(DPSDanax, (~(*dest & *src) & *pat) ^ *dest, 0xda);
ROP3_HANDLERS(SPxDSxan, ~((*src ^ *dest) & (*pat ^ *src)), 0xdb);
ROP3_HANDLERS(SPDnao, (~*dest & *pat) | *src, 0xdc);
ROP3_HANDLERS(SDPxo, (*pat ^ *dest) | *src, 0xde);
ROP3_HANDLERS(SDPano, ~(*pat & *dest) | *src, 0xdf);
ROP3_HANDLERS(PDSoa, (*src | *dest) & *pat, 0xe0);
ROP3_HANDLERS(PDSoxn, ~((*src | *dest) ^ *pat), 0xe1);
ROP3_HANDLERS(DSPDxax, ((*dest ^ *pat) & *src) ^ *dest, 0xe2);
ROP3_HANDLERS(PSDPaoxn, ~(((*pat & *dest) | *src) ^ *pat), 0xe3);
ROP3_HANDLERS(SDPSxax, ((*src ^ *pat) & *dest) ^ *src, 0xe4);
ROP3_HANDLERS(PDSPaoxn, ~(((*pat & *src) | *dest) ^ *pat), 0xe5);
ROP3_HANDLERS(SDPSanax, (~(*src & *pat) & *dest) ^ *src, 0xe6);
ROP3_HANDLERS(SPxPDxan, ~((*dest ^ *pat) & (*pat ^ *src)), 0xe7);
ROP3_HANDLERS(SSPxDSxax, ((*src ^ *dest) & (*pat ^ *src)) ^ *src, 0xe8);
ROP3_HANDLERS(DSPDSanaxxn, ~((~(*src & *dest) & *pat) ^ *src ^ *dest), 0xe9);
ROP3_HANDLERS(DPSao, (*src & *pat) | *dest, 0xea);
ROP3_HANDLERS(DPSxno, ~(*src ^ *pat) | *dest, 0xeb);
ROP3_HANDLERS(SDPao, (*pat & *dest) | *src, 0xec);
ROP3_HANDLERS(SDPxno, ~(*pat ^ *dest) | *src, 0xed);
ROP3_HANDLERS(SDPnoo, ~*pat | *dest | *src, 0xef);
ROP3_HANDLERS(PDSono, ~(*src | *dest) | *pat, 0xf1);
ROP3_HANDLERS(PDSnao, (~*src & *dest) | *pat, 0xf2);
ROP3_HANDLERS(PSDnao, (~*dest & *src) | *pat, 0xf4);
ROP3_HANDLERS(PDSxo, (*src ^ *dest) | *pat, 0xf6);
ROP3_HANDLERS(PDSano, ~(*src & *dest) | *pat, 0xf7);
ROP3_HANDLERS(PDSao, (*src & *dest) | *pat, 0xf8);
ROP3_HANDLERS(PDSxno, ~(*src ^ *dest) | *pat, 0xf9);
ROP3_HANDLERS(DPSnoo, ~*src | *pat | *dest, 0xfb);
ROP3_HANDLERS(PSDnoo, ~*dest | *src | *pat, 0xfd);
ROP3_HANDLERS(DPSoo, *src | *pat | *dest, 0xfe);
#define ROP3_FILL_HANDLERS(op, index) \
rop3_with_pattern_handlers_32[index] = rop3_handle_p32_##op; \
rop3_with_pattern_handlers_16[index] = rop3_handle_p16_##op; \
rop3_with_color_handlers_32[index] = rop3_handle_c32_##op; \
rop3_with_color_handlers_16[index] = rop3_handle_c16_##op; \
rop3_test_handlers_32[index] = rop3_test32_##op; \
rop3_test_handlers_16[index] = rop3_test16_##op;
void rop3_init(void)
{
static int need_init = 1;
int i;
if (!need_init) {
return;
}
need_init = 0;
for (i = 0; i < ROP3_NUM_OPS; i++) {
rop3_with_pattern_handlers_32[i] = default_rop3_with_pattern_handler;
rop3_with_pattern_handlers_16[i] = default_rop3_with_pattern_handler;
rop3_with_color_handlers_32[i] = default_rop3_withe_color_handler;
rop3_with_color_handlers_16[i] = default_rop3_withe_color_handler;
rop3_test_handlers_32[i] = default_rop3_test_handler;
rop3_test_handlers_16[i] = default_rop3_test_handler;
}
ROP3_FILL_HANDLERS(DPSoon, 0x01);
ROP3_FILL_HANDLERS(DPSona, 0x02);
ROP3_FILL_HANDLERS(SDPona, 0x04);
ROP3_FILL_HANDLERS(PDSxnon, 0x06);
ROP3_FILL_HANDLERS(PDSaon, 0x07);
ROP3_FILL_HANDLERS(SDPnaa, 0x08);
ROP3_FILL_HANDLERS(PDSxon, 0x09);
ROP3_FILL_HANDLERS(PSDnaon, 0x0b);
ROP3_FILL_HANDLERS(PDSnaon, 0x0d);
ROP3_FILL_HANDLERS(PDSonon, 0x0e);
ROP3_FILL_HANDLERS(PDSona, 0x10);
ROP3_FILL_HANDLERS(SDPxnon, 0x12);
ROP3_FILL_HANDLERS(SDPaon, 0x13);
ROP3_FILL_HANDLERS(DPSxnon, 0x14);
ROP3_FILL_HANDLERS(DPSaon, 0x15);
ROP3_FILL_HANDLERS(PSDPSanaxx, 0x16);
ROP3_FILL_HANDLERS(SSPxDSxaxn, 0x17);
ROP3_FILL_HANDLERS(SPxPDxa, 0x18);
ROP3_FILL_HANDLERS(SDPSanaxn, 0x19);
ROP3_FILL_HANDLERS(PDSPaox, 0x1a);
ROP3_FILL_HANDLERS(SDPSxaxn, 0x1b);
ROP3_FILL_HANDLERS(PSDPaox, 0x1c);
ROP3_FILL_HANDLERS(DSPDxaxn, 0x1d);
ROP3_FILL_HANDLERS(PDSox, 0x1e);
ROP3_FILL_HANDLERS(PDSoan, 0x1f);
ROP3_FILL_HANDLERS(DPSnaa, 0x20);
ROP3_FILL_HANDLERS(SDPxon, 0x21);
ROP3_FILL_HANDLERS(SPDnaon, 0x23);
ROP3_FILL_HANDLERS(SPxDSxa, 0x24);
ROP3_FILL_HANDLERS(PDSPanaxn, 0x25);
ROP3_FILL_HANDLERS(SDPSaox, 0x26);
ROP3_FILL_HANDLERS(SDPSxnox, 0x27);
ROP3_FILL_HANDLERS(DPSxa, 0x28);
ROP3_FILL_HANDLERS(PSDPSaoxxn, 0x29);
ROP3_FILL_HANDLERS(DPSana, 0x2a);
ROP3_FILL_HANDLERS(SSPxPDxaxn, 0x2b);
ROP3_FILL_HANDLERS(SPDSoax, 0x2c);
ROP3_FILL_HANDLERS(PSDnox, 0x2d);
ROP3_FILL_HANDLERS(PSDPxox, 0x2e);
ROP3_FILL_HANDLERS(PSDnoan, 0x2f);
ROP3_FILL_HANDLERS(SDPnaon, 0x31);
ROP3_FILL_HANDLERS(SDPSoox, 0x32);
ROP3_FILL_HANDLERS(SPDSaox, 0x34);
ROP3_FILL_HANDLERS(SPDSxnox, 0x35);
ROP3_FILL_HANDLERS(SDPox, 0x36);
ROP3_FILL_HANDLERS(SDPoan, 0x37);
ROP3_FILL_HANDLERS(PSDPoax, 0x38);
ROP3_FILL_HANDLERS(SPDnox, 0x39);
ROP3_FILL_HANDLERS(SPDSxox, 0x3a);
ROP3_FILL_HANDLERS(SPDnoan, 0x3b);
ROP3_FILL_HANDLERS(SPDSonox, 0x3d);
ROP3_FILL_HANDLERS(SPDSnaox, 0x3e);
ROP3_FILL_HANDLERS(PSDnaa, 0x40);
ROP3_FILL_HANDLERS(DPSxon, 0x41);
ROP3_FILL_HANDLERS(SDxPDxa, 0x42);
ROP3_FILL_HANDLERS(SPDSanaxn, 0x43);
ROP3_FILL_HANDLERS(DPSnaon, 0x45);
ROP3_FILL_HANDLERS(DSPDaox, 0x46);
ROP3_FILL_HANDLERS(PSDPxaxn, 0x47);
ROP3_FILL_HANDLERS(SDPxa, 0x48);
ROP3_FILL_HANDLERS(PDSPDaoxxn, 0x49);
ROP3_FILL_HANDLERS(DPSDoax, 0x4a);
ROP3_FILL_HANDLERS(PDSnox, 0x4b);
ROP3_FILL_HANDLERS(SDPana, 0x4c);
ROP3_FILL_HANDLERS(SSPxDSxoxn, 0x4d);
ROP3_FILL_HANDLERS(PDSPxox, 0x4e);
ROP3_FILL_HANDLERS(PDSnoan, 0x4f);
ROP3_FILL_HANDLERS(DSPnaon, 0x51);
ROP3_FILL_HANDLERS(DPSDaox, 0x52);
ROP3_FILL_HANDLERS(SPDSxaxn, 0x53);
ROP3_FILL_HANDLERS(DPSonon, 0x54);
ROP3_FILL_HANDLERS(DPSox, 0x56);
ROP3_FILL_HANDLERS(DPSoan, 0x57);
ROP3_FILL_HANDLERS(PDSPoax, 0x58);
ROP3_FILL_HANDLERS(DPSnox, 0x59);
ROP3_FILL_HANDLERS(DPSDonox, 0x5b);
ROP3_FILL_HANDLERS(DPSDxox, 0x5c);
ROP3_FILL_HANDLERS(DPSnoan, 0x5d);
ROP3_FILL_HANDLERS(DPSDnaox, 0x5e);
ROP3_FILL_HANDLERS(PDSxa, 0x60);
ROP3_FILL_HANDLERS(DSPDSaoxxn, 0x61);
ROP3_FILL_HANDLERS(DSPDoax, 0x62);
ROP3_FILL_HANDLERS(SDPnox, 0x63);
ROP3_FILL_HANDLERS(SDPSoax, 0x64);
ROP3_FILL_HANDLERS(DSPnox, 0x65);
ROP3_FILL_HANDLERS(SDPSonox, 0x67);
ROP3_FILL_HANDLERS(DSPDSonoxxn, 0x68);
ROP3_FILL_HANDLERS(PDSxxn, 0x69);
ROP3_FILL_HANDLERS(DPSax, 0x6a);
ROP3_FILL_HANDLERS(PSDPSoaxxn, 0x6b);
ROP3_FILL_HANDLERS(SDPax, 0x6c);
ROP3_FILL_HANDLERS(PDSPDoaxxn, 0x6d);
ROP3_FILL_HANDLERS(SDPSnoax, 0x6e);
ROP3_FILL_HANDLERS(PDSxnan, 0x6f);
ROP3_FILL_HANDLERS(PDSana, 0x70);
ROP3_FILL_HANDLERS(SSDxPDxaxn, 0x71);
ROP3_FILL_HANDLERS(SDPSxox, 0x72);
ROP3_FILL_HANDLERS(SDPnoan, 0x73);
ROP3_FILL_HANDLERS(DSPDxox, 0x74);
ROP3_FILL_HANDLERS(DSPnoan, 0x75);
ROP3_FILL_HANDLERS(SDPSnaox, 0x76);
ROP3_FILL_HANDLERS(PDSax, 0x78);
ROP3_FILL_HANDLERS(DSPDSoaxxn, 0x79);
ROP3_FILL_HANDLERS(DPSDnoax, 0x7a);
ROP3_FILL_HANDLERS(SDPxnan, 0x7b);
ROP3_FILL_HANDLERS(SPDSnoax, 0x7c);
ROP3_FILL_HANDLERS(DPSxnan, 0x7d);
ROP3_FILL_HANDLERS(SPxDSxo, 0x7e);
ROP3_FILL_HANDLERS(DPSaan, 0x7f);
ROP3_FILL_HANDLERS(DPSaa, 0x80);
ROP3_FILL_HANDLERS(SPxDSxon, 0x81);
ROP3_FILL_HANDLERS(DPSxna, 0x82);
ROP3_FILL_HANDLERS(SPDSnoaxn, 0x83);
ROP3_FILL_HANDLERS(SDPxna, 0x84);
ROP3_FILL_HANDLERS(PDSPnoaxn, 0x85);
ROP3_FILL_HANDLERS(DSPDSoaxx, 0x86);
ROP3_FILL_HANDLERS(PDSaxn, 0x87);
ROP3_FILL_HANDLERS(SDPSnaoxn, 0x89);
ROP3_FILL_HANDLERS(DSPnoa, 0x8a);
ROP3_FILL_HANDLERS(DSPDxoxn, 0x8b);
ROP3_FILL_HANDLERS(SDPnoa, 0x8c);
ROP3_FILL_HANDLERS(SDPSxoxn, 0x8d);
ROP3_FILL_HANDLERS(SSDxPDxax, 0x8e);
ROP3_FILL_HANDLERS(PDSanan, 0x8f);
ROP3_FILL_HANDLERS(PDSxna, 0x90);
ROP3_FILL_HANDLERS(SDPSnoaxn, 0x91);
ROP3_FILL_HANDLERS(DPSDPoaxx, 0x92);
ROP3_FILL_HANDLERS(SPDaxn, 0x93);
ROP3_FILL_HANDLERS(PSDPSoaxx, 0x94);
ROP3_FILL_HANDLERS(DPSaxn, 0x95);
ROP3_FILL_HANDLERS(DPSxx, 0x96);
ROP3_FILL_HANDLERS(PSDPSonoxx, 0x97);
ROP3_FILL_HANDLERS(SDPSonoxn, 0x98);
ROP3_FILL_HANDLERS(DPSnax, 0x9a);
ROP3_FILL_HANDLERS(SDPSoaxn, 0x9b);
ROP3_FILL_HANDLERS(SPDnax, 0x9c);
ROP3_FILL_HANDLERS(DSPDoaxn, 0x9d);
ROP3_FILL_HANDLERS(DSPDSaoxx, 0x9e);
ROP3_FILL_HANDLERS(PDSxan, 0x9f);
ROP3_FILL_HANDLERS(PDSPnaoxn, 0xa1);
ROP3_FILL_HANDLERS(DPSnoa, 0xa2);
ROP3_FILL_HANDLERS(DPSDxoxn, 0xa3);
ROP3_FILL_HANDLERS(PDSPonoxn, 0xa4);
ROP3_FILL_HANDLERS(DSPnax, 0xa6);
ROP3_FILL_HANDLERS(PDSPoaxn, 0xa7);
ROP3_FILL_HANDLERS(DPSoa, 0xa8);
ROP3_FILL_HANDLERS(DPSoxn, 0xa9);
ROP3_FILL_HANDLERS(DPSono, 0xab);
ROP3_FILL_HANDLERS(SPDSxax, 0xac);
ROP3_FILL_HANDLERS(DPSDaoxn, 0xad);
ROP3_FILL_HANDLERS(DSPnao, 0xae);
ROP3_FILL_HANDLERS(PDSnoa, 0xb0);
ROP3_FILL_HANDLERS(PDSPxoxn, 0xb1);
ROP3_FILL_HANDLERS(SSPxDSxox, 0xb2);
ROP3_FILL_HANDLERS(SDPanan, 0xb3);
ROP3_FILL_HANDLERS(PSDnax, 0xb4);
ROP3_FILL_HANDLERS(DPSDoaxn, 0xb5);
ROP3_FILL_HANDLERS(DPSDPaoxx, 0xb6);
ROP3_FILL_HANDLERS(SDPxan, 0xb7);
ROP3_FILL_HANDLERS(PSDPxax, 0xb8);
ROP3_FILL_HANDLERS(DSPDaoxn, 0xb9);
ROP3_FILL_HANDLERS(DPSnao, 0xba);
ROP3_FILL_HANDLERS(SPDSanax, 0xbc);
ROP3_FILL_HANDLERS(SDxPDxan, 0xbd);
ROP3_FILL_HANDLERS(DPSxo, 0xbe);
ROP3_FILL_HANDLERS(DPSano, 0xbf);
ROP3_FILL_HANDLERS(SPDSnaoxn, 0xc1);
ROP3_FILL_HANDLERS(SPDSonoxn, 0xc2);
ROP3_FILL_HANDLERS(SPDnoa, 0xc4);
ROP3_FILL_HANDLERS(SPDSxoxn, 0xc5);
ROP3_FILL_HANDLERS(SDPnax, 0xc6);
ROP3_FILL_HANDLERS(PSDPoaxn, 0xc7);
ROP3_FILL_HANDLERS(SDPoa, 0xc8);
ROP3_FILL_HANDLERS(SPDoxn, 0xc9);
ROP3_FILL_HANDLERS(DPSDxax, 0xca);
ROP3_FILL_HANDLERS(SPDSaoxn, 0xcb);
ROP3_FILL_HANDLERS(SDPono, 0xcd);
ROP3_FILL_HANDLERS(SDPnao, 0xce);
ROP3_FILL_HANDLERS(PSDnoa, 0xd0);
ROP3_FILL_HANDLERS(PSDPxoxn, 0xd1);
ROP3_FILL_HANDLERS(PDSnax, 0xd2);
ROP3_FILL_HANDLERS(SPDSoaxn, 0xd3);
ROP3_FILL_HANDLERS(SSPxPDxax, 0xd4);
ROP3_FILL_HANDLERS(DPSanan, 0xd5);
ROP3_FILL_HANDLERS(PSDPSaoxx, 0xd6);
ROP3_FILL_HANDLERS(DPSxan, 0xd7);
ROP3_FILL_HANDLERS(PDSPxax, 0xd8);
ROP3_FILL_HANDLERS(SDPSaoxn, 0xd9);
ROP3_FILL_HANDLERS(DPSDanax, 0xda);
ROP3_FILL_HANDLERS(SPxDSxan, 0xdb);
ROP3_FILL_HANDLERS(SPDnao, 0xdc);
ROP3_FILL_HANDLERS(SDPxo, 0xde);
ROP3_FILL_HANDLERS(SDPano, 0xdf);
ROP3_FILL_HANDLERS(PDSoa, 0xe0);
ROP3_FILL_HANDLERS(PDSoxn, 0xe1);
ROP3_FILL_HANDLERS(DSPDxax, 0xe2);
ROP3_FILL_HANDLERS(PSDPaoxn, 0xe3);
ROP3_FILL_HANDLERS(SDPSxax, 0xe4);
ROP3_FILL_HANDLERS(PDSPaoxn, 0xe5);
ROP3_FILL_HANDLERS(SDPSanax, 0xe6);
ROP3_FILL_HANDLERS(SPxPDxan, 0xe7);
ROP3_FILL_HANDLERS(SSPxDSxax, 0xe8);
ROP3_FILL_HANDLERS(DSPDSanaxxn, 0xe9);
ROP3_FILL_HANDLERS(DPSao, 0xea);
ROP3_FILL_HANDLERS(DPSxno, 0xeb);
ROP3_FILL_HANDLERS(SDPao, 0xec);
ROP3_FILL_HANDLERS(SDPxno, 0xed);
ROP3_FILL_HANDLERS(SDPnoo, 0xef);
ROP3_FILL_HANDLERS(PDSono, 0xf1);
ROP3_FILL_HANDLERS(PDSnao, 0xf2);
ROP3_FILL_HANDLERS(PSDnao, 0xf4);
ROP3_FILL_HANDLERS(PDSxo, 0xf6);
ROP3_FILL_HANDLERS(PDSano, 0xf7);
ROP3_FILL_HANDLERS(PDSao, 0xf8);
ROP3_FILL_HANDLERS(PDSxno, 0xf9);
ROP3_FILL_HANDLERS(DPSnoo, 0xfb);
ROP3_FILL_HANDLERS(PSDnoo, 0xfd);
ROP3_FILL_HANDLERS(DPSoo, 0xfe);
for (i = 0; i < ROP3_NUM_OPS; i++) {
rop3_test_handlers_32[i]();
rop3_test_handlers_16[i]();
}
}
void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
pixman_image_t *p, SpicePoint *pat_pos)
{
int bpp;
bpp = spice_pixman_image_get_bpp(d);
ASSERT (bpp == spice_pixman_image_get_bpp(s));
ASSERT (bpp == spice_pixman_image_get_bpp(p));
if (bpp == 32) {
rop3_with_pattern_handlers_32[rop3](d, s, src_pos, p, pat_pos);
} else {
rop3_with_pattern_handlers_16[rop3](d, s, src_pos, p, pat_pos);
}
}
void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
uint32_t rgb)
{
int bpp;
bpp = spice_pixman_image_get_bpp(d);
ASSERT (bpp == spice_pixman_image_get_bpp(s));
if (bpp == 32) {
rop3_with_color_handlers_32[rop3](d, s, src_pos, rgb);
} else {
rop3_with_color_handlers_16[rop3](d, s, src_pos, rgb);
}
}

View File

@ -1,42 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_ROP3
#define _H_ROP3
#include <stdint.h>
#include "draw.h"
#include "pixman_utils.h"
#ifdef __cplusplus
extern "C" {
#endif
void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
pixman_image_t *p, SpicePoint *pat_pos);
void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
uint32_t rgb);
void rop3_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,78 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef H_SPICE_COMMON
#define H_SPICE_COMMON
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <stdlib.h>
#include "backtrace.h"
#define ASSERT(x) if (!(x)) { \
printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \
spice_backtrace(); \
abort(); \
}
#define PANIC(format, ...) do { \
printf("%s: panic: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
abort(); \
} while (0)
#define PANIC_ON(x) if ((x)) { \
printf("%s: panic %s\n", __FUNCTION__, #x); \
abort(); \
}
#define red_error(format, ...) do { \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
abort(); \
} while (0)
#define red_printf(format, ...) \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ )
#define red_printf_once(format, ...) do { \
static int do_print = TRUE; \
if (do_print) { \
do_print = FALSE; \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
} \
} while (0)
#define WARN(format, ...) red_printf("warning: "format, ##__VA_ARGS__ );
#define WARN_ONCE red_printf_once
#define red_printf_some(every, format, ...) do { \
static int count = 0; \
if (count++ % (every) == 0) { \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
} \
} while (0)
#define red_printf_debug(debug, prefix, format, ...) do { \
static int debug_level = -1; \
if (debug_level == -1) { \
debug_level = getenv("SPICE_DEBUG_LEVEL") != NULL ? atoi(getenv("SPICE_DEBUG_LEVEL")) : 0; \
} \
if (debug <= debug_level) { \
printf("%s: %s: " format "\n", prefix, __FUNCTION__, ## __VA_ARGS__ ); \
} \
} while(0)
#endif

View File

@ -1,482 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2011 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "mem.h"
#include "ssl_verify.h"
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <ctype.h>
#ifndef SPICE_DEBUG
# define SPICE_DEBUG(format, ...)
#endif
#ifdef WIN32
static int inet_aton(const char* ip, struct in_addr* in_addr)
{
unsigned long addr = inet_addr(ip);
if (addr == INADDR_NONE) {
return 0;
}
in_addr->S_un.S_addr = addr;
return 1;
}
#endif
static int verify_pubkey(X509* cert, const char *key, size_t key_size)
{
EVP_PKEY* cert_pubkey = NULL;
EVP_PKEY* orig_pubkey = NULL;
BIO* bio = NULL;
int ret = 0;
if (!key || key_size == 0)
return 0;
if (!cert) {
SPICE_DEBUG("warning: no cert!");
return 0;
}
cert_pubkey = X509_get_pubkey(cert);
if (!cert_pubkey) {
SPICE_DEBUG("warning: reading public key from certificate failed");
goto finish;
}
bio = BIO_new_mem_buf((void*)key, key_size);
if (!bio) {
SPICE_DEBUG("creating BIO failed");
goto finish;
}
orig_pubkey = d2i_PUBKEY_bio(bio, NULL);
if (!orig_pubkey) {
SPICE_DEBUG("reading pubkey from bio failed");
goto finish;
}
ret = EVP_PKEY_cmp(orig_pubkey, cert_pubkey);
if (ret == 1)
SPICE_DEBUG("public keys match");
else if (ret == 0)
SPICE_DEBUG("public keys mismatch");
else
SPICE_DEBUG("public keys types mismatch");
finish:
if (bio)
BIO_free(bio);
if (orig_pubkey)
EVP_PKEY_free(orig_pubkey);
if (cert_pubkey)
EVP_PKEY_free(cert_pubkey);
return ret;
}
/* from gnutls
* compare hostname against certificate, taking account of wildcards
* return 1 on success or 0 on error
*
* note: certnamesize is required as X509 certs can contain embedded NULs in
* the strings such as CN or subjectAltName
*/
static int _gnutls_hostname_compare(const char *certname,
size_t certnamesize, const char *hostname)
{
/* find the first different character */
for (; *certname && *hostname && toupper (*certname) == toupper (*hostname);
certname++, hostname++, certnamesize--)
;
/* the strings are the same */
if (certnamesize == 0 && *hostname == '\0')
return 1;
if (*certname == '*')
{
/* a wildcard certificate */
certname++;
certnamesize--;
while (1)
{
/* Use a recursive call to allow multiple wildcards */
if (_gnutls_hostname_compare (certname, certnamesize, hostname))
return 1;
/* wildcards are only allowed to match a single domain
component or component fragment */
if (*hostname == '\0' || *hostname == '.')
break;
hostname++;
}
return 0;
}
return 0;
}
/**
* From gnutls and spice red_peer.c
* TODO: switch to gnutls and get rid of this
*
* This function will check if the given certificate's subject matches
* the given hostname. This is a basic implementation of the matching
* described in RFC2818 (HTTPS), which takes into account wildcards,
* and the DNSName/IPAddress subject alternative name PKIX extension.
*
* Returns: 1 for a successful match, and 0 on failure.
**/
static int verify_hostname(X509* cert, const char *hostname)
{
GENERAL_NAMES* subject_alt_names;
int found_dns_name = 0;
struct in_addr addr;
int addr_len = 0;
int cn_match = 0;
X509_NAME* subject;
if (!cert) {
SPICE_DEBUG("warning: no cert!");
return 0;
}
// only IpV4 supported
if (inet_aton(hostname, &addr)) {
addr_len = sizeof(struct in_addr);
}
/* try matching against:
* 1) a DNS name as an alternative name (subjectAltName) extension
* in the certificate
* 2) the common name (CN) in the certificate
*
* either of these may be of the form: *.domain.tld
*
* only try (2) if there is no subjectAltName extension of
* type dNSName
*/
/* Check through all included subjectAltName extensions, comparing
* against all those of type dNSName.
*/
subject_alt_names = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
if (subject_alt_names) {
int num_alts = sk_GENERAL_NAME_num(subject_alt_names);
int i;
for (i = 0; i < num_alts; i++) {
const GENERAL_NAME* name = sk_GENERAL_NAME_value(subject_alt_names, i);
if (name->type == GEN_DNS) {
found_dns_name = 1;
if (_gnutls_hostname_compare((char *)ASN1_STRING_data(name->d.dNSName),
ASN1_STRING_length(name->d.dNSName),
hostname)) {
SPICE_DEBUG("alt name match=%s", ASN1_STRING_data(name->d.dNSName));
GENERAL_NAMES_free(subject_alt_names);
return 1;
}
} else if (name->type == GEN_IPADD) {
int alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
found_dns_name = 1;
if ((addr_len == alt_ip_len)&&
!memcmp(ASN1_STRING_data(name->d.iPAddress), &addr, addr_len)) {
SPICE_DEBUG("alt name IP match=%s",
inet_ntoa(*((struct in_addr*)ASN1_STRING_data(name->d.dNSName))));
GENERAL_NAMES_free(subject_alt_names);
return 1;
}
}
}
GENERAL_NAMES_free(subject_alt_names);
}
if (found_dns_name) {
SPICE_DEBUG("warning: SubjectAltName mismatch");
return 0;
}
/* extracting commonNames */
subject = X509_get_subject_name(cert);
if (subject) {
int pos = -1;
X509_NAME_ENTRY* cn_entry;
ASN1_STRING* cn_asn1;
while ((pos = X509_NAME_get_index_by_NID(subject, NID_commonName, pos)) != -1) {
cn_entry = X509_NAME_get_entry(subject, pos);
if (!cn_entry) {
continue;
}
cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry);
if (!cn_asn1) {
continue;
}
if (_gnutls_hostname_compare((char*)ASN1_STRING_data(cn_asn1),
ASN1_STRING_length(cn_asn1),
hostname)) {
SPICE_DEBUG("common name match=%s", (char*)ASN1_STRING_data(cn_asn1));
cn_match = 1;
break;
}
}
}
if (!cn_match)
SPICE_DEBUG("warning: common name mismatch");
return cn_match;
}
X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
{
X509_NAME* in_subject;
const char *p;
char *key, *val, *k, *v = NULL;
enum {
KEY,
VALUE
} state;
key = (char*)alloca(strlen(subject));
val = (char*)alloca(strlen(subject));
in_subject = X509_NAME_new();
if (!in_subject || !key || !val) {
SPICE_DEBUG("failed to allocate");
return NULL;
}
*nentries = 0;
k = key;
state = KEY;
for (p = subject;; ++p) {
int escape = 0;
if (*p == '\\') {
++p;
if (*p != '\\' && *p != ',') {
SPICE_DEBUG("Invalid character after \\");
goto fail;
}
escape = 1;
}
switch (state) {
case KEY:
if (*p == ' ' && k == key) {
continue; /* skip spaces before key */
} if (*p == 0) {
if (k == key) /* empty key, ending */
goto success;
goto fail;
} else if (*p == ',' && !escape) {
goto fail; /* assignment is missing */
} else if (*p == '=' && !escape) {
state = VALUE;
*k = 0;
v = val;
} else
*k++ = *p;
break;
case VALUE:
if (*p == 0 || (*p == ',' && !escape)) {
if (v == val) /* empty value */
goto fail;
*v = 0;
if (!X509_NAME_add_entry_by_txt(in_subject, key,
MBSTRING_UTF8,
(const unsigned char*)val,
-1, -1, 0)) {
SPICE_DEBUG("warning: failed to add entry %s=%s to X509_NAME",
key, val);
goto fail;
}
*nentries += 1;
if (*p == 0)
goto success;
state = KEY;
k = key;
} else
*v++ = *p;
break;
}
}
success:
return in_subject;
fail:
if (in_subject)
X509_NAME_free(in_subject);
return NULL;
}
int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
{
X509_NAME *cert_subject = NULL;
int ret;
int in_entries;
if (!cert) {
SPICE_DEBUG("warning: no cert!");
return 0;
}
cert_subject = X509_get_subject_name(cert);
if (!cert_subject) {
SPICE_DEBUG("warning: reading certificate subject failed");
return 0;
}
if (!verify->in_subject) {
verify->in_subject = subject_to_x509_name(verify->subject, &in_entries);
if (!verify->in_subject) {
SPICE_DEBUG("warning: no in_subject!");
return 0;
}
}
/* Note: this check is redundant with the pre-condition in X509_NAME_cmp */
if (X509_NAME_entry_count(cert_subject) != in_entries) {
SPICE_DEBUG("subject mismatch: #entries cert=%d, input=%d",
X509_NAME_entry_count(cert_subject), in_entries);
return 0;
}
ret = X509_NAME_cmp(cert_subject, verify->in_subject);
if (ret == 0)
SPICE_DEBUG("subjects match");
else
SPICE_DEBUG("subjects mismatch");
return !ret;
}
static int openssl_verify(int preverify_ok, X509_STORE_CTX *ctx)
{
int depth;
SpiceOpenSSLVerify *v;
SSL *ssl;
X509* cert;
ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
v = (SpiceOpenSSLVerify*)SSL_get_app_data(ssl);
depth = X509_STORE_CTX_get_error_depth(ctx);
if (depth > 0) {
if (!preverify_ok) {
SPICE_DEBUG("openssl verify failed at depth=%d", depth);
v->all_preverify_ok = 0;
return 0;
} else
return 1;
}
/* depth == 0 */
cert = X509_STORE_CTX_get_current_cert(ctx);
if (!cert) {
SPICE_DEBUG("failed to get server certificate");
return 0;
}
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY &&
verify_pubkey(cert, v->pubkey, v->pubkey_size))
return 1;
if (!v->all_preverify_ok || !preverify_ok)
return 0;
if (v->verifyop & SPICE_SSL_VERIFY_OP_HOSTNAME &&
verify_hostname(cert, v->hostname))
return 1;
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT &&
verify_subject(cert, v))
return 1;
return 0;
}
SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verifyop,
const char *hostname,
const char *pubkey, size_t pubkey_size,
const char *subject)
{
SpiceOpenSSLVerify *v;
if (!verifyop)
return NULL;
v = spice_new0(SpiceOpenSSLVerify, 1);
v->ssl = ssl;
v->verifyop = verifyop;
v->hostname = spice_strdup(hostname);
v->pubkey = (char*)spice_memdup(pubkey, pubkey_size);
v->pubkey_size = pubkey_size;
v->subject = spice_strdup(subject);
v->all_preverify_ok = 1;
SSL_set_app_data(ssl, v);
SSL_set_verify(ssl,
SSL_VERIFY_PEER, openssl_verify);
return v;
}
void spice_openssl_verify_free(SpiceOpenSSLVerify* verify)
{
if (!verify)
return;
free(verify->pubkey);
free(verify->subject);
free(verify->hostname);
if (verify->in_subject)
X509_NAME_free(verify->in_subject);
if (verify->ssl)
SSL_set_app_data(verify->ssl, NULL);
free(verify);
}

View File

@ -1,66 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2011 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SSL_VERIFY_H
#define SSL_VERIFY_H
#if defined(WIN32) && !defined(__MINGW32__)
#include <windows.h>
#include <wincrypt.h>
#endif
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#undef X509_NAME
#include <openssl/x509v3.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
SPICE_SSL_VERIFY_OP_NONE = 0,
SPICE_SSL_VERIFY_OP_PUBKEY = (1 << 0),
SPICE_SSL_VERIFY_OP_HOSTNAME = (1 << 1),
SPICE_SSL_VERIFY_OP_SUBJECT = (1 << 2),
} SPICE_SSL_VERIFY_OP;
typedef struct {
SSL *ssl;
SPICE_SSL_VERIFY_OP verifyop;
int all_preverify_ok;
char *hostname;
char *pubkey;
size_t pubkey_size;
char *subject;
X509_NAME *in_subject;
} SpiceOpenSSLVerify;
SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verifyop,
const char *hostname,
const char *pubkey, size_t pubkey_size,
const char *subject);
void spice_openssl_verify_free(SpiceOpenSSLVerify* verify);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SSL_VERIFY_H

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H__CANVAS
#define _H__CANVAS
#ifndef SPICE_CANVAS_INTERNAL
#error "This header shouldn't be included directly"
#endif
#include <stdint.h>
#include "draw.h"
#include "pixman_utils.h"
#include "canvas_base.h"
#include "region.h"
#ifdef __cplusplus
extern "C" {
#endif
SpiceCanvas *canvas_create(int width, int height, uint32_t format
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
);
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, int stride
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
);
void sw_canvas_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1 +0,0 @@
SUBDIRS = my_getopt-1.5

View File

@ -1,22 +0,0 @@
2006-12-09 Benjamin C. W. Sittler <bsittler@>
* my_getopt.c: add my_getopt_reset to reset the argument parser
* README: updated email address, updated for version 1.5
2002-07-26 Benjamin C. W. Sittler <bsittler@knownow.com>
* README: updated for version 1.4
* my_getopt.c: now we include <sys/types.h> explicitly for those
systems that narrowly (mis-)interpret ANSI C and POSIX
(_my_getopt_internal): added an explicit cast to size_t to make
g++ happy
* getopt.h, my_getopt.h: added extern "C" { ... } for C++
compilation (thanks to Jeff Lawson <bovine@ud.com> and others)
2001-08-20 Benjamin C. W. Sittler <bsittler@knownow.com>
* getopt.h (getopt_long_only): fixed typo (thanks to Justin Lee
<justin_lee@ud.com>)

View File

@ -1,22 +0,0 @@
my_getopt - a command-line argument parser
Copyright 1997-2001, Benjamin Sittler
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,14 +0,0 @@
NULL =
EXTRA_DIST = \
ChangeLog \
getopt.3 \
getopt.h \
getopt.txt \
LICENSE \
main.c \
Makefile \
my_getopt.c \
my_getopt.h \
README \
$(NULL)

View File

@ -1,26 +0,0 @@
all: copy
# Compiler options
#CCOPTS = -g -O3 -Wall -Werror
CCOPTS =
# Compiler
CC = gcc -Wall -Werror
#CC = cc
# Linker
LD = $(CC)
# Utility to remove a file
RM = rm
OBJS = main.o my_getopt.o
copy: $(OBJS)
$(LD) -o $@ $(OBJS)
clean:
$(RM) -f copy $(OBJS) *~
%.o: %.c getopt.h my_getopt.h
$(CC) $(CCOPTS) -o $@ -c $<

View File

@ -1,140 +0,0 @@
my_getopt - a command-line argument parser
Copyright 1997-2006, Benjamin Sittler
The author can be reached by sending email to <bsittler@gmail.com>.
The version of my_getopt in this package (1.5) has a BSD-like license;
see the file LICENSE for details. Version 1.0 of my_getopt was similar
to the GPL'ed version of my_getopt included with SMOKE-16 Version 1,
Release 19990717. SMOKE-16 packages are available from:
http://geocities.com/bsittler/#smoke16
OVERVIEW OF THE ARGUMENT PARSER
===============================
The getopt(), getopt_long() and getopt_long_only() functions parse
command line arguments. The argc and argv parameters passed to these
functions correspond to the argument count and argument list passed to
your program's main() function at program start-up. Element 0 of the
argument list conventionally contains the name of your program. Any
remaining arguments starting with "-" (except for "-" or "--" by
themselves) are option arguments, some of include option values. This
family of getopt() functions allows intermixed option and non-option
arguments anywhere in the argument list, except that "--" by itself
causes the remaining elements of the argument list to be treated as
non-option arguments.
[ See the parts of this document labeled "DOCUMENTATION" and
"WHY RE-INVENT THE WHEEL?" for a more information. ]
FILES
=====
The following four files constitute the my_getopt package:
LICENSE - license and warranty information for my_getopt
my_getopt.c - implementation of my getopt replacement
my_getopt.h - interface for my getopt replacement
getopt.h - a header file to make my getopt look like GNU getopt
USAGE
=====
To use my_getopt in your application, include the following line to
your main program source:
#include "getopt.h"
This line should appear after your standard system header files to
avoid conflicting with your system's built-in getopt.
Then compile my_getopt.c into my_getopt.o, and link my_getopt.o into
your application:
$ cc -c my_getopt.c
$ ld -o app app.o ... my_getopt.o
To avoid conflicting with standard library functions, the function
names and global variables used by my_getopt all begin with `my_'. To
ensure compatibility with existing C programs, the `getopt.h' header
file uses the C preprocessor to redefine names like getopt, optarg,
optind, and so forth to my_getopt, my_optarg, my_optind, etc.
SAMPLE PROGRAM
==============
There is also a public-domain sample program:
main.c - main() for a sample program using my_getopt
Makefile - build script for the sample program (called `copy')
To build and test the sample program:
$ make
$ ./copy -help
$ ./copy -version
The sample program bears a slight resemblance to the UNIX `cat'
utility, but can be used rot13-encode streams, and can redirect output
to a file.
DOCUMENTATION
=============
There is not yet any real documentation for my_getopt. For the moment,
use the Linux manual page for getopt. It has its own copyright and
license; view the file `getopt.3' in a text editor for more details.
getopt.3 - the manual page for GNU getopt
getopt.txt - preformatted copy of the manual page for GNU getopt,
for your convenience
WHY RE-INVENT THE WHEEL?
========================
I re-implemented getopt, getopt_long, and getopt_long_only because
there were noticable bugs in several versions of the GNU
implementations, and because the GNU versions aren't always available
on some systems (*BSD, for example.) Other systems don't include any
sort of standard argument parser (Win32 with Microsoft tools, for
example, has no getopt.)
These should do all the expected Unix- and GNU-style argument
parsing, including permution, bunching, long options with single or
double dashes (double dashes are required if you use
my_getopt_long,) and optional arguments for both long and short
options. A word with double dashes all by themselves halts argument
parsing. A required long option argument can be in the same word as
the option name, separated by '=', or in the next word. An optional
long option argument must be in the same word as the option name,
separated by '='.
As with the GNU versions, a '+' prefix to the short option
specification (or the POSIXLY_CORRECT environment variable) disables
permution, a '-' prefix to the short option specification returns 1
for non-options, ':' after a short option indicates a required
argument, and '::' after a short option specification indicates an
optional argument (which must appear in the same word.) If you'd like
to recieve ':' instead of '?' for missing option arguments, prefix the
short option specification with ':'.
The original intent was to re-implement the documented behavior of
the GNU versions, but I have found it necessary to emulate some of
the undocumented behavior as well. Some programs depend on it.
KNOWN BUGS
==========
The GNU versions support POSIX-style -W "name=value" long
options. Currently, my_getopt does not support these, because I
don't have any documentation on them (other than the fact that they
are enabled by "W;" in the short option specification.) As a
temporary workaround, my_getopt treats "W;" in the short option
string identically to "W:".
The GNU versions support internationalized/localized
messages. Currently, my_getopt does not.
There should be re-entrant versions of all these functions so that
multiple threads can parse arguments simultaneously.

View File

@ -1,288 +0,0 @@
.\" (c) 1993 by Thomas Koenig (ig25@rz.uni-karlsruhe.de)
.\"
.\" Permission is granted to make and distribute verbatim copies of this
.\" manual provided the copyright notice and this permission notice are
.\" preserved on all copies.
.\"
.\" Permission is granted to copy and distribute modified versions of this
.\" manual under the conditions for verbatim copying, provided that the
.\" entire resulting derived work is distributed under the terms of a
.\" permission notice identical to this one
.\"
.\" Since the Linux kernel and libraries are constantly changing, this
.\" manual page may be incorrect or out-of-date. The author(s) assume no
.\" responsibility for errors or omissions, or for damages resulting from
.\" the use of the information contained herein. The author(s) may not
.\" have taken the same level of care in the production of this manual,
.\" which is licensed free of charge, as they might when working
.\" professionally.
.\"
.\" Formatted or processed versions of this manual, if unaccompanied by
.\" the source, must acknowledge the copyright and authors of this work.
.\" License.
.\" Modified Sat Jul 24 19:27:50 1993 by Rik Faith (faith@cs.unc.edu)
.\" Modified Mon Aug 30 22:02:34 1995 by Jim Van Zandt <jrv@vanzandt.mv.com>
.\" longindex is a pointer, has_arg can take 3 values, using consistent
.\" names for optstring and longindex, "\n" in formats fixed. Documenting
.\" opterr and getopt_long_only. Clarified explanations (borrowing heavily
.\" from the source code).
.TH GETOPT 3 "Aug 30, 1995" "GNU" "Linux Programmer's Manual"
.SH NAME
getopt \- Parse command line options
.SH SYNOPSIS
.nf
.B #include <unistd.h>
.sp
.BI "int getopt(int " argc ", char * const " argv[] ","
.BI " const char *" optstring ");"
.sp
.BI "extern char *" optarg ;
.BI "extern int " optind ", " opterr ", " optopt ;
.sp
.B #include <getopt.h>
.sp
.BI "int getopt_long(int " argc ", char * const " argv[] ",
.BI " const char *" optstring ,
.BI " const struct option *" longopts ", int *" longindex ");"
.sp
.BI "int getopt_long_only(int " argc ", char * const " argv[] ",
.BI " const char *" optstring ,
.BI " const struct option *" longopts ", int *" longindex ");"
.fi
.SH DESCRIPTION
The
.B getopt()
function parses the command line arguments. Its arguments
.I argc
and
.I argv
are the argument count and array as passed to the
.B main()
function on program invocation.
An element of \fIargv\fP that starts with `-' (and is not exactly "-" or "--")
is an option element. The characters of this element
(aside from the initial `-') are option characters. If \fBgetopt()\fP
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
.PP
If \fBgetopt()\fP finds another option character, it returns that
character, updating the external variable \fIoptind\fP and a static
variable \fInextchar\fP so that the next call to \fBgetopt()\fP can
resume the scan with the following option character or
\fIargv\fP-element.
.PP
If there are no more option characters, \fBgetopt()\fP returns
\fBEOF\fP. Then \fIoptind\fP is the index in \fIargv\fP of the first
\fIargv\fP-element that is not an option.
.PP
.I optstring
is a string containing the legitimate option characters. If such a
character is followed by a colon, the option requires an argument, so
\fBgetopt\fP places a pointer to the following text in the same
\fIargv\fP-element, or the text of the following \fIargv\fP-element, in
.IR optarg .
Two colons mean an option takes
an optional arg; if there is text in the current \fIargv\fP-element,
it is returned in \fIoptarg\fP, otherwise \fIoptarg\fP is set to zero.
.PP
By default, \fBgetargs()\fP permutes the contents of \fIargv\fP as it
scans, so that eventually all the non-options are at the end. Two
other modes are also implemented. If the first character of
\fIoptstring\fP is `+' or the environment variable POSIXLY_CORRECT is
set, then option processing stops as soon as a non-option argument is
encountered. If the first character of \fIoptstring\fP is `-', then
each non-option \fIargv\fP-element is handled as if it were the argument of
an option with character code 1. (This is used by programs that were
written to expect options and other \fIargv\fP-elements in any order
and that care about the ordering of the two.)
The special argument `--' forces an end of option-scanning regardless
of the scanning mode.
.PP
If \fBgetopt()\fP does not recognize an option character, it prints an
error message to stderr, stores the character in \fIoptopt\fP, and
returns `?'. The calling program may prevent the error message by
setting \fIopterr\fP to 0.
.PP
The
.B getopt_long()
function works like
.B getopt()
except that it also accepts long options, started out by two dashes.
Long option names may be abbreviated if the abbreviation is
unique or is an exact match for some defined option. A long option
may take a parameter, of the form
.B --arg=param
or
.BR "--arg param" .
.PP
.I longopts
is a pointer to the first element of an array of
.B struct option
declared in
.B <getopt.h>
as
.nf
.sp
.in 10
struct option {
.in 14
const char *name;
int has_arg;
int *flag;
int val;
.in 10
};
.fi
.PP
The meanings of the different fields are:
.TP
.I name
is the name of the long option.
.TP
.I has_arg
is:
\fBno_argument\fP (or 0) if the option does not take an argument,
\fBrequired_argument\fP (or 1) if the option requires an argument, or
\fBoptional_argument\fP (or 2) if the option takes an optional argument.
.TP
.I flag
specifies how results are returned for a long option. If \fIflag\fP
is \fBNULL\fP, then \fBgetopt_long()\fP returns \fIval\fP. (For
example, the calling program may set \fIval\fP to the equivalent short
option character.) Otherwise, \fBgetopt_long()\fP returns 0, and
\fIflag\fP points to a variable which is set to \fIval\fP if the
option is found, but left unchanged if the option is not found.
.TP
\fIval\fP
is the value to return, or to load into the variable pointed
to by \fIflag\fP.
.PP
The last element of the array has to be filled with zeroes.
.PP
If \fIlongindex\fP is not \fBNULL\fP, it
points to a variable which is set to the index of the long option relative to
.IR longopts .
.PP
\fBgetopt_long_only()\fP is like \fBgetopt_long()\fP, but `-' as well
as `--' can indicate a long option. If an option that starts with `-'
(not `--') doesn't match a long option, but does match a short option,
it is parsed as a short option instead.
.SH "RETURN VALUE"
The
.B getopt()
function returns the option character if the option was found
successfully, `:' if there was a missing parameter for one of the
options, `?' for an unknown option character, or \fBEOF\fP
for the end of the option list.
.PP
\fBgetopt_long()\fP and \fBgetopt_long_only()\fP also return the option
character when a short option is recognized. For a long option, they
return \fIval\fP if \fIflag\fP is \fBNULL\fP, and 0 otherwise. Error
and EOF returns are the same as for \fBgetopt()\fP, plus `?' for an
ambiguous match or an extraneous parameter.
.SH "ENVIRONMENT VARIABLES"
.TP
.SM
.B POSIXLY_CORRECT
If this is set, then option processing stops as soon as a non-option
argument is encountered.
.SH "EXAMPLE"
The following example program, from the source code, illustrates the
use of
.BR getopt_long()
with most of its features.
.nf
.sp
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 1, 0, 'c'},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:012",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\\n");
break;
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\\n");
digit_optind = this_option_optind;
printf ("option %c\\n", c);
break;
case 'a':
printf ("option a\\n");
break;
case 'b':
printf ("option b\\n");
break;
case 'c':
printf ("option c with value `%s'\\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\\n");
}
exit (0);
}
.fi
.SH "BUGS"
This manpage is confusing.
.SH "CONFORMING TO"
.TP
\fBgetopt()\fP:
POSIX.1, provided the environment variable POSIXLY_CORRECT is set.
Otherwise, the elements of \fIargv\fP aren't really const, because we
permute them. We pretend they're const in the prototype to be
compatible with other systems.

View File

@ -1,56 +0,0 @@
/*
* getopt.h - cpp wrapper for my_getopt to make it look like getopt.
* Copyright 1997, 2000, 2001, 2002, Benjamin Sittler
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef MY_WRAPPER_GETOPT_H_INCLUDED
#define MY_WRAPPER_GETOPT_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include "my_getopt.h"
#undef getopt
#define getopt my_getopt
#undef getopt_long
#define getopt_long my_getopt_long
#undef getopt_long_only
#define getopt_long_only my_getopt_long_only
#undef _getopt_internal
#define _getopt_internal _my_getopt_internal
#undef opterr
#define opterr my_opterr
#undef optind
#define optind my_optind
#undef optopt
#define optopt my_optopt
#undef optarg
#define optarg my_optarg
#ifdef __cplusplus
}
#endif
#endif /* MY_WRAPPER_GETOPT_H_INCLUDED */

View File

@ -1,330 +0,0 @@
GETOPT(3) Linux Programmer's Manual GETOPT(3)
NAME
getopt - Parse command line options
SYNOPSIS
#include <unistd.h>
int getopt(int argc, char * const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#include <getopt.h>
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
int getopt_long_only(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
DESCRIPTION
The getopt() function parses the command line arguments.
Its arguments argc and argv are the argument count and
array as passed to the main() function on program invoca-
tion. An element of argv that starts with `-' (and is not
exactly "-" or "--") is an option element. The characters
of this element (aside from the initial `-') are option
characters. If getopt() is called repeatedly, it returns
successively each of the option characters from each of
the option elements.
If getopt() finds another option character, it returns
that character, updating the external variable optind and
a static variable nextchar so that the next call to
getopt() can resume the scan with the following option
character or argv-element.
If there are no more option characters, getopt() returns
EOF. Then optind is the index in argv of the first argv-
element that is not an option.
optstring is a string containing the legitimate option
characters. If such a character is followed by a colon,
the option requires an argument, so getopt places a
pointer to the following text in the same argv-element, or
the text of the following argv-element, in optarg. Two
colons mean an option takes an optional arg; if there is
text in the current argv-element, it is returned in
optarg, otherwise optarg is set to zero.
By default, getargs() permutes the contents of argv as it
scans, so that eventually all the non-options are at the
GNU Aug 30, 1995 1
GETOPT(3) Linux Programmer's Manual GETOPT(3)
end. Two other modes are also implemented. If the first
character of optstring is `+' or the environment variable
POSIXLY_CORRECT is set, then option processing stops as
soon as a non-option argument is encountered. If the
first character of optstring is `-', then each non-option
argv-element is handled as if it were the argument of an
option with character code 1. (This is used by programs
that were written to expect options and other argv-ele-
ments in any order and that care about the ordering of the
two.) The special argument `--' forces an end of option-
scanning regardless of the scanning mode.
If getopt() does not recognize an option character, it
prints an error message to stderr, stores the character in
optopt, and returns `?'. The calling program may prevent
the error message by setting opterr to 0.
The getopt_long() function works like getopt() except that
it also accepts long options, started out by two dashes.
Long option names may be abbreviated if the abbreviation
is unique or is an exact match for some defined option. A
long option may take a parameter, of the form --arg=param
or --arg param.
longopts is a pointer to the first element of an array of
struct option declared in <getopt.h> as
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
The meanings of the different fields are:
name is the name of the long option.
has_arg
is: no_argument (or 0) if the option does not take
an argument, required_argument (or 1) if the option
requires an argument, or optional_argument (or 2)
if the option takes an optional argument.
flag specifies how results are returned for a long
option. If flag is NULL, then getopt_long()
returns val. (For example, the calling program may
set val to the equivalent short option character.)
Otherwise, getopt_long() returns 0, and flag points
to a variable which is set to val if the option is
found, but left unchanged if the option is not
found.
val is the value to return, or to load into the
GNU Aug 30, 1995 2
GETOPT(3) Linux Programmer's Manual GETOPT(3)
variable pointed to by flag.
The last element of the array has to be filled with
zeroes.
If longindex is not NULL, it points to a variable which is
set to the index of the long option relative to longopts.
getopt_long_only() is like getopt_long(), but `-' as well
as `--' can indicate a long option. If an option that
starts with `-' (not `--') doesn't match a long option,
but does match a short option, it is parsed as a short
option instead.
RETURN VALUE
The getopt() function returns the option character if the
option was found successfully, `:' if there was a missing
parameter for one of the options, `?' for an unknown
option character, or EOF for the end of the option list.
getopt_long() and getopt_long_only() also return the
option character when a short option is recognized. For a
long option, they return val if flag is NULL, and 0 other-
wise. Error and EOF returns are the same as for getopt(),
plus `?' for an ambiguous match or an extraneous parame-
ter.
ENVIRONMENT VARIABLES
POSIXLY_CORRECT
If this is set, then option processing stops as
soon as a non-option argument is encountered.
EXAMPLE
The following example program, from the source code,
illustrates the use of getopt_long() with most of its fea-
tures.
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
GNU Aug 30, 1995 3
GETOPT(3) Linux Programmer's Manual GETOPT(3)
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 1, 0, 'c'},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:012",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
GNU Aug 30, 1995 4
GETOPT(3) Linux Programmer's Manual GETOPT(3)
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
BUGS
This manpage is confusing.
CONFORMING TO
getopt():
POSIX.1, provided the environment variable
POSIXLY_CORRECT is set. Otherwise, the elements of
argv aren't really const, because we permute them.
We pretend they're const in the prototype to be
compatible with other systems.
GNU Aug 30, 1995 5

View File

@ -1,387 +0,0 @@
/*
* copy - test program for my getopt() re-implementation
*
* This program is in the public domain.
*/
#define VERSION \
"0.3"
#define COPYRIGHT \
"This program is in the public domain."
/* for isprint(), printf(), fopen(), perror(), getenv(), strcmp(), etc. */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* for my getopt() re-implementation */
#include "getopt.h"
/* the default verbosity level is 0 (no verbose reporting) */
static unsigned verbose = 0;
/* print version and copyright information */
static void
version(char *progname)
{
printf("%s version %s\n"
"%s\n",
progname,
VERSION,
COPYRIGHT);
}
/* print a help summary */
static void
help(char *progname)
{
printf("Usage: %s [options] [FILE]...\n"
"Options:\n"
"-h or -help show this message and exit\n"
"-append append to the output file\n"
"-o FILE or\n"
"-output FILE send output to FILE (default is stdout)\n"
"-r or --rotate rotate letters 13 positions (rot13)\n"
"-rNUM or\n"
"--rotate=NUM rotate letters NUM positions\n"
"-truncate truncate the output file "
"(this is the default)\n"
"-v or -verbose increase the level of verbosity by 1"
"(the default is 0)\n"
"-vNUM or\n"
"-verbose=NUM set the level of verbosity to NUM\n"
"-V or -version print program version and exit\n"
"\n"
"This program reads the specified FILEs "
"(or stdin if none are given)\n"
"and writes their bytes to the specified output FILE "
"(or stdout if none is\n"
"given.) It can optionally rotate letters.\n",
progname);
}
/* print usage information to stderr */
static void
usage(char *progname)
{
fprintf(stderr,
"Summary: %s [-help] [-version] [options] [FILE]...\n",
progname);
}
/* input file handler -- returns nonzero or exit()s on failure */
static int
handle(char *progname,
FILE *infile, char *infilename,
FILE *outfile, char *outfilename,
int rotate)
{
int c;
unsigned long bytes_copied = 0;
if (verbose > 2)
{
fprintf(stderr,
"%s: copying from `%s' to `%s'\n",
progname,
infilename,
outfilename);
}
while ((c = getc(infile)) != EOF)
{
if (rotate && isalpha(c))
{
const char *letters = "abcdefghijklmnopqrstuvwxyz";
char *match;
if ((match = strchr(letters, tolower(c))))
{
char rc = letters[(match - letters + rotate) % 26];
if (isupper(c))
rc = toupper(rc);
c = rc;
}
}
if (putc(c, outfile) == EOF)
{
perror(outfilename);
exit(1);
}
bytes_copied ++;
}
if (! feof(infile))
{
perror(infilename);
return 1;
}
if (verbose > 2)
{
fprintf(stderr,
"%s: %lu bytes copied from `%s' to `%s'\n",
progname,
bytes_copied,
infilename,
outfilename);
}
return 0;
}
/* argument parser and dispatcher */
int
main(int argc, char * argv[])
{
/* the program name */
char *progname = argv[0];
/* during argument parsing, opt contains the return value from getopt() */
int opt;
/* the output filename is initially 0 (a.k.a. stdout) */
char *outfilename = 0;
/* the default return value is initially 0 (success) */
int retval = 0;
/* initially we truncate */
int append = 0;
/* initially we don't rotate letters */
int rotate = 0;
/* short options string */
char *shortopts = "Vho:r::v::";
/* long options list */
struct option longopts[] =
{
/* name, has_arg, flag, val */ /* longind */
{ "append", no_argument, 0, 0 }, /* 0 */
{ "truncate", no_argument, 0, 0 }, /* 1 */
{ "version", no_argument, 0, 'V' }, /* 3 */
{ "help", no_argument, 0, 'h' }, /* 4 */
{ "output", required_argument, 0, 'o' }, /* 5 */
{ "rotate", optional_argument, 0, 'r' }, /* 6 */
{ "verbose", optional_argument, 0, 'v' }, /* 7 */
/* end-of-list marker */
{ 0, 0, 0, 0 }
};
/* long option list index */
int longind = 0;
/*
* print a warning when the POSIXLY_CORRECT environment variable will
* interfere with argument placement
*/
if (getenv("POSIXLY_CORRECT"))
{
fprintf(stderr,
"%s: "
"Warning: implicit argument reordering disallowed by "
"POSIXLY_CORRECT\n",
progname);
}
/* parse all options from the command line */
while ((opt =
getopt_long_only(argc, argv, shortopts, longopts, &longind)) != -1)
switch (opt)
{
case 0: /* a long option without an equivalent short option */
switch (longind)
{
case 0: /* -append */
append = 1;
break;
case 1: /* -truncate */
append = 0;
break;
default: /* something unexpected has happened */
fprintf(stderr,
"%s: "
"getopt_long_only unexpectedly returned %d for `--%s'\n",
progname,
opt,
longopts[longind].name);
return 1;
}
break;
case 'V': /* -version */
version(progname);
return 0;
case 'h': /* -help */
help(progname);
return 0;
case 'r': /* -rotate[=NUM] */
if (optarg)
{
/* we use this while trying to parse a numeric argument */
char ignored;
if (sscanf(optarg,
"%d%c",
&rotate,
&ignored) != 1)
{
fprintf(stderr,
"%s: "
"rotation `%s' is not a number\n",
progname,
optarg);
usage(progname);
return 2;
}
/* normalize rotation */
while (rotate < 0)
{
rotate += 26;
}
rotate %= 26;
}
else
rotate = 13;
break;
case 'o': /* -output=FILE */
outfilename = optarg;
/* we allow "-" as a synonym for stdout here */
if (! strcmp(optarg, "-"))
{
outfilename = 0;
}
break;
case 'v': /* -verbose[=NUM] */
if (optarg)
{
/* we use this while trying to parse a numeric argument */
char ignored;
if (sscanf(optarg,
"%u%c",
&verbose,
&ignored) != 1)
{
fprintf(stderr,
"%s: "
"verbosity level `%s' is not a number\n",
progname,
optarg);
usage(progname);
return 2;
}
}
else
verbose ++;
break;
case '?': /* getopt_long_only noticed an error */
usage(progname);
return 2;
default: /* something unexpected has happened */
fprintf(stderr,
"%s: "
"getopt_long_only returned an unexpected value (%d)\n",
progname,
opt);
return 1;
}
/* re-open stdout to outfilename, if requested */
if (outfilename)
{
if (! freopen(outfilename, (append ? "a" : "w"), stdout))
{
perror(outfilename);
return 1;
}
}
else
{
/* make a human-readable version of the output filename "-" */
outfilename = "stdout";
/* you can't truncate stdout */
append = 1;
}
if (verbose)
{
fprintf(stderr,
"%s: verbosity level is %u; %s `%s'; rotation %d\n",
progname,
verbose,
(append ? "appending to" : "truncating"),
outfilename,
rotate);
}
if (verbose > 1)
{
fprintf(stderr,
"%s: %d input file(s) were given\n",
progname,
((argc > optind) ? (argc - optind) : 0));
}
if (verbose > 3)
{
fprintf(stderr,
"\topterr: %d\n\toptind: %d\n\toptopt: %d (%c)\n\toptarg: %s\n",
opterr,
optind,
optopt, optopt,
optarg ? optarg : "(null)");
}
/* handle each of the input files (or stdin, if no files were given) */
if (optind < argc)
{
int argindex;
for (argindex = optind; argindex < argc; argindex ++)
{
char *infilename = argv[argindex];
FILE *infile;
/* we allow "-" as a synonym for stdin here */
if (! strcmp(infilename, "-"))
{
infile = stdin;
infilename = "stdin";
}
else if (! (infile = fopen(infilename, "r")))
{
perror(infilename);
retval = 1;
continue;
}
if (handle(progname,
infile, argv[optind],
stdout, outfilename,
rotate))
{
retval = 1;
fclose(infile);
continue;
}
if ((infile != stdin) && fclose(infile))
{
perror(infilename);
retval = 1;
}
}
}
else
{
retval =
handle(progname,
stdin, "stdin",
stdout, outfilename,
rotate);
}
/* close stdout */
if (fclose(stdout))
{
perror(outfilename);
return 1;
}
if (verbose > 3)
{
fprintf(stderr,
"%s: normal return, exit code is %d\n",
progname,
retval);
}
return retval;
}

Some files were not shown because too many files have changed in this diff Show More