|
Packit |
e9ba0d |
/* -*- mode: c; c-file-style: "openbsd" -*- */
|
|
Packit |
e9ba0d |
/*
|
|
Packit |
e9ba0d |
* Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
|
|
Packit |
e9ba0d |
*
|
|
Packit |
e9ba0d |
* Permission to use, copy, modify, and/or distribute this software for any
|
|
Packit |
e9ba0d |
* purpose with or without fee is hereby granted, provided that the above
|
|
Packit |
e9ba0d |
* copyright notice and this permission notice appear in all copies.
|
|
Packit |
e9ba0d |
*
|
|
Packit |
e9ba0d |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
Packit |
e9ba0d |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
Packit |
e9ba0d |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
Packit |
e9ba0d |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
Packit |
e9ba0d |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
Packit |
e9ba0d |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
Packit |
e9ba0d |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
Packit |
e9ba0d |
*/
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
#define MARSHAL_EXPORT
|
|
Packit |
e9ba0d |
#include "marshal.h"
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
#include <stdio.h>
|
|
Packit |
e9ba0d |
#include <stdlib.h>
|
|
Packit |
e9ba0d |
#include <sys/types.h>
|
|
Packit |
e9ba0d |
#include <sys/queue.h>
|
|
Packit |
e9ba0d |
#include <string.h>
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
#include "compat/compat.h"
|
|
Packit |
e9ba0d |
#include "log.h"
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
#include "lldpd-structs.h"
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Stolen from CCAN */
|
|
Packit |
e9ba0d |
#if HAVE_ALIGNOF
|
|
Packit |
e9ba0d |
# define ALIGNOF(t) (__alignof__(t))
|
|
Packit |
e9ba0d |
#else
|
|
Packit |
e9ba0d |
# define ALIGNOF(t) ((sizeof(t) > 1)?((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0):1)
|
|
Packit |
e9ba0d |
#endif
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* A serialized object */
|
|
Packit |
e9ba0d |
struct marshal_serialized {
|
|
Packit |
e9ba0d |
void *orig; /* Original reference. Also enforce alignment. */
|
|
Packit |
e9ba0d |
size_t size;
|
|
Packit |
e9ba0d |
unsigned char object[0];
|
|
Packit |
e9ba0d |
};
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
struct marshal_info marshal_info_string = {
|
|
Packit |
e9ba0d |
.name = "null string",
|
|
Packit |
e9ba0d |
.size = 0,
|
|
Packit |
e9ba0d |
.pointers = {MARSHAL_SUBINFO_NULL},
|
|
Packit |
e9ba0d |
};
|
|
Packit |
e9ba0d |
struct marshal_info marshal_info_fstring = {
|
|
Packit |
e9ba0d |
.name = "fixed string",
|
|
Packit |
e9ba0d |
.size = 0,
|
|
Packit |
e9ba0d |
.pointers = {MARSHAL_SUBINFO_NULL},
|
|
Packit |
e9ba0d |
};
|
|
Packit |
e9ba0d |
struct marshal_info marshal_info_ignore = {
|
|
Packit |
e9ba0d |
.name = "ignored",
|
|
Packit |
e9ba0d |
.size = 0,
|
|
Packit |
e9ba0d |
.pointers = {MARSHAL_SUBINFO_NULL},
|
|
Packit |
e9ba0d |
};
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* List of already seen pointers */
|
|
Packit |
e9ba0d |
struct ref {
|
|
Packit |
e9ba0d |
TAILQ_ENTRY(ref) next;
|
|
Packit |
e9ba0d |
void *pointer;
|
|
Packit |
e9ba0d |
int dummy; /* To renumerate pointers */
|
|
Packit |
e9ba0d |
};
|
|
Packit |
e9ba0d |
TAILQ_HEAD(ref_l, ref);
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Serialize the given object. */
|
|
Packit |
e9ba0d |
ssize_t
|
|
Packit |
e9ba0d |
marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
|
|
Packit |
e9ba0d |
int skip, void *_refs, int osize)
|
|
Packit |
e9ba0d |
{
|
|
Packit |
e9ba0d |
struct ref_l *refs = _refs;
|
|
Packit |
e9ba0d |
struct ref *cref;
|
|
Packit |
e9ba0d |
int size;
|
|
Packit |
e9ba0d |
size_t len;
|
|
Packit |
e9ba0d |
struct marshal_subinfo *current;
|
|
Packit |
e9ba0d |
struct marshal_serialized *new = NULL, *serialized = NULL;
|
|
Packit |
e9ba0d |
int dummy = 1;
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
log_debug("marshal", "start serialization of %s", mi->name);
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Check if we have already serialized this one. */
|
|
Packit |
e9ba0d |
if (!refs) {
|
|
Packit |
e9ba0d |
refs = calloc(1, sizeof(struct ref_l));
|
|
Packit |
e9ba0d |
if (!refs) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "unable to allocate memory for list of references");
|
|
Packit |
e9ba0d |
return -1;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
TAILQ_INIT(refs);
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
TAILQ_FOREACH(cref, refs, next) {
|
|
Packit |
e9ba0d |
if (unserialized == cref->pointer)
|
|
Packit |
e9ba0d |
return 0;
|
|
Packit |
e9ba0d |
/* dummy should be higher than any existing dummy */
|
|
Packit |
e9ba0d |
if (cref->dummy >= dummy) dummy = cref->dummy + 1;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Handle special cases. */
|
|
Packit |
e9ba0d |
size = mi->size;
|
|
Packit |
e9ba0d |
if (!strcmp(mi->name, "null string"))
|
|
Packit |
e9ba0d |
/* We know we can't be called with NULL */
|
|
Packit |
e9ba0d |
size = strlen((char *)unserialized) + 1;
|
|
Packit |
e9ba0d |
else if (!strcmp(mi->name, "fixed string"))
|
|
Packit |
e9ba0d |
size = osize;
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Allocate serialized structure */
|
|
Packit |
e9ba0d |
len = sizeof(struct marshal_serialized) + (skip?0:size);
|
|
Packit |
e9ba0d |
serialized = calloc(1, len);
|
|
Packit |
e9ba0d |
if (!serialized) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "unable to allocate memory to serialize structure %s",
|
|
Packit |
e9ba0d |
mi->name);
|
|
Packit |
e9ba0d |
len = -1;
|
|
Packit |
e9ba0d |
goto marshal_error;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
/* We don't use the original pointer but a dummy one. */
|
|
Packit |
e9ba0d |
serialized->orig = (unsigned char*)NULL + dummy;
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Append the new reference */
|
|
Packit |
e9ba0d |
if (!(cref = calloc(1, sizeof(struct ref)))) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "unable to allocate memory for list of references");
|
|
Packit |
e9ba0d |
free(serialized);
|
|
Packit |
e9ba0d |
len = -1;
|
|
Packit |
e9ba0d |
goto marshal_error;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
cref->pointer = unserialized;
|
|
Packit |
e9ba0d |
cref->dummy = dummy;
|
|
Packit |
e9ba0d |
TAILQ_INSERT_TAIL(refs, cref, next);
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* First, serialize the main structure */
|
|
Packit |
e9ba0d |
if (!skip)
|
|
Packit |
e9ba0d |
memcpy(serialized->object, unserialized, size);
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Then, serialize inner structures */
|
|
Packit |
e9ba0d |
for (current = mi->pointers; current->mi; current++) {
|
|
Packit |
e9ba0d |
size_t sublen;
|
|
Packit |
e9ba0d |
size_t padlen;
|
|
Packit |
e9ba0d |
void *source;
|
|
Packit |
e9ba0d |
void *target = NULL;
|
|
Packit |
e9ba0d |
if (current->kind == ignore) continue;
|
|
Packit |
e9ba0d |
if (current->kind == pointer) {
|
|
Packit |
e9ba0d |
memcpy(&source,
|
|
Packit |
e9ba0d |
(unsigned char *)unserialized + current->offset,
|
|
Packit |
e9ba0d |
sizeof(void *));
|
|
Packit |
e9ba0d |
if (source == NULL) continue;
|
|
Packit |
e9ba0d |
} else
|
|
Packit |
e9ba0d |
source = (void *)((unsigned char *)unserialized + current->offset);
|
|
Packit |
e9ba0d |
if (current->offset2)
|
|
Packit |
e9ba0d |
memcpy(&osize, (unsigned char*)unserialized + current->offset2, sizeof(int));
|
|
Packit |
e9ba0d |
target = NULL;
|
|
Packit |
e9ba0d |
sublen = marshal_serialize_(current->mi,
|
|
Packit |
e9ba0d |
source, &target,
|
|
Packit |
e9ba0d |
current->kind == substruct, refs, osize);
|
|
Packit |
e9ba0d |
if (sublen == -1) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "unable to serialize substructure %s for %s",
|
|
Packit |
e9ba0d |
current->mi->name, mi->name);
|
|
Packit |
e9ba0d |
free(serialized);
|
|
Packit |
e9ba0d |
return -1;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
/* We want to put the renumerated pointer instead of the real one. */
|
|
Packit |
e9ba0d |
if (current->kind == pointer && !skip) {
|
|
Packit |
e9ba0d |
TAILQ_FOREACH(cref, refs, next) {
|
|
Packit |
e9ba0d |
if (source == cref->pointer) {
|
|
Packit |
e9ba0d |
void *fakepointer = (unsigned char*)NULL + cref->dummy;
|
|
Packit |
e9ba0d |
memcpy((unsigned char *)serialized->object + current->offset,
|
|
Packit |
e9ba0d |
&fakepointer, sizeof(void *));
|
|
Packit |
e9ba0d |
break;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
if (sublen == 0) continue; /* This was already serialized */
|
|
Packit |
e9ba0d |
/* Append the result, force alignment to be able to unserialize it */
|
|
Packit |
e9ba0d |
padlen = ALIGNOF(struct marshal_serialized);
|
|
Packit |
e9ba0d |
padlen = (padlen - (len % padlen)) % padlen;
|
|
Packit |
e9ba0d |
new = realloc(serialized, len + padlen + sublen);
|
|
Packit |
e9ba0d |
if (!new) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "unable to allocate more memory to serialize structure %s",
|
|
Packit |
e9ba0d |
mi->name);
|
|
Packit |
e9ba0d |
free(serialized);
|
|
Packit |
e9ba0d |
free(target);
|
|
Packit |
e9ba0d |
len = -1;
|
|
Packit |
e9ba0d |
goto marshal_error;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
memset((unsigned char *)new + len, 0, padlen);
|
|
Packit |
e9ba0d |
memcpy((unsigned char *)new + len + padlen, target, sublen);
|
|
Packit |
e9ba0d |
free(target);
|
|
Packit |
e9ba0d |
len += sublen + padlen;
|
|
Packit |
e9ba0d |
serialized = (struct marshal_serialized *)new;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
serialized->size = len;
|
|
Packit |
e9ba0d |
*input = serialized;
|
|
Packit |
e9ba0d |
marshal_error:
|
|
Packit |
e9ba0d |
if (refs && !_refs) {
|
|
Packit |
e9ba0d |
struct ref *cref, *cref_next;
|
|
Packit |
e9ba0d |
for (cref = TAILQ_FIRST(refs);
|
|
Packit |
e9ba0d |
cref != NULL;
|
|
Packit |
e9ba0d |
cref = cref_next) {
|
|
Packit |
e9ba0d |
cref_next = TAILQ_NEXT(cref, next);
|
|
Packit |
e9ba0d |
TAILQ_REMOVE(refs, cref, next);
|
|
Packit |
e9ba0d |
free(cref);
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
free(refs);
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
return len;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* This structure is used to track memory allocation when serializing */
|
|
Packit |
e9ba0d |
struct gc {
|
|
Packit |
e9ba0d |
TAILQ_ENTRY(gc) next;
|
|
Packit |
e9ba0d |
void *pointer;
|
|
Packit |
e9ba0d |
void *orig; /* Original reference (not valid anymore !) */
|
|
Packit |
e9ba0d |
};
|
|
Packit |
e9ba0d |
TAILQ_HEAD(gc_l, gc);
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
static void*
|
|
Packit |
e9ba0d |
marshal_alloc(struct gc_l *pointers, size_t len, void *orig)
|
|
Packit |
e9ba0d |
{
|
|
Packit |
e9ba0d |
struct gc *gpointer = NULL;
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
void *result = calloc(1, len);
|
|
Packit |
e9ba0d |
if (!result) return NULL;
|
|
Packit |
e9ba0d |
if ((gpointer = (struct gc *)calloc(1,
|
|
Packit |
e9ba0d |
sizeof(struct gc))) == NULL) {
|
|
Packit |
e9ba0d |
free(result);
|
|
Packit |
e9ba0d |
return NULL;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
gpointer->pointer = result;
|
|
Packit |
e9ba0d |
gpointer->orig = orig;
|
|
Packit |
e9ba0d |
TAILQ_INSERT_TAIL(pointers, gpointer, next);
|
|
Packit |
e9ba0d |
return result;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
static void
|
|
Packit |
e9ba0d |
marshal_free(struct gc_l *pointers, int gconly)
|
|
Packit |
e9ba0d |
{
|
|
Packit |
e9ba0d |
struct gc *pointer, *pointer_next;
|
|
Packit |
e9ba0d |
for (pointer = TAILQ_FIRST(pointers);
|
|
Packit |
e9ba0d |
pointer != NULL;
|
|
Packit |
e9ba0d |
pointer = pointer_next) {
|
|
Packit |
e9ba0d |
pointer_next = TAILQ_NEXT(pointer, next);
|
|
Packit |
e9ba0d |
TAILQ_REMOVE(pointers, pointer, next);
|
|
Packit |
e9ba0d |
if (!gconly)
|
|
Packit |
e9ba0d |
free(pointer->pointer);
|
|
Packit |
e9ba0d |
free(pointer);
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Unserialize the given object. */
|
|
Packit |
e9ba0d |
size_t
|
|
Packit |
e9ba0d |
marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **output,
|
|
Packit |
e9ba0d |
void *_pointers, int skip, int osize)
|
|
Packit |
e9ba0d |
{
|
|
Packit |
e9ba0d |
int total_len = sizeof(struct marshal_serialized) + (skip?0:mi->size);
|
|
Packit |
e9ba0d |
struct marshal_serialized *serialized = buffer;
|
|
Packit |
e9ba0d |
struct gc_l *pointers = _pointers;
|
|
Packit |
e9ba0d |
int size, already, extra = 0;
|
|
Packit |
e9ba0d |
void *new;
|
|
Packit |
e9ba0d |
struct marshal_subinfo *current;
|
|
Packit |
e9ba0d |
struct gc *apointer;
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
log_debug("marshal", "start unserialization of %s", mi->name);
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
if (len < sizeof(struct marshal_serialized) || len < total_len) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "data to deserialize is too small (%zu) for structure %s",
|
|
Packit |
e9ba0d |
len, mi->name);
|
|
Packit |
e9ba0d |
return 0;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Initialize garbage collection */
|
|
Packit |
e9ba0d |
if (!pointers) {
|
|
Packit |
e9ba0d |
pointers = calloc(1, sizeof(struct gc_l));
|
|
Packit |
e9ba0d |
if (!pointers) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "unable to allocate memory for garbage collection");
|
|
Packit |
e9ba0d |
return 0;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
TAILQ_INIT(pointers);
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Special cases */
|
|
Packit |
e9ba0d |
size = mi->size;
|
|
Packit |
e9ba0d |
if (!strcmp(mi->name, "null string") || !strcmp(mi->name, "fixed string")) {
|
|
Packit |
e9ba0d |
switch (mi->name[0]) {
|
|
Packit |
e9ba0d |
case 'n': size = strnlen((char *)serialized->object,
|
|
Packit |
e9ba0d |
len - sizeof(struct marshal_serialized)) + 1; break;
|
|
Packit |
e9ba0d |
case 'f': size = osize; extra=1; break; /* The extra byte is to ensure that
|
|
Packit |
e9ba0d |
the string is null terminated. */
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
if (size > len - sizeof(struct marshal_serialized)) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "data to deserialize contains a string too long");
|
|
Packit |
e9ba0d |
total_len = 0;
|
|
Packit |
e9ba0d |
goto unmarshal_error;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
total_len += size;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* First, the main structure */
|
|
Packit |
e9ba0d |
if (!skip) {
|
|
Packit |
e9ba0d |
if ((*output = marshal_alloc(pointers, size + extra, serialized->orig)) == NULL) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "unable to allocate memory to unserialize structure %s",
|
|
Packit |
e9ba0d |
mi->name);
|
|
Packit |
e9ba0d |
total_len = 0;
|
|
Packit |
e9ba0d |
goto unmarshal_error;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
memcpy(*output, serialized->object, size);
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Then, each substructure */
|
|
Packit |
e9ba0d |
for (current = mi->pointers; current->mi; current++) {
|
|
Packit |
e9ba0d |
size_t sublen;
|
|
Packit |
e9ba0d |
size_t padlen;
|
|
Packit |
e9ba0d |
new = (unsigned char *)*output + current->offset;
|
|
Packit |
e9ba0d |
if (current->kind == ignore) {
|
|
Packit |
e9ba0d |
memset((unsigned char *)*output + current->offset,
|
|
Packit |
e9ba0d |
0, sizeof(void *));
|
|
Packit |
e9ba0d |
continue;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
if (current->kind == pointer) {
|
|
Packit |
e9ba0d |
if (*(void **)new == NULL) continue;
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
/* Did we already see this reference? */
|
|
Packit |
e9ba0d |
already = 0;
|
|
Packit |
e9ba0d |
TAILQ_FOREACH(apointer, pointers, next)
|
|
Packit |
e9ba0d |
if (apointer->orig == *(void **)new) {
|
|
Packit |
e9ba0d |
memcpy((unsigned char *)*output + current->offset,
|
|
Packit |
e9ba0d |
&apointer->pointer, sizeof(void *));
|
|
Packit |
e9ba0d |
already = 1;
|
|
Packit |
e9ba0d |
break;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
if (already) continue;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
/* Deserialize */
|
|
Packit |
e9ba0d |
if (current->offset2)
|
|
Packit |
e9ba0d |
memcpy(&osize, (unsigned char *)*output + current->offset2, sizeof(int));
|
|
Packit |
e9ba0d |
padlen = ALIGNOF(struct marshal_serialized);
|
|
Packit |
e9ba0d |
padlen = (padlen - (total_len % padlen)) % padlen;
|
|
Packit |
e9ba0d |
if (len < total_len + padlen || ((sublen = marshal_unserialize_(current->mi,
|
|
Packit |
e9ba0d |
(unsigned char *)buffer + total_len + padlen,
|
|
Packit |
e9ba0d |
len - total_len - padlen, &new, pointers,
|
|
Packit |
e9ba0d |
current->kind == substruct, osize)) == 0)) {
|
|
Packit |
e9ba0d |
log_warnx("marshal", "unable to serialize substructure %s for %s",
|
|
Packit |
e9ba0d |
current->mi->name, mi->name);
|
|
Packit |
e9ba0d |
total_len = 0;
|
|
Packit |
e9ba0d |
goto unmarshal_error;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
/* Link the result */
|
|
Packit |
e9ba0d |
if (current->kind == pointer)
|
|
Packit |
e9ba0d |
memcpy((unsigned char *)*output + current->offset,
|
|
Packit |
e9ba0d |
&new, sizeof(void *));
|
|
Packit |
e9ba0d |
total_len += sublen + padlen;
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
|
|
Packit |
e9ba0d |
unmarshal_error:
|
|
Packit |
e9ba0d |
if (pointers && !_pointers) {
|
|
Packit |
e9ba0d |
marshal_free(pointers, (total_len > 0));
|
|
Packit |
e9ba0d |
free(pointers);
|
|
Packit |
e9ba0d |
}
|
|
Packit |
e9ba0d |
return total_len;
|
|
Packit |
e9ba0d |
}
|