Remove codegen

Codegen generates code specific to spice-common submodule. It's not
meant as a generic protocol header or specification. See discussion and
commits about spice-common codegen re-import.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2016-02-26 18:14:33 +01:00
parent 7937915d67
commit 2a6e51c7ee
15 changed files with 2 additions and 6078 deletions

View File

@ -1,18 +1,6 @@
NULL =
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = python_modules spice
codegendir = $(datadir)/spice-protocol
dist_codegen_DATA = \
spice.proto \
spice1.proto \
$(NULL)
dist_codegen_SCRIPTS = \
spice_codegen.py \
$(NULL)
DISTCLEANFILES = *.pyc
SUBDIRS = spice
pkgconfigdir = $(datadir)/pkgconfig
pkgconfig_DATA = spice-protocol.pc

View File

@ -11,7 +11,7 @@ test -z "$srcdir" && srcdir=.
autoreconf --verbose --force --install
)
CONFIGURE_ARGS="--enable-maintainer-mode --enable-code-generator"
CONFIGURE_ARGS="--enable-maintainer-mode"
if [ -z "$NOCONFIGURE" ]; then
echo "Running configure with $CONFIGURE_ARGS $@"

View File

@ -14,25 +14,8 @@ AM_MAINTAINER_MODE
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
dnl Enable generation of enums.h, mainly useful when building from git,
dnl should not be needed for tarball users
AC_ARG_ENABLE([code-generator],
AS_HELP_STRING([--enable-code-generator=@<:@yes/no/auto@:>@],
[Enable checks needed to use the Python code generator @<:@default=auto@:>@]),
[],
[enable_code_generator="auto"])
if test "x$enable_code_generator" != "xno"; then
AS_IF([test "x$enable_code_generator" = "xyes"], modules_required=[1], modules_required=[])
AX_PYTHON_MODULE([six], $modules_required)
AX_PYTHON_MODULE([pyparsing], $modules_required)
AS_IF([test "x${HAVE_PYMOD_SIX}" = "xno"], enable_code_generator="no")
AS_IF([test "x${HAVE_PYMOD_PYPARSING}" = "xno"], enable_code_generator="no")
fi
AM_CONDITIONAL([ENABLE_CODEGEN], [test "x$enable_code_generator" != "xno"])
AC_OUTPUT([
Makefile
spice-protocol.pc
spice/Makefile
python_modules/Makefile
])

View File

@ -1,15 +0,0 @@
NULL =
python_codegendir = $(datadir)/spice-protocol/python_modules
dist_python_codegen_DATA = \
__init__.py \
codegen.py \
demarshal.py \
marshal.py \
ptypes.py \
spice_parser.py \
$(NULL)
DISTCLEANFILES = *.pyc
-include $(top_srcdir)/git.mk

View File

