mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-protocol
synced 2025-12-26 14:18:31 +00:00
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:
parent
7937915d67
commit
2a6e51c7ee
14
Makefile.am
14
Makefile.am
@ -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
|
||||
|
||||
@ -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 $@"
|
||||
|
||||
17
configure.ac
17
configure.ac
@ -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
|
||||
])
|
||||
|
||||
@ -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
|
||||
@ -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
@ -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
@ -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
|
||||
@ -1,7 +1,6 @@
|
||||
prefix=@prefix@
|
||||
includedir=@includedir@
|
||||
datadir=${prefix}/share
|
||||
codegendir=${datadir}/spice-protocol
|
||||
|
||||
Name: spice-protocol
|
||||
Description: SPICE protocol headers
|
||||
|
||||
1414
spice.proto
1414
spice.proto
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
943
spice1.proto
943
spice1.proto
@ -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;
|
||||
};
|
||||
275
spice_codegen.py
275
spice_codegen.py
@ -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)
|
||||
Loading…
Reference in New Issue
Block a user