mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-26 19:11:03 +00:00
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:
parent
4df135c858
commit
359fc1cb5d
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,3 +1,3 @@
|
||||
[submodule "spice-protocol"]
|
||||
path = spice-protocol
|
||||
url = ../spice-protocol
|
||||
[submodule "spice-common"]
|
||||
path = spice-common
|
||||
url = ../spice-common
|
||||
|
||||
18
Makefile.am
18
Makefile.am
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 = \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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
|
||||
@ -20,7 +20,6 @@
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "canvas.h"
|
||||
#include "red_pixmap.h"
|
||||
#ifdef USE_OPENGL
|
||||
#include "red_pixmap_gl.h"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
@ -18,7 +18,7 @@
|
||||
#ifndef _H_MONITOR
|
||||
#define _H_MONITOR
|
||||
|
||||
#include "draw.h"
|
||||
#include "common/draw.h"
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
|
||||
@ -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*))
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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()
|
||||
{
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
9
common/.gitignore
vendored
@ -1,9 +0,0 @@
|
||||
*.la
|
||||
*.lo
|
||||
*.loT
|
||||
*.o
|
||||
.deps
|
||||
.dirstamp
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
@ -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)
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
3394
common/canvas_base.c
3394
common/canvas_base.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
281
common/draw.h
281
common/draw.h
@ -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 */
|
||||
1858
common/gdi_canvas.c
1858
common/gdi_canvas.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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, ©->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, ©->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();
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
1513
common/glc.c
1513
common/glc.c
File diff suppressed because it is too large
Load Diff
167
common/glc.h
167
common/glc.h
@ -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
|
||||
3613
common/lines.c
3613
common/lines.c
File diff suppressed because it is too large
Load Diff
138
common/lines.h
138
common/lines.h
@ -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 */
|
||||
740
common/lz.c
740
common/lz.c
@ -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");
|
||||
}
|
||||
}
|
||||
82
common/lz.h
82
common/lz.h
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
297
common/mem.c
297
common/mem.c
@ -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;
|
||||
}
|
||||
162
common/mem.h
162
common/mem.h
@ -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
|
||||
@ -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 */
|
||||
@ -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
|
||||
251
common/ogl_ctx.c
251
common/ogl_ctx.c
@ -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);
|
||||
}
|
||||
@ -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
@ -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 */
|
||||
1699
common/quic.c
1699
common/quic.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
122
common/rect.h
122
common/rect.h
@ -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
|
||||
890
common/region.c
890
common/region.c
@ -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 (®1->extents, ®2->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(®1->extents, ®2->extents)) {
|
||||
res |= REGION_TEST_RIGHT_EXCLUSIVE;
|
||||
}
|
||||
|
||||
if (!SUBSUMES(®2->extents, ®1->extents)) {
|
||||
res |= REGION_TEST_LEFT_EXCLUSIVE;
|
||||
}
|
||||
|
||||
return res & query;
|
||||
} else if (!reg2->data && SUBSUMES (®2->extents, ®1->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 (®1->extents, ®2->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
|
||||
@ -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
|
||||
172
common/ring.h
172
common/ring.h
@ -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
|
||||
650
common/rop3.c
650
common/rop3.c
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
1327
common/sw_canvas.c
1327
common/sw_canvas.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -1 +0,0 @@
|
||||
SUBDIRS = my_getopt-1.5
|
||||
@ -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>)
|
||||
@ -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.
|
||||
@ -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)
|
||||
@ -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 $<
|
||||
@ -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.
|
||||
@ -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.
|
||||
|
||||
@ -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 */
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
Loading…
Reference in New Issue
Block a user