@ -1,380 +0,0 @@
import six
from io 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
self.index_type = 'uint32_t'
def set_option(self, opt, value = True):
self.options[opt] = value
def has_option(self, opt):
return opt in self.options
def set_is_generated(self, kind, name):
if kind not in self.generated:
v = {}
self.generated[kind] = v
else:
v = self.generated[kind]
v[name] = 1
def is_generated(self, kind, name):
if kind not in self.generated:
return False
v = self.generated[kind]
return name in v
def getvalue(self):
strs = [writer.getvalue() for writer in 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.index_type = self.index_type
writer.generated = self.generated
writer.options = self.options
writer.public_prefix = self.public_prefix
return writer
def write(self, s):
# Ensure its a unicode string
if six.PY3:
s = str(s)
else:
s = unicode(s)
if len(s) == 0:
return
if self.at_line_start:
self.out.write(u" " * self.indentation)
self.at_line_start = False
self.out.write(s)
return self
def newline(self):
self.out.write(u"\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.indentation = 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 ifdef(self, name):
indentation = self.indentation
self.indentation = 0;
self.write("#ifdef %s" % (name)).newline()
self.indentation = indentation
def ifdef_else(self, name):
indentation = self.indentation
self.indentation = 0;
self.write("#else /* %s */" % (name)).newline()
self.indentation = indentation
def endif(self, name):
indentation = self.indentation
self.indentation = 0;
self.write("#endif /* %s */" % (name)).newline()
self.indentation = indentation
def add_function_variable(self, ctype, name):
if name in self.function_variables:
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(self.index_type, index)
return index
def push_index(self):
assert self.current_index > 0
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)

File diff suppressed because it is too large Load Diff

View File

@ -1,420 +0,0 @@
from . import ptypes
from . import codegen
def write_includes(writer):
writer.header.writeln("#include <spice/protocol.h>")
writer.header.writeln('#include "common/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 "common/marshaller.h"')
writer.newline()
writer.writeln("#ifdef _MSC_VER")
writer.writeln("#pragma warning(disable:4101)")
writer.writeln("#pragma warning(disable:4018)")
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, containee):
return SubMarshallingSource(self, containee)
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
assert pointer != None
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()
writer.assign(self.base_var, "(%s *)%s" % (self.c_type, self.pointer))
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, containee):
self.reuse_scope = None
self.parent_src = parent_src
self.base_var = parent_src.base_var
self.containee = containee
self.name = containee.name
self.is_helper = False
def get_self_ref(self):
if self.containee.has_attr("to_ptr"):
return "%s" % self.parent_src.get_ref(self.name)
else:
return "&%s" % self.parent_src.get_ref(self.name)
def get_ref(self, member):
if self.containee.has_attr("to_ptr"):
return self.parent_src.get_ref(self.name) + "->" + member
else:
return self.parent_src.get_ref(self.name) + "." + member
def write_marshal_ptr_function(writer, target_type, is_helper=True):
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(False)
names_args = ""
if len(names) > 0:
n = [", SpiceMarshaller **%s_out" % name for name in names]
names_args = "".join(n)
header = writer.header
if is_helper:
writer = writer.function_helper()
writer.header = header
writer.out_prefix = ""
if target_type.is_array():
scope = writer.function(marshal_function, "SPICE_GNUC_UNUSED static void", "SpiceMarshaller *m, %s_t *ptr, unsigned 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 SpiceMarshaller *", "m2")
for n in names:
writer.assign("*%s_out" % n, "NULL")
writer.newline()
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.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 "(unsigned) (%s * %s)" % (width_v, rows_v)
elif bpp == 1:
return "(unsigned) (((%s + 7) / 8 ) * %s)" % (width_v, rows_v)
else:
return "(unsigned) (((%s * %s + 7) / 8 ) * %s)" % (bpp, width_v, rows_v)
elif array.is_bytes_length():
return container_src.get_ref(array.size[2])
else:
raise NotImplementedError("TODO array size type not handled yet: %s" % array)
def write_array_marshaller(writer, 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()
element = "%s__element" % member.name
if not scope.variable_defined(element):
if array.has_attr("ptr_array"):
stars = " **"
else:
stars = " *"
scope.variable_def(element_type.c_type() + stars, element)
element_array = element
if array.has_attr("ptr_array"):
element = "*" + element
writer.assign(element_array, container_src.get_ref(member.name))
if is_byte_size:
size_start_var = "%s__size_start" % member.name
scope.variable_def("size_t", size_start_var)
writer.assign(size_start_var, "spice_marshaller_get_size(m)")
with writer.index() as index:
with writer.for_loop(index, nelements) as array_scope:
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()
writer.statement("%s++" % element_array)
if is_byte_size:
size_var = member.container.lookup_member(array.size[1])
size_var_type = size_var.member_type
var = "%s__ref" % array.size[1]
writer.statement("spice_marshaller_set_%s(m, %s, spice_marshaller_get_size(m) - %s)" % (size_var_type.primitive_type(), var, size_start_var))
def write_pointer_marshaller(writer, member, src):
t = member.member_type
ptr_func = write_marshal_ptr_function(writer, t.target_type)
submarshaller = "spice_marshaller_get_ptr_submarshaller(m, %d)" % (1 if member.get_fixed_nw_size() == 8 else 0)
if member.has_attr("marshall"):
rest_args = ""
if t.target_type.is_array():
rest_args = ", %s" % get_array_size(t.target_type, src)
writer.assign("m2", submarshaller)
if t.has_attr("nonnull"):
writer.statement("%s(m2, %s%s)" % (ptr_func, src.get_ref(member.name), rest_args))
else:
with writer.if_block("%s != NULL" % src.get_ref(member.name)) as block:
writer.statement("%s(m2, %s%s)" % (ptr_func, src.get_ref(member.name), rest_args))
else:
writer.assign("*%s_out" % (writer.out_prefix + member.name), submarshaller)
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_attr("anon"):
if t.is_struct():
src2 = src.child_sub(m)
else:
src2 = src
else:
if t.is_struct():
src2 = src.child_sub(switch).child_sub(m)
else:
src2 = src.child_sub(switch)
src2.reuse_scope = block
if t.is_struct():
write_container_marshaller(writer, t, src2)
elif t.is_pointer():
write_pointer_marshaller(writer, m, src2)
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, m, t, src2, 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("virtual"):
writer.comment("Don't marshall @virtual %s" % member.name).newline()
return
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():
write_pointer_marshaller(writer, member, src)
elif t.is_primitive():
if member.has_attr("zero"):
writer.statement("spice_marshaller_add_%s(m, 0)" % (t.primitive_type()))
if member.has_attr("bytes_count"):
var = "%s__ref" % member.name
scope.variable_def("void *", var)
writer.statement("%s = spice_marshaller_add_%s(m, %s)" % (var, t.primitive_type(), 0))
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, t, src, scope)
elif t.is_struct():
src2 = src.child_sub(member)
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, private):
if message.has_attr("ifdef"):
writer.ifdef(message.attributes["ifdef"][0])
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(False)
names_args = ""
if len(names) > 0:
n = [", SpiceMarshaller **%s_out" % name for name in names]
names_args = "".join(n)
if not private:
writer.header.writeln("void " + function_name + "(SpiceMarshaller *m, %s *msg" % message.c_type() + names_args + ");")
scope = writer.function(function_name,
"static void" if private else "void",
"SPICE_GNUC_UNUSED SpiceMarshaller *m, SPICE_GNUC_UNUSED %s *msg" % message.c_type() + names_args)
scope.variable_def("SPICE_GNUC_UNUSED SpiceMarshaller *", "m2")
for n in names:
writer.assign("*%s_out" % n, "NULL")
# fix warnings about unused variables by not creating body if no members to parse
if any(x.is_fixed_nw_size() for x in message.members):
src = RootMarshallingSource(None, message.c_type(), message.sizeof(), "msg")
src.reuse_scope = scope
write_container_marshaller(writer, message, src)
writer.end_block()
if message.has_attr("ifdef"):
writer.endif(message.attributes["ifdef"][0])
writer.newline()
return function_name
def write_protocol_marshaller(writer, proto, is_server, private_marshallers):
functions = {}
for c in proto.channels:
channel = c.channel_type
if channel.has_attr("ifdef"):
writer.ifdef(channel.attributes["ifdef"][0])
writer.header.ifdef(channel.attributes["ifdef"][0])
if is_server:
messages = channel.client_messages
else:
messages = channel.server_messages
for m in messages:
message = m.message_type
f = write_message_marshaller(writer, message, is_server, private_marshallers)
if channel.has_attr("ifdef") and f not in functions:
functions[f] = channel.attributes["ifdef"][0]
elif message.has_attr("ifdef") and f not in functions:
functions[f] = message.attributes["ifdef"][0]
else:
functions[f] = True
if channel.has_attr("ifdef"):
writer.endif(channel.attributes["ifdef"][0])
writer.header.endif(channel.attributes["ifdef"][0])
if private_marshallers:
scope = writer.function("spice_message_marshallers_get" + writer.public_prefix,
"SpiceMessageMarshallers *",
"void")
writer.writeln("static SpiceMessageMarshallers marshallers = {NULL};").newline()
for f in sorted(functions.keys()):
member = f[len("spice_marshall_"):]
if not member.startswith("msg"):
member = "msg_" + member
if functions[f] != True:
writer.ifdef(functions[f])
writer.assign("marshallers.%s" % member, f)
if functions[f] != True:
writer.endif(functions[f])
writer.newline()
writer.statement("return &marshallers")
writer.end_block()
writer.newline()
def write_trailer(writer):
writer.header.writeln("#endif")

