signed_24_8 is a signed decimal type which offers a sign bit, 23 bits of integer precision, and 8 bits of decimal precision. This is converted to double on the C API side, as passing through varargs involves an implicit type promotion to double anyway.
Signed-off-by: Daniel Stone <[email protected]> --- src/Makefile.am | 4 ++-- src/connection.c | 33 ++++++++++++++++++++++++++++++++- src/scanner.c | 9 +++++++++ tests/connection-test.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) v2: Fix up broken negative numbers. Add test cases for large and negative numbers. Add test case for too-large numbers to fail in marshalling. diff --git a/src/Makefile.am b/src/Makefile.am index c685885..f93954e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ libwayland_util_la_SOURCES = \ wayland-os.h \ wayland-private.h -libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt +libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm libwayland_server_la_SOURCES = \ wayland-protocol.c \ wayland-server.c \ @@ -26,7 +26,7 @@ libwayland_server_la_SOURCES = \ data-device.c \ event-loop.c -libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt +libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm libwayland_client_la_SOURCES = \ wayland-protocol.c \ wayland-client.c diff --git a/src/connection.c b/src/connection.c index 06cc66f..0369fbe 100644 --- a/src/connection.c +++ b/src/connection.c @@ -22,6 +22,7 @@ #define _GNU_SOURCE +#include <math.h> #include <stdlib.h> #include <stdint.h> #include <string.h> @@ -382,6 +383,8 @@ wl_message_size_extra(const struct wl_message *message) case 'h': extra += sizeof (int); break; + case 'f': + extra += sizeof (double); default: break; } @@ -415,6 +418,7 @@ wl_closure_vmarshal(struct wl_closure *closure, const char **sp, *s; char *extra; int i, count, fd, extra_size, *fd_ptr; + double d; extra_size = wl_message_size_extra(message); count = strlen(message->signature) + 2; @@ -428,6 +432,17 @@ wl_closure_vmarshal(struct wl_closure *closure, for (i = 2; i < count; i++) { switch (message->signature[i - 2]) { + case 'f': + closure->types[i] = &ffi_type_double; + closure->args[i] = p; + if (end - p < 1) + goto err; + d = va_arg(ap, double); + if (fabs(trunc(d)) > (1 << 23) - 1) + goto err; + *p = (int32_t) round(d * 256.0); + p++; + break; case 'u': closure->types[i] = &ffi_type_uint32; closure->args[i] = p; @@ -567,6 +582,8 @@ wl_connection_demarshal(struct wl_connection *connection, unsigned int i, count, extra_space; struct wl_object **object; struct wl_array **array; + int32_t si; + double *d; count = strlen(message->signature) + 2; if (count > ARRAY_LENGTH(closure->types)) { @@ -611,6 +628,15 @@ wl_connection_demarshal(struct wl_connection *connection, closure->types[i] = &ffi_type_sint32; closure->args[i] = p++; break; + case 'f': + closure->types[i] = &ffi_type_double; + si = (int32_t) *p; + p++; + d = (double *) extra; + extra += sizeof *d; + *d = si / 256.0; + closure->args[i] = d; + break; case 's': closure->types[i] = &ffi_type_pointer; length = *p++; @@ -812,6 +838,7 @@ void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send) { union wl_value *value; + int32_t si; int i; struct timespec tp; unsigned int time; @@ -835,8 +862,12 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send) fprintf(stderr, "%u", value->uint32); break; case 'i': - fprintf(stderr, "%d", value->uint32); + si = (int32_t) value->uint32; + fprintf(stderr, "%d", si); break; + case 'f': + si = (int32_t) value->uint32; + fprintf(stderr, "%f", (double) si / 256.0); case 's': fprintf(stderr, "\"%s\"", value->string); break; diff --git a/src/scanner.c b/src/scanner.c index 3fba0ad..9090aad 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -82,6 +82,7 @@ enum arg_type { NEW_ID, INT, UNSIGNED, + SIGNED_24_8, STRING, OBJECT, ARRAY, @@ -296,6 +297,8 @@ start_element(void *data, const char *element_name, const char **atts) arg->type = INT; else if (strcmp(type, "uint") == 0) arg->type = UNSIGNED; + else if (strcmp(type, "signed_24_8") == 0) + arg->type = SIGNED_24_8; else if (strcmp(type, "string") == 0) arg->type = STRING; else if (strcmp(type, "array") == 0) @@ -446,6 +449,9 @@ emit_type(struct arg *a) case UNSIGNED: printf("uint32_t "); break; + case SIGNED_24_8: + printf("double "); + break; case STRING: printf("const char *"); break; @@ -953,6 +959,9 @@ emit_messages(struct wl_list *message_list, case UNSIGNED: printf("u"); break; + case SIGNED_24_8: + printf("f"); + break; case STRING: printf("s"); break; diff --git a/tests/connection-test.c b/tests/connection-test.c index d17a456..11d085b 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -20,6 +20,7 @@ * OF THIS SOFTWARE. */ +#include <math.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> @@ -153,6 +154,7 @@ struct marshal_data { int32_t i; const char *s; int h; + double d; } value; }; @@ -288,6 +290,13 @@ validate_demarshal_h(struct marshal_data *data, } static void +validate_demarshal_d(struct marshal_data *data, + struct wl_object *object, double d) +{ + assert(fabs(data->value.d - d) <= 1.0 / 256.0); +} + +static void demarshal(struct marshal_data *data, const char *format, uint32_t *msg, void (*func)(void)) { @@ -335,6 +344,24 @@ TEST(connection_demarshal) memcpy(&msg[3], data.value.s, msg[2]); demarshal(&data, "s", msg, (void *) validate_demarshal_s); + data.value.d = 5678.1234; + msg[0] = 400200; + msg[1] = 12; + msg[2] = (int32_t) trunc(data.value.d * 256.0); + demarshal(&data, "f", msg, (void *) validate_demarshal_d); + + data.value.d = -90000.2390; + msg[0] = 400200; + msg[1] = 12; + msg[2] = (int32_t) trunc(data.value.d * 256.0); + demarshal(&data, "f", msg, (void *) validate_demarshal_d); + + data.value.d = (1 << 23) - 1 + 0.0941; + msg[0] = 400200; + msg[1] = 12; + msg[2] = (int32_t) trunc(data.value.d * 256.0); + demarshal(&data, "f", msg, (void *) validate_demarshal_d); + release_marshal_data(&data); } @@ -405,6 +432,22 @@ TEST(connection_marshal_demarshal) marshal_demarshal(0, &data, (void *) validate_demarshal_h, 8, "h", data.value.h); + data.value.d = 1234.5678; + marshal_demarshal(0, &data, (void *) validate_demarshal_d, + 12, "f", data.value.d); + + data.value.d = -90000.2390; + marshal_demarshal(0, &data, (void *) validate_demarshal_d, + 12, "f", data.value.d); + + data.value.d = (1 << 23) - 1 + 0.0941; + marshal_demarshal(0, &data, (void *) validate_demarshal_d, + 12, "f", data.value.d); + + data.value.d = (1 << 23); + marshal_demarshal(1, &data, (void *) validate_demarshal_d, + 12, "f", data.value.d); + release_marshal_data(&data); } -- 1.7.10 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
