[Spice-commits] 34 commits - client/canvas.cpp client/canvas.h client/cursor_channel.cpp client/cursor_channel.h client/cursor.h client/demarshallers.h client/display_channel.cpp client/display_channel.h client/inputs_channel.cpp client/Makefile.am client/marshaller.cpp client/playback_channel.cpp client/record_channel.cpp client/red_channel.cpp client/red_channel.h client/red_client.cpp client/red_client.h client/red_peer.cpp client/red_peer.h client/tunnel_channel.cpp client/windows client/x11 common/canvas_base.c common/canvas_base.h common/gdi_canvas.c common/gl_canvas.c common/Makefile.am common/marshaller.c common/marshaller.h common/mem.c common/mem.h common/messages.h common/sw_canvas.c configure.ac Makefile.am python_modules/codegen.py python_modules/demarshal.py python_modules/__init__.py python_modules/Makefile.am python_modules/marshal.py python_modules/ptypes.py python_modules/spice_parser.py server/demarshallers.h server/Makefile.am server/red_common.h server/reds.c se rver/red_worker.c server/snd_worker.c spice_codegen.py spice.proto

Alexander Larsson alexl at kemper.freedesktop.org
Fri Jun 18 12:23:18 PDT 2010


 Makefile.am                    |    4 
 client/Makefile.am             |   25 
 client/canvas.cpp              |  102 --
 client/canvas.h                |    3 
 client/cursor.h                |    2 
 client/cursor_channel.cpp      |   48 -
 client/cursor_channel.h        |    2 
 client/demarshallers.h         |   25 
 client/display_channel.cpp     |  154 +--
 client/display_channel.h       |    3 
 client/inputs_channel.cpp      |   87 +
 client/marshaller.cpp          |   24 
 client/playback_channel.cpp    |   57 -
 client/record_channel.cpp      |   65 -
 client/red_channel.cpp         |   28 
 client/red_channel.h           |   89 +
 client/red_client.cpp          |   94 +-
 client/red_client.h            |    2 
 client/red_peer.cpp            |   65 -
 client/red_peer.h              |   19 
 client/tunnel_channel.cpp      |  151 +--
 client/windows/generate.bat    |    3 
 client/windows/redc.vcproj     |   79 +
 client/x11/Makefile.am         |    6 
 common/Makefile.am             |    2 
 common/canvas_base.c           |   54 -
 common/canvas_base.h           |    1 
 common/gdi_canvas.c            |   21 
 common/gl_canvas.c             |   19 
 common/marshaller.c            |  590 +++++++++++++
 common/marshaller.h            |   62 +
 common/mem.c                   |   12 
 common/mem.h                   |    2 
 common/messages.h              |  498 +++++++++++
 common/sw_canvas.c             |   10 
 configure.ac                   |    2 
 python_modules/Makefile.am     |    6 
 python_modules/codegen.py      |  354 +++++++
 python_modules/demarshal.py    | 1045 +++++++++++++++++++++++
 python_modules/marshal.py      |  358 +++++++
 python_modules/ptypes.py       |  965 +++++++++++++++++++++
 python_modules/spice_parser.py |  157 +++
 server/Makefile.am             |   18 
 server/demarshallers.h         |   25 
 server/red_common.h            |    2 
 server/red_worker.c            | 1855 +++++++++++++++++++++++------------------
 server/reds.c                  |  577 +++++-------
 server/snd_worker.c            |  301 ++----
 spice.proto                    | 1086 ++++++++++++++++++++++++
 spice_codegen.py               |  200 ++++
 50 files changed, 7399 insertions(+), 1960 deletions(-)

New commits:
commit ae4436215cb113a02eac73c6afd368166090967c
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 21:10:25 2010 +0200

    Make generated marshallers build on win32

diff --git a/client/windows/generate.bat b/client/windows/generate.bat
new file mode 100644
index 0000000..3757bb0
--- /dev/null
+++ b/client/windows/generate.bat
@@ -0,0 +1,3 @@
+python ..\..\spice_codegen.py -d -c  -i common.h -i messages.h ..\..\spice.proto ..\generated_demarshallers.cpp
+python ..\..\spice_codegen.py --generate-marshallers --include messages.h --client ..\..\spice.proto ..\generated_marshallers.cpp
+python ..\..\spice_codegen.py --generate-marshallers --client -H ..\..\spice.proto ..\generated_marshallers.h
diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
index a178a33..8f9e509 100644
--- a/client/windows/redc.vcproj
+++ b/client/windows/redc.vcproj
@@ -220,10 +220,6 @@
 				>
 			</File>
 			<File
-				RelativePath="..\generated_demarshallers.cpp"
-				>
-			</File>
-			<File
 				RelativePath="..\display_channel.cpp"
 				>
 			</File>
@@ -236,6 +232,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\generated_demarshallers.cpp"
+				>
+			</File>
+			<File
 				RelativePath="..\glz_decoder.cpp"
 				>
 			</File>
@@ -500,6 +500,14 @@
 				>
 			</File>
 			<File
+				RelativePath="..\generated_marshallers.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\generated_marshallers.h"
+				>
+			</File>
+			<File
 				RelativePath="..\..\common\win\my_getopt-1.5\getopt.h"
 				>
 			</File>
@@ -544,6 +552,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\marshaller.cpp"
+				>
+			</File>
+			<File
 				RelativePath="..\menu.h"
 				>
 			</File>
@@ -695,9 +707,9 @@
 				<Tool
 					Name="VCCustomBuildTool"
 					Description="Generating demarshaller"
-					CommandLine="python $(ProjectDir)\..\..\spice_codegen.py -d -c  -i common.h $(ProjectDir)\..\..\spice.proto $(ProjectDir)\..\generated_demarshallers.cpp&#x0D;&#x0A;"
+					CommandLine="generate.bat"
 					AdditionalDependencies=""
-					Outputs="$(ProjectDir)/../generated_demarshallers.cpp"
+					Outputs="$(ProjectDir)/../generated_demarshallers.cpp;$(ProjectDir)/../generated_marshallers.h;$(ProjectDir)/../generated_marshallers.cpp"
 				/>
 			</FileConfiguration>
 			<FileConfiguration
@@ -706,8 +718,8 @@
 				<Tool
 					Name="VCCustomBuildTool"
 					Description="Generating demarshaller"
-					CommandLine="python $(ProjectDir)\..\..\spice_codegen.py -d -c  -i common.h $(ProjectDir)\..\..\spice.proto $(ProjectDir)\..\generated_demarshallers.cpp"
-					Outputs="$(ProjectDir)/../generated_demarshallers.cpp"
+					CommandLine="generate.bat"
+					Outputs="$(ProjectDir)/../generated_demarshallers.cpp;$(ProjectDir)/../generated_marshallers.h;$(ProjectDir)/../generated_marshallers.cpp"
 				/>
 			</FileConfiguration>
 		</File>
diff --git a/common/marshaller.c b/common/marshaller.c
index 13385e5..5844b89 100644
--- a/common/marshaller.c
+++ b/common/marshaller.c
@@ -491,6 +491,7 @@ void spice_marshaller_flush(SpiceMarshaller *m)
     }
 }
 
+#ifndef WIN32
 int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
                                 int n_vec, size_t skip_bytes)
 {
@@ -522,6 +523,7 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
 
     return v;
 }
+#endif
 
 void spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
 {
diff --git a/common/marshaller.h b/common/marshaller.h
index 3b159aa..a60e97b 100644
--- a/common/marshaller.h
+++ b/common/marshaller.h
@@ -20,7 +20,9 @@
 #define _H_MARSHALLER
 
 #include <spice/types.h>
+#ifndef WIN32
 #include <sys/uio.h>
+#endif
 
 typedef struct SpiceMarshaller SpiceMarshaller;
 typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
@@ -44,8 +46,10 @@ 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);
diff --git a/python_modules/marshal.py b/python_modules/marshal.py
index 23b029a..4cbf942 100644
--- a/python_modules/marshal.py
+++ b/python_modules/marshal.py
@@ -18,6 +18,7 @@ def write_includes(writer):
     writer.newline()
     writer.writeln("#ifdef _MSC_VER")
     writer.writeln("#pragma warning(disable:4101)")
+    writer.writeln("#pragma warning(disable:4018)")
     writer.writeln("#endif")
     writer.newline()
 
commit 0f2e0378348f87c8e408a1db59783e1d9c00d68d
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 20:18:32 2010 +0200

    Add server/demarshaller.h

diff --git a/server/demarshallers.h b/server/demarshallers.h
new file mode 100644
index 0000000..e568cd0
--- /dev/null
+++ b/server/demarshallers.h
@@ -0,0 +1,25 @@
+/*
+   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 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);
+
+spice_parse_channel_func_t spice_get_client_channel_parser(uint32_t channel, unsigned int *max_message_type);
+
+#endif
+
commit 972951dbb78ecb8b9b7549a1302a49a00ad1b44b
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 17:12:31 2010 +0200

    Make sound data @as_ptr to avoid copying data

diff --git a/client/playback_channel.cpp b/client/playback_channel.cpp
index 9ac6ed6..1e902a9 100644
--- a/client/playback_channel.cpp
+++ b/client/playback_channel.cpp
@@ -295,8 +295,8 @@ void PlaybackChannel::handle_stop(RedPeer::InMessage* message)
 void PlaybackChannel::handle_raw_data(RedPeer::InMessage* message)
 {
     SpiceMsgPlaybackPacket* packet = (SpiceMsgPlaybackPacket*)message->data();
-    uint8_t* data = (uint8_t*)(packet + 1);
-    uint32_t size = message->size() - sizeof(*packet);
+    uint8_t* data = packet->data;
+    uint32_t size = packet->data_size;
 #ifdef WAVE_CAPTURE
     put_wave_data(data, size);
     return;
@@ -315,8 +315,8 @@ void PlaybackChannel::handle_raw_data(RedPeer::InMessage* message)
 void PlaybackChannel::handle_celt_data(RedPeer::InMessage* message)
 {
     SpiceMsgPlaybackPacket* packet = (SpiceMsgPlaybackPacket*)message->data();
-    uint8_t* data = (uint8_t*)(packet + 1);
-    uint32_t size = message->size() - sizeof(*packet);
+    uint8_t* data = packet->data;
+    uint32_t size = packet->data_size;
     celt_int16_t pcm[256 * 2];
 
     if (celt051_decode(_celt_decoder, data, size, pcm) != CELT_OK) {
diff --git a/common/messages.h b/common/messages.h
index e317949..7575f07 100644
--- a/common/messages.h
+++ b/common/messages.h
@@ -368,7 +368,8 @@ typedef struct SpiceMsgcMouseRelease {
 typedef struct SpiceMsgPlaybackMode {
     uint32_t time;
     uint32_t mode; //SPICE_AUDIO_DATA_MODE_?
-    uint8_t data[0];
+    uint8_t *data;
+    uint32_t data_size;
 } SpiceMsgPlaybackMode, SpiceMsgcRecordMode;
 
 typedef struct SpiceMsgPlaybackStart {
@@ -380,7 +381,8 @@ typedef struct SpiceMsgPlaybackStart {
 
 typedef struct SpiceMsgPlaybackPacket {
     uint32_t time;
-    uint8_t data[0];
+    uint8_t *data;
+    uint32_t data_size;
 } SpiceMsgPlaybackPacket, SpiceMsgcRecordPacket;
 
 typedef struct SpiceMsgRecordStart {
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 544da3b..d55380c 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -281,7 +281,7 @@ static int snd_record_handle_write(RecordChannel *record_channel, size_t size, v
     }
 
     packet = (SpiceMsgcRecordPacket *)message;
-    size = size - sizeof(*packet);
+    size = packet->data_size;
 
     if (record_channel->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) {
         int celt_err = celt051_decode(record_channel->celt_decoder, packet->data, size,
diff --git a/spice.proto b/spice.proto
index bad9ed3..6cedfac 100644
--- a/spice.proto
+++ b/spice.proto
@@ -921,13 +921,13 @@ channel PlaybackChannel : BaseChannel {
  server:
     message {
 	uint32 time;
-	uint8 data[] @end;
+	uint8 data[] @end @as_ptr(data_size);
     } @ctype(SpiceMsgPlaybackPacket) data = 101;
 
     message {
 	uint32 time;
 	audio_data_mode mode;
-	uint8 data[] @end;
+	uint8 data[] @end @as_ptr(data_size);
     } mode;
 
     message {
@@ -952,13 +952,13 @@ channel RecordChannel : BaseChannel {
  client:
     message {
 	uint32 time;
-	uint8 data[] @end @nomarshal;
+	uint8 data[] @end @nomarshal @as_ptr(data_size);
     } @ctype(SpiceMsgcRecordPacket) data = 101;
 
     message {
 	uint32 time;
 	audio_data_mode mode;
-	uint8 data[] @end;
+	uint8 data[] @end @as_ptr(data_size);
     } mode;
 
     message {
commit 4ce4364f84a1b458b715f4c5fa83ea20fd26f749
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 17:12:07 2010 +0200

    Make ping data @as_ptr to avoid copying data

diff --git a/common/messages.h b/common/messages.h
index 2ba14bf..e317949 100644
--- a/common/messages.h
+++ b/common/messages.h
@@ -150,6 +150,8 @@ typedef struct SpiceMsgMainMouseMode {
 typedef struct SpiceMsgPing {
     uint32_t id;
     uint64_t timestamp;
+    void *data;
+    uint32_t data_len;
 } SpiceMsgPing;
 
 typedef struct SpiceMsgMainAgentDisconnect {
diff --git a/spice.proto b/spice.proto
index 6750d2d..bad9ed3 100644
--- a/spice.proto
+++ b/spice.proto
@@ -111,7 +111,7 @@ channel BaseChannel {
     message {
 	uint32 id;
 	uint64 timestamp;
-	uint8 data[] @end @ctype(uint8_t);
+	uint8 data[] @end @ctype(uint8_t) @as_ptr(data_len);
     } ping;
 
     message {
commit 3c8cb83af5cbe85e6ab41ec1c0b41c5a29230d9e
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 17:11:39 2010 +0200

    Make cursor data @as_ptr to avoid copying data

diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp
index 26eb4c8..c973e9d 100644
--- a/client/cursor_channel.cpp
+++ b/client/cursor_channel.cpp
@@ -485,7 +485,7 @@ void CursorChannel::create_native_cursor(CursorData* cursor)
     cursor->set_opaque(native_cursor);
 }
 
-void CursorChannel::set_cursor(SpiceCursor& red_cursor, int data_size, int x, int y, bool visible)
+void CursorChannel::set_cursor(SpiceCursor& red_cursor, int x, int y, bool visible)
 {
     CursorData *cursor;
 
@@ -497,7 +497,7 @@ void CursorChannel::set_cursor(SpiceCursor& red_cursor, int data_size, int x, in
     if (red_cursor.flags & SPICE_CURSOR_FLAGS_FROM_CACHE) {
         cursor = _cursor_cache.get(red_cursor.header.unique);
     } else {
-        cursor = new CursorData(red_cursor, data_size);
+        cursor = new CursorData(red_cursor, red_cursor.data_size);
         if (red_cursor.flags & SPICE_CURSOR_FLAGS_CACHE_ME) {
             ASSERT(red_cursor.header.unique);
             _cursor_cache.add(red_cursor.header.unique, cursor);
@@ -560,7 +560,7 @@ void CursorChannel::handle_init(RedPeer::InMessage *message)
     attach_to_screen(get_client().get_application(), get_id());
     remove_cursor();
     _cursor_cache.clear();
-    set_cursor(init->cursor, message->size() - sizeof(SpiceMsgCursorInit), init->position.x,
+    set_cursor(init->cursor, init->position.x,
                init->position.y, init->visible != 0);
 }
 
@@ -574,7 +574,7 @@ void CursorChannel::handle_reset(RedPeer::InMessage *message)
 void CursorChannel::handle_cursor_set(RedPeer::InMessage* message)
 {
     SpiceMsgCursorSet* set = (SpiceMsgCursorSet*)message->data();
-    set_cursor(set->cursor, message->size() - sizeof(SpiceMsgCursorSet), set->position.x,
+    set_cursor(set->cursor, set->position.x,
                set->position.y, set->visible != 0);
 }
 
diff --git a/client/cursor_channel.h b/client/cursor_channel.h
index 3d6218f..c9e32b4 100644
--- a/client/cursor_channel.h
+++ b/client/cursor_channel.h
@@ -63,7 +63,7 @@ private:
     static void create_native_cursor(CursorData* cursor);
 
     void update_display_cursor();
-    void set_cursor(SpiceCursor& red_cursor, int data_size, int x, int y, bool visible);
+    void set_cursor(SpiceCursor& red_cursor, int x, int y, bool visible);
     void remove_cursor();
 
     virtual void copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc);
diff --git a/common/messages.h b/common/messages.h
index f6c2aeb..2ba14bf 100644
--- a/common/messages.h
+++ b/common/messages.h
@@ -173,7 +173,8 @@ typedef struct SpiceMsgcMainMouseModeRequest {
 typedef struct SpiceCursor {
     uint32_t flags;
     SpiceCursorHeader header;
-    uint8_t data[0];
+    uint32_t data_size;
+    uint8_t *data;
 } SpiceCursor;
 
 typedef struct SpiceMsgDisplayMode {
diff --git a/spice.proto b/spice.proto
index 093c808..6750d2d 100644
--- a/spice.proto
+++ b/spice.proto
@@ -867,7 +867,7 @@ struct CursorHeader {
 struct Cursor {
     cursor_flags flags;
     CursorHeader header;
-    uint8 data[] @end;
+    uint8 data[] @end @as_ptr(data_size);
 };
 
 channel CursorChannel : BaseChannel {
commit 7fa29ea67e5202d4a3f6678445cef9bcad54aa79
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 17:09:58 2010 +0200

    Support @as_ptr in demarshaller to avoid copying data unnecessary

diff --git a/python_modules/demarshal.py b/python_modules/demarshal.py
index fcd6850..8b90458 100644
--- a/python_modules/demarshal.py
+++ b/python_modules/demarshal.py
@@ -760,7 +760,19 @@ def write_member_parser(writer, container, member, dest, scope):
         #TODO validate e.g. flags and enums
     elif t.is_array():
         nelements = read_array_len(writer, member.name, t, dest, scope, handles_bytes = True)
-        write_array_parser(writer, nelements, t, dest, scope)
+        if member.has_attr("as_ptr") and t.element_type.is_fixed_nw_size():
+            writer.comment("use array as pointer").newline()
+            writer.assign(dest.get_ref(member.name), "(%s *)in" % t.element_type.c_type())
+            len_var = member.attributes["as_ptr"]
+            if len(len_var) > 0:
+                writer.assign(dest.get_ref(len_var[0]), nelements)
+            el_size = t.element_type.get_fixed_nw_size()
+            if el_size != 1:
+                writer.increment("in", "%s * %s" % (nelements, el_size))
+            else:
+                writer.increment("in", "%s" % (nelements))
+        else:
+            write_array_parser(writer, nelements, t, dest, scope)
     elif t.is_struct():
         if member.has_end_attr():
             dest2 = dest.child_at_end(writer, t)
commit 0b82006733e2eba89c32ac4dfb35e6db49cfa992
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 15:44:04 2010 +0200

    Make pointer types in messages be 64bit in memory
    
    Right now we always assume pointers are stored as SPICE_ADDRESS,
    i.e. 64bit, independent on the size sent on the network.
    This is required for 64bit architectures of course, but slightly overkill
    on 32bit architectures, so needs fixing when all SPICE_ADDRESS elements
    can be made internal.

diff --git a/common/messages.h b/common/messages.h
index cf9523e..f6c2aeb 100644
--- a/common/messages.h
+++ b/common/messages.h
@@ -442,8 +442,8 @@ typedef struct SpiceMsgcTunnelAddGenericService {
     uint32_t id;
     uint32_t group;
     uint32_t port;
-    uint32_t name;
-    uint32_t description;
+    uint64_t name;
+    uint64_t description;
 } SpiceMsgcTunnelAddGenericService;
 
 typedef struct SpiceMsgcTunnelAddPrintService {
commit 3a07edb4afa00dd897a3b9f07c9b5c10f5b39b8e
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 15:10:57 2010 +0200

    Don't pack the message structures

diff --git a/common/messages.h b/common/messages.h
index 7f6fe07..cf9523e 100644
--- a/common/messages.h
+++ b/common/messages.h
@@ -33,29 +33,27 @@
 
 #include <spice/protocol.h>
 
-#include <spice/start-packed.h>
-
-typedef struct SPICE_ATTR_PACKED SpiceMsgData {
+typedef struct SpiceMsgData {
     uint32_t data_size;
     uint8_t data[0];
 } SpiceMsgData;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgEmpty {
+typedef struct SpiceMsgEmpty {
 } SpiceMsgEmpty;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgInputsInit {
+typedef struct SpiceMsgInputsInit {
     uint32_t keyboard_modifiers;
 } SpiceMsgInputsInit;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgInputsKeyModifiers {
+typedef struct SpiceMsgInputsKeyModifiers {
     uint32_t modifiers;
 } SpiceMsgInputsKeyModifiers;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgMainMultiMediaTime {
+typedef struct SpiceMsgMainMultiMediaTime {
     uint32_t time;
 } SpiceMsgMainMultiMediaTime;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgMainMigrationBegin {
+typedef struct SpiceMsgMainMigrationBegin {
     uint16_t port;
     uint16_t sport;
     uint32_t host_offset;
@@ -65,7 +63,7 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgMainMigrationBegin {
     uint32_t pub_key_size;
 } SpiceMsgMainMigrationBegin;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgMainMigrationSwitchHost {
+typedef struct SpiceMsgMainMigrationSwitchHost {
     uint16_t port;
     uint16_t sport;
     uint32_t host_offset;
@@ -75,46 +73,46 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgMainMigrationSwitchHost {
 } SpiceMsgMainMigrationSwitchHost;
 
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgMigrate {
+typedef struct SpiceMsgMigrate {
     uint32_t flags;
 } SpiceMsgMigrate;
 
-typedef struct SPICE_ATTR_PACKED SpiceResourceID {
+typedef struct SpiceResourceID {
     uint8_t type;
     uint64_t id;
 } SpiceResourceID;
 
-typedef struct SPICE_ATTR_PACKED SpiceResourceList {
+typedef struct SpiceResourceList {
     uint16_t count;
     SpiceResourceID resources[0];
 } SpiceResourceList;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgSetAck {
+typedef struct SpiceMsgSetAck {
     uint32_t generation;
     uint32_t window;
 } SpiceMsgSetAck;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcAckSync {
+typedef struct SpiceMsgcAckSync {
   uint32_t generation;
 } SpiceMsgcAckSync;
 
-typedef struct SPICE_ATTR_PACKED SpiceWaitForChannel {
+typedef struct SpiceWaitForChannel {
     uint8_t channel_type;
     uint8_t channel_id;
     uint64_t message_serial;
 } SpiceWaitForChannel;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgWaitForChannels {
+typedef struct SpiceMsgWaitForChannels {
     uint8_t wait_count;
     SpiceWaitForChannel wait_list[0];
 } SpiceMsgWaitForChannels;
 
-typedef struct SPICE_ATTR_PACKED SpiceChannelId {
+typedef struct SpiceChannelId {
     uint8_t type;
     uint8_t id;
 } SpiceChannelId;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgMainInit {
+typedef struct SpiceMsgMainInit {
     uint32_t session_id;
     uint32_t display_channels_hint;
     uint32_t supported_mouse_modes;
@@ -125,12 +123,12 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgMainInit {
     uint32_t ram_hint;
 } SpiceMsgMainInit;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisconnect {
+typedef struct SpiceMsgDisconnect {
     uint64_t time_stamp;
     uint32_t reason; // SPICE_ERR_?
 } SpiceMsgDisconnect;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgNotify {
+typedef struct SpiceMsgNotify {
     uint64_t time_stamp;
     uint32_t severity;
     uint32_t visibilty;
@@ -139,52 +137,52 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgNotify {
     uint8_t message[0];
 } SpiceMsgNotify;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgChannels {
+typedef struct SpiceMsgChannels {
     uint32_t num_of_channels;
     SpiceChannelId channels[0];
 } SpiceMsgChannels;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgMainMouseMode {
+typedef struct SpiceMsgMainMouseMode {
     uint32_t supported_modes;
     uint32_t current_mode;
 } SpiceMsgMainMouseMode;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgPing {
+typedef struct SpiceMsgPing {
     uint32_t id;
     uint64_t timestamp;
 } SpiceMsgPing;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgMainAgentDisconnect {
+typedef struct SpiceMsgMainAgentDisconnect {
     uint32_t error_code; // SPICE_ERR_?
 } SpiceMsgMainAgentDisconnect;
 
 #define SPICE_AGENT_MAX_DATA_SIZE 2048
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgMainAgentTokens {
+typedef struct SpiceMsgMainAgentTokens {
     uint32_t num_tokens;
 } SpiceMsgMainAgentTokens, SpiceMsgcMainAgentTokens, SpiceMsgcMainAgentStart;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcClientInfo {
+typedef struct SpiceMsgcClientInfo {
     uint64_t cache_size;
 } SpiceMsgcClientInfo;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcMainMouseModeRequest {
+typedef struct SpiceMsgcMainMouseModeRequest {
     uint32_t mode;
 } SpiceMsgcMainMouseModeRequest;
 
-typedef struct SPICE_ATTR_PACKED SpiceCursor {
+typedef struct SpiceCursor {
     uint32_t flags;
     SpiceCursorHeader header;
     uint8_t data[0];
 } SpiceCursor;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayMode {
+typedef struct SpiceMsgDisplayMode {
     uint32_t x_res;
     uint32_t y_res;
     uint32_t bits;
 } SpiceMsgDisplayMode;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgSurfaceCreate {
+typedef struct SpiceMsgSurfaceCreate {
     uint32_t surface_id;
     uint32_t width;
     uint32_t height;
@@ -192,83 +190,83 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgSurfaceCreate {
     uint32_t flags;
 } SpiceMsgSurfaceCreate;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgSurfaceDestroy {
+typedef struct SpiceMsgSurfaceDestroy {
     uint32_t surface_id;
 } SpiceMsgSurfaceDestroy;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayBase {
+typedef struct SpiceMsgDisplayBase {
     uint32_t surface_id;
     SpiceRect box;
     SpiceClip clip;
 } SpiceMsgDisplayBase;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawFill {
+typedef struct SpiceMsgDisplayDrawFill {
     SpiceMsgDisplayBase base;
     SpiceFill data;
 } SpiceMsgDisplayDrawFill;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawOpaque {
+typedef struct SpiceMsgDisplayDrawOpaque {
     SpiceMsgDisplayBase base;
     SpiceOpaque data;
 } SpiceMsgDisplayDrawOpaque;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawCopy {
+typedef struct SpiceMsgDisplayDrawCopy {
     SpiceMsgDisplayBase base;
     SpiceCopy data;
 } SpiceMsgDisplayDrawCopy;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawTransparent {
+typedef struct SpiceMsgDisplayDrawTransparent {
     SpiceMsgDisplayBase base;
     SpiceTransparent data;
 } SpiceMsgDisplayDrawTransparent;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawAlphaBlend {
+typedef struct SpiceMsgDisplayDrawAlphaBlend {
     SpiceMsgDisplayBase base;
     SpiceAlphaBlnd data;
 } SpiceMsgDisplayDrawAlphaBlend;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayCopyBits {
+typedef struct SpiceMsgDisplayCopyBits {
     SpiceMsgDisplayBase base;
     SpicePoint src_pos;
 } SpiceMsgDisplayCopyBits;
 
 typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawRop3 {
+typedef struct SpiceMsgDisplayDrawRop3 {
     SpiceMsgDisplayBase base;
     SpiceRop3 data;
 } SpiceMsgDisplayDrawRop3;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawBlackness {
+typedef struct SpiceMsgDisplayDrawBlackness {
     SpiceMsgDisplayBase base;
     SpiceBlackness data;
 } SpiceMsgDisplayDrawBlackness;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawWhiteness {
+typedef struct SpiceMsgDisplayDrawWhiteness {
     SpiceMsgDisplayBase base;
     SpiceWhiteness data;
 } SpiceMsgDisplayDrawWhiteness;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawInvers {
+typedef struct SpiceMsgDisplayDrawInvers {
     SpiceMsgDisplayBase base;
     SpiceInvers data;
 } SpiceMsgDisplayDrawInvers;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawStroke {
+typedef struct SpiceMsgDisplayDrawStroke {
     SpiceMsgDisplayBase base;
     SpiceStroke data;
 } SpiceMsgDisplayDrawStroke;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawText {
+typedef struct SpiceMsgDisplayDrawText {
     SpiceMsgDisplayBase base;
     SpiceText data;
 } SpiceMsgDisplayDrawText;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayInvalOne {
+typedef struct SpiceMsgDisplayInvalOne {
     uint64_t id;
 } SpiceMsgDisplayInvalOne;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayStreamCreate {
+typedef struct SpiceMsgDisplayStreamCreate {
     uint32_t surface_id;
     uint32_t id;
     uint32_t flags;
@@ -282,7 +280,7 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayStreamCreate {
     SpiceClip clip;
 } SpiceMsgDisplayStreamCreate;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayStreamData {
+typedef struct SpiceMsgDisplayStreamData {
     uint32_t id;
     uint32_t multi_media_time;
     uint32_t data_size;
@@ -290,16 +288,16 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayStreamData {
     uint8_t data[0];
 } SpiceMsgDisplayStreamData;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayStreamClip {
+typedef struct SpiceMsgDisplayStreamClip {
     uint32_t id;
     SpiceClip clip;
 } SpiceMsgDisplayStreamClip;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayStreamDestroy {
+typedef struct SpiceMsgDisplayStreamDestroy {
     uint32_t id;
 } SpiceMsgDisplayStreamDestroy;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgCursorInit {
+typedef struct SpiceMsgCursorInit {
     SpicePoint16 position;
     uint16_t trail_length;
     uint16_t trail_frequency;
@@ -307,109 +305,109 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgCursorInit {
     SpiceCursor cursor;
 } SpiceMsgCursorInit;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgCursorSet {
+typedef struct SpiceMsgCursorSet {
     SpicePoint16 position;
     uint8_t visible;
     SpiceCursor cursor;
 } SpiceMsgCursorSet;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgCursorMove {
+typedef struct SpiceMsgCursorMove {
     SpicePoint16 position;
 } SpiceMsgCursorMove;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgCursorTrail {
+typedef struct SpiceMsgCursorTrail {
     uint16_t length;
     uint16_t frequency;
 } SpiceMsgCursorTrail;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcDisplayInit {
+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 SPICE_ATTR_PACKED SpiceMsgcKeyDown {
+typedef struct SpiceMsgcKeyDown {
     uint32_t code;
 } SpiceMsgcKeyDown;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcKeyUp {
+typedef struct SpiceMsgcKeyUp {
     uint32_t code;
 } SpiceMsgcKeyUp;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcKeyModifiers {
+typedef struct SpiceMsgcKeyModifiers {
     uint32_t modifiers;
 } SpiceMsgcKeyModifiers;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcMouseMotion {
+typedef struct SpiceMsgcMouseMotion {
     int32_t dx;
     int32_t dy;
     uint32_t buttons_state;
 } SpiceMsgcMouseMotion;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcMousePosition {
+typedef struct SpiceMsgcMousePosition {
     uint32_t x;
     uint32_t y;
     uint32_t buttons_state;
     uint8_t display_id;
 } SpiceMsgcMousePosition;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcMousePress {
+typedef struct SpiceMsgcMousePress {
     int32_t button;
     int32_t buttons_state;
 } SpiceMsgcMousePress;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcMouseRelease {
+typedef struct SpiceMsgcMouseRelease {
     int32_t button;
     int32_t buttons_state;
 } SpiceMsgcMouseRelease;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgPlaybackMode {
+typedef struct SpiceMsgPlaybackMode {
     uint32_t time;
     uint32_t mode; //SPICE_AUDIO_DATA_MODE_?
     uint8_t data[0];
 } SpiceMsgPlaybackMode, SpiceMsgcRecordMode;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgPlaybackStart {
+typedef struct SpiceMsgPlaybackStart {
     uint32_t channels;
     uint32_t format; //SPICE_AUDIO_FMT_?
     uint32_t frequency;
     uint32_t time;
 } SpiceMsgPlaybackStart;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgPlaybackPacket {
+typedef struct SpiceMsgPlaybackPacket {
     uint32_t time;
     uint8_t data[0];
 } SpiceMsgPlaybackPacket, SpiceMsgcRecordPacket;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgRecordStart {
+typedef struct SpiceMsgRecordStart {
     uint32_t channels;
     uint32_t format; //SPICE_AUDIO_FMT_?
     uint32_t frequency;
 } SpiceMsgRecordStart;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcRecordStartMark {
+typedef struct SpiceMsgcRecordStartMark {
     uint32_t time;
 } SpiceMsgcRecordStartMark;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelInit {
+typedef struct SpiceMsgTunnelInit {
     uint16_t max_num_of_sockets;
     uint32_t max_socket_data_size;
 } SpiceMsgTunnelInit;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelIpInfo {
+typedef struct SpiceMsgTunnelIpInfo {
     uint16_t type;
     uint8_t data[0];
 } SpiceMsgTunnelIpInfo;
 
 typedef uint8_t SpiceTunnelIPv4[4];
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelServiceIpMap {
+typedef struct SpiceMsgTunnelServiceIpMap {
     uint32_t service_id;
     SpiceMsgTunnelIpInfo virtual_ip;
 } SpiceMsgTunnelServiceIpMap;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketOpen {
+typedef struct SpiceMsgTunnelSocketOpen {
     uint16_t connection_id;
     uint32_t service_id;
     uint32_t tokens;
@@ -417,29 +415,29 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketOpen {
 
 /* connection id must be the first field in msgs directed to a specific connection */
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketFin {
+typedef struct SpiceMsgTunnelSocketFin {
     uint16_t connection_id;
 } SpiceMsgTunnelSocketFin;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketClose {
+typedef struct SpiceMsgTunnelSocketClose {
     uint16_t connection_id;
 } SpiceMsgTunnelSocketClose;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketData {
+typedef struct SpiceMsgTunnelSocketData {
     uint16_t connection_id;
     uint8_t data[0];
 } SpiceMsgTunnelSocketData;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketTokens {
+typedef struct SpiceMsgTunnelSocketTokens {
     uint16_t connection_id;
     uint32_t num_tokens;
 } SpiceMsgTunnelSocketTokens;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketClosedAck {
+typedef struct SpiceMsgTunnelSocketClosedAck {
     uint16_t connection_id;
 } SpiceMsgTunnelSocketClosedAck;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelAddGenericService {
+typedef struct SpiceMsgcTunnelAddGenericService {
     uint32_t type;
     uint32_t id;
     uint32_t group;
@@ -448,50 +446,48 @@ typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelAddGenericService {
     uint32_t description;
 } SpiceMsgcTunnelAddGenericService;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelAddPrintService {
+typedef struct SpiceMsgcTunnelAddPrintService {
     SpiceMsgcTunnelAddGenericService base;
     SpiceMsgTunnelIpInfo ip;
 } SpiceMsgcTunnelAddPrintService;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelRemoveService {
+typedef struct SpiceMsgcTunnelRemoveService {
     uint32_t id;
 } SpiceMsgcTunnelRemoveService;
 
 /* connection id must be the first field in msgs directed to a specific connection */
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketOpenAck {
+typedef struct SpiceMsgcTunnelSocketOpenAck {
     uint16_t connection_id;
     uint32_t tokens;
 } SpiceMsgcTunnelSocketOpenAck;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketOpenNack {
+typedef struct SpiceMsgcTunnelSocketOpenNack {
     uint16_t connection_id;
 } SpiceMsgcTunnelSocketOpenNack;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketData {
+typedef struct SpiceMsgcTunnelSocketData {
     uint16_t connection_id;
     uint8_t data[0];
 } SpiceMsgcTunnelSocketData;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketFin {
+typedef struct SpiceMsgcTunnelSocketFin {
     uint16_t connection_id;
 } SpiceMsgcTunnelSocketFin;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketClosed {
+typedef struct SpiceMsgcTunnelSocketClosed {
     uint16_t connection_id;
 } SpiceMsgcTunnelSocketClosed;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketClosedAck {
+typedef struct SpiceMsgcTunnelSocketClosedAck {
     uint16_t connection_id;
 } SpiceMsgcTunnelSocketClosedAck;
 
-typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketTokens {
+typedef struct SpiceMsgcTunnelSocketTokens {
     uint16_t connection_id;
     uint32_t num_tokens;
 } SpiceMsgcTunnelSocketTokens;
 
-#include <spice/end-packed.h>
-
 #endif /* _H_SPICE_PROTOCOL */
 
 
commit 4c1094acce7a062d28fc2c7c45b2e0357105c7bf
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 14:05:59 2010 +0200

    Make all message structs internal to spice
    
    We move all message structs from spice-protocol to spice as
    we want to be able to change these as needed internally. The
    on-network format is no longer defined by these structures anyway,
    but rather by the spice protocol description.

diff --git a/client/Makefile.am b/client/Makefile.am
index f140203..86d7c3e 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -6,11 +6,11 @@ DIST_SUBDIRS = x11 #windows
 spice_built_sources = generated_demarshallers.cpp generated_marshallers.cpp generated_marshallers.h
 
 generated_demarshallers.cpp: $(top_srcdir)/spice.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h $(top_srcdir)/spice.proto generated_demarshallers.cpp
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h --include messages.h $(top_srcdir)/spice.proto generated_demarshallers.cpp
 
 STRUCTS=
 generated_marshallers.cpp: $(top_srcdir)/spice.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --client $(top_srcdir)/spice.proto generated_marshallers.cpp
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --include messages.h --client $(top_srcdir)/spice.proto generated_marshallers.cpp
 
 generated_marshallers.h: $(top_srcdir)/spice.proto
 	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --client -H $(top_srcdir)/spice.proto generated_marshallers.h
diff --git a/client/canvas.h b/client/canvas.h
index c988a52..ff70e11 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -22,7 +22,7 @@
 #include "common.h"
 #include "debug.h"
 #include "region.h"
-#include <spice/protocol.h>
+#include "messages.h"
 #include "cache.hpp"
 #include "shared_cache.hpp"
 #include "canvas_base.h"
diff --git a/client/cursor.h b/client/cursor.h
index a756543..f5084cd 100644
--- a/client/cursor.h
+++ b/client/cursor.h
@@ -19,7 +19,7 @@
 #define _H_CURSOR_
 
 #include "threads.h"
-#include <spice/protocol.h>
+#include "messages.h"
 #include "red_window_p.h"
 
 class CursorOpaque {
diff --git a/client/red_client.h b/client/red_client.h
index 51c1780..1b81328 100644
--- a/client/red_client.h
+++ b/client/red_client.h
@@ -27,7 +27,7 @@
 #include "inputs_channel.h"
 #include "cursor_channel.h"
 #include "audio_channels.h"
-#include <spice/protocol.h>
+#include "messages.h"
 #include <spice/vd_agent.h>
 #include "process_loop.h"
 
diff --git a/common/messages.h b/common/messages.h
new file mode 100644
index 0000000..7f6fe07
--- /dev/null
+++ b/common/messages.h
@@ -0,0 +1,497 @@
+/*
+   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 <spice/start-packed.h>
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgData {
+    uint32_t data_size;
+    uint8_t data[0];
+} SpiceMsgData;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgEmpty {
+} SpiceMsgEmpty;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgInputsInit {
+    uint32_t keyboard_modifiers;
+} SpiceMsgInputsInit;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgInputsKeyModifiers {
+    uint32_t modifiers;
+} SpiceMsgInputsKeyModifiers;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgMainMultiMediaTime {
+    uint32_t time;
+} SpiceMsgMainMultiMediaTime;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgMainMigrationBegin {
+    uint16_t port;
+    uint16_t sport;
+    uint32_t host_offset;
+    uint32_t host_size;
+    uint16_t pub_key_type;
+    uint32_t pub_key_offset;
+    uint32_t pub_key_size;
+} SpiceMsgMainMigrationBegin;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgMainMigrationSwitchHost {
+    uint16_t port;
+    uint16_t sport;
+    uint32_t host_offset;
+    uint32_t host_size;
+    uint32_t cert_subject_offset;
+    uint32_t cert_subject_size;
+} SpiceMsgMainMigrationSwitchHost;
+
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgMigrate {
+    uint32_t flags;
+} SpiceMsgMigrate;
+
+typedef struct SPICE_ATTR_PACKED SpiceResourceID {
+    uint8_t type;
+    uint64_t id;
+} SpiceResourceID;
+
+typedef struct SPICE_ATTR_PACKED SpiceResourceList {
+    uint16_t count;
+    SpiceResourceID resources[0];
+} SpiceResourceList;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgSetAck {
+    uint32_t generation;
+    uint32_t window;
+} SpiceMsgSetAck;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcAckSync {
+  uint32_t generation;
+} SpiceMsgcAckSync;
+
+typedef struct SPICE_ATTR_PACKED SpiceWaitForChannel {
+    uint8_t channel_type;
+    uint8_t channel_id;
+    uint64_t message_serial;
+} SpiceWaitForChannel;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgWaitForChannels {
+    uint8_t wait_count;
+    SpiceWaitForChannel wait_list[0];
+} SpiceMsgWaitForChannels;
+
+typedef struct SPICE_ATTR_PACKED SpiceChannelId {
+    uint8_t type;
+    uint8_t id;
+} SpiceChannelId;
+
+typedef struct SPICE_ATTR_PACKED 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 SPICE_ATTR_PACKED SpiceMsgDisconnect {
+    uint64_t time_stamp;
+    uint32_t reason; // SPICE_ERR_?
+} SpiceMsgDisconnect;
+
+typedef struct SPICE_ATTR_PACKED 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 SPICE_ATTR_PACKED SpiceMsgChannels {
+    uint32_t num_of_channels;
+    SpiceChannelId channels[0];
+} SpiceMsgChannels;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgMainMouseMode {
+    uint32_t supported_modes;
+    uint32_t current_mode;
+} SpiceMsgMainMouseMode;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgPing {
+    uint32_t id;
+    uint64_t timestamp;
+} SpiceMsgPing;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgMainAgentDisconnect {
+    uint32_t error_code; // SPICE_ERR_?
+} SpiceMsgMainAgentDisconnect;
+
+#define SPICE_AGENT_MAX_DATA_SIZE 2048
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgMainAgentTokens {
+    uint32_t num_tokens;
+} SpiceMsgMainAgentTokens, SpiceMsgcMainAgentTokens, SpiceMsgcMainAgentStart;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcClientInfo {
+    uint64_t cache_size;
+} SpiceMsgcClientInfo;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcMainMouseModeRequest {
+    uint32_t mode;
+} SpiceMsgcMainMouseModeRequest;
+
+typedef struct SPICE_ATTR_PACKED SpiceCursor {
+    uint32_t flags;
+    SpiceCursorHeader header;
+    uint8_t data[0];
+} SpiceCursor;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayMode {
+    uint32_t x_res;
+    uint32_t y_res;
+    uint32_t bits;
+} SpiceMsgDisplayMode;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgSurfaceCreate {
+    uint32_t surface_id;
+    uint32_t width;
+    uint32_t height;
+    uint32_t format;
+    uint32_t flags;
+} SpiceMsgSurfaceCreate;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgSurfaceDestroy {
+    uint32_t surface_id;
+} SpiceMsgSurfaceDestroy;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayBase {
+    uint32_t surface_id;
+    SpiceRect box;
+    SpiceClip clip;
+} SpiceMsgDisplayBase;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawFill {
+    SpiceMsgDisplayBase base;
+    SpiceFill data;
+} SpiceMsgDisplayDrawFill;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawOpaque {
+    SpiceMsgDisplayBase base;
+    SpiceOpaque data;
+} SpiceMsgDisplayDrawOpaque;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawCopy {
+    SpiceMsgDisplayBase base;
+    SpiceCopy data;
+} SpiceMsgDisplayDrawCopy;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawTransparent {
+    SpiceMsgDisplayBase base;
+    SpiceTransparent data;
+} SpiceMsgDisplayDrawTransparent;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawAlphaBlend {
+    SpiceMsgDisplayBase base;
+    SpiceAlphaBlnd data;
+} SpiceMsgDisplayDrawAlphaBlend;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayCopyBits {
+    SpiceMsgDisplayBase base;
+    SpicePoint src_pos;
+} SpiceMsgDisplayCopyBits;
+
+typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawRop3 {
+    SpiceMsgDisplayBase base;
+    SpiceRop3 data;
+} SpiceMsgDisplayDrawRop3;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawBlackness {
+    SpiceMsgDisplayBase base;
+    SpiceBlackness data;
+} SpiceMsgDisplayDrawBlackness;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawWhiteness {
+    SpiceMsgDisplayBase base;
+    SpiceWhiteness data;
+} SpiceMsgDisplayDrawWhiteness;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawInvers {
+    SpiceMsgDisplayBase base;
+    SpiceInvers data;
+} SpiceMsgDisplayDrawInvers;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawStroke {
+    SpiceMsgDisplayBase base;
+    SpiceStroke data;
+} SpiceMsgDisplayDrawStroke;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayDrawText {
+    SpiceMsgDisplayBase base;
+    SpiceText data;
+} SpiceMsgDisplayDrawText;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayInvalOne {
+    uint64_t id;
+} SpiceMsgDisplayInvalOne;
+
+typedef struct SPICE_ATTR_PACKED 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 SPICE_ATTR_PACKED SpiceMsgDisplayStreamData {
+    uint32_t id;
+    uint32_t multi_media_time;
+    uint32_t data_size;
+    uint32_t pad_size;
+    uint8_t data[0];
+} SpiceMsgDisplayStreamData;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayStreamClip {
+    uint32_t id;
+    SpiceClip clip;
+} SpiceMsgDisplayStreamClip;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgDisplayStreamDestroy {
+    uint32_t id;
+} SpiceMsgDisplayStreamDestroy;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgCursorInit {
+    SpicePoint16 position;
+    uint16_t trail_length;
+    uint16_t trail_frequency;
+    uint8_t visible;
+    SpiceCursor cursor;
+} SpiceMsgCursorInit;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgCursorSet {
+    SpicePoint16 position;
+    uint8_t visible;
+    SpiceCursor cursor;
+} SpiceMsgCursorSet;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgCursorMove {
+    SpicePoint16 position;
+} SpiceMsgCursorMove;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgCursorTrail {
+    uint16_t length;
+    uint16_t frequency;
+} SpiceMsgCursorTrail;
+
+typedef struct SPICE_ATTR_PACKED 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 SPICE_ATTR_PACKED SpiceMsgcKeyDown {
+    uint32_t code;
+} SpiceMsgcKeyDown;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcKeyUp {
+    uint32_t code;
+} SpiceMsgcKeyUp;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcKeyModifiers {
+    uint32_t modifiers;
+} SpiceMsgcKeyModifiers;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcMouseMotion {
+    int32_t dx;
+    int32_t dy;
+    uint32_t buttons_state;
+} SpiceMsgcMouseMotion;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcMousePosition {
+    uint32_t x;
+    uint32_t y;
+    uint32_t buttons_state;
+    uint8_t display_id;
+} SpiceMsgcMousePosition;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcMousePress {
+    int32_t button;
+    int32_t buttons_state;
+} SpiceMsgcMousePress;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcMouseRelease {
+    int32_t button;
+    int32_t buttons_state;
+} SpiceMsgcMouseRelease;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgPlaybackMode {
+    uint32_t time;
+    uint32_t mode; //SPICE_AUDIO_DATA_MODE_?
+    uint8_t data[0];
+} SpiceMsgPlaybackMode, SpiceMsgcRecordMode;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgPlaybackStart {
+    uint32_t channels;
+    uint32_t format; //SPICE_AUDIO_FMT_?
+    uint32_t frequency;
+    uint32_t time;
+} SpiceMsgPlaybackStart;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgPlaybackPacket {
+    uint32_t time;
+    uint8_t data[0];
+} SpiceMsgPlaybackPacket, SpiceMsgcRecordPacket;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgRecordStart {
+    uint32_t channels;
+    uint32_t format; //SPICE_AUDIO_FMT_?
+    uint32_t frequency;
+} SpiceMsgRecordStart;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcRecordStartMark {
+    uint32_t time;
+} SpiceMsgcRecordStartMark;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelInit {
+    uint16_t max_num_of_sockets;
+    uint32_t max_socket_data_size;
+} SpiceMsgTunnelInit;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelIpInfo {
+    uint16_t type;
+    uint8_t data[0];
+} SpiceMsgTunnelIpInfo;
+
+typedef uint8_t SpiceTunnelIPv4[4];
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelServiceIpMap {
+    uint32_t service_id;
+    SpiceMsgTunnelIpInfo virtual_ip;
+} SpiceMsgTunnelServiceIpMap;
+
+typedef struct SPICE_ATTR_PACKED 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 SPICE_ATTR_PACKED SpiceMsgTunnelSocketFin {
+    uint16_t connection_id;
+} SpiceMsgTunnelSocketFin;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketClose {
+    uint16_t connection_id;
+} SpiceMsgTunnelSocketClose;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketData {
+    uint16_t connection_id;
+    uint8_t data[0];
+} SpiceMsgTunnelSocketData;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketTokens {
+    uint16_t connection_id;
+    uint32_t num_tokens;
+} SpiceMsgTunnelSocketTokens;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgTunnelSocketClosedAck {
+    uint16_t connection_id;
+} SpiceMsgTunnelSocketClosedAck;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelAddGenericService {
+    uint32_t type;
+    uint32_t id;
+    uint32_t group;
+    uint32_t port;
+    uint32_t name;
+    uint32_t description;
+} SpiceMsgcTunnelAddGenericService;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelAddPrintService {
+    SpiceMsgcTunnelAddGenericService base;
+    SpiceMsgTunnelIpInfo ip;
+} SpiceMsgcTunnelAddPrintService;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelRemoveService {
+    uint32_t id;
+} SpiceMsgcTunnelRemoveService;
+
+/* connection id must be the first field in msgs directed to a specific connection */
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketOpenAck {
+    uint16_t connection_id;
+    uint32_t tokens;
+} SpiceMsgcTunnelSocketOpenAck;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketOpenNack {
+    uint16_t connection_id;
+} SpiceMsgcTunnelSocketOpenNack;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketData {
+    uint16_t connection_id;
+    uint8_t data[0];
+} SpiceMsgcTunnelSocketData;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketFin {
+    uint16_t connection_id;
+} SpiceMsgcTunnelSocketFin;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketClosed {
+    uint16_t connection_id;
+} SpiceMsgcTunnelSocketClosed;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketClosedAck {
+    uint16_t connection_id;
+} SpiceMsgcTunnelSocketClosedAck;
+
+typedef struct SPICE_ATTR_PACKED SpiceMsgcTunnelSocketTokens {
+    uint16_t connection_id;
+    uint32_t num_tokens;
+} SpiceMsgcTunnelSocketTokens;
+
+#include <spice/end-packed.h>
+
+#endif /* _H_SPICE_PROTOCOL */
+
+
diff --git a/server/Makefile.am b/server/Makefile.am
index 8d507a4..9a6ac88 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -25,7 +25,7 @@ generated_demarshallers.c: $(top_srcdir)/spice.proto
 
 STRUCTS=-M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlnd -M PathSegment
 generated_marshallers.c: $(top_srcdir)/spice.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server $(top_srcdir)/spice.proto generated_marshallers.c
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --include red_common.h --generate-marshallers $(STRUCTS) --server $(top_srcdir)/spice.proto generated_marshallers.c
 
 generated_marshallers.h: $(top_srcdir)/spice.proto
 	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server -H $(top_srcdir)/spice.proto generated_marshallers.h
diff --git a/server/red_common.h b/server/red_common.h
index 2df1a16..c863922 100644
--- a/server/red_common.h
+++ b/server/red_common.h
@@ -23,7 +23,7 @@
 
 #include "spice.h"
 #include "mem.h"
-#include <spice/protocol.h>
+#include <messages.h>
 #include <spice/macros.h>
 
 #define ASSERT(x) if (!(x)) {                               \
commit 185a320c9be85d07586e5d475c991770853fec77
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 13:43:45 2010 +0200

    Allow multiple --include args

diff --git a/spice_codegen.py b/spice_codegen.py
index 0e9551f..c8d0d5f 100755
--- a/spice_codegen.py
+++ b/spice_codegen.py
@@ -108,7 +108,7 @@ parser.add_option("-k", "--keep-identical-file",
                   action="store_true", dest="keep_identical_file", default=False,
                   help="Print errors")
 parser.add_option("-i", "--include",
-                  dest="include", default=None, metavar="FILE",
+                  action="append", dest="includes", metavar="FILE",
                   help="Include FILE in generated code")
 
 (options, args) = parser.parse_args()
@@ -137,8 +137,9 @@ if options.assert_on_error:
 if options.print_error:
     writer.set_option("print_error")
 
-if options.include:
-    writer.writeln('#include "%s"' % options.include)
+if options.includes:
+    for i in options.includes:
+        writer.writeln('#include "%s"' % i)
 
 if options.generate_enums:
     write_enums(writer)
commit c553fafe4b1c9db32ea3e83b314ff23dfd44f554
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 10:22:57 2010 +0200

    Use generated demarshallers in server

diff --git a/server/red_worker.c b/server/red_worker.c
index 8b40116..387861c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -51,6 +51,7 @@
 #include "jpeg_encoder.h"
 #include "rect.h"
 #include "marshaller.h"
+#include "demarshallers.h"
 #include "generated_marshallers.h"
 
 //#define COMPRESS_STAT
@@ -348,11 +349,12 @@ typedef struct RedChannel RedChannel;
 typedef void (*disconnect_channel_proc)(RedChannel *channel);
 typedef void (*hold_item_proc)(void *item);
 typedef void (*release_item_proc)(RedChannel *channel, void *item);
-typedef int (*handle_message_proc)(RedChannel *channel, SpiceDataHeader *message);
+typedef int (*handle_message_proc)(RedChannel *channel, size_t size, uint32_t type, void *message);
 
 struct RedChannel {
     EventListener listener;
     uint32_t id;
+    spice_parse_channel_func_t parser;
     struct RedWorker *worker;
     RedsStreamContext *peer;
     int migrate;
@@ -9888,15 +9890,11 @@ static void on_new_display_channel(RedWorker *worker)
     }
 }
 
-static int channel_handle_message(RedChannel *channel, SpiceDataHeader *message)
+static int channel_handle_message(RedChannel *channel, size_t size, uint32_t type, void *message)
 {
-    switch (message->type) {
+    switch (type) {
     case SPICE_MSGC_ACK_SYNC:
-        if (message->size != sizeof(uint32_t)) {
-            red_printf("bad message size");
-            return FALSE;
-        }
-        channel->client_ack_generation = *(uint32_t *)(message + 1);
+        channel->client_ack_generation = *(uint32_t *)message;
         break;
     case SPICE_MSGC_ACK:
         if (channel->client_ack_generation == channel->ack_generation) {
@@ -9906,7 +9904,7 @@ static int channel_handle_message(RedChannel *channel, SpiceDataHeader *message)
     case SPICE_MSGC_DISCONNECTING:
         break;
     default:
-        red_printf("invalid message type %u", message->type);
+        red_printf("invalid message type %u", type);
         return FALSE;
     }
     return TRUE;
@@ -10146,7 +10144,7 @@ static int display_channel_handle_migrate_mark(DisplayChannel *channel)
     return TRUE;
 }
 
-static int display_channel_handle_migrate_data(DisplayChannel *channel, SpiceDataHeader *message)
+static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t size, void *message)
 {
     DisplayChannelMigrateData *migrate_data;
     int i;
@@ -10156,11 +10154,11 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, SpiceDat
         return FALSE;
     }
     channel->expect_migrate_data = FALSE;
-    if (message->size < sizeof(*migrate_data)) {
+    if (size < sizeof(*migrate_data)) {
         red_printf("bad message size");
         return FALSE;
     }
-    migrate_data = (DisplayChannelMigrateData *)(message + 1);
+    migrate_data = (DisplayChannelMigrateData *)message;
     if (migrate_data->magic != DISPLAY_MIGRATE_DATA_MAGIC ||
                                             migrate_data->version != DISPLAY_MIGRATE_DATA_VERSION) {
         red_printf("invalid content");
@@ -10197,26 +10195,22 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, SpiceDat
     return TRUE;
 }
 
-static int display_channel_handle_message(RedChannel *channel, SpiceDataHeader *message)
+static int display_channel_handle_message(RedChannel *channel, size_t size, uint32_t type, void *message)
 {
-    switch (message->type) {
+    switch (type) {
     case SPICE_MSGC_DISPLAY_INIT:
-        if (message->size != sizeof(SpiceMsgcDisplayInit)) {
-            red_printf("bad message size");
-            return FALSE;
-        }
         if (!((DisplayChannel *)channel)->expect_init) {
             red_printf("unexpected SPICE_MSGC_DISPLAY_INIT");
             return FALSE;
         }
         ((DisplayChannel *)channel)->expect_init = FALSE;
-        return display_channel_init((DisplayChannel *)channel, (SpiceMsgcDisplayInit *)(message + 1));
+        return display_channel_init((DisplayChannel *)channel, (SpiceMsgcDisplayInit *)message);
     case SPICE_MSGC_MIGRATE_FLUSH_MARK:
         return display_channel_handle_migrate_mark((DisplayChannel *)channel);
     case SPICE_MSGC_MIGRATE_DATA:
-        return display_channel_handle_migrate_data((DisplayChannel *)channel, message);
+        return display_channel_handle_migrate_data((DisplayChannel *)channel, size, message);
     default:
-        return channel_handle_message(channel, message);
+        return channel_handle_message(channel, size, type, message);
     }
 }
 
@@ -10249,19 +10243,34 @@ static void red_receive(RedChannel *channel)
         } else {
             channel->recive_data.now += n;
             for (;;) {
-                SpiceDataHeader *message = channel->recive_data.message;
-                n = channel->recive_data.now - (uint8_t *)message;
+                SpiceDataHeader *header = channel->recive_data.message;
+                uint8_t *data = (uint8_t *)(header+1);
+                size_t parsed_size;
+                uint8_t *parsed;
+
+                n = channel->recive_data.now - (uint8_t *)header;
                 if (n < sizeof(SpiceDataHeader) ||
-                    n < sizeof(SpiceDataHeader) + message->size) {
+                    n < sizeof(SpiceDataHeader) + header->size) {
                     break;
                 }
-                if (!channel->handle_message(channel, message)) {
+                parsed = channel->parser((void *)data, data + header->size, header->type,
+                                         SPICE_VERSION_MINOR, &parsed_size);
+
+                if (parsed == NULL) {
+                    red_printf("failed to parse message type %d", header->type);
+                    channel->disconnect(channel);
+                    return;
+                }
+
+                if (!channel->handle_message(channel, parsed_size, header->type, parsed)) {
+                    free(parsed);
                     channel->disconnect(channel);
                     return;
                 }
-                channel->recive_data.message = (SpiceDataHeader *)((uint8_t *)message +
-                                                                 sizeof(SpiceDataHeader) +
-                                                                 message->size);
+                free(parsed);
+                channel->recive_data.message = (SpiceDataHeader *)((uint8_t *)header +
+                                                                   sizeof(SpiceDataHeader) +
+                                                                   header->size);
             }
 
             if (channel->recive_data.now == (uint8_t *)channel->recive_data.message) {
@@ -10276,7 +10285,8 @@ static void red_receive(RedChannel *channel)
     }
 }
 
-static RedChannel *__new_channel(RedWorker *worker, int size, RedsStreamContext *peer, int migrate,
+static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
+                                 RedsStreamContext *peer, int migrate,
                                  event_listener_action_proc handler,
                                  disconnect_channel_proc disconnect,
                                  hold_item_proc hold_item,
@@ -10306,6 +10316,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, RedsStreamContext
     ASSERT(size >= sizeof(*channel));
     channel = spice_malloc0(size);
     channel->id = worker->id;
+    channel->parser = spice_get_client_channel_parser(channel_id, NULL);
     channel->listener.refs = 1;
     channel->listener.action = handler;
     channel->disconnect = disconnect;
@@ -10408,7 +10419,8 @@ static void handle_new_display_channel(RedWorker *worker, RedsStreamContext *pee
 
     red_disconnect_display((RedChannel *)worker->display_channel);
 
-    if (!(display_channel = (DisplayChannel *)__new_channel(worker, sizeof(*display_channel), peer,
+    if (!(display_channel = (DisplayChannel *)__new_channel(worker, sizeof(*display_channel),
+                                                            SPICE_CHANNEL_DISPLAY, peer,
                                                             migrate, handle_channel_events,
                                                             red_disconnect_display,
                                                             display_channel_hold_item,
@@ -10508,7 +10520,8 @@ static void red_connect_cursor(RedWorker *worker, RedsStreamContext *peer, int m
 
     red_disconnect_cursor((RedChannel *)worker->cursor_channel);
 
-    if (!(channel = (CursorChannel *)__new_channel(worker, sizeof(*channel), peer, migrate,
+    if (!(channel = (CursorChannel *)__new_channel(worker, sizeof(*channel),
+                                                   SPICE_CHANNEL_CURSOR, peer, migrate,
                                                    handle_channel_events,
                                                    red_disconnect_cursor,
                                                    cursor_channel_hold_item,
diff --git a/server/reds.c b/server/reds.c
index fee1cbf..f9d91db 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -52,6 +52,7 @@
 #include "stat.h"
 #include "ring.h"
 #include "config.h"
+#include "demarshallers.h"
 #include "marshaller.h"
 #include "generated_marshallers.h"
 #ifdef HAVE_SLIRP
@@ -113,11 +114,12 @@ static void openssl_init();
 #define CAPS_LOCK_SCAN_CODE 0x3a
 
 typedef struct IncomingHandler {
+    spice_parse_channel_func_t parser;
     void *opaque;
     int shut;
     uint8_t buf[RECIVE_BUF_SIZE];
     uint32_t end_pos;
-    void (*handle_message)(void *opaque, SpiceDataHeader *message);
+    void (*handle_message)(void *opaque, size_t size, uint32_t type, void *message);
 } IncomingHandler;
 
 typedef struct OutgoingHandler {
@@ -792,9 +794,19 @@ static int handle_incoming(RedsStreamContext *peer, IncomingHandler *handler)
             end = buf + pos;
             while (buf + sizeof(SpiceDataHeader) <= end &&
                    buf + sizeof(SpiceDataHeader) + (header = (SpiceDataHeader *)buf)->size <= end) {
-                buf += sizeof(SpiceDataHeader) + header->size;
-                handler->handle_message(handler->opaque, header);
+                uint8_t *data = (uint8_t *)(header+1);
+                size_t parsed_size;
+                uint8_t *parsed;
 
+                buf += sizeof(SpiceDataHeader) + header->size;
+                parsed = handler->parser(data, data + header->size, header->type,
+                                         SPICE_VERSION_MINOR, &parsed_size);
+                if (parsed == NULL) {
+                    red_printf("failed to parse message type %d", header->type);
+                    return -1;
+                }
+                handler->handle_message(handler->opaque, parsed_size, header->type, parsed);
+                free(parsed);
                 if (handler->shut) {
                     return -1;
                 }
@@ -1586,9 +1598,9 @@ static void main_channel_recive_migrate_data(MainMigrateData *data, uint8_t *end
     ASSERT(state->num_client_tokens + state->num_tokens == REDS_AGENT_WINDOW_SIZE);
 }
 
-static void reds_main_handle_message(void *opaque, SpiceDataHeader *message)
+static void reds_main_handle_message(void *opaque, size_t size, uint32_t type, void *message)
 {
-    switch (message->type) {
+    switch (type) {
     case SPICE_MSGC_MAIN_AGENT_START: {
         SpiceMsgcMainAgentTokens *agent_start;
 
@@ -1596,7 +1608,7 @@ static void reds_main_handle_message(void *opaque, SpiceDataHeader *message)
         if (!reds->peer) {
             return;
         }
-        agent_start = (SpiceMsgcMainAgentTokens *)(message + 1);
+        agent_start = (SpiceMsgcMainAgentTokens *)message;
         reds->agent_state.client_agent_started = TRUE;
         reds->agent_state.send_tokens = agent_start->num_tokens;
         read_from_vdi_port();
@@ -1624,7 +1636,7 @@ static void reds_main_handle_message(void *opaque, SpiceDataHeader *message)
             break;
         }
 
-        if (message->size > SPICE_AGENT_MAX_DATA_SIZE) {
+        if (size > SPICE_AGENT_MAX_DATA_SIZE) {
             red_printf("invalid agent message");
             reds_disconnect();
             break;
@@ -1638,9 +1650,9 @@ static void reds_main_handle_message(void *opaque, SpiceDataHeader *message)
         ring_remove(ring_item);
         buf = (VDAgentExtBuf *)ring_item;
         buf->base.now = (uint8_t *)&buf->base.chunk_header.port;
-        buf->base.write_len = message->size + sizeof(VDIChunkHeader);
-        buf->base.chunk_header.size = message->size;
-        memcpy(buf->buf, message + 1, message->size);
+        buf->base.write_len = size + sizeof(VDIChunkHeader);
+        buf->base.chunk_header.size = size;
+        memcpy(buf->buf, message, size);
         ring_add(&reds->agent_state.write_queue, ring_item);
         write_to_vdi_port();
         break;
@@ -1653,7 +1665,7 @@ static void reds_main_handle_message(void *opaque, SpiceDataHeader *message)
             break;
         }
 
-        token = (SpiceMsgcMainAgentTokens *)(message + 1);
+        token = (SpiceMsgcMainAgentTokens *)message;
         reds->agent_state.send_tokens += token->num_tokens;
         read_from_vdi_port();
         break;
@@ -1674,7 +1686,7 @@ static void reds_main_handle_message(void *opaque, SpiceDataHeader *message)
         }
         break;
     case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST: {
-        switch (((SpiceMsgcMainMouseModeRequest *)(message + 1))->mode) {
+        switch (((SpiceMsgcMainMouseModeRequest *)message)->mode) {
         case SPICE_MOUSE_MODE_CLIENT:
             if (reds->is_client_mouse_allowed) {
                 reds_set_mouse_mode(SPICE_MOUSE_MODE_CLIENT);
@@ -1691,7 +1703,7 @@ static void reds_main_handle_message(void *opaque, SpiceDataHeader *message)
         break;
     }
     case SPICE_MSGC_PONG: {
-        SpiceMsgPing *ping = (SpiceMsgPing *)(message + 1);
+        SpiceMsgPing *ping = (SpiceMsgPing *)message;
         uint64_t roundtrip;
         struct timespec ts;
 
@@ -1743,15 +1755,15 @@ static void reds_main_handle_message(void *opaque, SpiceDataHeader *message)
         main_channel_push_migrate_data_item();
         break;
     case SPICE_MSGC_MIGRATE_DATA:
-        main_channel_recive_migrate_data((MainMigrateData *)(message + 1),
-                                         (uint8_t *)(message + 1) + message->size);
+        main_channel_recive_migrate_data((MainMigrateData *)message,
+                                         ((uint8_t *)message) + size);
         reds->mig_target = FALSE;
         while (write_to_vdi_port() || read_from_vdi_port());
         break;
     case SPICE_MSGC_DISCONNECTING:
         break;
     default:
-        red_printf("unexpected type %d", message->type);
+        red_printf("unexpected type %d", type);
     }
 }
 
@@ -2058,12 +2070,12 @@ static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
     return sif->get_leds(sin);
 }
 
-static void inputs_handle_input(void *opaque, SpiceDataHeader *header)
+static void inputs_handle_input(void *opaque, size_t size, uint32_t type, void *message)
 {
     InputsState *state = (InputsState *)opaque;
-    uint8_t *buf = (uint8_t *)(header + 1);
+    uint8_t *buf = (uint8_t *)message;
 
-    switch (header->type) {
+    switch (type) {
     case SPICE_MSGC_INPUTS_KEY_DOWN: {
         SpiceMsgcKeyDown *key_up = (SpiceMsgcKeyDown *)buf;
         if (key_up->code == CAPS_LOCK_SCAN_CODE || key_up->code == NUM_LOCK_SCAN_CODE ||
@@ -2216,7 +2228,7 @@ static void inputs_handle_input(void *opaque, SpiceDataHeader *header)
     case SPICE_MSGC_DISCONNECTING:
         break;
     default:
-        red_printf("unexpected type %d", header->type);
+        red_printf("unexpected type %d", type);
     }
 }
 
@@ -2344,6 +2356,7 @@ static void inputs_link(Channel *channel, RedsStreamContext *peer, int migration
     inputs_state->peer = peer;
     inputs_state->end_pos = 0;
     inputs_state->channel = channel;
+    inputs_state->in_handler.parser = spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL);
     inputs_state->in_handler.opaque = inputs_state;
     inputs_state->in_handler.handle_message = inputs_handle_input;
     inputs_state->out_handler.length = 0;
@@ -3571,6 +3584,7 @@ static void do_spice_init(SpiceCoreInterface *core_interface)
     reds->listen_socket = -1;
     reds->secure_listen_socket = -1;
     reds->peer = NULL;
+    reds->in_handler.parser = spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL);
     reds->in_handler.handle_message = reds_main_handle_message;
     ring_init(&reds->outgoing.pipe);
     reds->outgoing.vec = reds->outgoing.vec_buf;
diff --git a/server/snd_worker.c b/server/snd_worker.c
index cd9af97..544da3b 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -30,6 +30,7 @@
 #include "snd_worker.h"
 #include "marshaller.h"
 #include "generated_marshallers.h"
+#include "demarshallers.h"
 
 #define MAX_SEND_VEC 100
 
@@ -65,7 +66,7 @@ enum RecordCommand {
 
 typedef struct SndChannel SndChannel;
 typedef void (*send_messages_proc)(void *in_channel);
-typedef int (*handle_message_proc)(SndChannel *channel, SpiceDataHeader *message);
+typedef int (*handle_message_proc)(SndChannel *channel, size_t size, uint32_t type, void *message);
 typedef void (*on_message_done_proc)(SndChannel *channel);
 typedef void (*cleanup_channel_proc)(SndChannel *channel);
 
@@ -74,6 +75,7 @@ typedef struct SndWorker SndWorker;
 struct SndChannel {
     RedsStreamContext *peer;
     SndWorker *worker;
+    spice_parse_channel_func_t parser;
 
     int active;
     int client_active;
@@ -266,12 +268,11 @@ static int snd_send_data(SndChannel *channel)
     return TRUE;
 }
 
-static int snd_record_handle_write(RecordChannel *record_channel, SpiceDataHeader *message)
+static int snd_record_handle_write(RecordChannel *record_channel, size_t size, void *message)
 {
     SpiceMsgcRecordPacket *packet;
     uint32_t write_pos;
     uint32_t* data;
-    uint32_t size;
     uint32_t len;
     uint32_t now;
 
@@ -279,8 +280,8 @@ static int snd_record_handle_write(RecordChannel *record_channel, SpiceDataHeade
         return FALSE;
     }
 
-    packet = (SpiceMsgcRecordPacket *)(message + 1);
-    size = message->size - sizeof(*packet);
+    packet = (SpiceMsgcRecordPacket *)message;
+    size = size - sizeof(*packet);
 
     if (record_channel->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) {
         int celt_err = celt051_decode(record_channel->celt_decoder, packet->data, size,
@@ -316,34 +317,34 @@ static int snd_record_handle_write(RecordChannel *record_channel, SpiceDataHeade
     return TRUE;
 }
 
-static int snd_playback_handle_message(SndChannel *channel, SpiceDataHeader *message)
+static int snd_playback_handle_message(SndChannel *channel, size_t size, uint32_t type, void *message)
 {
     if (!channel) {
         return FALSE;
     }
 
-    switch (message->type) {
+    switch (type) {
     case SPICE_MSGC_DISCONNECTING:
         break;
     default:
-        red_printf("invalid message type %u", message->type);
+        red_printf("invalid message type %u", type);
         return FALSE;
     }
     return TRUE;
 }
 
-static int snd_record_handle_message(SndChannel *channel, SpiceDataHeader *message)
+static int snd_record_handle_message(SndChannel *channel, size_t size, uint32_t type, void *message)
 {
     RecordChannel *record_channel = (RecordChannel *)channel;
 
     if (!channel) {
         return FALSE;
     }
-    switch (message->type) {
+    switch (type) {
     case SPICE_MSGC_RECORD_DATA:
-        return snd_record_handle_write((RecordChannel *)channel, message);
+        return snd_record_handle_write((RecordChannel *)channel, size, message);
     case SPICE_MSGC_RECORD_MODE: {
-        SpiceMsgcRecordMode *mode = (SpiceMsgcRecordMode *)(message + 1);
+        SpiceMsgcRecordMode *mode = (SpiceMsgcRecordMode *)message;
         record_channel->mode = mode->mode;
         record_channel->mode_time = mode->time;
         if (record_channel->mode != SPICE_AUDIO_DATA_MODE_CELT_0_5_1 &&
@@ -353,14 +354,14 @@ static int snd_record_handle_message(SndChannel *channel, SpiceDataHeader *messa
         break;
     }
     case SPICE_MSGC_RECORD_START_MARK: {
-        SpiceMsgcRecordStartMark *mark = (SpiceMsgcRecordStartMark *)(message + 1);
+        SpiceMsgcRecordStartMark *mark = (SpiceMsgcRecordStartMark *)message;
         record_channel->start_time = mark->time;
         break;
     }
     case SPICE_MSGC_DISCONNECTING:
         break;
     case SPICE_MSGC_MIGRATE_DATA: {
-        RecordMigrateData* mig_data = (RecordMigrateData *)(message + 1);
+        RecordMigrateData* mig_data = (RecordMigrateData *)message;
         if (mig_data->version != RECORD_MIG_VERSION) {
             red_printf("invalid mig version");
             break;
@@ -371,7 +372,7 @@ static int snd_record_handle_message(SndChannel *channel, SpiceDataHeader *messa
         break;
     }
     default:
-        red_printf("invalid message type %u", message->type);
+        red_printf("invalid message type %u", type);
         return FALSE;
     }
     return TRUE;
@@ -410,18 +411,31 @@ static void snd_receive(void* data)
         } else {
             channel->recive_data.now += n;
             for (;;) {
-                SpiceDataHeader *message = channel->recive_data.message;
-                n = channel->recive_data.now - (uint8_t *)message;
-                if (n < sizeof(SpiceDataHeader) || n < sizeof(SpiceDataHeader) + message->size) {
+                SpiceDataHeader *header = channel->recive_data.message;
+                uint8_t *data = (uint8_t *)(header+1);
+                size_t parsed_size;
+                uint8_t *parsed;
+
+                n = channel->recive_data.now - (uint8_t *)header;
+                if (n < sizeof(SpiceDataHeader) || n < sizeof(SpiceDataHeader) + header->size) {
                     break;
                 }
-                if (!channel->handle_message(channel, message)) {
+                parsed = channel->parser((void *)data, data + header->size, header->type,
+                                         SPICE_VERSION_MINOR, &parsed_size);
+                if (parsed == NULL) {
+                    red_printf("failed to parse message type %d", header->type);
+                    snd_disconnect_channel(channel);
+                    return;
+                }
+                if (!channel->handle_message(channel, parsed_size, header->type, parsed)) {
+                    free(parsed);
                     snd_disconnect_channel(channel);
                     return;
                 }
-                channel->recive_data.message = (SpiceDataHeader *)((uint8_t *)message +
+                free(parsed);
+                channel->recive_data.message = (SpiceDataHeader *)((uint8_t *)header +
                                                                  sizeof(SpiceDataHeader) +
-                                                                 message->size);
+                                                                 header->size);
             }
             if (channel->recive_data.now == (uint8_t *)channel->recive_data.message) {
                 channel->recive_data.now = channel->recive_data.buf;
@@ -718,7 +732,8 @@ static void snd_record_send(void* data)
     }
 }
 
-static SndChannel *__new_channel(SndWorker *worker, int size, RedsStreamContext *peer,
+static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_id,
+                                 RedsStreamContext *peer,
                                  int migrate, send_messages_proc send_messages,
                                  handle_message_proc handle_message,
                                  on_message_done_proc on_message_done,
@@ -758,6 +773,7 @@ static SndChannel *__new_channel(SndWorker *worker, int size, RedsStreamContext
 
     ASSERT(size >= sizeof(*channel));
     channel = spice_malloc0(size);
+    channel->parser = spice_get_client_channel_parser(channel_id, NULL);
     channel->peer = peer;
     channel->worker = worker;
     channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
@@ -941,6 +957,7 @@ static void snd_set_playback_peer(Channel *channel, RedsStreamContext *peer, int
 
     if (!(playback_channel = (PlaybackChannel *)__new_channel(worker,
                                                               sizeof(*playback_channel),
+                                                              SPICE_CHANNEL_PLAYBACK,
                                                               peer,
                                                               migration,
                                                               snd_playback_send,
@@ -1106,6 +1123,7 @@ static void snd_set_record_peer(Channel *channel, RedsStreamContext *peer, int m
 
     if (!(record_channel = (RecordChannel *)__new_channel(worker,
                                                           sizeof(*record_channel),
+                                                          SPICE_CHANNEL_RECORD,
                                                           peer,
                                                           migration,
                                                           snd_record_send,
commit ec10a1662fb8b7c0f9ba8c26c506028a6b21ee44
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Jun 17 11:20:22 2010 +0200

    Generate demarshallers on server side

diff --git a/server/Makefile.am b/server/Makefile.am
index 7cd9218..8d507a4 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -18,7 +18,10 @@ INCLUDES = \
 	$(VISIBILITY_HIDDEN_CFLAGS)		\
 	$(NULL)
 
-spice_built_sources = generated_marshallers.c generated_marshallers.h
+spice_built_sources = generated_marshallers.c generated_marshallers.h generated_demarshallers.c
+
+generated_demarshallers.c: $(top_srcdir)/spice.proto
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --server --include red_common.h $(top_srcdir)/spice.proto generated_demarshallers.c
 
 STRUCTS=-M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlnd -M PathSegment
 generated_marshallers.c: $(top_srcdir)/spice.proto
@@ -99,6 +102,7 @@ libspice_server_la_SOURCES =			\
 	red_channel.c				\
 	spice.h					\
 	spice-experimental.h			\
+	generated_demarshallers.c		\
 	generated_marshallers.c			\
 	generated_marshallers.h			\
 	$(TUNNEL_SRCS)				\
commit 4e44b7cf95421ebdf9890653cf7b110fad340f3a
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Jun 17 11:19:31 2010 +0200

    Make tunnel_service_add members be of cstring array size

diff --git a/spice.proto b/spice.proto
index d41137f..093c808 100644
--- a/spice.proto
+++ b/spice.proto
@@ -1031,8 +1031,8 @@ channel TunnelChannel : BaseChannel {
 	uint32 id;
 	uint32 group;
 	uint32 port;
-	uint8 *name[] @ptr32;
-	uint8 *description[] @ptr32;
+	uint8 *name[cstring()] @ptr32 @nocopy;
+	uint8 *description[cstring()] @ptr32 @nocopy;
 	switch (type) {
 	case IPP:
 	    TunnelIpInfo ip @ctype(SpiceMsgTunnelIpInfo);
commit ee91ed475dc5b9ea8f5ee05faa3dd153306e3471
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Jun 17 10:15:15 2010 +0200

    Switch client to use generated marshallers

diff --git a/client/Makefile.am b/client/Makefile.am
index fa7dbb6..f140203 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -36,6 +36,7 @@ RED_COMMON_SRCS =			\
 	common.h			\
 	demarshallers.h			\
 	generated_demarshallers.cpp	\
+	marshaller.cpp			\
 	generated_marshallers.cpp	\
 	generated_marshallers.h		\
 	cursor_channel.cpp		\
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 9cc5550..5286aed 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -42,6 +42,7 @@
 #include "inputs_channel.h"
 #include "cursor_channel.h"
 #include "mjpeg_decoder.h"
+#include "generated_marshallers.h"
 
 class CreatePrimarySurfaceEvent: public SyncEvent {
 public:
@@ -1022,12 +1023,13 @@ private:
 
 void DisplayChannel::on_connect()
 {
-    Message* message = new Message(SPICE_MSGC_DISPLAY_INIT, sizeof(SpiceMsgcDisplayInit));
-    SpiceMsgcDisplayInit* init = (SpiceMsgcDisplayInit*)message->data();
-    init->pixmap_cache_id = 1;
-    init->pixmap_cache_size = get_client().get_pixmap_cache_size();
-    init->glz_dictionary_id = 1;
-    init->glz_dictionary_window_size = get_client().get_glz_window_size();
+    Message* message = new Message(SPICE_MSGC_DISPLAY_INIT);
+    SpiceMsgcDisplayInit init;
+    init.pixmap_cache_id = 1;
+    init.pixmap_cache_size = get_client().get_pixmap_cache_size();
+    init.glz_dictionary_id = 1;
+    init.glz_dictionary_window_size = get_client().get_glz_window_size();
+    spice_marshall_msgc_display_init(message->marshaller(), &init);
     post_message(message);
     AutoRef<AttachChannelsEvent> attach_channels(new AttachChannelsEvent(*this));
     get_client().push_event(*attach_channels);
diff --git a/client/inputs_channel.cpp b/client/inputs_channel.cpp
index 4e99563..6fd0b4f 100644
--- a/client/inputs_channel.cpp
+++ b/client/inputs_channel.cpp
@@ -22,6 +22,7 @@
 #include "red_client.h"
 #include "application.h"
 #include "display_channel.h"
+#include "generated_marshallers.h"
 
 #define SYNC_REMOTH_MODIFIRES
 
@@ -114,7 +115,7 @@ private:
 
 MotionMessage::MotionMessage(InputsChannel& channel)
     : RedChannel::OutMessage()
-    , RedPeer::OutMessage(SPICE_MSGC_INPUTS_MOUSE_MOTION, sizeof(SpiceMsgcMouseMotion))
+    , RedPeer::OutMessage(SPICE_MSGC_INPUTS_MOUSE_MOTION)
     , _channel (channel)
 {
 }
@@ -126,7 +127,11 @@ void MotionMessage::release()
 
 RedPeer::OutMessage& MotionMessage::peer_message()
 {
-    _channel.set_motion_event(*(SpiceMsgcMouseMotion*)data());
+    SpiceMsgcMouseMotion motion;
+
+    _channel.set_motion_event(motion);
+    spice_marshall_msgc_inputs_mouse_motion(_marshaller, &motion);
+
     return *this;
 }
 
@@ -142,7 +147,7 @@ private:
 
 PositionMessage::PositionMessage(InputsChannel& channel)
     : RedChannel::OutMessage()
-    , RedPeer::OutMessage(SPICE_MSGC_INPUTS_MOUSE_POSITION, sizeof(SpiceMsgcMousePosition))
+    , RedPeer::OutMessage(SPICE_MSGC_INPUTS_MOUSE_POSITION)
     , _channel (channel)
 {
 }
@@ -154,7 +159,9 @@ void PositionMessage::release()
 
 RedPeer::OutMessage& PositionMessage::peer_message()
 {
-    _channel.set_position_event(*(SpiceMsgcMousePosition*)data());
+    SpiceMsgcMousePosition pos;
+    _channel.set_position_event(pos);
+    spice_marshall_msgc_inputs_mouse_position(_marshaller, &pos);
     return *this;
 }
 
@@ -311,10 +318,12 @@ void InputsChannel::on_mouse_down(int button, int buttons_state)
 {
     Message* message;
 
-    message = new Message(SPICE_MSGC_INPUTS_MOUSE_PRESS, sizeof(SpiceMsgcMouseRelease));
-    SpiceMsgcMousePress* event = (SpiceMsgcMousePress*)message->data();
-    event->button = button;
-    event->buttons_state = buttons_state;
+    message = new Message(SPICE_MSGC_INPUTS_MOUSE_PRESS);
+    SpiceMsgcMousePress event;
+    event.button = button;
+    event.buttons_state = buttons_state;
+    spice_marshall_msgc_inputs_mouse_press(message->marshaller(), &event);
+
     post_message(message);
 }
 
@@ -322,10 +331,11 @@ void InputsChannel::on_mouse_up(int button, int buttons_state)
 {
     Message* message;
 
-    message = new Message(SPICE_MSGC_INPUTS_MOUSE_RELEASE, sizeof(SpiceMsgcMouseRelease));
-    SpiceMsgcMouseRelease* event = (SpiceMsgcMouseRelease*)message->data();
-    event->button = button;
-    event->buttons_state = buttons_state;
+    message = new Message(SPICE_MSGC_INPUTS_MOUSE_RELEASE);
+    SpiceMsgcMouseRelease event;
+    event.button = button;
+    event.buttons_state = buttons_state;
+    spice_marshall_msgc_inputs_mouse_release(message->marshaller(), &event);
     post_message(message);
 }
 
@@ -349,9 +359,11 @@ void InputsChannel::on_key_down(RedKey key)
         return;
     }
 
-    Message* message = new Message(SPICE_MSGC_INPUTS_KEY_DOWN, sizeof(SpiceMsgcKeyDown));
-    SpiceMsgcKeyDown* event = (SpiceMsgcKeyDown*)message->data();
-    event->code = scan_code;
+    Message* message = new Message(SPICE_MSGC_INPUTS_KEY_DOWN);
+    SpiceMsgcKeyDown event;
+    event.code = scan_code;
+    spice_marshall_msgc_inputs_key_down(message->marshaller(), &event);
+
     post_message(message);
 }
 
@@ -363,9 +375,10 @@ void InputsChannel::on_key_up(RedKey key)
         return;
     }
 
-    Message* message = new Message(SPICE_MSGC_INPUTS_KEY_UP, sizeof(SpiceMsgcKeyUp));
-    SpiceMsgcKeyUp* event = (SpiceMsgcKeyUp*)message->data();
-    event->code = scan_code;
+    Message* message = new Message(SPICE_MSGC_INPUTS_KEY_UP);
+    SpiceMsgcKeyUp event;
+    event.code = scan_code;
+    spice_marshall_msgc_inputs_key_up(message->marshaller(), &event);
     post_message(message);
 }
 
@@ -391,9 +404,10 @@ void InputsChannel::set_local_modifiers()
 void InputsChannel::on_focus_in()
 {
 #ifdef SYNC_REMOTH_MODIFIRES
-    Message* message = new Message(SPICE_MSGC_INPUTS_KEY_MODIFIERS, sizeof(SpiceMsgcKeyDown));
-    SpiceMsgcKeyModifiers* modifiers = (SpiceMsgcKeyModifiers*)message->data();
-    modifiers->modifiers = Platform::get_keyboard_lock_modifiers();
+    Message* message = new Message(SPICE_MSGC_INPUTS_KEY_MODIFIERS);
+    SpiceMsgcKeyModifiers modifiers;
+    modifiers.modifiers = Platform::get_keyboard_lock_modifiers();
+    spice_marshall_msgc_inputs_key_modifiers(message->marshaller(), &modifiers);
     post_message(message);
 #else
     set_local_modifiers();
diff --git a/client/record_channel.cpp b/client/record_channel.cpp
index a48df60..155e8d9 100644
--- a/client/record_channel.cpp
+++ b/client/record_channel.cpp
@@ -19,6 +19,7 @@
 #include "red_client.h"
 #include "audio_channels.h"
 #include "audio_devices.h"
+#include "generated_marshallers.h"
 
 #define NUM_SAMPLES_MESSAGES 4
 
@@ -33,23 +34,23 @@ public:
     RecordSamplesMessage(RecordChannel& channel);
     virtual ~RecordSamplesMessage();
 
-    virtual RedPeer::OutMessage& peer_message() { return *_massage;}
+    virtual RedPeer::OutMessage& peer_message() { return *_message;}
     virtual void release();
 
 private:
     RecordChannel& _channel;
-    RedPeer::OutMessage *_massage;
+    RedPeer::OutMessage *_message;
 };
 
 RecordSamplesMessage::RecordSamplesMessage(RecordChannel& channel)
     : _channel (channel)
-    , _massage (new Message(SPICE_MSGC_RECORD_DATA, sizeof(SpiceMsgcRecordPacket) + 4096))
+    , _message (new Message(SPICE_MSGC_RECORD_DATA))
 {
 }
 
 RecordSamplesMessage::~RecordSamplesMessage()
 {
-    delete _massage;
+    delete _message;
 }
 
 void RecordSamplesMessage::release()
@@ -115,19 +116,22 @@ bool RecordChannel::abort(void)
 
 void RecordChannel::on_connect()
 {
-    Message* message = new Message(SPICE_MSGC_RECORD_MODE, sizeof(SpiceMsgcRecordMode));
-    SpiceMsgcRecordMode *mode = (SpiceMsgcRecordMode *)message->data();
-    mode->time = get_mm_time();
-    mode->mode = _mode = test_capability(SPICE_RECORD_CAP_CELT_0_5_1) ? RecordChannel::data_mode :
+    Message* message = new Message(SPICE_MSGC_RECORD_MODE);
+    SpiceMsgcRecordMode mode;
+    mode.time = get_mm_time();
+    mode.mode = _mode =
+      test_capability(SPICE_RECORD_CAP_CELT_0_5_1) ? RecordChannel::data_mode :
                                                                       SPICE_AUDIO_DATA_MODE_RAW;
+    spice_marshall_msgc_record_mode(message->marshaller(), &mode);
     post_message(message);
 }
 
 void RecordChannel::send_start_mark()
 {
-    Message* message = new Message(SPICE_MSGC_RECORD_START_MARK, sizeof(SpiceMsgcRecordStartMark));
-    SpiceMsgcRecordStartMark *start_mark = (SpiceMsgcRecordStartMark *)message->data();
-    start_mark->time = get_mm_time();
+    Message* message = new Message(SPICE_MSGC_RECORD_START_MARK);
+    SpiceMsgcRecordStartMark start_mark;
+    start_mark.time = get_mm_time();
+    spice_marshall_msgc_record_start_mark(message->marshaller(), &start_mark);
     post_message(message);
 }
 
@@ -253,10 +257,11 @@ void RecordChannel::push_frame(uint8_t *frame)
         n = _frame_bytes;
     }
     RedPeer::OutMessage& peer_message = message->peer_message();
-    peer_message.resize(n + sizeof(SpiceMsgcRecordPacket));
-    SpiceMsgcRecordPacket* packet = (SpiceMsgcRecordPacket*)peer_message.data();
-    packet->time = get_mm_time();
-    memcpy(packet->data, frame, n);
+    peer_message.reset(SPICE_MSGC_RECORD_DATA);
+    SpiceMsgcRecordPacket packet;
+    packet.time = get_mm_time();
+    spice_marshall_msgc_record_data(peer_message.marshaller(), &packet);
+    spice_marshaller_add(peer_message.marshaller(), frame, n);
     post_message(message);
 }
 
diff --git a/client/red_channel.cpp b/client/red_channel.cpp
index 475cec4..7065b0a 100644
--- a/client/red_channel.cpp
+++ b/client/red_channel.cpp
@@ -21,6 +21,7 @@
 #include "application.h"
 #include "debug.h"
 #include "utils.h"
+#include "generated_marshallers.h"
 
 #include "openssl/rsa.h"
 #include "openssl/evp.h"
@@ -507,7 +508,7 @@ void RedChannel::on_send_trigger()
 void RedChannel::on_message_recived()
 {
     if (_message_ack_count && !--_message_ack_count) {
-        post_message(new Message(SPICE_MSGC_ACK, 0));
+        post_message(new Message(SPICE_MSGC_ACK));
         _message_ack_count = _message_ack_window;
     }
 }
@@ -547,8 +548,8 @@ void RedChannel::on_event()
 {
     if (_outgoing_message) {
         RedPeer::OutMessage& peer_message = _outgoing_message->peer_message();
-        _outgoing_pos += send(peer_message.base() + _outgoing_pos,
-                              peer_message.message_size() - _outgoing_pos);
+
+        _outgoing_pos += do_send(peer_message,  _outgoing_pos);
         if (_outgoing_pos == peer_message.message_size()) {
             _outgoing_message->release();
             _outgoing_message = NULL;
@@ -592,7 +593,7 @@ void RedChannel::send_migrate_flush_mark()
 {
     if (_outgoing_message) {
         RedPeer::OutMessage& peer_message = _outgoing_message->peer_message();
-        send(peer_message.base() + _outgoing_pos, peer_message.message_size() - _outgoing_pos);
+        do_send(peer_message, _outgoing_pos);
         _outgoing_message->release();
         _outgoing_message = NULL;
     }
@@ -605,7 +606,7 @@ void RedChannel::send_migrate_flush_mark()
         send(message.get()->peer_message());
     }
     lock.unlock();
-    std::auto_ptr<RedPeer::OutMessage> message(new RedPeer::OutMessage(SPICE_MSGC_MIGRATE_FLUSH_MARK, 0));
+    std::auto_ptr<RedPeer::OutMessage> message(new RedPeer::OutMessage(SPICE_MSGC_MIGRATE_FLUSH_MARK));
     send(*message);
 }
 
@@ -627,9 +628,8 @@ void RedChannel::handle_migrate(RedPeer::InMessage* message)
         if ((*data_message)->type() != SPICE_MSG_MIGRATE_DATA) {
             THROW("expect SPICE_MSG_MIGRATE_DATA");
         }
-        std::auto_ptr<RedPeer::OutMessage> message(new RedPeer::OutMessage(SPICE_MSGC_MIGRATE_DATA,
-                                                                          (*data_message)->size()));
-        memcpy(message->data(), (*data_message)->data(), (*data_message)->size());
+        std::auto_ptr<RedPeer::OutMessage> message(new RedPeer::OutMessage(SPICE_MSGC_MIGRATE_DATA));
+	spice_marshaller_add(message->marshaller(), (*data_message)->data(), (*data_message)->size());
         send(*message);
     }
     _loop.add_socket(*this);
@@ -643,16 +643,18 @@ void RedChannel::handle_set_ack(RedPeer::InMessage* message)
 {
     SpiceMsgSetAck* ack = (SpiceMsgSetAck*)message->data();
     _message_ack_window = _message_ack_count = ack->window;
-    Message *responce = new Message(SPICE_MSGC_ACK_SYNC, sizeof(uint32_t));
-    *(uint32_t *)responce->data() = ack->generation;
-    post_message(responce);
+    Message *response = new Message(SPICE_MSGC_ACK_SYNC);
+    SpiceMsgcAckSync sync;
+    sync.generation = ack->generation;
+    spice_marshall_msgc_ack_sync(response->marshaller(), &sync);
+    post_message(response);
 }
 
 void RedChannel::handle_ping(RedPeer::InMessage* message)
 {
     SpiceMsgPing *ping = (SpiceMsgPing *)message->data();
-    Message *pong = new Message(SPICE_MSGC_PONG, sizeof(SpiceMsgPing));
-    *(SpiceMsgPing *)pong->data() = *ping;
+    Message *pong = new Message(SPICE_MSGC_PONG);
+    spice_marshall_msgc_pong(pong->marshaller(), ping);
     post_message(pong);
 }
 
diff --git a/client/red_channel.h b/client/red_channel.h
index 8d6b62f..a9d3ee5 100644
--- a/client/red_channel.h
+++ b/client/red_channel.h
@@ -212,9 +212,9 @@ public:
 
 class Message: public RedChannel::OutMessage, public RedPeer::OutMessage {
 public:
-    Message(uint32_t type, uint32_t size)
+    Message(uint32_t type)
         : RedChannel::OutMessage()
-        , RedPeer::OutMessage(type, size)
+        , RedPeer::OutMessage(type)
     {
     }
 
diff --git a/client/red_client.cpp b/client/red_client.cpp
index 8778eeb..c079f3d 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -22,6 +22,7 @@
 #include "process_loop.h"
 #include "utils.h"
 #include "debug.h"
+#include "generated_marshallers.h"
 
 #ifdef __GNUC__
 typedef struct __attribute__ ((__packed__)) OldRedMigrationBegin {
@@ -190,10 +191,10 @@ void Migrate::run()
     Lock lock(_lock);
     _cond.notify_one();
     if (_connected) {
-        Message* message = new Message(SPICE_MSGC_MAIN_MIGRATE_CONNECTED, 0);
+        Message* message = new Message(SPICE_MSGC_MAIN_MIGRATE_CONNECTED);
         _client.post_message(message);
     } else {
-        Message* message = new Message(SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR, 0);
+        Message* message = new Message(SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR);
         _client.post_message(message);
     }
     _running = false;
@@ -593,16 +594,17 @@ void RedClient::send_agent_monitors_config()
         }
     }
 
-    Message* message = new Message(SPICE_MSGC_MAIN_AGENT_DATA,sizeof(VDAgentMessage) +
-                                   sizeof(VDAgentMonitorsConfig) +
-                                   monitors.size() * sizeof(VDAgentMonConfig));
-    VDAgentMessage* msg = (VDAgentMessage*)message->data();
+    Message* message = new Message(SPICE_MSGC_MAIN_AGENT_DATA);
+    VDAgentMessage* msg = (VDAgentMessage*)
+      spice_marshaller_reserve_space(message->marshaller(), sizeof(VDAgentMessage));
     msg->protocol = VD_AGENT_PROTOCOL;
     msg->type = VD_AGENT_MONITORS_CONFIG;
     msg->opaque = 0;
     msg->size = sizeof(VDAgentMonitorsConfig) + monitors.size() * sizeof(VDAgentMonConfig);
 
-    VDAgentMonitorsConfig* mon_config = (VDAgentMonitorsConfig*)msg->data;
+    VDAgentMonitorsConfig* mon_config = (VDAgentMonitorsConfig*)
+      spice_marshaller_reserve_space(message->marshaller(),
+				     sizeof(VDAgentMonitorsConfig) + monitors.size() * sizeof(VDAgentMonConfig));
     mon_config->num_of_monitors = monitors.size();
     mon_config->flags = 0;
     if (Platform::is_monitors_pos_valid()) {
@@ -696,9 +698,12 @@ void RedClient::set_mouse_mode(uint32_t supported_modes, uint32_t current_mode)
     }
     // FIXME: use configured mouse mode (currently, use client mouse mode if supported by server)
     if ((supported_modes & SPICE_MOUSE_MODE_CLIENT) && (current_mode != SPICE_MOUSE_MODE_CLIENT)) {
-        Message* message = new Message(SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, sizeof(SpiceMsgcMainMouseModeRequest));
-        SpiceMsgcMainMouseModeRequest* mouse_mode_request = (SpiceMsgcMainMouseModeRequest*)message->data();
-        mouse_mode_request->mode = SPICE_MOUSE_MODE_CLIENT;
+        Message* message = new Message(SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST);
+        SpiceMsgcMainMouseModeRequest mouse_mode_request;
+        mouse_mode_request.mode = SPICE_MOUSE_MODE_CLIENT;
+	spice_marshall_msgc_main_mouse_mode_request(message->marshaller(),
+						    &mouse_mode_request);
+
         post_message(message);
     }
 }
@@ -714,9 +719,10 @@ void RedClient::handle_init(RedPeer::InMessage* message)
     _agent_tokens = init->agent_tokens;
     _agent_connected = !!init->agent_connected;
     if (_agent_connected) {
-        Message* msg = new Message(SPICE_MSGC_MAIN_AGENT_START, sizeof(SpiceMsgcMainAgentStart));
-        SpiceMsgcMainAgentStart* agent_start = (SpiceMsgcMainAgentStart *)msg->data();
-        agent_start->num_tokens = ~0;
+        Message* msg = new Message(SPICE_MSGC_MAIN_AGENT_START);
+        SpiceMsgcMainAgentStart agent_start;
+        agent_start.num_tokens = ~0;
+	spice_marshall_msgc_main_agent_start(msg->marshaller(), &agent_start);
         post_message(msg);
     }
     if (_auto_display_res) {
@@ -725,7 +731,7 @@ void RedClient::handle_init(RedPeer::InMessage* message)
             send_agent_monitors_config();
         }
     } else {
-        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS, 0));
+        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
     }
 }
 
@@ -754,9 +760,10 @@ void RedClient::handle_agent_connected(RedPeer::InMessage* message)
 {
     DBG(0, "");
     _agent_connected = true;
-    Message* msg = new Message(SPICE_MSGC_MAIN_AGENT_START, sizeof(SpiceMsgcMainAgentStart));
-    SpiceMsgcMainAgentStart* agent_start = (SpiceMsgcMainAgentStart *)msg->data();
-    agent_start->num_tokens = ~0;
+    Message* msg = new Message(SPICE_MSGC_MAIN_AGENT_START);
+    SpiceMsgcMainAgentStart agent_start;
+    agent_start.num_tokens = ~0;
+    spice_marshall_msgc_main_agent_start(msg->marshaller(), &agent_start);
     post_message(msg);
     if (_auto_display_res && !_agent_mon_config_sent) {
         send_agent_monitors_config();
@@ -781,7 +788,7 @@ void RedClient::on_agent_reply(VDAgentReply* reply)
     }
     switch (reply->type) {
     case VD_AGENT_MONITORS_CONFIG:
-        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS, 0));
+        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
         _application.deactivate_interval_timer(*_agent_timer);
         break;
     default:
diff --git a/client/red_peer.cpp b/client/red_peer.cpp
index be18dfb..9a608ad 100644
--- a/client/red_peer.cpp
+++ b/client/red_peer.cpp
@@ -726,38 +726,59 @@ uint32_t RedPeer::send(uint8_t *buf, uint32_t size)
     return pos - buf;
 }
 
+uint32_t RedPeer::do_send(RedPeer::OutMessage& message, uint32_t skip_bytes)
+{
+    uint8_t *data;
+    int free_data;
+    size_t len;
+    uint32_t res;
+
+    data = spice_marshaller_linearize(message.marshaller(), skip_bytes,
+                                      &len, &free_data);
+
+    res = send(data, len);
+
+    if (free_data) {
+        free(data);
+    }
+    return res;
+}
+
 uint32_t RedPeer::send(RedPeer::OutMessage& message)
 {
+
     message.header().serial = ++_serial;
-    return send(message.base(), message.message_size());
+    message.header().size = message.message_size() - sizeof(SpiceDataHeader);
+
+    return do_send(message, 0);
 }
 
-RedPeer::OutMessage::OutMessage(uint32_t type, uint32_t size)
-    : _data (new uint8_t[size + sizeof(SpiceDataHeader)])
-    , _size (size)
+RedPeer::OutMessage::OutMessage(uint32_t type)
+    : _marshaller (spice_marshaller_new())
 {
-    header().type = type;
-    header().size = size;
+    SpiceDataHeader *header;
+    header = (SpiceDataHeader *)
+        spice_marshaller_reserve_space(_marshaller, sizeof(SpiceDataHeader));
+    spice_marshaller_set_base(_marshaller, sizeof(SpiceDataHeader));
+
+    header->type = type;
+    header->sub_list = 0;
 }
 
-RedPeer::OutMessage::~OutMessage()
+void RedPeer::OutMessage::reset(uint32_t type)
 {
-    delete[] _data;
+    spice_marshaller_reset(_marshaller);
+
+    SpiceDataHeader *header;
+    header = (SpiceDataHeader *)
+        spice_marshaller_reserve_space(_marshaller, sizeof(SpiceDataHeader));
+    spice_marshaller_set_base(_marshaller, sizeof(SpiceDataHeader));
+
+    header->type = type;
+    header->sub_list = 0;
 }
 
-void RedPeer::OutMessage::resize(uint32_t size)
+RedPeer::OutMessage::~OutMessage()
 {
-    if (size <= _size) {
-        header().size = size;
-        return;
-    }
-    uint32_t type = header().type;
-    delete[] _data;
-    _data = NULL;
-    _size = 0;
-    _data = new uint8_t[size + sizeof(SpiceDataHeader)];
-    _size = size;
-    header().type = type;
-    header().size = size;
+    spice_marshaller_destroy(_marshaller);
 }
-
diff --git a/client/red_peer.h b/client/red_peer.h
index f24e5e7..001f9fa 100644
--- a/client/red_peer.h
+++ b/client/red_peer.h
@@ -26,6 +26,7 @@
 #include "process_loop.h"
 #include "threads.h"
 #include "platform_utils.h"
+#include "marshaller.h"
 
 class RedPeer: protected EventSources::Socket {
 public:
@@ -111,6 +112,7 @@ public:
     void enable() { _shut = false;}
 
     virtual CompundInMessage* recive();
+    uint32_t do_send(OutMessage& message, uint32_t skip_bytes);
     uint32_t send(OutMessage& message);
 
     uint32_t recive(uint8_t* buf, uint32_t size);
@@ -194,20 +196,19 @@ private:
 
 class RedPeer::OutMessage {
 public:
-    OutMessage(uint32_t type, uint32_t size);
+    OutMessage(uint32_t type);
     virtual ~OutMessage();
 
-    SpiceDataHeader& header() { return *(SpiceDataHeader *)_data;}
-    uint8_t* data() { return _data + sizeof(SpiceDataHeader);}
-    void resize(uint32_t size);
+    SpiceMarshaller *marshaller() { return _marshaller;}
+    void reset(uint32_t type);
 
 private:
-    uint32_t message_size() { return header().size + sizeof(SpiceDataHeader);}
-    uint8_t* base() { return _data;}
+    uint32_t message_size() { return spice_marshaller_get_total_size(_marshaller);}
+    uint8_t* base() { return spice_marshaller_get_ptr(_marshaller);}
+    SpiceDataHeader& header() { return *(SpiceDataHeader *)base();}
 
-private:
-    uint8_t* _data;
-    uint32_t _size;
+protected:
+    SpiceMarshaller *_marshaller;
 
     friend class RedPeer;
     friend class RedChannel;
diff --git a/client/tunnel_channel.cpp b/client/tunnel_channel.cpp
index cecd9ba..1464b1d 100644
--- a/client/tunnel_channel.cpp
+++ b/client/tunnel_channel.cpp
@@ -21,6 +21,7 @@
 
 #include "common.h"
 #include "tunnel_channel.h"
+#include "generated_marshallers.h"
 #include <spice/protocol.h>
 
 #define SOCKET_WINDOW_SIZE 60
@@ -93,13 +94,13 @@ public:
     virtual RedPeer::OutMessage& peer_message() { return *this;}
     virtual void release();
 
-    virtual uint8_t* buf();
+    virtual uint8_t* buf() { return _the_buf; };
     virtual uint32_t buf_max_size() {return _max_data_size;}
     virtual void set_buf_size(uint32_t size);
     virtual void release_buf();
 
     static void init(uint32_t max_data_size);
-    static OutSocketMessage& alloc_message();
+    static OutSocketMessage& alloc_message(uint16_t id);
     static void clear_free_messages();
 
 protected:
@@ -109,26 +110,22 @@ protected:
 private:
     static std::list<OutSocketMessage*> _free_messages;
     static uint32_t _max_data_size;
+    uint8_t *_the_buf;
 };
 
 std::list<OutSocketMessage*> OutSocketMessage::_free_messages;
 uint32_t OutSocketMessage::_max_data_size;
 
 OutSocketMessage::OutSocketMessage()
-    : RedPeer::OutMessage(SPICE_MSGC_TUNNEL_SOCKET_DATA, sizeof(SpiceMsgcTunnelSocketData) + _max_data_size)
+    : RedPeer::OutMessage(SPICE_MSGC_TUNNEL_SOCKET_DATA)
     , RedChannel::OutMessage()
     , ClientNetSocket::ReceiveBuffer()
 {
 }
 
-uint8_t* OutSocketMessage::buf()
-{
-    return ((SpiceMsgcTunnelSocketData*)RedPeer::OutMessage::data())->data;
-}
-
 void OutSocketMessage::set_buf_size(uint32_t size)
 {
-    RedPeer::OutMessage::header().size = size + sizeof(SpiceMsgcTunnelSocketData);
+    spice_marshaller_unreserve_space(_marshaller, _max_data_size - size);
 }
 
 void OutSocketMessage::release()
@@ -146,16 +143,22 @@ void OutSocketMessage::init(uint32_t max_data_size)
     _max_data_size = max_data_size;
 }
 
-OutSocketMessage& OutSocketMessage::alloc_message()
+OutSocketMessage& OutSocketMessage::alloc_message(uint16_t id)
 {
     OutSocketMessage* ret;
     if (!_free_messages.empty()) {
         ret = _free_messages.front();
         _free_messages.pop_front();
+	spice_marshaller_reset(ret->marshaller());
     } else {
         ret = new OutSocketMessage();
     }
 
+    SpiceMsgcTunnelSocketData data;
+    data.connection_id = id;
+    spice_marshall_msgc_tunnel_socket_data(ret->marshaller(), &data);
+    ret->_the_buf = spice_marshaller_reserve_space(ret->marshaller(), _max_data_size);
+
     return *ret;
 }
 
@@ -198,7 +201,7 @@ public:
     bool     get_guest_closed() {return _guest_closed;}
 
 protected:
-    virtual ReceiveBuffer& alloc_receive_buffer() {return OutSocketMessage::alloc_message();}
+    virtual ReceiveBuffer& alloc_receive_buffer() {return OutSocketMessage::alloc_message(id());}
 
 private:
     uint32_t _num_tokens;
@@ -275,45 +278,33 @@ void TunnelChannel::handle_init(RedPeer::InMessage* message)
 
 void TunnelChannel::send_service(TunnelService& service)
 {
-    int msg_size = 0;
-    msg_size += service.name.length() + 1;
-    msg_size += service.description.length() + 1;
-
-    if (service.type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
-        msg_size += sizeof(SpiceMsgcTunnelAddPrintService) + sizeof(SpiceTunnelIPv4);
-    } else if (service.type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
-        msg_size += sizeof(SpiceMsgcTunnelAddGenericService);
-    } else {
+    if (service.type != SPICE_TUNNEL_SERVICE_TYPE_IPP &&
+        service.type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
         THROW("%s: invalid service type", __FUNCTION__);
     }
-    Message* service_msg = new Message(SPICE_MSGC_TUNNEL_SERVICE_ADD, msg_size);
-    SpiceMsgcTunnelAddGenericService* out_service = (SpiceMsgcTunnelAddGenericService*)service_msg->data();
-    out_service->id = service.id;
-    out_service->group = service.group;
-    out_service->type = service.type;
-    out_service->port = service.port;
 
-    int cur_offset;
+    Message* service_msg = new Message(SPICE_MSGC_TUNNEL_SERVICE_ADD);
+    SpiceMsgcTunnelAddPrintService add;
+    SpiceMarshaller *name_out, *description_out;
+    add.base.id = service.id;
+    add.base.group = service.group;
+    add.base.type = service.type;
+    add.base.port = service.port;
+
     if (service.type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
-        cur_offset = sizeof(SpiceMsgcTunnelAddPrintService);
-        ((SpiceMsgcTunnelAddPrintService*)out_service)->ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
-        memcpy(((SpiceMsgcTunnelAddPrintService*)out_service)->ip.data, &(service.ip.s_addr),
-               sizeof(SpiceTunnelIPv4));
-        cur_offset += sizeof(SpiceTunnelIPv4);
-    } else {
-        cur_offset = sizeof(SpiceMsgcTunnelAddGenericService);
+        add.ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
     }
 
-    out_service->name = cur_offset;
-    service.name.copy((char*)(service_msg->data() + cur_offset), service.name.length());
-    (service_msg->data() + cur_offset)[service.name.length()] = '\0';
-    cur_offset += service.name.length() + 1;
+    spice_marshall_msgc_tunnel_service_add(service_msg->marshaller(), &add.base,
+                                           &name_out, &description_out);
 
-    out_service->description = cur_offset;
-    service.description.copy((char*)(service_msg->data() + cur_offset),
-                             service.description.length());
-    (service_msg->data() + cur_offset)[service.description.length()] = '\0';
-    cur_offset += service.description.length() + 1;
+    if (service.type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
+        spice_marshaller_add(service_msg->marshaller(), (uint8_t *)&(service.ip.s_addr),
+                             sizeof(SpiceTunnelIPv4));
+    }
+
+    spice_marshaller_add(name_out, (uint8_t *)service.name.c_str(), service.name.length() + 1);
+    spice_marshaller_add(description_out, (uint8_t *)service.description.c_str(), service.description.length() + 1);
 
     post_message(service_msg);
 }
@@ -361,15 +352,18 @@ void TunnelChannel::handle_socket_open(RedPeer::InMessage* message)
 
     if (sckt->connect(open_msg->tokens)) {
         _sockets[open_msg->connection_id] = sckt;
-        out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK, sizeof(SpiceMsgcTunnelSocketOpenAck));
+        out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK);
         sckt->set_num_tokens(0);
         sckt->set_server_num_tokens(SOCKET_WINDOW_SIZE);
-
-        ((SpiceMsgcTunnelSocketOpenAck*)out_msg->data())->connection_id = open_msg->connection_id;
-        ((SpiceMsgcTunnelSocketOpenAck*)out_msg->data())->tokens = SOCKET_WINDOW_SIZE;
+        SpiceMsgcTunnelSocketOpenAck ack;
+        ack.connection_id = open_msg->connection_id;
+        ack.tokens = SOCKET_WINDOW_SIZE;
+        spice_marshall_msgc_tunnel_socket_open_ack(out_msg->marshaller(), &ack);
     } else {
-        out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK, sizeof(SpiceMsgcTunnelSocketOpenNack));
-        ((SpiceMsgcTunnelSocketOpenNack*)out_msg->data())->connection_id = open_msg->connection_id;
+        out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK);
+        SpiceMsgcTunnelSocketOpenNack nack;
+        nack.connection_id = open_msg->connection_id;
+        spice_marshall_msgc_tunnel_socket_open_nack(out_msg->marshaller(), &nack);
         delete sckt;
     }
 
@@ -480,19 +474,19 @@ void TunnelChannel::handle_socket_token(RedPeer::InMessage* message)
 void TunnelChannel::on_socket_message_recv_done(ClientNetSocket& sckt,
                                                 ClientNetSocket::ReceiveBuffer& buf)
 {
-    TunnelChannel::TunnelSocket* tunnel_sckt = static_cast<TunnelChannel::TunnelSocket*>(&sckt);
     OutSocketMessage* out_msg = static_cast<OutSocketMessage*>(&buf);
 
-    ((SpiceMsgcTunnelSocketData*)(out_msg->data()))->connection_id = tunnel_sckt->id();
     post_message(out_msg);
 }
 
 void TunnelChannel::on_socket_fin_recv(ClientNetSocket& sckt)
 {
     TunnelChannel::TunnelSocket* tunnel_sckt = static_cast<TunnelChannel::TunnelSocket*>(&sckt);
-    Message* out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_FIN, sizeof(SpiceMsgcTunnelSocketFin));
+    Message* out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_FIN);
     DBG(0, "FIN from client coonection id=%d", tunnel_sckt->id());
-    ((SpiceMsgcTunnelSocketFin*)out_msg->data())->connection_id = tunnel_sckt->id();
+    SpiceMsgcTunnelSocketFin fin;
+    fin.connection_id = tunnel_sckt->id();
+    spice_marshall_msgc_tunnel_socket_fin(out_msg->marshaller(), &fin);
     post_message(out_msg);
 }
 
@@ -503,14 +497,18 @@ void TunnelChannel::on_socket_disconnect(ClientNetSocket& sckt)
     // close initiated by server -> needs ack
     if (tunnel_sckt->get_guest_closed()) {
         DBG(0, "send close ack connection_id=%d", tunnel_sckt->id());
-        out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK, sizeof(SpiceMsgcTunnelSocketClosedAck));
-        ((SpiceMsgcTunnelSocketClosedAck*)out_msg->data())->connection_id = tunnel_sckt->id();
+        out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK);
+        SpiceMsgcTunnelSocketClosedAck ack;
+        ack.connection_id = tunnel_sckt->id();
+        spice_marshall_msgc_tunnel_socket_closed_ack(out_msg->marshaller(), &ack);
         _sockets[tunnel_sckt->id()] = NULL;
         delete &sckt;
     } else { // close initiated by client
         DBG(0, "send close coonection_id=%d", tunnel_sckt->id());
-        out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_CLOSED, sizeof(SpiceMsgcTunnelSocketClosed));
-        ((SpiceMsgcTunnelSocketClosed*)out_msg->data())->connection_id = tunnel_sckt->id();
+        out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_CLOSED);
+        SpiceMsgcTunnelSocketClosed closed;
+        closed.connection_id = tunnel_sckt->id();
+        spice_marshall_msgc_tunnel_socket_closed(out_msg->marshaller(), &closed);
     }
 
     post_message(out_msg);
@@ -523,10 +521,11 @@ void TunnelChannel::on_socket_message_send_done(ClientNetSocket& sckt)
     num_tokens++;
 
     if (num_tokens == SOCKET_TOKENS_TO_SEND) {
-        Message* out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_TOKEN, sizeof(SpiceMsgcTunnelSocketTokens));
-        SpiceMsgcTunnelSocketTokens* tokens_msg = (SpiceMsgcTunnelSocketTokens*)out_msg->data();
-        tokens_msg->connection_id = tunnel_sckt->id();
-        tokens_msg->num_tokens = num_tokens;
+        Message* out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_TOKEN);
+        SpiceMsgcTunnelSocketTokens tokens_msg;
+        tokens_msg.connection_id = tunnel_sckt->id();
+        tokens_msg.num_tokens = num_tokens;
+        spice_marshall_msgc_tunnel_socket_token(out_msg->marshaller(), &tokens_msg);
         post_message(out_msg);
 
         tunnel_sckt->set_num_tokens(0);
commit 13026676627887a7d85abb49a0468150ac75ebe6
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Jun 16 10:32:00 2010 +0200

    Generate and link marshallers into client

diff --git a/client/Makefile.am b/client/Makefile.am
index f8ccb98..fa7dbb6 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -3,11 +3,18 @@ NULL =
 SUBDIRS = . $(red_target)
 DIST_SUBDIRS = x11 #windows
 
-spice_built_sources = generated_demarshallers.cpp
+spice_built_sources = generated_demarshallers.cpp generated_marshallers.cpp generated_marshallers.h
 
 generated_demarshallers.cpp: $(top_srcdir)/spice.proto
 	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h $(top_srcdir)/spice.proto generated_demarshallers.cpp
 
+STRUCTS=
+generated_marshallers.cpp: $(top_srcdir)/spice.proto
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --client $(top_srcdir)/spice.proto generated_marshallers.cpp
+
+generated_marshallers.h: $(top_srcdir)/spice.proto
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --client -H $(top_srcdir)/spice.proto generated_marshallers.h
+
 RED_COMMON_SRCS =			\
 	application.cpp			\
 	application.h			\
@@ -29,6 +36,8 @@ RED_COMMON_SRCS =			\
 	common.h			\
 	demarshallers.h			\
 	generated_demarshallers.cpp	\
+	generated_marshallers.cpp	\
+	generated_marshallers.h		\
 	cursor_channel.cpp		\
 	cursor_channel.h		\
 	cursor.cpp			\
diff --git a/client/marshaller.cpp b/client/marshaller.cpp
new file mode 100644
index 0000000..14bd096
--- /dev/null
+++ b/client/marshaller.cpp
@@ -0,0 +1,24 @@
+/*
+   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 "common.h"
+#include "utils.h"
+
+
+#define CANVAS_ERROR(format, ...) THROW(format, ## __VA_ARGS__)
+
+#include "../common/marshaller.c"
diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
index 82a08dd..cbc9c52 100644
--- a/client/x11/Makefile.am
+++ b/client/x11/Makefile.am
@@ -39,6 +39,9 @@ RED_COMMON_SRCS =					\
 	$(CLIENT_DIR)/cache.hpp				\
 	$(CLIENT_DIR)/demarshallers.h			\
 	$(CLIENT_DIR)/generated_demarshallers.cpp	\
+	$(CLIENT_DIR)/marshaller.cpp			\
+	$(CLIENT_DIR)/generated_marshallers.h		\
+	$(CLIENT_DIR)/generated_marshallers.cpp		\
 	$(CLIENT_DIR)/sw_canvas.cpp			\
 	$(CLIENT_DIR)/canvas.cpp			\
 	$(CLIENT_DIR)/canvas.h				\
commit d9772344e60d9930ab35b7e88d4fd491314175d1
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 15 15:43:21 2010 +0200

    Re-enable cache freeing
    
    I don't know why this was disabled but it seems like a bad idea

diff --git a/server/red_worker.c b/server/red_worker.c
index 80abb7c..8b40116 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8382,7 +8382,7 @@ static inline void display_begin_send_massage(DisplayChannel *channel, void *ite
 {
     FreeList *free_list = &channel->send_data.free_list;
 
-    if (0 && free_list->res->count) {
+    if (free_list->res->count) {
         int sub_list_len = 1;
         SpiceMarshaller *wait_m = NULL;
         SpiceMarshaller *inval_m;
commit 04e0c6e5b2027c3457d62380c1433aab6490d7ed
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 15 19:15:27 2010 +0200

    Convert reds.c to use SpiceMarshaller

diff --git a/server/reds.c b/server/reds.c
index ed5d212..fee1cbf 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
@@ -51,6 +52,8 @@
 #include "stat.h"
 #include "ring.h"
 #include "config.h"
+#include "marshaller.h"
+#include "generated_marshallers.h"
 #ifdef HAVE_SLIRP
 #include "red_tunnel_worker.h"
 #endif
@@ -148,14 +151,13 @@ typedef struct MonitorMode {
 typedef struct RedsOutItem RedsOutItem;
 struct RedsOutItem {
     RingItem link;
-    void (*prepare)(RedsOutItem *item, struct iovec* vec, int *len);
-    void (*release)(RedsOutItem *item);
+    SpiceMarshaller *m;
+    SpiceDataHeader *header;
 };
 
 typedef struct VDIReadBuf {
-    RedsOutItem out_item;
+    RingItem link;
     int len;
-    SpiceDataHeader header;
     uint8_t data[SPICE_AGENT_MAX_DATA_SIZE];
 } VDIReadBuf;
 
@@ -353,18 +355,12 @@ struct ChannelSecurityOptions {
     ChannelSecurityOptions *next;
 };
 
-typedef struct PingItem {
-    RedsOutItem base;
-    SpiceDataHeader header;
-    SpiceMsgPing ping;
-    int size;
-} PingItem;
-
 #define ZERO_BUF_SIZE 4096
 
 static uint8_t zero_page[ZERO_BUF_SIZE] = {0};
 
 static void reds_push();
+static void reds_out_item_free(RedsOutItem *item);
 
 static ChannelSecurityOptions *channels_security = NULL;
 static int default_channel_security =
@@ -693,7 +689,7 @@ static void reds_reset_vdp()
     state->recive_len = sizeof(state->vdi_chunk_header);
     state->message_recive_len = 0;
     if (state->current_read_buf) {
-        ring_add(&state->read_bufs, &state->current_read_buf->out_item.link);
+        ring_add(&state->read_bufs, &state->current_read_buf->link);
         state->current_read_buf = NULL;
     }
     state->client_agent_started = FALSE;
@@ -706,13 +702,13 @@ static void reds_reset_outgoing()
     RingItem *ring_item;
 
     if (outgoing->item) {
-        outgoing->item->release(outgoing->item);
+        reds_out_item_free(outgoing->item);
         outgoing->item = NULL;
     }
     while ((ring_item = ring_get_tail(&outgoing->pipe))) {
         RedsOutItem *out_item = (RedsOutItem *)ring_item;
         ring_remove(ring_item);
-        out_item->release(out_item);
+        reds_out_item_free(out_item);
     }
     outgoing->vec_size = 0;
     outgoing->vec = outgoing->vec_buf;
@@ -881,49 +877,31 @@ static int outgoing_write(RedsStreamContext *peer, OutgoingHandler *handler, voi
     return OUTGOING_OK;
 }
 
-typedef struct SimpleOutItem {
-    RedsOutItem base;
-    SpiceDataHeader header;
-    uint8_t data[0];
-} SimpleOutItem;
-
-static void reds_prepare_basic_out_item(RedsOutItem *in_item, struct iovec* vec, int *len)
+static RedsOutItem *new_out_item(uint32_t type)
 {
-    SimpleOutItem *item = (SimpleOutItem *)in_item;
-
-    vec[0].iov_base = &item->header;
-    vec[0].iov_len = sizeof(item->header);
-    if (item->header.size) {
-        vec[1].iov_base = item->data;
-        vec[1].iov_len = item->header.size;
-        *len = 2;
-    } else {
-        *len = 1;
-    }
-}
-
-static void reds_free_basic_out_item(RedsOutItem *item)
-{
-    free(item);
-}
+    RedsOutItem *item;
 
-static SimpleOutItem *new_simple_out_item(uint32_t type, int message_size)
-{
-    SimpleOutItem *item;
+    item = spice_new(RedsOutItem, 1);
+    ring_item_init(&item->link);
 
-    item = (SimpleOutItem *)spice_malloc(sizeof(*item) + message_size);
-    ring_item_init(&item->base.link);
-    item->base.prepare = reds_prepare_basic_out_item;
-    item->base.release = reds_free_basic_out_item;
+    item->m = spice_marshaller_new();
+    item->header = (SpiceDataHeader *)
+        spice_marshaller_reserve_space(item->m, sizeof(SpiceDataHeader));
+    spice_marshaller_set_base(item->m, sizeof(SpiceDataHeader));
 
-    item->header.serial = ++reds->serial;
-    item->header.type = type;
-    item->header.size = message_size;
-    item->header.sub_list = 0;
+    item->header->serial = ++reds->serial;
+    item->header->type = type;
+    item->header->sub_list = 0;
 
     return item;
 }
 
+static void reds_out_item_free(RedsOutItem *item)
+{
+    spice_marshaller_destroy(item->m);
+    free(item);
+}
+
 static void reds_push_pipe_item(RedsOutItem *item)
 {
     ring_add(&reds->outgoing.pipe, &item->link);
@@ -933,14 +911,12 @@ static void reds_push_pipe_item(RedsOutItem *item)
 static void reds_send_channels()
 {
     SpiceMsgChannels* channels_info;
-    SimpleOutItem *item;
-    int message_size;
+    RedsOutItem *item;
     Channel *channel;
     int i;
 
-    message_size = sizeof(SpiceMsgChannels) + reds->num_of_channels * sizeof(SpiceChannelId);
-    item = new_simple_out_item(SPICE_MSG_MAIN_CHANNELS_LIST, message_size);
-    channels_info = (SpiceMsgChannels *)item->data;
+    item = new_out_item(SPICE_MSG_MAIN_CHANNELS_LIST);
+    channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels) + reds->num_of_channels * sizeof(SpiceChannelId));
     channels_info->num_of_channels = reds->num_of_channels;
     channel = reds->channels;
 
@@ -950,59 +926,34 @@ static void reds_send_channels()
         channels_info->channels[i].id = channel->id;
         channel = channel->next;
     }
-    reds_push_pipe_item(&item->base);
-}
-
-static void reds_prepare_ping_item(RedsOutItem *in_item, struct iovec* vec, int *len)
-{
-    PingItem *item = (PingItem *)in_item;
-
-    vec[0].iov_base = &item->header;
-    vec[0].iov_len = sizeof(item->header);
-    vec[1].iov_base = &item->ping;
-    vec[1].iov_len = sizeof(item->ping);
-    int size = item->size;
-    int pos = 2;
-    while (size) {
-        ASSERT(pos < REDS_MAX_SEND_IOVEC);
-        int now = MIN(ZERO_BUF_SIZE, size);
-        size -= now;
-        vec[pos].iov_base = zero_page;
-        vec[pos].iov_len = now;
-        pos++;
-    }
-    *len = pos;
-}
-
-static void reds_free_ping_item(RedsOutItem *item)
-{
-    free(item);
+    spice_marshall_msg_main_channels_list(item->m, channels_info);
+    free(channels_info);
+    reds_push_pipe_item(item);
 }
 
 static int send_ping(int size)
 {
     struct timespec time_space;
-    PingItem *item;
+    RedsOutItem *item;
+    SpiceMsgPing ping;
 
     if (!reds->peer) {
         return FALSE;
     }
-    item = spice_new(PingItem, 1);
-    ring_item_init(&item->base.link);
-    item->base.prepare = reds_prepare_ping_item;
-    item->base.release = reds_free_ping_item;
+    item = new_out_item(SPICE_MSG_PING);
+    ping.id = ++reds->ping_id;
+    clock_gettime(CLOCK_MONOTONIC, &time_space);
+    ping.timestamp = time_space.tv_sec * 1000000LL + time_space.tv_nsec / 1000LL;
+    spice_marshall_msg_ping(item->m, &ping);
 
-    item->header.serial = ++reds->serial;
-    item->header.type = SPICE_MSG_PING;
-    item->header.size = sizeof(item->ping) + size;
-    item->header.sub_list = 0;
+    while (size > 0) {
+        int now = MIN(ZERO_BUF_SIZE, size);
+        size -= now;
+        spice_marshaller_add_ref(item->m, zero_page, now);
+    }
 
-    item->ping.id = ++reds->ping_id;
-    clock_gettime(CLOCK_MONOTONIC, &time_space);
-    item->ping.timestamp = time_space.tv_sec * 1000000LL + time_space.tv_nsec / 1000LL;
+    reds_push_pipe_item(item);
 
-    item->size = size;
-    reds_push_pipe_item(&item->base);
     return TRUE;
 }
 
@@ -1044,21 +995,23 @@ static void ping_timer_cb()
 
 static void reds_send_mouse_mode()
 {
-    SpiceMsgMainMouseMode *mouse_mode;
-    SimpleOutItem *item;
+    SpiceMsgMainMouseMode mouse_mode;
+    RedsOutItem *item;
 
     if (!reds->peer) {
         return;
     }
 
-    item = new_simple_out_item(SPICE_MSG_MAIN_MOUSE_MODE, sizeof(SpiceMsgMainMouseMode));
-    mouse_mode = (SpiceMsgMainMouseMode *)item->data;
-    mouse_mode->supported_modes = SPICE_MOUSE_MODE_SERVER;
+    item = new_out_item(SPICE_MSG_MAIN_MOUSE_MODE);
+    mouse_mode.supported_modes = SPICE_MOUSE_MODE_SERVER;
     if (reds->is_client_mouse_allowed) {
-        mouse_mode->supported_modes |= SPICE_MOUSE_MODE_CLIENT;
+        mouse_mode.supported_modes |= SPICE_MOUSE_MODE_CLIENT;
     }
-    mouse_mode->current_mode = reds->mouse_mode;
-    reds_push_pipe_item(&item->base);
+    mouse_mode.current_mode = reds->mouse_mode;
+
+    spice_marshall_msg_main_mouse_mode(item->m, &mouse_mode);
+
+    reds_push_pipe_item(item);
 }
 
 static void reds_set_mouse_mode(uint32_t mode)
@@ -1092,20 +1045,21 @@ static void reds_update_mouse_mode()
 
 static void reds_send_agent_connected()
 {
-    SimpleOutItem *item;
-    item = new_simple_out_item(SPICE_MSG_MAIN_AGENT_CONNECTED, 0);
-    reds_push_pipe_item(&item->base);
+    RedsOutItem *item;
+
+    item = new_out_item(SPICE_MSG_MAIN_AGENT_CONNECTED);
+    reds_push_pipe_item(item);
 }
 
 static void reds_send_agent_disconnected()
 {
-    SpiceMsgMainAgentDisconnect *disconnect;
-    SimpleOutItem *item;
+    SpiceMsgMainAgentDisconnect disconnect;
+    RedsOutItem *item;
 
-    item = new_simple_out_item(SPICE_MSG_MAIN_AGENT_DISCONNECTED, sizeof(SpiceMsgMainAgentDisconnect));
-    disconnect = (SpiceMsgMainAgentDisconnect *)item->data;
-    disconnect->error_code = SPICE_LINK_ERR_OK;
-    reds_push_pipe_item(&item->base);
+    item = new_out_item(SPICE_MSG_MAIN_AGENT_DISCONNECTED);
+    disconnect.error_code = SPICE_LINK_ERR_OK;
+    spice_marshall_msg_main_agent_disconnected(item->m, &disconnect);
+    reds_push_pipe_item(item);
 }
 
 static void reds_agent_remove()
@@ -1137,20 +1091,22 @@ static void reds_agent_remove()
 
 static void reds_send_tokens()
 {
-    SpiceMsgMainAgentTokens *tokens;
-    SimpleOutItem *item;
+    SpiceMsgMainAgentTokens tokens;
+    RedsOutItem *item;
 
     if (!reds->peer) {
         return;
     }
 
-    item = new_simple_out_item(SPICE_MSG_MAIN_AGENT_TOKEN, sizeof(SpiceMsgMainAgentTokens));
-    tokens = (SpiceMsgMainAgentTokens *)item->data;
-    tokens->num_tokens = reds->agent_state.num_tokens;
-    reds->agent_state.num_client_tokens += tokens->num_tokens;
+    item = new_out_item(SPICE_MSG_MAIN_AGENT_TOKEN);
+    tokens.num_tokens = reds->agent_state.num_tokens;
+    reds->agent_state.num_client_tokens += tokens.num_tokens;
     ASSERT(reds->agent_state.num_client_tokens <= REDS_AGENT_WINDOW_SIZE);
     reds->agent_state.num_tokens = 0;
-    reds_push_pipe_item(&item->base);
+
+    spice_marshall_msg_main_agent_token(item->m, &tokens);
+
+    reds_push_pipe_item(item);
 }
 
 static int write_to_vdi_port()
@@ -1188,27 +1144,41 @@ static int write_to_vdi_port()
     return total;
 }
 
+static int read_from_vdi_port(void);
+
+void vdi_read_buf_release(uint8_t *data, void *opaque)
+{
+    VDIReadBuf *buf = (VDIReadBuf *)opaque;
+
+    ring_add(&reds->agent_state.read_bufs, &buf->link);
+    read_from_vdi_port();
+}
+
 static void dispatch_vdi_port_data(int port, VDIReadBuf *buf)
 {
     VDIPortState *state = &reds->agent_state;
+    RedsOutItem *item;
+
     switch (port) {
     case VDP_CLIENT_PORT: {
-        buf->header.serial = ++reds->serial;
-        buf->header.size = buf->len;
-        reds_push_pipe_item(&buf->out_item);
+        item = new_out_item(SPICE_MSG_MAIN_AGENT_DATA);
+
+        spice_marshaller_add_ref_full(item->m, buf->data, buf->len,
+                                      vdi_read_buf_release, buf);
+        reds_push_pipe_item(item);
         break;
     }
     case VDP_SERVER_PORT:
-        ring_add(&state->read_bufs, &buf->out_item.link);
+        ring_add(&state->read_bufs, &buf->link);
         break;
     default:
-        ring_add(&state->read_bufs, &buf->out_item.link);
+        ring_add(&state->read_bufs, &buf->link);
         red_printf("invalid port");
         reds_agent_remove();
     }
 }
 
-static int read_from_vdi_port()
+static int read_from_vdi_port(void)
 {
     VDIPortState *state = &reds->agent_state;
     SpiceVDIPortInterface *sif;
@@ -1346,112 +1316,69 @@ typedef struct WriteQueueInfo {
     uint32_t len;
 } WriteQueueInfo;
 
-typedef struct SendMainMigrateItem {
-    RedsOutItem base;
-    SpiceDataHeader header;
-    MainMigrateData data;
-    WriteQueueInfo queue_info[REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES];
-} SendMainMigrateItem;
-
-static void main_channel_send_migrate_data_item(RedsOutItem *in_item, struct iovec* vec_start,
-                                                int *len)
+static void main_channel_push_migrate_data_item()
 {
-    SendMainMigrateItem *item = (SendMainMigrateItem *)in_item;
+    RedsOutItem *item;
+    MainMigrateData *data;
     VDIPortState *state = &reds->agent_state;
-    struct iovec* vec;
     int buf_index;
     RingItem *now;
 
-    vec = vec_start;
-
-    item->header.serial = ++reds->serial;
-    item->header.type = SPICE_MSG_MIGRATE_DATA;
-    item->header.size = sizeof(item->data);
-    item->header.sub_list = 0;
-
-    vec[0].iov_base = &item->header;
-    vec[0].iov_len = sizeof(item->header);
-    vec[1].iov_base = &item->data;
-    vec[1].iov_len = sizeof(item->data);
-
-    vec += 2;
-    *len = 2;
+    item = new_out_item(SPICE_MSG_MIGRATE_DATA);
 
-    item->data.version = MAIN_CHANNEL_MIG_DATA_VERSION;
-    item->data.serial = reds->serial;
-    item->data.ping_id = reds->ping_id;
+    data = (MainMigrateData *)spice_marshaller_reserve_space(item->m, sizeof(MainMigrateData));
+    data->version = MAIN_CHANNEL_MIG_DATA_VERSION;
+    data->serial = reds->serial;
+    data->ping_id = reds->ping_id;
 
-    item->data.agent_connected = !!state->connected;
-    item->data.client_agent_started = state->client_agent_started;
-    item->data.num_client_tokens = state->num_client_tokens;
-    item->data.send_tokens = state->send_tokens;
-
-    item->data.read_state = state->read_state;
-    item->data.vdi_chunk_header = state->vdi_chunk_header;
-    item->data.recive_len = state->recive_len;
-    item->data.message_recive_len = state->message_recive_len;
+    data->agent_connected = !!state->connected;
+    data->client_agent_started = state->client_agent_started;
+    data->num_client_tokens = state->num_client_tokens;
+    data->send_tokens = state->send_tokens;
 
+    data->read_state = state->read_state;
+    data->vdi_chunk_header = state->vdi_chunk_header;
+    data->recive_len = state->recive_len;
+    data->message_recive_len = state->message_recive_len;
 
     if (state->current_read_buf) {
-        item->data.read_buf_len = state->current_read_buf->len;
-        if ((vec->iov_len = item->data.read_buf_len - item->data.recive_len)) {
-            vec->iov_base = state->current_read_buf->data;
-            item->header.size += vec->iov_len;
-            vec++;
-            (*len)++;
+        data->read_buf_len = state->current_read_buf->len;
+
+        if (data->read_buf_len - data->recive_len) {
+            spice_marshaller_add_ref(item->m,
+                                     state->current_read_buf->data,
+                                     data->read_buf_len - data->recive_len);
         }
     } else {
-        item->data.read_buf_len = 0;
+        data->read_buf_len = 0;
     }
 
     now = &state->write_queue;
-    item->data.write_queue_size = 0;
+    data->write_queue_size = 0;
     while ((now = ring_prev(&state->write_queue, now))) {
-        item->data.write_queue_size++;
-    }
-    if (!item->data.write_queue_size) {
-        return;
+        data->write_queue_size++;
     }
-    ASSERT(item->data.write_queue_size <= sizeof(item->queue_info) / sizeof(item->queue_info[0]));
-    vec->iov_base = item->queue_info;
-    vec->iov_len = item->data.write_queue_size * sizeof(item->queue_info[0]);
-    item->header.size += vec->iov_len;
-    vec++;
-    (*len)++;
+    if (data->write_queue_size) {
+        WriteQueueInfo *queue_info;
 
-    buf_index = 0;
-    now = &state->write_queue;
-    while ((now = ring_prev(&state->write_queue, now))) {
-        VDIPortBuf *buf = (VDIPortBuf *)now;
-        item->queue_info[buf_index].port = buf->chunk_header.port;
-        item->queue_info[buf_index++].len = buf->write_len;
-        ASSERT(vec - vec_start < REDS_MAX_SEND_IOVEC);
-        vec->iov_base = buf->now;
-        vec->iov_len = buf->write_len;
-        item->header.size += vec->iov_len;
-        vec++;
-        (*len)++;
-    }
-}
-
-static void main_channelrelease_migrate_data_item(RedsOutItem *in_item)
-{
-    SendMainMigrateItem *item = (SendMainMigrateItem *)in_item;
-    free(item);
-}
-
-static void main_channel_push_migrate_data_item()
-{
-    SendMainMigrateItem *item;
+        queue_info = (WriteQueueInfo *)
+            spice_marshaller_reserve_space(item->m,
+                                           data->write_queue_size * sizeof(queue_info[0]));
 
-    item = spice_new0(SendMainMigrateItem, 1);
-    ring_item_init(&item->base.link);
-    item->base.prepare = main_channel_send_migrate_data_item;
-    item->base.release = main_channelrelease_migrate_data_item;
+        buf_index = 0;
+        now = &state->write_queue;
+        while ((now = ring_prev(&state->write_queue, now))) {
+            VDIPortBuf *buf = (VDIPortBuf *)now;
+            queue_info[buf_index].port = buf->chunk_header.port;
+            queue_info[buf_index++].len = buf->write_len;
+            spice_marshaller_add_ref(item->m, buf->now, buf->write_len);
+        }
+    }
 
     reds_push_pipe_item((RedsOutItem *)item);
 }
 
+
 static int main_channel_restore_vdi_read_state(MainMigrateData *data, uint8_t **in_pos,
                                                uint8_t *end)
 {
@@ -1858,7 +1785,7 @@ static int reds_send_data()
         } else {
             outgoing->vec = reds_iovec_skip(outgoing->vec, n, &outgoing->vec_size);
             if (!outgoing->vec_size) {
-                outgoing->item->release(outgoing->item);
+                reds_out_item_free(outgoing->item);
                 outgoing->item = NULL;
                 outgoing->vec = outgoing->vec_buf;
                 return TRUE;
@@ -1870,15 +1797,22 @@ static int reds_send_data()
 static void reds_push()
 {
     RedsOutgoingData *outgoing = &reds->outgoing;
-    RingItem *item;
+    RingItem *ring_item;
+    RedsOutItem *item;
 
     for (;;) {
-        if (!reds->peer || outgoing->item || !(item = ring_get_tail(&outgoing->pipe))) {
+        if (!reds->peer || outgoing->item || !(ring_item = ring_get_tail(&outgoing->pipe))) {
             return;
         }
-        ring_remove(item);
-        outgoing->item = (RedsOutItem *)item;
-        outgoing->item->prepare(outgoing->item, outgoing->vec_buf, &outgoing->vec_size);
+        ring_remove(ring_item);
+        outgoing->item = item = (RedsOutItem *)ring_item;
+
+        spice_marshaller_flush(item->m);
+        item->header->size = spice_marshaller_get_total_size(item->m) - sizeof(SpiceDataHeader);
+
+        outgoing->vec_size = spice_marshaller_fill_iovec(item->m,
+                                                         outgoing->vec_buf,
+                                                         REDS_MAX_SEND_IOVEC, 0);
         reds_send_data();
     }
 }
@@ -2063,24 +1997,26 @@ static void reds_handle_main_link(RedLinkInfo *link)
                                         reds_main_event, NULL);
 
     if (!reds->mig_target) {
-        SimpleOutItem *item;
-        SpiceMsgMainInit *init;
-
-        item = new_simple_out_item(SPICE_MSG_MAIN_INIT, sizeof(SpiceMsgMainInit));
-        init = (SpiceMsgMainInit *)item->data;
-        init->session_id = connection_id;
-        init->display_channels_hint = red_dispatcher_count();
-        init->current_mouse_mode = reds->mouse_mode;
-        init->supported_mouse_modes = SPICE_MOUSE_MODE_SERVER;
+        RedsOutItem *item;
+        SpiceMsgMainInit init;
+
+        item = new_out_item(SPICE_MSG_MAIN_INIT);
+        init.session_id = connection_id;
+        init.display_channels_hint = red_dispatcher_count();
+        init.current_mouse_mode = reds->mouse_mode;
+        init.supported_mouse_modes = SPICE_MOUSE_MODE_SERVER;
         if (reds->is_client_mouse_allowed) {
-            init->supported_mouse_modes |= SPICE_MOUSE_MODE_CLIENT;
+            init.supported_mouse_modes |= SPICE_MOUSE_MODE_CLIENT;
         }
-        init->agent_connected = !!vdagent;
-        init->agent_tokens = REDS_AGENT_WINDOW_SIZE;
+        init.agent_connected = !!vdagent;
+        init.agent_tokens = REDS_AGENT_WINDOW_SIZE;
         reds->agent_state.num_client_tokens = REDS_AGENT_WINDOW_SIZE;
-        init->multi_media_time = reds_get_mm_time() - MM_TIME_DELTA;
-        init->ram_hint = red_dispatcher_qxl_ram_size();
-        reds_push_pipe_item(&item->base);
+        init.multi_media_time = reds_get_mm_time() - MM_TIME_DELTA;
+        init.ram_hint = red_dispatcher_qxl_ram_size();
+
+        spice_marshall_msg_main_init(item->m, &init);
+
+        reds_push_pipe_item(item);
         reds_start_net_test();
     }
 }
@@ -2516,25 +2452,23 @@ static void reds_handle_other_links(RedLinkInfo *link)
     reds_send_link_result(link, SPICE_LINK_ERR_OK);
     reds_show_new_channel(link);
     if (link_mess->channel_type == SPICE_CHANNEL_INPUTS && !link->peer->ssl) {
-        SimpleOutItem *item;
-        SpiceMsgNotify *notify;
+        RedsOutItem *item;
+        SpiceMsgNotify notify;
         char *mess = "keyboard channel is insecure";
         const int mess_len = strlen(mess);
 
-        if (!(item = new_simple_out_item(SPICE_MSG_NOTIFY, sizeof(SpiceMsgNotify) + mess_len + 1))) {
-            red_printf("alloc item failed");
-            reds_disconnect();
-            return;
-        }
+        item = new_out_item(SPICE_MSG_NOTIFY);
+
+        notify.time_stamp = get_time_stamp();
+        notify.severity = SPICE_NOTIFY_SEVERITY_WARN;
+        notify.visibilty = SPICE_NOTIFY_VISIBILITY_HIGH;
+        notify.what = SPICE_WARN_GENERAL;
+        notify.message_len = mess_len;
 
-        notify = (SpiceMsgNotify *)item->data;
-        notify->time_stamp = get_time_stamp();
-        notify->severity = SPICE_NOTIFY_SEVERITY_WARN;
-        notify->visibilty = SPICE_NOTIFY_VISIBILITY_HIGH;
-        notify->what = SPICE_WARN_GENERAL;
-        notify->message_len = mess_len;
-        memcpy(notify->message, mess, mess_len + 1);
-        reds_push_pipe_item(&item->base);
+        spice_marshall_msg_notify(item->m, &notify);
+        spice_marshaller_add(item->m, (uint8_t *)mess, mess_len + 1);
+
+        reds_push_pipe_item(item);
     }
     peer = link->peer;
     link->link_mess = NULL;
@@ -3220,25 +3154,26 @@ typedef struct RedsMigCertPubKeyInfo {
 static void reds_mig_continue(void)
 {
     RedsMigSpice *s = reds->mig_spice;
-    SpiceMsgMainMigrationBegin *migrate;
-    SimpleOutItem *item;
+    SpiceMsgMainMigrationBegin migrate;
+    RedsOutItem *item;
     int host_len;
 
     red_printf("");
     host_len = strlen(s->host) + 1;
-    item = new_simple_out_item(SPICE_MSG_MAIN_MIGRATE_BEGIN,
-                               sizeof(SpiceMsgMainMigrationBegin) + host_len + s->cert_pub_key_len);
-    migrate = (SpiceMsgMainMigrationBegin *)item->data;
-    migrate->port = s->port;
-    migrate->sport = s->sport;
-    migrate->host_offset = sizeof(SpiceMsgMainMigrationBegin);
-    migrate->host_size = host_len;
-    migrate->pub_key_type = s->cert_pub_key_type;
-    migrate->pub_key_offset = sizeof(SpiceMsgMainMigrationBegin) + host_len;
-    migrate->pub_key_size = s->cert_pub_key_len;
-    memcpy((uint8_t*)(migrate) + migrate->host_offset , s->host, host_len);
-    memcpy((uint8_t*)(migrate) + migrate->pub_key_offset, s->cert_pub_key, s->cert_pub_key_len);
-    reds_push_pipe_item(&item->base);
+    item = new_out_item(SPICE_MSG_MAIN_MIGRATE_BEGIN);
+
+    migrate.port = s->port;
+    migrate.sport = s->sport;
+    migrate.host_offset = sizeof(SpiceMsgMainMigrationBegin);
+    migrate.host_size = host_len;
+    migrate.pub_key_type = s->cert_pub_key_type;
+    migrate.pub_key_offset = sizeof(SpiceMsgMainMigrationBegin) + host_len;
+    migrate.pub_key_size = s->cert_pub_key_len;
+    spice_marshall_msg_main_migrate_begin(item->m, &migrate);
+    spice_marshaller_add(item->m, (uint8_t *)s->host, host_len);
+    spice_marshaller_add(item->m, s->cert_pub_key, s->cert_pub_key_len);
+
+    reds_push_pipe_item(item);
 
     free(reds->mig_spice->host);
     free(reds->mig_spice);
@@ -3287,7 +3222,7 @@ error:
 
 static void reds_mig_finished(int completed)
 {
-    SimpleOutItem *item;
+    RedsOutItem *item;
 
     red_printf("");
     if (reds->listen_watch != NULL) {
@@ -3306,23 +3241,24 @@ static void reds_mig_finished(int completed)
 
     if (completed) {
         Channel *channel;
-        SpiceMsgMigrate *migrate;
+        SpiceMsgMigrate migrate;
 
         reds->mig_wait_disconnect = TRUE;
         core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
 
-        item = new_simple_out_item(SPICE_MSG_MIGRATE, sizeof(SpiceMsgMigrate));
-        migrate = (SpiceMsgMigrate *)item->data;
-        migrate->flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
-        reds_push_pipe_item(&item->base);
+        item = new_out_item(SPICE_MSG_MIGRATE);
+        migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
+        spice_marshall_msg_migrate(item->m, &migrate);
+
+        reds_push_pipe_item(item);
         channel = reds->channels;
         while (channel) {
             channel->migrate(channel);
             channel = channel->next;
         }
     } else {
-        item = new_simple_out_item(SPICE_MSG_MAIN_MIGRATE_CANCEL, 0);
-        reds_push_pipe_item(&item->base);
+        item = new_out_item(SPICE_MSG_MAIN_MIGRATE_CANCEL);
+        reds_push_pipe_item(item);
         reds_mig_cleanup();
     }
 }
@@ -3353,22 +3289,18 @@ void reds_update_mm_timer(uint32_t mm_time)
 
 void reds_enable_mm_timer()
 {
-    SpiceMsgMainMultiMediaTime *time_mes;
-    SimpleOutItem *item;
+    SpiceMsgMainMultiMediaTime time_mes;
+    RedsOutItem *item;
 
     core->timer_start(reds->mm_timer, MM_TIMER_GRANULARITY_MS);
     if (!reds->peer) {
         return;
     }
 
-    if (!(item = new_simple_out_item(SPICE_MSG_MAIN_MULTI_MEDIA_TIME, sizeof(SpiceMsgMainMultiMediaTime)))) {
-        red_printf("alloc item failed");
-        reds_disconnect();
-        return;
-    }
-    time_mes = (SpiceMsgMainMultiMediaTime *)item->data;
-    time_mes->time = reds_get_mm_time() - MM_TIME_DELTA;
-    reds_push_pipe_item(&item->base);
+    item = new_out_item(SPICE_MSG_MAIN_MULTI_MEDIA_TIME);
+    time_mes.time = reds_get_mm_time() - MM_TIME_DELTA;
+    spice_marshall_msg_main_multi_media_time(item->m, &time_mes);
+    reds_push_pipe_item(item);
 }
 
 void reds_desable_mm_timer()
@@ -3584,25 +3516,6 @@ static void free_internal_agent_buff(VDIPortBuf *in_buf)
     }
 }
 
-void reds_prepare_read_buf(RedsOutItem *in_nuf, struct iovec* vec, int *len)
-{
-    VDIReadBuf *buf = (VDIReadBuf *)in_nuf;
-
-    vec[0].iov_base = &buf->header;
-    vec[0].iov_len = sizeof(buf->header);
-    vec[1].iov_base = buf->data;
-    vec[1].iov_len = buf->len;
-    *len = 2;
-}
-
-void reds_release_read_buf(RedsOutItem *in_nuf)
-{
-    VDIReadBuf *buf = (VDIReadBuf *)in_nuf;
-
-    ring_add(&reds->agent_state.read_bufs, &buf->out_item.link);
-    read_from_vdi_port();
-}
-
 static void init_vd_agent_resources()
 {
     VDIPortState *state = &reds->agent_state;
@@ -3640,12 +3553,8 @@ static void init_vd_agent_resources()
 
     for (i = 0; i < REDS_VDI_PORT_NUM_RECIVE_BUFFS; i++) {
         VDIReadBuf *buf = spice_new0(VDIReadBuf, 1);
-        buf->out_item.prepare = reds_prepare_read_buf;
-        buf->out_item.release = reds_release_read_buf;
-        buf->header.type = SPICE_MSG_MAIN_AGENT_DATA;
-        buf->header.sub_list = 0;
-        ring_item_init(&buf->out_item.link);
-        ring_add(&reds->agent_state.read_bufs, &buf->out_item.link);
+        ring_item_init(&buf->link);
+        ring_add(&reds->agent_state.read_bufs, &buf->link);
     }
 }
 
commit 8418da7ab24eb46547543a886d798759f39891f1
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 15 17:36:04 2010 +0200

    Convert snd_worker.c to use SpiceMarshaller and generated marshallers

diff --git a/server/snd_worker.c b/server/snd_worker.c
index 2deb8a3..cd9af97 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
@@ -27,9 +28,10 @@
 #include "reds.h"
 #include "red_dispatcher.h"
 #include "snd_worker.h"
+#include "marshaller.h"
+#include "generated_marshallers.h"
 
 #define MAX_SEND_VEC 100
-#define MAX_SEND_BUFS 200
 
 #define RECIVE_BUF_SIZE (16 * 1024 * 2)
 
@@ -61,11 +63,6 @@ enum RecordCommand {
 #define SND_RECORD_MIGRATE_MASK (1 << SND_RECORD_MIGRATE)
 #define SND_RECORD_CTRL_MASK (1 << SND_RECORD_CTRL)
 
-typedef struct BufDescriptor {
-    uint32_t size;
-    uint8_t *data;
-} BufDescriptor;
-
 typedef struct SndChannel SndChannel;
 typedef void (*send_messages_proc)(void *in_channel);
 typedef int (*handle_message_proc)(SndChannel *channel, SpiceDataHeader *message);
@@ -90,10 +87,9 @@ struct SndChannel {
     uint32_t ack_messages;
 
     struct {
-        SpiceDataHeader header;
-        uint32_t n_bufs;
-        BufDescriptor bufs[MAX_SEND_BUFS];
-
+        uint64_t serial;
+        SpiceDataHeader *header;
+        SpiceMarshaller *marshaller;
         uint32_t size;
         uint32_t pos;
     } send_data;
@@ -129,12 +125,7 @@ typedef struct PlaybackChannel {
     int celt_allowed;
     uint32_t mode;
     struct {
-        union {
-            SpiceMsgPlaybackMode mode;
-            SpiceMsgPlaybackStart start;
-            SpiceMsgMigrate migrate;
-            uint8_t celt_buf[CELT_COMPRESSED_FRAME_BYTES];
-        } u;
+        uint8_t celt_buf[CELT_COMPRESSED_FRAME_BYTES];
     } send_data;
 } PlaybackChannel;
 
@@ -165,12 +156,6 @@ typedef struct __attribute__ ((__packed__)) RecordMigrateData {
     uint32_t mode_time;
 } RecordMigrateData;
 
-typedef struct __attribute__ ((__packed__)) RecordMigrateMessage {
-    SpiceMsgMigrate migrate;
-    SpiceDataHeader header;
-    RecordMigrateData data;
-} RecordMigrateMessage;
-
 typedef struct RecordChannel {
     SndChannel base;
     uint32_t samples[RECORD_SAMPLES_SIZE];
@@ -182,12 +167,6 @@ typedef struct RecordChannel {
     CELTDecoder *celt_decoder;
     CELTMode *celt_mode;
     uint32_t celt_buf[FRAME_SIZE];
-    struct {
-        union {
-            SpiceMsgRecordStart start;
-            RecordMigrateMessage migrate;
-        } u;
-    } send_data;
 } RecordChannel;
 
 static SndWorker *workers = NULL;
@@ -195,46 +174,6 @@ static uint32_t playback_compression = SPICE_AUDIO_DATA_MODE_CELT_0_5_1;
 
 static void snd_receive(void* data);
 
-static inline BufDescriptor *snd_find_buf(SndChannel *channel, int buf_pos, int *buf_offset)
-{
-    BufDescriptor *buf;
-    int pos = 0;
-
-    for (buf = channel->send_data.bufs; buf_pos >= pos + buf->size; buf++) {
-        pos += buf->size;
-        ASSERT(buf != &channel->send_data.bufs[channel->send_data.n_bufs - 1]);
-    }
-    *buf_offset = buf_pos - pos;
-    return buf;
-}
-
-static inline uint32_t __snd_fill_iovec(BufDescriptor *buf, int skip, struct iovec *vec,
-                                        int *vec_index, long phys_delta)
-{
-    uint32_t size = 0;
-    vec[*vec_index].iov_base = buf->data + skip;
-    vec[*vec_index].iov_len = size = buf->size - skip;
-    (*vec_index)++;
-    return size;
-}
-
-static inline void snd_fill_iovec(SndChannel *channel, struct iovec *vec, int *vec_size)
-{
-    int vec_index = 0;
-    uint32_t pos = channel->send_data.pos;
-    ASSERT(channel->send_data.size != pos && channel->send_data.size > pos);
-
-    do {
-        BufDescriptor *buf;
-        int buf_offset;
-
-        buf = snd_find_buf(channel, pos, &buf_offset);
-        ASSERT(buf);
-        pos += __snd_fill_iovec(buf, buf_offset, vec, &vec_index, 0);
-    } while (vec_index < MAX_SEND_VEC && pos != channel->send_data.size);
-    *vec_size = vec_index;
-}
-
 static void snd_disconnect_channel(SndChannel *channel)
 {
     SndWorker *worker;
@@ -248,6 +187,7 @@ static void snd_disconnect_channel(SndChannel *channel)
     core->watch_remove(channel->peer->watch);
     channel->peer->watch = NULL;
     channel->peer->cb_free(channel->peer);
+    spice_marshaller_destroy(channel->send_data.marshaller);
     free(channel);
 }
 
@@ -299,7 +239,8 @@ static int snd_send_data(SndChannel *channel)
             break;
         }
 
-        snd_fill_iovec(channel, vec, &vec_size);
+        vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
+                                               vec, MAX_SEND_VEC, channel->send_data.pos);
         if ((n = channel->peer->cb_writev(channel->peer->ctx, vec, vec_size)) == -1) {
             switch (errno) {
             case EAGAIN:
@@ -506,76 +447,75 @@ static void snd_event(int fd, int event, void *data)
     }
 }
 
-static inline void __snd_add_buf(SndChannel *channel, void *data, uint32_t size)
-{
-    int pos = channel->send_data.n_bufs++;
-    ASSERT(pos < MAX_SEND_BUFS);
-    channel->send_data.bufs[pos].size = size;
-    channel->send_data.bufs[pos].data = data;
-}
-
-static void snd_add_buf(SndChannel *channel, void *data, uint32_t size)
-{
-    __snd_add_buf(channel, data, size);
-    channel->send_data.header.size += size;
-}
-
 static inline int snd_reset_send_data(SndChannel *channel, uint16_t verb)
 {
     if (!channel) {
         return FALSE;
     }
 
+    spice_marshaller_reset(channel->send_data.marshaller);
+    channel->send_data.header = (SpiceDataHeader *)
+        spice_marshaller_reserve_space(channel->send_data.marshaller, sizeof(SpiceDataHeader));
+    spice_marshaller_set_base(channel->send_data.marshaller, sizeof(SpiceDataHeader));
     channel->send_data.pos = 0;
-    channel->send_data.n_bufs = 0;
-    channel->send_data.header.sub_list = 0;
-    channel->send_data.header.size = 0;
-    channel->send_data.header.type = verb;
-    ++channel->send_data.header.serial;
-    __snd_add_buf(channel, &channel->send_data.header, sizeof(SpiceDataHeader));
+    channel->send_data.header->sub_list = 0;
+    channel->send_data.header->size = 0;
+    channel->send_data.header->type = verb;
+    channel->send_data.header->serial = ++channel->send_data.serial;
     return TRUE;
 }
 
+static int snd_begin_send_message(SndChannel *channel)
+{
+    spice_marshaller_flush(channel->send_data.marshaller);
+    channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
+    channel->send_data.header->size = channel->send_data.size - sizeof(SpiceDataHeader);
+    channel->send_data.header = NULL; /* avoid writing to this until we have a new message */
+    return snd_send_data(channel);
+}
+
+
 static int snd_playback_send_migrate(PlaybackChannel *channel)
 {
+    SpiceMsgMigrate migrate;
+
     if (!snd_reset_send_data((SndChannel *)channel, SPICE_MSG_MIGRATE)) {
         return FALSE;
     }
-    channel->send_data.u.migrate.flags = 0;
-    snd_add_buf((SndChannel *)channel, &channel->send_data.u.migrate,
-                sizeof(channel->send_data.u.migrate));
-    channel->base.send_data.size = channel->base.send_data.header.size + sizeof(SpiceDataHeader);
-    return snd_send_data((SndChannel *)channel);
+    migrate.flags = 0;
+    spice_marshall_msg_migrate(channel->base.send_data.marshaller, &migrate);
+
+    return snd_begin_send_message((SndChannel *)channel);
 }
 
 static int snd_playback_send_start(PlaybackChannel *playback_channel)
 {
     SndChannel *channel = (SndChannel *)playback_channel;
-    SpiceMsgPlaybackStart *start;
+    SpiceMsgPlaybackStart start;
+
     if (!snd_reset_send_data(channel, SPICE_MSG_PLAYBACK_START)) {
         return FALSE;
     }
 
-    start = &playback_channel->send_data.u.start;
-    start->channels = SPICE_INTERFACE_PLAYBACK_CHAN;
-    start->frequency = SPICE_INTERFACE_PLAYBACK_FREQ;
+    start.channels = SPICE_INTERFACE_PLAYBACK_CHAN;
+    start.frequency = SPICE_INTERFACE_PLAYBACK_FREQ;
     ASSERT(SPICE_INTERFACE_PLAYBACK_FMT == SPICE_INTERFACE_AUDIO_FMT_S16);
-    start->format = SPICE_AUDIO_FMT_S16;
-    start->time = reds_get_mm_time();
-    snd_add_buf(channel, start, sizeof(*start));
+    start.format = SPICE_AUDIO_FMT_S16;
+    start.time = reds_get_mm_time();
+    spice_marshall_msg_playback_start(channel->send_data.marshaller, &start);
 
-    channel->send_data.size = sizeof(SpiceDataHeader) + sizeof(*start);
-    return snd_send_data(channel);
+    return snd_begin_send_message(channel);
 }
 
 static int snd_playback_send_stop(PlaybackChannel *playback_channel)
 {
     SndChannel *channel = (SndChannel *)playback_channel;
+
     if (!snd_reset_send_data(channel, SPICE_MSG_PLAYBACK_STOP)) {
         return FALSE;
     }
-    channel->send_data.size = sizeof(SpiceDataHeader);
-    return snd_send_data(channel);
+
+    return snd_begin_send_message(channel);
 }
 
 static int snd_playback_send_ctl(PlaybackChannel *playback_channel)
@@ -592,30 +532,30 @@ static int snd_playback_send_ctl(PlaybackChannel *playback_channel)
 static int snd_record_send_start(RecordChannel *record_channel)
 {
     SndChannel *channel = (SndChannel *)record_channel;
-    SpiceMsgRecordStart *start;
+    SpiceMsgRecordStart start;
+
     if (!snd_reset_send_data(channel, SPICE_MSG_RECORD_START)) {
         return FALSE;
     }
 
-    start = &record_channel->send_data.u.start;
-    start->channels = SPICE_INTERFACE_RECORD_CHAN;
-    start->frequency = SPICE_INTERFACE_RECORD_FREQ;
+    start.channels = SPICE_INTERFACE_RECORD_CHAN;
+    start.frequency = SPICE_INTERFACE_RECORD_FREQ;
     ASSERT(SPICE_INTERFACE_RECORD_FMT == SPICE_INTERFACE_AUDIO_FMT_S16);
-    start->format = SPICE_AUDIO_FMT_S16;
-    snd_add_buf(channel, start, sizeof(*start));
+    start.format = SPICE_AUDIO_FMT_S16;
+    spice_marshall_msg_record_start(channel->send_data.marshaller, &start);
 
-    channel->send_data.size = sizeof(SpiceDataHeader) + sizeof(*start);
-    return snd_send_data(channel);
+    return snd_begin_send_message(channel);
 }
 
 static int snd_record_send_stop(RecordChannel *record_channel)
 {
     SndChannel *channel = (SndChannel *)record_channel;
+
     if (!snd_reset_send_data(channel, SPICE_MSG_RECORD_STOP)) {
         return FALSE;
     }
-    channel->send_data.size = sizeof(SpiceDataHeader);
-    return snd_send_data(channel);
+
+    return snd_begin_send_message(channel);
 }
 
 static int snd_record_send_ctl(RecordChannel *record_channel)
@@ -632,29 +572,35 @@ static int snd_record_send_ctl(RecordChannel *record_channel)
 static int snd_record_send_migrate(RecordChannel *record_channel)
 {
     SndChannel *channel = (SndChannel *)record_channel;
-    RecordMigrateMessage* migrate;
+    SpiceMsgMigrate migrate;
+    SpiceDataHeader *header;
+    RecordMigrateData *data;
 
     if (!snd_reset_send_data(channel, SPICE_MSG_MIGRATE)) {
         return FALSE;
     }
 
-    migrate = &record_channel->send_data.u.migrate;
-    migrate->migrate.flags = SPICE_MIGRATE_NEED_DATA_TRANSFER;
-    migrate->header.type = SPICE_MSG_MIGRATE_DATA;
-    migrate->header.size = sizeof(RecordMigrateData);
-    migrate->header.serial = ++channel->send_data.header.serial;
-    migrate->header.sub_list = 0;
+    migrate.flags = SPICE_MIGRATE_NEED_DATA_TRANSFER;
+    spice_marshall_msg_migrate(channel->send_data.marshaller, &migrate);
+
+    header = (SpiceDataHeader *)spice_marshaller_reserve_space(channel->send_data.marshaller,
+                                                               sizeof(SpiceDataHeader));
+    header->type = SPICE_MSG_MIGRATE_DATA;
+    header->size = sizeof(RecordMigrateData);
+    header->serial = ++channel->send_data.serial;
+    header->sub_list = 0;
 
-    migrate->data.version = RECORD_MIG_VERSION;
-    migrate->data.serial = channel->send_data.header.serial;
-    migrate->data.start_time = record_channel->start_time;
-    migrate->data.mode = record_channel->mode;
-    migrate->data.mode_time = record_channel->mode_time;
+    data = (RecordMigrateData *)spice_marshaller_reserve_space(channel->send_data.marshaller,
+                                                               sizeof(RecordMigrateData));
+    data->version = RECORD_MIG_VERSION;
+    data->serial = channel->send_data.serial;
+    data->start_time = record_channel->start_time;
+    data->mode = record_channel->mode;
+    data->mode_time = record_channel->mode_time;
+
+    channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
+    channel->send_data.header->size = channel->send_data.size - sizeof(SpiceDataHeader) - sizeof(SpiceDataHeader) - sizeof(*data);
 
-    snd_add_buf(channel, migrate, sizeof(*migrate));
-    channel->send_data.size = channel->send_data.header.size + sizeof(SpiceDataHeader);
-    channel->send_data.header.size -= sizeof(migrate->header);
-    channel->send_data.header.size -= sizeof(migrate->data);
     return snd_send_data(channel);
 }
 
@@ -662,46 +608,48 @@ static int snd_playback_send_write(PlaybackChannel *playback_channel)
 {
     SndChannel *channel = (SndChannel *)playback_channel;
     AudioFrame *frame;
+    SpiceMsgPlaybackPacket msg;
 
     if (!snd_reset_send_data(channel, SPICE_MSG_PLAYBACK_DATA)) {
         return FALSE;
     }
 
     frame = playback_channel->in_progress;
-    snd_add_buf(channel, &frame->time, sizeof(frame->time));
+    msg.time = frame->time;
+
+    spice_marshall_msg_playback_data(channel->send_data.marshaller, &msg);
+
     if (playback_channel->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) {
         int n = celt051_encode(playback_channel->celt_encoder, (celt_int16_t *)frame->samples, NULL,
-                               playback_channel->send_data.u.celt_buf, CELT_COMPRESSED_FRAME_BYTES);
+                               playback_channel->send_data.celt_buf, CELT_COMPRESSED_FRAME_BYTES);
         if (n < 0) {
             red_printf("celt encode failed");
             snd_disconnect_channel(channel);
             return FALSE;
         }
-        snd_add_buf(channel, playback_channel->send_data.u.celt_buf, n);
+        spice_marshaller_add_ref(channel->send_data.marshaller,
+                                 playback_channel->send_data.celt_buf, n);
     } else {
-        snd_add_buf(channel, frame->samples, sizeof(frame->samples));
+        spice_marshaller_add_ref(channel->send_data.marshaller,
+                                 (uint8_t *)frame->samples, sizeof(frame->samples));
     }
 
-    channel->send_data.size = channel->send_data.header.size + sizeof(SpiceDataHeader);
-
-    return snd_send_data(channel);
+    return snd_begin_send_message(channel);
 }
 
 static int playback_send_mode(PlaybackChannel *playback_channel)
 {
     SndChannel *channel = (SndChannel *)playback_channel;
-    SpiceMsgPlaybackMode *mode;
+    SpiceMsgPlaybackMode mode;
 
     if (!snd_reset_send_data(channel, SPICE_MSG_PLAYBACK_MODE)) {
         return FALSE;
     }
-    mode = &playback_channel->send_data.u.mode;
-    mode->time = reds_get_mm_time();
-    mode->mode = playback_channel->mode;
-    snd_add_buf(channel, mode, sizeof(*mode));
+    mode.time = reds_get_mm_time();
+    mode.mode = playback_channel->mode;
+    spice_marshall_msg_playback_mode(channel->send_data.marshaller, &mode);
 
-    channel->send_data.size = channel->send_data.header.size + sizeof(SpiceDataHeader);
-    return snd_send_data(channel);
+    return snd_begin_send_message(channel);
 }
 
 static void snd_playback_send(void* data)
@@ -815,6 +763,7 @@ static SndChannel *__new_channel(SndWorker *worker, int size, RedsStreamContext
     channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
     channel->recive_data.now = channel->recive_data.buf;
     channel->recive_data.end = channel->recive_data.buf + sizeof(channel->recive_data.buf);
+    channel->send_data.marshaller = spice_marshaller_new();
 
     peer->watch = core->watch_add(peer->socket, SPICE_WATCH_EVENT_READ,
                                   snd_event, channel);
commit cfc86f33409ad1e401ad9107d51aba68123971ec
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 11 17:18:33 2010 +0200

    Convert red_worker.c to use SpiceMarshaller for marshalling

diff --git a/server/red_worker.c b/server/red_worker.c
index efdfebc..80abb7c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -50,6 +50,8 @@
 #include "red_memslots.h"
 #include "jpeg_encoder.h"
 #include "rect.h"
+#include "marshaller.h"
+#include "generated_marshallers.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -71,7 +73,6 @@
 
 #define DISPLAY_CLIENT_TIMEOUT 15000000000ULL //nano
 #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
-#define DISPLAY_MAX_SUB_MESSAGES 10
 
 #define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
 
@@ -213,7 +214,6 @@ struct EventListener {
 
 enum {
     BUF_TYPE_RAW = 1,
-    BUF_TYPE_COMPRESS_BUF,
     BUF_TYPE_CHUNK,
 };
 
@@ -318,7 +318,6 @@ typedef struct LocalCursor {
     SpiceCursor red_cursor;
 } LocalCursor;
 
-#define MAX_SEND_BUFS 20
 #define MAX_BITMAPS 4
 #define MAX_PIPE_SIZE 50
 #define RECIVE_BUF_SIZE 1024
@@ -368,12 +367,9 @@ struct RedChannel {
 
     struct {
         int blocked;
-        SpiceDataHeader header;
-        union {
-            SpiceMsgSetAck ack;
-        } u;
-        uint32_t n_bufs;
-        BufDescriptor bufs[MAX_SEND_BUFS];
+        uint64_t serial;
+        SpiceDataHeader *header;
+        SpiceMarshaller *marshaller;
         uint32_t size;
         uint32_t pos;
         void *item;
@@ -662,51 +658,12 @@ struct DisplayChannel {
     QRegion surface_client_lossy_region[NUM_SURFACES];
 
     struct {
-        union {
-            SpiceMsgDisplayDrawFill fill;
-            SpiceMsgDisplayDrawOpaque opaque;
-            SpiceMsgDisplayDrawCopy copy;
-            SpiceMsgDisplayDrawTransparent transparent;
-            SpiceMsgDisplayDrawAlphaBlend alpha_blend;
-            SpiceMsgDisplayCopyBits copy_bits;
-            SpiceMsgDisplayDrawBlend blend;
-            SpiceMsgDisplayDrawRop3 rop3;
-            SpiceMsgDisplayDrawBlackness blackness;
-            SpiceMsgDisplayDrawWhiteness whiteness;
-            SpiceMsgDisplayDrawInvers invers;
-            SpiceMsgDisplayDrawStroke stroke;
-            SpiceMsgDisplayDrawText text;
-            SpiceMsgDisplayMode mode;
-            SpiceMsgDisplayInvalOne inval_one;
-            SpiceMsgSurfaceCreate surface_create;
-            SpiceMsgSurfaceDestroy surface_destroy;
-            WaitForChannels wait;
-            struct {
-                SpiceMsgDisplayStreamCreate message;
-                uint32_t num_rects;
-            } stream_create;
-            SpiceMsgDisplayStreamClip stream_clip;
-            SpiceMsgDisplayStreamData stream_data;
-            SpiceMsgDisplayStreamDestroy stream_destroy;
-            SpiceMsgMigrate migrate;
-            DisplayChannelMigrateData migrate_data;
-        } u;
-
-        uint32_t bitmap_pos;
-        RedImage images[MAX_BITMAPS];
-
         uint32_t stream_outbuf_size;
         uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
 
         RedCompressBuf *free_compress_bufs;
         RedCompressBuf *used_compress_bufs;
 
-        struct {
-            SpiceSubMessageList sub_list;
-            uint32_t sub_messages[DISPLAY_MAX_SUB_MESSAGES];
-        } sub_list;
-        SpicedSubMessage sub_header[DISPLAY_MAX_SUB_MESSAGES];
-
         FreeList free_list;
     } send_data;
 
@@ -734,16 +691,6 @@ typedef struct CursorChannel {
     long cursor_cache_available;
     uint32_t cursor_cache_items;
 
-    struct {
-        union {
-            SpiceMsgCursorInit cursor_init;
-            SpiceMsgCursorSet cursor_set;
-            SpiceMsgCursorMove cursor_move;
-            SpiceMsgCursorTrail cursor_trail;
-            SpiceMsgDisplayInvalOne inval_one;
-            SpiceMsgMigrate migrate;
-        } u;
-    } send_data;
 #ifdef RED_STATISTICS
     StatNodeRef stat;
 #endif
@@ -1403,7 +1350,7 @@ static inline void red_pipe_add_image_item_after(RedWorker *worker, ImageItem *i
 
 static inline uint64_t channel_message_serial(RedChannel *channel)
 {
-    return channel->send_data.header.serial;
+    return channel->send_data.header->serial;
 }
 
 static void release_image_item(ImageItem *item)
@@ -5082,7 +5029,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
         }
         n++;
         if ((worker->display_channel && worker->display_channel->base.send_data.blocked) ||
-                                                            red_now() - start > 10 * 1000 * 1000) {
+            red_now() - start > 10 * 1000 * 1000) {
             worker->epoll_timeout = 0;
             return n;
         }
@@ -5204,100 +5151,226 @@ static void red_add_surface_image(RedWorker *worker, int surface_id)
     display_channel_push(worker);
 }
 
-static void inline __add_buf(RedChannel *channel, uint32_t type, void *data, uint32_t size,
-                             uint32_t slot_id, uint32_t group_id)
+static uint8_t *chunk_linearize(RedWorker *worker, QXLDataChunk *first_chunk,
+                                int memslot_id, uint32_t group_id, size_t expected_size,
+                                int *free_chunk)
 {
-    int pos = channel->send_data.n_bufs++;
-    ASSERT(pos < MAX_SEND_BUFS);
-    channel->send_data.bufs[pos].type = type;
-    channel->send_data.bufs[pos].size = size;
-    channel->send_data.bufs[pos].data = data;
-    channel->send_data.bufs[pos].slot_id = slot_id;
-    channel->send_data.bufs[pos].group_id = group_id;
+    uint8_t *data, *ptr;
+    QXLDataChunk *chunk;
+    int data_size;
+    QXLPHYSICAL next_chunk;
+
+    data_size = first_chunk->data_size;
+    next_chunk = first_chunk->next_chunk;
+
+    if (next_chunk == 0) {
+        ASSERT(expected_size <= data_size);
+        validate_virt(&worker->mem_slots, (unsigned long)first_chunk->data, memslot_id, data_size, group_id);
+        *free_chunk = FALSE;
+        return first_chunk->data;
+    }
+
+    data = spice_malloc(expected_size);
+    *free_chunk = TRUE;
+
+    ptr = data;
+    chunk = first_chunk;
+    while (chunk != NULL && expected_size > 0) {
+        data_size = chunk->data_size;
+        next_chunk = chunk->next_chunk;
+
+        if (data_size > expected_size) {
+            data_size = expected_size;
+        }
+        expected_size -= data_size;
+
+        if (data_size) {
+            validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id);
+            memcpy(ptr, chunk->data, data_size);
+            ptr += data_size;
+        }
+
+        chunk = next_chunk ?
+            (QXLDataChunk *)get_virt(&worker->mem_slots, next_chunk, sizeof(QXLDataChunk),
+                                     group_id) :
+            NULL;
+    }
+    ASSERT(expected_size == 0)
+
+    return data;
+}
+
+typedef struct {
+    uint32_t type;
+    void *data;
+    uint32_t size;
+    uint32_t slot_id;
+    uint32_t group_id;
+} AddBufInfo;
+
+static void marshaller_add_compressed(RedWorker *worker, SpiceMarshaller *m,
+                                      RedCompressBuf *comp_buf, size_t size)
+{
+    size_t max = size;
+    size_t now;
+    do {
+        ASSERT(comp_buf);
+        now = MIN(sizeof(comp_buf->buf), max);
+        max -= now;
+        spice_marshaller_add_ref(m, (uint8_t*)comp_buf->buf, now);
+        comp_buf = comp_buf->send_next;
+    } while (max);
 }
 
-static void add_buf(RedChannel *channel, uint32_t type, void *data, uint32_t size,
-                    uint32_t slot_id, uint32_t group_id)
+static void marshaller_add_chunk(RedWorker *worker, SpiceMarshaller *m, QXLDataChunk *chunk, size_t size,
+                                 int memslot_id, uint32_t group_id)
 {
-    __add_buf(channel, type, data, size, slot_id, group_id);
-    channel->send_data.header.size += size;
+    while (chunk != NULL && size > 0) {
+        int data_size = chunk->data_size;
+
+        if (data_size > size)
+            data_size = size;
+        size -= data_size;
+
+        if (data_size) {
+            validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id);
+            spice_marshaller_add_ref(m, (uint8_t *)chunk->data, data_size);
+        }
+        chunk = chunk->next_chunk ?
+            (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk, sizeof(QXLDataChunk),
+                                     group_id) :
+            NULL;
+    }
 }
 
-static void fill_path(DisplayChannel *display_channel, QXLPHYSICAL *in_path, uint32_t group_id)
+static void add_buf_from_info(RedChannel *channel, SpiceMarshaller *m, AddBufInfo *info)
+{
+    QXLDataChunk *chunk;
+
+    if (info->data) {
+        switch (info->type) {
+        case BUF_TYPE_RAW:
+            spice_marshaller_add_ref(m, info->data, info->size);
+            break;
+        case BUF_TYPE_CHUNK:
+            chunk = (QXLDataChunk *)info->data;
+            marshaller_add_chunk(channel->worker, m, chunk,
+                                 info->size, info->slot_id, info->group_id);
+            break;
+        }
+    }
+}
+
+
+static void fill_path(DisplayChannel *display_channel, SpiceMarshaller *m,
+                      QXLPHYSICAL in_path, uint32_t group_id)
 {
     RedWorker *worker;
     RedChannel *channel = &display_channel->base;
     int memslot_id;
+    uint8_t *path_data, *p;
+    int free_path_data;
     worker = channel->worker;
-    ASSERT(in_path && *in_path);
-    memslot_id  = get_memslot_id(&worker->mem_slots, *in_path);
-    QXLPath *path = (QXLPath *)get_virt(&worker->mem_slots, *in_path, sizeof(QXLPath), group_id);
-    *in_path = channel->send_data.header.size;
-    add_buf(channel, BUF_TYPE_RAW, &path->data_size, sizeof(uint32_t), 0, 0);
-    add_buf(channel, BUF_TYPE_CHUNK, &path->chunk, path->data_size, memslot_id, group_id);
+    size_t data_size;
+    ASSERT(in_path);
+    memslot_id  = get_memslot_id(&worker->mem_slots, in_path);
+
+    QXLPath *path = (QXLPath *)get_virt(&worker->mem_slots, in_path, sizeof(QXLPath), group_id);
+
+    data_size = path->data_size;
+    spice_marshaller_add_uint32(m, data_size);
+    path_data = chunk_linearize(worker, &path->chunk,
+                                memslot_id, group_id, data_size,
+                                &free_path_data);
+
+    p = path_data;
+    while (p < path_data + data_size) {
+        p = spice_marshall_PathSegment(m, (SpicePathSeg *)p);
+    }
+
+    if (free_path_data) {
+        free(path_data);
+    }
 }
 
-static void fill_str(DisplayChannel *display_channel, QXLPHYSICAL *in_str, uint32_t group_id)
+static void fill_str(DisplayChannel *display_channel, SpiceMarshaller *m,
+                     QXLPHYSICAL in_str, uint32_t group_id)
 {
     RedWorker *worker;
     RedChannel *channel = &display_channel->base;
     int memslot_id;
+    SpiceString string;
+
     worker = channel->worker;
-    ASSERT(in_str && *in_str);
-    memslot_id  = get_memslot_id(&worker->mem_slots, *in_str);
-    QXLString *str = (QXLString *)get_virt(&worker->mem_slots, *in_str, sizeof(QXLString), group_id);
-    *in_str = channel->send_data.header.size;
-    add_buf(channel, BUF_TYPE_RAW, &str->length, sizeof(uint32_t), 0, 0);
-    add_buf(channel, BUF_TYPE_CHUNK, &str->chunk, str->data_size, memslot_id, group_id);
+
+    ASSERT(in_str);
+    memslot_id  = get_memslot_id(&worker->mem_slots, in_str);
+    QXLString *str = (QXLString *)get_virt(&worker->mem_slots, in_str, sizeof(QXLString), group_id);
+    string.length = str->length;
+    string.flags = str->flags;
+    spice_marshall_String(m, &string);
+    /* TODO: This doesn't properly marshal the glyph data */
+    marshaller_add_chunk(worker, m, &str->chunk,
+                         str->data_size, memslot_id, group_id);
 }
 
-static inline void fill_rects_clip(RedChannel *channel, QXLPHYSICAL *in_clip, uint32_t group_id)
+static inline void fill_rects_clip(RedChannel *channel, SpiceMarshaller *m, QXLPHYSICAL in_clip, uint32_t group_id)
 {
     RedWorker *worker = channel->worker;
     QXLClipRects *clip;
-    int memslot_id = get_memslot_id(&worker->mem_slots, *in_clip);
+    uint8_t *rects, *r;
+    int free_rects, i;
+    int memslot_id = get_memslot_id(&worker->mem_slots, in_clip);
 
-    ASSERT(in_clip && *in_clip);
-    clip = (QXLClipRects *)get_virt(&worker->mem_slots, *in_clip, sizeof(QXLClipRects), group_id);
-    *in_clip = channel->send_data.header.size;
-    add_buf(channel, BUF_TYPE_RAW, &clip->num_rects, sizeof(uint32_t), 0, 0);
-    add_buf(channel, BUF_TYPE_CHUNK, &clip->chunk, clip->num_rects * sizeof(SpiceRect), memslot_id,
-            group_id);
-}
+    ASSERT(in_clip);
+    clip = (QXLClipRects *)get_virt(&worker->mem_slots, in_clip, sizeof(QXLClipRects), group_id);
+    spice_marshaller_add_uint32(m, clip->num_rects);
+    rects = chunk_linearize(worker, &clip->chunk,
+                            memslot_id, group_id, clip->num_rects * sizeof(SpiceRect),
+                            &free_rects);
 
-static void fill_base(DisplayChannel *display_channel, SpiceMsgDisplayBase *base, Drawable *drawable,
-                      uint32_t size, uint32_t surface_id)
-{
-    RedChannel *channel = &display_channel->base;
-    add_buf(channel, BUF_TYPE_RAW, base, size, 0, 0);
-    base->surface_id = surface_id;
-    base->box = drawable->qxl_drawable->bbox;
-    base->clip = drawable->qxl_drawable->clip;
+    r = rects;
+    for (i = 0; i < clip->num_rects; i++) {
+        r = spice_marshall_Rect(m, (SpiceRect *)r);
+    }
 
-    if (base->clip.type == SPICE_CLIP_TYPE_RECTS) {
-        fill_rects_clip(channel, &base->clip.data, drawable->group_id);
-    } else if (base->clip.type == SPICE_CLIP_TYPE_PATH) {
-        fill_path(display_channel, &base->clip.data, drawable->group_id);
+    if (free_rects) {
+        free(rects);
     }
 }
 
-static inline RedImage *alloc_image(DisplayChannel *display_channel)
+static void fill_base(DisplayChannel *display_channel, Drawable *drawable)
 {
-    ASSERT(display_channel->send_data.bitmap_pos < MAX_BITMAPS);
-    return &display_channel->send_data.images[display_channel->send_data.bitmap_pos++];
+    RedChannel *channel = &display_channel->base;
+    SpiceMsgDisplayBase base;
+    SpiceMarshaller *cliprects_data_out, *clippath_data_out;
+
+    base.surface_id = drawable->surface_id;
+    base.box = drawable->qxl_drawable->bbox;
+    base.clip = drawable->qxl_drawable->clip;
+
+    spice_marshall_DisplayBase(channel->send_data.marshaller, &base,
+                              &cliprects_data_out, &clippath_data_out);
+    if (cliprects_data_out) {
+        fill_rects_clip(channel, cliprects_data_out, base.clip.data, drawable->group_id);
+    } else if (clippath_data_out) {
+        fill_path(display_channel, clippath_data_out, base.clip.data, drawable->group_id);
+    }
 }
 
 /* io_palette is relative address of the palette*/
 static inline void fill_palette(DisplayChannel *display_channel, SPICE_ADDRESS *io_palette, uint8_t *flags,
-                                uint32_t group_id)
+                                uint32_t group_id, SpicePalette **palette_out)
 {
     RedChannel *channel = &display_channel->base;
     RedWorker *worker = channel->worker;
     SpicePalette *palette;
 
+    *palette_out = NULL;
     if (!(*io_palette)) {
         return;
     }
+
     palette = (SpicePalette *)get_virt(&worker->mem_slots, *io_palette, sizeof(SpicePalette), group_id);
     if (palette->unique) {
         if (red_palette_cache_find(display_channel, palette->unique)) {
@@ -5309,9 +5382,7 @@ static inline void fill_palette(DisplayChannel *display_channel, SPICE_ADDRESS *
             *flags |= SPICE_BITMAP_FLAGS_PAL_CACHE_ME;
         }
     }
-    *io_palette = channel->send_data.header.size;
-    add_buf(channel, BUF_TYPE_RAW, palette,
-            sizeof(SpicePalette) + palette->num_ents * sizeof(uint32_t), 0, 0);
+    *palette_out = palette;
 }
 
 static inline RedCompressBuf *red_display_alloc_compress_buf(DisplayChannel *display_channel)
@@ -6114,11 +6185,9 @@ static const LzImageType MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[] = {
 };
 
 typedef struct compress_send_data_t {
-    uint32_t raw_size;
     void*    comp_buf;
     uint32_t comp_buf_size;
-    SPICE_ADDRESS  *plt_ptr;
-    uint8_t    *flags_ptr;
+    SpicePalette *lzplt_palette;
     int is_lossy;
 } compress_send_data_t;
 
@@ -6180,15 +6249,11 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
     dest->descriptor.type = SPICE_IMAGE_TYPE_GLZ_RGB;
     dest->lz_rgb.data_size = size;
 
-    o_comp_data->raw_size = sizeof(SpiceLZRGBImage);
     o_comp_data->comp_buf = glz_data->data.bufs_head;
     o_comp_data->comp_buf_size = size;
-    o_comp_data->plt_ptr = NULL;
-    o_comp_data->flags_ptr = NULL;
-    o_comp_data->is_lossy = FALSE;
 
     stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y,
-                      o_comp_data->comp_buf_size);
+                      size);
     return TRUE;
 }
 
@@ -6256,25 +6321,21 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
         dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_RGB;
         dest->lz_rgb.data_size = size;
 
-        o_comp_data->raw_size = sizeof(SpiceLZRGBImage);
         o_comp_data->comp_buf = lz_data->data.bufs_head;
         o_comp_data->comp_buf_size = size;
-        o_comp_data->plt_ptr = NULL;
-        o_comp_data->flags_ptr = NULL;
     } else {
         dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_PLT;
         dest->lz_plt.data_size = size;
         dest->lz_plt.flags = src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
         dest->lz_plt.palette = src->palette;
 
-        o_comp_data->raw_size = sizeof(SpiceLZPLTImage);
         o_comp_data->comp_buf = lz_data->data.bufs_head;
         o_comp_data->comp_buf_size = size;
-        o_comp_data->plt_ptr = &(dest->lz_plt.palette);
-        o_comp_data->flags_ptr = &(dest->lz_plt.flags);
+
+        fill_palette(display_channel, &(dest->lz_plt.palette), &(dest->lz_plt.flags),
+                     group_id, &o_comp_data->lzplt_palette);
     }
 
-    o_comp_data->is_lossy = FALSE;
     stat_compress_add(&display_channel->lz_stat, start_time, src->stride * src->y,
                       o_comp_data->comp_buf_size);
     return TRUE;
@@ -6412,12 +6473,10 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, RedImage *de
     dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG;
     dest->jpeg.data_size = size;
 
-    o_comp_data->raw_size = sizeof(SpiceJPEGImage);
     o_comp_data->comp_buf = jpeg_data->data.bufs_head;
     o_comp_data->comp_buf_size = size;
-    o_comp_data->plt_ptr = NULL;
-    o_comp_data->flags_ptr = NULL;
     o_comp_data->is_lossy = TRUE;
+
     stat_compress_add(&display_channel->jpeg_stat, start_time, src->stride * src->y,
                       o_comp_data->comp_buf_size);
     return TRUE;
@@ -6559,12 +6618,8 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, RedIm
     dest->descriptor.type = SPICE_IMAGE_TYPE_QUIC;
     dest->quic.data_size = size << 2;
 
-    o_comp_data->raw_size = sizeof(SpiceQUICImage);
     o_comp_data->comp_buf = quic_data->data.bufs_head;
     o_comp_data->comp_buf_size = size << 2;
-    o_comp_data->plt_ptr = NULL;
-    o_comp_data->flags_ptr = NULL;
-    o_comp_data->is_lossy = FALSE;
 
     stat_compress_add(&display_channel->quic_stat, start_time, src->stride * src->y,
                       o_comp_data->comp_buf_size);
@@ -6658,8 +6713,9 @@ static inline int red_compress_image(DisplayChannel *display_channel,
             /* using the global dictionary only if it is not freezed */
             pthread_rwlock_rdlock(&display_channel->glz_dict->encode_lock);
             if (!display_channel->glz_dict->migrate_freeze) {
-                ret = red_glz_compress_image(
-                        display_channel, dest, src, drawable, o_comp_data);
+                ret = red_glz_compress_image(display_channel,
+                                             dest, src,
+                                             drawable, o_comp_data);
             } else {
                 glz = FALSE;
             }
@@ -6714,58 +6770,60 @@ typedef enum {
 
 /* if the number of times fill_bits can be called per one qxl_drawable increases -
    MAX_LZ_DRAWABLE_INSTANCES must be increased as well */
-static FillBitsType fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap,
-                              Drawable *drawable, int can_lossy)
+static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *m,
+                              QXLPHYSICAL in_bitmap, Drawable *drawable, int can_lossy)
 {
     RedChannel *channel = &display_channel->base;
     RedWorker *worker = channel->worker;
-    RedImage *image;
+    RedImage image;
     QXLImage *qxl_image;
     uint8_t *data;
     int memslot_id;
-    compress_send_data_t comp_send_data;
+    compress_send_data_t comp_send_data = {0};
+    SpiceMarshaller *bitmap_palette_out, *data_out, *lzplt_palette_out;
 
-    if (*in_bitmap == 0) {
+    if (in_bitmap == 0) {
         ASSERT(drawable->self_bitmap);
         qxl_image = (QXLImage *)drawable->self_bitmap;
     } else {
-        qxl_image = (QXLImage *)get_virt(&worker->mem_slots, *in_bitmap, sizeof(QXLImage),
+        qxl_image = (QXLImage *)get_virt(&worker->mem_slots, in_bitmap, sizeof(QXLImage),
                                          drawable->group_id);
     }
 
-    image = alloc_image(display_channel);
-
-    image->descriptor.id = qxl_image->descriptor.id;
-    image->descriptor.type = qxl_image->descriptor.type;
-    image->descriptor.flags = 0;
+    image.descriptor.id = qxl_image->descriptor.id;
+    image.descriptor.type = qxl_image->descriptor.type;
+    image.descriptor.flags = 0;
     if (qxl_image->descriptor.flags & QXL_IMAGE_HIGH_BITS_SET) {
-        image->descriptor.flags |= SPICE_IMAGE_FLAGS_HIGH_BITS_SET;
+        image.descriptor.flags |= SPICE_IMAGE_FLAGS_HIGH_BITS_SET;
     }
-    image->descriptor.width = qxl_image->descriptor.width;
-    image->descriptor.height = qxl_image->descriptor.height;
+    image.descriptor.width = qxl_image->descriptor.width;
+    image.descriptor.height = qxl_image->descriptor.height;
 
-    memslot_id = get_memslot_id(&worker->mem_slots, *in_bitmap);
-    *in_bitmap = channel->send_data.header.size;
+    memslot_id = get_memslot_id(&worker->mem_slots, in_bitmap);
     if ((qxl_image->descriptor.flags & QXL_IMAGE_CACHE)) {
         int lossy_cache_item;
-        if (pixmap_cache_hit(display_channel->pixmap_cache, image->descriptor.id,
+        if (pixmap_cache_hit(display_channel->pixmap_cache, image.descriptor.id,
                              &lossy_cache_item, display_channel)) {
             if (can_lossy || !lossy_cache_item) {
                 if (!display_channel->enable_jpeg || lossy_cache_item) {
-                    image->descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
+                    image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
                 } else {
                     // making sure, in multiple monitor scenario, that lossy items that
                     // should have been replaced with lossless data by one display channel,
                     // will be retrieved as lossless by another display channel.
-                    image->descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS;
+                    image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS;
                 }
-                add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceImageDescriptor), 0, 0);
+                spice_marshall_Image(m, (SpiceImageDescriptor *)&image,
+                                     &bitmap_palette_out, &data_out, &lzplt_palette_out);
+                ASSERT(bitmap_palette_out == NULL);
+                ASSERT(data_out == NULL);
+                ASSERT(lzplt_palette_out == NULL);
                 stat_inc_counter(display_channel->cache_hits_counter, 1);
                 return FILL_BITS_TYPE_CACHE;
             } else {
                 pixmap_cache_set_lossy(display_channel->pixmap_cache, qxl_image->descriptor.id,
                                        FALSE);
-                image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME;
+                image.descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME;
             }
         }
     }
@@ -6779,13 +6837,17 @@ static FillBitsType fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_b
         validate_surface(worker, surface_id);
 
         surface = &worker->surfaces[surface_id];
-        image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
-        image->descriptor.flags = 0;
-        image->descriptor.width = surface->context.width;
-        image->descriptor.height = surface->context.height;
-
-        image->surface.surface_id = surface_id;
-        add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceSurfaceImage), 0, 0);
+        image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
+        image.descriptor.flags = 0;
+        image.descriptor.width = surface->context.width;
+        image.descriptor.height = surface->context.height;
+
+        image.surface.surface_id = surface_id;
+        spice_marshall_Image(m, (SpiceImageDescriptor *)&image,
+                             &bitmap_palette_out, &data_out, &lzplt_palette_out);
+        ASSERT(bitmap_palette_out == NULL);
+        ASSERT(data_out == NULL);
+        ASSERT(lzplt_palette_out == NULL);
         return FILL_BITS_TYPE_SURFACE;
     }
     case SPICE_IMAGE_TYPE_BITMAP:
@@ -6795,101 +6857,114 @@ static FillBitsType fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_b
         /* Images must be added to the cache only after they are compressed
            in order to prevent starvation in the client between pixmap_cache and
            global dictionary (in cases of multiple monitors) */
-        if (!red_compress_image(display_channel, image, &qxl_image->bitmap,
+        if (!red_compress_image(display_channel, &image, &qxl_image->bitmap,
                                 drawable, can_lossy, &comp_send_data)) {
             uint32_t y;
             uint32_t stride;
             SPICE_ADDRESS image_data;
+            SpicePalette *palette;
+
+            red_display_add_image_to_pixmap_cache(display_channel, qxl_image, &image, FALSE);
 
-            red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image, FALSE);
+            image.bitmap = qxl_image->bitmap;
+            y = image.bitmap.y;
+            stride = image.bitmap.stride;
+            image_data = image.bitmap.data;
+            image.bitmap.flags = image.bitmap.flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
 
-            image->bitmap = qxl_image->bitmap;
-            y = image->bitmap.y;
-            stride = image->bitmap.stride;
-            image_data = image->bitmap.data;
-            image->bitmap.flags = image->bitmap.flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
+            fill_palette(display_channel, &image.bitmap.palette, &image.bitmap.flags,
+                         drawable->group_id, &palette);
+            spice_marshall_Image(m, (SpiceImageDescriptor *)&image,
+                                 &bitmap_palette_out, &data_out, &lzplt_palette_out);
+            ASSERT(lzplt_palette_out == NULL);
+
+            if (palette) {
+                spice_marshall_Palette(bitmap_palette_out, palette);
+            }
 
-            add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceBitmapImage), 0, 0);
-            fill_palette(display_channel, &(image->bitmap.palette), &(image->bitmap.flags),
-                         drawable->group_id);
-            image->bitmap.data = channel->send_data.header.size;
             if (qxl_image->bitmap.flags & QXL_BITMAP_DIRECT) {
                 data = (uint8_t *)get_virt(&worker->mem_slots, image_data, stride * y, drawable->group_id);
-                add_buf(channel, BUF_TYPE_RAW, data, y * stride, 0, 0);
+                spice_marshaller_add_ref(data_out, data, y * stride);
             } else {
                 data = (uint8_t *)get_virt(&worker->mem_slots, image_data, sizeof(QXLDataChunk),
                                            drawable->group_id);
-                add_buf(channel, BUF_TYPE_CHUNK, data, y * stride, memslot_id, drawable->group_id);
+                marshaller_add_chunk(worker, data_out, (QXLDataChunk *)data,
+                                     y * stride, memslot_id, drawable->group_id);
             }
             return FILL_BITS_TYPE_BITMAP;
         } else {
-            red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image,
+            red_display_add_image_to_pixmap_cache(display_channel, qxl_image, &image,
                                                   comp_send_data.is_lossy);
 
-            add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, image, comp_send_data.raw_size,
-                    0, 0);
-            add_buf((RedChannel *)display_channel, BUF_TYPE_COMPRESS_BUF,
-                    comp_send_data.comp_buf, comp_send_data.comp_buf_size, 0, 0);
+            spice_marshall_Image(m, (SpiceImageDescriptor *)&image,
+                                 &bitmap_palette_out, &data_out, &lzplt_palette_out);
+            ASSERT(bitmap_palette_out == NULL);
 
-            if (comp_send_data.plt_ptr != NULL) {
-                fill_palette(display_channel, comp_send_data.plt_ptr, comp_send_data.flags_ptr,
-                             drawable->group_id);
+            marshaller_add_compressed(worker, m, comp_send_data.comp_buf,
+                                      comp_send_data.comp_buf_size);
+
+            if (comp_send_data.lzplt_palette) {
+                spice_marshall_Palette(lzplt_palette_out, comp_send_data.lzplt_palette);
             }
+
             ASSERT(!comp_send_data.is_lossy || can_lossy);
             return (comp_send_data.is_lossy ? FILL_BITS_TYPE_COMPRESS_LOSSY :
                                               FILL_BITS_TYPE_COMPRESS_LOSSLESS);
         }
         break;
     case SPICE_IMAGE_TYPE_QUIC:
-        red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image, FALSE);
-        image->quic = qxl_image->quic;
-        add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceQUICImage), 0, 0);
-        add_buf(channel, BUF_TYPE_CHUNK, qxl_image->quic.data, qxl_image->quic.data_size,
-                memslot_id, drawable->group_id);
+        red_display_add_image_to_pixmap_cache(display_channel, qxl_image, &image, FALSE);
+        image.quic = qxl_image->quic;
+        spice_marshall_Image(m, (SpiceImageDescriptor *)&image,
+                             &bitmap_palette_out, &data_out, &lzplt_palette_out);
+        ASSERT(bitmap_palette_out == NULL);
+        ASSERT(lzplt_palette_out == NULL);
+        marshaller_add_chunk(worker, m, (QXLDataChunk *)qxl_image->quic.data,
+                             qxl_image->quic.data_size,
+                             memslot_id, drawable->group_id);
         return FILL_BITS_TYPE_COMPRESS_LOSSLESS;
     default:
-        red_error("invalid image type %u", image->descriptor.type);
+        red_error("invalid image type %u", image.descriptor.type);
     }
 }
 
-static void fill_brush(DisplayChannel *display_channel, SpiceBrush *brush, Drawable *drawable)
+static void fill_mask(DisplayChannel *display_channel, SpiceMarshaller *m,
+                      SPICE_ADDRESS mask_bitmap, Drawable *drawable)
 {
-    if (brush->type == SPICE_BRUSH_TYPE_PATTERN) {
-        fill_bits(display_channel, &brush->u.pattern.pat, drawable, FALSE);
-    }
-}
-
-static void fill_mask(DisplayChannel *display_channel, SpiceQMask *mask, Drawable *drawable)
-{
-    if (mask->bitmap) {
+    if (mask_bitmap && m) {
         if (display_channel->base.worker->image_compression != SPICE_IMAGE_COMPRESS_OFF) {
             spice_image_compression_t save_img_comp =
                 display_channel->base.worker->image_compression;
             display_channel->base.worker->image_compression = SPICE_IMAGE_COMPRESS_OFF;
-            fill_bits(display_channel, &mask->bitmap, drawable, FALSE);
+            fill_bits(display_channel, m, mask_bitmap, drawable, FALSE);
             display_channel->base.worker->image_compression = save_img_comp;
         } else {
-            fill_bits(display_channel, &mask->bitmap, drawable, FALSE);
+            fill_bits(display_channel, m, mask_bitmap, drawable, FALSE);
         }
     }
 }
 
-static void fill_attr(DisplayChannel *display_channel, SpiceLineAttr *attr, uint32_t group_id)
+static void fill_attr(DisplayChannel *display_channel, SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id)
 {
-    if (attr->style_nseg) {
-        RedChannel *channel = &display_channel->base;
-        uint8_t *buf = (uint8_t *)get_virt(&channel->worker->mem_slots, attr->style,
-                                           attr->style_nseg * sizeof(uint32_t), group_id);
-        ASSERT(attr->style);
-        attr->style = channel->send_data.header.size;
-        add_buf(channel, BUF_TYPE_RAW, buf, attr->style_nseg * sizeof(uint32_t), 0, 0);
+    RedChannel *channel = &display_channel->base;
+    uint32_t *style;
+    int i;
+
+    if (m && attr->style_nseg) {
+        style = (uint32_t *)get_virt(&channel->worker->mem_slots, attr->style,
+                                     attr->style_nseg * sizeof(uint32_t), group_id);
+        for (i = 0 ; i < attr->style_nseg; i++) {
+            spice_marshaller_add_uint32(m, style[i]);
+        }
     }
 }
 
-static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor, CursorItem *cursor)
+static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor, CursorItem *cursor, AddBufInfo *addbuf)
 {
     RedChannel *channel = &cursor_channel->base;
 
+    addbuf->data = NULL;
+
     if (!cursor) {
         red_cursor->flags = SPICE_CURSOR_FLAGS_NONE;
         return;
@@ -6916,35 +6991,41 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
         }
 
         if (qxl_cursor->data_size) {
-            add_buf(channel, BUF_TYPE_CHUNK, &qxl_cursor->chunk, qxl_cursor->data_size,
-                    get_memslot_id(&channel->worker->mem_slots, cursor_cmd->u.set.shape), cursor->group_id);
+            addbuf->type = BUF_TYPE_CHUNK;
+            addbuf->data = &qxl_cursor->chunk;
+            addbuf->size = qxl_cursor->data_size;
+            addbuf->slot_id = get_memslot_id(&channel->worker->mem_slots, cursor_cmd->u.set.shape);
+            addbuf->group_id = cursor->group_id;
         }
     } else {
         LocalCursor *local_cursor;
         ASSERT(cursor->type == CURSOR_TYPE_LOCAL);
         local_cursor = (LocalCursor *)cursor;
         *red_cursor = local_cursor->red_cursor;
-        add_buf(channel, BUF_TYPE_RAW, local_cursor->red_cursor.data, local_cursor->data_size, 0,
-                0);
+        addbuf->type = BUF_TYPE_RAW;
+        addbuf->data = local_cursor->red_cursor.data;
+        addbuf->size = local_cursor->data_size;
+        addbuf->slot_id = 0;
+        addbuf->group_id = 0;
     }
 }
 
 static inline void red_channel_reset_send_data(RedChannel *channel)
 {
+    spice_marshaller_reset(channel->send_data.marshaller);
+    channel->send_data.header = (SpiceDataHeader *)
+        spice_marshaller_reserve_space(channel->send_data.marshaller, sizeof(SpiceDataHeader));
+    spice_marshaller_set_base(channel->send_data.marshaller, sizeof(SpiceDataHeader));
     channel->send_data.pos = 0;
-    channel->send_data.n_bufs = 1;
-    channel->send_data.header.size = 0;
-    channel->send_data.header.sub_list = 0;
-    ++channel->send_data.header.serial;
-    channel->send_data.bufs[0].type = BUF_TYPE_RAW;
-    channel->send_data.bufs[0].size = sizeof(SpiceDataHeader);
-    channel->send_data.bufs[0].data = (void *)&channel->send_data.header;
+    channel->send_data.header->type = 0;
+    channel->send_data.header->size = 0;
+    channel->send_data.header->sub_list = 0;
+    channel->send_data.header->serial = ++channel->send_data.serial;
 }
 
 static inline void red_display_reset_send_data(DisplayChannel *channel)
 {
     red_channel_reset_send_data((RedChannel *)channel);
-    channel->send_data.bitmap_pos = 0;
     red_display_reset_compress_buf(channel);
     channel->send_data.free_list.res->count = 0;
     memset(channel->send_data.free_list.sync, 0, sizeof(channel->send_data.free_list.sync));
@@ -7323,13 +7404,39 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
     }
 }
 
-static inline void red_lossy_send_qxl_draw_fill(RedWorker *worker,
-                                                DisplayChannel *display_channel,
-                                                Drawable *item)
+static void red_send_qxl_draw_fill(RedWorker *worker,
+                                   DisplayChannel *display_channel,
+                                   Drawable *item)
+{
+    RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *brush_pat_out;
+    SpiceMarshaller *mask_bitmap_out;
+    SpiceFill fill;
+
+    fill_base(display_channel, item);
+
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_FILL;
+    fill = drawable->u.fill;
+    spice_marshall_Fill(channel->send_data.marshaller,
+                        &fill,
+                        &brush_pat_out,
+                        &mask_bitmap_out);
+
+    if (brush_pat_out) {
+        fill_bits(display_channel, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE);
+    }
+
+    fill_mask(display_channel, mask_bitmap_out, fill.mask.bitmap, item);
+}
+
+
+static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
+                                         DisplayChannel *display_channel,
+                                         Drawable *item)
 {
     QXLDrawable *drawable = item->qxl_drawable;
 
-    RedChannel *channel = &display_channel->base;
     int dest_allowed_lossy = FALSE;
     int dest_is_lossy = FALSE;
     SpiceRect dest_lossy_area;
@@ -7342,23 +7449,19 @@ static inline void red_lossy_send_qxl_draw_fill(RedWorker *worker,
     dest_allowed_lossy = !((rop & SPICE_ROPD_OP_OR) ||
                            (rop & SPICE_ROPD_OP_AND) ||
                            (rop & SPICE_ROPD_OP_XOR));
-    
+
     brush_is_lossy = is_brush_lossy(display_channel, &drawable->u.fill.brush, item,
                                     &brush_bitmap_data);
     if (!dest_allowed_lossy) {
         dest_is_lossy = is_surface_area_lossy(display_channel, item->surface_id, &drawable->bbox,
                                               &dest_lossy_area);
     }
-                  
-    if (!dest_is_lossy && 
+
+    if (!dest_is_lossy &&
         !(brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE))) {
         int has_mask = !!drawable->u.fill.mask.bitmap;
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_FILL;
-        fill_base(display_channel, &display_channel->send_data.u.fill.base, item,
-                  sizeof(SpiceMsgDisplayDrawFill), item->surface_id);
-        display_channel->send_data.u.fill.data = drawable->u.fill;
-        fill_brush(display_channel, &display_channel->send_data.u.fill.data.brush, item);
-        fill_mask(display_channel, &display_channel->send_data.u.fill.data.mask, item);
+
+        red_send_qxl_draw_fill(worker, display_channel, item);
 
         // eitehr the brush operation is opaque, or the dest is not lossy
         surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
@@ -7384,12 +7487,44 @@ static inline void red_lossy_send_qxl_draw_fill(RedWorker *worker,
     }
 }
 
-static inline void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
-                                                  DisplayChannel *display_channel,
-                                                  Drawable *item)
+static FillBitsType red_send_qxl_draw_opaque(RedWorker *worker,
+                                             DisplayChannel *display_channel,
+                                             Drawable *item, int src_allowed_lossy)
 {
-    QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *brush_pat_out;
+    SpiceMarshaller *src_bitmap_out;
+    SpiceMarshaller *mask_bitmap_out;
+    SpiceOpaque opaque;
+    FillBitsType src_send_type;
+
+    fill_base(display_channel, item);
+
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_OPAQUE;
+    opaque = drawable->u.opaque;
+    spice_marshall_Opaque(channel->send_data.marshaller,
+                          &opaque,
+                          &src_bitmap_out,
+                          &brush_pat_out,
+                          &mask_bitmap_out);
+
+    src_send_type = fill_bits(display_channel, src_bitmap_out, opaque.src_bitmap, item,
+                              src_allowed_lossy);
+
+    if (brush_pat_out) {
+        fill_bits(display_channel, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE);
+    }
+    fill_mask(display_channel, mask_bitmap_out, opaque.mask.bitmap, item);
+
+    return src_send_type;
+}
+
+static void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
+                                           DisplayChannel *display_channel,
+                                           Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
 
     int src_allowed_lossy;
     int rop;
@@ -7418,15 +7553,7 @@ static inline void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
         FillBitsType src_send_type;
         int has_mask = !!drawable->u.opaque.mask.bitmap;
 
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_OPAQUE;
-        fill_base(display_channel, &display_channel->send_data.u.opaque.base, item,
-                  sizeof(SpiceMsgDisplayDrawOpaque), item->surface_id);
-        display_channel->send_data.u.opaque.data = drawable->u.opaque;
-        src_send_type = fill_bits(display_channel,
-                                  &display_channel->send_data.u.opaque.data.src_bitmap,
-                                  item, src_allowed_lossy);
-        fill_brush(display_channel, &display_channel->send_data.u.opaque.data.brush, item);
-        fill_mask(display_channel, &display_channel->send_data.u.opaque.data.mask, item);
+        src_send_type = red_send_qxl_draw_opaque(worker, display_channel, item, src_allowed_lossy);
 
         if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
             src_is_lossy = TRUE;
@@ -7457,12 +7584,38 @@ static inline void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
     }
 }
 
-static inline void red_lossy_send_qxl_draw_copy(RedWorker *worker,
-                                                DisplayChannel *display_channel,
-                                                Drawable *item)
+static FillBitsType red_send_qxl_draw_copy(RedWorker *worker,
+                                           DisplayChannel *display_channel,
+                                           Drawable *item, int src_allowed_lossy)
 {
-    QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *src_bitmap_out;
+    SpiceMarshaller *mask_bitmap_out;
+    SpiceCopy copy;
+    FillBitsType src_send_type;
+
+    fill_base(display_channel, item);
+
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_COPY;
+
+    copy = drawable->u.copy;
+    spice_marshall_Copy(channel->send_data.marshaller,
+                        &copy,
+                        &src_bitmap_out,
+                        &mask_bitmap_out);
+
+    src_send_type = fill_bits(display_channel, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy);
+    fill_mask(display_channel, mask_bitmap_out, copy.mask.bitmap, item);
+
+    return src_send_type;
+}
+
+static void red_lossy_send_qxl_draw_copy(RedWorker *worker,
+                                         DisplayChannel *display_channel,
+                                         Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int has_mask = !!drawable->u.copy.mask.bitmap;
     int src_is_lossy;
     BitmapData src_bitmap_data;
@@ -7471,13 +7624,7 @@ static inline void red_lossy_send_qxl_draw_copy(RedWorker *worker,
     src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.copy.src_bitmap,
                                    &drawable->u.copy.src_area, item, &src_bitmap_data);
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_COPY;
-    fill_base(display_channel, &display_channel->send_data.u.copy.base, item,
-              sizeof(SpiceMsgDisplayDrawCopy), item->surface_id);
-    display_channel->send_data.u.copy.data = drawable->u.copy;
-    src_send_type = fill_bits(display_channel, &display_channel->send_data.u.copy.data.src_bitmap,
-                              item, TRUE);
-    fill_mask(display_channel, &display_channel->send_data.u.copy.data.mask, item);
+    src_send_type = red_send_qxl_draw_copy(worker, display_channel, item, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -7489,25 +7636,37 @@ static inline void red_lossy_send_qxl_draw_copy(RedWorker *worker,
                                 src_is_lossy);
 }
 
-static inline void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
-                                                       DisplayChannel *display_channel,
-                                                       Drawable *item)
+static void red_send_qxl_draw_transparent(RedWorker *worker,
+                                          DisplayChannel *display_channel,
+                                          Drawable *item)
 {
-    QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *src_bitmap_out;
+    SpiceTransparent transparent;
+
+    fill_base(display_channel, item);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_TRANSPARENT;
+    transparent = drawable->u.transparent;
+    spice_marshall_Transparent(channel->send_data.marshaller,
+                               &transparent,
+                               &src_bitmap_out);
+    fill_bits(display_channel, src_bitmap_out, transparent.src_bitmap, item, FALSE);
+}
+
+static void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
+                                                DisplayChannel *display_channel,
+                                                Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
 
     src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.transparent.src_bitmap,
                                    &drawable->u.transparent.src_area, item, &src_bitmap_data);
 
-    if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) {  
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_TRANSPARENT;
-        fill_base(display_channel, &display_channel->send_data.u.transparent.base, item,
-                  sizeof(SpiceMsgDisplayDrawTransparent), item->surface_id);
-        display_channel->send_data.u.transparent.data = drawable->u.transparent;
-        fill_bits(display_channel, &display_channel->send_data.u.transparent.data.src_bitmap,
-                  item, FALSE);
+    if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) {
+        red_send_qxl_draw_transparent(worker, display_channel, item);
 
         // don't update surface lossy region since transperent areas might be lossy
     } else {
@@ -7522,26 +7681,41 @@ static inline void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
     }
 }
 
-static inline void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
-                                                       DisplayChannel *display_channel,
-                                                       Drawable *item)
+static FillBitsType red_send_qxl_draw_alpha_blend(RedWorker *worker,
+                                                  DisplayChannel *display_channel,
+                                                  Drawable *item,
+                                                  int src_allowed_lossy)
 {
-    QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *src_bitmap_out;
+    SpiceAlphaBlnd alpha_blend;
+    FillBitsType src_send_type;
+
+    fill_base(display_channel, item);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND;
+    alpha_blend = drawable->u.alpha_blend;
+    spice_marshall_AlphaBlnd(channel->send_data.marshaller,
+                             &alpha_blend,
+                             &src_bitmap_out);
+    src_send_type = fill_bits(display_channel, src_bitmap_out, alpha_blend.src_bitmap, item, src_allowed_lossy);
+
+    return src_send_type;
+}
+
+static void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
+                                                DisplayChannel *display_channel,
+                                                Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
     FillBitsType src_send_type;
 
     src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.alpha_blend.src_bitmap,
                                    &drawable->u.alpha_blend.src_area, item, &src_bitmap_data);
-    
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND;
-    fill_base(display_channel, &display_channel->send_data.u.alpha_blend.base, item,
-              sizeof(SpiceMsgDisplayDrawAlphaBlend), item->surface_id);
-    display_channel->send_data.u.alpha_blend.data = drawable->u.alpha_blend;
-    src_send_type = fill_bits(display_channel,
-                              &display_channel->send_data.u.alpha_blend.data.src_bitmap,
-                              item, TRUE);
+
+    src_send_type = red_send_qxl_draw_alpha_blend(worker, display_channel, item, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -7554,27 +7728,37 @@ static inline void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
     } // else, the area stays lossy/lossless as the destination
 }
 
-static inline void red_lossy_send_qxl_copy_bits(RedWorker *worker,
-                                                DisplayChannel *display_channel,
-                                                Drawable *item)
+static void red_send_qxl_copy_bits(RedWorker *worker,
+                                   DisplayChannel *display_channel,
+                                   Drawable *item)
 {
-    QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpicePoint copy_bits;
+
+    fill_base(display_channel, item);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_COPY_BITS;
+    copy_bits = drawable->u.copy_bits.src_pos;
+    spice_marshall_Point(channel->send_data.marshaller,
+                         &copy_bits);
+}
+
+static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
+                                         DisplayChannel *display_channel,
+                                         Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     SpiceRect src_rect;
     int horz_offset;
     int vert_offset;
     int src_is_lossy;
     SpiceRect src_lossy_area;
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_COPY_BITS;
-    fill_base(display_channel, &display_channel->send_data.u.copy_bits.base, item,
-              sizeof(SpiceMsgDisplayCopyBits), item->surface_id);
-    display_channel->send_data.u.copy_bits.src_pos = drawable->u.copy_bits.src_pos;
-    
+    red_send_qxl_copy_bits(worker, display_channel, item);
+
     horz_offset = drawable->u.copy_bits.src_pos.x - drawable->bbox.left;
     vert_offset = drawable->u.copy_bits.src_pos.y - drawable->bbox.top;
 
-
     src_rect.left = drawable->u.copy_bits.src_pos.x;
     src_rect.top = drawable->u.copy_bits.src_pos.y;
     src_rect.right = drawable->bbox.right + horz_offset;
@@ -7587,12 +7771,34 @@ static inline void red_lossy_send_qxl_copy_bits(RedWorker *worker,
                                 src_is_lossy);
 }
 
-static inline void red_lossy_send_qxl_draw_blend(RedWorker *worker,
-                                                 DisplayChannel *display_channel,
-                                                 Drawable *item)
+static void red_send_qxl_draw_blend(RedWorker *worker,
+                                    DisplayChannel *display_channel,
+                                    Drawable *item)
 {
-    QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *src_bitmap_out;
+    SpiceMarshaller *mask_bitmap_out;
+    SpiceBlend blend;
+
+    fill_base(display_channel, item);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_BLEND;
+    blend = drawable->u.blend;
+    spice_marshall_Blend(channel->send_data.marshaller,
+                         &blend,
+                         &src_bitmap_out,
+                         &mask_bitmap_out);
+
+    fill_bits(display_channel, src_bitmap_out, blend.src_bitmap, item, FALSE);
+
+    fill_mask(display_channel, mask_bitmap_out, blend.mask.bitmap, item);
+}
+
+static void red_lossy_send_qxl_draw_blend(RedWorker *worker,
+                                          DisplayChannel *display_channel,
+                                          Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
     int dest_is_lossy;
@@ -7603,18 +7809,13 @@ static inline void red_lossy_send_qxl_draw_blend(RedWorker *worker,
     dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
                                           &drawable->bbox, &dest_lossy_area);
 
-    if (!dest_is_lossy && (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_BLEND;
-        fill_base(display_channel, &display_channel->send_data.u.blend.base, item,
-                  sizeof(SpiceMsgDisplayDrawBlend), item->surface_id);
-        display_channel->send_data.u.blend.data = drawable->u.blend;
-        fill_bits(display_channel, &display_channel->send_data.u.blend.data.src_bitmap,
-                  item, FALSE);
-        fill_mask(display_channel, &display_channel->send_data.u.blend.data.mask, item);
+    if (!dest_is_lossy &&
+        (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
+        red_send_qxl_draw_blend(worker, display_channel, item);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
-        int num_resend = 0; 
+        int num_resend = 0;
 
         if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) {
             resend_surface_ids[num_resend] = src_bitmap_data.id;
@@ -7633,61 +7834,130 @@ static inline void red_lossy_send_qxl_draw_blend(RedWorker *worker,
     }
 }
 
-static inline void red_lossy_send_qxl_draw_blackness(RedWorker *worker,
-                                                     DisplayChannel *display_channel,
-                                                     Drawable *item)
+static void red_send_qxl_draw_blackness(RedWorker *worker,
+                                        DisplayChannel *display_channel,
+                                        Drawable *item)
 {
-    QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *mask_bitmap_out;
+    SpiceBlackness blackness;
+
+    fill_base(display_channel, item);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_BLACKNESS;
+    blackness = drawable->u.blackness;
+
+    spice_marshall_Blackness(channel->send_data.marshaller,
+                             &blackness,
+                             &mask_bitmap_out);
+
+    fill_mask(display_channel, mask_bitmap_out, blackness.mask.bitmap, item);
+}
+
+static void red_lossy_send_qxl_draw_blackness(RedWorker *worker,
+                                              DisplayChannel *display_channel,
+                                              Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int has_mask = !!drawable->u.blackness.mask.bitmap;
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_BLACKNESS;
-    fill_base(display_channel, &display_channel->send_data.u.blackness.base, item,
-              sizeof(SpiceMsgDisplayDrawBlackness), item->surface_id);
-    display_channel->send_data.u.blackness.data = drawable->u.blackness;
-    fill_mask(display_channel, &display_channel->send_data.u.blackness.data.mask, item);
+    red_send_qxl_draw_blackness(worker, display_channel, item);
 
     surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
 }
 
-static inline void red_lossy_send_qxl_draw_whiteness(RedWorker *worker,
-                                                     DisplayChannel *display_channel,
-                                                     Drawable *item)
+static void red_send_qxl_draw_whiteness(RedWorker *worker,
+                                        DisplayChannel *display_channel,
+                                        Drawable *item)
 {
-    QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *mask_bitmap_out;
+    SpiceWhiteness whiteness;
+
+    fill_base(display_channel, item);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_WHITENESS;
+    whiteness = drawable->u.whiteness;
+
+    spice_marshall_Whiteness(channel->send_data.marshaller,
+                             &whiteness,
+                             &mask_bitmap_out);
+
+    fill_mask(display_channel, mask_bitmap_out, whiteness.mask.bitmap, item);
+}
+
+static void red_lossy_send_qxl_draw_whiteness(RedWorker *worker,
+                                              DisplayChannel *display_channel,
+                                              Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int has_mask = !!drawable->u.whiteness.mask.bitmap;
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_WHITENESS;
-    fill_base(display_channel, &display_channel->send_data.u.whiteness.base, item,
-              sizeof(SpiceMsgDisplayDrawWhiteness), item->surface_id);
-    display_channel->send_data.u.whiteness.data = drawable->u.whiteness;
-    fill_mask(display_channel, &display_channel->send_data.u.whiteness.data.mask, item);
+    red_send_qxl_draw_whiteness(worker, display_channel, item);
 
     surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
 }
 
-static inline void red_lossy_send_qxl_draw_inverse(RedWorker *worker,
-                                                   DisplayChannel *display_channel,
-                                                   Drawable *item)
+static void red_send_qxl_draw_inverse(RedWorker *worker,
+                                        DisplayChannel *display_channel,
+                                        Drawable *item)
 {
     QXLDrawable *drawable = item->qxl_drawable;
+    SpiceMarshaller *mask_bitmap_out;
     RedChannel *channel = &display_channel->base;
+    SpiceInvers inverse;
+
+    fill_base(display_channel, item);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_INVERS;
+    inverse = drawable->u.invers;
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_INVERS;
-    fill_base(display_channel, &display_channel->send_data.u.invers.base, item,
-              sizeof(SpiceMsgDisplayDrawInvers), item->surface_id);
-    display_channel->send_data.u.invers.data = drawable->u.invers;
-    fill_mask(display_channel, &display_channel->send_data.u.invers.data.mask, item);
+    spice_marshall_Invers(channel->send_data.marshaller,
+                          &inverse,
+                          &mask_bitmap_out);
+
+    fill_mask(display_channel, mask_bitmap_out, inverse.mask.bitmap, item);
 }
 
-static inline void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
-                                                DisplayChannel *display_channel,
-                                                Drawable *item)
+static void red_lossy_send_qxl_draw_inverse(RedWorker *worker,
+                                            DisplayChannel *display_channel,
+                                            Drawable *item)
+{
+    red_send_qxl_draw_inverse(worker, display_channel, item);
+}
+
+static void red_send_qxl_draw_rop3(RedWorker *worker,
+                                   DisplayChannel *display_channel,
+                                   Drawable *item)
 {
     QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    SpiceRop3 rop3;
+    SpiceMarshaller *src_bitmap_out;
+    SpiceMarshaller *brush_pat_out;
+    SpiceMarshaller *mask_bitmap_out;
+
+    fill_base(display_channel, item);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_ROP3;
+    rop3 = drawable->u.rop3;
+    spice_marshall_Rop3(channel->send_data.marshaller,
+                        &rop3,
+                        &src_bitmap_out,
+                        &brush_pat_out,
+                        &mask_bitmap_out);
 
+    fill_bits(display_channel, src_bitmap_out, rop3.src_bitmap, item, FALSE);
+
+    if (brush_pat_out) {
+        fill_bits(display_channel, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE);
+    }
+    fill_mask(display_channel, mask_bitmap_out, rop3.mask.bitmap, item);
+}
+
+static void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
+                                         DisplayChannel *display_channel,
+                                         Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
     int brush_is_lossy;
@@ -7706,14 +7976,7 @@ static inline void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
         (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
         !dest_is_lossy) {
         int has_mask = !!drawable->u.rop3.mask.bitmap;
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_ROP3;
-        fill_base(display_channel, &display_channel->send_data.u.rop3.base, item,
-                  sizeof(SpiceMsgDisplayDrawRop3), item->surface_id);
-        display_channel->send_data.u.rop3.data = drawable->u.rop3;
-        fill_bits(display_channel, &display_channel->send_data.u.rop3.data.src_bitmap,
-                  item, FALSE);
-        fill_brush(display_channel, &display_channel->send_data.u.rop3.data.brush, item);
-        fill_mask(display_channel, &display_channel->send_data.u.rop3.data.mask, item);
+        red_send_qxl_draw_rop3(worker, display_channel, item);
 
         surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
     } else {
@@ -7744,12 +8007,39 @@ static inline void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
     }
 }
 
-static inline void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
-                                                  DisplayChannel *display_channel,
-                                                  Drawable *item)
+static void red_send_qxl_draw_stroke(RedWorker *worker,
+                                     DisplayChannel *display_channel,
+                                     Drawable *item)
 {
     QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    SpiceStroke stroke;
+    SpiceMarshaller *brush_pat_out;
+    SpiceMarshaller *path_out;
+    SpiceMarshaller *style_out;
+
+    fill_base(display_channel, item);
+
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_STROKE;
+    stroke = drawable->u.stroke;
+    spice_marshall_Stroke(channel->send_data.marshaller,
+                          &stroke,
+                          &path_out,
+                          &style_out,
+                          &brush_pat_out);
+
+    fill_path(display_channel, path_out, stroke.path, item->group_id);
+    fill_attr(display_channel, style_out, &stroke.attr, item->group_id);
+    if (brush_pat_out) {
+        fill_bits(display_channel, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
+    }
+}
+
+static void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
+                                           DisplayChannel *display_channel,
+                                           Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int brush_is_lossy;
     BitmapData brush_bitmap_data;
     int dest_is_lossy = FALSE;
@@ -7763,24 +8053,18 @@ static inline void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
     rop = drawable->u.stroke.fore_mode;
 
     // assuming that if the brush type is solid, the destination can
-    // be lossy, no matter what the rop is. 
+    // be lossy, no matter what the rop is.
     if (drawable->u.stroke.brush.type != SPICE_BRUSH_TYPE_SOLID &&
         ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) ||
         (rop & SPICE_ROPD_OP_XOR))) {
         dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
                                               &drawable->bbox, &dest_lossy_area);
     }
-    
+
     if (!dest_is_lossy &&
         (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)))
     {
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_STROKE;
-        fill_base(display_channel, &display_channel->send_data.u.stroke.base, item,
-                  sizeof(SpiceMsgDisplayDrawStroke), item->surface_id);
-        display_channel->send_data.u.stroke.data = drawable->u.stroke;
-        fill_path(display_channel, &display_channel->send_data.u.stroke.data.path, item->group_id);
-        fill_attr(display_channel, &display_channel->send_data.u.stroke.data.attr, item->group_id);
-        fill_brush(display_channel, &display_channel->send_data.u.stroke.data.brush, item);
+        red_send_qxl_draw_stroke(worker, display_channel, item);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -7805,12 +8089,42 @@ static inline void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
 
 }
 
-static inline void red_lossy_send_qxl_draw_text(RedWorker *worker,
-                                                DisplayChannel *display_channel,
-                                                Drawable *item)
+static void red_send_qxl_draw_text(RedWorker *worker,
+                                   DisplayChannel *display_channel,
+                                   Drawable *item)
 {
     QXLDrawable *drawable = item->qxl_drawable;
     RedChannel *channel = &display_channel->base;
+    SpiceText text;
+    SpiceMarshaller *brush_pat_out;
+    SpiceMarshaller *back_brush_pat_out;
+    SpiceMarshaller *str_out;
+
+    fill_base(display_channel, item);
+
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_TEXT;
+    text = drawable->u.text;
+    spice_marshall_Text(channel->send_data.marshaller,
+                        &text,
+                        &str_out,
+                        &brush_pat_out,
+                        &back_brush_pat_out);
+
+    if (brush_pat_out) {
+        fill_bits(display_channel, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE);
+    }
+    if (back_brush_pat_out) {
+        fill_bits(display_channel, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE);
+    }
+
+    fill_str(display_channel, str_out, text.str, item->group_id);
+}
+
+static void red_lossy_send_qxl_draw_text(RedWorker *worker,
+                                         DisplayChannel *display_channel,
+                                         Drawable *item)
+{
+    QXLDrawable *drawable = item->qxl_drawable;
     int fg_is_lossy;
     BitmapData fg_bitmap_data;
     int bg_is_lossy;
@@ -7843,13 +8157,7 @@ static inline void red_lossy_send_qxl_draw_text(RedWorker *worker,
     if (!dest_is_lossy &&
         (!fg_is_lossy || (fg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
         (!bg_is_lossy || (bg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_TEXT;
-        fill_base(display_channel, &display_channel->send_data.u.text.base, item,
-                  sizeof(SpiceMsgDisplayDrawText), item->surface_id);
-        display_channel->send_data.u.text.data = drawable->u.text;
-        fill_brush(display_channel, &display_channel->send_data.u.text.data.fore_brush, item);
-        fill_brush(display_channel, &display_channel->send_data.u.text.data.back_brush, item);
-        fill_str(display_channel, &display_channel->send_data.u.text.data.str, item->group_id);
+        red_send_qxl_draw_text(worker, display_channel, item);
     } else {
         int resend_surface_ids[3];
         SpiceRect *resend_areas[3];
@@ -7907,7 +8215,7 @@ static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *displ
         break;
      case QXL_DRAW_WHITENESS:
         red_lossy_send_qxl_draw_whiteness(worker, display_channel, item);
-        break;   
+        break;
     case QXL_DRAW_INVERS:
         red_lossy_send_qxl_draw_inverse(worker, display_channel, item);
         break;
@@ -7916,7 +8224,7 @@ static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *displ
         break;
     case QXL_DRAW_STROKE:
         red_lossy_send_qxl_draw_stroke(worker, display_channel, item);
-        break;      
+        break;
     case QXL_DRAW_TEXT:
         red_lossy_send_qxl_draw_text(worker, display_channel, item);
         break;
@@ -7925,7 +8233,7 @@ static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *displ
     }
 
     // a message is pending
-    if (display_channel->base.send_data.header.size) {
+    if (display_channel->base.send_data.header->type != 0) {
         display_begin_send_massage(display_channel, &item->pipe_item);
     }
 }
@@ -7935,113 +8243,45 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
 {
     QXLDrawable *drawable = item->qxl_drawable;
 
-    RedChannel *channel = &display_channel->base;
     switch (drawable->type) {
     case QXL_DRAW_FILL:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_FILL;
-        fill_base(display_channel, &display_channel->send_data.u.fill.base, item,
-                  sizeof(SpiceMsgDisplayDrawFill), item->surface_id);
-        display_channel->send_data.u.fill.data = drawable->u.fill;
-        fill_brush(display_channel, &display_channel->send_data.u.fill.data.brush, item);
-        fill_mask(display_channel, &display_channel->send_data.u.fill.data.mask, item);
+        red_send_qxl_draw_fill(worker, display_channel, item);
         break;
     case QXL_DRAW_OPAQUE:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_OPAQUE;
-        fill_base(display_channel, &display_channel->send_data.u.opaque.base, item,
-                  sizeof(SpiceMsgDisplayDrawOpaque), item->surface_id);
-        display_channel->send_data.u.opaque.data = drawable->u.opaque;
-        fill_bits(display_channel, &display_channel->send_data.u.opaque.data.src_bitmap,
-                  item, FALSE);
-        fill_brush(display_channel, &display_channel->send_data.u.opaque.data.brush, item);
-        fill_mask(display_channel, &display_channel->send_data.u.opaque.data.mask, item);
+        red_send_qxl_draw_opaque(worker, display_channel, item, FALSE);
         break;
     case QXL_DRAW_COPY:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_COPY;
-        fill_base(display_channel, &display_channel->send_data.u.copy.base, item,
-                  sizeof(SpiceMsgDisplayDrawCopy), item->surface_id);
-        display_channel->send_data.u.copy.data = drawable->u.copy;
-        fill_bits(display_channel, &display_channel->send_data.u.copy.data.src_bitmap, item, FALSE);
-        fill_mask(display_channel, &display_channel->send_data.u.copy.data.mask, item);
+        red_send_qxl_draw_copy(worker, display_channel, item, FALSE);
         break;
     case QXL_DRAW_TRANSPARENT:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_TRANSPARENT;
-        fill_base(display_channel, &display_channel->send_data.u.transparent.base, item,
-                  sizeof(SpiceMsgDisplayDrawTransparent), item->surface_id);
-        display_channel->send_data.u.transparent.data = drawable->u.transparent;
-        fill_bits(display_channel, &display_channel->send_data.u.transparent.data.src_bitmap,
-                  item, FALSE);
+        red_send_qxl_draw_transparent(worker, display_channel, item);
         break;
     case QXL_DRAW_ALPHA_BLEND:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND;
-        fill_base(display_channel, &display_channel->send_data.u.alpha_blend.base, item,
-                  sizeof(SpiceMsgDisplayDrawAlphaBlend), item->surface_id);
-        display_channel->send_data.u.alpha_blend.data = drawable->u.alpha_blend;
-        fill_bits(display_channel, &display_channel->send_data.u.alpha_blend.data.src_bitmap,
-                  item, FALSE);
+        red_send_qxl_draw_alpha_blend(worker, display_channel, item, FALSE);
         break;
     case QXL_COPY_BITS:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_COPY_BITS;
-        fill_base(display_channel, &display_channel->send_data.u.copy_bits.base, item,
-                  sizeof(SpiceMsgDisplayCopyBits), item->surface_id);
-        display_channel->send_data.u.copy_bits.src_pos = drawable->u.copy_bits.src_pos;
+        red_send_qxl_copy_bits(worker, display_channel, item);
         break;
     case QXL_DRAW_BLEND:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_BLEND;
-        fill_base(display_channel, &display_channel->send_data.u.blend.base, item,
-                  sizeof(SpiceMsgDisplayDrawBlend), item->surface_id);
-        display_channel->send_data.u.blend.data = drawable->u.blend;
-        fill_bits(display_channel, &display_channel->send_data.u.blend.data.src_bitmap,
-                  item, FALSE);
-        fill_mask(display_channel, &display_channel->send_data.u.blend.data.mask, item);
+        red_send_qxl_draw_blend(worker, display_channel, item);
         break;
     case QXL_DRAW_BLACKNESS:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_BLACKNESS;
-        fill_base(display_channel, &display_channel->send_data.u.blackness.base, item,
-                  sizeof(SpiceMsgDisplayDrawBlackness), item->surface_id);
-        display_channel->send_data.u.blackness.data = drawable->u.blackness;
-        fill_mask(display_channel, &display_channel->send_data.u.blackness.data.mask, item);
+        red_send_qxl_draw_blackness(worker, display_channel, item);
         break;
     case QXL_DRAW_WHITENESS:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_WHITENESS;
-        fill_base(display_channel, &display_channel->send_data.u.whiteness.base, item,
-                  sizeof(SpiceMsgDisplayDrawWhiteness), item->surface_id);
-        display_channel->send_data.u.whiteness.data = drawable->u.whiteness;
-        fill_mask(display_channel, &display_channel->send_data.u.whiteness.data.mask, item);
+        red_send_qxl_draw_whiteness(worker, display_channel, item);
         break;
     case QXL_DRAW_INVERS:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_INVERS;
-        fill_base(display_channel, &display_channel->send_data.u.invers.base, item,
-                  sizeof(SpiceMsgDisplayDrawInvers), item->surface_id);
-        display_channel->send_data.u.invers.data = drawable->u.invers;
-        fill_mask(display_channel, &display_channel->send_data.u.invers.data.mask, item);
+        red_send_qxl_draw_inverse(worker, display_channel, item);
         break;
     case QXL_DRAW_ROP3:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_ROP3;
-        fill_base(display_channel, &display_channel->send_data.u.rop3.base, item,
-                  sizeof(SpiceMsgDisplayDrawRop3), item->surface_id);
-        display_channel->send_data.u.rop3.data = drawable->u.rop3;
-        fill_bits(display_channel, &display_channel->send_data.u.rop3.data.src_bitmap,
-                  item, FALSE);
-        fill_brush(display_channel, &display_channel->send_data.u.rop3.data.brush, item);
-        fill_mask(display_channel, &display_channel->send_data.u.rop3.data.mask, item);
+        red_send_qxl_draw_rop3(worker, display_channel, item);
         break;
     case QXL_DRAW_STROKE:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_STROKE;
-        fill_base(display_channel, &display_channel->send_data.u.stroke.base, item,
-                  sizeof(SpiceMsgDisplayDrawStroke), item->surface_id);
-        display_channel->send_data.u.stroke.data = drawable->u.stroke;
-        fill_path(display_channel, &display_channel->send_data.u.stroke.data.path, item->group_id);
-        fill_attr(display_channel, &display_channel->send_data.u.stroke.data.attr, item->group_id);
-        fill_brush(display_channel, &display_channel->send_data.u.stroke.data.brush, item);
+        red_send_qxl_draw_stroke(worker, display_channel, item);
         break;
     case QXL_DRAW_TEXT:
-        channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_TEXT;
-        fill_base(display_channel, &display_channel->send_data.u.text.base, item,
-                  sizeof(SpiceMsgDisplayDrawText), item->surface_id);
-        display_channel->send_data.u.text.data = drawable->u.text;
-        fill_brush(display_channel, &display_channel->send_data.u.text.data.fore_brush, item);
-        fill_brush(display_channel, &display_channel->send_data.u.text.data.back_brush, item);
-        fill_str(display_channel, &display_channel->send_data.u.text.data.str, item->group_id);
+        red_send_qxl_draw_text(worker, display_channel, item);
         break;
     default:
         red_error("invalid type");
@@ -8051,105 +8291,6 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
 
 #define MAX_SEND_VEC 100
 
-static inline BufDescriptor *find_buf(RedChannel *channel, int buf_pos, int *buf_offset)
-{
-    BufDescriptor *buf;
-    int pos = 0;
-
-    for (buf = channel->send_data.bufs; buf_pos >= pos + buf->size; buf++) {
-        pos += buf->size;
-        ASSERT(buf != &channel->send_data.bufs[channel->send_data.n_bufs - 1]);
-    }
-    *buf_offset = buf_pos - pos;
-    return buf;
-}
-
-static inline uint32_t __fill_iovec(RedWorker *worker, BufDescriptor *buf, int skip,
-                                    struct iovec *vec, int *vec_index)
-{
-    uint32_t size = 0;
-
-    switch (buf->type) {
-    case BUF_TYPE_RAW:
-        vec[*vec_index].iov_base = buf->data + skip;
-        vec[*vec_index].iov_len = size = buf->size - skip;
-        (*vec_index)++;
-        break;
-    case BUF_TYPE_COMPRESS_BUF: {
-        RedCompressBuf *comp_buf = (RedCompressBuf *)buf->data;
-        int max = buf->size - skip;
-        int now;
-        do {
-            ASSERT(comp_buf);
-            if (skip >= sizeof(comp_buf->buf)) {
-                skip -= sizeof(comp_buf->buf);
-                comp_buf = comp_buf->send_next;
-                continue;
-            }
-            now = MIN(sizeof(comp_buf->buf) - skip, max);
-            max -= now;
-            size += now;
-            vec[*vec_index].iov_base = (uint8_t*)comp_buf->buf + skip;
-            vec[*vec_index].iov_len = now;
-            skip = 0;
-            comp_buf = comp_buf->send_next;
-            (*vec_index)++;
-        } while (max && *vec_index < MAX_SEND_VEC);
-        break;
-    }
-    case BUF_TYPE_CHUNK: {
-        QXLDataChunk *chunk = (QXLDataChunk *)buf->data;
-        do {
-            int data_size = chunk->data_size;
-            int skip_now = MIN(data_size, skip);
-            skip -= skip_now;
-            data_size -= skip_now;
-
-            if (data_size) {
-                validate_virt(&worker->mem_slots, (unsigned long)chunk->data, buf->slot_id, data_size,
-                              buf->group_id);
-                size += data_size;
-                vec[*vec_index].iov_base = chunk->data + skip_now;
-                vec[*vec_index].iov_len = data_size;
-                (*vec_index)++;
-            }
-            chunk = chunk->next_chunk ?
-                    (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk, sizeof(QXLDataChunk),
-                                             buf->group_id) :
-                    NULL;
-        } while (chunk && *vec_index < MAX_SEND_VEC);
-        break;
-    }
-    default:
-        red_error("invalid type");
-    }
-    return size;
-}
-
-static inline void fill_iovec(RedChannel *channel, struct iovec *vec, int *vec_size)
-{
-    int rc, vec_index = 0;
-    uint32_t pos = channel->send_data.pos;
-
-    ASSERT(channel->send_data.size != pos && channel->send_data.size > pos);
-
-    do {
-        BufDescriptor *buf;
-        int buf_offset;
-
-        buf = find_buf(channel, pos, &buf_offset);
-        ASSERT(buf);
-        rc = __fill_iovec(channel->worker, buf, buf_offset, vec, &vec_index);
-        if (rc == 0) {
-            fprintf(stderr, "%s: got only %d of %d bytes\n", __FUNCTION__, 
-                    pos, channel->send_data.size);
-            abort();
-        }
-        pos += rc;
-    } while (vec_index < MAX_SEND_VEC && pos != channel->send_data.size);
-    *vec_size = vec_index;
-}
-
 static void inline channel_release_res(RedChannel *channel)
 {
     if (!channel->send_data.item) {
@@ -8174,7 +8315,8 @@ static void red_send_data(RedChannel *channel, void *item)
             }
             break;
         }
-        fill_iovec(channel, vec, &vec_size);
+        vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
+                                               vec, MAX_SEND_VEC, channel->send_data.pos);
         ASSERT(channel->peer);
         if ((n = channel->peer->cb_writev(channel->peer->ctx, vec, vec_size)) == -1) {
             switch (errno) {
@@ -8228,8 +8370,11 @@ static void display_channel_push_release(DisplayChannel *channel, uint8_t type,
 
 static inline void red_begin_send_massage(RedChannel *channel, void *item)
 {
-    channel->send_data.size = channel->send_data.header.size + sizeof(SpiceDataHeader);
+    spice_marshaller_flush(channel->send_data.marshaller);
+    channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
+    channel->send_data.header->size =  channel->send_data.size - sizeof(SpiceDataHeader);
     channel->messages_window++;
+    channel->send_data.header = NULL; /* avoid writing to this until we have a new message */
     red_send_data(channel, item);
 }
 
@@ -8238,11 +8383,20 @@ static inline void display_begin_send_massage(DisplayChannel *channel, void *ite
     FreeList *free_list = &channel->send_data.free_list;
 
     if (0 && free_list->res->count) {
+        int sub_list_len = 1;
+        SpiceMarshaller *wait_m = NULL;
+        SpiceMarshaller *inval_m;
         int sync_count = 0;
-        int sub_index;
         int i;
 
-        channel->base.send_data.header.sub_list = channel->base.send_data.header.size;
+        inval_m = spice_marshaller_get_submarshaller(channel->base.send_data.marshaller);
+
+        /* type + size + submessage */
+        spice_marshaller_add_uint16(inval_m, SPICE_MSG_DISPLAY_INVAL_LIST);
+        spice_marshaller_add_uint32(inval_m,
+                                    sizeof(*free_list->res) + free_list->res->count * sizeof(free_list->res->resources[0]));
+        spice_marshall_msg_display_inval_list(inval_m, free_list->res);
+
         for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
             if (i != channel->base.id && free_list->sync[i] != 0) {
                 free_list->wait.header.wait_list[sync_count].channel_type = SPICE_CHANNEL_DISPLAY;
@@ -8250,36 +8404,26 @@ static inline void display_begin_send_massage(DisplayChannel *channel, void *ite
                 free_list->wait.header.wait_list[sync_count++].message_serial = free_list->sync[i];
             }
         }
-        SpiceSubMessageList *sub_list = &channel->send_data.sub_list.sub_list;
-        SpicedSubMessage *sub_header = channel->send_data.sub_header;
+        free_list->wait.header.wait_count = sync_count;
+
         if (sync_count) {
-            sub_list->size = 2;
-            add_buf((RedChannel*)channel, BUF_TYPE_RAW, sub_list,
-                    sizeof(*sub_list) + 2 * sizeof(sub_list->sub_messages[0]), 0, 0);
-            sub_list->sub_messages[0] = channel->base.send_data.header.size;
-            sub_header[0].type = SPICE_MSG_WAIT_FOR_CHANNELS;
-            sub_header[0].size = sizeof(free_list->wait.header) +
-                                 sync_count * sizeof(free_list->wait.buf[0]);
-            add_buf((RedChannel*)channel, BUF_TYPE_RAW, sub_header, sizeof(*sub_header), 0, 0);
-            free_list->wait.header.wait_count = sync_count;
-            add_buf((RedChannel*)channel, BUF_TYPE_RAW, &free_list->wait.header,
-                    sub_header[0].size, 0, 0);
-            sub_list->sub_messages[1] = channel->base.send_data.header.size;
-            sub_index = 1;
-        } else {
-            sub_list->size = 1;
-            add_buf((RedChannel*)channel, BUF_TYPE_RAW, sub_list,
-                    sizeof(*sub_list) + sizeof(sub_list->sub_messages[0]), 0, 0);
-            sub_list->sub_messages[0] = channel->base.send_data.header.size;
-            sub_index = 0;
-        }
-        sub_header[sub_index].type = SPICE_MSG_DISPLAY_INVAL_LIST;
-        sub_header[sub_index].size = sizeof(*free_list->res) + free_list->res->count *
-                                     sizeof(free_list->res->resources[0]);
-        add_buf((RedChannel*)channel, BUF_TYPE_RAW, &sub_header[sub_index], sizeof(*sub_header), 0,
-                0);
-        add_buf((RedChannel*)channel, BUF_TYPE_RAW, free_list->res, sub_header[sub_index].size, 0,
-                0);
+            wait_m = spice_marshaller_get_submarshaller(channel->base.send_data.marshaller);
+
+            /* type + size + submessage */
+            spice_marshaller_add_uint16(wait_m, SPICE_MSG_WAIT_FOR_CHANNELS);
+            spice_marshaller_add_uint32(wait_m,
+                                        sizeof(free_list->wait.header) + sync_count * sizeof(free_list->wait.buf[0]));
+            spice_marshall_msg_wait_for_channels(wait_m, &free_list->wait.header);
+            sub_list_len++;
+        }
+
+        SpiceMarshaller *sub_list_m = spice_marshaller_get_submarshaller(channel->base.send_data.marshaller);
+        spice_marshaller_add_uint16(sub_list_m, sub_list_len);
+        if (wait_m) {
+            spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(wait_m));
+        }
+        spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
+        channel->base.send_data.header->sub_list = spice_marshaller_get_offset(sub_list_m);
     }
     red_begin_send_massage((RedChannel *)channel, item);
 }
@@ -8297,6 +8441,7 @@ static inline void red_unref_channel(RedChannel *channel)
 {
     ASSERT(channel);
     if (!--channel->listener.refs) {
+        spice_marshaller_destroy(channel->send_data.marshaller);
         free(channel);
     }
 }
@@ -8565,17 +8710,18 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
         red_display_share_stream_buf(display_channel);
     }
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_STREAM_DATA;
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_DATA;
+
+    SpiceMsgDisplayStreamData stream_data;
 
-    SpiceMsgDisplayStreamData* stream_data = &display_channel->send_data.u.stream_data;
-    add_buf(channel, BUF_TYPE_RAW, stream_data, sizeof(SpiceMsgDisplayStreamData), 0, 0);
-    add_buf(channel, BUF_TYPE_RAW, display_channel->send_data.stream_outbuf,
-            n + PADDING, 0, 0);
+    stream_data.id = stream - worker->streams_buf;
+    stream_data.multi_media_time = drawable->qxl_drawable->mm_time;
+    stream_data.data_size = n;
+    stream_data.pad_size = PADDING;
+    spice_marshall_msg_display_stream_data(channel->send_data.marshaller, &stream_data);
+    spice_marshaller_add_ref(channel->send_data.marshaller,
+                             display_channel->send_data.stream_outbuf, n + PADDING);
 
-    stream_data->id = stream - worker->streams_buf;
-    stream_data->multi_media_time = drawable->qxl_drawable->mm_time;
-    stream_data->data_size = n;
-    stream_data->pad_size = PADDING;
     display_begin_send_massage(display_channel, NULL);
     agent->lats_send_time = time_now;
     return TRUE;
@@ -8599,136 +8745,139 @@ static inline void send_qxl_drawable(DisplayChannel *display_channel, Drawable *
 
 static void red_send_set_ack(RedChannel *channel)
 {
+    SpiceMsgSetAck ack;
+
     ASSERT(channel);
-    channel->send_data.header.type = SPICE_MSG_SET_ACK;
-    channel->send_data.u.ack.generation = ++channel->ack_generation;
-    channel->send_data.u.ack.window = channel->client_ack_window;
+    channel->send_data.header->type = SPICE_MSG_SET_ACK;
+    ack.generation = ++channel->ack_generation;
+    ack.window = channel->client_ack_window;
     channel->messages_window = 0;
 
-    add_buf(channel, BUF_TYPE_RAW, &channel->send_data.u.ack, sizeof(SpiceMsgSetAck), 0, 0);
+    spice_marshall_msg_set_ack(channel->send_data.marshaller, &ack);
+
     red_begin_send_massage(channel, NULL);
 }
 
 static inline void red_send_verb(RedChannel *channel, uint16_t verb)
 {
     ASSERT(channel);
-    channel->send_data.header.type = verb;
+    channel->send_data.header->type = verb;
     red_begin_send_massage(channel, NULL);
 }
 
 static inline void display_send_verb(DisplayChannel *channel, uint16_t verb)
 {
     ASSERT(channel);
-    channel->base.send_data.header.type = verb;
+    channel->base.send_data.header->type = verb;
     display_begin_send_massage(channel, NULL);
 }
 
-static inline void __red_send_inval(RedChannel *channel, CacheItem *cach_item,
-                                    SpiceMsgDisplayInvalOne *inval_one)
+static inline void __red_send_inval(RedChannel *channel, CacheItem *cach_item)
 {
-    channel->send_data.header.type = cach_item->inval_type;
-    inval_one->id = *(uint64_t *)&cach_item->id;
-    add_buf(channel, BUF_TYPE_RAW, inval_one, sizeof(*inval_one), 0, 0);
+    SpiceMsgDisplayInvalOne inval_one;
+
+    channel->send_data.header->type = cach_item->inval_type;
+    inval_one.id = *(uint64_t *)&cach_item->id;
+
+    spice_marshall_msg_cursor_inval_one(channel->send_data.marshaller, &inval_one);
 }
 
-static void red_send_inval(RedChannel *channel, CacheItem *cach_item, SpiceMsgDisplayInvalOne *inval_one)
+static void red_send_inval(RedChannel *channel, CacheItem *cach_item)
 {
-    __red_send_inval(channel, cach_item, inval_one);
+    __red_send_inval(channel, cach_item);
     red_begin_send_massage(channel, NULL);
 }
 
 static void red_display_send_inval(DisplayChannel *display_channel, CacheItem *cach_item)
 {
-    __red_send_inval((RedChannel *)display_channel, cach_item,
-                     &display_channel->send_data.u.inval_one);
+    __red_send_inval((RedChannel *)display_channel, cach_item);
     display_begin_send_massage(display_channel, NULL);
 }
 
 static void display_channel_send_migrate(DisplayChannel *display_channel)
 {
-    display_channel->base.send_data.header.type = SPICE_MSG_MIGRATE;
-    display_channel->send_data.u.migrate.flags = SPICE_MIGRATE_NEED_FLUSH |
-                                                 SPICE_MIGRATE_NEED_DATA_TRANSFER;
-    add_buf((RedChannel*)display_channel, BUF_TYPE_RAW, &display_channel->send_data.u.migrate,
-            sizeof(display_channel->send_data.u.migrate), 0, 0);
+    SpiceMsgMigrate migrate;
+
+    display_channel->base.send_data.header->type = SPICE_MSG_MIGRATE;
+    migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
+    spice_marshall_msg_migrate(display_channel->base.send_data.marshaller, &migrate);
     display_channel->expect_migrate_mark = TRUE;
     display_begin_send_massage(display_channel, NULL);
 }
 
 static void display_channel_send_migrate_data(DisplayChannel *display_channel)
 {
-    DisplayChannelMigrateData* display_data;
+    DisplayChannelMigrateData display_data;
+
+    display_channel->base.send_data.header->type = SPICE_MSG_MIGRATE_DATA;
 
-    display_channel->base.send_data.header.type = SPICE_MSG_MIGRATE_DATA;
     ASSERT(display_channel->pixmap_cache);
-    display_data = &display_channel->send_data.u.migrate_data;
-    display_data->magic = DISPLAY_MIGRATE_DATA_MAGIC;
+    display_data.magic = DISPLAY_MIGRATE_DATA_MAGIC;
     ASSERT(MAX_CACHE_CLIENTS == 4); //MIGRATE_DATA_VERSION dependent
-    display_data->version = DISPLAY_MIGRATE_DATA_VERSION;
+    display_data.version = DISPLAY_MIGRATE_DATA_VERSION;
 
-    display_data->message_serial = channel_message_serial((RedChannel *)display_channel);
+    display_data.message_serial = channel_message_serial((RedChannel *)display_channel);
 
-    display_data->pixmap_cache_freezer = pixmap_cache_freeze(display_channel->pixmap_cache);
-    display_data->pixmap_cache_id = display_channel->pixmap_cache->id;
-    display_data->pixmap_cache_size = display_channel->pixmap_cache->size;
-    memcpy(display_data->pixmap_cache_clients, display_channel->pixmap_cache->sync,
-           sizeof(display_data->pixmap_cache_clients));
+    display_data.pixmap_cache_freezer = pixmap_cache_freeze(display_channel->pixmap_cache);
+    display_data.pixmap_cache_id = display_channel->pixmap_cache->id;
+    display_data.pixmap_cache_size = display_channel->pixmap_cache->size;
+    memcpy(display_data.pixmap_cache_clients, display_channel->pixmap_cache->sync,
+           sizeof(display_data.pixmap_cache_clients));
 
     ASSERT(display_channel->glz_dict);
     red_freeze_glz(display_channel);
-    display_data->glz_dict_id = display_channel->glz_dict->id;
+    display_data.glz_dict_id = display_channel->glz_dict->id;
     glz_enc_dictionary_get_restore_data(display_channel->glz_dict->dict,
-                                        &display_data->glz_dict_restore_data,
+                                        &display_data.glz_dict_restore_data,
                                         &display_channel->glz_data.usr);
 
-    add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, &display_channel->send_data.u.migrate_data,
-            sizeof(display_channel->send_data.u.migrate_data), 0, 0);
+    spice_marshaller_add_ref(display_channel->base.send_data.marshaller,
+                             (uint8_t *)&display_data, sizeof(display_data));
     display_begin_send_massage(display_channel, NULL);
 }
 
 static void display_channel_pixmap_sync(DisplayChannel *display_channel)
 {
-    SpiceMsgWaitForChannels *wait;
+    SpiceMsgWaitForChannels wait;
     PixmapCache *pixmap_cache;
 
 
-    display_channel->base.send_data.header.type = SPICE_MSG_WAIT_FOR_CHANNELS;
-    wait = &display_channel->send_data.u.wait.header;
+    display_channel->base.send_data.header->type = SPICE_MSG_WAIT_FOR_CHANNELS;
     pixmap_cache = display_channel->pixmap_cache;
 
 
     pthread_mutex_lock(&pixmap_cache->lock);
 
-    wait->wait_count = 1;
-    wait->wait_list[0].channel_type = SPICE_CHANNEL_DISPLAY;
-    wait->wait_list[0].channel_id = pixmap_cache->generation_initiator.client;
-    wait->wait_list[0].message_serial = pixmap_cache->generation_initiator.message;
+    wait.wait_count = 1;
+    wait.wait_list[0].channel_type = SPICE_CHANNEL_DISPLAY;
+    wait.wait_list[0].channel_id = pixmap_cache->generation_initiator.client;
+    wait.wait_list[0].message_serial = pixmap_cache->generation_initiator.message;
     display_channel->pixmap_cache_generation = pixmap_cache->generation;
     display_channel->pending_pixmaps_sync = FALSE;
 
     pthread_mutex_unlock(&pixmap_cache->lock);
 
-    add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, wait,
-            sizeof(*wait) + sizeof(wait->wait_list[0]), 0, 0);
+    spice_marshall_msg_wait_for_channels(display_channel->base.send_data.marshaller, &wait);
+
     display_begin_send_massage(display_channel, NULL);
 }
 
 static void display_channel_reset_cache(DisplayChannel *display_channel)
 {
-    SpiceMsgWaitForChannels *wait = &display_channel->send_data.u.wait.header;
+    SpiceMsgWaitForChannels wait;
 
-    display_channel->base.send_data.header.type = SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS;
-    pixmap_cache_reset(display_channel->pixmap_cache, display_channel, wait);
+    display_channel->base.send_data.header->type = SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS;
+    pixmap_cache_reset(display_channel->pixmap_cache, display_channel, &wait);
 
-    add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, wait,
-            sizeof(*wait) + wait->wait_count * sizeof(wait->wait_list[0]), 0, 0);
+    spice_marshall_msg_display_inval_all_pixmaps(display_channel->base.send_data.marshaller,
+                                                 &wait);
     display_begin_send_massage(display_channel, NULL);
 }
 
 static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
 {
     RedChannel *channel;
-    RedImage *red_image;
+    RedImage red_image;
     RedWorker *worker;
     SpiceBitmap bitmap;
     QRegion *surface_lossy_region;
@@ -8736,19 +8885,19 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     int lossy_comp = FALSE;
     int lz_comp = FALSE;
     spice_image_compression_t comp_mode;
+    SpiceMsgDisplayDrawCopy copy;
+    SpiceMarshaller *cliprects_data_out, *clippath_data_out, *src_bitmap_out, *mask_bitmap_out;
+    SpiceMarshaller *bitmap_palette_out, *data_out, *lzplt_palette_out;
 
     ASSERT(display_channel && item);
     channel = &display_channel->base;
     worker = channel->worker;
 
-    red_image = alloc_image(display_channel);
-    ASSERT(red_image);
-
-    QXL_SET_IMAGE_ID(red_image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
-    red_image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
-    red_image->descriptor.flags = item->image_flags;
-    red_image->descriptor.width = item->width;
-    red_image->descriptor.height = item->height;
+    QXL_SET_IMAGE_ID(&red_image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
+    red_image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
+    red_image.descriptor.flags = item->image_flags;
+    red_image.descriptor.width = item->width;
+    red_image.descriptor.height = item->height;
 
     bitmap.format = item->image_format;
     bitmap.flags = QXL_BITMAP_DIRECT;
@@ -8759,26 +8908,35 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     bitmap.palette = 0;
     bitmap.data = (SPICE_ADDRESS)item->data;
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_COPY;
-
-    add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.copy, sizeof(SpiceMsgDisplayDrawCopy), 0, 0);
-    display_channel->send_data.u.copy.base.surface_id = item->surface_id;
-    display_channel->send_data.u.copy.base.box.left = item->pos.x;
-    display_channel->send_data.u.copy.base.box.top = item->pos.y;
-    display_channel->send_data.u.copy.base.box.right = item->pos.x + bitmap.x;
-    display_channel->send_data.u.copy.base.box.bottom = item->pos.y + bitmap.y;
-    display_channel->send_data.u.copy.base.clip.type = SPICE_CLIP_TYPE_NONE;
-    display_channel->send_data.u.copy.base.clip.data = 0;
-    display_channel->send_data.u.copy.data.rop_decriptor = SPICE_ROPD_OP_PUT;
-    display_channel->send_data.u.copy.data.src_area.left = 0;
-    display_channel->send_data.u.copy.data.src_area.top = 0;
-    display_channel->send_data.u.copy.data.src_area.right = bitmap.x;
-    display_channel->send_data.u.copy.data.src_area.bottom = bitmap.y;
-    display_channel->send_data.u.copy.data.scale_mode = 0;
-    display_channel->send_data.u.copy.data.src_bitmap = channel->send_data.header.size;
-    display_channel->send_data.u.copy.data.mask.bitmap = 0;
-
-    compress_send_data_t comp_send_data;
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_COPY;
+
+    copy.base.surface_id = item->surface_id;
+    copy.base.box.left = item->pos.x;
+    copy.base.box.top = item->pos.y;
+    copy.base.box.right = item->pos.x + bitmap.x;
+    copy.base.box.bottom = item->pos.y + bitmap.y;
+    copy.base.clip.type = SPICE_CLIP_TYPE_NONE;
+    copy.base.clip.data = 0;
+    copy.data.rop_decriptor = SPICE_ROPD_OP_PUT;
+    copy.data.src_area.left = 0;
+    copy.data.src_area.top = 0;
+    copy.data.src_area.right = bitmap.x;
+    copy.data.src_area.bottom = bitmap.y;
+    copy.data.scale_mode = 0;
+    copy.data.src_bitmap = 0;
+    copy.data.mask.flags = 0;
+    copy.data.mask.flags = 0;
+    copy.data.mask.pos.x = 0;
+    copy.data.mask.pos.y = 0;
+    copy.data.mask.bitmap = 0;
+
+    SpiceMarshaller *m = channel->send_data.marshaller;
+
+    spice_marshall_msg_display_draw_copy(m, &copy,
+                                         &cliprects_data_out, &clippath_data_out,
+                                         &src_bitmap_out, &mask_bitmap_out);
+
+    compress_send_data_t comp_send_data = {0};
 
     comp_mode = display_channel->base.worker->image_compression;
 
@@ -8803,39 +8961,47 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     }
 
     if (lossy_comp) {
-        comp_succeeded = red_jpeg_compress_image(display_channel, red_image,
+        comp_succeeded = red_jpeg_compress_image(display_channel, &red_image,
                                                  &bitmap, &comp_send_data,
                                                  worker->mem_slots.internal_groupslot_id);
     } else {
         if (!lz_comp) {
-            comp_succeeded = red_quic_compress_image(display_channel, red_image, &bitmap,
+            comp_succeeded = red_quic_compress_image(display_channel, &red_image, &bitmap,
                                                      &comp_send_data,
                                                      worker->mem_slots.internal_groupslot_id);
         } else {
-            comp_succeeded = red_lz_compress_image(display_channel, red_image, &bitmap,
+            comp_succeeded = red_lz_compress_image(display_channel, &red_image, &bitmap,
                                                    &comp_send_data,
                                                    worker->mem_slots.internal_groupslot_id);
         }
     }
-  
+
     surface_lossy_region = &display_channel->surface_client_lossy_region[item->surface_id];
     if (comp_succeeded) {
-        add_buf(channel, BUF_TYPE_RAW, red_image, comp_send_data.raw_size, 0, 0);
-        add_buf(channel, BUF_TYPE_COMPRESS_BUF, comp_send_data.comp_buf,
-                comp_send_data.comp_buf_size, 0, 0);
+        spice_marshall_Image(src_bitmap_out, (SpiceImageDescriptor *)&red_image,
+                             &bitmap_palette_out, &data_out, &lzplt_palette_out);
+
+        marshaller_add_compressed(worker, src_bitmap_out,
+                                  comp_send_data.comp_buf, comp_send_data.comp_buf_size);
+
+        if (comp_send_data.lzplt_palette) {
+            spice_marshall_Palette(lzplt_palette_out, comp_send_data.lzplt_palette);
+        }
+
         if (lossy_comp) {
-            region_add(surface_lossy_region, &display_channel->send_data.u.copy.base.box);
+            region_add(surface_lossy_region, &copy.base.box);
         } else {
-            region_remove(surface_lossy_region, &display_channel->send_data.u.copy.base.box);
+            region_remove(surface_lossy_region, &copy.base.box);
         }
     } else {
-        red_image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
-        red_image->bitmap = bitmap;
-        red_image->bitmap.flags &= ~QXL_BITMAP_DIRECT;
-        add_buf(channel, BUF_TYPE_RAW, red_image, sizeof(SpiceBitmapImage), 0, 0);
-        red_image->bitmap.data = channel->send_data.header.size;
-        add_buf(channel, BUF_TYPE_RAW, item->data, bitmap.y * bitmap.stride, 0, 0);
-        region_remove(surface_lossy_region, &display_channel->send_data.u.copy.base.box);
+        red_image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
+        red_image.bitmap = bitmap;
+        red_image.bitmap.flags &= ~QXL_BITMAP_DIRECT;
+
+        spice_marshall_Image(src_bitmap_out, (SpiceImageDescriptor *)&red_image,
+                             &bitmap_palette_out, &data_out, &lzplt_palette_out);
+        spice_marshaller_add_ref(data_out, item->data, bitmap.y * bitmap.stride);
+        region_remove(surface_lossy_region, &copy.base.box);
     }
     display_begin_send_massage(display_channel, &item->link);
 }
@@ -8844,27 +9010,37 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
 {
     RedChannel *channel;
     QXLDrawable *qxl_drawable;
-    SpiceMsgDisplayDrawCopy *copy = &display_channel->send_data.u.copy;
+    SpiceMsgDisplayDrawCopy copy;
+    SpiceMarshaller *cliprects_data_out, *clippath_data_out, *src_bitmap_out, *mask_bitmap_out;
+    int i;
 
     ASSERT(display_channel && item && item->drawable);
     channel = &display_channel->base;
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_COPY;
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_COPY;
 
     qxl_drawable = item->drawable->qxl_drawable;
     ASSERT(qxl_drawable->type == QXL_DRAW_COPY);
     ASSERT(qxl_drawable->u.copy.rop_decriptor == SPICE_ROPD_OP_PUT);
     ASSERT(qxl_drawable->u.copy.mask.bitmap == 0);
 
-    add_buf(channel, BUF_TYPE_RAW, copy, sizeof(SpiceMsgDisplayDrawCopy), 0, 0);
-    copy->base.surface_id = 0;
-    copy->base.box = qxl_drawable->bbox;
-    copy->base.clip.type = SPICE_CLIP_TYPE_RECTS;
-    copy->base.clip.data = channel->send_data.header.size;
-    add_buf(channel, BUF_TYPE_RAW, &item->n_rects, sizeof(uint32_t), 0, 0);
-    add_buf(channel, BUF_TYPE_RAW, item->rects, sizeof(SpiceRect) * item->n_rects, 0, 0);
-    copy->data = qxl_drawable->u.copy;
-    fill_bits(display_channel, &copy->data.src_bitmap, item->drawable, FALSE);
+    copy.base.surface_id = 0;
+    copy.base.box = qxl_drawable->bbox;
+    copy.base.clip.type = SPICE_CLIP_TYPE_RECTS;
+    copy.base.clip.data = 0;
+    copy.data = qxl_drawable->u.copy;
+
+    SpiceMarshaller *m = channel->send_data.marshaller;
+
+    spice_marshall_msg_display_draw_copy(m, &copy,
+                                         &cliprects_data_out, &clippath_data_out,
+                                         &src_bitmap_out, &mask_bitmap_out);
+
+    spice_marshaller_add_uint32(cliprects_data_out, item->n_rects);
+    for (i = 0; i < item->n_rects; i++) {
+        spice_marshall_Rect(cliprects_data_out, &item->rects[i]);
+    }
+    fill_bits(display_channel, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
 
     display_begin_send_massage(display_channel, &item->base);
 }
@@ -8876,35 +9052,44 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
 
     agent->lats_send_time = 0;
     ASSERT(stream);
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_STREAM_CREATE;
-    SpiceMsgDisplayStreamCreate *stream_create = &display_channel->send_data.u.stream_create.message;
-    stream_create->surface_id = 0;
-    stream_create->id = agent - display_channel->stream_agents;
-    stream_create->flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0;
-    stream_create->codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG;
-
-    stream_create->src_width = stream->width;
-    stream_create->src_height = stream->height;
-    stream_create->stream_width = SPICE_ALIGN(stream_create->src_width, 2);
-    stream_create->stream_height = SPICE_ALIGN(stream_create->src_height, 2);
-    stream_create->dest = stream->dest_area;
-
-    add_buf(channel, BUF_TYPE_RAW, stream_create, sizeof(*stream_create), 0, 0);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_CREATE;
+    SpiceMsgDisplayStreamCreate stream_create;
+    SpiceMarshaller *cliprects_data_out, *clippath_data_out;
+
+    stream_create.surface_id = 0;
+    stream_create.id = agent - display_channel->stream_agents;
+    stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0;
+    stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG;
+
+    stream_create.src_width = stream->width;
+    stream_create.src_height = stream->height;
+    stream_create.stream_width = SPICE_ALIGN(stream_create.src_width, 2);
+    stream_create.stream_height = SPICE_ALIGN(stream_create.src_height, 2);
+    stream_create.dest = stream->dest_area;
+
+    if (stream->current) {
+        QXLDrawable *qxl_drawable = stream->current->qxl_drawable;
+        stream_create.clip = qxl_drawable->clip;
+    } else {
+        stream_create.clip.type = SPICE_CLIP_TYPE_RECTS;
+        stream_create.clip.data = 0;
+    }
+
+    spice_marshall_msg_display_stream_create(channel->send_data.marshaller, &stream_create,
+                                             &cliprects_data_out, &clippath_data_out);
+
+
     if (stream->current) {
         QXLDrawable *qxl_drawable = stream->current->qxl_drawable;
-        stream_create->clip = qxl_drawable->clip;
         if (qxl_drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
-            fill_rects_clip(channel, &stream_create->clip.data, stream->current->group_id);
+            fill_rects_clip(channel, cliprects_data_out, stream_create.clip.data,
+                            stream->current->group_id);
         } else {
             ASSERT(qxl_drawable->clip.type == SPICE_CLIP_TYPE_NONE);
         }
         display_begin_send_massage(display_channel, &stream->current->pipe_item);
     } else {
-        stream_create->clip.type = SPICE_CLIP_TYPE_RECTS;
-        stream_create->clip.data = channel->send_data.header.size;
-        display_channel->send_data.u.stream_create.num_rects = 0;
-        add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.stream_create.num_rects,
-                sizeof(uint32_t), 0, 0);
+        spice_marshaller_add_uint32(cliprects_data_out, 0);
         display_begin_send_massage(display_channel, NULL);
     }
 }
@@ -8916,20 +9101,26 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
 
     StreamAgent *agent = item->stream_agent;
     Stream *stream = agent->stream;
+    int i;
 
     ASSERT(stream);
 
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_STREAM_CLIP;
-    SpiceMsgDisplayStreamClip *stream_clip = &display_channel->send_data.u.stream_clip;
-    add_buf(channel, BUF_TYPE_RAW, stream_clip, sizeof(*stream_clip), 0, 0);
-    stream_clip->id = agent - display_channel->stream_agents;
-    if ((stream_clip->clip.type = item->clip_type) == SPICE_CLIP_TYPE_NONE) {
-        stream_clip->clip.data = 0;
-    } else {
-        ASSERT(stream_clip->clip.type == SPICE_CLIP_TYPE_RECTS);
-        stream_clip->clip.data = channel->send_data.header.size;
-        add_buf(channel, BUF_TYPE_RAW, &item->n_rects, sizeof(uint32_t), 0, 0);
-        add_buf(channel, BUF_TYPE_RAW, item->rects, item->n_rects * sizeof(SpiceRect), 0, 0);
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_CLIP;
+    SpiceMsgDisplayStreamClip stream_clip;
+    SpiceMarshaller *cliprects_data_out, *clippath_data_out;
+
+    stream_clip.id = agent - display_channel->stream_agents;
+    stream_clip.clip.type = item->clip_type;
+    stream_clip.clip.data = 0;
+
+    spice_marshall_msg_display_stream_clip(channel->send_data.marshaller, &stream_clip,
+                                           &cliprects_data_out, &clippath_data_out);
+
+    if (stream_clip.clip.type == SPICE_CLIP_TYPE_RECTS) {
+        spice_marshaller_add_uint32(cliprects_data_out, item->n_rects);
+        for (i = 0; i < item->n_rects; i++) {
+            spice_marshall_Rect(cliprects_data_out, &item->rects[i]);
+        }
     }
     display_begin_send_massage(display_channel, item);
 }
@@ -8937,35 +9128,41 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
 static void red_display_send_stream_end(DisplayChannel *display_channel, StreamAgent* agent)
 {
     RedChannel *channel = &display_channel->base;
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_STREAM_DESTROY;
-    display_channel->send_data.u.stream_destroy.id = agent - display_channel->stream_agents;
-    add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.stream_destroy,
-            sizeof(SpiceMsgDisplayStreamDestroy), 0, 0);
+    SpiceMsgDisplayStreamDestroy destroy;
+
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_DESTROY;
+    destroy.id = agent - display_channel->stream_agents;
+
+    spice_marshall_msg_display_stream_destroy(channel->send_data.marshaller, &destroy);
+
     display_begin_send_massage(display_channel, NULL);
 }
 
 static void red_cursor_send_inval(CursorChannel *channel, CacheItem *cach_item)
 {
     ASSERT(channel);
-    red_send_inval((RedChannel *)channel, cach_item, &channel->send_data.u.inval_one);
+    red_send_inval((RedChannel *)channel, cach_item);
 }
 
 static void red_send_cursor_init(CursorChannel *channel)
 {
     RedWorker *worker;
+    SpiceMsgCursorInit msg;
+    AddBufInfo info;
+
     ASSERT(channel);
 
     worker = channel->base.worker;
 
-    channel->base.send_data.header.type = SPICE_MSG_CURSOR_INIT;
-    channel->send_data.u.cursor_init.visible = worker->cursor_visible;
-    channel->send_data.u.cursor_init.position = worker->cursor_position;
-    channel->send_data.u.cursor_init.trail_length = worker->cursor_trail_length;
-    channel->send_data.u.cursor_init.trail_frequency = worker->cursor_trail_frequency;
-    add_buf(&channel->base, BUF_TYPE_RAW, &channel->send_data.u.cursor_init, sizeof(SpiceMsgCursorInit),
-            0, 0);
+    channel->base.send_data.header->type = SPICE_MSG_CURSOR_INIT;
+    msg.visible = worker->cursor_visible;
+    msg.position = worker->cursor_position;
+    msg.trail_length = worker->cursor_trail_length;
+    msg.trail_frequency = worker->cursor_trail_frequency;
 
-    fill_cursor(channel, &channel->send_data.u.cursor_init.cursor, worker->cursor);
+    fill_cursor(channel, &msg.cursor, worker->cursor, &info);
+    spice_marshall_msg_cursor_init(channel->base.send_data.marshaller, &msg);
+    add_buf_from_info(&channel->base, channel->base.send_data.marshaller, &info);
 
     red_begin_send_massage(&channel->base, worker->cursor);
 }
@@ -8973,16 +9170,19 @@ static void red_send_cursor_init(CursorChannel *channel)
 static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cursor)
 {
     RedChannel *channel;
+    SpiceMsgCursorSet cursor_set;
+    AddBufInfo info;
 
     ASSERT(cursor_channel);
 
     channel = &cursor_channel->base;
-    channel->send_data.header.type = SPICE_MSG_CURSOR_SET;
-    cursor_channel->send_data.u.cursor_set.position = cursor->position;
-    cursor_channel->send_data.u.cursor_set.visible = channel->worker->cursor_visible;
-    add_buf(channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.cursor_set,
-            sizeof(SpiceMsgCursorSet), 0, 0);
-    fill_cursor(cursor_channel, &cursor_channel->send_data.u.cursor_set.cursor, &cursor->base);
+    channel->send_data.header->type = SPICE_MSG_CURSOR_SET;
+    cursor_set.position = cursor->position;
+    cursor_set.visible = channel->worker->cursor_visible;
+
+    fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
+    spice_marshall_msg_cursor_set(channel->send_data.marshaller, &cursor_set);
+    add_buf_from_info(channel, channel->send_data.marshaller, &info);
 
     red_begin_send_massage(channel, cursor);
 
@@ -8991,10 +9191,12 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
 
 static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
 {
-    cursor_channel->base.send_data.header.type = SPICE_MSG_MIGRATE;
-    cursor_channel->send_data.u.migrate.flags = 0;
-    add_buf((RedChannel*)cursor_channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.migrate,
-            sizeof(cursor_channel->send_data.u.migrate), 0, 0);
+    SpiceMsgMigrate migrate;
+
+    cursor_channel->base.send_data.header->type = SPICE_MSG_MIGRATE;
+    migrate.flags = 0;
+
+    spice_marshall_msg_migrate(cursor_channel->base.send_data.marshaller, &migrate);
     red_begin_send_massage((RedChannel*)cursor_channel, NULL);
 }
 
@@ -9002,36 +9204,49 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
 {
     RedChannel *channel;
     QXLCursorCmd *cmd;
+    SpiceMarshaller *m;
 
     ASSERT(cursor_channel);
 
     channel = &cursor_channel->base;
+    m = channel->send_data.marshaller;
 
     cmd = cursor->qxl_cursor;
     switch (cmd->type) {
     case QXL_CURSOR_MOVE:
-        channel->send_data.header.type = SPICE_MSG_CURSOR_MOVE;
-        cursor_channel->send_data.u.cursor_move.position = cmd->u.position;
-        add_buf(channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.cursor_move,
-                sizeof(SpiceMsgCursorMove), 0, 0);
-        break;
+        {
+            SpiceMsgCursorMove cursor_move;
+            channel->send_data.header->type = SPICE_MSG_CURSOR_MOVE;
+            cursor_move.position = cmd->u.position;
+            spice_marshall_msg_cursor_move(m, &cursor_move);
+            break;
+        }
     case QXL_CURSOR_SET:
-        channel->send_data.header.type = SPICE_MSG_CURSOR_SET;
-        cursor_channel->send_data.u.cursor_set.position = cmd->u.set.position;
-        cursor_channel->send_data.u.cursor_set.visible = channel->worker->cursor_visible;
-        add_buf(channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.cursor_set,
-                sizeof(SpiceMsgCursorSet), 0, 0);
-        fill_cursor(cursor_channel, &cursor_channel->send_data.u.cursor_set.cursor, cursor);
-        break;
+        {
+            SpiceMsgCursorSet cursor_set;
+            AddBufInfo info;
+
+            channel->send_data.header->type = SPICE_MSG_CURSOR_SET;
+            cursor_set.position = cmd->u.set.position;
+            cursor_set.visible = channel->worker->cursor_visible;
+
+            fill_cursor(cursor_channel, &cursor_set.cursor, cursor, &info);
+            spice_marshall_msg_cursor_set(m, &cursor_set);
+            add_buf_from_info(channel, m, &info);
+            break;
+        }
     case QXL_CURSOR_HIDE:
-        channel->send_data.header.type = SPICE_MSG_CURSOR_HIDE;
+        channel->send_data.header->type = SPICE_MSG_CURSOR_HIDE;
         break;
     case QXL_CURSOR_TRAIL:
-        channel->send_data.header.type = SPICE_MSG_CURSOR_TRAIL;
-        cursor_channel->send_data.u.cursor_trail.length = cmd->u.trail.length;
-        cursor_channel->send_data.u.cursor_trail.frequency = cmd->u.trail.frequency;
-        add_buf(channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.cursor_trail,
-                sizeof(SpiceMsgCursorTrail), 0, 0);
+        {
+            SpiceMsgCursorTrail cursor_trail;
+
+            channel->send_data.header->type = SPICE_MSG_CURSOR_TRAIL;
+            cursor_trail.length = cmd->u.trail.length;
+            cursor_trail.frequency = cmd->u.trail.frequency;
+            spice_marshall_msg_cursor_trail(m, &cursor_trail);
+        }
         break;
     default:
         red_error("bad cursor command %d", cmd->type);
@@ -9050,11 +9265,9 @@ static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCrea
     channel = &display->base;
 
     region_init(&display->surface_client_lossy_region[surface_create->surface_id]);
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_SURFACE_CREATE;
-    display->send_data.u.surface_create = *surface_create;
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_SURFACE_CREATE;
 
-    add_buf(channel, BUF_TYPE_RAW, &display->send_data.u.surface_create,
-            sizeof(SpiceMsgSurfaceCreate), 0, 0);
+    spice_marshall_msg_display_surface_create(channel->send_data.marshaller, surface_create);
 
     red_begin_send_massage(channel, NULL);
 }
@@ -9062,16 +9275,17 @@ static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCrea
 static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_id)
 {
     RedChannel *channel;
+    SpiceMsgSurfaceDestroy surface_destroy;
 
     ASSERT(display);
     channel = &display->base;
 
     region_destroy(&display->surface_client_lossy_region[surface_id]);
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_SURFACE_DESTROY;
-    display->send_data.u.surface_destroy.surface_id = surface_id;
+    channel->send_data.header->type = SPICE_MSG_DISPLAY_SURFACE_DESTROY;
+
+    surface_destroy.surface_id = surface_id;
 
-    add_buf(channel, BUF_TYPE_RAW, &display->send_data.u.surface_destroy,
-            sizeof(SpiceMsgSurfaceDestroy), 0, 0);
+    spice_marshall_msg_display_surface_destroy(channel->send_data.marshaller, &surface_destroy);
 
     red_begin_send_massage(channel, NULL);
 }
@@ -9327,6 +9541,7 @@ static void red_disconnect_channel(RedChannel *channel)
     channel->peer = NULL;
     channel->send_data.blocked = FALSE;
     channel->send_data.size = channel->send_data.pos = 0;
+    spice_marshaller_reset(channel->send_data.marshaller);
     red_unref_channel(channel);
 }
 
@@ -9951,8 +10166,8 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, SpiceDat
         red_printf("invalid content");
         return FALSE;
     }
-    ASSERT(channel->base.send_data.header.serial == 0);
-    channel->base.send_data.header.serial = migrate_data->message_serial;
+    ASSERT(channel->base.send_data.serial == 0);
+    channel->base.send_data.serial = migrate_data->message_serial;
     if (!(channel->pixmap_cache = red_get_pixmap_cache(migrate_data->pixmap_cache_id, -1))) {
         return FALSE;
     }
@@ -10108,6 +10323,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, RedsStreamContext
     channel->recive_data.now = channel->recive_data.buf;
     channel->recive_data.end = channel->recive_data.buf + sizeof(channel->recive_data.buf);
     ring_init(&channel->pipe);
+    channel->send_data.marshaller = spice_marshaller_new();
 
     event.events = EPOLLIN | EPOLLOUT | EPOLLET;
     event.data.ptr = channel;
commit e2728082d0d11b7293a93bedb93dac98511fb561
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 1 18:14:51 2010 +0200

    Generate marshallers in server

diff --git a/server/Makefile.am b/server/Makefile.am
index ff97a40..7cd9218 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -18,6 +18,15 @@ INCLUDES = \
 	$(VISIBILITY_HIDDEN_CFLAGS)		\
 	$(NULL)
 
+spice_built_sources = generated_marshallers.c generated_marshallers.h
+
+STRUCTS=-M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlnd -M PathSegment
+generated_marshallers.c: $(top_srcdir)/spice.proto
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server $(top_srcdir)/spice.proto generated_marshallers.c
+
+generated_marshallers.h: $(top_srcdir)/spice.proto
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server -H $(top_srcdir)/spice.proto generated_marshallers.h
+
 COMMON_SRCS =						\
 	$(top_srcdir)/common/sw_canvas.c		\
 	$(top_srcdir)/common/pixman_utils.c		\
@@ -90,6 +99,8 @@ libspice_server_la_SOURCES =			\
 	red_channel.c				\
 	spice.h					\
 	spice-experimental.h			\
+	generated_marshallers.c			\
+	generated_marshallers.h			\
 	$(TUNNEL_SRCS)				\
 	$(COMMON_SRCS)				\
 	$(NULL)
@@ -104,3 +115,5 @@ EXTRA_DIST =					\
 	glz_encode_match_tmpl.c			\
 	glz_encode_tmpl.c			\
 	$(NULL)
+
+BUILT_SOURCES = $(spice_built_sources)
commit c36efa5950e07f7795c8b34709f1e770adfad80d
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Jun 17 10:07:36 2010 +0200

    Use @ptr32 for 32bit offsets in spice.proto

diff --git a/spice.proto b/spice.proto
index 7952f9a..d41137f 100644
--- a/spice.proto
+++ b/spice.proto
@@ -1031,8 +1031,8 @@ channel TunnelChannel : BaseChannel {
 	uint32 id;
 	uint32 group;
 	uint32 port;
-	uint32 name;
-	uint32 description;
+	uint8 *name[] @ptr32;
+	uint8 *description[] @ptr32;
 	switch (type) {
 	case IPP:
 	    TunnelIpInfo ip @ctype(SpiceMsgTunnelIpInfo);
commit 635ad37ee9df0861860f49dc602044b356f08cb2
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 11 16:39:27 2010 +0200

    Add @nomarshal in a few places where we're marshalling manually

diff --git a/spice.proto b/spice.proto
index 32ad869..7952f9a 100644
--- a/spice.proto
+++ b/spice.proto
@@ -130,8 +130,8 @@ channel BaseChannel {
 	notify_visibility visibilty;
 	uint32 what; /* error_code/warn_code/info_code */
 	uint32 message_len;
-	uint8 message[message_len] @end;
-	uint8 zero @end @ctype(uint8_t) @zero;
+	uint8 message[message_len] @end @nomarshal;
+	uint8 zero @end @ctype(uint8_t) @zero  @nomarshal;
     } notify;
 
  client:
@@ -171,8 +171,8 @@ channel MainChannel : BaseChannel {
 	pubkey_type pub_key_type @minor(2);
 	uint32 pub_key_offset @minor(2);
 	uint32 pub_key_size @minor(2);
-	uint8 host_data[host_size] @end @ctype(uint8_t) @zero_terminated;
-	uint8 pub_key_data[pub_key_size] @minor(2) @end @ctype(uint8_t) @zero_terminated;
+	uint8 host_data[host_size] @end @ctype(uint8_t) @zero_terminated @nomarshal;
+	uint8 pub_key_data[pub_key_size] @minor(2) @end @ctype(uint8_t) @zero_terminated @nomarshal;
     } @ctype(SpiceMsgMainMigrationBegin) migrate_begin = 101;
 
     Empty migrate_cancel;
@@ -455,7 +455,7 @@ struct BitmapData {
 
 struct BinaryData {
     uint32 data_size;
-    uint8 data[data_size] @end;
+    uint8 data[data_size] @end @nomarshal;
 } @ctype(SpiceQUICData);
 
 struct LZPLTData {
@@ -467,7 +467,7 @@ struct LZPLTData {
     default:
 	Palette *palette @nonnull @outvar(lzplt);
     } pal @anon;
-    uint8 data[data_size] @end;
+    uint8 data[data_size] @end @nomarshal;
 };
 
 struct Surface {
@@ -561,7 +561,7 @@ struct String {
 	RasterGlyphA4 glyphs[length] @ctype(SpiceRasterGlyph);
     case RASTER_A8:
 	RasterGlyphA8 glyphs[length] @ctype(SpiceRasterGlyph);
-    } u @end;
+    } u @end @nomarshal;
 };
 
 channel DisplayChannel : BaseChannel {
@@ -614,8 +614,8 @@ channel DisplayChannel : BaseChannel {
 	uint32 multi_media_time;
 	uint32 data_size;
 	uint32 pad_size;
-	uint8 data[data_size] @end;
-	uint8 padding[pad_size] @end @ctype(uint8_t); /* Uhm, why are we sending padding over network? */
+	uint8 data[data_size] @end  @nomarshal;
+	uint8 padding[pad_size] @end @ctype(uint8_t)  @nomarshal; /* Uhm, why are we sending padding over network? */
     } stream_data;
 
     message {
@@ -952,7 +952,7 @@ channel RecordChannel : BaseChannel {
  client:
     message {
 	uint32 time;
-	uint8 data[] @end;
+	uint8 data[] @end @nomarshal;
     } @ctype(SpiceMsgcRecordPacket) data = 101;
 
     message {
@@ -982,7 +982,7 @@ struct TunnelIpInfo {
     switch (type) {
     case IPv4:
 	uint8 ipv4[4] @ctype(uint8_t);
-    } u @end;
+    } u @end @nomarshal;
 } @ctype(SpiceMsgTunnelIpInfo);
 
 channel TunnelChannel : BaseChannel {
commit a7284761be3d45b2be4bab27725556a668dc491e
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 1 21:54:16 2010 +0200

    spice.proto: add @outvar markup
    
    With this we can reference pointer member with no naming conflicts

diff --git a/spice.proto b/spice.proto
index dec6a63..32ad869 100644
--- a/spice.proto
+++ b/spice.proto
@@ -409,9 +409,9 @@ struct Clip {
     case NONE:
         uint64 data @zero;
       case RECTS:
-        ClipRects *data;
+        ClipRects *data @outvar(cliprects);
     case PATH:
-        Path *data;
+        Path *data @outvar(clippath);
     } u @anon;
 };
 
@@ -448,7 +448,7 @@ struct BitmapData {
     case PAL_FROM_CACHE:
 	uint64 palette;
     default:
-	Palette *palette;
+	Palette *palette @outvar(bitmap);
     } pal @anon;
     uint8 *data[image_size(8, stride, y)] @nocopy; /* pointer to array, not array of pointers as in C */
 } @ctype(SpiceBitmap);
@@ -465,7 +465,7 @@ struct LZPLTData {
     case PAL_FROM_CACHE:
 	uint64 palette;
     default:
-	Palette *palette @nonnull;
+	Palette *palette @nonnull @outvar(lzplt);
     } pal @anon;
     uint8 data[data_size] @end;
 };
@@ -632,9 +632,9 @@ channel DisplayChannel : BaseChannel {
     message {
 	DisplayBase base;
 	struct Fill {
-	    Brush brush;
+	    Brush brush @outvar(brush);
 	    uint16 rop_decriptor;
-	    QMask mask;
+	    QMask mask @outvar(mask);
 	} data;
     } draw_fill = 302;
 
@@ -646,7 +646,7 @@ channel DisplayChannel : BaseChannel {
 	    Brush brush;
 	    ropd rop_decriptor;
 	    image_scale_mode scale_mode;
-	    QMask mask;
+	    QMask mask @outvar(mask);
 	} data;
     } draw_opaque;
 
@@ -657,7 +657,7 @@ channel DisplayChannel : BaseChannel {
 	    Rect src_area;
 	    ropd rop_decriptor;
 	    image_scale_mode scale_mode;
-	    QMask mask;
+	    QMask mask @outvar(mask);
 	} data;
     } draw_copy;
 
@@ -668,28 +668,28 @@ channel DisplayChannel : BaseChannel {
 	    Rect src_area;
 	    ropd rop_decriptor;
 	    image_scale_mode scale_mode;
-	    QMask mask;
+	    QMask mask @outvar(mask);
 	} @ctype(SpiceCopy) data;
     } draw_blend;
 
     message {
 	DisplayBase base;
 	struct Blackness {
-	    QMask mask;
+	    QMask mask @outvar(mask);
 	} data;
     } draw_blackness;
 
     message {
 	DisplayBase base;
 	struct Whiteness {
-	    QMask mask;
+	    QMask mask @outvar(mask);
 	} data;
     } draw_whiteness;
 
     message {
 	DisplayBase base;
 	struct Invers {
-	    QMask mask;
+	    QMask mask @outvar(mask);
 	} data;
     } draw_invers;
 
@@ -701,7 +701,7 @@ channel DisplayChannel : BaseChannel {
 	    Brush brush;
 	    uint8 rop3;
 	    image_scale_mode scale_mode;
-	    QMask mask;
+	    QMask mask @outvar(mask);
 	} data;
     } draw_rop3;
 
@@ -721,8 +721,8 @@ channel DisplayChannel : BaseChannel {
 	struct Text {
 	    String *str;
 	    Rect back_area;
-	    Brush fore_brush;
-	    Brush back_brush;
+	    Brush fore_brush @outvar(fore_brush);
+	    Brush back_brush @outvar(back_brush);
 	    uint16 fore_mode;
 	    uint16 back_mode;
 	} data;
commit 936b3f01f9ba9779385986e1beb342007ec7e981
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Jun 14 16:11:39 2010 +0200

    Add support for generating message and structure marshallers

diff --git a/python_modules/marshal.py b/python_modules/marshal.py
new file mode 100644
index 0000000..23b029a
--- /dev/null
+++ b/python_modules/marshal.py
@@ -0,0 +1,357 @@
+import ptypes
+import codegen
+
+def write_includes(writer):
+    writer.header.writeln("#include <spice/protocol.h>")
+    writer.header.writeln("#include <marshaller.h>")
+    writer.header.newline()
+    writer.header.writeln("#ifndef _GENERATED_HEADERS_H")
+    writer.header.writeln("#define _GENERATED_HEADERS_H")
+
+    writer.writeln("#include <string.h>")
+    writer.writeln("#include <assert.h>")
+    writer.writeln("#include <stdlib.h>")
+    writer.writeln("#include <stdio.h>")
+    writer.writeln("#include <spice/protocol.h>")
+    writer.writeln("#include <spice/macros.h>")
+    writer.writeln("#include <marshaller.h>")
+    writer.newline()
+    writer.writeln("#ifdef _MSC_VER")
+    writer.writeln("#pragma warning(disable:4101)")
+    writer.writeln("#endif")
+    writer.newline()
+
+class MarshallingSource:
+    def __init__(self):
+        pass
+
+    def child_at_end(self, t):
+        return RootMarshallingSource(self, t.c_type(), t.sizeof())
+
+    def child_sub(self, member):
+        return SubMarshallingSource(self, member)
+
+    def declare(self, writer):
+        return writer.optional_block(self.reuse_scope)
+
+    def is_toplevel(self):
+        return self.parent_src == None and not self.is_helper
+
+class RootMarshallingSource(MarshallingSource):
+    def __init__(self, parent_src, c_type, sizeof, pointer = None):
+        self.is_helper = False
+        self.reuse_scope = None
+        self.parent_src = parent_src
+        if parent_src:
+            self.base_var = codegen.increment_identifier(parent_src.base_var)
+        else:
+            self.base_var = "src"
+        self.c_type = c_type
+        self.sizeof = sizeof
+        self.pointer = pointer # None == at "end"
+
+    def get_self_ref(self):
+        return self.base_var
+
+    def get_ref(self, member):
+        return self.base_var + "->" + member
+
+    def declare(self, writer):
+        if self.reuse_scope:
+            scope = self.reuse_scope
+        else:
+            writer.begin_block()
+            scope = writer.get_subwriter()
+
+        scope.variable_def(self.c_type + " *", self.base_var)
+        if not self.reuse_scope:
+            scope.newline()
+
+        if self.pointer:
+            writer.assign(self.base_var, "(%s *)%s" % (self.c_type, self.pointer))
+        else:
+            writer.assign(self.base_var, "(%s *)end" % self.c_type)
+            writer.increment("end", "%s" % self.sizeof)
+        writer.newline()
+
+        if self.reuse_scope:
+            return writer.no_block(self.reuse_scope)
+        else:
+            return writer.partial_block(scope)
+
+class SubMarshallingSource(MarshallingSource):
+    def __init__(self, parent_src, member):
+        self.reuse_scope = None
+        self.parent_src = parent_src
+        self.base_var = parent_src.base_var
+        self.member = member
+        self.is_helper = False
+
+    def get_self_ref(self):
+        return "&%s" % self.parent_src.get_ref(self.member)
+
+    def get_ref(self, member):
+        return self.parent_src.get_ref(self.member) + "." + member
+
+def write_marshal_ptr_function(writer, target_type):
+    if target_type.is_array():
+        marshal_function = "spice_marshall_array_%s" % target_type.element_type.primitive_type()
+    else:
+        marshal_function = "spice_marshall_%s" % target_type.name
+    if writer.is_generated("marshaller", marshal_function):
+        return marshal_function
+
+    writer.set_is_generated("marshaller", marshal_function)
+
+    names = target_type.get_pointer_names()
+    names_args = ""
+    if len(names) > 0:
+        n = map(lambda name: ", SpiceMarshaller **%s" % name, names)
+        names_args = "".join(n)
+
+    header = writer.header
+    writer = writer.function_helper()
+    writer.header = header
+    writer.out_prefix = ""
+    if target_type.is_array():
+        scope = writer.function(marshal_function, "void *", "SpiceMarshaller *m, %s_t *ptr, int count" % target_type.element_type.primitive_type() + names_args)
+    else:
+        scope = writer.function(marshal_function, "void *", "SpiceMarshaller *m, %s *ptr" % target_type.c_type() + names_args)
+        header.writeln("void *" + marshal_function + "(SpiceMarshaller *m, %s *msg" % target_type.c_type() + names_args + ");")
+    scope.variable_def("SPICE_GNUC_UNUSED uint8_t *", "end")
+
+    for n in names:
+        writer.assign("*%s" % n, "NULL")
+
+    writer.newline()
+    writer.assign("end", "(uint8_t *)(ptr+1)")
+
+    if target_type.is_struct():
+        src = RootMarshallingSource(None, target_type.c_type(), target_type.sizeof(), "ptr")
+        src.reuse_scope = scope
+        write_container_marshaller(writer, target_type, src)
+    elif target_type.is_array() and target_type.element_type.is_primitive():
+        with writer.index() as index:
+            with writer.for_loop(index, "count") as array_scope:
+                writer.statement("spice_marshaller_add_%s(m, *ptr++)" % (target_type.element_type.primitive_type()))
+    else:
+        writer.todo("Unsuppored pointer marshaller type")
+
+    writer.statement("return end")
+
+    writer.end_block()
+
+    return marshal_function
+
+def get_array_size(array, container_src):
+    if array.is_constant_length():
+        return array.size
+    elif array.is_identifier_length():
+        return container_src.get_ref(array.size)
+    elif array.is_remaining_length():
+        raise NotImplementedError("remaining size array sizes marshalling not supported")
+    elif array.is_image_size_length():
+        bpp = array.size[1]
+        width = array.size[2]
+        rows = array.size[3]
+        width_v = container_src.get_ref(width)
+        rows_v = container_src.get_ref(rows)
+        # TODO: Handle multiplication overflow
+        if bpp == 8:
+            return "(%s * %s)" % (width_v, rows_v)
+        elif bpp == 1:
+            return "(((%s + 7) / 8 ) * %s)" % (width_v, rows_v)
+        else:
+            return "(((%s * %s + 7) / 8 ) * %s)" % (bpp, width_v, rows_v)
+    elif array.is_bytes_length():
+        return container_src.get_ref(array.size[1])
+    else:
+        raise NotImplementedError("TODO array size type not handled yet")
+
+def write_array_marshaller(writer, at_end, member, array, container_src, scope):
+    element_type = array.element_type
+
+    if array.is_remaining_length():
+        writer.comment("Remaining data must be appended manually").newline()
+        return
+
+    nelements = get_array_size(array, container_src)
+    is_byte_size = array.is_bytes_length()
+
+    if is_byte_size:
+        element = "%s__bytes" % member.name
+    else:
+        element = "%s__element" % member.name
+
+    if not at_end:
+        writer.assign(element, container_src.get_ref(member.name))
+
+    if is_byte_size:
+        scope.variable_def("size_t", "array_end")
+        writer.assign("array_end", "spice_marshaller_get_size(m) + %s" % nelements)
+
+    with writer.index(no_block = is_byte_size) as index:
+        with writer.while_loop("spice_marshaller_get_size(m) < array_end") if is_byte_size else writer.for_loop(index, nelements) as array_scope:
+            array_scope.variable_def(element_type.c_type() + " *", element)
+            if at_end:
+                writer.assign(element, "(%s *)end" % element_type.c_type())
+                writer.increment("end", element_type.sizeof())
+
+            if element_type.is_primitive():
+                writer.statement("spice_marshaller_add_%s(m, *%s)" % (element_type.primitive_type(), element))
+            elif element_type.is_struct():
+                src2 = RootMarshallingSource(container_src, element_type.c_type(), element_type.sizeof(), element)
+                src2.reuse_scope = array_scope
+                write_container_marshaller(writer, element_type, src2)
+            else:
+                writer.todo("array element unhandled type").newline()
+
+            if not at_end:
+                writer.statement("%s++" % element)
+
+def write_switch_marshaller(writer, container, switch, src, scope):
+    var = container.lookup_member(switch.variable)
+    var_type = var.member_type
+
+    saved_out_prefix = writer.out_prefix
+    first = True
+    for c in switch.cases:
+        check = c.get_check(src.get_ref(switch.variable), var_type)
+        m = c.member
+        writer.out_prefix = saved_out_prefix
+        if m.has_attr("outvar"):
+            writer.out_prefix = "%s_%s" % (m.attributes["outvar"][0], writer.out_prefix)
+        with writer.if_block(check, not first, False) as block:
+            t = m.member_type
+            if switch.has_end_attr():
+                src2 = src.child_at_end(m.member_type)
+            elif switch.has_attr("anon"):
+                src2 = src
+            else:
+                if t.is_struct():
+                    src2 = src.child_sub(switch.name + "." + m.name)
+                else:
+                    src2 = src.child_sub(switch.name)
+            src2.reuse_scope = block
+
+            if t.is_struct():
+                write_container_marshaller(writer, t, src2)
+            elif t.is_pointer():
+                ptr_func = write_marshal_ptr_function(writer, t.target_type)
+                writer.assign("*%s_out" % (writer.out_prefix + m.name), "spice_marshaller_get_ptr_submarshaller(m, %s)" % ("0" if m.has_attr("ptr32") else "1"))
+            elif t.is_primitive():
+                if m.has_attr("zero"):
+                    writer.statement("spice_marshaller_add_%s(m, 0)" % (t.primitive_type()))
+                else:
+                    writer.statement("spice_marshaller_add_%s(m, %s)" % (t.primitive_type(), src2.get_ref(m.name)))
+                #TODO validate e.g. flags and enums
+            elif t.is_array():
+                write_array_marshaller(writer, switch.has_end_attr(), m, t, src, scope)
+            else:
+                writer.todo("Can't handle type %s" % m.member_type)
+
+            if switch.has_attr("fixedsize"):
+                remaining = switch.get_fixed_nw_size() - t.get_fixed_nw_size()
+                if remaining != 0:
+                    writer.statement("spice_marshaller_reserve_space(m, %s)" % remaining)
+
+        first = False
+    if switch.has_attr("fixedsize"):
+        with writer.block(" else"):
+            writer.statement("spice_marshaller_reserve_space(m, %s)" % switch.get_fixed_nw_size())
+
+    writer.newline()
+
+def write_member_marshaller(writer, container, member, src, scope):
+    if member.has_attr("outvar"):
+        writer.out_prefix = "%s_%s" % (member.attributes["outvar"][0], writer.out_prefix)
+    if member.has_attr("nomarshal"):
+        writer.comment("Don't marshall @nomarshal %s" % member.name).newline()
+        return
+    if member.is_switch():
+        write_switch_marshaller(writer, container, member, src, scope)
+        return
+
+    t = member.member_type
+
+    if t.is_pointer():
+#        if member.has_attr("nocopy"):
+#            writer.comment("Reuse data from network message").newline()
+#            writer.assign(src.get_ref(member.name), "(size_t)(message_start + consume_uint64(&in))")
+#        else:
+#            write_parse_pointer(writer, t, member.has_end_attr(), src, member.name, scope)
+        ptr_func = write_marshal_ptr_function(writer, t.target_type)
+        writer.assign("*%s_out" % (writer.out_prefix + member.name), "spice_marshaller_get_ptr_submarshaller(m, %s)" % ("0" if member.has_attr("ptr32") else "1"))
+    elif t.is_primitive():
+        if member.has_attr("zero"):
+            writer.statement("spice_marshaller_add_%s(m, 0)" % (t.primitive_type()))
+        elif member.has_end_attr():
+            writer.statement("spice_marshaller_add_%s(m, *(%s_t *)end)" % (t.primitive_type(), t.primitive_type()))
+            writer.increment("end", t.sizeof())
+        else:
+            writer.statement("spice_marshaller_add_%s(m, %s)" % (t.primitive_type(), src.get_ref(member.name)))
+    elif t.is_array():
+        write_array_marshaller(writer, member.has_end_attr(), member, t, src, scope)
+    elif t.is_struct():
+        if member.has_end_attr():
+            src2 = src.child_at_end(t)
+        else:
+            src2 = src.child_sub(member.name)
+        writer.comment(member.name)
+        write_container_marshaller(writer, t, src2)
+    else:
+        raise NotImplementedError("TODO can't handle parsing of %s" % t)
+
+def write_container_marshaller(writer, container, src):
+    saved_out_prefix = writer.out_prefix
+    with src.declare(writer) as scope:
+        for m in container.members:
+            writer.out_prefix = saved_out_prefix
+            write_member_marshaller(writer, container, m, src, scope)
+
+def write_message_marshaller(writer, message, is_server):
+    writer.out_prefix = ""
+    function_name = "spice_marshall_" + message.c_name()
+    if writer.is_generated("marshaller", function_name):
+        return function_name
+    writer.set_is_generated("marshaller", function_name)
+
+    names = message.get_pointer_names()
+    names_args = ""
+    if len(names) > 0:
+        n = map(lambda name: ", SpiceMarshaller **%s" % name, names)
+        names_args = "".join(n)
+
+    writer.header.writeln("void " + function_name + "(SpiceMarshaller *m, %s *msg" % message.c_type() + names_args + ");")
+
+    scope = writer.function(function_name,
+                            "void",
+                            "SpiceMarshaller *m, %s *msg" % message.c_type() + names_args)
+    scope.variable_def("SPICE_GNUC_UNUSED uint8_t *", "end")
+
+    for n in names:
+        writer.assign("*%s" % n, "NULL")
+
+    src = RootMarshallingSource(None, message.c_type(), message.sizeof(), "msg")
+    src.reuse_scope = scope
+
+    writer.assign("end", "(uint8_t *)(msg+1)")
+    write_container_marshaller(writer, message, src)
+
+    writer.end_block()
+    writer.newline()
+
+def write_protocol_marshaller(writer, proto, is_server):
+    for c in proto.channels:
+        channel = c.channel_type
+        if is_server:
+            for m in channel.client_messages:
+                message = m.message_type
+                write_message_marshaller(writer, message, is_server)
+        else:
+            for m in channel.server_messages:
+                message = m.message_type
+                write_message_marshaller(writer, message, is_server)
+
+def write_trailer(writer):
+    writer.header.writeln("#endif")
diff --git a/spice_codegen.py b/spice_codegen.py
index f897ce8..0e9551f 100755
--- a/spice_codegen.py
+++ b/spice_codegen.py
@@ -8,6 +8,7 @@ from python_modules import spice_parser
 from python_modules import ptypes
 from python_modules import codegen
 from python_modules import demarshal
+from python_modules import marshal
 
 def write_channel_enums(writer, channel, client):
     messages = filter(lambda m : m.channel == channel, \
@@ -82,9 +83,18 @@ parser.add_option("-e", "--generate-enums",
 parser.add_option("-d", "--generate-demarshallers",
                   action="store_true", dest="generate_demarshallers", default=False,
                   help="Generate demarshallers")
+parser.add_option("-m", "--generate-marshallers",
+                  action="store_true", dest="generate_marshallers", default=False,
+                  help="Generate message marshallers")
+parser.add_option("-M", "--generate-struct-marshaller",
+                  action="append", dest="struct_marshallers",
+                  help="Generate struct marshallers")
 parser.add_option("-a", "--assert-on-error",
                   action="store_true", dest="assert_on_error", default=False,
                   help="Assert on error")
+parser.add_option("-H", "--header",
+                  action="store_true", dest="header", default=False,
+                  help="Generate header")
 parser.add_option("-p", "--print-error",
                   action="store_true", dest="print_error", default=False,
                   help="Print errors")
@@ -118,6 +128,7 @@ if proto == None:
 
 codegen.set_prefix(proto.name)
 writer = codegen.CodeWriter()
+writer.header = codegen.CodeWriter()
 writer.set_option("source", os.path.basename(proto_file))
 
 if options.assert_on_error:
@@ -143,7 +154,30 @@ if options.generate_demarshallers:
     if options.client:
         demarshal.write_protocol_parser(writer, proto, True)
 
-content = writer.getvalue()
+if options.generate_marshallers or (options.struct_marshallers and len(options.struct_marshallers) > 0):
+    marshal.write_includes(writer)
+
+if options.generate_marshallers:
+    if not options.server and not options.client:
+        print >> sys.stderr, "Must specify client and/or server"
+        sys.exit(1)
+    if options.server:
+        marshal.write_protocol_marshaller(writer, proto, False)
+    if options.client:
+        marshal.write_protocol_marshaller(writer, proto, True)
+
+if options.struct_marshallers:
+    for structname in options.struct_marshallers:
+        t = ptypes.lookup_type(structname)
+        marshal.write_marshal_ptr_function(writer, t)
+
+if options.generate_marshallers or (options.struct_marshallers and len(options.struct_marshallers) > 0):
+    marshal.write_trailer(writer)
+
+if options.header:
+    content = writer.header.getvalue()
+else:
+    content = writer.getvalue()
 if options.keep_identical_file:
     try:
         f = open(dest_file, 'rb')
commit 0cca1ed2af3f74ec6519382c2d52dbfaa9762700
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Jun 14 16:11:04 2010 +0200

    Add SpiceMarshaller for easy marshalling

diff --git a/common/Makefile.am b/common/Makefile.am
index 222965e..5c1d6e0 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -39,6 +39,8 @@ COMMON_SRCS = 				\
 	lz_config.h			\
 	lz_decompress_tmpl.c		\
 	lz.h				\
+	marshaller.h			\
+	marshaller.c			\
 	quic_family_tmpl.c		\
 	quic_rgb_tmpl.c			\
 	quic_tmpl.c			\
diff --git a/common/marshaller.c b/common/marshaller.c
new file mode 100644
index 0000000..13385e5
--- /dev/null
+++ b/common/marshaller.c
@@ -0,0 +1,588 @@
+/* -*- 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/>.
+*/
+
+#include "config.h"
+
+#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((uint63_t)(v)))
+#define write_uint64(ptr,v) (*((uint64_t)(ptr)) = SPICE_BYTESWAP64((uint63_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;
+    SpiceMarshallerData *d;
+
+    /* Only supported for root marshaller */
+    assert(m->data->marshallers == m);
+
+    for (m2 = m; m2 != NULL; m2 = 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);
+}
+
+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));
+            }
+        }
+    }
+}
+
+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 = item->data + skip_bytes;
+            vec[v].iov_len = item->len - skip_bytes;
+            skip_bytes = 0;
+            v++;
+        }
+        m = m->next;
+    } while (m != NULL);
+
+    return v;
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
diff --git a/common/marshaller.h b/common/marshaller.h
new file mode 100644
index 0000000..3b159aa
--- /dev/null
+++ b/common/marshaller.h
@@ -0,0 +1,58 @@
+/* -*- 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 <sys/uio.h>
+
+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_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);
+int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
+                                int n_vec, size_t skip_bytes);
+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);
+
+#endif
diff --git a/server/Makefile.am b/server/Makefile.am
index 8d93618..ff97a40 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -31,6 +31,7 @@ COMMON_SRCS =						\
 	$(top_srcdir)/common/lz.c			\
 	$(top_srcdir)/common/canvas_utils.c		\
 	$(top_srcdir)/common/mem.c			\
+	$(top_srcdir)/common/marshaller.c		\
 	$(NULL)
 
 lib_LTLIBRARIES = libspice-server.la
commit 1a0b3fbdbb4d0c0cb54415e361dcd2af164ecdd7
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed May 26 15:46:42 2010 +0200

    Generate demarshalling code on win32 too

diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
index f980c21..a178a33 100644
--- a/client/windows/redc.vcproj
+++ b/client/windows/redc.vcproj
@@ -29,6 +29,10 @@
 			/>
 			<Tool
 				Name="VCCustomBuildTool"
+				Description=""
+				CommandLine=""
+				AdditionalDependencies=""
+				Outputs=""
 			/>
 			<Tool
 				Name="VCXMLDataGeneratorTool"
@@ -192,10 +196,6 @@
 				>
 			</File>
 			<File
-				RelativePath="..\sw_canvas.cpp"
-				>
-			</File>
-			<File
 				RelativePath="..\canvas.cpp"
 				>
 			</File>
@@ -220,6 +220,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\generated_demarshallers.cpp"
+				>
+			</File>
+			<File
 				RelativePath="..\display_channel.cpp"
 				>
 			</File>
@@ -350,10 +354,6 @@
 				>
 			</File>
 			<File
-				RelativePath="..\red_sw_canvas.cpp"
-				>
-			</File>
-			<File
 				RelativePath="..\red_channel.cpp"
 				>
 			</File>
@@ -378,11 +378,15 @@
 				>
 			</File>
 			<File
+				RelativePath=".\red_pixmap_gdi.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\red_pixmap_sw.cpp"
 				>
 			</File>
 			<File
-				RelativePath=".\red_pixmap_gdi.cpp"
+				RelativePath="..\red_sw_canvas.cpp"
 				>
 			</File>
 			<File
@@ -418,6 +422,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\sw_canvas.cpp"
+				>
+			</File>
+			<File
 				RelativePath="..\threads.cpp"
 				>
 			</File>
@@ -472,6 +480,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\demarshallers.h"
+				>
+			</File>
+			<File
 				RelativePath="..\display_channel.h"
 				>
 			</File>
@@ -572,10 +584,6 @@
 				>
 			</File>
 			<File
-				RelativePath="..\red_sw_canvas.h"
-				>
-			</File>
-			<File
 				RelativePath="..\red_channel.h"
 				>
 			</File>
@@ -600,6 +608,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\red_sw_canvas.h"
+				>
+			</File>
+			<File
 				RelativePath="..\red_window.h"
 				>
 			</File>
@@ -674,6 +686,31 @@
 				>
 			</File>
 		</Filter>
+		<File
+			RelativePath="..\..\spice.proto"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCustomBuildTool"
+					Description="Generating demarshaller"
+					CommandLine="python $(ProjectDir)\..\..\spice_codegen.py -d -c  -i common.h $(ProjectDir)\..\..\spice.proto $(ProjectDir)\..\generated_demarshallers.cpp&#x0D;&#x0A;"
+					AdditionalDependencies=""
+					Outputs="$(ProjectDir)/../generated_demarshallers.cpp"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCustomBuildTool"
+					Description="Generating demarshaller"
+					CommandLine="python $(ProjectDir)\..\..\spice_codegen.py -d -c  -i common.h $(ProjectDir)\..\..\spice.proto $(ProjectDir)\..\generated_demarshallers.cpp"
+					Outputs="$(ProjectDir)/../generated_demarshallers.cpp"
+				/>
+			</FileConfiguration>
+		</File>
 	</Files>
 	<Globals>
 	</Globals>
commit 4154d7028943ca4bf0f1ff2e0480d688fc081fcc
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue May 25 16:01:18 2010 +0200

    Client: Use the autogenerated demarshallers
    
    When a message has been read from the network we now pass it into
    the generated demarshaller for the channel. The demarshaller converts
    the network data to in-memory structures that is passed on to the
    spice internals.
    
    Additionally it also:
    * Converts endianness
    * Validates sizes of message and any pointers in it
    * Localizes offsets (converts them to pointers)
    * Checks for zero offsets in messages where they are not supported
    
    Some of this was previously done using custom code in the client, this
    is now removed.

diff --git a/client/Makefile.am b/client/Makefile.am
index ab80bfb..f8ccb98 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -27,6 +27,8 @@ RED_COMMON_SRCS =			\
 	cmd_line_parser.cpp		\
 	cmd_line_parser.h		\
 	common.h			\
+	demarshallers.h			\
+	generated_demarshallers.cpp	\
 	cursor_channel.cpp		\
 	cursor_channel.h		\
 	cursor.cpp			\
diff --git a/client/canvas.cpp b/client/canvas.cpp
index 4ed1e18..284a814 100644
--- a/client/canvas.cpp
+++ b/client/canvas.cpp
@@ -44,95 +44,14 @@ void Canvas::clear()
     }
 }
 
-
-inline void Canvas::access_test(void *ptr, size_t size)
-{
-    if ((unsigned long)ptr < _base || (unsigned long)ptr + size > _max) {
-        THROW("access violation %p %lu", ptr, size);
-    }
-}
-
-void Canvas::localalize_ptr(SPICE_ADDRESS* data)
-{
-    if (*data) {
-        *data += _base;
-    }
-}
-
-void Canvas::localalize_image(SPICE_ADDRESS* in_bitmap)
-{
-    SpiceImageDescriptor* image;
-
-    ASSERT(*in_bitmap);
-    localalize_ptr(in_bitmap);
-    image = (SpiceImageDescriptor*)SPICE_GET_ADDRESS(*in_bitmap);
-    switch (image->type) {
-    case SPICE_IMAGE_TYPE_SURFACE:
-        break;
-    case SPICE_IMAGE_TYPE_BITMAP: {
-        SpiceBitmapImage *bitmap = (SpiceBitmapImage *)image;
-        localalize_ptr(&bitmap->bitmap.data);
-        if (bitmap->bitmap.palette && !(bitmap->bitmap.flags & SPICE_BITMAP_FLAGS_PAL_FROM_CACHE)) {
-            localalize_ptr(&bitmap->bitmap.palette);
-        }
-        break;
-    }
-    case SPICE_IMAGE_TYPE_LZ_PLT: {
-        SpiceLZPLTImage *lzImage = (SpiceLZPLTImage *)image;
-        ASSERT(lzImage->lz_plt.palette);
-        if (!(lzImage->lz_plt.flags & SPICE_BITMAP_FLAGS_PAL_FROM_CACHE)) {
-            localalize_ptr(&lzImage->lz_plt.palette);
-        }
-        break;
-    }
-    case SPICE_IMAGE_TYPE_LZ_RGB:
-    case SPICE_IMAGE_TYPE_GLZ_RGB:
-    case SPICE_IMAGE_TYPE_QUIC:
-    case SPICE_IMAGE_TYPE_JPEG:
-        break;
-    case SPICE_IMAGE_TYPE_FROM_CACHE:
-    case SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS:
-        break;
-    default:
-        THROW("invalid image type %u", image->type);
-    }
-}
-
-void Canvas::localalize_brush(SpiceBrush& brush)
-{
-    if (brush.type == SPICE_BRUSH_TYPE_PATTERN) {
-        localalize_image(&brush.u.pattern.pat);
-    }
-}
-
-void Canvas::localalize_attr(SpiceLineAttr& attr)
-{
-    if (attr.style_nseg) {
-        localalize_ptr(&attr.style);
-    }
-}
-
-void Canvas::localalize_mask(SpiceQMask& mask)
-{
-    if (mask.bitmap) {
-        localalize_image(&mask.bitmap);
-    }
-}
-
 void Canvas::begin_draw(SpiceMsgDisplayBase& base, int size, size_t min_size)
 {
     _base = (unsigned long)&base;
-    _max = _base + size;
-    _canvas->ops->set_access_params(_canvas, _base, _max);
-    access_test(&base, min_size);
-    localalize_ptr(&base.clip.data);
 }
 
 void Canvas::draw_fill(SpiceMsgDisplayDrawFill& fill, int size)
 {
     begin_draw(fill.base, size, sizeof(SpiceMsgDisplayDrawFill));
-    localalize_brush(fill.data.brush);
-    localalize_mask(fill.data.mask);
     _canvas->ops->draw_fill(_canvas, &fill.base.box, &fill.base.clip, &fill.data);
     touched_bbox(&fill.base.box);
 }
@@ -140,9 +59,6 @@ void Canvas::draw_fill(SpiceMsgDisplayDrawFill& fill, int size)
 void Canvas::draw_text(SpiceMsgDisplayDrawText& text, int size)
 {
     begin_draw(text.base, size, sizeof(SpiceMsgDisplayDrawText));
-    localalize_brush(text.data.fore_brush);
-    localalize_brush(text.data.back_brush);
-    localalize_ptr(&text.data.str);
     _canvas->ops->draw_text(_canvas, &text.base.box, &text.base.clip, &text.data);
     touched_bbox(&text.base.box);
 }
@@ -150,9 +66,6 @@ void Canvas::draw_text(SpiceMsgDisplayDrawText& text, int size)
 void Canvas::draw_opaque(SpiceMsgDisplayDrawOpaque& opaque, int size)
 {
     begin_draw(opaque.base, size, sizeof(SpiceMsgDisplayDrawOpaque));
-    localalize_brush(opaque.data.brush);
-    localalize_image(&opaque.data.src_bitmap);
-    localalize_mask(opaque.data.mask);
     _canvas->ops->draw_opaque(_canvas, &opaque.base.box, &opaque.base.clip, &opaque.data);
     touched_bbox(&opaque.base.box);
 }
@@ -160,8 +73,6 @@ void Canvas::draw_opaque(SpiceMsgDisplayDrawOpaque& opaque, int size)
 void Canvas::draw_copy(SpiceMsgDisplayDrawCopy& copy, int size)
 {
     begin_draw(copy.base, size, sizeof(SpiceMsgDisplayDrawCopy));
-    localalize_image(&copy.data.src_bitmap);
-    localalize_mask(copy.data.mask);
     _canvas->ops->draw_copy(_canvas, &copy.base.box, &copy.base.clip, &copy.data);
     touched_bbox(&copy.base.box);
 }
@@ -169,7 +80,6 @@ void Canvas::draw_copy(SpiceMsgDisplayDrawCopy& copy, int size)
 void Canvas::draw_transparent(SpiceMsgDisplayDrawTransparent& transparent, int size)
 {
     begin_draw(transparent.base, size, sizeof(SpiceMsgDisplayDrawTransparent));
-    localalize_image(&transparent.data.src_bitmap);
     _canvas->ops->draw_transparent(_canvas, &transparent.base.box, &transparent.base.clip, &transparent.data);
     touched_bbox(&transparent.base.box);
 }
@@ -177,7 +87,6 @@ void Canvas::draw_transparent(SpiceMsgDisplayDrawTransparent& transparent, int s
 void Canvas::draw_alpha_blend(SpiceMsgDisplayDrawAlphaBlend& alpha_blend, int size)
 {
     begin_draw(alpha_blend.base, size, sizeof(SpiceMsgDisplayDrawAlphaBlend));
-    localalize_image(&alpha_blend.data.src_bitmap);
     _canvas->ops->draw_alpha_blend(_canvas, &alpha_blend.base.box, &alpha_blend.base.clip, &alpha_blend.data);
     touched_bbox(&alpha_blend.base.box);
 }
@@ -192,8 +101,6 @@ void Canvas::copy_bits(SpiceMsgDisplayCopyBits& copy, int size)
 void Canvas::draw_blend(SpiceMsgDisplayDrawBlend& blend, int size)
 {
     begin_draw(blend.base, size, sizeof(SpiceMsgDisplayDrawBlend));
-    localalize_image(&blend.data.src_bitmap);
-    localalize_mask(blend.data.mask);
     _canvas->ops->draw_blend(_canvas, &blend.base.box, &blend.base.clip, &blend.data);
     touched_bbox(&blend.base.box);
 }
@@ -201,7 +108,6 @@ void Canvas::draw_blend(SpiceMsgDisplayDrawBlend& blend, int size)
 void Canvas::draw_blackness(SpiceMsgDisplayDrawBlackness& blackness, int size)
 {
     begin_draw(blackness.base, size, sizeof(SpiceMsgDisplayDrawBlackness));
-    localalize_mask(blackness.data.mask);
     _canvas->ops->draw_blackness(_canvas, &blackness.base.box, &blackness.base.clip, &blackness.data);
     touched_bbox(&blackness.base.box);
 }
@@ -209,7 +115,6 @@ void Canvas::draw_blackness(SpiceMsgDisplayDrawBlackness& blackness, int size)
 void Canvas::draw_whiteness(SpiceMsgDisplayDrawWhiteness& whiteness, int size)
 {
     begin_draw(whiteness.base, size, sizeof(SpiceMsgDisplayDrawWhiteness));
-    localalize_mask(whiteness.data.mask);
     _canvas->ops->draw_whiteness(_canvas, &whiteness.base.box, &whiteness.base.clip, &whiteness.data);
     touched_bbox(&whiteness.base.box);
 }
@@ -217,7 +122,6 @@ void Canvas::draw_whiteness(SpiceMsgDisplayDrawWhiteness& whiteness, int size)
 void Canvas::draw_invers(SpiceMsgDisplayDrawInvers& invers, int size)
 {
     begin_draw(invers.base, size, sizeof(SpiceMsgDisplayDrawInvers));
-    localalize_mask(invers.data.mask);
     _canvas->ops->draw_invers(_canvas, &invers.base.box, &invers.base.clip, &invers.data);
     touched_bbox(&invers.base.box);
 }
@@ -225,9 +129,6 @@ void Canvas::draw_invers(SpiceMsgDisplayDrawInvers& invers, int size)
 void Canvas::draw_rop3(SpiceMsgDisplayDrawRop3& rop3, int size)
 {
     begin_draw(rop3.base, size, sizeof(SpiceMsgDisplayDrawRop3));
-    localalize_brush(rop3.data.brush);
-    localalize_image(&rop3.data.src_bitmap);
-    localalize_mask(rop3.data.mask);
     _canvas->ops->draw_rop3(_canvas, &rop3.base.box, &rop3.base.clip, &rop3.data);
     touched_bbox(&rop3.base.box);
 }
@@ -235,9 +136,6 @@ void Canvas::draw_rop3(SpiceMsgDisplayDrawRop3& rop3, int size)
 void Canvas::draw_stroke(SpiceMsgDisplayDrawStroke& stroke, int size)
 {
     begin_draw(stroke.base, size, sizeof(SpiceMsgDisplayDrawStroke));
-    localalize_brush(stroke.data.brush);
-    localalize_ptr(&stroke.data.path);
-    localalize_attr(stroke.data.attr);
     _canvas->ops->draw_stroke(_canvas, &stroke.base.box, &stroke.base.clip, &stroke.data);
     touched_bbox(&stroke.base.box);
 }
diff --git a/client/canvas.h b/client/canvas.h
index f0314b9..c988a52 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -452,7 +452,6 @@ private:
     void localalize_ptr(SPICE_ADDRESS* data);
     void localalize_image(SPICE_ADDRESS* in_bitmap);
     void localalize_brush(SpiceBrush& brush);
-    void localalize_attr(SpiceLineAttr& attr);
     void localalize_mask(SpiceQMask& mask);
     void begin_draw(SpiceMsgDisplayBase& base, int size, size_t min_size);
 
diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp
index 44cacd4..26eb4c8 100644
--- a/client/cursor_channel.cpp
+++ b/client/cursor_channel.cpp
@@ -348,10 +348,10 @@ private:
     CursorChannel& _channel;
 };
 
-class CursorHandler: public MessageHandlerImp<CursorChannel, SPICE_MSG_END_CURSOR> {
+class CursorHandler: public MessageHandlerImp<CursorChannel, SPICE_CHANNEL_CURSOR> {
 public:
     CursorHandler(CursorChannel& channel)
-        : MessageHandlerImp<CursorChannel, SPICE_MSG_END_CURSOR>(channel) {}
+      : MessageHandlerImp<CursorChannel, SPICE_CHANNEL_CURSOR>(channel) {}
 };
 
 CursorChannel::CursorChannel(RedClient& client, uint32_t id)
@@ -363,27 +363,21 @@ CursorChannel::CursorChannel(RedClient& client, uint32_t id)
 {
     CursorHandler* handler = static_cast<CursorHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_MIGRATE, &CursorChannel::handle_migrate, 0);
-    handler->set_handler(SPICE_MSG_SET_ACK, &CursorChannel::handle_set_ack, sizeof(SpiceMsgSetAck));
-    handler->set_handler(SPICE_MSG_PING, &CursorChannel::handle_ping, sizeof(SpiceMsgPing));
-    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &CursorChannel::handle_wait_for_channels,
-                         sizeof(SpiceMsgWaitForChannels));
-    handler->set_handler(SPICE_MSG_DISCONNECTING, &CursorChannel::handle_disconnect,
-                         sizeof(SpiceMsgDisconnect));
-    handler->set_handler(SPICE_MSG_NOTIFY, &CursorChannel::handle_notify, sizeof(SpiceMsgNotify));
-
-    handler->set_handler(SPICE_MSG_CURSOR_INIT, &CursorChannel::handle_init, sizeof(SpiceMsgCursorInit));
-    handler->set_handler(SPICE_MSG_CURSOR_RESET, &CursorChannel::handle_reset, 0);
-    handler->set_handler(SPICE_MSG_CURSOR_SET, &CursorChannel::handle_cursor_set,
-                         sizeof(SpiceMsgCursorSet));
-    handler->set_handler(SPICE_MSG_CURSOR_MOVE, &CursorChannel::handle_cursor_move,
-                         sizeof(SpiceMsgCursorMove));
-    handler->set_handler(SPICE_MSG_CURSOR_HIDE, &CursorChannel::handle_cursor_hide, 0);
-    handler->set_handler(SPICE_MSG_CURSOR_TRAIL, &CursorChannel::handle_cursor_trail,
-                         sizeof(SpiceMsgCursorTrail));
-    handler->set_handler(SPICE_MSG_CURSOR_INVAL_ONE, &CursorChannel::handle_inval_one,
-                         sizeof(SpiceMsgDisplayInvalOne));
-    handler->set_handler(SPICE_MSG_CURSOR_INVAL_ALL, &CursorChannel::handle_inval_all, 0);
+    handler->set_handler(SPICE_MSG_MIGRATE, &CursorChannel::handle_migrate);
+    handler->set_handler(SPICE_MSG_SET_ACK, &CursorChannel::handle_set_ack);
+    handler->set_handler(SPICE_MSG_PING, &CursorChannel::handle_ping);
+    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &CursorChannel::handle_wait_for_channels);
+    handler->set_handler(SPICE_MSG_DISCONNECTING, &CursorChannel::handle_disconnect);
+    handler->set_handler(SPICE_MSG_NOTIFY, &CursorChannel::handle_notify);
+
+    handler->set_handler(SPICE_MSG_CURSOR_INIT, &CursorChannel::handle_init);
+    handler->set_handler(SPICE_MSG_CURSOR_RESET, &CursorChannel::handle_reset);
+    handler->set_handler(SPICE_MSG_CURSOR_SET, &CursorChannel::handle_cursor_set);
+    handler->set_handler(SPICE_MSG_CURSOR_MOVE, &CursorChannel::handle_cursor_move);
+    handler->set_handler(SPICE_MSG_CURSOR_HIDE, &CursorChannel::handle_cursor_hide);
+    handler->set_handler(SPICE_MSG_CURSOR_TRAIL, &CursorChannel::handle_cursor_trail);
+    handler->set_handler(SPICE_MSG_CURSOR_INVAL_ONE, &CursorChannel::handle_inval_one);
+    handler->set_handler(SPICE_MSG_CURSOR_INVAL_ALL, &CursorChannel::handle_inval_all);
 }
 
 CursorChannel::~CursorChannel()
diff --git a/client/demarshallers.h b/client/demarshallers.h
new file mode 100644
index 0000000..8118973
--- /dev/null
+++ b/client/demarshallers.h
@@ -0,0 +1,25 @@
+/*
+   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 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);
+
+spice_parse_channel_func_t spice_get_server_channel_parser(uint32_t channel, unsigned int *max_message_type);
+
+#endif
+
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 5d18517..9cc5550 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -578,10 +578,10 @@ Canvas* DisplaySurfacesManger::get_canvas(int surface_id)
     return canvases.get(surface_id);
 }
 
-class DisplayHandler: public MessageHandlerImp<DisplayChannel, SPICE_MSG_END_DISPLAY> {
+class DisplayHandler: public MessageHandlerImp<DisplayChannel, SPICE_CHANNEL_DISPLAY> {
 public:
     DisplayHandler(DisplayChannel& channel)
-        : MessageHandlerImp<DisplayChannel, SPICE_MSG_END_DISPLAY>(channel) {}
+        : MessageHandlerImp<DisplayChannel, SPICE_CHANNEL_DISPLAY>(channel) {}
 };
 
 DisplayChannel::DisplayChannel(RedClient& client, uint32_t id,
@@ -608,42 +608,33 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id,
 {
     DisplayHandler* handler = static_cast<DisplayHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_MIGRATE, &DisplayChannel::handle_migrate, 0);
-    handler->set_handler(SPICE_MSG_SET_ACK, &DisplayChannel::handle_set_ack, sizeof(SpiceMsgSetAck));
-    handler->set_handler(SPICE_MSG_PING, &DisplayChannel::handle_ping, sizeof(SpiceMsgPing));
-    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &DisplayChannel::handle_wait_for_channels,
-                         sizeof(SpiceMsgWaitForChannels));
-    handler->set_handler(SPICE_MSG_DISCONNECTING, &DisplayChannel::handle_disconnect,
-                         sizeof(SpiceMsgDisconnect));
-    handler->set_handler(SPICE_MSG_NOTIFY, &DisplayChannel::handle_notify, sizeof(SpiceMsgNotify));
+    handler->set_handler(SPICE_MSG_MIGRATE, &DisplayChannel::handle_migrate);
+    handler->set_handler(SPICE_MSG_SET_ACK, &DisplayChannel::handle_set_ack);
+    handler->set_handler(SPICE_MSG_PING, &DisplayChannel::handle_ping);
+    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &DisplayChannel::handle_wait_for_channels);
+    handler->set_handler(SPICE_MSG_DISCONNECTING, &DisplayChannel::handle_disconnect);
+    handler->set_handler(SPICE_MSG_NOTIFY, &DisplayChannel::handle_notify);
 
-    handler->set_handler(SPICE_MSG_DISPLAY_MARK, &DisplayChannel::handle_mark, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_RESET, &DisplayChannel::handle_reset, 0);
+    handler->set_handler(SPICE_MSG_DISPLAY_MARK, &DisplayChannel::handle_mark);
+    handler->set_handler(SPICE_MSG_DISPLAY_RESET, &DisplayChannel::handle_reset);
 
     handler->set_handler(SPICE_MSG_DISPLAY_INVAL_LIST,
-                         &DisplayChannel::handle_inval_list,
-                         sizeof(SpiceResourceList));
+                         &DisplayChannel::handle_inval_list);
     handler->set_handler(SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS,
-                         &DisplayChannel::handle_inval_all_pixmaps,
-                         sizeof(SpiceMsgWaitForChannels));
+                         &DisplayChannel::handle_inval_all_pixmaps);
     handler->set_handler(SPICE_MSG_DISPLAY_INVAL_PALETTE,
-                         &DisplayChannel::handle_inval_palette, sizeof(SpiceMsgDisplayInvalOne));
+                         &DisplayChannel::handle_inval_palette);
     handler->set_handler(SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES,
-                         &DisplayChannel::handle_inval_all_palettes, 0);
-
-    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_CREATE, &DisplayChannel::handle_stream_create,
-                         sizeof(SpiceMsgDisplayStreamCreate));
-    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_CLIP, &DisplayChannel::handle_stream_clip,
-                         sizeof(SpiceMsgDisplayStreamClip));
-    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_DESTROY, &DisplayChannel::handle_stream_destroy,
-                         sizeof(SpiceMsgDisplayStreamDestroy));
+                         &DisplayChannel::handle_inval_all_palettes);
+
+    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_CREATE, &DisplayChannel::handle_stream_create);
+    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_CLIP, &DisplayChannel::handle_stream_clip);
+    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_DESTROY, &DisplayChannel::handle_stream_destroy);
     handler->set_handler(SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL,
-                         &DisplayChannel::handle_stream_destroy_all, 0);
+                         &DisplayChannel::handle_stream_destroy_all);
 
-    handler->set_handler(SPICE_MSG_DISPLAY_SURFACE_CREATE, &DisplayChannel::handle_surface_create,
-                         sizeof(SpiceMsgSurfaceCreate));
-    handler->set_handler(SPICE_MSG_DISPLAY_SURFACE_DESTROY, &DisplayChannel::handle_surface_destroy,
-                         sizeof(SpiceMsgSurfaceDestroy));
+    handler->set_handler(SPICE_MSG_DISPLAY_SURFACE_CREATE, &DisplayChannel::handle_surface_create);
+    handler->set_handler(SPICE_MSG_DISPLAY_SURFACE_DESTROY, &DisplayChannel::handle_surface_destroy);
 
     get_process_loop().add_trigger(_streams_trigger);
 #ifdef USE_OGL
@@ -678,55 +669,43 @@ void DisplayChannel::set_draw_handlers()
 {
     DisplayHandler* handler = static_cast<DisplayHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_DISPLAY_COPY_BITS, &DisplayChannel::handle_copy_bits,
-                         sizeof(SpiceMsgDisplayCopyBits));
-
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_FILL, &DisplayChannel::handle_draw_fill,
-                         sizeof(SpiceMsgDisplayDrawFill));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_OPAQUE, &DisplayChannel::handle_draw_opaque,
-                         sizeof(SpiceMsgDisplayDrawOpaque));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_COPY, &DisplayChannel::handle_draw_copy,
-                         sizeof(SpiceMsgDisplayDrawCopy));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_BLEND, &DisplayChannel::handle_draw_blend,
-                         sizeof(SpiceMsgDisplayDrawBlend));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &DisplayChannel::handle_draw_blackness,
-                         sizeof(SpiceMsgDisplayDrawBlackness));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_WHITENESS, &DisplayChannel::handle_draw_whiteness,
-                         sizeof(SpiceMsgDisplayDrawWhiteness));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_INVERS, &DisplayChannel::handle_draw_invers,
-                         sizeof(SpiceMsgDisplayDrawInvers));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_ROP3, &DisplayChannel::handle_draw_rop3,
-                         sizeof(SpiceMsgDisplayDrawRop3));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_STROKE, &DisplayChannel::handle_draw_stroke,
-                         sizeof(SpiceMsgDisplayDrawStroke));
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_TEXT, &DisplayChannel::handle_draw_text,
-                         sizeof(SpiceMsgDisplayDrawText));
+    handler->set_handler(SPICE_MSG_DISPLAY_COPY_BITS, &DisplayChannel::handle_copy_bits);
+
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_FILL, &DisplayChannel::handle_draw_fill);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_OPAQUE, &DisplayChannel::handle_draw_opaque);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_COPY, &DisplayChannel::handle_draw_copy);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_BLEND, &DisplayChannel::handle_draw_blend);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &DisplayChannel::handle_draw_blackness);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_WHITENESS, &DisplayChannel::handle_draw_whiteness);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_INVERS, &DisplayChannel::handle_draw_invers);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_ROP3, &DisplayChannel::handle_draw_rop3);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_STROKE, &DisplayChannel::handle_draw_stroke);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_TEXT, &DisplayChannel::handle_draw_text);
     handler->set_handler(SPICE_MSG_DISPLAY_DRAW_TRANSPARENT,
-                         &DisplayChannel::handle_draw_transparent, sizeof(SpiceMsgDisplayDrawTransparent));
+                         &DisplayChannel::handle_draw_transparent);
     handler->set_handler(SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND,
-                         &DisplayChannel::handle_draw_alpha_blend, sizeof(SpiceMsgDisplayDrawAlphaBlend));
-    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_DATA, &DisplayChannel::handle_stream_data,
-                         sizeof(SpiceMsgDisplayStreamData));
+                         &DisplayChannel::handle_draw_alpha_blend);
+    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_DATA, &DisplayChannel::handle_stream_data);
 }
 
 void DisplayChannel::clear_draw_handlers()
 {
     DisplayHandler* handler = static_cast<DisplayHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_DISPLAY_COPY_BITS, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_FILL, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_OPAQUE, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_COPY, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_BLEND, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_BLACKNESS, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_WHITENESS, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_INVERS, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_ROP3, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_STROKE, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_TEXT, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, NULL, 0);
-    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_DATA, NULL, 0);
+    handler->set_handler(SPICE_MSG_DISPLAY_COPY_BITS, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_FILL, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_OPAQUE, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_COPY, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_BLEND, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_BLACKNESS, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_WHITENESS, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_INVERS, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_ROP3, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_STROKE, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_TEXT, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, NULL);
+    handler->set_handler(SPICE_MSG_DISPLAY_STREAM_DATA, NULL);
 }
 
 void DisplayChannel::copy_pixels(const QRegion& dest_region,
@@ -1289,20 +1268,13 @@ void DisplayChannel::handle_inval_all_palettes(RedPeer::InMessage* message)
 }
 
 void DisplayChannel::set_clip_rects(const SpiceClip& clip, uint32_t& num_clip_rects,
-                                    SpiceRect*& clip_rects, unsigned long addr_offset,
-                                    uint8_t *min, uint8_t *max)
+                                    SpiceRect*& clip_rects)
 {
     switch (clip.type) {
     case SPICE_CLIP_TYPE_RECTS: {
-        uint32_t* n = (uint32_t*)SPICE_GET_ADDRESS(clip.data + addr_offset);
-        if (n < (uint32_t*)min || n + 1 > (uint32_t*)max) {
-            THROW("access violation");
-        }
+        uint32_t* n = (uint32_t*)SPICE_GET_ADDRESS(clip.data);
         num_clip_rects = *n;
         clip_rects = (SpiceRect *)(n + 1);
-        if (clip_rects + num_clip_rects > (SpiceRect*)max) {
-            THROW("access violation");
-        }
         break;
     }
     case SPICE_CLIP_TYPE_NONE:
@@ -1330,9 +1302,7 @@ void DisplayChannel::handle_stream_create(RedPeer::InMessage* message)
 
     uint32_t num_clip_rects;
     SpiceRect* clip_rects;
-    set_clip_rects(stream_create->clip, num_clip_rects, clip_rects,
-                   (unsigned long)message->data(), (uint8_t*)(stream_create + 1),
-                   message->data() + message->size());
+    set_clip_rects(stream_create->clip, num_clip_rects, clip_rects);
     _streams[stream_create->id] = new VideoStream(get_client(), *surfaces_mngr.get_canvas(surface_id),
                                                   *this, stream_create->codec_type,
                                                   !!(stream_create->flags & SPICE_STREAM_FLAGS_TOP_DOWN),
@@ -1379,9 +1349,7 @@ void DisplayChannel::handle_stream_clip(RedPeer::InMessage* message)
     if (message->size() < sizeof(SpiceMsgDisplayStreamClip)) {
         THROW("access violation");
     }
-    set_clip_rects(clip_data->clip, num_clip_rects, clip_rects,
-                   (unsigned long)message->data(), (uint8_t*)(clip_data + 1),
-                   message->data() + message->size());
+    set_clip_rects(clip_data->clip, num_clip_rects, clip_rects);
     Lock lock(_streams_lock);
     stream->set_clip(clip_data->clip.type, num_clip_rects, clip_rects);
 }
diff --git a/client/display_channel.h b/client/display_channel.h
index 52b0cef..c56adf6 100644
--- a/client/display_channel.h
+++ b/client/display_channel.h
@@ -189,8 +189,7 @@ private:
     void activate_streams_timer();
     void stream_update_request(uint32_t update_time);
 
-    static void set_clip_rects(const SpiceClip& clip, uint32_t& num_clip_rects, SpiceRect*& clip_rects,
-                               unsigned long addr_offset, uint8_t *min, uint8_t *max);
+    static void set_clip_rects(const SpiceClip& clip, uint32_t& num_clip_rects, SpiceRect*& clip_rects);
 private:
     DisplaySurfacesManger surfaces_mngr;
     PixmapCache& _pixmap_cache;
diff --git a/client/inputs_channel.cpp b/client/inputs_channel.cpp
index 46fc015..4e99563 100644
--- a/client/inputs_channel.cpp
+++ b/client/inputs_channel.cpp
@@ -158,10 +158,10 @@ RedPeer::OutMessage& PositionMessage::peer_message()
     return *this;
 }
 
-class InputsMessHandler: public MessageHandlerImp<InputsChannel, SPICE_MSG_END_INPUTS> {
+class InputsMessHandler: public MessageHandlerImp<InputsChannel, SPICE_CHANNEL_INPUTS> {
 public:
     InputsMessHandler(InputsChannel& channel)
-        : MessageHandlerImp<InputsChannel, SPICE_MSG_END_INPUTS>(channel) {}
+        : MessageHandlerImp<InputsChannel, SPICE_CHANNEL_INPUTS>(channel) {}
 };
 
 InputsChannel::InputsChannel(RedClient& client, uint32_t id)
@@ -177,19 +177,16 @@ InputsChannel::InputsChannel(RedClient& client, uint32_t id)
     , _active_modifiers_event (false)
 {
     InputsMessHandler* handler = static_cast<InputsMessHandler*>(get_message_handler());
-    handler->set_handler(SPICE_MSG_MIGRATE, &InputsChannel::handle_migrate, 0);
-    handler->set_handler(SPICE_MSG_SET_ACK, &InputsChannel::handle_set_ack, sizeof(SpiceMsgSetAck));
-    handler->set_handler(SPICE_MSG_PING, &InputsChannel::handle_ping, sizeof(SpiceMsgPing));
-    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &InputsChannel::handle_wait_for_channels,
-                         sizeof(SpiceMsgWaitForChannels));
-    handler->set_handler(SPICE_MSG_DISCONNECTING, &InputsChannel::handle_disconnect,
-                         sizeof(SpiceMsgDisconnect));
-    handler->set_handler(SPICE_MSG_NOTIFY, &InputsChannel::handle_notify, sizeof(SpiceMsgNotify));
-
-    handler->set_handler(SPICE_MSG_INPUTS_INIT, &InputsChannel::handle_init, sizeof(SpiceMsgInputsInit));
-    handler->set_handler(SPICE_MSG_INPUTS_KEY_MODIFIERS, &InputsChannel::handle_modifaiers,
-                         sizeof(SpiceMsgInputsKeyModifiers));
-    handler->set_handler(SPICE_MSG_INPUTS_MOUSE_MOTION_ACK, &InputsChannel::handle_motion_ack, 0);
+    handler->set_handler(SPICE_MSG_MIGRATE, &InputsChannel::handle_migrate);
+    handler->set_handler(SPICE_MSG_SET_ACK, &InputsChannel::handle_set_ack);
+    handler->set_handler(SPICE_MSG_PING, &InputsChannel::handle_ping);
+    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &InputsChannel::handle_wait_for_channels);
+    handler->set_handler(SPICE_MSG_DISCONNECTING, &InputsChannel::handle_disconnect);
+    handler->set_handler(SPICE_MSG_NOTIFY, &InputsChannel::handle_notify);
+
+    handler->set_handler(SPICE_MSG_INPUTS_INIT, &InputsChannel::handle_init);
+    handler->set_handler(SPICE_MSG_INPUTS_KEY_MODIFIERS, &InputsChannel::handle_modifaiers);
+    handler->set_handler(SPICE_MSG_INPUTS_MOUSE_MOTION_ACK, &InputsChannel::handle_motion_ack);
 }
 
 InputsChannel::~InputsChannel()
diff --git a/client/playback_channel.cpp b/client/playback_channel.cpp
index 3e8bb46..9ac6ed6 100644
--- a/client/playback_channel.cpp
+++ b/client/playback_channel.cpp
@@ -137,10 +137,10 @@ static void end_wave()
 
 #endif
 
-class PlaybackHandler: public MessageHandlerImp<PlaybackChannel, SPICE_MSG_END_PLAYBACK> {
+class PlaybackHandler: public MessageHandlerImp<PlaybackChannel, SPICE_CHANNEL_PLAYBACK> {
 public:
     PlaybackHandler(PlaybackChannel& channel)
-        : MessageHandlerImp<PlaybackChannel, SPICE_MSG_END_PLAYBACK>(channel) {}
+        : MessageHandlerImp<PlaybackChannel, SPICE_CHANNEL_PLAYBACK>(channel) {}
 };
 
 PlaybackChannel::PlaybackChannel(RedClient& client, uint32_t id)
@@ -157,17 +157,14 @@ PlaybackChannel::PlaybackChannel(RedClient& client, uint32_t id)
 #endif
     PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_MIGRATE, &PlaybackChannel::handle_migrate, 0);
-    handler->set_handler(SPICE_MSG_SET_ACK, &PlaybackChannel::handle_set_ack, sizeof(SpiceMsgSetAck));
-    handler->set_handler(SPICE_MSG_PING, &PlaybackChannel::handle_ping, sizeof(SpiceMsgPing));
-    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &PlaybackChannel::handle_wait_for_channels,
-                         sizeof(SpiceMsgWaitForChannels));
-    handler->set_handler(SPICE_MSG_DISCONNECTING, &PlaybackChannel::handle_disconnect,
-                         sizeof(SpiceMsgDisconnect));
-    handler->set_handler(SPICE_MSG_NOTIFY, &PlaybackChannel::handle_notify, sizeof(SpiceMsgNotify));
+    handler->set_handler(SPICE_MSG_MIGRATE, &PlaybackChannel::handle_migrate);
+    handler->set_handler(SPICE_MSG_SET_ACK, &PlaybackChannel::handle_set_ack);
+    handler->set_handler(SPICE_MSG_PING, &PlaybackChannel::handle_ping);
+    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &PlaybackChannel::handle_wait_for_channels);
+    handler->set_handler(SPICE_MSG_DISCONNECTING, &PlaybackChannel::handle_disconnect);
+    handler->set_handler(SPICE_MSG_NOTIFY, &PlaybackChannel::handle_notify);
 
-    handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::handle_mode,
-                         sizeof(SpiceMsgPlaybackMode));
+    handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::handle_mode);
 
     set_capability(SPICE_PLAYBACK_CAP_CELT_0_5_1);
 }
@@ -195,9 +192,9 @@ void PlaybackChannel::set_data_handler()
     PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
 
     if (_mode == SPICE_AUDIO_DATA_MODE_RAW) {
-        handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_raw_data, 0);
+        handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_raw_data);
     } else if (_mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) {
-        handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_celt_data, 0);
+        handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_celt_data);
     } else {
         THROW("invalid mode");
     }
@@ -218,8 +215,7 @@ void PlaybackChannel::handle_mode(RedPeer::InMessage* message)
     }
 
     PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
-    handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::handle_start,
-                         sizeof(SpiceMsgPlaybackStart));
+    handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::handle_start);
 }
 
 void PlaybackChannel::null_handler(RedPeer::InMessage* message)
@@ -230,10 +226,10 @@ void PlaybackChannel::disable()
 {
     PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::null_handler, 0);
-    handler->set_handler(SPICE_MSG_PLAYBACK_STOP, &PlaybackChannel::null_handler, 0);
-    handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::null_handler, 0);
-    handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::null_handler, 0);
+    handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::null_handler);
+    handler->set_handler(SPICE_MSG_PLAYBACK_STOP, &PlaybackChannel::null_handler);
+    handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::null_handler);
+    handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::null_handler);
 }
 
 void PlaybackChannel::handle_start(RedPeer::InMessage* message)
@@ -241,8 +237,8 @@ void PlaybackChannel::handle_start(RedPeer::InMessage* message)
     PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
     SpiceMsgPlaybackStart* start = (SpiceMsgPlaybackStart*)message->data();
 
-    handler->set_handler(SPICE_MSG_PLAYBACK_START, NULL, 0);
-    handler->set_handler(SPICE_MSG_PLAYBACK_STOP, &PlaybackChannel::handle_stop, 0);
+    handler->set_handler(SPICE_MSG_PLAYBACK_START, NULL);
+    handler->set_handler(SPICE_MSG_PLAYBACK_STOP, &PlaybackChannel::handle_stop);
 
 #ifdef WAVE_CAPTURE
     start_wave();
@@ -285,10 +281,9 @@ void PlaybackChannel::handle_stop(RedPeer::InMessage* message)
 {
     PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_PLAYBACK_STOP, NULL, 0);
-    handler->set_handler(SPICE_MSG_PLAYBACK_DATA, NULL, 0);
-    handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::handle_start,
-                         sizeof(SpiceMsgPlaybackStart));
+    handler->set_handler(SPICE_MSG_PLAYBACK_STOP, NULL);
+    handler->set_handler(SPICE_MSG_PLAYBACK_DATA, NULL);
+    handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::handle_start);
 
 #ifdef WAVE_CAPTURE
     end_wave();
diff --git a/client/record_channel.cpp b/client/record_channel.cpp
index 893cc63..a48df60 100644
--- a/client/record_channel.cpp
+++ b/client/record_channel.cpp
@@ -59,10 +59,10 @@ void RecordSamplesMessage::release()
 
 int RecordChannel::data_mode = SPICE_AUDIO_DATA_MODE_CELT_0_5_1;
 
-class RecordHandler: public MessageHandlerImp<RecordChannel, SPICE_MSGC_END_RECORD> {
+class RecordHandler: public MessageHandlerImp<RecordChannel, SPICE_CHANNEL_RECORD> {
 public:
     RecordHandler(RecordChannel& channel)
-        : MessageHandlerImp<RecordChannel, SPICE_MSGC_END_RECORD>(channel) {}
+        : MessageHandlerImp<RecordChannel, SPICE_CHANNEL_RECORD>(channel) {}
 };
 
 RecordChannel::RecordChannel(RedClient& client, uint32_t id)
@@ -78,16 +78,14 @@ RecordChannel::RecordChannel(RedClient& client, uint32_t id)
 
     RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_MIGRATE, &RecordChannel::handle_migrate, 0);
-    handler->set_handler(SPICE_MSG_SET_ACK, &RecordChannel::handle_set_ack, sizeof(SpiceMsgSetAck));
-    handler->set_handler(SPICE_MSG_PING, &RecordChannel::handle_ping, sizeof(SpiceMsgPing));
-    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &RecordChannel::handle_wait_for_channels,
-                         sizeof(SpiceMsgWaitForChannels));
-    handler->set_handler(SPICE_MSG_DISCONNECTING, &RecordChannel::handle_disconnect,
-                         sizeof(SpiceMsgDisconnect));
-    handler->set_handler(SPICE_MSG_NOTIFY, &RecordChannel::handle_notify, sizeof(SpiceMsgNotify));
+    handler->set_handler(SPICE_MSG_MIGRATE, &RecordChannel::handle_migrate);
+    handler->set_handler(SPICE_MSG_SET_ACK, &RecordChannel::handle_set_ack);
+    handler->set_handler(SPICE_MSG_PING, &RecordChannel::handle_ping);
+    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &RecordChannel::handle_wait_for_channels);
+    handler->set_handler(SPICE_MSG_DISCONNECTING, &RecordChannel::handle_disconnect);
+    handler->set_handler(SPICE_MSG_NOTIFY, &RecordChannel::handle_notify);
 
-    handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start, sizeof(SpiceMsgRecordStart));
+    handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start);
 
     set_capability(SPICE_RECORD_CAP_CELT_0_5_1);
 }
@@ -138,8 +136,8 @@ void RecordChannel::handle_start(RedPeer::InMessage* message)
     RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
     SpiceMsgRecordStart* start = (SpiceMsgRecordStart*)message->data();
 
-    handler->set_handler(SPICE_MSG_RECORD_START, NULL, 0);
-    handler->set_handler(SPICE_MSG_RECORD_STOP, &RecordChannel::handle_stop, 0);
+    handler->set_handler(SPICE_MSG_RECORD_START, NULL);
+    handler->set_handler(SPICE_MSG_RECORD_STOP, &RecordChannel::handle_stop);
     ASSERT(!_wave_recorder && !_celt_mode && !_celt_encoder);
 
     // for now support only one setting
@@ -176,8 +174,8 @@ void RecordChannel::handle_start(RedPeer::InMessage* message)
 void RecordChannel::handle_stop(RedPeer::InMessage* message)
 {
     RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
-    handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start, sizeof(SpiceMsgRecordStart));
-    handler->set_handler(SPICE_MSG_RECORD_STOP, NULL, 0);
+    handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start);
+    handler->set_handler(SPICE_MSG_RECORD_STOP, NULL);
     if (!_wave_recorder) {
         return;
     }
diff --git a/client/red_channel.h b/client/red_channel.h
index d80a331..8d6b62f 100644
--- a/client/red_channel.h
+++ b/client/red_channel.h
@@ -24,6 +24,7 @@
 #include "red_peer.h"
 #include "platform.h"
 #include "process_loop.h"
+#include "demarshallers.h"
 
 enum {
     PASSIVE_STATE,
@@ -230,67 +231,83 @@ public:
 };
 
 
-template <class HandlerClass, unsigned int end_message>
+template <class HandlerClass, unsigned int channel_id>
 class MessageHandlerImp: public RedChannel::MessageHandler {
 public:
     MessageHandlerImp(HandlerClass& obj);
-    virtual ~MessageHandlerImp() {}
+    ~MessageHandlerImp() { delete [] _handlers; };
     virtual void handle_message(RedPeer::CompundInMessage& message);
     typedef void (HandlerClass::*Handler)(RedPeer::InMessage* message);
-    void set_handler(unsigned int id, Handler handler, size_t mess_size);
+    void set_handler(unsigned int id, Handler handler);
 
 private:
     HandlerClass& _obj;
-    struct HandlerInfo {
-        Handler handler;
-        size_t mess_size;
-    };
-
-    HandlerInfo _handlers[end_message];
+    unsigned int _max_messages;
+    spice_parse_channel_func_t _parser;
+    Handler *_handlers;
 };
 
-template <class HandlerClass, unsigned int end_message>
-MessageHandlerImp<HandlerClass, end_message>::MessageHandlerImp(HandlerClass& obj)
+template <class HandlerClass, unsigned int channel_id>
+MessageHandlerImp<HandlerClass, channel_id>::MessageHandlerImp(HandlerClass& obj)
     : _obj (obj)
 {
-    memset(_handlers, 0, sizeof(_handlers));
+    _parser = spice_get_server_channel_parser(channel_id, &_max_messages);
+    _handlers = new Handler[_max_messages + 1];
+    memset(_handlers, 0, sizeof(Handler) * (_max_messages + 1));
 }
 
-template <class HandlerClass, unsigned int end_message>
-void MessageHandlerImp<HandlerClass, end_message>::handle_message(RedPeer::CompundInMessage&
-                                                                                            message)
+template <class HandlerClass, unsigned int channel_id>
+void MessageHandlerImp<HandlerClass, channel_id>::handle_message(RedPeer::CompundInMessage&
+                                                                 message)
 {
-    if (message.type() >= end_message || !_handlers[message.type()].handler) {
-        THROW("bad message type %d", message.type());
-    }
-    if (message.size() < _handlers[message.type()].mess_size) {
-        THROW("bad message size, type %d size %d expected %d",
-              message.type(),
-              message.size(),
-              _handlers[message.type()].mess_size);
-    }
+    uint8_t *msg;
+    uint8_t *parsed;
+    uint16_t type;
+    uint32_t size;
+    size_t parsed_size;
+
     if (message.sub_list()) {
         SpiceSubMessageList *sub_list;
         sub_list = (SpiceSubMessageList *)(message.data() + message.sub_list());
         for (int i = 0; i < sub_list->size; i++) {
             SpicedSubMessage *sub = (SpicedSubMessage *)(message.data() + sub_list->sub_messages[i]);
-            //todo: test size
-            RedPeer::InMessage sub_message(sub->type, sub->size, (uint8_t *)(sub + 1));
-            (_obj.*_handlers[sub_message.type()].handler)(&sub_message);
+            msg = (uint8_t *)(sub + 1);
+            type = sub->type;
+            size = sub->size;
+            parsed = _parser(msg, msg + size, type, _obj.get_peer_minor(), &parsed_size);
+
+            if (parsed == NULL) {
+                THROW("failed to parse message type %d", type);
+            }
+
+            RedPeer::InMessage sub_message(type, parsed_size, parsed);
+            (_obj.*_handlers[type])(&sub_message);
+
+            free(parsed);
         }
     }
-    (_obj.*_handlers[message.type()].handler)(&message);
+
+    msg = message.data();
+    type = message.type();
+    size = message.size();
+    parsed = _parser(msg, msg + size, type, _obj.get_peer_minor(), &parsed_size);
+    RedPeer::InMessage main_message(type, parsed_size, parsed);
+
+    if (parsed == NULL) {
+        THROW("failed to parse message channel %d type %d", channel_id, type);
+    }
+
+    (_obj.*_handlers[type])(&main_message);
+    free(parsed);
 }
 
-template <class HandlerClass, unsigned int end_message>
-void MessageHandlerImp<HandlerClass, end_message>::set_handler(unsigned int id, Handler handler,
-                                                               size_t mess_size)
+template <class HandlerClass, unsigned int channel_id>
+void MessageHandlerImp<HandlerClass, channel_id>::set_handler(unsigned int id, Handler handler)
 {
-    if (id >= end_message) {
+    if (id > _max_messages) {
         THROW("bad handler id");
     }
-    _handlers[id].handler = handler;
-    _handlers[id].mess_size = mess_size;
+    _handlers[id] = handler;
 }
 
 #endif
diff --git a/client/red_client.cpp b/client/red_client.cpp
index 8424a94..8778eeb 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -293,9 +293,9 @@ void AgentTimer::response(AbstractProcessLoop& events_loop)
     THROW_ERR(SPICEC_ERROR_CODE_AGENT_TIMEOUT, "vdagent timeout");
 }
 
-class MainChannelLoop: public MessageHandlerImp<RedClient, SPICE_MSG_END_MAIN> {
+class MainChannelLoop: public MessageHandlerImp<RedClient, SPICE_CHANNEL_MAIN> {
 public:
-    MainChannelLoop(RedClient& client): MessageHandlerImp<RedClient, SPICE_MSG_END_MAIN>(client) {}
+    MainChannelLoop(RedClient& client): MessageHandlerImp<RedClient, SPICE_CHANNEL_MAIN>(client) {}
 };
 
 RedClient::RedClient(Application& application)
@@ -320,35 +320,26 @@ RedClient::RedClient(Application& application)
 {
     MainChannelLoop* message_loop = static_cast<MainChannelLoop*>(get_message_handler());
 
-    message_loop->set_handler(SPICE_MSG_MIGRATE, &RedClient::handle_migrate, 0);
-    message_loop->set_handler(SPICE_MSG_SET_ACK, &RedClient::handle_set_ack, sizeof(SpiceMsgSetAck));
-    message_loop->set_handler(SPICE_MSG_PING, &RedClient::handle_ping, sizeof(SpiceMsgPing));
-    message_loop->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &RedClient::handle_wait_for_channels,
-                              sizeof(SpiceMsgWaitForChannels));
-    message_loop->set_handler(SPICE_MSG_DISCONNECTING, &RedClient::handle_disconnect,
-                              sizeof(SpiceMsgDisconnect));
-    message_loop->set_handler(SPICE_MSG_NOTIFY, &RedClient::handle_notify, sizeof(SpiceMsgNotify));
-
-    message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_BEGIN, &RedClient::handle_migrate_begin,
-                              sizeof(SpiceMsgMainMigrationBegin));
-    message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_CANCEL, &RedClient::handle_migrate_cancel, 0);
+    message_loop->set_handler(SPICE_MSG_MIGRATE, &RedClient::handle_migrate);
+    message_loop->set_handler(SPICE_MSG_SET_ACK, &RedClient::handle_set_ack);
+    message_loop->set_handler(SPICE_MSG_PING, &RedClient::handle_ping);
+    message_loop->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &RedClient::handle_wait_for_channels);
+    message_loop->set_handler(SPICE_MSG_DISCONNECTING, &RedClient::handle_disconnect);
+    message_loop->set_handler(SPICE_MSG_NOTIFY, &RedClient::handle_notify);
+
+    message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_BEGIN, &RedClient::handle_migrate_begin);
+    message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_CANCEL, &RedClient::handle_migrate_cancel);
     message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST,
-                              &RedClient::handle_migrate_switch_host,
-                              sizeof(SpiceMsgMainMigrationSwitchHost));
-    message_loop->set_handler(SPICE_MSG_MAIN_INIT, &RedClient::handle_init, sizeof(SpiceMsgMainInit));
-    message_loop->set_handler(SPICE_MSG_MAIN_CHANNELS_LIST, &RedClient::handle_channels,
-                              sizeof(SpiceMsgChannels));
-    message_loop->set_handler(SPICE_MSG_MAIN_MOUSE_MODE, &RedClient::handle_mouse_mode,
-                              sizeof(SpiceMsgMainMouseMode));
-    message_loop->set_handler(SPICE_MSG_MAIN_MULTI_MEDIA_TIME, &RedClient::handle_mm_time,
-                              sizeof(SpiceMsgMainMultiMediaTime));
-
-    message_loop->set_handler(SPICE_MSG_MAIN_AGENT_CONNECTED, &RedClient::handle_agent_connected, 0);
-    message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DISCONNECTED, &RedClient::handle_agent_disconnected,
-                              sizeof(SpiceMsgMainAgentDisconnect));
-    message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DATA, &RedClient::handle_agent_data, 0);
-    message_loop->set_handler(SPICE_MSG_MAIN_AGENT_TOKEN, &RedClient::handle_agent_tokens,
-                              sizeof(SpiceMsgMainAgentTokens));
+                              &RedClient::handle_migrate_switch_host);
+    message_loop->set_handler(SPICE_MSG_MAIN_INIT, &RedClient::handle_init);
+    message_loop->set_handler(SPICE_MSG_MAIN_CHANNELS_LIST, &RedClient::handle_channels);
+    message_loop->set_handler(SPICE_MSG_MAIN_MOUSE_MODE, &RedClient::handle_mouse_mode);
+    message_loop->set_handler(SPICE_MSG_MAIN_MULTI_MEDIA_TIME, &RedClient::handle_mm_time);
+
+    message_loop->set_handler(SPICE_MSG_MAIN_AGENT_CONNECTED, &RedClient::handle_agent_connected);
+    message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DISCONNECTED, &RedClient::handle_agent_disconnected);
+    message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DATA, &RedClient::handle_agent_data);
+    message_loop->set_handler(SPICE_MSG_MAIN_AGENT_TOKEN, &RedClient::handle_agent_tokens);
     start();
 }
 
diff --git a/client/tunnel_channel.cpp b/client/tunnel_channel.cpp
index 1b7d7cb..cecd9ba 100644
--- a/client/tunnel_channel.cpp
+++ b/client/tunnel_channel.cpp
@@ -219,10 +219,10 @@ TunnelChannel::TunnelSocket::TunnelSocket(uint16_t id, TunnelService& dst_servic
 {
 }
 
-class TunnelHandler: public MessageHandlerImp<TunnelChannel, SPICE_MSG_END_TUNNEL> {
+class TunnelHandler: public MessageHandlerImp<TunnelChannel, SPICE_CHANNEL_TUNNEL> {
 public:
     TunnelHandler(TunnelChannel& channel)
-        : MessageHandlerImp<TunnelChannel, SPICE_MSG_END_TUNNEL>(channel) {}
+        : MessageHandlerImp<TunnelChannel, SPICE_CHANNEL_TUNNEL>(channel) {}
 };
 
 TunnelChannel::TunnelChannel(RedClient& client, uint32_t id)
@@ -236,29 +236,27 @@ TunnelChannel::TunnelChannel(RedClient& client, uint32_t id)
 {
     TunnelHandler* handler = static_cast<TunnelHandler*>(get_message_handler());
 
-    handler->set_handler(SPICE_MSG_MIGRATE, &TunnelChannel::handle_migrate, 0);
-    handler->set_handler(SPICE_MSG_SET_ACK, &TunnelChannel::handle_set_ack, sizeof(SpiceMsgSetAck));
-    handler->set_handler(SPICE_MSG_PING, &TunnelChannel::handle_ping, sizeof(SpiceMsgPing));
-    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &TunnelChannel::handle_wait_for_channels,
-                         sizeof(SpiceMsgWaitForChannels));
+    handler->set_handler(SPICE_MSG_MIGRATE, &TunnelChannel::handle_migrate);
+    handler->set_handler(SPICE_MSG_SET_ACK, &TunnelChannel::handle_set_ack);
+    handler->set_handler(SPICE_MSG_PING, &TunnelChannel::handle_ping);
+    handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &TunnelChannel::handle_wait_for_channels);
 
     handler->set_handler(SPICE_MSG_TUNNEL_INIT,
-                         &TunnelChannel::handle_init, sizeof(SpiceMsgTunnelInit));
+                         &TunnelChannel::handle_init);
     handler->set_handler(SPICE_MSG_TUNNEL_SERVICE_IP_MAP,
-                         &TunnelChannel::handle_service_ip_map, sizeof(SpiceMsgTunnelServiceIpMap));
+                         &TunnelChannel::handle_service_ip_map);
     handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_OPEN,
-                         &TunnelChannel::handle_socket_open, sizeof(SpiceMsgTunnelSocketOpen));
+                         &TunnelChannel::handle_socket_open);
     handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_CLOSE,
-                         &TunnelChannel::handle_socket_close, sizeof(SpiceMsgTunnelSocketClose));
+                         &TunnelChannel::handle_socket_close);
     handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_FIN,
-                         &TunnelChannel::handle_socket_fin, sizeof(SpiceMsgTunnelSocketFin));
+                         &TunnelChannel::handle_socket_fin);
     handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_TOKEN,
-                         &TunnelChannel::handle_socket_token, sizeof(SpiceMsgTunnelSocketTokens));
+                         &TunnelChannel::handle_socket_token);
     handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK,
-                         &TunnelChannel::handle_socket_closed_ack,
-                         sizeof(SpiceMsgTunnelSocketClosedAck));
+                         &TunnelChannel::handle_socket_closed_ack);
     handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_DATA,
-                         &TunnelChannel::handle_socket_data, sizeof(SpiceMsgTunnelSocketData));
+                         &TunnelChannel::handle_socket_data);
 }
 
 TunnelChannel::~TunnelChannel()
diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
index c0ba905..f980c21 100644
--- a/client/windows/redc.vcproj
+++ b/client/windows/redc.vcproj
@@ -43,7 +43,7 @@
 				Name="VCCLCompilerTool"
 				Optimization="0"
 				AdditionalIncludeDirectories=".;..;..\..\common;..\..\..\spice-protocol;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;"
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;SW_CANVAS_ACCESS_TEST;SW_CANVAS_CACHE;RED_DEBUG;SW_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;SW_CANVAS_CACHE;RED_DEBUG;SW_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
 				MinimalRebuild="false"
 				BasicRuntimeChecks="3"
 				RuntimeLibrary="1"
@@ -125,7 +125,7 @@
 			<Tool
 				Name="VCCLCompilerTool"
 				AdditionalIncludeDirectories=".;..;..\..\..\spice-protocol;..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;"
-				PreprocessorDefinitions="WIN32;_WINDOWS;SW_CANVAS_ACCESS_TEST;SW_CANVAS_CACHE;SW_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
+				PreprocessorDefinitions="WIN32;_WINDOWS;SW_CANVAS_CACHE;SW_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
 				RuntimeLibrary="0"
 				UsePrecompiledHeader="0"
 				WarningLevel="3"
diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
index 26140f4..82a08dd 100644
--- a/client/x11/Makefile.am
+++ b/client/x11/Makefile.am
@@ -6,7 +6,6 @@ CLIENT_DIR=$(top_srcdir)/client
 SUBDIRS = images
 
 INCLUDES = \
-	-DSW_CANVAS_ACCESS_TEST				\
 	-DSW_CANVAS_CACHE				\
 	-DSW_CANVAS_NO_CHUNKS				\
 	-DUSE_GLZ					\
@@ -38,6 +37,8 @@ RED_COMMON_SRCS =					\
 	$(CLIENT_DIR)/audio_channels.h			\
 	$(CLIENT_DIR)/audio_devices.h			\
 	$(CLIENT_DIR)/cache.hpp				\
+	$(CLIENT_DIR)/demarshallers.h			\
+	$(CLIENT_DIR)/generated_demarshallers.cpp	\
 	$(CLIENT_DIR)/sw_canvas.cpp			\
 	$(CLIENT_DIR)/canvas.cpp			\
 	$(CLIENT_DIR)/canvas.h				\
diff --git a/common/canvas_base.c b/common/canvas_base.c
index aac472c..26bc52c 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -43,16 +43,6 @@
 }
 #endif
 
-#ifdef SW_CANVAS_ACCESS_TEST
-#define access_test(cancas, ptr, size)                                                         \
-    if ((unsigned long)(ptr) < (cancas)->base ||                                               \
-                                            (unsigned long)(ptr) + (size) > (cancas)->max) {   \
-        CANVAS_ERROR("access violation 0x%lx %lu", (unsigned long)ptr, (unsigned long)(size)); \
-    }
-#else
-#define access_test(cancas, base, size)
-#endif
-
 #ifndef ASSERT
 #define ASSERT(x) if (!(x)) {                               \
     printf("%s: ASSERT %s failed\n", __FUNCTION__, #x);     \
@@ -175,10 +165,6 @@ typedef struct CanvasBase {
     uint32_t color_shift;
     uint32_t color_mask;
     QuicData quic_data;
-#ifdef SW_CANVAS_ACCESS_TEST
-    unsigned long base;
-    unsigned long max;
-#endif
 
     uint32_t format;
     int width;
@@ -630,7 +616,6 @@ static pixman_image_t *canvas_bitmap_to_surface(CanvasBase *canvas, SpiceBitmap*
 
     src = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
     src_stride = bitmap->stride;
-    access_test(canvas, src, bitmap->y * src_stride);
 
     if (want_original) {
         format = spice_bitmap_format_to_pixman(bitmap->format, canvas->format);
@@ -672,8 +657,6 @@ static inline SpicePalette *canvas_get_palette(CanvasBase *canvas, SPICE_ADDRESS
         palette = canvas->palette_cache->ops->get(canvas->palette_cache, base_palette);
     } else if (flags & SPICE_BITMAP_FLAGS_PAL_CACHE_ME) {
         palette = (SpicePalette *)SPICE_GET_ADDRESS(base_palette);
-        access_test(canvas, palette, sizeof(SpicePalette));
-        access_test(canvas, palette, sizeof(SpicePalette) + palette->num_ents * sizeof(uint32_t));
         canvas->palette_cache->ops->put(canvas->palette_cache, palette);
     } else {
         palette = (SpicePalette *)SPICE_GET_ADDRESS(base_palette);
@@ -990,11 +973,9 @@ static void dump_surface(pixman_image_t *surface, int cache)
 static SpiceCanvas *canvas_get_surface_internal(CanvasBase *canvas, SPICE_ADDRESS addr)
 {
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
-    access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
 
     if (descriptor->type == SPICE_IMAGE_TYPE_SURFACE) {
         SpiceSurfaceImage *surface = (SpiceSurfaceImage *)descriptor;
-        access_test(canvas, descriptor, sizeof(SpiceSurfaceImage));
         return canvas->surfaces->ops->get(canvas->surfaces, surface->surface.surface_id);
     }
     return NULL;
@@ -1005,11 +986,9 @@ static SpiceCanvas *canvas_get_surface_mask_internal(CanvasBase *canvas, SPICE_A
     SpiceImageDescriptor *descriptor;
 
     descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
-    access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
 
     if (descriptor->type == SPICE_IMAGE_TYPE_SURFACE) {
         SpiceSurfaceImage *surface = (SpiceSurfaceImage *)descriptor;
-        access_test(canvas, descriptor, sizeof(SpiceSurfaceImage));
         return canvas->surfaces->ops->get(canvas->surfaces, surface->surface.surface_id);
     }
     return NULL;
@@ -1034,7 +1013,6 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
     pixman_image_t *surface, *converted;
     pixman_format_code_t wanted_format, surface_format;
     int saved_want_original;
-    access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
 #ifdef DEBUG_LZ
     LOG_DEBUG("canvas_get_image image type: " << (int)descriptor->type);
 #endif
@@ -1063,19 +1041,16 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
     switch (descriptor->type) {
     case SPICE_IMAGE_TYPE_QUIC: {
         SpiceQUICImage *image = (SpiceQUICImage *)descriptor;
-        access_test(canvas, descriptor, sizeof(SpiceQUICImage));
         surface = canvas_get_quic(canvas, image, 0, want_original);
         break;
     }
 #ifdef SW_CANVAS_NO_CHUNKS
     case SPICE_IMAGE_TYPE_LZ_PLT: {
-        access_test(canvas, descriptor, sizeof(SpiceLZPLTImage));
         LZImage *image = (LZImage *)descriptor;
         surface = canvas_get_lz(canvas, image, 0, want_original);
         break;
     }
     case SPICE_IMAGE_TYPE_LZ_RGB: {
-        access_test(canvas, descriptor, sizeof(SpiceLZRGBImage));
         LZImage *image = (LZImage *)descriptor;
         surface = canvas_get_lz(canvas, image, 0, want_original);
         break;
@@ -1083,13 +1058,11 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
 #endif
     case SPICE_IMAGE_TYPE_JPEG: {
         SpiceJPEGImage *image = (SpiceJPEGImage *)descriptor;
-        access_test(canvas, descriptor, sizeof(SpiceJPEGImage));
         surface = canvas_get_jpeg(canvas, image, 0);
         break;
     }
 #if defined(SW_CANVAS_CACHE)
     case SPICE_IMAGE_TYPE_GLZ_RGB: {
-        access_test(canvas, descriptor, sizeof(SpiceLZRGBImage));
         LZImage *image = (LZImage *)descriptor;
         surface = canvas_get_glz(canvas, image, want_original);
         break;
@@ -1106,7 +1079,6 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
 #endif
     case SPICE_IMAGE_TYPE_BITMAP: {
         SpiceBitmapImage *bitmap = (SpiceBitmapImage *)descriptor;
-        access_test(canvas, descriptor, sizeof(SpiceBitmapImage));
         surface = canvas_get_bits(canvas, &bitmap->bitmap, want_original);
         break;
     }
@@ -1213,8 +1185,6 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
     pixman_format_code_t format;
 
-    access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
-
     /* When touching, never load image. */
     if (!real_get) {
         return NULL;
@@ -1223,12 +1193,10 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
     switch (descriptor->type) {
     case SPICE_IMAGE_TYPE_QUIC: {
         SpiceQUICImage *image = (SpiceQUICImage *)descriptor;
-        access_test(canvas, descriptor, sizeof(SpiceQUICImage));
         return canvas_get_quic(canvas, image, 0);
     }
     case SPICE_IMAGE_TYPE_BITMAP: {
         SpiceBitmapImage *bitmap = (SpiceBitmapImage *)descriptor;
-        access_test(canvas, descriptor, sizeof(SpiceBitmapImage));
         return canvas_get_bits(canvas, &bitmap->bitmap, want_original, &format);
     }
     default:
@@ -1323,7 +1291,6 @@ static pixman_image_t *canvas_get_bitmap_mask(CanvasBase *canvas, SpiceBitmap* b
     src_line = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
     src_stride = bitmap->stride;
     end_line = src_line + (bitmap->y * src_stride);
-    access_test(canvas, src_line, end_line - src_line);
     line_size = SPICE_ALIGN(bitmap->x, 8) >> 3;
 
     dest_stride = pixman_image_get_stride(surface);
@@ -1455,7 +1422,6 @@ static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int
     }
 
     descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(mask->bitmap);
-    access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
     need_invers = mask->flags & SPICE_MASK_FLAGS_INVERS;
 
 #ifdef SW_CANVAS_CACHE
@@ -1467,7 +1433,6 @@ static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int
     switch (descriptor->type) {
     case SPICE_IMAGE_TYPE_BITMAP: {
         SpiceBitmapImage *bitmap = (SpiceBitmapImage *)descriptor;
-        access_test(canvas, descriptor, sizeof(SpiceBitmapImage));
         is_invers = need_invers && !cache_me;
         surface = canvas_get_bitmap_mask(canvas, &bitmap->bitmap, is_invers);
         break;
@@ -1668,18 +1633,14 @@ static pixman_image_t *canvas_get_str_mask(CanvasBase *canvas, SpiceString *str,
 
     ASSERT(str->length > 0);
 
-    access_test(canvas, glyph, sizeof(SpiceRasterGlyph));
     next_glyph = canvas_next_raster_glyph(glyph, bpp);
-    access_test(canvas, glyph, (uint8_t*)next_glyph - (uint8_t*)glyph);
     canvas_raster_glyph_box(glyph, &bounds);
 
     for (i = 1; i < str->length; i++) {
         SpiceRect glyph_box;
 
         glyph = next_glyph;
-        access_test(canvas, glyph, sizeof(SpiceRasterGlyph));
         next_glyph = canvas_next_raster_glyph(glyph, bpp);
-        access_test(canvas, glyph, (uint8_t*)next_glyph - (uint8_t*)glyph);
         canvas_raster_glyph_box(glyph, &glyph_box);
         rect_union(&bounds, &glyph_box);
     }
@@ -1860,14 +1821,6 @@ static int quic_usr_more_lines(QuicUsrContext *usr, uint8_t **lines)
     return 0;
 }
 
-#ifdef SW_CANVAS_ACCESS_TEST
-static void __canvas_set_access_params(CanvasBase *canvas, unsigned long base, unsigned long max)
-{
-    canvas->base = base;
-    canvas->max = max;
-}
-#endif
-
 static void canvas_base_destroy(CanvasBase *canvas)
 {
     quic_destroy(canvas->quic_data.quic);
@@ -1920,10 +1873,8 @@ static void canvas_clip_pixman(CanvasBase *canvas,
         break;
     case SPICE_CLIP_TYPE_RECTS: {
         uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data);
-        access_test(canvas, n, sizeof(uint32_t));
 
         SpiceRect *now = (SpiceRect *)(n + 1);
-        access_test(canvas, now, (unsigned long)(now + *n) - (unsigned long)now);
 
         pixman_region32_t clip;
 
@@ -3073,7 +3024,6 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
         gc.base.lineStyle = LineOnOffDash;
         gc.base.dash = (unsigned char *)spice_malloc(nseg);
         gc.base.numInDashList = nseg;
-        access_test(canvas, style, nseg * sizeof(*style));
 
         if (stroke->attr.flags & SPICE_LINE_FLAGS_START_WITH_GAP) {
             gc.base.dash[stroke->attr.style_nseg - 1] = fix_to_int(style[0]);
@@ -3118,19 +3068,15 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
     }
 
     data_size = (uint32_t*)SPICE_GET_ADDRESS(stroke->path);
-    access_test(canvas, data_size, sizeof(uint32_t));
     more = *data_size;
     seg = (SpicePathSeg*)(data_size + 1);
 
     stroke_lines_init(&lines);
 
     do {
-        access_test(canvas, seg, sizeof(SpicePathSeg));
-
         uint32_t flags = seg->flags;
         SpicePointFix* point = (SpicePointFix*)seg->data;
         SpicePointFix* end_point = point + seg->count;
-        access_test(canvas, point, (unsigned long)end_point - (unsigned long)point);
         ASSERT(point < end_point);
         more -= ((unsigned long)end_point - (unsigned long)seg);
         seg = (SpicePathSeg*)end_point;
diff --git a/common/canvas_base.h b/common/canvas_base.h
index 1bbe465..b54fce5 100644
--- a/common/canvas_base.h
+++ b/common/canvas_base.h
@@ -142,7 +142,6 @@ typedef struct {
     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 (*set_access_params)(SpiceCanvas *canvas, unsigned long base, unsigned long max);
     void (*destroy)(SpiceCanvas *canvas);
 
     /* Implementation vfuncs */
diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index 20113fe..fea2390 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -311,18 +311,14 @@ uint32_t raster_ops[] = {
 static void set_path(GdiCanvas *canvas, void *addr)
 {
     uint32_t* data_size = (uint32_t*)addr;
-    access_test(&canvas->base, data_size, sizeof(uint32_t));
     uint32_t more = *data_size;
 
     SpicePathSeg* seg = (SpicePathSeg*)(data_size + 1);
 
     do {
-        access_test(&canvas->base, seg, sizeof(SpicePathSeg));
-
         uint32_t flags = seg->flags;
         SpicePointFix* point = (SpicePointFix*)seg->data;
         SpicePointFix* end_point = point + seg->count;
-        access_test(&canvas->base, point, (unsigned long)end_point - (unsigned long)point);
         ASSERT(point < end_point);
         more -= ((unsigned long)end_point - (unsigned long)seg);
         seg = (SpicePathSeg*)end_point;
@@ -399,11 +395,9 @@ static void set_clip(GdiCanvas *canvas, SpiceClip *clip)
         break;
     case SPICE_CLIP_TYPE_RECTS: {
         uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data);
-        access_test(&canvas->base, n, sizeof(uint32_t));
 
         SpiceRect *now = (SpiceRect *)(n + 1);
         SpiceRect *end = now + *n;
-        access_test(&canvas->base, now, (unsigned long)end - (unsigned long)now);
 
         if (now < end) {
             HRGN main_hrgn;
@@ -1643,8 +1637,6 @@ static uint32_t *gdi_get_userstyle(GdiCanvas *canvas, uint8_t nseg, SPICE_ADDRES
     uint32_t *local_style;
     int i;
 
-    access_test(&canvas->base, style, nseg * sizeof(*style));
-
     if (nseg == 0) {
         CANVAS_ERROR("bad nseg");
     }
@@ -1835,14 +1827,6 @@ static void gdi_canvas_clear(SpiceCanvas *spice_canvas)
 {
 }
 
-static void gdi_canvas_set_access_params(SpiceCanvas *spice_canvas, unsigned long base, unsigned long max)
-{
-#ifdef SW_CANVAS_ACCESS_TEST
-    GdiCanvas *canvas = (GdiCanvas *)spice_canvas;
-    __canvas_set_access_params(&canvas->base, base, max);
-#endif
-}
-
 static void gdi_canvas_destroy(SpiceCanvas *spice_canvas)
 {
     GdiCanvas *canvas = (GdiCanvas *)spice_canvas;
@@ -1915,7 +1899,6 @@ void gdi_canvas_init() //unsafe global function
     gdi_canvas_ops.draw_alpha_blend = gdi_canvas_draw_alpha_blend;
     gdi_canvas_ops.put_image = gdi_canvas_put_image;
     gdi_canvas_ops.clear = gdi_canvas_clear;
-    gdi_canvas_ops.set_access_params = gdi_canvas_set_access_params;
     gdi_canvas_ops.destroy = gdi_canvas_destroy;
 
     rop3_init();
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index 00caf89..444fa4b 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -115,18 +115,14 @@ static GLCPath get_path(GLCanvas *canvas, void *addr)
 {
     GLCPath path = glc_path_create(canvas->glc);
     uint32_t* data_size = (uint32_t*)addr;
-    access_test(&canvas->base, data_size, sizeof(uint32_t));
     uint32_t more = *data_size;
 
     SpicePathSeg* seg = (SpicePathSeg*)(data_size + 1);
 
     do {
-        access_test(&canvas->base, seg, sizeof(SpicePathSeg));
-
         uint32_t flags = seg->flags;
         SpicePointFix* point = (SpicePointFix*)seg->data;
         SpicePointFix* end_point = point + seg->count;
-        access_test(&canvas->base, point, (unsigned long)end_point - (unsigned long)point);
         ASSERT(point < end_point);
         more -= ((unsigned long)end_point - (unsigned long)seg);
         seg = (SpicePathSeg*)end_point;
@@ -183,10 +179,8 @@ static void set_clip(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip)
         break;
     case SPICE_CLIP_TYPE_RECTS: {
         uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data);
-        access_test(&canvas->base, n, sizeof(uint32_t));
         SpiceRect *now = (SpiceRect *)(n + 1);
         SpiceRect *end = now + *n;
-        access_test(&canvas->base, now, (unsigned long)end - (unsigned long)now);
 
         if (*n == 0) {
             rect.x = rect.y = 0;
@@ -810,14 +804,6 @@ static void gl_canvas_group_end(SpiceCanvas *spice_canvas)
     glc_clear_mask(canvas->glc, GLC_MASK_B);
 }
 
-static void gl_canvas_set_access_params(SpiceCanvas *spice_canvas, unsigned long base, unsigned long max)
-{
-#ifdef SW_CANVAS_ACCESS_TEST
-    GLCanvas *canvas = (GLCanvas *)spice_canvas;
-    __canvas_set_access_params(&canvas->base, base, max);
-#endif
-}
-
 static int need_init = 1;
 static SpiceCanvasOps gl_canvas_ops;
 
@@ -926,7 +912,6 @@ void gl_canvas_init() //unsafe global function
     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.set_access_params = gl_canvas_set_access_params;
     gl_canvas_ops.destroy = gl_canvas_destroy;
 
     rop3_init();
diff --git a/common/sw_canvas.c b/common/sw_canvas.c
index 8280362..c1a7392 100644
--- a/common/sw_canvas.c
+++ b/common/sw_canvas.c
@@ -1144,15 +1144,6 @@ static void canvas_clear(SpiceCanvas *spice_canvas)
                            0);
 }
 
-static void canvas_set_access_params(SpiceCanvas *spice_canvas,
-                                     unsigned long base, unsigned long max)
-{
-#ifdef SW_CANVAS_ACCESS_TEST
-    SwCanvas *canvas = (SwCanvas *)spice_canvas;
-    __canvas_set_access_params(&canvas->base, base, max);
-#endif
-}
-
 static void canvas_destroy(SpiceCanvas *spice_canvas)
 {
     SwCanvas *canvas = (SwCanvas *)spice_canvas;
@@ -1306,7 +1297,6 @@ void sw_canvas_init() //unsafe global function
     sw_canvas_ops.put_image = canvas_put_image;
     sw_canvas_ops.clear = canvas_clear;
     sw_canvas_ops.read_bits = canvas_read_bits;
-    sw_canvas_ops.set_access_params = canvas_set_access_params;
     sw_canvas_ops.destroy = canvas_destroy;
 
     sw_canvas_ops.fill_solid_spans = fill_solid_spans;
commit 17bbef4df334bd8d98d3960143f229d753b4b0a3
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed May 26 13:59:51 2010 +0200

    Generate demarshallers in client

diff --git a/client/Makefile.am b/client/Makefile.am
index 55bc0f8..ab80bfb 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -1,8 +1,13 @@
 NULL =
 
-SUBDIRS = $(red_target)
+SUBDIRS = . $(red_target)
 DIST_SUBDIRS = x11 #windows
 
+spice_built_sources = generated_demarshallers.cpp
+
+generated_demarshallers.cpp: $(top_srcdir)/spice.proto
+	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h $(top_srcdir)/spice.proto generated_demarshallers.cpp
+
 RED_COMMON_SRCS =			\
 	application.cpp			\
 	application.h			\
@@ -90,4 +95,8 @@ RED_COMMON_SRCS =			\
 	utils.h				\
 	$(NULL)
 
-EXTRA_DIST = $(RED_COMMON_SRCS)
+MAINTAINERCLEANFILES = $(spice_built_sources)
+
+EXTRA_DIST = $(RED_COMMON_SRCS) $(spice_built_sources)
+
+BUILT_SOURCES = $(spice_built_sources)
diff --git a/configure.ac b/configure.ac
index 08804bf..3114a1a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -25,6 +25,7 @@ AC_CANONICAL_HOST
 AC_PROG_LIBTOOL
 AM_PROG_CC_C_O
 AC_C_BIGENDIAN
+AC_PATH_PROGS(PYTHON, python2 python)
 
 SPICE_LT_VERSION=m4_format("%d:%d:%d", 1, 0, 0)
 AC_SUBST(SPICE_LT_VERSION)
commit b228d18d5c8a2feb8319de50d5e6cc8925e11545
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed May 26 12:24:48 2010 +0200

    Add python code to automake system

diff --git a/Makefile.am b/Makefile.am
index 6640259..5701e25 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,9 @@
-SUBDIRS = common server client
+SUBDIRS = common server client python_modules
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = spice-server.pc
 
 DISTCLEANFILES =                                \
 	spice-server.pc
+
+EXTRA_DIST = spice.proto spice_codegen.py
diff --git a/configure.ac b/configure.ac
index 0958b6d..08804bf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -337,6 +337,7 @@ AC_OUTPUT([
 Makefile
 spice-server.pc
 common/Makefile
+python_modules/Makefile
 server/Makefile
 client/Makefile
 client/x11/Makefile
diff --git a/python_modules/Makefile.am b/python_modules/Makefile.am
new file mode 100644
index 0000000..4b3c960
--- /dev/null
+++ b/python_modules/Makefile.am
@@ -0,0 +1,6 @@
+NULL =
+
+PYTHON_MODULES = __init__.py codegen.py demarshal.py ptypes.py spice_parser.py
+
+EXTRA_DIST = $(PYTHON_MODULES)
+
diff --git a/spice_codegen.py b/spice_codegen.py
new file mode 100755
index 0000000..f897ce8
--- /dev/null
+++ b/spice_codegen.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+
+import os
+import sys
+from optparse import OptionParser
+import traceback
+from python_modules import spice_parser
+from python_modules import ptypes
+from python_modules import codegen
+from python_modules import demarshal
+
+def write_channel_enums(writer, channel, client):
+    messages = filter(lambda m : m.channel == channel, \
+                          channel.client_messages if client else channel.server_messages)
+    if len(messages) == 0:
+        return
+    writer.begin_block("enum")
+    i = 0;
+    if client:
+        prefix = [ "MSGC" ]
+    else:
+        prefix = [ "MSG" ]
+    if channel.member_name:
+        prefix.append(channel.member_name.upper())
+    prefix.append(None) # To be replaced with name
+    for m in messages:
+        prefix[-1] = m.name.upper()
+        enum = codegen.prefix_underscore_upper(*prefix)
+        if m.value == i:
+            writer.writeln("%s," % enum)
+            i = i + 1
+        else:
+            writer.writeln("%s = %s," % (enum, m.value))
+            i = m.value + 1
+    if channel.member_name:
+        prefix[-1] = prefix[-2]
+        prefix[-2] = "END"
+        writer.newline()
+        writer.writeln("%s" % (codegen.prefix_underscore_upper(*prefix)))
+    writer.end_block(semicolon=True)
+    writer.newline()
+
+def write_enums(writer):
+    writer.writeln("#ifndef _H_SPICE_ENUMS")
+    writer.writeln("#define _H_SPICE_ENUMS")
+    writer.newline()
+    writer.comment("Generated from %s, don't edit" % writer.options["source"]).newline()
+    writer.newline()
+
+    # Define enums
+    for t in ptypes.get_named_types():
+        if isinstance(t, ptypes.EnumBaseType):
+            t.c_define(writer)
+
+    i = 0;
+    writer.begin_block("enum")
+    for c in proto.channels:
+        enum = codegen.prefix_underscore_upper("CHANNEL", c.name.upper())
+        if c.value == i:
+            writer.writeln("%s," % enum)
+            i = i + 1
+        else:
+            writer.writeln("%s = %s," % (enum, c.value))
+            i = c.value + 1
+    writer.newline()
+    writer.writeln("SPICE_END_CHANNEL")
+    writer.end_block(semicolon=True)
+    writer.newline()
+
+    for c in ptypes.get_named_types():
+        if not isinstance(c, ptypes.ChannelType):
+            continue
+        write_channel_enums(writer, c, False)
+        write_channel_enums(writer, c, True)
+
+    writer.writeln("#endif /* _H_SPICE_ENUMS */")
+
+parser = OptionParser(usage="usage: %prog [options] <protocol_file> <destination file>")
+parser.add_option("-e", "--generate-enums",
+                  action="store_true", dest="generate_enums", default=False,
+                  help="Generate enums")
+parser.add_option("-d", "--generate-demarshallers",
+                  action="store_true", dest="generate_demarshallers", default=False,
+                  help="Generate demarshallers")
+parser.add_option("-a", "--assert-on-error",
+                  action="store_true", dest="assert_on_error", default=False,
+                  help="Assert on error")
+parser.add_option("-p", "--print-error",
+                  action="store_true", dest="print_error", default=False,
+                  help="Print errors")
+parser.add_option("-s", "--server",
+                  action="store_true", dest="server", default=False,
+                  help="Print errors")
+parser.add_option("-c", "--client",
+                  action="store_true", dest="client", default=False,
+                  help="Print errors")
+parser.add_option("-k", "--keep-identical-file",
+                  action="store_true", dest="keep_identical_file", default=False,
+                  help="Print errors")
+parser.add_option("-i", "--include",
+                  dest="include", default=None, metavar="FILE",
+                  help="Include FILE in generated code")
+
+(options, args) = parser.parse_args()
+
+if len(args) == 0:
+    parser.error("No protocol file specified")
+
+if len(args) == 1:
+    parser.error("No destination file specified")
+
+proto_file = args[0]
+dest_file = args[1]
+proto = spice_parser.parse(proto_file)
+
+if proto == None:
+    exit(1)
+
+codegen.set_prefix(proto.name)
+writer = codegen.CodeWriter()
+writer.set_option("source", os.path.basename(proto_file))
+
+if options.assert_on_error:
+    writer.set_option("assert_on_error")
+
+if options.print_error:
+    writer.set_option("print_error")
+
+if options.include:
+    writer.writeln('#include "%s"' % options.include)
+
+if options.generate_enums:
+    write_enums(writer)
+
+if options.generate_demarshallers:
+    if not options.server and not options.client:
+        print >> sys.stderr, "Must specify client and/or server"
+        sys.exit(1)
+    demarshal.write_includes(writer)
+
+    if options.server:
+        demarshal.write_protocol_parser(writer, proto, False)
+    if options.client:
+        demarshal.write_protocol_parser(writer, proto, True)
+
+content = writer.getvalue()
+if options.keep_identical_file:
+    try:
+        f = open(dest_file, 'rb')
+        old_content = f.read()
+        f.close()
+
+        if content == old_content:
+            print "No changes to %s" % dest_file
+            sys.exit(0)
+
+    except IOError:
+        pass
+
+f = open(dest_file, 'wb')
+f.write(content)
+f.close()
+
+print "Wrote %s" % dest_file
+sys.exit(0)
diff --git a/spice_gen.py b/spice_gen.py
deleted file mode 100755
index f897ce8..0000000
--- a/spice_gen.py
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/usr/bin/env python
-
-import os
-import sys
-from optparse import OptionParser
-import traceback
-from python_modules import spice_parser
-from python_modules import ptypes
-from python_modules import codegen
-from python_modules import demarshal
-
-def write_channel_enums(writer, channel, client):
-    messages = filter(lambda m : m.channel == channel, \
-                          channel.client_messages if client else channel.server_messages)
-    if len(messages) == 0:
-        return
-    writer.begin_block("enum")
-    i = 0;
-    if client:
-        prefix = [ "MSGC" ]
-    else:
-        prefix = [ "MSG" ]
-    if channel.member_name:
-        prefix.append(channel.member_name.upper())
-    prefix.append(None) # To be replaced with name
-    for m in messages:
-        prefix[-1] = m.name.upper()
-        enum = codegen.prefix_underscore_upper(*prefix)
-        if m.value == i:
-            writer.writeln("%s," % enum)
-            i = i + 1
-        else:
-            writer.writeln("%s = %s," % (enum, m.value))
-            i = m.value + 1
-    if channel.member_name:
-        prefix[-1] = prefix[-2]
-        prefix[-2] = "END"
-        writer.newline()
-        writer.writeln("%s" % (codegen.prefix_underscore_upper(*prefix)))
-    writer.end_block(semicolon=True)
-    writer.newline()
-
-def write_enums(writer):
-    writer.writeln("#ifndef _H_SPICE_ENUMS")
-    writer.writeln("#define _H_SPICE_ENUMS")
-    writer.newline()
-    writer.comment("Generated from %s, don't edit" % writer.options["source"]).newline()
-    writer.newline()
-
-    # Define enums
-    for t in ptypes.get_named_types():
-        if isinstance(t, ptypes.EnumBaseType):
-            t.c_define(writer)
-
-    i = 0;
-    writer.begin_block("enum")
-    for c in proto.channels:
-        enum = codegen.prefix_underscore_upper("CHANNEL", c.name.upper())
-        if c.value == i:
-            writer.writeln("%s," % enum)
-            i = i + 1
-        else:
-            writer.writeln("%s = %s," % (enum, c.value))
-            i = c.value + 1
-    writer.newline()
-    writer.writeln("SPICE_END_CHANNEL")
-    writer.end_block(semicolon=True)
-    writer.newline()
-
-    for c in ptypes.get_named_types():
-        if not isinstance(c, ptypes.ChannelType):
-            continue
-        write_channel_enums(writer, c, False)
-        write_channel_enums(writer, c, True)
-
-    writer.writeln("#endif /* _H_SPICE_ENUMS */")
-
-parser = OptionParser(usage="usage: %prog [options] <protocol_file> <destination file>")
-parser.add_option("-e", "--generate-enums",
-                  action="store_true", dest="generate_enums", default=False,
-                  help="Generate enums")
-parser.add_option("-d", "--generate-demarshallers",
-                  action="store_true", dest="generate_demarshallers", default=False,
-                  help="Generate demarshallers")
-parser.add_option("-a", "--assert-on-error",
-                  action="store_true", dest="assert_on_error", default=False,
-                  help="Assert on error")
-parser.add_option("-p", "--print-error",
-                  action="store_true", dest="print_error", default=False,
-                  help="Print errors")
-parser.add_option("-s", "--server",
-                  action="store_true", dest="server", default=False,
-                  help="Print errors")
-parser.add_option("-c", "--client",
-                  action="store_true", dest="client", default=False,
-                  help="Print errors")
-parser.add_option("-k", "--keep-identical-file",
-                  action="store_true", dest="keep_identical_file", default=False,
-                  help="Print errors")
-parser.add_option("-i", "--include",
-                  dest="include", default=None, metavar="FILE",
-                  help="Include FILE in generated code")
-
-(options, args) = parser.parse_args()
-
-if len(args) == 0:
-    parser.error("No protocol file specified")
-
-if len(args) == 1:
-    parser.error("No destination file specified")
-
-proto_file = args[0]
-dest_file = args[1]
-proto = spice_parser.parse(proto_file)
-
-if proto == None:
-    exit(1)
-
-codegen.set_prefix(proto.name)
-writer = codegen.CodeWriter()
-writer.set_option("source", os.path.basename(proto_file))
-
-if options.assert_on_error:
-    writer.set_option("assert_on_error")
-
-if options.print_error:
-    writer.set_option("print_error")
-
-if options.include:
-    writer.writeln('#include "%s"' % options.include)
-
-if options.generate_enums:
-    write_enums(writer)
-
-if options.generate_demarshallers:
-    if not options.server and not options.client:
-        print >> sys.stderr, "Must specify client and/or server"
-        sys.exit(1)
-    demarshal.write_includes(writer)
-
-    if options.server:
-        demarshal.write_protocol_parser(writer, proto, False)
-    if options.client:
-        demarshal.write_protocol_parser(writer, proto, True)
-
-content = writer.getvalue()
-if options.keep_identical_file:
-    try:
-        f = open(dest_file, 'rb')
-        old_content = f.read()
-        f.close()
-
-        if content == old_content:
-            print "No changes to %s" % dest_file
-            sys.exit(0)
-
-    except IOError:
-        pass
-
-f = open(dest_file, 'wb')
-f.write(content)
-f.close()
-
-print "Wrote %s" % dest_file
-sys.exit(0)
commit 0366e7395c97e51b8a6294c10176bef73e1bdcf7
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed May 26 12:19:58 2010 +0200

    Initial import of spice protocol description and demarshall generator
    
    The "spice.proto" file describes in detail the networking prototcol
    that spice uses and spice_codegen.py can parse this and generate
    demarshallers for such network messages.

diff --git a/python_modules/__init__.py b/python_modules/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/python_modules/codegen.py b/python_modules/codegen.py
new file mode 100644
index 0000000..5bb659a
--- /dev/null
+++ b/python_modules/codegen.py
@@ -0,0 +1,354 @@
+from cStringIO import StringIO
+
+def camel_to_underscores(s, upper = False):
+    res = ""
+    for i in range(len(s)):
+        c = s[i]
+        if i > 0 and c.isupper():
+            res = res + "_"
+        if upper:
+            res = res + c.upper()
+        else:
+            res = res + c.lower()
+        return res
+
+def underscores_to_camel(s):
+    res = ""
+    do_upper = True
+    for i in range(len(s)):
+        c = s[i]
+        if c == "_":
+            do_upper = True
+        else:
+            if do_upper:
+                res = res + c.upper()
+            else:
+                res = res + c
+            do_upper = False
+    return res
+
+proto_prefix = "Temp"
+
+def set_prefix(prefix):
+    global proto_prefix
+    global proto_prefix_upper
+    global proto_prefix_lower
+    proto_prefix = prefix
+    proto_prefix_upper = prefix.upper()
+    proto_prefix_lower = prefix.lower()
+
+def prefix_underscore_upper(*args):
+    s = proto_prefix_upper
+    for arg in args:
+        s = s + "_" + arg
+    return s
+
+def prefix_underscore_lower(*args):
+    s = proto_prefix_lower
+    for arg in args:
+        s = s + "_" + arg
+    return s
+
+def prefix_camel(*args):
+    s = proto_prefix
+    for arg in args:
+        s = s + underscores_to_camel(arg)
+    return s
+
+def increment_identifier(idf):
+    v = idf[-1:]
+    if v.isdigit():
+        return idf[:-1] + str(int(v) + 1)
+    return idf + "2"
+
+def sum_array(array):
+    if len(array) == 0:
+        return 0
+    return " + ".join(array)
+
+class CodeWriter:
+    def __init__(self):
+        self.out = StringIO()
+        self.contents = [self.out]
+        self.indentation = 0
+        self.at_line_start = True
+        self.indexes = ["i", "j", "k", "ii", "jj", "kk"]
+        self.current_index = 0
+        self.generated = {}
+        self.vars = []
+        self.has_error_check = False
+        self.options = {}
+        self.function_helper_writer = None
+
+    def set_option(self, opt, value = True):
+        self.options[opt] = value
+
+    def has_option(self, opt):
+        return self.options.has_key(opt)
+
+    def set_is_generated(self, kind, name):
+        if not self.generated.has_key(kind):
+            v = {}
+            self.generated[kind] = v
+        else:
+            v = self.generated[kind]
+        v[name] = 1
+
+    def is_generated(self, kind, name):
+        if not self.generated.has_key(kind):
+            return False
+        v = self.generated[kind]
+        return v.has_key(name)
+
+    def getvalue(self):
+        strs = map(lambda writer: writer.getvalue(), self.contents)
+        return "".join(strs)
+
+    def get_subwriter(self):
+        writer = CodeWriter()
+        self.contents.append(writer)
+        self.out = StringIO()
+        self.contents.append(self.out)
+        writer.indentation = self.indentation
+        writer.at_line_start = self.at_line_start
+        writer.generated = self.generated
+        writer.options = self.options
+
+        return writer;
+
+    def write(self, s):
+        # Ensure its a string
+        s = str(s)
+
+        if len(s) == 0:
+            return
+
+        if self.at_line_start:
+            for i in range(self.indentation):
+                self.out.write(" ")
+            self.at_line_start = False
+        self.out.write(s)
+        return self
+
+    def newline(self):
+        self.out.write("\n")
+        self.at_line_start = True
+        return self
+
+    def writeln(self, s):
+        self.write(s)
+        self.newline()
+        return self
+
+    def label(self, s):
+        self.indentation = self.indentation - 1
+        self.write(s + ":")
+        self.indentation = self.indentation + 1
+        self.newline()
+
+    def statement(self, s):
+        self.write(s)
+        self.write(";")
+        self.newline()
+        return self
+
+    def assign(self, var, val):
+        self.write("%s = %s" % (var, val))
+        self.write(";")
+        self.newline()
+        return self
+
+    def increment(self, var, val):
+        self.write("%s += %s" % (var, val))
+        self.write(";")
+        self.newline()
+        return self
+
+    def comment(self, str):
+        self.write("/* " + str + " */")
+        return self
+
+    def todo(self, str):
+        self.comment("TODO: *** %s ***" % str).newline()
+        return self
+
+    def error_check(self, check, label = "error"):
+        self.has_error_check = True
+        with self.block("if (SPICE_UNLIKELY(%s))" % check):
+            if self.has_option("print_error"):
+                self.statement('printf("%%s: Caught error - %s", __PRETTY_FUNCTION__)' % check)
+            if self.has_option("assert_on_error"):
+                self.statement("assert(0)")
+            self.statement("goto %s" % label)
+
+    def indent(self):
+        self.indentation += 4;
+
+    def unindent(self):
+        self.indentation -= 4;
+        if self.indentation < 0:
+            self.indenttation = 0
+
+    def begin_block(self, prefix= "", comment = ""):
+        if len(prefix) > 0:
+            self.write(prefix)
+        if self.at_line_start:
+            self.write("{")
+        else:
+            self.write(" {")
+        if len(comment) > 0:
+            self.write(" ")
+            self.comment(comment)
+        self.newline()
+        self.indent()
+
+    def end_block(self, semicolon=False, newline=True):
+        self.unindent()
+        if self.at_line_start:
+            self.write("}")
+        else:
+            self.write(" }")
+        if semicolon:
+            self.write(";")
+        if newline:
+            self.newline()
+
+    class Block:
+        def __init__(self, writer, semicolon, newline):
+            self.writer = writer
+            self.semicolon = semicolon
+            self.newline = newline
+
+        def __enter__(self):
+            return self.writer.get_subwriter()
+
+        def __exit__(self, exc_type, exc_value, traceback):
+            self.writer.end_block(self.semicolon, self.newline)
+
+    class PartialBlock:
+        def __init__(self, writer, scope, semicolon, newline):
+            self.writer = writer
+            self.scope = scope
+            self.semicolon = semicolon
+            self.newline = newline
+
+        def __enter__(self):
+            return self.scope
+
+        def __exit__(self, exc_type, exc_value, traceback):
+            self.writer.end_block(self.semicolon, self.newline)
+
+    class NoBlock:
+        def __init__(self, scope):
+            self.scope = scope
+
+        def __enter__(self):
+            return self.scope
+
+        def __exit__(self, exc_type, exc_value, traceback):
+            pass
+
+    def block(self, prefix= "", comment = "", semicolon=False, newline=True):
+        self.begin_block(prefix, comment)
+        return self.Block(self, semicolon, newline)
+
+    def partial_block(self, scope, semicolon=False, newline=True):
+        return self.PartialBlock(self, scope, semicolon, newline)
+
+    def no_block(self, scope):
+        return self.NoBlock(scope)
+
+    def optional_block(self, scope):
+        if scope != None:
+            return self.NoBlock(scope)
+        return self.block()
+
+    def for_loop(self, index, limit):
+        return self.block("for (%s = 0; %s < %s; %s++)" % (index, index, limit, index))
+
+    def while_loop(self, expr):
+        return self.block("while (%s)" % (expr))
+
+    def if_block(self, check, elseif=False, newline=True):
+        s = "if (%s)" % (check)
+        if elseif:
+            s = " else " + s
+        self.begin_block(s, "")
+        return self.Block(self, False, newline)
+
+    def variable_defined(self, name):
+        for n in self.vars:
+            if n == name:
+                return True
+        return False
+
+    def variable_def(self, ctype, *names):
+        for n in names:
+            # Strip away initialization
+            i = n.find("=")
+            if i != -1:
+                n = n[0:i]
+            self.vars.append(n.strip())
+        # only add space for non-pointer types
+        if ctype[-1] == "*":
+            ctype = ctype[:-1].rstrip()
+            self.writeln("%s *%s;"%(ctype, ", *".join(names)))
+        else:
+            self.writeln("%s %s;"%(ctype, ", ".join(names)))
+        return self
+
+    def function_helper(self):
+        if self.function_helper_writer != None:
+            writer = self.function_helper_writer.get_subwriter()
+            self.function_helper_writer.newline()
+        else:
+            writer = self.get_subwriter()
+        return writer
+
+    def function(self, name, return_type, args, static = False):
+        self.has_error_check = False
+        self.function_helper_writer = self.get_subwriter()
+        if static:
+            self.write("static ")
+        self.write(return_type)
+        self.write(" %s(%s)"% (name, args)).newline()
+        self.begin_block()
+        self.function_variables_writer = self.get_subwriter()
+        self.function_variables = {}
+        return self.function_variables_writer
+
+    def macro(self, name, args, define):
+        self.write("#define %s(%s) %s" % (name, args, define)).newline()
+
+    def add_function_variable(self, ctype, name):
+        if self.function_variables.has_key(name):
+            assert(self.function_variables[name] == ctype)
+        else:
+            self.function_variables[name] = ctype
+            self.function_variables_writer.variable_def(ctype, name)
+
+    def pop_index(self):
+        index = self.indexes[self.current_index]
+        self.current_index = self.current_index + 1
+        self.add_function_variable("uint32_t", index)
+        return index
+
+    def push_index(self):
+        self.current_index = self.current_index - 1
+
+    class Index:
+        def __init__(self, writer, val):
+            self.writer = writer
+            self.val = val
+
+        def __enter__(self):
+            return self.val
+
+        def __exit__(self, exc_type, exc_value, traceback):
+            self.writer.push_index()
+
+    def index(self, no_block = False):
+        if no_block:
+            return self.no_block(None)
+        val = self.pop_index()
+        return self.Index(self, val)
diff --git a/python_modules/demarshal.py b/python_modules/demarshal.py
new file mode 100644
index 0000000..fcd6850
--- /dev/null
+++ b/python_modules/demarshal.py
@@ -0,0 +1,1033 @@
+import ptypes
+import codegen
+
+
+def write_parser_helpers(writer):
+    if writer.is_generated("helper", "demarshaller"):
+        return
+
+    writer.set_is_generated("helper", "demarshaller")
+
+    writer = writer.function_helper()
+
+    writer.writeln("#ifdef WORDS_BIGENDIAN")
+    for size in [8, 16, 32, 64]:
+        for sign in ["", "u"]:
+            utype = "uint%d" % (size)
+            type = "%sint%d" % (sign, size)
+            swap = "SPICE_BYTESWAP%d" % size
+            if size == 8:
+                writer.macro("read_%s" % type, "ptr", "(*((%s_t *)(ptr)))" % type)
+            else:
+                writer.macro("read_%s" % type, "ptr", "((%s_t)%s(*((%s_t *)(ptr)))" % (type, swap, utype))
+    writer.writeln("#else")
+    for size in [8, 16, 32, 64]:
+        for sign in ["", "u"]:
+            type = "%sint%d" % (sign, size)
+            writer.macro("read_%s" % type, "ptr", "(*((%s_t *)(ptr)))" % type)
+    writer.writeln("#endif")
+
+    for size in [8, 16, 32, 64]:
+        for sign in ["", "u"]:
+            writer.newline()
+            type = "%sint%d" % (sign, size)
+            ctype = "%s_t" % type
+            scope = writer.function("SPICE_GNUC_UNUSED consume_%s" % type, ctype, "uint8_t **ptr", True)
+            scope.variable_def(ctype, "val")
+            writer.assign("val", "read_%s(*ptr)" % type)
+            writer.increment("*ptr", size / 8)
+            writer.statement("return val")
+            writer.end_block()
+
+    writer.newline()
+    writer.statement("typedef struct PointerInfo PointerInfo")
+    writer.statement("typedef uint8_t * (*parse_func_t)(uint8_t *message_start, uint8_t *message_end, uint8_t *struct_data, PointerInfo *ptr_info, int minor)")
+    writer.statement("typedef uint8_t * (*parse_msg_func_t)(uint8_t *message_start, uint8_t *message_end, int minor, size_t *size_out)")
+    writer.statement("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)")
+
+    writer.newline()
+    writer.begin_block("struct PointerInfo")
+    writer.variable_def("uint64_t", "offset")
+    writer.variable_def("parse_func_t", "parse")
+    writer.variable_def("SPICE_ADDRESS *", "dest")
+    writer.variable_def("uint32_t", "nelements")
+    writer.end_block(semicolon=True)
+
+def write_read_primitive(writer, start, container, name, scope):
+    m = container.lookup_member(name)
+    assert(m.is_primitive())
+    writer.assign("pos", start + " + " + container.get_nw_offset(m, "", "__nw_size"))
+    writer.error_check("pos + %s > message_end" % m.member_type.get_fixed_nw_size())
+
+    var = "%s__value" % (name)
+    scope.variable_def(m.member_type.c_type(), var)
+    writer.assign(var, "read_%s(pos)" % (m.member_type.primitive_type()))
+    return var
+
+def write_read_primitive_item(writer, item, scope):
+    assert(item.type.is_primitive())
+    writer.assign("pos", item.get_position())
+    writer.error_check("pos + %s > message_end" % item.type.get_fixed_nw_size())
+    var = "%s__value" % (item.subprefix)
+    scope.variable_def(item.type.c_type(), var)
+    writer.assign(var, "read_%s(pos)" % (item.type.primitive_type()))
+    return var
+
+class ItemInfo:
+    def __init__(self, type, prefix, position):
+        self.type = type
+        self.prefix = prefix
+        self.subprefix = prefix
+        self.position = position
+        self.non_null = False
+        self.member = None
+
+    def nw_size(self):
+        return self.prefix + "__nw_size"
+
+    def mem_size(self):
+        return self.prefix + "__mem_size"
+
+    def extra_size(self):
+        return self.prefix + "__extra_size"
+
+    def get_position(self):
+        return self.position
+
+class MemberItemInfo(ItemInfo):
+    def __init__(self, member, container, start):
+        if not member.is_switch():
+            self.type = member.member_type
+        self.prefix = member.name
+        self.subprefix = member.name
+        self.non_null = member.has_attr("nonnull")
+        self.position = "(%s + %s)" % (start, container.get_nw_offset(member, "", "__nw_size"))
+        self.member = member
+
+def write_validate_switch_member(writer, container, switch_member, scope, parent_scope, start,
+                                 want_nw_size, want_mem_size, want_extra_size):
+    var = container.lookup_member(switch_member.variable)
+    var_type = var.member_type
+
+    v = write_read_primitive(writer, start, container, switch_member.variable, parent_scope)
+
+    item = MemberItemInfo(switch_member, container, start)
+
+    first = True
+    for c in switch_member.cases:
+        check = c.get_check(v, var_type)
+        m = c.member
+        with writer.if_block(check, not first, False) as if_scope:
+            item.type = c.member.member_type
+            item.subprefix = item.prefix + "_" + m.name
+            item.non_null = c.member.has_attr("nonnull")
+            sub_want_extra_size = want_extra_size
+            if sub_want_extra_size and not m.contains_extra_size():
+                writer.assign(item.extra_size(), 0)
+                sub_want_extra_size = False
+
+            write_validate_item(writer, container, item, if_scope, scope, start,
+                                want_nw_size, want_mem_size, sub_want_extra_size)
+
+        first = False
+
+    with writer.block(" else"):
+        if want_nw_size:
+            writer.assign(item.nw_size(), 0)
+        if want_mem_size:
+            writer.assign(item.mem_size(), 0)
+        if want_extra_size:
+            writer.assign(item.extra_size(), 0)
+
+    writer.newline()
+
+def write_validate_struct_function(writer, struct):
+    validate_function = "validate_%s" % struct.c_type()
+    if writer.is_generated("validator", validate_function):
+        return validate_function
+
+    writer.set_is_generated("validator", validate_function)
+    writer = writer.function_helper()
+    scope = writer.function(validate_function, "intptr_t", "uint8_t *message_start, uint8_t *message_end, SPICE_ADDRESS offset, int minor")
+    scope.variable_def("uint8_t *", "start = message_start + offset")
+    scope.variable_def("SPICE_GNUC_UNUSED uint8_t *", "pos");
+    scope.variable_def("size_t", "mem_size", "nw_size");
+    num_pointers = struct.get_num_pointers()
+    if  num_pointers != 0:
+        scope.variable_def("SPICE_GNUC_UNUSED intptr_t", "ptr_size");
+
+    writer.newline()
+    with writer.if_block("offset == 0"):
+        writer.statement("return 0")
+
+    writer.newline()
+    writer.error_check("start >= message_end")
+
+    writer.newline()
+    write_validate_container(writer, None, struct, "start", scope, True, True, False)
+
+    writer.newline()
+    writer.comment("Check if struct fits in reported side").newline()
+    writer.error_check("start + nw_size > message_end")
+
+    writer.statement("return mem_size")
+
+    writer.newline()
+    writer.label("error")
+    writer.statement("return -1")
+
+    writer.end_block()
+
+    return validate_function
+
+def write_validate_pointer_item(writer, container, item, scope, parent_scope, start,
+                                want_nw_size, want_mem_size, want_extra_size):
+    if want_nw_size:
+        writer.assign(item.nw_size(), 8)
+
+    if want_mem_size or want_extra_size:
+        target_type = item.type.target_type
+
+        v = write_read_primitive_item(writer, item, scope)
+        if item.non_null:
+            writer.error_check("%s == 0" % v)
+
+        # pointer target is struct, or array of primitives
+        # if array, need no function check
+
+        if target_type.is_array():
+            writer.error_check("message_start + %s >= message_end" % v)
+
+
+            assert target_type.element_type.is_primitive()
+
+            array_item = ItemInfo(target_type, "%s__array" % item.prefix, start)
+            scope.variable_def("uint32_t", array_item.nw_size())
+            scope.variable_def("uint32_t", array_item.mem_size())
+            if target_type.is_cstring_length():
+                writer.assign(array_item.nw_size(), "spice_strnlen((char *)message_start + %s, message_end - (message_start + %s))" % (v, v))
+                writer.error_check("*(message_start + %s + %s) != 0" % (v, array_item.nw_size()))
+                writer.assign(array_item.mem_size(), array_item.nw_size())
+            else:
+                write_validate_array_item(writer, container, array_item, scope, parent_scope, start,
+                                          True, True, False)
+                writer.error_check("message_start + %s + %s > message_end" % (v, array_item.nw_size()))
+
+            if want_extra_size:
+                if item.member and item.member.has_attr("nocopy"):
+                    writer.comment("@nocopy, so no extra size").newline()
+                    writer.assign(item.extra_size(), 0)
+                elif target_type.element_type.get_fixed_nw_size == 1:
+                    writer.assign(item.extra_size(), array_item.mem_size())
+                # If not bytes or zero, add padding needed for alignment
+                else:
+                    writer.assign(item.extra_size(), "%s + /* for alignment */ 3" % array_item.mem_size())
+            if want_mem_size:
+                writer.assign(item.mem_size(), "sizeof(void *) + %s" % array_item.mem_size())
+
+        elif target_type.is_struct():
+            validate_function = write_validate_struct_function(writer, target_type)
+            writer.assign("ptr_size", "%s(message_start, message_end, %s, minor)" % (validate_function, v))
+            writer.error_check("ptr_size < 0")
+
+            if want_extra_size:
+                writer.assign(item.extra_size(), "ptr_size + /* for alignment */ 3")
+            if want_mem_size:
+                writer.assign(item.mem_size(), "sizeof(void *) + ptr_size")
+        else:
+            raise NotImplementedError("pointer to unsupported type %s" % target_type)
+
+
+def write_validate_array_item(writer, container, item, scope, parent_scope, start,
+                              want_nw_size, want_mem_size, want_extra_size):
+    array = item.type
+    is_byte_size = False
+    element_type = array.element_type
+    if array.is_bytes_length():
+        nelements = "%s__nbytes" %(item.prefix)
+    else:
+        nelements = "%s__nelements" %(item.prefix)
+    if not parent_scope.variable_defined(nelements):
+        parent_scope.variable_def("uint32_t", nelements)
+
+    if array.is_constant_length():
+        writer.assign(nelements, array.size)
+    elif array.is_remaining_length():
+        if element_type.is_fixed_nw_size():
+            if element_type.get_fixed_nw_size() == 1:
+                writer.assign(nelements, "message_end - %s" % item.get_position())
+            else:
+                writer.assign(nelements, "(message_end - %s) / (%s)" %(item.get_position(), element_type.get_fixed_nw_size()))
+        else:
+            raise NotImplementedError("TODO array[] of dynamic element size not done yet")
+    elif array.is_identifier_length():
+        v = write_read_primitive(writer, start, container, array.size, scope)
+        writer.assign(nelements, v)
+    elif array.is_image_size_length():
+        bpp = array.size[1]
+        width = array.size[2]
+        rows = array.size[3]
+        width_v = write_read_primitive(writer, start, container, width, scope)
+        rows_v = write_read_primitive(writer, start, container, rows, scope)
+        # TODO: Handle multiplication overflow
+        if bpp == 8:
+            writer.assign(nelements, "%s * %s" % (width_v, rows_v))
+        elif bpp == 1:
+            writer.assign(nelements, "((%s + 7) / 8 ) * %s" % (width_v, rows_v))
+        else:
+            writer.assign(nelements, "((%s * %s + 7) / 8 ) * %s" % (bpp, width_v, rows_v))
+    elif array.is_bytes_length():
+        is_byte_size = True
+        v = write_read_primitive(writer, start, container, array.size[1], scope)
+        writer.assign(nelements, v)
+    elif array.is_cstring_length():
+        writer.todo("cstring array size type not handled yet")
+    else:
+        writer.todo("array size type not handled yet")
+
+    writer.newline()
+
+    nw_size = item.nw_size()
+    mem_size = item.mem_size()
+    extra_size = item.extra_size()
+
+    if is_byte_size and want_nw_size:
+        writer.assign(nw_size, nelements)
+        want_nw_size = False
+
+    if element_type.is_fixed_nw_size() and want_nw_size:
+        element_size = element_type.get_fixed_nw_size()
+        # TODO: Overflow check the multiplication
+        if element_size == 1:
+            writer.assign(nw_size, nelements)
+        else:
+            writer.assign(nw_size, "(%s) * %s" % (element_size, nelements))
+        want_nw_size = False
+
+    if element_type.is_fixed_sizeof() and want_mem_size and not is_byte_size:
+        # TODO: Overflow check the multiplication
+        writer.assign(mem_size, "%s * %s" % (element_type.sizeof(), nelements))
+        want_mem_size = False
+
+    if not element_type.contains_extra_size() and want_extra_size:
+        writer.assign(extra_size, 0)
+        want_extra_size = False
+
+    if not (want_mem_size or want_nw_size or want_extra_size):
+        return
+
+    start2 = codegen.increment_identifier(start)
+    scope.variable_def("uint8_t *", "%s = %s" % (start2, item.get_position()))
+    if is_byte_size:
+        start2_end = "%s_array_end" % start2
+        scope.variable_def("uint8_t *", start2_end)
+
+    element_item = ItemInfo(element_type, "%s__element" % item.prefix, start2)
+
+    element_nw_size = element_item.nw_size()
+    element_mem_size = element_item.mem_size()
+    scope.variable_def("uint32_t", element_nw_size)
+    scope.variable_def("uint32_t", element_mem_size)
+
+    if want_nw_size:
+        writer.assign(nw_size, 0)
+    if want_mem_size:
+        writer.assign(mem_size, 0)
+    if want_extra_size:
+        writer.assign(extra_size, 0)
+
+    want_element_nw_size = want_nw_size
+    if element_type.is_fixed_nw_size():
+        start_increment = element_type.get_fixed_nw_size()
+    else:
+        want_element_nw_size = True
+        start_increment = element_nw_size
+
+    if is_byte_size:
+        writer.assign(start2_end, "%s + %s" % (start2, nelements))
+
+    with writer.index(no_block = is_byte_size) as index:
+        with writer.while_loop("%s < %s" % (start2, start2_end) ) if is_byte_size else writer.for_loop(index, nelements) as scope:
+            write_validate_item(writer, container, element_item, scope, parent_scope, start2,
+                                want_element_nw_size, want_mem_size, want_extra_size)
+
+            if want_nw_size:
+                writer.increment(nw_size, element_nw_size)
+            if want_mem_size:
+                writer.increment(mem_size, element_mem_size)
+            if want_extra_size:
+                writer.increment(extra_size, element_extra_size)
+
+            writer.increment(start2, start_increment)
+    if is_byte_size:
+        writer.error_check("%s != %s" % (start2, start2_end))
+
+def write_validate_struct_item(writer, container, item, scope, parent_scope, start,
+                               want_nw_size, want_mem_size, want_extra_size):
+    struct = item.type
+    start2 = codegen.increment_identifier(start)
+    scope.variable_def("SPICE_GNUC_UNUSED uint8_t *", start2 + " = %s" % (item.get_position()))
+
+    write_validate_container(writer, item.prefix, struct, start2, scope, want_nw_size, want_mem_size, want_extra_size)
+
+def write_validate_primitive_item(writer, container, item, scope, parent_scope, start,
+                                  want_nw_size, want_mem_size, want_extra_size):
+    if want_nw_size:
+        nw_size = item.nw_size()
+        writer.assign(nw_size, item.type.get_fixed_nw_size())
+    if want_mem_size:
+        mem_size = item.mem_size()
+        writer.assign(mem_size, item.type.sizeof())
+    assert not want_extra_size
+
+def write_validate_item(writer, container, item, scope, parent_scope, start,
+                        want_nw_size, want_mem_size, want_extra_size):
+    if item.type.is_pointer():
+        write_validate_pointer_item(writer, container, item, scope, parent_scope, start,
+                                    want_nw_size, want_mem_size, want_extra_size)
+    elif item.type.is_array():
+        write_validate_array_item(writer, container, item, scope, parent_scope, start,
+                                  want_nw_size, want_mem_size, want_extra_size)
+    elif item.type.is_struct():
+        write_validate_struct_item(writer, container, item, scope, parent_scope, start,
+                                   want_nw_size, want_mem_size, want_extra_size)
+    elif item.type.is_primitive():
+        write_validate_primitive_item(writer, container, item, scope, parent_scope, start,
+                                      want_nw_size, want_mem_size, want_extra_size)
+    else:
+        writer.todo("Implement validation of %s" % item.type)
+
+def write_validate_member(writer, container, member, parent_scope, start,
+                          want_nw_size, want_mem_size, want_extra_size):
+    if member.has_minor_attr():
+        prefix = "if (minor >= %s)" % (member.get_minor_attr())
+        newline = False
+    else:
+        prefix = ""
+        newline = True
+    item = MemberItemInfo(member, container, start)
+    with writer.block(prefix, newline=newline, comment=member.name) as scope:
+        if member.is_switch():
+            write_validate_switch_member(writer, container, member, scope, parent_scope, start,
+                                         want_nw_size, want_mem_size, want_extra_size)
+        else:
+            write_validate_item(writer, container, item, scope, parent_scope, start,
+                                want_nw_size, want_mem_size, want_extra_size)
+
+    if member.has_minor_attr():
+        with writer.block(" else", comment = "minor < %s" % (member.get_minor_attr())):
+            if member.is_array():
+                nelements = "%s__nelements" %(item.prefix)
+                writer.assign(nelements, 0)
+            if want_nw_size:
+                writer.assign(item.nw_size(), 0)
+
+            if want_mem_size:
+                if member.is_fixed_sizeof():
+                    writer.assign(item.mem_size(), member.sizeof())
+                elif member.is_array():
+                    writer.assign(item.mem_size(), 0)
+                else:
+                    raise NotImplementedError("TODO minor check for non-constant items")
+
+            assert not want_extra_size
+
+def write_validate_container(writer, prefix, container, start, parent_scope, want_nw_size, want_mem_size, want_extra_size):
+    for m in container.members:
+        sub_want_nw_size = want_nw_size and not m.is_fixed_nw_size()
+        sub_want_mem_size = m.is_extra_size()
+        sub_want_extra_size = not m.is_extra_size() and m.contains_extra_size()
+
+        defs = ["size_t"]
+        if sub_want_nw_size:
+            defs.append (m.name + "__nw_size")
+        if sub_want_mem_size:
+            defs.append (m.name + "__mem_size")
+        if sub_want_extra_size:
+            defs.append (m.name + "__extra_size")
+
+        if sub_want_nw_size or sub_want_mem_size or sub_want_extra_size:
+            parent_scope.variable_def(*defs)
+            write_validate_member(writer, container, m, parent_scope, start,
+                                  sub_want_nw_size, sub_want_mem_size, sub_want_extra_size)
+            writer.newline()
+
+    if want_nw_size:
+        if prefix:
+            nw_size = prefix + "__nw_size"
+        else:
+            nw_size = "nw_size"
+
+        size = 0
+        for m in container.members:
+            if m.is_fixed_nw_size():
+                size = size + m.get_fixed_nw_size()
+
+        nm_sum = str(size)
+        for m in container.members:
+            if not m.is_fixed_nw_size():
+                nm_sum = nm_sum + " + " + m.name + "__nw_size"
+
+        writer.assign(nw_size, nm_sum)
+
+    if want_mem_size:
+        if prefix:
+            mem_size = prefix + "__mem_size"
+        else:
+            mem_size = "mem_size"
+
+        mem_sum = container.sizeof()
+        for m in container.members:
+            if m.is_extra_size():
+                mem_sum = mem_sum + " + " + m.name + "__mem_size"
+            elif m.contains_extra_size():
+                mem_sum = mem_sum + " + " + m.name + "__extra_size"
+
+        writer.assign(mem_size, mem_sum)
+
+    if want_extra_size:
+        if prefix:
+            extra_size = prefix + "__extra_size"
+        else:
+            extra_size = "extra_size"
+
+        extra_sum = []
+        for m in container.members:
+            if m.is_extra_size():
+                extra_sum.append(m.name + "__mem_size")
+            elif m.contains_extra_size():
+                extra_sum.append(m.name + "__extra_size")
+        writer.assign(extra_size, codegen.sum_array(extra_sum))
+
+class DemarshallingDestination:
+    def __init__(self):
+        pass
+
+    def child_at_end(self, writer, t):
+        return RootDemarshallingDestination(self, t.c_type(), t.sizeof())
+
+    def child_sub(self, member):
+        return SubDemarshallingDestination(self, member)
+
+    def declare(self, writer):
+        return writer.optional_block(self.reuse_scope)
+
+    def is_toplevel(self):
+        return self.parent_dest == None and not self.is_helper
+
+class RootDemarshallingDestination(DemarshallingDestination):
+    def __init__(self, parent_dest, c_type, sizeof, pointer = None):
+        self.is_helper = False
+        self.reuse_scope = None
+        self.parent_dest = parent_dest
+        if parent_dest:
+            self.base_var = codegen.increment_identifier(parent_dest.base_var)
+        else:
+            self.base_var = "out"
+        self.c_type = c_type
+        self.sizeof = sizeof
+        self.pointer = pointer # None == at "end"
+
+    def get_ref(self, member):
+        return self.base_var + "->" + member
+
+    def declare(self, writer):
+        if self.reuse_scope:
+            scope = self.reuse_scope
+        else:
+            writer.begin_block()
+            scope = writer.get_subwriter()
+
+        scope.variable_def(self.c_type + " *", self.base_var)
+        if not self.reuse_scope:
+            scope.newline()
+
+        if self.pointer:
+            writer.assign(self.base_var, "(%s *)%s" % (self.c_type, self.pointer))
+        else:
+            writer.assign(self.base_var, "(%s *)end" % (self.c_type))
+            writer.increment("end", self.sizeof)
+        writer.newline()
+
+        if self.reuse_scope:
+            return writer.no_block(self.reuse_scope)
+        else:
+            return writer.partial_block(scope)
+
+class SubDemarshallingDestination(DemarshallingDestination):
+    def __init__(self, parent_dest, member):
+        self.reuse_scope = None
+        self.parent_dest = parent_dest
+        self.base_var = parent_dest.base_var
+        self.member = member
+        self.is_helper = False
+
+    def get_ref(self, member):
+        return self.parent_dest.get_ref(self.member) + "." + member
+
+def read_array_len(writer, prefix, array, dest, scope, handles_bytes = False):
+    if array.is_bytes_length():
+        nelements = "%s__nbytes" % prefix
+    else:
+        nelements = "%s__nelements" % prefix
+    if dest.is_toplevel():
+        return nelements # Already there for toplevel, need not recalculate
+    element_type = array.element_type
+    scope.variable_def("uint32_t", nelements)
+    if array.is_constant_length():
+        writer.assign(nelements, array.size)
+    elif array.is_identifier_length():
+        writer.assign(nelements, dest.get_ref(array.size))
+    elif array.is_remaining_length():
+        if element_type.is_fixed_nw_size():
+            writer.assign(nelements, "(message_end - in) / (%s)" %(element_type.get_fixed_nw_size()))
+        else:
+            raise NotImplementedError("TODO array[] of dynamic element size not done yet")
+    elif array.is_image_size_length():
+        bpp = array.size[1]
+        width = array.size[2]
+        rows = array.size[3]
+        width_v = dest.get_ref(width)
+        rows_v = dest.get_ref(rows)
+        # TODO: Handle multiplication overflow
+        if bpp == 8:
+            writer.assign(nelements, "%s * %s" % (width_v, rows_v))
+        elif bpp == 1:
+            writer.assign(nelements, "((%s + 7) / 8 ) * %s" % (width_v, rows_v))
+        else:
+            writer.assign(nelements, "((%s * %s + 7) / 8 ) * %s" % (bpp, width_v, rows_v))
+    elif array.is_bytes_length():
+        if not handles_bytes:
+            raise NotImplementedError("handling of bytes() not supported here yet")
+        writer.assign(nelements, dest.get_ref(array.size[1]))
+    else:
+        raise NotImplementedError("TODO array size type not handled yet")
+    return nelements
+
+def write_switch_parser(writer, container, switch, dest, scope):
+    var = container.lookup_member(switch.variable)
+    var_type = var.member_type
+
+    if switch.has_attr("fixedsize"):
+        scope.variable_def("uint8_t *", "in_save")
+        writer.assign("in_save", "in")
+
+    first = True
+    for c in switch.cases:
+        check = c.get_check(dest.get_ref(switch.variable), var_type)
+        m = c.member
+        with writer.if_block(check, not first, False) as block:
+            t = m.member_type
+            if switch.has_end_attr():
+                dest2 = dest.child_at_end(writer, m.member_type)
+            elif switch.has_attr("anon"):
+                dest2 = dest
+            else:
+                if t.is_struct():
+                    dest2 = dest.child_sub(switch.name + "." + m.name)
+                else:
+                    dest2 = dest.child_sub(switch.name)
+            dest2.reuse_scope = block
+
+            if t.is_struct():
+                write_container_parser(writer, t, dest2)
+            elif t.is_pointer():
+                write_parse_pointer(writer, t, False, dest2, m.name, not m.has_attr("ptr32"), block)
+            elif t.is_primitive():
+                writer.assign(dest2.get_ref(m.name), "consume_%s(&in)" % (t.primitive_type()))
+                #TODO validate e.g. flags and enums
+            elif t.is_array():
+                nelements = read_array_len(writer, m.name, t, dest, block)
+                write_array_parser(writer, nelements, t, dest, block)
+            else:
+                writer.todo("Can't handle type %s" % m.member_type)
+
+        first = False
+
+    writer.newline()
+
+    if switch.has_attr("fixedsize"):
+        writer.assign("in", "in_save + %s" % switch.get_fixed_nw_size())
+
+def write_parse_ptr_function(writer, target_type):
+    if target_type.is_array():
+        parse_function = "parse_array_%s" % target_type.element_type.primitive_type()
+    else:
+        parse_function = "parse_struct_%s" % target_type.c_type()
+    if writer.is_generated("parser", parse_function):
+        return parse_function
+
+    writer.set_is_generated("parser", parse_function)
+
+    writer = writer.function_helper()
+    scope = writer.function(parse_function, "uint8_t *", "uint8_t *message_start, uint8_t *message_end, uint8_t *struct_data, PointerInfo *this_ptr_info, int minor")
+    scope.variable_def("uint8_t *", "in = message_start + this_ptr_info->offset")
+    scope.variable_def("uint8_t *", "end")
+
+    num_pointers = target_type.get_num_pointers()
+    if  num_pointers != 0:
+        scope.variable_def("SPICE_GNUC_UNUSED intptr_t", "ptr_size");
+        scope.variable_def("uint32_t", "n_ptr=0");
+        scope.variable_def("PointerInfo", "ptr_info[%s]" % num_pointers)
+
+    writer.newline()
+    if target_type.is_array():
+        writer.assign("end", "struct_data")
+    else:
+        writer.assign("end", "struct_data + %s" % (target_type.sizeof()))
+
+    dest = RootDemarshallingDestination(None, target_type.c_type(), target_type.sizeof(), "struct_data")
+    dest.is_helper = True
+    dest.reuse_scope = scope
+    if target_type.is_array():
+        write_array_parser(writer, "this_ptr_info->nelements", target_type, dest, scope)
+    else:
+        write_container_parser(writer, target_type, dest)
+
+    if num_pointers != 0:
+        write_ptr_info_check(writer)
+
+    writer.statement("return end")
+
+    if writer.has_error_check:
+        writer.newline()
+        writer.label("error")
+        writer.statement("return NULL")
+
+    writer.end_block()
+
+    return parse_function
+
+def write_array_parser(writer, nelements, array, dest, scope):
+    is_byte_size = array.is_bytes_length()
+
+    element_type = array.element_type
+    if element_type == ptypes.uint8 or element_type == ptypes.int8:
+        writer.statement("memcpy(end, in, %s)" % (nelements))
+        writer.increment("in", nelements)
+        writer.increment("end", nelements)
+    else:
+        if is_byte_size:
+            scope.variable_def("uint8_t *", "array_end")
+            writer.assign("array_end", "end + %s" % nelements)
+        with writer.index(no_block = is_byte_size) as index:
+            with writer.while_loop("end < array_end") if is_byte_size else writer.for_loop(index, nelements) as array_scope:
+                if element_type.is_primitive():
+                    writer.statement("*(%s *)end = consume_%s(&in)" % (element_type.c_type(), element_type.primitive_type()))
+                    writer.increment("end", element_type.sizeof())
+                else:
+                    dest2 = dest.child_at_end(writer, element_type)
+                    dest2.reuse_scope = array_scope
+                    write_container_parser(writer, element_type, dest2)
+
+def write_parse_pointer(writer, t, at_end, dest, member_name, is_64bit, scope):
+        target_type = t.target_type
+        if is_64bit:
+            writer.assign("ptr_info[n_ptr].offset", "consume_uint64(&in)")
+        else:
+            writer.assign("ptr_info[n_ptr].offset", "consume_uint32(&in)")
+        writer.assign("ptr_info[n_ptr].parse", write_parse_ptr_function(writer, target_type))
+        if at_end:
+            writer.assign("ptr_info[n_ptr].dest", "end")
+            writer.increment("end", "sizeof(SPICE_ADDRESS)");
+        else:
+            writer.assign("ptr_info[n_ptr].dest", "&%s" % dest.get_ref(member_name))
+        if target_type.is_array():
+            nelements = read_array_len(writer, member_name, target_type, dest, scope)
+            writer.assign("ptr_info[n_ptr].nelements", nelements)
+
+        writer.statement("n_ptr++")
+
+def write_member_parser(writer, container, member, dest, scope):
+    if member.is_switch():
+        write_switch_parser(writer, container, member, dest, scope)
+        return
+
+    t = member.member_type
+
+    if t.is_pointer():
+        if member.has_attr("nocopy"):
+            writer.comment("Reuse data from network message").newline()
+            writer.assign(dest.get_ref(member.name), "(size_t)(message_start + consume_uint64(&in))")
+        else:
+            write_parse_pointer(writer, t, member.has_end_attr(), dest, member.name, not member.has_attr("ptr32"), scope)
+    elif t.is_primitive():
+        if member.has_end_attr():
+            writer.statement("*(%s *)end = consume_%s(&in)" % (t.c_type(), t.primitive_type()))
+            writer.increment("end", t.sizeof())
+        else:
+            writer.assign(dest.get_ref(member.name), "consume_%s(&in)" % (t.primitive_type()))
+        #TODO validate e.g. flags and enums
+    elif t.is_array():
+        nelements = read_array_len(writer, member.name, t, dest, scope, handles_bytes = True)
+        write_array_parser(writer, nelements, t, dest, scope)
+    elif t.is_struct():
+        if member.has_end_attr():
+            dest2 = dest.child_at_end(writer, t)
+        else:
+            dest2 = dest.child_sub(member.name)
+        writer.comment(member.name)
+        write_container_parser(writer, t, dest2)
+    else:
+        raise NotImplementedError("TODO can't handle parsing of %s" % t)
+
+def write_container_parser(writer, container, dest):
+    with dest.declare(writer) as scope:
+        for m in container.members:
+            if m.has_minor_attr():
+                writer.begin_block("if (minor >= %s)" % m.get_minor_attr())
+            write_member_parser(writer, container, m, dest, scope)
+            if m.has_minor_attr():
+                # We need to zero out the fixed part of all optional fields
+                if not m.member_type.is_array():
+                    writer.end_block(newline=False)
+                    writer.begin_block(" else")
+                    # TODO: This is not right for fields that don't exist in the struct
+                    if m.member_type.is_primitive():
+                        writer.assign(dest.get_ref(m.name), "0")
+                    elif m.is_fixed_sizeof():
+                        writer.statement("memset ((char *)&%s, 0, %s)" % (dest.get_ref(m.name), m.sizeof()))
+                    else:
+                        raise NotImplementedError("TODO Clear optional dynamic fields")
+                writer.end_block()
+
+def write_ptr_info_check(writer):
+    writer.newline()
+    with writer.index() as index:
+        with writer.for_loop(index, "n_ptr") as scope:
+            offset = "ptr_info[%s].offset" % index
+            function = "ptr_info[%s].parse" % index
+            dest = "ptr_info[%s].dest" % index
+            with writer.if_block("%s == 0" % offset, newline=False):
+                writer.assign("*%s" % dest, "0")
+            with writer.block(" else"):
+                writer.comment("Align to 32 bit").newline()
+                writer.assign("end", "(uint8_t *)SPICE_ALIGN((size_t)end, 4)")
+                writer.assign("*%s" % dest, "(size_t)end")
+                writer.assign("end", "%s(message_start, message_end, end, &ptr_info[%s], minor)" % (function, index))
+                writer.error_check("end == NULL")
+    writer.newline()
+
+def write_msg_parser(writer, message):
+    msg_name = message.c_name()
+    function_name = "parse_%s" % msg_name
+    if writer.is_generated("demarshaller", function_name):
+        return function_name
+    writer.set_is_generated("demarshaller", function_name)
+
+    msg_type = message.c_type()
+    msg_sizeof = message.sizeof()
+
+    writer.newline()
+    parent_scope = writer.function(function_name,
+                                   "uint8_t *",
+                                   "uint8_t *message_start, uint8_t *message_end, int minor, size_t *size", True)
+    parent_scope.variable_def("SPICE_GNUC_UNUSED uint8_t *", "pos");
+    parent_scope.variable_def("uint8_t *", "start = message_start");
+    parent_scope.variable_def("uint8_t *", "data = NULL");
+    parent_scope.variable_def("size_t", "mem_size", "nw_size");
+    if not message.has_attr("nocopy"):
+        parent_scope.variable_def("uint8_t *", "in", "end");
+    num_pointers = message.get_num_pointers()
+    if  num_pointers != 0:
+        parent_scope.variable_def("SPICE_GNUC_UNUSED intptr_t", "ptr_size");
+        parent_scope.variable_def("uint32_t", "n_ptr=0");
+        parent_scope.variable_def("PointerInfo", "ptr_info[%s]" % num_pointers)
+    writer.newline()
+
+    write_parser_helpers(writer)
+
+    write_validate_container(writer, None, message, "start", parent_scope, True, True, False)
+
+    writer.newline()
+
+    writer.comment("Check if message fits in reported side").newline()
+    with writer.block("if (start + nw_size > message_end)"):
+        writer.statement("return NULL")
+
+    writer.newline().comment("Validated extents and calculated size").newline()
+
+    if message.has_attr("nocopy"):
+        writer.assign("data", "message_start")
+        writer.assign("*size", "message_end - message_start")
+    else:
+        writer.assign("data", "(uint8_t *)malloc(mem_size)")
+        writer.error_check("data == NULL")
+        writer.assign("end", "data + %s" % (msg_sizeof))
+        writer.assign("in", "start").newline()
+
+        dest = RootDemarshallingDestination(None, msg_type, msg_sizeof, "data")
+        dest.reuse_scope = parent_scope
+        write_container_parser(writer, message, dest)
+
+        writer.newline()
+        writer.statement("assert(in <= message_end)")
+
+        if num_pointers != 0:
+            write_ptr_info_check(writer)
+
+        writer.statement("assert(end <= data + mem_size)")
+
+        writer.newline()
+        writer.assign("*size", "end - data")
+
+    writer.statement("return data")
+    writer.newline()
+    if writer.has_error_check:
+        writer.label("error")
+        with writer.block("if (data != NULL)"):
+            writer.statement("free(data)")
+        writer.statement("return NULL")
+    writer.end_block()
+
+    return function_name
+
+def write_channel_parser(writer, channel, server):
+    writer.newline()
+    ids = {}
+    min_id = 1000000
+    if server:
+        messages = channel.server_messages
+    else:
+        messages = channel.client_messages
+    for m in messages:
+        ids[m.value] = m
+
+    ranges = []
+    ids2 = ids.copy()
+    while len(ids2) > 0:
+        end = start = min(ids2.keys())
+        while ids2.has_key(end):
+            del ids2[end]
+            end = end + 1
+
+        ranges.append( (start, end) )
+
+    if server:
+        function_name = "parse_%s_msg" % channel.name
+    else:
+        function_name = "parse_%s_msgc" % channel.name
+    writer.newline()
+    scope = writer.function(function_name,
+                            "uint8_t *",
+                            "uint8_t *message_start, uint8_t *message_end, uint16_t message_type, int minor, size_t *size_out")
+
+    helpers = writer.function_helper()
+
+    d = 0
+    for r in ranges:
+        d = d + 1
+        writer.write("static parse_msg_func_t funcs%d[%d] = " % (d, r[1] - r[0]));
+        writer.begin_block()
+        for i in range(r[0], r[1]):
+            func = write_msg_parser(helpers, ids[i].message_type)
+            writer.write(func)
+            if i != r[1] -1:
+                writer.write(",")
+            writer.newline()
+
+        writer.end_block(semicolon = True)
+
+    d = 0
+    for r in ranges:
+        d = d + 1
+        with writer.if_block("message_type >= %d && message_type < %d" % (r[0], r[1]), d > 1, False):
+            writer.statement("return funcs%d[message_type-%d](message_start, message_end, minor, size_out)" % (d, r[0]))
+    writer.newline()
+
+    writer.statement("return NULL")
+    writer.end_block()
+
+    return function_name
+
+def write_get_channel_parser(writer, channel_parsers, max_channel, is_server):
+    writer.newline()
+    if is_server:
+        function_name = "spice_get_server_channel_parser"
+    else:
+        function_name = "spice_get_client_channel_parser"
+
+    scope = writer.function(function_name,
+                            "spice_parse_channel_func_t",
+                            "uint32_t channel, unsigned int *max_message_type")
+
+    writer.write("static struct {spice_parse_channel_func_t func; unsigned int max_messages; } channels[%d] = " % (max_channel+1))
+    writer.begin_block()
+    for i in range(0, max_channel + 1):
+        writer.write("{ ")
+        if channel_parsers.has_key(i):
+            writer.write(channel_parsers[i][1])
+            writer.write(", ")
+
+            channel = channel_parsers[i][0]
+            max_msg = 0
+            if is_server:
+                messages = channel.server_messages
+            else:
+                messages = channel.client_messages
+            for m in messages:
+                max_msg = max(max_msg, m.value)
+            writer.write(max_msg)
+        else:
+            writer.write("NULL, 0")
+        writer.write("}")
+
+        if i != max_channel:
+            writer.write(",")
+        writer.newline()
+    writer.end_block(semicolon = True)
+
+    with writer.if_block("channel < %d" % (max_channel + 1)):
+        with writer.if_block("max_message_type != NULL"):
+            writer.assign("*max_message_type", "channels[channel].max_messages")
+        writer.statement("return channels[channel].func")
+
+    writer.statement("return NULL")
+    writer.end_block()
+
+
+def write_full_protocol_parser(writer, is_server):
+    writer.newline()
+    if is_server:
+        function_name = "spice_parse_msg"
+    else:
+        function_name = "spice_parse_reply"
+    scope = writer.function(function_name,
+                            "uint8_t *",
+                            "uint8_t *message_start, uint8_t *message_end, uint32_t channel, uint16_t message_type, int minor, size_t *size_out")
+    scope.variable_def("spice_parse_channel_func_t", "func" )
+
+    if is_server:
+        writer.assign("func", "spice_get_server_channel_parser(channel, NULL)")
+    else:
+        writer.assign("func", "spice_get_client_channel_parser(channel, NULL)")
+
+    with writer.if_block("func != NULL"):
+        writer.statement("return func(message_start, message_end, message_type, minor, size_out)")
+
+    writer.statement("return NULL")
+    writer.end_block()
+
+def write_protocol_parser(writer, proto, is_server):
+    max_channel = 0
+    parsers = {}
+
+    for channel in proto.channels:
+        max_channel = max(max_channel, channel.value)
+
+        parsers[channel.value] = (channel.channel_type, write_channel_parser(writer, channel.channel_type, is_server))
+
+    write_get_channel_parser(writer, parsers, max_channel, is_server)
+    write_full_protocol_parser(writer, is_server)
+
+def write_includes(writer):
+    writer.writeln("#include <string.h>")
+    writer.writeln("#include <assert.h>")
+    writer.writeln("#include <stdlib.h>")
+    writer.writeln("#include <stdio.h>")
+    writer.writeln("#include <spice/protocol.h>")
+    writer.writeln("#include <spice/macros.h>")
+    writer.newline()
+    writer.writeln("#ifdef _MSC_VER")
+    writer.writeln("#pragma warning(disable:4101)")
+    writer.writeln("#endif")
diff --git a/python_modules/ptypes.py b/python_modules/ptypes.py
new file mode 100644
index 0000000..fe8a321
--- /dev/null
+++ b/python_modules/ptypes.py
@@ -0,0 +1,965 @@
+import codegen
+import types
+
+_types_by_name = {}
+_types = []
+
+def type_exists(name):
+    return _types_by_name.has_key(name)
+
+def lookup_type(name):
+    return _types_by_name[name]
+
+def get_named_types():
+    return _types
+
+class FixedSize:
+    def __init__(self, val = 0, minor = 0):
+        if isinstance(val, FixedSize):
+            self.vals = val.vals
+        else:
+            self.vals = [0] * (minor + 1)
+            self.vals[minor] = val
+
+    def __add__(self, other):
+        if isinstance(other, types.IntType):
+            other = FixedSize(other)
+
+        new = FixedSize()
+        l = max(len(self.vals), len(other.vals))
+        shared = min(len(self.vals), len(other.vals))
+
+        new.vals = [0] * l
+
+        for i in range(shared):
+            new.vals[i] = self.vals[i] + other.vals[i]
+
+        for i in range(shared,len(self.vals)):
+            new.vals[i] = self.vals[i];
+
+        for i in range(shared,len(other.vals)):
+            new.vals[i] = new.vals[i] + other.vals[i];
+
+        return new
+
+    def __radd__(self, other):
+        return self.__add__(other)
+
+    def __str__(self):
+        s = "%d" % (self.vals[0])
+
+        for i in range(1,len(self.vals)):
+            if self.vals[i] > 0:
+                s = s + " + ((minor >= %d)?%d:0)" % (i, self.vals[i])
+        return s
+
+class Type:
+    def __init__(self):
+        self.attributes = {}
+        self.registred = False
+        self.name = None
+
+    def has_name(self):
+        return self.name != None
+
+    def get_type(self, recursive=False):
+        return self
+
+    def is_primitive(self):
+        return False
+
+    def is_fixed_sizeof(self):
+        return True
+
+    def is_extra_size(self):
+        return False
+
+    def contains_extra_size(self):
+        return False
+
+    def is_fixed_nw_size(self):
+        return True
+
+    def is_array(self):
+        return isinstance(self, ArrayType)
+
+    def is_struct(self):
+        return isinstance(self, StructType)
+
+    def is_pointer(self):
+        return isinstance(self, PointerType)
+
+    def get_num_pointers(self):
+        return 0
+
+    def get_pointer_names(self):
+        return []
+
+    def sizeof(self):
+        return "sizeof(%s)" % (self.c_type())
+
+    def __repr__(self):
+        return self.__str__()
+
+    def __str__(self):
+        if self.name != None:
+            return self.name
+        return "anonymous type"
+
+    def resolve(self):
+        return self
+
+    def register(self):
+        if self.registred or self.name == None:
+            return
+        self.registred = True
+        if _types_by_name.has_key(self.name):
+            raise Exception, "Type %s already defined" % self.name
+        _types.append(self)
+        _types_by_name[self.name] = self
+
+    def has_pointer(self):
+        return False
+
+    def has_attr(self, name):
+        return self.attributes.has_key(name)
+
+class TypeRef(Type):
+    def __init__(self, name):
+        Type.__init__(self)
+        self.name = name
+
+    def __str__(self):
+        return "ref to %s" % (self.name)
+
+    def resolve(self):
+        if not _types_by_name.has_key(self.name):
+            raise Exception, "Unknown type %s" % self.name
+        return _types_by_name[self.name]
+
+    def register(self):
+        assert True, "Can't register TypeRef!"
+
+
+class IntegerType(Type):
+    def __init__(self, bits, signed):
+        Type.__init__(self)
+        self.bits = bits
+        self.signed = signed
+
+        if signed:
+            self.name = "int%d" % bits
+        else:
+            self.name = "uint%d" % bits
+
+    def primitive_type(self):
+        return self.name
+
+    def c_type(self):
+        return self.name + "_t"
+
+    def get_fixed_nw_size(self):
+        return self.bits / 8
+
+    def is_primitive(self):
+        return True
+
+class TypeAlias(Type):
+    def __init__(self, name, the_type, attribute_list):
+        Type.__init__(self)
+        self.name = name
+        self.the_type = the_type
+        for attr in attribute_list:
+            self.attributes[attr[0][1:]] = attr[1:]
+
+    def get_type(self, recursive=False):
+        if recursive:
+            return self.the_type.get_type(True)
+        else:
+            return self.the_type
+
+    def primitive_type(self):
+        return self.the_type.primitive_type()
+
+    def resolve(self):
+        self.the_type = self.the_type.resolve()
+        return self
+
+    def __str__(self):
+        return "alias %s" % self.name
+
+    def is_primitive(self):
+        return self.the_type.is_primitive()
+
+    def is_fixed_sizeof(self):
+        return self.the_type.is_fixed_sizeof()
+
+    def is_fixed_nw_size(self):
+        return self.the_type.is_fixed_nw_size()
+
+    def get_fixed_nw_size(self):
+        return self.the_type.get_fixed_nw_size()
+
+    def get_num_pointers(self):
+        return self.the_type.get_num_pointers()
+
+    def get_pointer_names(self):
+        return self.the_type.get_pointer_names()
+
+    def c_type(self):
+        if self.has_attr("ctype"):
+            return self.attributes["ctype"][0]
+        return self.name
+
+    def has_pointer(self):
+        return self.the_type.has_pointer()
+
+class EnumBaseType(Type):
+    def is_enum(self):
+        return isinstance(self, EnumType)
+
+    def primitive_type(self):
+        return "uint%d" % (self.bits)
+
+    def c_type(self):
+        return "uint%d_t" % (self.bits)
+
+    def c_name(self):
+        return codegen.prefix_camel(self.name)
+
+    def c_enumname(self, value):
+        if self.has_attr("prefix"):
+            return self.attributes["prefix"][0] + self.names[value]
+        return codegen.prefix_underscore_upper(self.name.upper(), self.names[value])
+
+    def c_enumname_by_name(self, name):
+        if self.has_attr("prefix"):
+            return self.attributes["prefix"][0] + self.names[value]
+        return codegen.prefix_underscore_upper(self.name.upper(), name)
+
+    def is_primitive(self):
+        return True
+
+    def get_fixed_nw_size(self):
+        return self.bits / 8
+
+class EnumType(EnumBaseType):
+    def __init__(self, bits, name, enums, attribute_list):
+        Type.__init__(self)
+        self.bits = bits
+        self.name = name
+
+        last = -1
+        names = {}
+        values = {}
+        for v in enums:
+            name = v[0]
+            if len(v) > 1:
+                value = v[1]
+            else:
+                value = last + 1
+            last = value
+
+            assert not names.has_key(value)
+            names[value] = name
+            values[name] = value
+
+        self.names = names
+        self.values = values
+
+        for attr in attribute_list:
+            self.attributes[attr[0][1:]] = attr[1:]
+
+    def __str__(self):
+        return "enum %s" % self.name
+
+    def c_define(self, writer):
+        writer.write("enum ")
+        writer.write(self.c_name())
+        writer.begin_block()
+        values = self.names.keys()
+        values.sort()
+        current_default = 0
+        for i in values:
+            writer.write(self.c_enumname(i))
+            if i != current_default:
+                writer.write(" = %d" % (i))
+            writer.write(",")
+            writer.newline()
+            current_default = i + 1
+        writer.newline()
+        writer.write(codegen.prefix_underscore_upper(self.name.upper(), "ENUM_END"))
+        writer.newline()
+        writer.end_block(semicolon=True)
+        writer.newline()
+
+class FlagsType(EnumBaseType):
+    def __init__(self, bits, name, flags, attribute_list):
+        Type.__init__(self)
+        self.bits = bits
+        self.name = name
+
+        last = -1
+        names = {}
+        values = {}
+        for v in flags:
+            name = v[0]
+            if len(v) > 1:
+                value = v[1]
+            else:
+                value = last + 1
+            last = value
+
+            assert not names.has_key(value)
+            names[value] = name
+            values[name] = value
+
+        self.names = names
+        self.values = values
+
+        for attr in attribute_list:
+            self.attributes[attr[0][1:]] = attr[1:]
+
+    def __str__(self):
+        return "flags %s" % self.name
+
+    def c_define(self, writer):
+        writer.write("enum ")
+        writer.write(self.c_name())
+        writer.begin_block()
+        values = self.names.keys()
+        values.sort()
+        mask = 0
+        for i in values:
+            writer.write(self.c_enumname(i))
+            mask = mask |  (1<<i)
+            writer.write(" = (1 << %d)" % (i))
+            writer.write(",")
+            writer.newline()
+            current_default = i + 1
+        writer.newline()
+        writer.write(codegen.prefix_underscore_upper(self.name.upper(), "MASK"))
+        writer.write(" = 0x%x" % (mask))
+        writer.newline()
+        writer.end_block(semicolon=True)
+        writer.newline()
+
+class ArrayType(Type):
+    def __init__(self, element_type, size):
+        Type.__init__(self)
+        self.name = None
+
+        self.element_type = element_type
+        self.size = size
+
+    def __str__(self):
+        if self.size == None:
+            return "%s[]" % (str(self.element_type))
+        else:
+            return "%s[%s]" % (str(self.element_type), str(self.size))
+
+    def resolve(self):
+        self.element_type = self.element_type.resolve()
+        return self
+
+    def is_constant_length(self):
+        return isinstance(self.size, types.IntType)
+
+    def is_remaining_length(self):
+        return isinstance(self.size, types.StringType) and len(self.size) == 0
+
+    def is_identifier_length(self):
+        return isinstance(self.size, types.StringType) and len(self.size) > 0
+
+    def is_image_size_length(self):
+        if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType):
+            return False
+        return self.size[0] == "image_size"
+
+    def is_bytes_length(self):
+        if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType):
+            return False
+        return self.size[0] == "bytes"
+
+    def is_cstring_length(self):
+        if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType):
+            return False
+        return self.size[0] == "cstring"
+
+    def is_fixed_sizeof(self):
+        return self.is_constant_length() and self.element_type.is_fixed_sizeof()
+
+    def is_fixed_nw_size(self):
+        return self.is_constant_length() and self.element_type.is_fixed_nw_size()
+
+    def get_fixed_nw_size(self):
+        if not self.is_fixed_nw_size():
+            raise Exception, "Not a fixed size type"
+
+        return self.element_type.get_fixed_nw_size() * self.size
+
+    def get_num_pointers(self):
+        element_count = self.element_type.get_num_pointers()
+        if element_count  == 0:
+            return 0
+        if self.is_constant_length(self):
+            return element_count * self.size
+        raise Exception, "Pointers in dynamic arrays not supported"
+
+    def get_pointer_names(self):
+        element_count = self.element_type.get_num_pointers()
+        if element_count  == 0:
+            return []
+        raise Exception, "Pointer names in arrays not supported"
+
+    def contains_extra_size(self):
+        return self.element_type.contains_extra_size()
+
+    def sizeof(self):
+        return "%s * %s" % (self.element_type.sizeof(), self.size)
+
+    def c_type(self):
+        return self.element_type.c_type()
+
+class PointerType(Type):
+    def __init__(self, target_type):
+        Type.__init__(self)
+        self.name = None
+        self.target_type = target_type
+
+    def __str__(self):
+        return "%s*" % (str(self.target_type))
+
+    def resolve(self):
+        self.target_type = self.target_type.resolve()
+        return self
+
+    def get_fixed_size(self):
+        return 8 # offsets are 64bit
+
+    def is_fixed_nw_size(self):
+        return True
+
+    def is_primitive(self):
+        return True
+
+    def primitive_type(self):
+        return "uint64"
+
+    def get_fixed_nw_size(self):
+        return 8
+
+    def c_type(self):
+        return "SPICE_ADDRESS"
+
+    def has_pointer(self):
+        return True
+
+    def contains_extra_size(self):
+        return True
+
+    def get_num_pointers(self):
+        return 1
+
+class Containee:
+    def __init__(self):
+        self.attributes = {}
+
+    def is_switch(self):
+        return False
+
+    def is_pointer(self):
+        return not self.is_switch() and self.member_type.is_pointer()
+
+    def is_array(self):
+        return not self.is_switch() and self.member_type.is_array()
+
+    def is_struct(self):
+        return not self.is_switch() and self.member_type.is_struct()
+
+    def is_primitive(self):
+        return not self.is_switch() and self.member_type.is_primitive()
+
+    def has_attr(self, name):
+        return self.attributes.has_key(name)
+
+    def has_minor_attr(self):
+        return self.has_attr("minor")
+
+    def has_end_attr(self):
+        return self.has_attr("end")
+
+    def get_minor_attr(self):
+        return self.attributes["minor"][0]
+
+class Member(Containee):
+    def __init__(self, name, member_type, attribute_list):
+        Containee.__init__(self)
+        self.name = name
+        self.member_type = member_type
+        for attr in attribute_list:
+            self.attributes[attr[0][1:]] = attr[1:]
+
+    def resolve(self, container):
+        self.container = container
+        self.member_type = self.member_type.resolve()
+        self.member_type.register()
+        return self
+
+    def is_primitive(self):
+        return self.member_type.is_primitive()
+
+    def is_fixed_sizeof(self):
+        if self.has_end_attr():
+            return False
+        return self.member_type.is_fixed_sizeof()
+
+    def is_extra_size(self):
+        return self.has_end_attr()
+
+    def is_fixed_nw_size(self):
+        return self.member_type.is_fixed_nw_size()
+
+    def get_fixed_nw_size(self):
+        size = self.member_type.get_fixed_nw_size()
+        if self.has_minor_attr():
+            minor = self.get_minor_attr()
+            size = FixedSize(size, minor)
+        return size
+
+    def contains_extra_size(self):
+        return self.member_type.contains_extra_size()
+
+    def sizeof(self):
+        return self.member_type.sizeof()
+
+    def __repr__(self):
+        return "%s (%s)" % (str(self.name), str(self.member_type))
+
+    def has_pointer(self):
+        return self.member_type.has_pointer()
+
+    def get_num_pointers(self):
+        return self.member_type.get_num_pointers()
+
+    def get_pointer_names(self):
+        if self.member_type.is_pointer():
+            names = [self.name + "_out"]
+        else:
+            names = self.member_type.get_pointer_names()
+        if self.has_attr("outvar"):
+            prefix = self.attributes["outvar"][0]
+            names = map(lambda name: prefix + "_" + name, names)
+        return names
+
+class SwitchCase:
+    def __init__(self, values, member):
+        self.values = values
+        self.member = member
+        self.members = [member]
+
+    def get_check(self, var_cname, var_type):
+        checks = []
+        for v in self.values:
+            if v == None:
+                return "1"
+            elif var_type.is_enum():
+                checks.append("%s == %s" % (var_cname, var_type.c_enumname_by_name(v)))
+            else:
+                checks.append("(%s & %s)" % (var_cname, var_type.c_enumname_by_name(v)))
+        return " || ".join(checks)
+
+    def resolve(self, container):
+        self.switch = container
+        self.member = self.member.resolve(self)
+        return self
+
+    def has_pointer(self):
+        return self.member.has_pointer()
+
+    def get_num_pointers(self):
+        return self.member.get_num_pointers()
+
+    def get_pointer_names(self):
+        return self.member.get_pointer_names()
+
+class Switch(Containee):
+    def __init__(self, variable, cases, name, attribute_list):
+        Containee.__init__(self)
+        self.variable = variable
+        self.name = name
+        self.cases = cases
+        for attr in attribute_list:
+            self.attributes[attr[0][1:]] = attr[1:]
+
+    def is_switch(self):
+        return True
+
+    def has_switch_member(self, member):
+        for c in self.cases:
+            if c.member == member:
+                return True
+        return False
+
+    def resolve(self, container):
+        self.container = container
+        self.cases = map(lambda c : c.resolve(self), self.cases)
+        return self
+
+    def __repr__(self):
+        return "switch on %s %s" % (str(self.variable),str(self.name))
+
+    def is_fixed_sizeof(self):
+        # Kinda weird, but we're unlikely to have a real struct if there is an @end
+        if self.has_end_attr():
+            return False
+        return True
+
+    def is_fixed_nw_size(self):
+        if self.has_attr("fixedsize"):
+            return True
+
+        size = None
+        for c in self.cases:
+            if not c.member.is_fixed_nw_size():
+                return False
+            if size == None:
+                size = c.member.get_fixed_nw_size()
+            elif size != c.member.get_fixed_nw_size():
+                return False
+        return True
+
+    def is_extra_size(self):
+        return self.has_end_attr()
+
+    def contains_extra_size(self):
+        for c in self.cases:
+            if c.member.is_extra_size():
+                return True
+            if c.member.contains_extra_size():
+                return True
+        return False
+
+    def get_fixed_nw_size(self):
+        if not self.is_fixed_nw_size():
+            raise Exception, "Not a fixed size type"
+        size = 0;
+        for c in self.cases:
+            size = max(size, c.member.get_fixed_nw_size())
+        return size
+
+    def sizeof(self):
+        return "sizeof(((%s *)NULL)->%s)" % (self.container.c_type(),
+                                             self.name)
+
+    def has_pointer(self):
+        for c in self.cases:
+            if c.has_pointer():
+                return True
+        return False
+
+    def get_num_pointers(self):
+        count = 0
+        for c in self.cases:
+            count = max(count, c.get_num_pointers())
+        return count
+
+    def get_pointer_names(self):
+        names = []
+        for c in self.cases:
+            names = names + c.get_pointer_names()
+        return names
+
+class ContainerType(Type):
+    def is_fixed_sizeof(self):
+        for m in self.members:
+            if not m.is_fixed_sizeof():
+                return False
+        return True
+
+    def contains_extra_size(self):
+        for m in self.members:
+            if m.is_extra_size():
+                return True
+            if m.contains_extra_size():
+                return True
+        return False
+
+    def is_fixed_nw_size(self):
+        for i in self.members:
+            if not i.is_fixed_nw_size():
+                return False
+        return True
+
+    def get_fixed_nw_size(self):
+        size = 0
+        for i in self.members:
+            size = size + i.get_fixed_nw_size()
+        return size
+
+    def get_fixed_nw_offset(self, member):
+        size = 0
+        for i in self.members:
+            if i == member:
+                break
+            if i.is_fixed_nw_size():
+                size = size + i.get_fixed_nw_size()
+        return size
+
+    def resolve(self):
+        self.members = map(lambda m : m.resolve(self), self.members)
+        return self
+
+    def get_num_pointers(self):
+        count = 0
+        for m in self.members:
+            count = count + m.get_num_pointers()
+        return count
+
+    def get_pointer_names(self):
+        names = []
+        for m in self.members:
+            names = names + m.get_pointer_names()
+        return names
+
+    def has_pointer(self):
+        for m in self.members:
+            if m.has_pointer():
+                return True
+        return False
+
+    def get_nw_offset(self, member, prefix = "", postfix = ""):
+        fixed = self.get_fixed_nw_offset(member)
+        v = []
+        for m in self.members:
+            if m == member:
+                break
+            if m.is_switch() and m.has_switch_member(member):
+                break
+            if not m.is_fixed_nw_size():
+                v.append(prefix + m.name + postfix)
+        if len(v) > 0:
+            return str(fixed) + " + " + (" + ".join(v))
+        else:
+            return str(fixed)
+
+    def lookup_member(self, name):
+        return self.members_by_name[name]
+
+class StructType(ContainerType):
+    def __init__(self, name, members, attribute_list):
+        Type.__init__(self)
+        self.name = name
+        self.members = members
+        self.members_by_name = {}
+        for m in members:
+            self.members_by_name[m.name] = m
+        for attr in attribute_list:
+            self.attributes[attr[0][1:]] = attr[1:]
+
+    def __str__(self):
+        if self.name == None:
+            return "anonymous struct"
+        else:
+            return "struct %s" % self.name
+
+    def c_type(self):
+        if self.has_attr("ctype"):
+            return self.attributes["ctype"][0]
+        return codegen.prefix_camel(self.name)
+
+class MessageType(ContainerType):
+    def __init__(self, name, members, attribute_list):
+        Type.__init__(self)
+        self.name = name
+        self.members = members
+        self.members_by_name = {}
+        for m in members:
+            self.members_by_name[m.name] = m
+        self.reverse_members = {} # ChannelMembers referencing this message
+        for attr in attribute_list:
+            self.attributes[attr[0][1:]] = attr[1:]
+
+    def __str__(self):
+        if self.name == None:
+            return "anonymous message"
+        else:
+            return "message %s" % self.name
+
+    def c_name(self):
+        if self.name == None:
+            cms = self.reverse_members.keys()
+            if len(cms) != 1:
+                raise "Unknown typename for message"
+            cm = cms[0]
+            channelname = cm.channel.member_name
+            if channelname == None:
+                channelname = ""
+            else:
+                channelname = channelname + "_"
+            if cm.is_server:
+                return "msg_" + channelname +  cm.name
+            else:
+                return "msgc_" + channelname +  cm.name
+        else:
+            return codegen.prefix_camel("Msg", self.name)
+
+    def c_type(self):
+        if self.has_attr("ctype"):
+            return self.attributes["ctype"][0]
+        if self.name == None:
+            cms = self.reverse_members.keys()
+            if len(cms) != 1:
+                raise "Unknown typename for message"
+            cm = cms[0]
+            channelname = cm.channel.member_name
+            if channelname == None:
+                channelname = ""
+            if cm.is_server:
+                return codegen.prefix_camel("Msg", channelname, cm.name)
+            else:
+                return codegen.prefix_camel("Msgc", channelname, cm.name)
+        else:
+            return codegen.prefix_camel("Msg", self.name)
+
+class ChannelMember(Containee):
+    def __init__(self, name, message_type, value):
+        Containee.__init__(self)
+        self.name = name
+        self.message_type = message_type
+        self.value = value
+
+    def resolve(self, channel):
+        self.channel = channel
+        self.message_type = self.message_type.resolve()
+        self.message_type.reverse_members[self] = 1
+
+        return self
+
+    def __repr__(self):
+        return "%s (%s)" % (str(self.name), str(self.message_type))
+
+class ChannelType(Type):
+    def __init__(self, name, base, members):
+        Type.__init__(self)
+        self.name = name
+        self.base = base
+        self.member_name = None
+        self.members = members
+
+    def __str__(self):
+        if self.name == None:
+            return "anonymous channel"
+        else:
+            return "channel %s" % self.name
+
+    def is_fixed_nw_size(self):
+        return False
+
+    def get_client_message(self, name):
+        return self.client_messages_byname[name]
+
+    def get_server_message(self, name):
+        return self.server_messages_byname[name]
+
+    def resolve(self):
+        if self.base != None:
+            self.base = self.base.resolve()
+
+            server_messages = self.base.server_messages[:]
+            server_messages_byname = self.base.server_messages_byname.copy()
+            client_messages = self.base.client_messages[:]
+            client_messages_byname = self.base.client_messages_byname.copy()
+        else:
+            server_messages = []
+            server_messages_byname = {}
+            client_messages = []
+            client_messages_byname = {}
+
+        server_count = 1
+        client_count = 1
+
+        server = True
+        for m in self.members:
+            if m == "server":
+                server = True
+            elif m == "client":
+                server = False
+            elif server:
+                m.is_server = True
+                m = m.resolve(self)
+                if m.value:
+                    server_count = m.value + 1
+                else:
+                    m.value = server_count
+                    server_count = server_count + 1
+                server_messages.append(m)
+                server_messages_byname[m.name] = m
+            else:
+                m.is_server = False
+                m = m.resolve(self)
+                if m.value:
+                    client_count = m.value + 1
+                else:
+                    m.value = client_count
+                    client_count = client_count + 1
+                client_messages.append(m)
+                client_messages_byname[m.name] = m
+
+        self.server_messages = server_messages
+        self.server_messages_byname = server_messages_byname
+        self.client_messages = client_messages
+        self.client_messages_byname = client_messages_byname
+
+        return self
+
+class ProtocolMember:
+    def __init__(self, name, channel_type, value):
+        self.name = name
+        self.channel_type = channel_type
+        self.value = value
+
+    def resolve(self, protocol):
+        self.channel_type = self.channel_type.resolve()
+        assert(self.channel_type.member_name == None)
+        self.channel_type.member_name = self.name
+        return self
+
+    def __repr__(self):
+        return "%s (%s)" % (str(self.name), str(self.channel_type))
+
+class ProtocolType(Type):
+    def __init__(self, name, channels):
+        Type.__init__(self)
+        self.name = name
+        self.channels = channels
+
+    def __str__(self):
+        if self.name == None:
+            return "anonymous protocol"
+        else:
+            return "protocol %s" % self.name
+
+    def is_fixed_nw_size(self):
+        return False
+
+    def resolve(self):
+        count = 1
+        for m in self.channels:
+            m = m.resolve(self)
+            if m.value:
+                count = m.value + 1
+            else:
+                m.value = count
+                count = count + 1
+
+        return self
+
+int8 = IntegerType(8, True)
+uint8 = IntegerType(8, False)
+int16 = IntegerType(16, True)
+uint16 = IntegerType(16, False)
+int32 = IntegerType(32, True)
+uint32 = IntegerType(32, False)
+int64 = IntegerType(64, True)
+uint64 = IntegerType(64, False)
diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py
new file mode 100644
index 0000000..65916b3
--- /dev/null
+++ b/python_modules/spice_parser.py
@@ -0,0 +1,157 @@
+from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \
+        Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \
+        alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith
+
+import ptypes
+import sys
+
+cvtInt = lambda toks: int(toks[0])
+
+def parseVariableDef(toks):
+    t = toks[0][0]
+    pointer = toks[0][1]
+    name = toks[0][2]
+    array_size = toks[0][3]
+    attributes = toks[0][4]
+
+    if array_size != None:
+        t = ptypes.ArrayType(t, array_size)
+
+    if pointer != None:
+        t = ptypes.PointerType(t);
+
+    return ptypes.Member(name, t, attributes)
+
+bnf = None
+def SPICE_BNF():
+    global bnf
+
+    if not bnf:
+
+        # punctuation
+        colon  = Literal(":").suppress()
+        lbrace = Literal("{").suppress()
+        rbrace = Literal("}").suppress()
+        lbrack = Literal("[").suppress()
+        rbrack = Literal("]").suppress()
+        lparen = Literal("(").suppress()
+        rparen = Literal(")").suppress()
+        equals = Literal("=").suppress()
+        comma  = Literal(",").suppress()
+        semi   = Literal(";").suppress()
+
+        # primitive types
+        int8_      = Keyword("int8").setParseAction(replaceWith(ptypes.int8))
+        uint8_     = Keyword("uint8").setParseAction(replaceWith(ptypes.uint8))
+        int16_     = Keyword("int16").setParseAction(replaceWith(ptypes.int16))
+        uint16_    = Keyword("uint16").setParseAction(replaceWith(ptypes.uint16))
+        int32_     = Keyword("int32").setParseAction(replaceWith(ptypes.int32))
+        uint32_    = Keyword("uint32").setParseAction(replaceWith(ptypes.uint32))
+        int64_     = Keyword("int64").setParseAction(replaceWith(ptypes.int64))
+        uint64_    = Keyword("uint64").setParseAction(replaceWith(ptypes.uint64))
+
+        # keywords
+        channel_   = Keyword("channel")
+        enum32_    = Keyword("enum32").setParseAction(replaceWith(32))
+        enum16_    = Keyword("enum16").setParseAction(replaceWith(16))
+        enum8_     = Keyword("enum8").setParseAction(replaceWith(8))
+        flags32_   = Keyword("flags32").setParseAction(replaceWith(32))
+        flags16_   = Keyword("flags16").setParseAction(replaceWith(16))
+        flags8_    = Keyword("flags8").setParseAction(replaceWith(8))
+        channel_   = Keyword("channel")
+        server_    = Keyword("server")
+        client_    = Keyword("client")
+        protocol_  = Keyword("protocol")
+        typedef_   = Keyword("typedef")
+        struct_    = Keyword("struct")
+        message_   = Keyword("message")
+        image_size_ = Keyword("image_size")
+        bytes_     = Keyword("bytes")
+        cstring_   = Keyword("cstring")
+        switch_    = Keyword("switch")
+        default_   = Keyword("default")
+        case_      = Keyword("case")
+
+        identifier = Word( alphas, alphanums + "_" )
+        enumname = Word( alphanums + "_" )
+
+        integer = ( Combine( CaselessLiteral("0x") + Word( nums+"abcdefABCDEF" ) ) |
+                    Word( nums+"+-", nums ) ).setName("int").setParseAction(cvtInt)
+
+        typename = identifier.copy().setParseAction(lambda toks : ptypes.TypeRef(str(toks[0])))
+
+        # This is just normal "types", i.e. not channels or messages
+        typeSpec = Forward()
+
+        attributeValue = integer ^ identifier
+        attribute = Group(Combine ("@" + identifier) + Optional(lparen + delimitedList(attributeValue) + rparen))
+        attributes = Group(ZeroOrMore(attribute))
+        arraySizeSpecImage = Group(image_size_ + lparen + integer + comma + identifier + comma + identifier + rparen)
+        arraySizeSpecBytes = Group(bytes_ + lparen + identifier + rparen)
+        arraySizeSpecCString = Group(cstring_ + lparen + rparen)
+        arraySizeSpec = lbrack + Optional(identifier ^ integer ^ arraySizeSpecImage ^ arraySizeSpecBytes ^arraySizeSpecCString, default="") + rbrack
+        variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \
+            .setParseAction(parseVariableDef)
+
+        switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | case_.suppress() + identifier + colon)) + variableDef) \
+            .setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1]))
+        switchBody = Group(switch_ + lparen + identifier + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \
+            .setParseAction(lambda toks: ptypes.Switch(toks[0][1], toks[0][2], toks[0][3], toks[0][4]))
+        messageBody = structBody = Group(lbrace + ZeroOrMore(variableDef | switchBody)  + rbrace)
+        structSpec = Group(struct_ + identifier + structBody + attributes).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3]))
+
+        # have to use longest match for type, in case a user-defined type name starts with a keyword type, like "channel_type"
+        typeSpec << ( structSpec ^ int8_ ^ uint8_ ^ int16_ ^ uint16_ ^
+                     int32_ ^ uint32_ ^ int64_ ^ uint64_ ^
+                     typename).setName("type")
+
+        flagsBody = enumBody = Group(lbrace + delimitedList(Group (enumname + Optional(equals + integer))) + Optional(comma) + rbrace)
+
+        messageSpec = Group(message_ + messageBody + attributes).setParseAction(lambda toks: ptypes.MessageType(None, toks[0][1], toks[0][2])) | typename
+
+        channelParent = Optional(colon + typename, default=None)
+        channelMessage = Group(messageSpec + identifier + Optional(equals + integer, default=None) + semi) \
+            .setParseAction(lambda toks: ptypes.ChannelMember(toks[0][1], toks[0][0], toks[0][2]))
+        channelBody = channelParent + Group(lbrace + ZeroOrMore( server_ + colon | client_ + colon | channelMessage)  + rbrace)
+
+        enum_ = (enum32_ | enum16_ | enum8_)
+        flags_ = (flags32_ | flags16_ | flags8_)
+        enumDef = Group(enum_ + identifier + enumBody + attributes - semi).setParseAction(lambda toks: ptypes.EnumType(toks[0][0], toks[0][1], toks[0][2], toks[0][3]))
+        flagsDef = Group(flags_ + identifier + flagsBody + attributes  - semi).setParseAction(lambda toks: ptypes.FlagsType(toks[0][0], toks[0][1], toks[0][2], toks[0][3]))
+        messageDef = Group(message_ + identifier + messageBody + attributes - semi).setParseAction(lambda toks: ptypes.MessageType(toks[0][1], toks[0][2], toks[0][3]))
+        channelDef = Group(channel_ + identifier + channelBody - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3]))
+        structDef = Group(struct_ + identifier + structBody + attributes - semi).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3]))
+        typedefDef = Group(typedef_ + identifier  + typeSpec + attributes - semi).setParseAction(lambda toks: ptypes.TypeAlias(toks[0][1], toks[0][2], toks[0][3]))
+
+        definitions = typedefDef | structDef | enumDef | flagsDef | messageDef | channelDef
+
+        protocolChannel = Group(typename + identifier +  Optional(equals + integer, default=None) + semi) \
+            .setParseAction(lambda toks: ptypes.ProtocolMember(toks[0][1], toks[0][0], toks[0][2]))
+        protocolDef = Group(protocol_ + identifier + Group(lbrace + ZeroOrMore(protocolChannel) + rbrace) + semi) \
+            .setParseAction(lambda toks: ptypes.ProtocolType(toks[0][1], toks[0][2]))
+
+        bnf = ZeroOrMore (definitions) +  protocolDef + StringEnd()
+
+        singleLineComment = "//" + restOfLine
+        bnf.ignore( singleLineComment )
+        bnf.ignore( cStyleComment )
+
+    return bnf
+
+
+def parse(filename):
+    try:
+        bnf = SPICE_BNF()
+        types = bnf.parseFile(filename)
+    except ParseException, err:
+        print >> sys.stderr, err.line
+        print >> sys.stderr, " "*(err.column-1) + "^"
+        print >> sys.stderr, err
+        return None
+
+    for t in types:
+        t.resolve()
+        t.register()
+    protocol = types[-1]
+    return protocol
+
diff --git a/spice.proto b/spice.proto
new file mode 100644
index 0000000..dec6a63
--- /dev/null
+++ b/spice.proto
@@ -0,0 +1,1086 @@
+/* built in types:
+   int8, uint8, 16, 32, 64
+*/
+
+typedef fixed28_4 int32 @ctype(SPICE_FIXED28_4);
+
+struct Point {
+    int32 x;
+    int32 y;
+};
+
+struct Point16 {
+    int16 x;
+    int16 y;
+};
+
+struct PointFix {
+    fixed28_4 x;
+    fixed28_4 y;
+};
+
+struct Rect {
+    int32 top;
+    int32 left;
+    int32 bottom;
+    int32 right;
+};
+
+enum32 link_err {
+    OK,
+    ERROR,
+    INVALID_MAGIC,
+    INVALID_DATA,
+    VERSION_MISMATCH,
+    NEED_SECURED,
+    NEED_UNSECURED,
+    PERMISSION_DENIED,
+    BAD_CONNECTION_ID,
+    CHANNEL_NOT_AVAILABLE
+};
+
+enum32 warn_code {
+    WARN_GENERAL
+} @prefix(SPICE_);
+
+enum32 info_code {
+    INFO_GENERAL
+} @prefix(SPICE_);
+
+flags32 migrate_flags {
+    NEED_FLUSH,
+    NEED_DATA_TRANSFER
+} @prefix(SPICE_MIGRATE_);
+
+enum32 notify_severity {
+    INFO,
+    WARN,
+    ERROR,
+};
+
+enum32 notify_visibility {
+    LOW,
+    MEDIUM,
+    HIGH,
+};
+
+flags32 mouse_mode {
+    SERVER,
+    CLIENT,
+};
+
+enum16 pubkey_type {
+    INVALID,
+    RSA,
+    RSA2,
+    DSA,
+    DSA1,
+    DSA2,
+    DSA3,
+    DSA4,
+    DH,
+    EC,
+};
+
+message Empty {
+};
+
+message Data {
+    uint8 data[] @end @ctype(uint8_t);
+} @nocopy;
+
+struct ChannelWait {
+    uint8 channel_type;
+    uint8 channel_id;
+    uint64 message_serial;
+} @ctype(SpiceWaitForChannel);
+
+channel BaseChannel {
+ server:
+    message {
+	migrate_flags flags;
+    } migrate;
+
+    Data migrate_data;
+
+    message {
+	uint32 generation;
+	uint32 window;
+    } set_ack;
+
+    message {
+	uint32 id;
+	uint64 timestamp;
+	uint8 data[] @end @ctype(uint8_t);
+    } ping;
+
+    message {
+	uint8 wait_count;
+	ChannelWait wait_list[wait_count] @end;
+    } wait_for_channels;
+
+    message {
+	uint64 time_stamp;
+	link_err reason;
+    } @ctype(SpiceMsgDisconnect) disconnecting;
+
+    message {
+	uint64 time_stamp;
+	notify_severity severity;
+	notify_visibility visibilty;
+	uint32 what; /* error_code/warn_code/info_code */
+	uint32 message_len;
+	uint8 message[message_len] @end;
+	uint8 zero @end @ctype(uint8_t) @zero;
+    } notify;
+
+ client:
+    message {
+	uint32 generation;
+    } ack_sync;
+
+    Empty ack;
+
+    message {
+	uint32 id;
+	uint64 timestamp;
+    } @ctype(SpiceMsgPing) pong;
+
+    Empty migrate_flush_mark;
+
+    Data migrate_data;
+
+    message {
+    	uint64 time_stamp;
+	link_err reason;
+    } @ctype(SpiceMsgDisconnect) disconnecting;
+};
+
+struct ChannelId {
+    uint8 type;
+    uint8 id;
+};
+
+channel MainChannel : BaseChannel {
+ server:
+     message {
+	uint16 port;
+	uint16 sport;
+    	uint32 host_offset;
+	uint32 host_size;
+	pubkey_type pub_key_type @minor(2);
+	uint32 pub_key_offset @minor(2);
+	uint32 pub_key_size @minor(2);
+	uint8 host_data[host_size] @end @ctype(uint8_t) @zero_terminated;
+	uint8 pub_key_data[pub_key_size] @minor(2) @end @ctype(uint8_t) @zero_terminated;
+    } @ctype(SpiceMsgMainMigrationBegin) migrate_begin = 101;
+
+    Empty migrate_cancel;
+
+    message {
+	uint32 session_id;
+	uint32 display_channels_hint;
+	uint32 supported_mouse_modes;
+	uint32 current_mouse_mode;
+	uint32 agent_connected;
+	uint32 agent_tokens;
+	uint32 multi_media_time;
+	uint32 ram_hint;
+    } init;
+
+    message {
+	uint32 num_of_channels;
+	ChannelId channels[num_of_channels] @end;
+    } @ctype(SpiceMsgChannels) channels_list;
+
+    message {
+	mouse_mode supported_modes;
+	mouse_mode current_mode @unique_flag;
+    } mouse_mode;
+
+    message {
+	uint32 time;
+    } @ctype(SpiceMsgMainMultiMediaTime) multi_media_time;
+
+    Empty agent_connected;
+
+    message {
+	link_err error_code;
+    } @ctype(SpiceMsgMainAgentDisconnect) agent_disconnected;
+
+    Data agent_data;
+
+    message {
+	uint32 num_tokens;
+    } @ctype(SpiceMsgMainAgentTokens) agent_token;
+
+    message {
+      uint16 port;
+      uint16 sport;
+      uint32 host_offset;
+      uint32 host_size;
+      uint32 cert_subject_offset;
+      uint32 cert_subject_size;
+      uint8 host_data[host_size] @end @ctype(uint8_t) @zero_terminated;
+      uint8 cert_subject_data[cert_subject_size] @end @ctype(uint8_t) @zero_terminated;
+    } @ctype(SpiceMsgMainMigrationSwitchHost) migrate_switch_host;
+
+ client:
+    message {
+	uint64 cache_size;
+    } @ctype(SpiceMsgcClientInfo) client_info = 101;
+
+    Empty migrate_connected;
+
+    Empty migrate_connect_error;
+
+    Empty attach_channels;
+
+    message {
+	mouse_mode mode;
+    } mouse_mode_request;
+
+    message {
+	uint32 num_tokens;
+    } agent_start;
+
+    Data agent_data;
+
+    message {
+        uint32 num_tokens;
+    } @ctype(SpiceMsgcMainAgentTokens) agent_token;
+};
+
+enum32 clip_type {
+    NONE,
+    RECTS,
+    PATH,
+};
+
+flags32 path_flags { /* TODO: C enum names changes */
+    BEGIN = 0,
+    END = 1,
+    CLOSE = 3,
+    BEZIER = 4,
+} @prefix(SPICE_PATH_);
+
+enum32 video_codec_type {
+    MJPEG = 1,
+};
+
+flags32 stream_flags {
+    TOP_DOWN = 0,
+};
+
+enum32 brush_type {
+    NONE,
+    SOLID,
+    PATTERN,
+};
+
+flags8 mask_flags {
+    INVERS,
+};
+
+enum8 image_type {
+    BITMAP,
+    QUIC,
+    RESERVED,
+    LZ_PLT = 100,
+    LZ_RGB,
+    GLZ_RGB,
+    FROM_CACHE,
+    SURFACE,
+    JPEG,
+    FROM_CACHE_LOSSLESS,
+};
+
+flags8 image_flags {
+    CACHE_ME,
+    HIGH_BITS_SET,
+    CACHE_REPLACE_ME,
+};
+
+enum8 bitmap_fmt {
+    INVALID,
+    1BIT_LE,
+    1BIT_BE,
+    4BIT_LE,
+    4BIT_BE,
+    8BIT /* 8bit indexed mode */,
+    16BIT, /* 0555 mode */
+    24BIT /* 3 byte, brg */,
+    32BIT /* 4 byte, xrgb in little endian format */,
+    RGBA /* 4 byte, argb in little endian format */
+};
+
+flags8 bitmap_flags {
+    PAL_CACHE_ME,
+    PAL_FROM_CACHE,
+    TOP_DOWN,
+};
+
+enum8 image_scale_mode {
+    INTERPOLATE,
+    NEAREST,
+};
+
+flags16 ropd {
+    INVERS_SRC,
+    INVERS_BRUSH,
+    INVERS_DEST,
+    OP_PUT,
+    OP_OR,
+    OP_AND,
+    OP_XOR,
+    OP_BLACKNESS,
+    OP_WHITENESS,
+    OP_INVERS,
+    INVERS_RES,
+};
+
+flags8 line_flags {
+    STYLED = 3,
+    START_WITH_GAP = 2,
+};
+
+enum8 line_cap {
+    ROUND,
+    SQUARE,
+    BUTT,
+};
+
+enum8 line_join {
+    ROUND,
+    BEVEL,
+    MITER,
+};
+
+flags16 string_flags {
+    RASTER_A1,
+    RASTER_A4,
+    RASTER_A8,
+    RASTER_TOP_DOWN,
+};
+
+flags32 surface_flags {
+    PRIMARY
+};
+
+enum32 surface_fmt {
+    INVALID,
+    1_A     = 1,
+    8_A     = 8,
+    16_555  = 16 ,
+    16_565  = 80,
+    32_xRGB = 32,
+    32_ARGB = 96
+};
+
+flags16 alpha_flags {
+    DEST_HAS_ALPHA,
+    SRC_SURFACE_HAS_ALPHA
+};
+
+enum8 resource_type {
+      INVALID,
+      PIXMAP
+} @prefix(SPICE_RES_TYPE_);
+
+struct ClipRects {
+    uint32 num_rects;
+    Rect rects[num_rects] @end;
+};
+
+struct PathSegment {
+    path_flags flags;
+    uint32 count;
+    PointFix points[count] @end;
+}  @ctype(SpicePathSeg);
+
+struct Path {
+    uint32 size;
+    PathSegment segments[bytes(size)] @end;
+};
+
+struct Clip {
+    clip_type type;
+    switch (type) {
+    case NONE:
+        uint64 data @zero;
+      case RECTS:
+        ClipRects *data;
+    case PATH:
+        Path *data;
+    } u @anon;
+};
+
+struct DisplayBase {
+    uint32 surface_id;
+    Rect box;
+    Clip clip;
+} @ctype(SpiceMsgDisplayBase);
+
+struct ResourceID {
+    uint8 type;
+    uint64 id;
+};
+
+struct WaitForChannel {
+    uint8 channel_type;
+    uint8 channel_id;
+    uint64 message_serial;
+};
+
+struct Palette {
+    uint64 unique;
+    uint16 num_ents;
+    uint32 ents[num_ents] @end;
+};
+
+struct BitmapData {
+    bitmap_fmt format;
+    bitmap_flags flags;
+    uint32 x;
+    uint32 y;
+    uint32 stride;
+    switch (flags) {
+    case PAL_FROM_CACHE:
+	uint64 palette;
+    default:
+	Palette *palette;
+    } pal @anon;
+    uint8 *data[image_size(8, stride, y)] @nocopy; /* pointer to array, not array of pointers as in C */
+} @ctype(SpiceBitmap);
+
+struct BinaryData {
+    uint32 data_size;
+    uint8 data[data_size] @end;
+} @ctype(SpiceQUICData);
+
+struct LZPLTData {
+    bitmap_flags flags;
+    uint32 data_size;
+    switch (flags) {
+    case PAL_FROM_CACHE:
+	uint64 palette;
+    default:
+	Palette *palette @nonnull;
+    } pal @anon;
+    uint8 data[data_size] @end;
+};
+
+struct Surface {
+    uint32 surface_id;
+};
+
+struct Image {
+    uint64 id;
+    image_type type;
+    image_flags flags;
+    uint32 width;
+    uint32 height;
+
+    switch (type) {
+    case BITMAP:
+        BitmapData bitmap_data @ctype(SpiceBitmap);
+    case QUIC:
+    case LZ_RGB:
+    case GLZ_RGB:
+    case JPEG:
+        BinaryData binary_data @ctype(SpiceQUICData);
+    case LZ_PLT:
+        LZPLTData lzplt_data @ctype(SpiceLZPLTData);
+    case SURFACE:
+        Surface surface_data;
+    } u @end;
+} @ctype(SpiceImageDescriptor);
+
+struct Pattern {
+    Image *pat @nonnull;
+    Point pos;
+};
+
+struct Brush {
+    brush_type type;
+    switch (type) {
+    case SOLID:
+        uint32 color;
+    case PATTERN:
+        Pattern pattern;
+    } u @fixedsize;
+};
+
+struct QMask {
+    mask_flags flags;
+    Point pos;
+    Image *bitmap;
+};
+
+struct LineAttr {
+    line_flags flags;
+    line_join join_style;
+    line_cap end_style;
+    uint8 style_nseg;
+    fixed28_4 width;
+    fixed28_4 miter_limit;
+    fixed28_4 *style[style_nseg];
+};
+
+struct RasterGlyphA1 {
+    Point render_pos;
+    Point glyph_origin;
+    uint16 width;
+    uint16 height;
+    uint8 data[image_size(1, width, height)] @end;
+} @ctype(SpiceRasterGlyph);
+
+struct RasterGlyphA4 {
+    Point render_pos;
+    Point glyph_origin;
+    uint16 width;
+    uint16 height;
+    uint8 data[image_size(4, width, height)] @end;
+} @ctype(SpiceRasterGlyph);
+
+struct RasterGlyphA8 {
+    Point render_pos;
+    Point glyph_origin;
+    uint16 width;
+    uint16 height;
+    uint8 data[image_size(8, width, height)] @end;
+} @ctype(SpiceRasterGlyph);
+
+struct String {
+    uint16 length;
+    string_flags flags; /* Special: Only one of a1/a4/a8 set */
+    switch (flags) {
+    case RASTER_A1:
+	RasterGlyphA1 glyphs[length] @ctype(SpiceRasterGlyph);
+    case RASTER_A4:
+	RasterGlyphA4 glyphs[length] @ctype(SpiceRasterGlyph);
+    case RASTER_A8:
+	RasterGlyphA8 glyphs[length] @ctype(SpiceRasterGlyph);
+    } u @end;
+};
+
+channel DisplayChannel : BaseChannel {
+ server:
+    message {
+	uint32 x_res;
+	uint32 y_res;
+	uint32 bits;
+    } mode = 101;
+
+    Empty mark;
+    Empty reset;
+    message {
+	DisplayBase base;
+	Point src_pos;
+    } copy_bits;
+
+    message {
+	uint16 count;
+	ResourceID resources[count] @end;
+    } @ctype(SpiceResourceList) inval_list;
+
+    message {
+	uint8 wait_count;
+	WaitForChannel wait_list[wait_count] @end;
+    } @ctype(SpiceMsgWaitForChannels) inval_all_pixmaps;
+
+    message {
+	uint64 id;
+    } @ctype(SpiceMsgDisplayInvalOne) inval_palette;
+
+    Empty inval_all_palettes;
+
+    message {
+	uint32 surface_id;
+	uint32 id;
+	stream_flags flags;
+	video_codec_type codec_type;
+	uint64 stamp;
+	uint32 stream_width;
+	uint32 stream_height;
+	uint32 src_width;
+	uint32 src_height;
+	Rect dest;
+	Clip clip;
+    } stream_create = 122;
+
+    message {
+	uint32 id;
+	uint32 multi_media_time;
+	uint32 data_size;
+	uint32 pad_size;
+	uint8 data[data_size] @end;
+	uint8 padding[pad_size] @end @ctype(uint8_t); /* Uhm, why are we sending padding over network? */
+    } stream_data;
+
+    message {
+	uint32 id;
+	Clip clip;
+    } stream_clip;
+
+    message {
+	uint32 id;
+    } stream_destroy;
+
+    Empty stream_destroy_all;
+
+    message {
+	DisplayBase base;
+	struct Fill {
+	    Brush brush;
+	    uint16 rop_decriptor;
+	    QMask mask;
+	} data;
+    } draw_fill = 302;
+
+    message {
+	DisplayBase base;
+	struct Opaque {
+	    Image *src_bitmap;
+	    Rect src_area;
+	    Brush brush;
+	    ropd rop_decriptor;
+	    image_scale_mode scale_mode;
+	    QMask mask;
+	} data;
+    } draw_opaque;
+
+    message {
+	DisplayBase base;
+	struct Copy {
+	    Image *src_bitmap;
+	    Rect src_area;
+	    ropd rop_decriptor;
+	    image_scale_mode scale_mode;
+	    QMask mask;
+	} data;
+    } draw_copy;
+
+    message {
+	DisplayBase base;
+	struct Blend {
+	    Image *src_bitmap;
+	    Rect src_area;
+	    ropd rop_decriptor;
+	    image_scale_mode scale_mode;
+	    QMask mask;
+	} @ctype(SpiceCopy) data;
+    } draw_blend;
+
+    message {
+	DisplayBase base;
+	struct Blackness {
+	    QMask mask;
+	} data;
+    } draw_blackness;
+
+    message {
+	DisplayBase base;
+	struct Whiteness {
+	    QMask mask;
+	} data;
+    } draw_whiteness;
+
+    message {
+	DisplayBase base;
+	struct Invers {
+	    QMask mask;
+	} data;
+    } draw_invers;
+
+    message {
+	DisplayBase base;
+	struct Rop3 {
+	    Image *src_bitmap;
+	    Rect src_area;
+	    Brush brush;
+	    uint8 rop3;
+	    image_scale_mode scale_mode;
+	    QMask mask;
+	} data;
+    } draw_rop3;
+
+    message {
+	DisplayBase base;
+	struct Stroke {
+	    Path *path;
+	    LineAttr attr;
+	    Brush brush;
+	    uint16 fore_mode;
+	    uint16 back_mode;
+	} data;
+    } draw_stroke;
+
+    message {
+	DisplayBase base;
+	struct Text {
+	    String *str;
+	    Rect back_area;
+	    Brush fore_brush;
+	    Brush back_brush;
+	    uint16 fore_mode;
+	    uint16 back_mode;
+	} data;
+    } draw_text;
+
+    message {
+	DisplayBase base;
+	struct Transparent {
+	    Image *src_bitmap;
+	    Rect src_area;
+	    uint32 src_color;
+	    uint32 true_color;
+	} data;
+    } draw_transparent;
+
+    message {
+	DisplayBase base;
+	struct AlphaBlnd {
+	    alpha_flags alpha_flags;
+	    uint8 alpha;
+	    Image *src_bitmap;
+	    Rect src_area;
+	} data;
+    } draw_alpha_blend;
+
+    message {
+	uint32 surface_id;
+	uint32 width;
+	uint32 height;
+	uint32 format;
+	surface_flags flags;
+    } @ctype(SpiceMsgSurfaceCreate) surface_create;
+
+    message {
+	uint32 surface_id;
+    } @ctype(SpiceMsgSurfaceDestroy) surface_destroy;
+
+ client:
+    message {
+	uint8 pixmap_cache_id;
+	int64 pixmap_cache_size; //in pixels
+	uint8 glz_dictionary_id;
+	int32 glz_dictionary_window_size;  // in pixels
+    } init = 101;
+};
+
+flags32 keyboard_modifier_flags {
+    SCROLL_LOCK,
+    NUM_LOCK,
+    CAPS_LOCK
+};
+
+enum32 mouse_button {
+    INVALID,
+    LEFT,
+    MIDDLE,
+    RIGHT,
+    UP,
+    DOWN,
+};
+
+flags32 mouse_button_mask {
+    LEFT,
+    MIDDLE,
+    RIGHT
+};
+
+channel InputsChannel : BaseChannel {
+ client:
+    message {
+	uint32 code;
+    } @ctype(SpiceMsgcKeyDown) key_down = 101;
+
+    message {
+	uint32 code;
+    } @ctype(SpiceMsgcKeyUp) key_up;
+
+    message {
+	keyboard_modifier_flags modifiers;
+    } @ctype(SpiceMsgcKeyModifiers) key_modifiers;
+
+    message {
+	int32 dx;
+	int32 dy;
+	mouse_button_mask buttons_state;
+    } @ctype(SpiceMsgcMouseMotion) mouse_motion = 111;
+
+    message {
+	uint32 x;
+	uint32 y;
+	mouse_button_mask buttons_state;
+	uint8 display_id;
+    } @ctype(SpiceMsgcMousePosition) mouse_position;
+
+    message {
+	mouse_button button;
+	mouse_button_mask buttons_state;
+    } @ctype(SpiceMsgcMousePress) mouse_press;
+
+    message {
+	mouse_button button;
+	mouse_button_mask buttons_state;
+    } @ctype(SpiceMsgcMouseRelease) mouse_release;
+
+ server:
+    message {
+	keyboard_modifier_flags keyboard_modifiers;
+    } init = 101;
+
+    message {
+	keyboard_modifier_flags modifiers;
+    } key_modifiers;
+
+    Empty mouse_motion_ack = 111;
+};
+
+enum16 cursor_type {
+    ALPHA,
+    MONO,
+    COLOR4,
+    COLOR8,
+    COLOR16,
+    COLOR24,
+    COLOR32,
+};
+
+flags32 cursor_flags {
+    NONE, /* Means no cursor */
+    CACHE_ME,
+    FROM_CACHE,
+};
+
+struct CursorHeader {
+    uint64 unique;
+    cursor_type type;
+    uint16 width;
+    uint16 height;
+    uint16 hot_spot_x;
+    uint16 hot_spot_y;
+};
+
+struct Cursor {
+    cursor_flags flags;
+    CursorHeader header;
+    uint8 data[] @end;
+};
+
+channel CursorChannel : BaseChannel {
+ server:
+    message {
+	Point16 position;
+	uint16 trail_length;
+	uint16 trail_frequency;
+	uint8 visible;
+	Cursor cursor;
+    } init = 101;
+
+    Empty reset;
+
+    message {
+	Point16 position;
+	uint8 visible;
+	Cursor cursor;
+    } set;
+
+    message {
+	Point16 position;
+    } move;
+
+    Empty hide;
+
+    message {
+	uint16 length;
+	uint16 frequency;
+    } trail;
+
+    message {
+	uint64 id;
+    } @ctype(SpiceMsgDisplayInvalOne) inval_one;
+
+    Empty inval_all;
+};
+
+enum32 audio_data_mode {
+    INVALID,
+    RAW,
+    CELT_0_5_1,
+};
+
+enum32 audio_fmt {
+    INVALID,
+    S16,
+};
+
+channel PlaybackChannel : BaseChannel {
+ server:
+    message {
+	uint32 time;
+	uint8 data[] @end;
+    } @ctype(SpiceMsgPlaybackPacket) data = 101;
+
+    message {
+	uint32 time;
+	audio_data_mode mode;
+	uint8 data[] @end;
+    } mode;
+
+    message {
+       uint32 channels;
+       audio_fmt format;
+       uint32 frequency;
+       uint32 time;
+    } start;
+
+    Empty stop;
+};
+
+channel RecordChannel : BaseChannel {
+ server:
+    message {
+	uint32 channels;
+	audio_fmt format;
+	uint32 frequency;
+    } start = 101;
+
+    Empty stop;
+ client:
+    message {
+	uint32 time;
+	uint8 data[] @end;
+    } @ctype(SpiceMsgcRecordPacket) data = 101;
+
+    message {
+	uint32 time;
+	audio_data_mode mode;
+	uint8 data[] @end;
+    } mode;
+
+    message {
+	uint32 time;
+    } start_mark;
+};
+
+enum32 tunnel_service_type {
+    INVALID,
+    GENERIC,
+    IPP,
+};
+
+enum16 tunnel_ip_type {
+    INVALID,
+    IPv4,
+};
+
+struct TunnelIpInfo {
+    tunnel_ip_type type;
+    switch (type) {
+    case IPv4:
+	uint8 ipv4[4] @ctype(uint8_t);
+    } u @end;
+} @ctype(SpiceMsgTunnelIpInfo);
+
+channel TunnelChannel : BaseChannel {
+ server:
+    message {
+	uint16 max_num_of_sockets;
+	uint32 max_socket_data_size;
+    } init = 101;
+
+    message {
+	uint32 service_id;
+	TunnelIpInfo virtual_ip;
+    } service_ip_map;
+
+    message {
+	uint16 connection_id;
+	uint32 service_id;
+	uint32 tokens;
+    } socket_open;
+
+    message {
+	uint16 connection_id;
+    } socket_fin;
+
+    message {
+	uint16 connection_id;
+    } socket_close;
+
+    message {
+	uint16 connection_id;
+	uint8 data[] @end;
+    } socket_data;
+
+    message {
+	uint16 connection_id;
+    } socket_closed_ack;
+
+    message {
+	uint16 connection_id;
+	uint32 num_tokens;
+    } @ctype(SpiceMsgTunnelSocketTokens) socket_token;
+
+ client:
+    message {
+	tunnel_service_type type;
+	uint32 id;
+	uint32 group;
+	uint32 port;
+	uint32 name;
+	uint32 description;
+	switch (type) {
+	case IPP:
+	    TunnelIpInfo ip @ctype(SpiceMsgTunnelIpInfo);
+	} u @end;
+    } @ctype(SpiceMsgcTunnelAddGenericService) service_add = 101;
+
+    message {
+	uint32 id;
+    } @ctype(SpiceMsgcTunnelRemoveService) service_remove;
+
+    message {
+	uint16 connection_id;
+	uint32 tokens;
+    } socket_open_ack;
+
+    message {
+	uint16 connection_id;
+    } socket_open_nack;
+
+    message {
+	uint16 connection_id;
+    } socket_fin;
+
+    message {
+	uint16 connection_id;
+    } socket_closed;
+
+    message {
+	uint16 connection_id;
+    } socket_closed_ack;
+
+    message {
+	uint16 connection_id;
+	uint8 data[] @end;
+    } socket_data;
+
+    message {
+	uint16 connection_id;
+	uint32 num_tokens;
+    } @ctype(SpiceMsgcTunnelSocketTokens) socket_token;
+};
+
+protocol Spice {
+    MainChannel main = 1;
+    DisplayChannel display;
+    InputsChannel inputs;
+    CursorChannel cursor;
+    PlaybackChannel playback;
+    RecordChannel record;
+    TunnelChannel tunnel;
+};
diff --git a/spice_gen.py b/spice_gen.py
new file mode 100755
index 0000000..f897ce8
--- /dev/null
+++ b/spice_gen.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+
+import os
+import sys
+from optparse import OptionParser
+import traceback
+from python_modules import spice_parser
+from python_modules import ptypes
+from python_modules import codegen
+from python_modules import demarshal
+
+def write_channel_enums(writer, channel, client):
+    messages = filter(lambda m : m.channel == channel, \
+                          channel.client_messages if client else channel.server_messages)
+    if len(messages) == 0:
+        return
+    writer.begin_block("enum")
+    i = 0;
+    if client:
+        prefix = [ "MSGC" ]
+    else:
+        prefix = [ "MSG" ]
+    if channel.member_name:
+        prefix.append(channel.member_name.upper())
+    prefix.append(None) # To be replaced with name
+    for m in messages:
+        prefix[-1] = m.name.upper()
+        enum = codegen.prefix_underscore_upper(*prefix)
+        if m.value == i:
+            writer.writeln("%s," % enum)
+            i = i + 1
+        else:
+            writer.writeln("%s = %s," % (enum, m.value))
+            i = m.value + 1
+    if channel.member_name:
+        prefix[-1] = prefix[-2]
+        prefix[-2] = "END"
+        writer.newline()
+        writer.writeln("%s" % (codegen.prefix_underscore_upper(*prefix)))
+    writer.end_block(semicolon=True)
+    writer.newline()
+
+def write_enums(writer):
+    writer.writeln("#ifndef _H_SPICE_ENUMS")
+    writer.writeln("#define _H_SPICE_ENUMS")
+    writer.newline()
+    writer.comment("Generated from %s, don't edit" % writer.options["source"]).newline()
+    writer.newline()
+
+    # Define enums
+    for t in ptypes.get_named_types():
+        if isinstance(t, ptypes.EnumBaseType):
+            t.c_define(writer)
+
+    i = 0;
+    writer.begin_block("enum")
+    for c in proto.channels:
+        enum = codegen.prefix_underscore_upper("CHANNEL", c.name.upper())
+        if c.value == i:
+            writer.writeln("%s," % enum)
+            i = i + 1
+        else:
+            writer.writeln("%s = %s," % (enum, c.value))
+            i = c.value + 1
+    writer.newline()
+    writer.writeln("SPICE_END_CHANNEL")
+    writer.end_block(semicolon=True)
+    writer.newline()
+
+    for c in ptypes.get_named_types():
+        if not isinstance(c, ptypes.ChannelType):
+            continue
+        write_channel_enums(writer, c, False)
+        write_channel_enums(writer, c, True)
+
+    writer.writeln("#endif /* _H_SPICE_ENUMS */")
+
+parser = OptionParser(usage="usage: %prog [options] <protocol_file> <destination file>")
+parser.add_option("-e", "--generate-enums",
+                  action="store_true", dest="generate_enums", default=False,
+                  help="Generate enums")
+parser.add_option("-d", "--generate-demarshallers",
+                  action="store_true", dest="generate_demarshallers", default=False,
+                  help="Generate demarshallers")
+parser.add_option("-a", "--assert-on-error",
+                  action="store_true", dest="assert_on_error", default=False,
+                  help="Assert on error")
+parser.add_option("-p", "--print-error",
+                  action="store_true", dest="print_error", default=False,
+                  help="Print errors")
+parser.add_option("-s", "--server",
+                  action="store_true", dest="server", default=False,
+                  help="Print errors")
+parser.add_option("-c", "--client",
+                  action="store_true", dest="client", default=False,
+                  help="Print errors")
+parser.add_option("-k", "--keep-identical-file",
+                  action="store_true", dest="keep_identical_file", default=False,
+                  help="Print errors")
+parser.add_option("-i", "--include",
+                  dest="include", default=None, metavar="FILE",
+                  help="Include FILE in generated code")
+
+(options, args) = parser.parse_args()
+
+if len(args) == 0:
+    parser.error("No protocol file specified")
+
+if len(args) == 1:
+    parser.error("No destination file specified")
+
+proto_file = args[0]
+dest_file = args[1]
+proto = spice_parser.parse(proto_file)
+
+if proto == None:
+    exit(1)
+
+codegen.set_prefix(proto.name)
+writer = codegen.CodeWriter()
+writer.set_option("source", os.path.basename(proto_file))
+
+if options.assert_on_error:
+    writer.set_option("assert_on_error")
+
+if options.print_error:
+    writer.set_option("print_error")
+
+if options.include:
+    writer.writeln('#include "%s"' % options.include)
+
+if options.generate_enums:
+    write_enums(writer)
+
+if options.generate_demarshallers:
+    if not options.server and not options.client:
+        print >> sys.stderr, "Must specify client and/or server"
+        sys.exit(1)
+    demarshal.write_includes(writer)
+
+    if options.server:
+        demarshal.write_protocol_parser(writer, proto, False)
+    if options.client:
+        demarshal.write_protocol_parser(writer, proto, True)
+
+content = writer.getvalue()
+if options.keep_identical_file:
+    try:
+        f = open(dest_file, 'rb')
+        old_content = f.read()
+        f.close()
+
+        if content == old_content:
+            print "No changes to %s" % dest_file
+            sys.exit(0)
+
+    except IOError:
+        pass
+
+f = open(dest_file, 'wb')
+f.write(content)
+f.close()
+
+print "Wrote %s" % dest_file
+sys.exit(0)
commit aa6b7b5beb4768e2384e21bfd4c1608cc1d39c39
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed May 26 21:43:13 2010 +0200

    Use the correctly spelled enum values from the new generated enums

diff --git a/client/playback_channel.cpp b/client/playback_channel.cpp
index e1aa065..3e8bb46 100644
--- a/client/playback_channel.cpp
+++ b/client/playback_channel.cpp
@@ -147,7 +147,7 @@ PlaybackChannel::PlaybackChannel(RedClient& client, uint32_t id)
     : RedChannel(client, SPICE_CHANNEL_PLAYBACK, id, new PlaybackHandler(*this),
                  Platform::PRIORITY_HIGH)
     , _wave_player (NULL)
-    , _mode (SPICE_AUDIO_DATA_MODE_INVALD)
+    , _mode (SPICE_AUDIO_DATA_MODE_INVALID)
     , _celt_mode (NULL)
     , _celt_decoder (NULL)
     , _playing (false)
diff --git a/client/record_channel.cpp b/client/record_channel.cpp
index 329dced..893cc63 100644
--- a/client/record_channel.cpp
+++ b/client/record_channel.cpp
@@ -68,7 +68,7 @@ public:
 RecordChannel::RecordChannel(RedClient& client, uint32_t id)
     : RedChannel(client, SPICE_CHANNEL_RECORD, id, new RecordHandler(*this))
     , _wave_recorder (NULL)
-    , _mode (SPICE_AUDIO_DATA_MODE_INVALD)
+    , _mode (SPICE_AUDIO_DATA_MODE_INVALID)
     , _celt_mode (NULL)
     , _celt_encoder (NULL)
 {
commit 1ba1ce52ed2b70c9d5671f17e8047c3d548da96a
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Jun 18 16:31:31 2010 +0200

    Use the new enums for keyboard modifier flags

diff --git a/client/inputs_channel.cpp b/client/inputs_channel.cpp
index 21a1412..46fc015 100644
--- a/client/inputs_channel.cpp
+++ b/client/inputs_channel.cpp
@@ -376,15 +376,15 @@ void InputsChannel::set_local_modifiers()
 {
     unsigned int modifiers = 0;
 
-    if (_modifiers & SPICE_SCROLL_LOCK_MODIFIER) {
+    if (_modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK) {
         modifiers |= Platform::SCROLL_LOCK_MODIFIER;
     }
 
-    if (_modifiers & SPICE_NUM_LOCK_MODIFIER) {
+    if (_modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK) {
         modifiers |= Platform::NUM_LOCK_MODIFIER;
     }
 
-    if (_modifiers & SPICE_CAPS_LOCK_MODIFIER) {
+    if (_modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK) {
         modifiers |= Platform::CAPS_LOCK_MODIFIER;
     }
 
diff --git a/server/reds.c b/server/reds.c
index 051fc30..ed5d212 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -2259,16 +2259,18 @@ static void inputs_handle_input(void *opaque, SpiceDataHeader *header)
             break;
         }
         leds = kbd_get_leds(keyboard);
-        if ((modifiers->modifiers & SPICE_SCROLL_LOCK_MODIFIER) !=
-                                                                (leds & SPICE_SCROLL_LOCK_MODIFIER)) {
+        if ((modifiers->modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK) !=
+            (leds & SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK)) {
             kbd_push_scan(keyboard, SCROLL_LOCK_SCAN_CODE);
             kbd_push_scan(keyboard, SCROLL_LOCK_SCAN_CODE | 0x80);
         }
-        if ((modifiers->modifiers & SPICE_NUM_LOCK_MODIFIER) != (leds & SPICE_NUM_LOCK_MODIFIER)) {
+        if ((modifiers->modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK) !=
+            (leds & SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK)) {
             kbd_push_scan(keyboard, NUM_LOCK_SCAN_CODE);
             kbd_push_scan(keyboard, NUM_LOCK_SCAN_CODE | 0x80);
         }
-        if ((modifiers->modifiers & SPICE_CAPS_LOCK_MODIFIER) != (leds & SPICE_CAPS_LOCK_MODIFIER)) {
+        if ((modifiers->modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK) !=
+            (leds & SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK)) {
             kbd_push_scan(keyboard, CAPS_LOCK_SCAN_CODE);
             kbd_push_scan(keyboard, CAPS_LOCK_SCAN_CODE | 0x80);
         }
commit ef8a8dae07f400f2573fc6f507bd98c6815d816e
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed May 26 21:16:25 2010 +0200

    There are multiple line attribute flags enums, use only one

diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index d01d9cd..20113fe 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -1799,10 +1799,10 @@ static void gdi_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, S
     SetMiterLimit(canvas->dc, (FLOAT)fix_to_double(stroke->attr.miter_limit), &old_miter);
 #endif
 
-    if (stroke->attr.flags & SPICE_LINE_ATTR_STYLED) {
+    if (stroke->attr.flags & SPICE_LINE_FLAGS_STYLED) {
         user_style = gdi_get_userstyle(canvas, stroke->attr.style_nseg,
                                        stroke->attr.style,
-                                       !!(stroke->attr.flags & SPICE_LINE_ATTR_STARTGAP));
+                                       !!(stroke->attr.flags & SPICE_LINE_FLAGS_START_WITH_GAP));
         hpen = ExtCreatePen(PS_GEOMETRIC | ps_join | line_cap | PS_USERSTYLE,
                             (uint32_t)fix_to_double(stroke->attr.width),
                             &logbrush, stroke->attr.style_nseg, (DWORD *)user_style);
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index f98c72a..00caf89 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -630,8 +630,8 @@ static void gl_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, Sp
     set_op(canvas, stroke->fore_mode);
     set_brush(canvas, &stroke->brush);
 
-    if (stroke->attr.flags & SPICE_LINE_ATTR_STYLED) {
-        WARN("SPICE_LINE_ATTR_STYLED");
+    if (stroke->attr.flags & SPICE_LINE_FLAGS_STYLED) {
+        WARN("SPICE_LINE_FLAGS_STYLED");
     }
     glc_set_line_width(canvas->glc, fix_to_double(stroke->attr.width));
 
commit 1d1792c217bee2f7aed28cbee60fc170bb56ecae
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Jun 17 11:18:27 2010 +0200

    Add spice_strnlen

diff --git a/common/mem.c b/common/mem.c
index ec274bb..ffb2fa4 100644
--- a/common/mem.c
+++ b/common/mem.c
@@ -28,6 +28,18 @@
 }
 #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;
diff --git a/common/mem.h b/common/mem.h
index 2087760..9b257ad 100644
--- a/common/mem.h
+++ b/common/mem.h
@@ -33,6 +33,8 @@ void *spice_malloc_n_m(size_t n_blocks, size_t n_block_bytes, size_t extra_size)
 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;
 
+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.
  */


More information about the Spice-commits mailing list