File diff suppressed because it is too large Load Diff

View File

@ -1,163 +0,0 @@
import six
try:
from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \
Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \
alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith
except ImportError:
six.print_("Module pyparsing not found.")
exit(1)
from . 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))
unix_fd_ = Keyword("unix_fd").setParseAction(replaceWith(ptypes.unix_fd))
# keywords
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 + comma + 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 | Group(case_.suppress() + Optional("!", default="") + identifier) + colon)) + variableDef) \
.setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1]))
switchBody = Group(switch_ + lparen + delimitedList(identifier,delim='.', combine=True) + 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_ ^ unix_fd_ ^
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 + attributes - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3], toks[0][4]))
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 as err:
six.print_(err.line, file=sys.stderr)
six.print_(" "*(err.column-1) + "^", file=sys.stderr)
six.print_(err, file=sys.stderr)
return None
for t in types:
t.resolve()
t.register()
protocol = types[-1]
return protocol

View File

@ -1,7 +1,6 @@
prefix=@prefix@
includedir=@includedir@
datadir=${prefix}/share
codegendir=${datadir}/spice-protocol
Name: spice-protocol
Description: SPICE protocol headers

File diff suppressed because it is too large Load Diff

View File

@ -21,28 +21,4 @@ spice_protocol_include_HEADERS = \
vdi_dev.h \
$(NULL)
# Using the python code generator requires some python modules
# which might not be installed on the user computer. Given that
# enums.h is stored in git, and should be up-to-date anyway,
# we can make this part optional
if ENABLE_CODEGEN
MARSHALLERS_DEPS = \
$(top_srcdir)/python_modules/__init__.py \
$(top_srcdir)/python_modules/codegen.py \
$(top_srcdir)/python_modules/demarshal.py \
$(top_srcdir)/python_modules/marshal.py \
$(top_srcdir)/python_modules/ptypes.py \
$(top_srcdir)/python_modules/spice_parser.py \
$(top_srcdir)/spice_codegen.py \
$(NULL)
BUILT_SOURCES = enums.h
# this is going to upset automake distcheck, since we try to write to
# readonly srcdir. To limit the fail chances, rebuild automatically
# enums.h only if the spice.proto has changed.
enums.h: $(top_srcdir)/spice.proto # $(MARSHALLERS_DEPS)
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-enums $< $@ >/dev/null
endif
-include $(top_srcdir)/git.mk

