Demarshal all arguments from protocol buffer
authorKristian Høgsberg <krh@bitplanet.net>
Tue, 7 Sep 2010 21:00:34 +0000 (17:00 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Tue, 7 Sep 2010 21:00:34 +0000 (17:00 -0400)
connection.c

index c09bc13..e9440f0 100644 (file)
@@ -50,13 +50,6 @@ struct wl_closure {
        const struct wl_message *message;
        ffi_type *types[20];
        ffi_cif cif;
-       union {
-               uint32_t uint32;
-               char *string;
-               void *object;
-               uint32_t new_id;
-               struct wl_array *array;
-       } values[20];
        void *args[20];
        uint32_t buffer[64];
 };
@@ -71,6 +64,14 @@ struct wl_connection {
        struct wl_closure closure;
 };
 
+union wl_value {
+       uint32_t uint32;
+       char *string;
+       struct wl_object *object;
+       uint32_t new_id;
+       struct wl_array *array;
+};
+
 static void
 wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
 {
@@ -396,16 +397,42 @@ wl_connection_vmarshal(struct wl_connection *connection,
        wl_connection_write(connection, closure->buffer, size);
 }
 
+static int
+wl_message_size_extra(const struct wl_message *message)
+{
+       int i, extra;
+
+       for (i = 0, extra = 0; message->signature[i]; i++) {
+
+               switch (message->signature[i - 2]) {
+               case 's':
+               case 'o':
+                       extra += sizeof (void *);
+                       break;
+               case 'a':
+                       extra += sizeof (void *) + sizeof (struct wl_array);
+                       break;
+               case 'h':
+                       extra += sizeof (uint32_t);
+               default:
+                       break;
+               }
+       }
+
+       return extra;
+}
+
 struct wl_closure *
 wl_connection_demarshal(struct wl_connection *connection,
                        uint32_t size,
                        struct wl_hash_table *objects,
                        const struct wl_message *message)
 {
-       uint32_t *p, *next, *end, length;
-       char *extra;
-       int i, count;
-       struct wl_object *object;
+       uint32_t *p, *next, *end, length, *uint;
+       char *extra, **s;
+       int i, count, extra_space;
+       struct wl_object **object;
+       struct wl_array **array;
        struct wl_closure *closure = &connection->closure;
 
        count = strlen(message->signature) + 2;
@@ -414,17 +441,15 @@ wl_connection_demarshal(struct wl_connection *connection,
                assert(0);
        }
 
-       if (sizeof closure->buffer < size) {
+       extra_space = wl_message_size_extra(message);
+       if (sizeof closure->buffer < size + extra_space) {
                printf("request too big, should malloc tmp buffer here\n");
                assert(0);
        }
 
        closure->message = message;
        closure->types[0] = &ffi_type_pointer;
-       closure->args[0] =  &closure->values[0];
-
        closure->types[1] = &ffi_type_pointer;
-       closure->args[1] =  &closure->values[1];
 
        wl_connection_copy(connection, closure->buffer, size);
        p = &closure->buffer[2];
@@ -443,7 +468,7 @@ wl_connection_demarshal(struct wl_connection *connection,
                case 'u':
                case 'i':
                        closure->types[i] = &ffi_type_uint32;
-                       closure->values[i].uint32 = *p++;
+                       closure->args[i] = p++;
                        break;
                case 's':
                        closure->types[i] = &ffi_type_pointer;
@@ -458,36 +483,44 @@ wl_connection_demarshal(struct wl_connection *connection,
                                goto err;
                        }
 
+                       s = (char **) extra;
+                       extra += sizeof *s;
+                       closure->args[i] = s;
+
                        if (length == 0) {
-                               closure->values[i].string = NULL;
+                               *s = NULL;
                        } else {
-                               closure->values[i].string = (char *) p;
-                               if (closure->values[i].string[length - 1] != '\0') {
-                                       printf("string not nul-terminated, "
-                                              "message %s(%s)\n",
-                                              message->name,
-                                              message->signature);
-                                       errno = EINVAL;
-                                       goto err;
-                               }
+                               *s = (char *) p;
+                       }
+
+                       if (length > 0 && (*s)[length - 1] != '\0') {
+                               printf("string not nul-terminated, "
+                                      "message %s(%s)\n",
+                                      message->name, message->signature);
+                               errno = EINVAL;
+                               goto err;
                        }
                        p = next;
                        break;
                case 'o':
                        closure->types[i] = &ffi_type_pointer;
-                       object = wl_hash_table_lookup(objects, *p);
-                       if (object == NULL && *p != 0) {
+                       object = (struct wl_object **) extra;
+                       extra += sizeof *object;
+                       closure->args[i] = object;
+
+                       *object = wl_hash_table_lookup(objects, *p);
+                       if (*object == NULL && *p != 0) {
                                printf("unknown object (%d), message %s(%s)\n",
                                       *p, message->name, message->signature);
                                errno = EINVAL;
                                goto err;
                        }
-                       closure->values[i].object = object;
+
                        p++;
                        break;
                case 'n':
                        closure->types[i] = &ffi_type_uint32;
-                       closure->values[i].new_id = *p;
+                       closure->args[i] = p;
                        object = wl_hash_table_lookup(objects, *p);
                        if (object != NULL) {
                                printf("not a new object (%d), "
@@ -511,27 +544,34 @@ wl_connection_demarshal(struct wl_connection *connection,
                                goto err;
                        }
 
-                       closure->values[i].array = (struct wl_array *) extra;
-                       extra += sizeof *closure->values[i].array;
-                       closure->values[i].array->size = length;
-                       closure->values[i].array->alloc = 0;
-                       closure->values[i].array->data = p;
+                       array = (struct wl_array **) extra;
+                       extra += sizeof *array;
+                       closure->args[i] = array;
+
+                       *array = (struct wl_array *) extra;
+                       extra += sizeof **array;
+
+                       (*array)->size = length;
+                       (*array)->alloc = 0;
+                       (*array)->data = p;
                        p = next;
                        break;
                case 'h':
                        closure->types[i] = &ffi_type_uint32;
+
+                       uint = (uint32_t *) extra;
+                       extra += sizeof *uint;
+                       closure->args[i] = uint;
+
                        wl_buffer_copy(&connection->fds_in,
-                                      &closure->values[i].uint32,
-                                      sizeof closure->values[i].uint32);
-                       connection->fds_in.tail +=
-                               sizeof closure->values[i].uint32;
+                                      uint, sizeof *uint);
+                       connection->fds_in.tail += sizeof *uint;
                        break;
                default:
                        printf("unknown type\n");
                        assert(0);
                        break;
                }
-               closure->args[i] = &closure->values[i];
        }
 
        closure->count = i;
@@ -555,8 +595,8 @@ wl_closure_invoke(struct wl_closure *closure,
 {
        int result;
 
-       closure->values[0].object = data;
-       closure->values[1].object = target;
+       closure->args[0] = &data;
+       closure->args[1] = &target;
 
        ffi_call(&closure->cif, func, &result, closure->args);
 }
@@ -564,7 +604,7 @@ wl_closure_invoke(struct wl_closure *closure,
 void
 wl_closure_print(struct wl_closure *closure, struct wl_object *target)
 {
-       struct wl_object *object;
+       union wl_value *value;
        int i;
 
        fprintf(stderr, "%s(%d).%s(",
@@ -574,29 +614,30 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target)
        for (i = 2; i < closure->count; i++) {
                if (i > 2)
                        fprintf(stderr, ", ");
+
+               value = closure->args[i];
                switch (closure->message->signature[i - 2]) {
                case 'u':
-                       fprintf(stderr, "%u", closure->values[i].uint32);
+                       fprintf(stderr, "%u", value->uint32);
                        break;
                case 'i':
-                       fprintf(stderr, "%d", closure->values[i].uint32);
+                       fprintf(stderr, "%d", value->uint32);
                        break;
                case 's':
-                       fprintf(stderr, "\"%s\"", closure->values[i].string);
+                       fprintf(stderr, "\"%s\"", value->string);
                        break;
                case 'o':
-                       object = closure->values[i].object;
-                       fprintf(stderr, "object %u", object ? object->id : 0);
+                       fprintf(stderr, "object %u",
+                               value->object ? value->object->id : 0);
                        break;
                case 'n':
-                       fprintf(stderr, "new id %u",
-                               closure->values[i].uint32);
+                       fprintf(stderr, "new id %u", value->uint32);
                        break;
                case 'a':
                        fprintf(stderr, "array");
                        break;
                case 'h':
-                       fprintf(stderr, "fd %d", closure->values[i].uint32);
+                       fprintf(stderr, "fd %d", value->uint32);
                        break;
                }
        }