View File

@ -1,943 +0,0 @@
/* 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[] @ctype(uint8_t) @as_ptr(data_len);
} 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 @nomarshal;
uint8 zero @end @ctype(uint8_t) @nomarshal;
} 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;
};
struct DstInfo {
uint16 port;
uint16 sport;
uint32 host_offset @zero;
uint32 host_size;
pubkey_type pub_key_type @minor(1);
uint32 pub_key_offset @minor(1) @zero;
uint32 pub_key_size @minor(1);
uint8 host_data[host_size] @as_ptr @zero_terminated;
uint8 pub_key_data[pub_key_size] @minor(1) @as_ptr @zero_terminated;
} @ctype(SpiceMigrationDstInfo);
channel MainChannel : BaseChannel {
server:
message {
DstInfo dst_info;
} @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 @zero;
uint32 host_size;
uint32 cert_subject_offset @zero;
uint32 cert_subject_size;
uint8 host_data[host_size] @as_ptr @zero_terminated;
uint8 cert_subject_data[cert_subject_size] @as_ptr @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
};
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,
};
flags8 image_flags {
CACHE_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,
};
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 segments_size @bytes_count(num_segments);
PathSegment segments[bytes(segments_size, num_segments)] @ptr_array;
};
struct Clip {
clip_type type;
switch (type) {
case RECTS:
ClipRects *rects @outvar(cliprects);
default:
uint64 data @zero;
} u @anon;
};
struct DisplayBase {
uint32 surface_id @virtual(0);
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_id;
default:
Palette *palette @outvar(bitmap);
} pal @anon;
uint8 *data[image_size(8, stride, y)] @chunk; /* pointer to array, not array of pointers as in C */
} @ctype(SpiceBitmap);
struct BinaryData {
uint32 data_size;
uint8 data[data_size] @nomarshal @chunk;
} @ctype(SpiceQUICData);
struct LZPLTData {
bitmap_flags flags;
uint32 data_size;
switch (flags) {
case PAL_FROM_CACHE:
uint64 palette_id;
default:
Palette *palette @nonnull @outvar(lzplt);
} pal @anon;
uint8 data[data_size] @nomarshal @chunk;
};
struct Image {
struct ImageDescriptor {
uint64 id;
image_type type;
image_flags flags;
uint32 width;
uint32 height;
} descriptor;
switch (descriptor.type) {
case BITMAP:
BitmapData bitmap;
case QUIC:
BinaryData quic;
case LZ_RGB:
case GLZ_RGB:
BinaryData lz_rgb;
case LZ_PLT:
LZPLTData lz_plt;
} u;
};
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 @zero;
line_cap end_style @zero;
uint8 style_nseg;
fixed28_4 width @zero;
fixed28_4 miter_limit @zero;
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) @ptr_array;
case RASTER_A4:
RasterGlyphA4 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array;
case RASTER_A8:
RasterGlyphA8 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array;
} u @anon;
};
struct StreamDataHeader {
uint32 id;
uint32 multi_media_time;
};
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 @virtual(0);
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 {
StreamDataHeader base;
uint32 data_size;
uint32 pad_size @zero;
uint8 data[data_size] @end @nomarshal;
/* Ignore: uint8 padding[pad_size] */
} 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 @outvar(brush);
uint16 rop_descriptor;
QMask mask @outvar(mask);
} data;
} draw_fill = 302;
message {
DisplayBase base;
struct Opaque {
Image *src_bitmap;
Rect src_area;
Brush brush;
ropd rop_descriptor;
image_scale_mode scale_mode;
QMask mask @outvar(mask);
} data;
} draw_opaque;
message {
DisplayBase base;
struct Copy {
Image *src_bitmap;
Rect src_area;
ropd rop_descriptor;
image_scale_mode scale_mode;
QMask mask @outvar(mask);
} data;
} draw_copy;
message {
DisplayBase base;
struct Blend {
Image *src_bitmap;
Rect src_area;
ropd rop_descriptor;
image_scale_mode scale_mode;
QMask mask @outvar(mask);
} @ctype(SpiceCopy) data;
} draw_blend;
message {
DisplayBase base;
struct Blackness {
QMask mask @outvar(mask);
} data;
} draw_blackness;
message {
DisplayBase base;
struct Whiteness {
QMask mask @outvar(mask);
} data;
} draw_whiteness;
message {
DisplayBase base;
struct Invers {
QMask mask @outvar(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 @outvar(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 @outvar(fore_brush);
Brush back_brush @outvar(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 AlphaBlend {
int8 alpha_flags @virtual(0);
uint8 alpha;
Image *src_bitmap;
Rect src_area;
} data;
} draw_alpha_blend;
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[] @as_ptr(data_size);
};
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,
OPUS,
};
enum32 audio_fmt {
INVALID,
S16,
};
channel PlaybackChannel : BaseChannel {
server:
message {
uint32 time;
uint8 data[] @as_ptr(data_size);
} @ctype(SpiceMsgPlaybackPacket) data = 101;
message {
uint32 time;
audio_data_mode mode;
uint8 data[] @as_ptr(data_size);
} 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[] @nomarshal @as_ptr(data_size);
} @ctype(SpiceMsgcRecordPacket) data = 101;
message {
uint32 time;
audio_data_mode mode;
uint8 data[] @as_ptr(data_size);
} mode;
message {
uint32 time;
} start_mark;
};
protocol Spice {
MainChannel main = 1;
DisplayChannel display;
InputsChannel inputs;
CursorChannel cursor;
PlaybackChannel playback;
RecordChannel record;
};

View File

@ -1,275 +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
from python_modules import marshal
import six
def write_channel_enums(writer, channel, client, describe):
messages = list(filter(lambda m : m.channel == channel, \
channel.client_messages if client else channel.server_messages))
if len(messages) == 0:
return
if client:
prefix = [ "MSGC" ]
else:
prefix = [ "MSG" ]
if channel.member_name:
prefix.append(channel.member_name.upper())
if not describe:
writer.begin_block("enum")
else:
writer.begin_block("static const value_string %s_vs[] = " % (codegen.prefix_underscore_lower(*[x.lower() for x in prefix])))
i = 0
prefix.append(None) # To be replaced with name
for m in messages:
prefix[-1] = m.name.upper()
enum = codegen.prefix_underscore_upper(*prefix)
if describe:
writer.writeln("{ %s, \"%s %s\" }," % (enum, "Client" if client else "Server", m.name.upper()))
else:
if m.value == i:
writer.writeln("%s," % enum)
i = i + 1
else:
writer.writeln("%s = %s," % (enum, m.value))
i = m.value + 1
if describe:
writer.writeln("{ 0, NULL }");
else:
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_channel_type_enum(writer, describe=False):
i = 0
if describe:
writer.begin_block("static const value_string channel_types_vs[] =")
else:
writer.begin_block("enum")
for c in proto.channels:
enum = codegen.prefix_underscore_upper("CHANNEL", c.name.upper())
if describe:
writer.writeln("{ %s, \"%s\" }," % (enum, c.name.upper()))
else:
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()
if describe:
writer.writeln("{ 0, NULL }")
else:
writer.writeln("SPICE_END_CHANNEL")
writer.end_block(semicolon=True)
writer.newline()
def write_enums(writer, describe=False):
writer.writeln("#ifndef _H_SPICE_ENUMS")
writer.writeln("#define _H_SPICE_ENUMS")
writer.newline()
# Define enums
for t in ptypes.get_named_types():
if isinstance(t, ptypes.EnumBaseType):
t.c_define(writer)
if describe:
t.c_describe(writer)
write_channel_type_enum(writer)
if (describe):
write_channel_type_enum(writer, True)
for c in ptypes.get_named_types():
if not isinstance(c, ptypes.ChannelType):
continue
write_channel_enums(writer, c, False, False)
if describe:
write_channel_enums(writer, c, False, describe)
write_channel_enums(writer, c, True, False)
if describe:
write_channel_enums(writer, c, True, describe)
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("-w", "--generate-wireshark-dissector",
action="store_true", dest="generate_dissector", default=False,
help="Generate Wireshark dissector definitions")
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("-P", "--private-marshallers",
action="store_true", dest="private_marshallers", default=False,
help="Generate private 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")
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",
action="append", dest="includes", metavar="FILE",
help="Include FILE in generated code")
parser.add_option("--prefix", dest="prefix",
help="set public symbol prefix", default="")
parser.add_option("--ptrsize", dest="ptrsize",
help="set default pointer size", default="4")
(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")
ptypes.default_pointer_size = int(options.ptrsize)
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.header = codegen.CodeWriter()
writer.set_option("source", os.path.basename(proto_file))
license = """/*
Copyright (C) 2013 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/>.
*/
"""
writer.public_prefix = options.prefix
writer.writeln("/* this is a file autogenerated by spice_codegen.py */")
writer.write(license)
writer.header.writeln("/* this is a file autogenerated by spice_codegen.py */")
writer.header.write(license)
if not options.header and not options.generate_enums:
writer.writeln("#ifdef HAVE_CONFIG_H")
writer.writeln("#include <config.h>")
writer.writeln("#endif")
if options.assert_on_error:
writer.set_option("assert_on_error")
if options.print_error:
writer.set_option("print_error")
if options.includes:
for i in options.includes:
writer.header.writeln('#include <%s>' % i)
writer.writeln('#include <%s>' % i)
if options.generate_enums or options.generate_dissector:
write_enums(writer, options.generate_dissector)
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)
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, options.private_marshallers)
if options.client:
marshal.write_protocol_marshaller(writer, proto, True, options.private_marshallers)
if options.struct_marshallers:
for structname in options.struct_marshallers:
t = ptypes.lookup_type(structname)
marshal.write_marshal_ptr_function(writer, t, False)
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')
old_content = f.read()
f.close()
if content == old_content:
six.print_("No changes to %s" % dest_file)
sys.exit(0)
except IOError:
pass
f = open(dest_file, 'wb')
if six.PY3:
f.write(bytes(content, 'UTF-8'))
else:
f.write(content)
f.close()
six.print_("Wrote %s" % dest_file)
sys.exit(0)