Added arrays of other primitives beyond bytes.
Namespace cleanup.
Exposed data-dump function.
Delete old serialiser.
Implement all changes in xdrn/tagz formats.
CPPFLAGS=-I.
-CFLAGS=-O0 -g -fPIC -Wall -mtune=native
+CFLAGS=-O2 -g -fPIC -Wall -mtune=native
test_LDLIBS=-lpthread -lrt
ARFLAGS=rvsUc
VERSION=2.1.99
ez-blob.c \
ez-blob-io.c \
ez-blob-print.c \
- ez-blob-blob.c \
+ ez-blob-dump.c \
ez-blob-tagz.c \
ez-blob-xdrn.c \
ez-port.c \
ez-bitset.h \
ez-blob.h \
ez-blobio.h \
- ez-blob-blob.h \
ez-blob-tagz.h \
ez-blob-xdrn.h \
ez-list.h \
test-bitset: libeze.a(ez-bitset.o)
test-blob: libeze.a(ez-blob.o) libeze.a(ez-blob-print.o) libeze.a(ez-blob-io.o) \
- libeze.a(ez-blob-xdrn.o) libeze.a(ez-blob-tagz.o) libeze.a(ez-blob-blob.o)
+ libeze.a(ez-blob-xdrn.o) libeze.a(ez-blob-tagz.o) libeze.a(ez-blob-dump.o)
test-port: libeze.a(ez-port.o)
test-set: libeze.a(ez-set.o)
test-tree: libeze.a(ez-tree.o)
+++ /dev/null
-/* ez-blob-blob.c: Prototype serialiser.
-
- Copyright (C) 2019 Michael Zucchi
-
- This program 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 3 of
- the License, or (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this program. If not, see
- <http://www.gnu.org/licenses/>.
-*/
-
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "ez-list.h"
-
-#include "ez-blob.h"
-#include "ez-blob-blob.h"
-
-/*
- This implements a basic 'high performance' serialisation based on the
- descriptors.
-
- Fields are encoded in the same order as the descriptor with no
- labelling. Therefore the same descriptor must be used on both ends.
- Fields may be at arbitrary alignments.
-
- primitives
- encoded in machine order at native size
-
- strings
- 4-byte length followed by characters. No nul termination. A length
- of ~0 indicates a null string pointer.
-
- arrays
- 4-byte length followed by data. ** currently null pointer arrays with zero length are converted to a zero-length array.
-
- struct
- 4-byte length followed by blob-encoded data.
-
- pointer
- 4-byte length followed by blob-encoded data. A length of ~0
- indicates a null pointer.
-
-*/
-
-static const int primitive_size[EZ_BLOB_FLOAT64+1] = {
- 1, 2, 4, 8,
- 4, 8
-};
-
-size_t ez_blob_size(const ez_blob_desc *desc, const void *p) {
- size_t size = 0;
-
- for (int i=0,dlen = desc->bd_length;i<dlen;i++) {
- const ez_blob_desc *d = &desc[i+1];
-
- if (d->bd_type <= EZ_BLOB_FLOAT64) {
- size += primitive_size[d->bd_type];
- } else {
- const void *v = p + d->bd_offset;
- switch (d->bd_type & EZ_BLOB_TYPE) {
- case EZ_BLOB_STRING: {
- char *s = ((char **)v)[0];
- size += s ? 4 + strlen(s) : 4;
- break;
- }
- case EZ_BLOB_BLOB:
- size += 4 + ((const struct ez_blob *)v)->size;
- break;
- case EZ_BLOB_STRUCT: {
- const void *sp = v;
- size += 4 + ez_blob_size(d->bd_table, sp);
- break;
- }
- case EZ_BLOB_POINTER: {
- const void *s = ((const void * const *)v)[0];
- size += s ? 4 + ez_blob_size(d->bd_table, s) : 4;
- break;
- }
- case EZ_BLOB_LIST: {
- ez_list *l = (ez_list *)v;
-
- size += 4;
- for (ez_node *w = ez_list_head(l), *n = ez_node_succ(w);
- n;
- w = n, n=ez_node_succ(n)) {
- size += 4 + ez_blob_size(d->bd_table, w);
- }
- break;
- }
- default:
- break;
- }
- }
- }
-
- return size;
-}
-
-int ez_blob_decode_raw(const ez_blob_desc *desc, const ez_blob *blob, void *p) {
- const char *b = blob->data;
- const char *be = b + blob->size;
-
- ez_blob_init(desc, p);
-
- for (int i=0,dlen = desc->bd_length;i<dlen;i++) {
- const ez_blob_desc *d = &desc[i+1];
- void *v = (p + d->bd_offset);
-
- if (d->bd_type <= EZ_BLOB_FLOAT64) {
- int psize = primitive_size[d->bd_type];
-
- if (b + psize > be)
- goto fail;
- memcpy(v, b, psize);
- b += psize;
- } else if (d->bd_type == EZ_BLOB_LIST) {
- uint32_t count;
- ez_list *l = v;
-
- if (b + 4 > be)
- goto fail;
- memcpy(&count, b, 4);
- b += 4;
-
- ez_list_init(l);
- for (int i=0;i<count;i++) {
- uint32_t ss;
- ez_blob sub;
- void *s;
-
- if (b + 4 > be)
- goto fail;
- memcpy(&ss, b, 4);
- b += 4;
-
- sub.size = ss;
- sub.data = (void *)b;
-
- if (b + ss > be)
- goto fail;
- if ((s = calloc(d->bd_table->bd_offset, 1)) == NULL)
- goto fail;
- if (ez_blob_decode_raw(d->bd_table, &sub, s) != 0) {
- free(s);
- goto fail;
- }
- ez_list_addtail(l, s);
- b+=ss;
- }
- } else {
- uint32_t ss;
- ez_blob sub;
-
- if (b + 4 > be)
- goto fail;
- memcpy(&ss, b, 4);
- b += 4;
-
- sub.size = ss;
- sub.data = (char *)b;
-
- switch (d->bd_type & EZ_BLOB_TYPE) {
- case EZ_BLOB_STRING: {
- char *s = NULL;
-
- if (ss != ~0) {
- if (b + ss > be)
- goto fail;
- if ((s = malloc((size_t)ss + 1)) == NULL)
- goto fail;
- memcpy(s, b, ss);
- s[ss] = 0;
- b += ss;
- }
- ((char **)v)[0] = s;
- break;
- }
- case EZ_BLOB_BLOB: {
- struct ez_blob *a = v;
-
- if (b + ss > be)
- goto fail;
- a->size = ss;
- if ((a->data = malloc(ss)) == NULL)
- goto fail;
- memcpy(a->data, b, ss);
- b += ss;
- break;
- }
- case EZ_BLOB_STRUCT:
- if (b + ss > be)
- goto fail;
-
- if (ez_blob_decode_raw(d->bd_table, &sub, v) != 0)
- goto fail;
- b += ss;
- break;
- case EZ_BLOB_POINTER: {
- void *s = NULL;
-
- if (ss != ~0) {
- if (b + ss > be)
- goto fail;
- if ((s = calloc(d->bd_table->bd_offset, 1)) == NULL)
- goto fail;
- if (ez_blob_decode_raw(d->bd_table, &sub, s) != 0) {
- free(s);
- goto fail;
- }
- b += ss;
- }
- ((void **)v)[0] = s;
- break;
- }
- default:
- break;
- }
- }
- }
- if (b != be)
- goto fail;
-
- return 0;
- fail:
- ez_blob_free_raw(desc, p);
- return 1;
-}
-
-void *ez_blob_decode(const ez_blob_desc *d, const ez_blob *blob) {
- void *p = calloc(d->bd_offset, 1);
-
- if (ez_blob_decode_raw(d, blob, p) != 0) {
- free(p);
- return NULL;
- }
-
- return p;
-}
-
-int ez_blob_encode_raw(const ez_blob_desc *desc, const void *p, ez_blob *blob) {
- char *b = blob->data;
- char *be = b+blob->size;
-
- for (int i=0,dlen = desc->bd_length;i<dlen;i++) {
- const ez_blob_desc *d = &desc[i+1];
- const void *v = (p + d->bd_offset);
-
- if (d->bd_type <= EZ_BLOB_FLOAT64) {
- int psize = primitive_size[d->bd_type];
-
- assert(b+psize <= be);
- memcpy(b, v, psize);
- b += psize;
- } else if (d->bd_type == EZ_BLOB_LIST) {
- ez_list *l = (void *)v;
- uint32_t ss = ez_list_size(l);
-
- memcpy(b, &ss, 4);
- b += 4;
- for (ez_node *w = ez_list_head(l), *n = ez_node_succ(w);
- n;
- w = n, n=ez_node_succ(n)) {
- ez_blob sub;
-
- ss = ez_blob_size(d->bd_table, w);
-
- assert(b+4+ss <= be);
- memcpy(b, &ss, 4);
- sub.data = b+4;
- sub.size = ss;
- ez_blob_encode_raw(d->bd_table, w, &sub);
- b += 4 + ss;
- }
- } else {
- uint32_t ss;
- struct ez_blob sub;
-
- switch (d->bd_type & EZ_BLOB_TYPE) {
- case EZ_BLOB_STRING: {
- char *s = ((char **)v)[0];
- if (s) {
- ss = strlen(s);
- assert(b+4+ss <= be);
- memcpy(b, &ss, 4);
- memcpy(b+4, s, ss);
- b += 4 + ss;
- } else {
- ss = ~0;
- assert(b+4 <= be);
- memcpy(b, &ss, 4);
- b += 4;
- }
- break;
- }
- case EZ_BLOB_BLOB: {
- const struct ez_blob *a = v;
-
- ss = a->size;
- assert(b+4+ss <= be);
- memcpy(b, &ss, 4);
- memcpy(b+4, a->data, ss);
- b += 4 + ss;
- break;
- }
- case EZ_BLOB_STRUCT:
- ss = ez_blob_size(d->bd_table, v);
-
- assert(b+4+ss <= be);
- memcpy(b, &ss, 4);
- sub.data = b+4;
- sub.size = ss;
- ez_blob_encode_raw(d->bd_table, v, &sub);
- b += 4 + ss;
- break;
- case EZ_BLOB_POINTER: {
- const void *s = ((const void **)v)[0];
-
- if (s) {
- ss = ez_blob_size(d->bd_table, s);
- assert(b+4+ss <= be);
- memcpy(b, &ss, 4);
- sub.data = b+4;
- sub.size = ss;
- ez_blob_encode_raw(d->bd_table, s, &sub);
- b += 4 + ss;
- } else {
- ss = ~0;
- assert(b+4 <= be);
- memcpy(b, &ss, 4);
- b += 4;
- }
- break;
- }
- default:
- break;
- }
- }
- }
- assert(b == be);
- return 0;
-}
-
-int ez_blob_encode(const ez_blob_desc *d, const void *p, ez_blob *blob) {
- blob->size = ez_blob_size(d, p);
- blob->data = malloc(blob->size);
-
- if (blob->data) {
- if (ez_blob_encode_raw(d, p, blob) == 0)
- return 0;
- free(blob->data);
- blob->data = NULL;
- }
- blob->size = 0;
-
- return -1;
-}
+++ /dev/null
-/* ez-blob-blob.h: Prototype serialiser.
-
- Copyright (C) 2019 Michael Zucchi
-
- This program 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 3 of
- the License, or (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this program. If not, see
- <http://www.gnu.org/licenses/>.
-*/
-
-/*
- * The implemented serialisation mechanism only supports
- * forward-linked structures and will not perform well when
- * marshalling deeply nested structures but other serialisation
- * mechanisms are possible.
- *
- * It's historical and is to be removed.
- */
-
-/**
- * Calculate the serialised blob size for a struct.
- *
- * @param d descriptor table matching struct.
- * @param p struct.
- */
-size_t ez_blob_size(const ez_blob_desc *d, const void *p);
-
-/**
- * Marshal a struct to a blob.
- *
- * @param d descriptor table matching the struct.
- * @param p structure.
- * @param sizep return pointer for blob size, must not be null.
- * @param blob return, the data pointer must be freed with free() when complete.
- * @return non-zero on failure.
- */
-int ez_blob_encode(const ez_blob_desc *d, const void *p, ez_blob *blob);
-
-/**
- * Marshal a struct to a blob directly
- *
- * @param d descriptor table matching the struct.
- * @param p structure.
- * @param blob available target memory, size must be exactly ez_blob_size().
- * @return non-zero on failure. On failure blob.data is invalid.
- */
-int ez_blob_encode_raw(const ez_blob_desc *d, const void *p, ez_blob *blob);
-
-/**
- * Unmarshall a blob into a struct.
- *
- * @param d descriptor table matching blob.
- * @param blob raw blob.
- * @param size blob size.
- * @return the decoded struct. May be freed using ez_blob_free().
- */
-void *ez_blob_decode(const ez_blob_desc *d, const ez_blob *blob);
-
-/**
- * Decode to pre-allocated buffer.
- *
- * @param b blob data
- * @param size blob size
- * @return non-zero on failure. Any allocated pointers are freed.
- */
-int ez_blob_decode_raw(const ez_blob_desc *d, const ez_blob *blob, void *p);
-
--- /dev/null
+/* ez-blob.h: Serialising description and serialiser.
+
+ Copyright (C) 2019 Michael Zucchi
+
+ This program 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 3 of
+ the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <ctype.h>
+
+#include "ez-blob.h"
+
+void ez_blob_dump(const ez_blob *blob, const char *prefix) {
+ const char *data = blob->eb_data;
+ size_t size = blob->eb_size;
+
+ for (int i=0;i<size;i+=16) {
+ fputs(prefix, stdout);
+ printf(" %04x:", i);
+ for (int j=0;j<16;j++) {
+ if (i+j<size)
+ printf(" %02x", data[i+j] & 0xff);
+ else
+ fputs(" ", stdout);
+ }
+ fputs(" ", stdout);
+ for (int j=0;j<16;j++) {
+ if (i+j<size)
+ putchar(isprint(data[i+j]) ? data[i+j] : '.');
+ else
+ putchar(' ');
+ }
+ putchar('\n');
+ }
+}
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
-#include <ctype.h>
+#include <errno.h>
#include "ez-blob.h"
#include "ez-blob-io.h"
alloc = realloc(io->data, size);
if (!alloc) {
- io->error = 1;
+ io->error = ENOMEM;
printf("realloc failed\n");
ABORT();
return NULL;
case BLOBIO_WRITE_FIXED:
if (to > size) {
- io->error = 1;
+ io->error = EOVERFLOW;
ABORT();
return NULL;
}
case BLOBIO_WRITE_SIZE:
io->index = to;
+ return NULL;
default:
+ io->error = EINVAL;
return NULL;
}
}
} else {
ABORT();
io->index = io->size;
- io->error = 1;
+ io->error = EOVERFLOW;
return NULL;
}
}
blobio_take(io, skip);
}
-
-void blobio_dumphex(const char *data, size_t size, const char *prefix) {
- for (int i=0;i<size;i+=16) {
- fputs(prefix, stdout);
- printf(" %04x:", i);
- for (int j=0;j<16;j++) {
- if (i+j<size)
- printf(" %02x", data[i+j] & 0xff);
- else
- fputs(" ", stdout);
- }
- fputs(" ", stdout);
- for (int j=0;j<16;j++) {
- if (i+j<size)
- putchar(isprint(data[i+j]) ? data[i+j] : '.');
- else
- putchar(' ');
- }
- putchar('\n');
- }
-}
-
#include <assert.h>
#include <stdio.h>
-#include <ctype.h>
#include "ez-blob.h"
#include "ez-list.h"
for (int i=0;i<=len;i++,d++) {
const void *u = a + d->bd_offset;
- printf("%s [type=$%02x, offset=$%04x]", x, d->bd_type, d->bd_offset);
+ printf("%s [type=$%04x, offset=$%04x]", x, d->bd_type, d->bd_offset);
- switch (d->bd_type & EZ_BLOB_TYPE) {
+ switch (d->bd_type) {
case EZ_BLOB_INT8:
printf(" .%d = %02x\n", d->bd_id, *(uint8_t *)u);
break;
case EZ_BLOB_FLOAT64:
printf(" .%d = %f\n", d->bd_id, *(double *)u);
break;
- case EZ_BLOB_STRING:
+
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE:
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP:
+ u = *(void **)u;
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLE:
+ if (u) {
+ printf(" .%d %p = {\n", d->bd_id, u);
+ ez_blob_print(d->bd_table, u, depth+4);
+ printf("%s }\n", x);
+ } else {
+ printf(" .%d %p\n", d->bd_id, u);
+ }
+ break;
+
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8 | EZ_BLOB_ISNULLABLE:
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8:
printf(" .%d %p = `%s'\n", d->bd_id, *((char **)u), *((char **)u));
break;
- case EZ_BLOB_BLOB: {
+
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT8:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT16:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT64:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT64: {
const struct ez_blob *ua = u;
+ unsigned int elsize = 1 << (d->bd_type & EZ_BLOB_SIZE);
+ ez_blob blob = { .eb_size = ua->eb_size * elsize, .eb_data = ua->eb_data };
- printf(" .%d %p [%zd] = {\n", d->bd_id, ua->data, ua->size);
- blobio_dumphex(ua->data, ua->size, x);
+ printf(" .%d %p [%zd x %d] = {\n", d->bd_id, ua->eb_data, ua->eb_size, elsize);
+ ez_blob_dump(&blob, x);
printf("%s }\n", x);
break;
}
- case EZ_BLOB_POINTER: {
- void *up = *((void **)u);
- if (up) {
- printf(" .%d %p = {\n", d->bd_id, up);
- ez_blob_print(d->bd_table, up, depth+4);
+
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP | EZ_BLOB_ISNULLABLE:
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP:
+ u = *(const void **)u;
+ case EZ_BLOB_STRUCT | EZ_BLOB_LIST:
+ if (u) {
+ printf(" .%d %p [] = {\n", d->bd_id, u);
+ for (ez_node *w = ez_list_head((ez_list *)u), *n = ez_node_next(w); n; w = n, n=ez_node_next(n)) {
+ printf("%s{\n", x);
+ ez_blob_print(d->bd_table, w, depth+4);
+ printf("%s},\n", x);
+ }
printf("%s }\n", x);
} else {
- printf(" .%d %p\n", d->bd_id, up);
+ printf(" .%d %p\n", d->bd_id, u);
}
break;
- }
- case EZ_BLOB_LIST: {
- ez_list *l = (void *)u;
-
- printf(" .%d %p [] = {\n", d->bd_id, l);
- for (ez_node *w = ez_list_head(l), *n = ez_node_next(w);
- n;
- w = n, n=ez_node_next(n)) {
- printf("%s{\n", x);
- ez_blob_print(d->bd_table, w, depth+4);
- printf("%s},\n", x);
- }
- printf("%s }\n", x);
+
+ case EZ_BLOB_MAGIC:
+ printf(" OBJECT id=%d length=%d\n", d->bd_id, d->bd_length);
break;
- }
default:
- printf("\n");
+ printf(" .%d ?? UNKNOWN ??\n", d->bd_id);
+ break;
}
}
}
*/
+/*
+ Support matrix:
+
+ single singlep vector vectorp list listp cstring
+ ?null 1 ?null ?null
+
+ int8 x x 2 x 3
+ int16 x x 2
+ int32 x x 2
+ int64 x x 2
+ float x x
+ double x x
+ struct x x x x
+
+ 1. All pointers are treated as nullable. The annotation is ignored.
+ 2. All bytes of integers are written with no prefix removal.
+ 3. ??Strings are written containing the trailing 0 byte??
+
+*/
+
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <errno.h>
#include "ez-list.h"
//#define D(x) do { x; fflush(stdout); } while (0)
#define D(x)
+// These are EZ_* types << 4
#define EZT_INT8 0x00
#define EZT_INT16 0x10
#define EZT_INT32 0x20
else if (size <= 0xffffffff)
return 0x2;
else
- return 0x3;
+ return 0x3;
}
static int tag_code(uint32_t size) {
static void tagz_encode_struct(struct ez_blobio *io, int id, const ez_blob_desc *desc, const void *p) {
blobio_writet(io, EZT_STRUCT, id);
-
+
for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
const ez_blob_desc *d = &desc[i+1];
const void *v = (p + d->bd_offset);
uint64_t val = 0;
uint64_t count = 0;
const void *ptr = NULL;
-
- switch (d->bd_type & EZ_BLOB_TYPE) {
- case EZ_BLOB_INT8:
+
+ switch (d->bd_type & (EZ_BLOB_TYPE | EZ_BLOB_STORAGE)) {
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT8:
val = *(uint8_t *)v;
goto doint;
- case EZ_BLOB_INT16:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT16:
val = *(uint16_t *)v;
goto doint;
- case EZ_BLOB_INT32:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT32:
val = *(uint32_t *)v;
goto doint;
- case EZ_BLOB_INT64:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT64:
val = *(uint64_t *)v;
doint:
if (val) {
int sc = size_code(val);
-
+
blobio_writet(io, EZT_INT8 | (sc << EZT_DATASHIFT), d->bd_id);
blobio_writei(io, sc, val);
}
break;
- case EZ_BLOB_FLOAT32:
+ case EZ_BLOB_SINGLE | EZ_BLOB_FLOAT32:
blobio_writet(io, EZT_FLOAT32, d->bd_id);
blobio_writef(io, *(const float *)v);
break;
- case EZ_BLOB_FLOAT64:
+ case EZ_BLOB_SINGLE | EZ_BLOB_FLOAT64:
blobio_writet(io, EZT_FLOAT64, d->bd_id);
blobio_writed(io, *(const double *)v);
break;
- case EZ_BLOB_STRING:
- // NULL strings are the default, so implement same but allow for empty strings
- ptr = *(const void **)v;
- if (ptr) {
- count = strlen(ptr);
- goto doblob;
+
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT8:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT16:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT64:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT64:
+ count = ((ez_blob *)v)->eb_size;
+ if (count) {
+ int sc = (d->bd_type & EZ_BLOB_SIZE);
+ int tc = (d->bd_type & EZ_BLOB_TYPE) << 4;
+
+ ptr = ((ez_blob *)v)->eb_data;
+ blobio_writetc(io, tc, d->bd_id, count);
+ blobio_write(io, ptr, count << sc);
}
break;
- case EZ_BLOB_BLOB:
- // empty blobs are the default, so implement same, empty are not encoded
- count = ((ez_blob *)v)->size;
- if (count) {
- ptr = ((ez_blob *)v)->data;
- doblob:
+
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8:
+ // NULL strings are the default, so implement same but allow for empty strings
+ v = *(const void **)v;
+ if (v) {
+ count = strlen(v);
blobio_writetc(io, EZT_INT8, d->bd_id, count);
- blobio_write(io, ptr, count);
+ blobio_write(io, v, count);
}
break;
- case EZ_BLOB_STRUCT:
- tagz_encode_struct(io, d->bd_id, d->bd_table, v);
- break;
- case EZ_BLOB_POINTER:
- ptr = *(const void **)v;
- if (ptr)
- tagz_encode_struct(io, d->bd_id, d->bd_table, ptr);
+
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP:
+ v = *(const void **)v;
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLE:
+ if (v)
+ tagz_encode_struct(io, d->bd_id, d->bd_table, v);
break;
- case EZ_BLOB_LIST:
- count = ez_list_size((ez_list *)v);
- if (count) {
- blobio_writetc(io, EZT_STRUCT, d->bd_id, count);
-
- for (ez_node *w = ez_list_head((ez_list *)v), *n = ez_node_succ(w);
- n;
- w = n, n=ez_node_succ(n)) {
- // which id to use?
- tagz_encode_struct(io, d->bd_table[0].bd_id, d->bd_table, w);
+
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP:
+ v = *(const void **)v;
+ case EZ_BLOB_STRUCT | EZ_BLOB_LIST:
+ if (v) {
+ count = ez_list_size((ez_list *)v);
+ if (count) {
+ blobio_writetc(io, EZT_STRUCT, d->bd_id, count);
+
+ for (ez_node *w = ez_list_head((ez_list *)v), *n = ez_node_succ(w); n; w = n, n=ez_node_succ(n)) {
+ // which id to use?
+ tagz_encode_struct(io, d->bd_table[0].bd_id, d->bd_table, w);
+ }
}
}
break;
+ default:
+ io->error = ENOTSUP;
+ return;
}
}
int ez_tagz_encode_raw(const ez_blob_desc *d, const void *p, ez_blob *blob) {
struct ez_blobio io = {
- .data = blob->data,
- .size = blob->size,
+ .data = blob->eb_data,
+ .size = blob->eb_size,
.mode = BLOBIO_WRITE_FIXED
};
tagz_encode_struct(&io, d->bd_id, d, p);
if (!io.error) {
- blob->size = io.index;
- blob->data = io.data;
+ blob->eb_size = io.index;
+ blob->eb_data = io.data;
return 0;
}
- free(io.data);
- blob->data = 0;
- blob->size = 0;
- return -1;
+ free(io.data);
+ blob->eb_data = NULL;
+ blob->eb_size = 0;
+
+ return io.error;
}
static int blobio_readb(struct ez_blobio *io) {
static void tagz_decode_struct(struct ez_blobio *io, const ez_blob_desc *desc, void *p);
static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, void *p);
+static unsigned int tagz_blob_type(int h) {
+ return (h >> 4) & EZ_BLOB_TYPE;
+}
+
static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, void *p) {
uint8_t h;
const ez_blob_desc *dscan = desc ? desc + 1 : desc;
if (p && d) {
void *v = p + d->bd_offset;
- switch (h & EZT_TYPE) {
- case EZT_INT8:
- case EZT_INT16:
- case EZT_INT32:
- case EZT_INT64:
- if (use_count) {
- char *mem;
- size_t len = fcount * (1<<sc);
- void *data = blobio_take(io, len);
-
- if (!data)
- goto error;
-
- switch (d->bd_type & EZ_BLOB_TYPE) {
- case EZ_BLOB_STRING:
- mem = malloc(len+1);
- if (!mem)
- goto error;
- *(char **)v = mem;
- memcpy(mem, data, len);
- mem[len] = 0;
- //*(char **)v = data;
- D(printf("string %d '%s'\n", d->bd_id, mem));
- break;
- case EZ_BLOB_BLOB:
- mem = malloc(len);
- if (!mem)
- goto error;
- ((ez_blob *)v)->data = mem;
- ((ez_blob *)v)->size = len;
- memcpy(mem, data, len);
- //((ez_blob *)v)->data = data;
- break;
- }
- } else {
- switch (d->bd_type) {
- case EZ_BLOB_INT8:
- *(uint8_t *)v = blobio_readi(io, sc);
- break;
- case EZ_BLOB_INT16:
- *(uint16_t *)v = blobio_readi(io, sc);
- break;
- case EZ_BLOB_INT32:
- *(uint32_t *)v = blobio_readi(io, sc);
- break;
- case EZ_BLOB_INT64:
- *(uint64_t *)v = blobio_readi(io, sc);
- break;
- default:
- goto error;
- }
+ unsigned int ttype = tagz_blob_type(h);
+ unsigned int btype = d->bd_type & EZ_BLOB_TYPE;
+
+ if (use_count) {
+ // Type must match exactly
+ if (ttype != btype) {
+ io->error = EILSEQ;
+ return;
}
- break;
- case EZT_FLOAT32:
- if (use_count) {
- blobio_take(io, fcount * 4);
- } else {
- switch (d->bd_type) {
- case EZ_BLOB_FLOAT32:
- *(float *)v = blobio_readf(io);
- break;
- case EZ_BLOB_FLOAT64:
- *(double *)v = blobio_readf(io);
- break;
- default:
- goto error;
+
+ switch (d->bd_type & (EZ_BLOB_STORAGE | EZ_BLOB_TYPE)) {
+ /* typed vectors */
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT8:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT16:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT64:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT64: {
+ size_t size = fcount << (d->bd_type & EZ_BLOB_SIZE);
+ void *src = blobio_take(io, size);
+
+ if (src) {
+ void *mem = malloc(size);
+
+ if (mem) {
+ memcpy(mem, src, size);
+ ((ez_blob *)v)->eb_data = mem;
+ ((ez_blob *)v)->eb_size = fcount;
+ D(printf("vector %d [%d]'\n", d->bd_id, fcount));
+ } else {
+ io->error = ENOMEM;
+ return;
+ }
}
+ break;
}
- break;
- case EZT_FLOAT64:
- if (use_count) {
- blobio_take(io, fcount * 8);
- } else {
- switch (d->bd_type) {
- case EZ_BLOB_FLOAT32:
- *(float *)v = blobio_readd(io);
- break;
- case EZ_BLOB_FLOAT64:
- *(double *)v = blobio_readd(io);
- break;
- default:
- goto error;
+
+ /* C string */
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8: {
+ size_t size = fcount;
+ void *src = blobio_take(io, size);
+ if (src) {
+ char *mem = malloc(size+1);
+
+ if (mem) {
+ memcpy(mem, src, size);
+ mem[size] = 0;
+ *(char **)v = mem;
+ } else {
+ io->error = ENOMEM;
+ return;
+ }
}
+ break;
}
- break;
- case EZT_STRUCT:
- if (use_count) {
- switch (d->bd_type) {
- case EZ_BLOB_LIST:
- for (int i=0; !io->error && i < fcount; i++) {
- void *node = ez_blob_alloc(d->bd_table);
-
- if (!node)
- goto error;
-
+
+ /* List */
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP:
+ *(void **)v = malloc(sizeof(ez_list));
+ v = *(void **)v;
+ if (!v) {
+ io->error = ENOMEM;
+ return;
+ }
+ ez_list_init((ez_list *)v);
+ case EZ_BLOB_STRUCT | EZ_BLOB_LIST:
+ for (int i=0; !io->error && i < fcount; i++) {
+ void *node = ez_blob_alloc(d->bd_table);
+
+ if (node) {
tagz_decode_struct(io, d->bd_table, node);
ez_list_addtail((ez_list *)v, node);
+ } else {
+ io->error = ENOMEM;
+ return;
}
- break;
- default:
- goto error;
}
- } else {
- switch (d->bd_type & EZ_BLOB_TYPE) {
- case EZ_BLOB_STRUCT:
- D(printf("struct %d\n", d->bd_id));
- //ez_blob_init(d->bd_table, v);
- tagz_decode_fields(io, d->bd_table, v);
- break;
- case EZ_BLOB_POINTER:
- D(printf("pointer %d\n", d->bd_id));
- *(void **)v = ez_blob_alloc(d->bd_table);
-
- if (!*(void **)v)
- goto error;
-
- tagz_decode_fields(io, d->bd_table, *(void **)v);
- break;
- default:
- goto error;
+ break;
+ default:
+ io->error = EILSEQ;
+ return;
+ }
+ } else {
+ // Type can either match or the target is a larger or same sized integer
+ if (ttype != btype
+ && (ttype > EZ_BLOB_INT64 || btype < ttype)) {
+ io->error = EILSEQ;
+ return;
+ }
+
+ switch (d->bd_type & (EZ_BLOB_STORAGE | EZ_BLOB_TYPE)) {
+
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT8:
+ *(uint8_t *)v = blobio_readi(io, sc);
+ break;
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT16:
+ *(uint16_t *)v = blobio_readi(io, sc);
+ break;
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT32:
+ *(uint32_t *)v = blobio_readi(io, sc);
+ break;
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT64:
+ *(uint64_t *)v = blobio_readi(io, sc);
+ break;
+ case EZ_BLOB_SINGLE | EZ_BLOB_FLOAT32:
+ *(float *)v = blobio_readf(io);
+ break;
+ case EZ_BLOB_SINGLE | EZ_BLOB_FLOAT64:
+ *(double *)v = blobio_readd(io);
+ break;
+
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP:
+ *(void **)v = ez_blob_alloc(d->bd_table);
+ v = *(void **)v;
+ if (!v) {
+ io->error = ENOMEM;
+ return;
}
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLE:
+ tagz_decode_fields(io, d->bd_table, v);
+ break;
+
+ default:
+ io->error = EILSEQ;
+ return;
}
- break;
- default:
- goto error;
}
} else {
// Just skip fields
}
break;
default:
- goto error;
+ io->error = EILSEQ;
+ return;
}
}
}
- return;
- error:
- io->index = io->size;
- io->error = 1;
}
static void tagz_decode_struct(struct ez_blobio *io, const ez_blob_desc *desc, void *p) {
uint8_t h = blobio_readb(io);
uint32_t stag;
int tc = (h >> EZT_TAGSHIFT) & 3;
- int cc = (h >> EZT_COUNTSHIFT) & 3;
+ int cc = (h >> EZT_COUNTSHIFT) & 3;
// must be a struct with tc=11 and cc!=11
- if ((h & EZT_TYPE) != EZT_STRUCT)
- goto error;
- if (tc != 3 || cc == 3)
- goto error;
+ if ((h & EZT_TYPE) != EZT_STRUCT
+ || tc != 3 || cc == 3) {
+ io->error = EILSEQ;
+ return;
+ }
// unused, but could check against desc->bd_id
stag = blobio_readi(io, cc);
stag = stag;
tagz_decode_fields(io, desc, p);
-
- return;
- error:
- io->error = 1;
}
int ez_tagz_decode_raw(const ez_blob_desc *desc, const ez_blob *blob, void *p) {
struct ez_blobio io = {
- .size = blob->size,
- .data = blob->data,
+ .size = blob->eb_size,
+ .data = blob->eb_data,
.mode = BLOBIO_READ
};
ez_blob_init(desc, p);
tagz_decode_struct(&io, desc, p);
- if (io.error) {
- ez_blob_free_raw(desc, p);
- return -1;
- }
-
- return 0;
+ if (!io.error)
+ return 0;
+
+ ez_blob_free_raw(desc, p);
+ return io.error;
}
void *ez_tagz_decode(const ez_blob_desc *desc, const ez_blob *blob) {
uint8_t h = blobio_readb(io);
uint32_t stag;
int tc = (h >> EZT_TAGSHIFT) & 3;
- int cc = (h >> EZT_COUNTSHIFT) & 3;
+ int cc = (h >> EZT_COUNTSHIFT) & 3;
char s[depth+1];
memset(s, ' ', depth);
stag = blobio_readi(io, cc);
printf("%s[%02x] %d = {\n", s, h, stag);
-
+
tagz_dump_fields(io, depth+4);
}
static void tagz_dump_fields(struct ez_blobio *io, int depth) {
int h;
-
+
char s[depth+1];
memset(s, ' ', depth);
s[depth] = 0;
-
+
// read fields
while ((h = blobio_readb(io)) != EZT_END) {
uint32_t ftag;
if (use_count) {
void *v = blobio_take(io, fcount * (1<<sc));
if (v) {
+ ez_blob blob = { .eb_size = fcount * (1<<sc), .eb_data = v };
printf("%s[%02x] integer-%-2d %d [%ld] = {\n", s, h, (1<<sc)*8, ftag, fcount);
- blobio_dumphex(v, fcount * (1<<sc), s);
+ ez_blob_dump(&blob, s);
printf("%s}\n", s);
}
} else {
*/
void ez_tagz_dump(ez_blob *blob) {
struct ez_blobio io = {
- .data = blob->data,
- .size = blob->size,
+ .data = blob->eb_data,
+ .size = blob->eb_size,
.mode = BLOBIO_READ
};
*/
/*
- Implements an XDR serialiser.
+ Implements a XDR serialiser using native byte ordering.
Each end must have identical descriptor tables.
- STRING or POINTER files which may be NULL must be marked as
- EZ_BLOB_NULLABLE. They are implemented as optional fields.
+ Support matrix:
+
+ single singlep vector vectorp list listp cstring
+ ?null 1 ?null ?null
+
+ int8 x x 2 x 3
+ int16 x x 2
+ int32 x x
+ int64 x x
+ float x x
+ double x x
+ struct x x x x
+
+ 1. Nullable fields are optional and must be properly annotated.
+ They are written as Optional-Data.
+ 2. These are written as Variable-Length Opaque Data rather than
+ Variable-Length Array. The size is the byte size not
+ the element count.
+ 3. These are 8-bit strings (e.g. UTF-8), not necessarily ASCII as
+ specified by String.
*/
#include <string.h>
#include <stdint.h>
+#include <errno.h>
+
#include "ez-list.h"
#include "ez-blob.h"
return (v+3) & ~3;
}
+/*
+ Arrays of byte and short are encoded as 'opquate data' for
+ compactness, the count is the number of bytes.
+
+ Arrays of int32/int64/float/double are written as arrays,
+ the count is the number of elements.
+*/
+
+static void xdrio_writev(struct ez_blobio *io, const ez_blob *data, size_t elshift) {
+ size_t size = data->eb_size << elshift;
+ int32_t count = elshift <= 1 ? size : data->eb_size;
+ void *v;
+
+ blobio_write32(io, count);
+ v = blobio_reserve(io, size);
+ if (v) {
+ memcpy(v, data->eb_data, size);
+ blobio_write_align(io, 4);
+ }
+}
+
+static void xdrio_readv(struct ez_blobio *io, ez_blob *data, size_t elshift) {
+ int32_t count = blobio_readi32(io);
+ size_t size = elshift <= 1 ? count : count << elshift;
+ void *src = blobio_take(io, size);
+
+ if (src) {
+ void *mem = malloc(size);
+
+ if (mem) {
+ memcpy(mem, src, size);
+ data->eb_data = mem;
+ data->eb_size = size >> elshift;
+ blobio_read_align(io, 4);
+ } else {
+ io->error = ENOMEM;
+ }
+ }
+}
+
+static void xdrio_writes(struct ez_blobio *io, const char *v) {
+ if (v) {
+ int32_t size = strlen(v);
+
+ blobio_write32(io, size);
+ blobio_write(io, v, size);
+ blobio_write_align(io, 4);
+ } else {
+ io->error = EINVAL;
+ }
+}
+
+static void xdrio_reads(struct ez_blobio *io, char **v) {
+ uint32_t size = blobio_readi32(io);
+ void *src = blobio_take(io, size);
+
+ if (src) {
+ char *mem = malloc(size+1);
+
+ if (mem) {
+ memcpy(mem, src, size);
+ mem[size] = 0;
+ *v = mem;
+ blobio_read_align(io, 4);
+ } else {
+ io->error = ENOMEM;
+ }
+ }
+}
+
static void xdrn_encode_raw(struct ez_blobio *io, const ez_blob_desc *desc, const void *p) {
for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
const ez_blob_desc *d = &desc[i+1];
const void *v = (p + d->bd_offset);
switch (d->bd_type) {
- case EZ_BLOB_INT8:
+ /*
+ * Primitive x 1
+ */
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT8:
blobio_write32(io, *(uint8_t *)v);
break;
- case EZ_BLOB_INT16:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT16:
blobio_write32(io, *(uint16_t *)v);
break;
- case EZ_BLOB_INT32:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT32:
blobio_write32(io, *(uint32_t *)v);
break;
- case EZ_BLOB_INT64:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT64:
blobio_write64(io, *(uint64_t *)v);
break;
- case EZ_BLOB_FLOAT32:
+ case EZ_BLOB_SINGLE | EZ_BLOB_FLOAT32:
blobio_writef(io, *(float *)v);
break;
- case EZ_BLOB_FLOAT64:
+ case EZ_BLOB_SINGLE | EZ_BLOB_FLOAT64:
blobio_writed(io, *(double *)v);
break;
- case EZ_BLOB_STRING | EZ_BLOB_NULLABLE:
- if (!*(char **)v) {
+
+ /*
+ * Primitive x array
+ */
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT8:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT16:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT64:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT64:
+ xdrio_writev(io, (const ez_blob *)v, (d->bd_type & EZ_BLOB_SIZE));
+ break;
+
+ /*
+ * C string byte
+ */
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8 | EZ_BLOB_ISNULLABLE:
+ if (!*(const char **)v) {
blobio_write32(io, 0);
break;
}
blobio_write32(io, 1);
// falls through
- case EZ_BLOB_STRING: {
- int32_t size = strlen(*(char **)v);
-
- blobio_write32(io, size);
- blobio_write(io, *(char **)v, size);
- blobio_write_align(io, 4);
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8:
+ xdrio_writes(io, *(const char **)v);
break;
- }
- case EZ_BLOB_BLOB: {
- uint32_t size = ((ez_blob *)v)->size;
- blobio_write32(io, size);
- blobio_write(io, ((ez_blob *)v)->data, size);
- blobio_write_align(io, 4);
- break;
- }
- case EZ_BLOB_STRUCT:
+ /*
+ * Structure x 1
+ */
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE:
+ if (!*(const void **)v) {
+ blobio_write32(io, 0);
+ break;
+ }
+ blobio_write32(io, 1);
+ // falls through
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP:
+ v = *(const void **)v;
+ if (!v) {
+ io->error = EINVAL;
+ return;
+ }
+ // falls through
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLE:
xdrn_encode_raw(io, d->bd_table, v);
break;
- case EZ_BLOB_POINTER | EZ_BLOB_NULLABLE:
- if (!*(void **)v) {
+
+ /*
+ * Structure x list
+ */
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP | EZ_BLOB_ISNULLABLE:
+ if (!*(const void **)v) {
blobio_write32(io, 0);
break;
}
blobio_write32(io, 1);
// falls through
- case EZ_BLOB_POINTER:
- xdrn_encode_raw(io, d->bd_table, *(void **)v);
- break;
- case EZ_BLOB_LIST:
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP:
+ v = *(const void **)v;
+ if (!v) {
+ io->error = EINVAL;
+ return;
+ }
+ // falls through
+ case EZ_BLOB_STRUCT | EZ_BLOB_LIST:
blobio_write32(io, ez_list_size((ez_list *)v));
- for (ez_node *w = ez_list_head((ez_list *)v), *n = ez_node_succ(w);
- n;
- w = n, n=ez_node_succ(n)) {
+ for (ez_node *w = ez_list_head((ez_list *)v), *n = ez_node_succ(w); n; w = n, n=ez_node_succ(n)) {
xdrn_encode_raw(io, d->bd_table, w);
}
break;
default:
- io->error = 1;
+ io->error = ENOTSUP;
return;
}
}
int ez_xdrn_encode_raw(const ez_blob_desc *d, const void *p, ez_blob *blob) {
struct ez_blobio io = {
- .data = blob->data,
- .size = blob->size,
+ .data = blob->eb_data,
+ .size = blob->eb_size,
.mode = BLOBIO_WRITE_FIXED
};
xdrn_encode_raw(&io, d, p);
if (!io.error) {
- blob->size = io.index;
- blob->data = io.data;
+ blob->eb_size = io.index;
+ blob->eb_data = io.data;
return 0;
}
- free(blob->data);
-
- return -1;
+ free(io.data);
+ blob->eb_data = NULL;
+ blob->eb_size = 0;
+
+ return io.error;
}
static void xdrn_decode_raw(struct ez_blobio *io, const ez_blob_desc *desc, void *p) {
- ez_blob_init(desc, p);
-
for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
const ez_blob_desc *d = &desc[i+1];
void *v = (p + d->bd_offset);
switch (d->bd_type) {
- case EZ_BLOB_INT8:
+ /*
+ * Primitive x 1
+ */
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT8:
*(uint8_t *)v = blobio_readi32(io);
break;
- case EZ_BLOB_INT16:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT16:
*(uint16_t *)v = blobio_readi32(io);
break;
- case EZ_BLOB_INT32:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT32:
*(uint32_t *)v = blobio_readi32(io);
break;
- case EZ_BLOB_INT64:
+ case EZ_BLOB_SINGLE | EZ_BLOB_INT64:
*(uint64_t *)v = blobio_readi64(io);
break;
- case EZ_BLOB_FLOAT32:
+ case EZ_BLOB_SINGLE | EZ_BLOB_FLOAT32:
*(float *)v = blobio_readf(io);
break;
- case EZ_BLOB_FLOAT64:
+ case EZ_BLOB_SINGLE | EZ_BLOB_FLOAT64:
*(double *)v = blobio_readd(io);
break;
- case EZ_BLOB_STRING | EZ_BLOB_NULLABLE:
+
+ /*
+ * Primitive x array
+ */
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT8:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT16:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT64:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT64:
+ xdrio_readv(io, (ez_blob *)v, (d->bd_type & EZ_BLOB_SIZE));
+ break;
+
+ /*
+ * C string byte
+ */
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8 | EZ_BLOB_ISNULLABLE:
if (blobio_readi32(io) == 0)
break;
// falls through
- case EZ_BLOB_STRING: {
- uint32_t size = blobio_readi32(io);
- void *src = blobio_take(io, size);
-
- if (src) {
- char *mem = malloc(size+1);
-
- if (!mem)
- goto error;
-
- memcpy(mem, src, size);
- mem[size] = 0;
- *(char **)v = mem;
- blobio_read_align(io, 4);
- }
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8:
+ xdrio_reads(io, (char **)v);
break;
- }
- case EZ_BLOB_BLOB: {
- uint32_t size = blobio_readi32(io);
- void *src = blobio_take(io, size);
- if (src) {
- char *mem = malloc(size);
-
- if (!mem)
- goto error;
-
- memcpy(mem, src, size);
- ((ez_blob *)v)->data = mem;
- ((ez_blob *)v)->size = size;
- blobio_read_align(io, 4);
+ /*
+ * Structure x 1
+ */
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE:
+ if (blobio_readi32(io) == 0)
+ break;
+ // falls through
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP:
+ *(void **)v = ez_blob_alloc(d->bd_table);
+ v = *(void **)v;
+ if (!v) {
+ io->error = ENOMEM;
+ return;
}
- break;
- }
- case EZ_BLOB_STRUCT:
+ // falls through
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLE:
xdrn_decode_raw(io, d->bd_table, v);
break;
- case EZ_BLOB_POINTER | EZ_BLOB_NULLABLE:
+
+ /*
+ * Structure x list
+ */
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP | EZ_BLOB_ISNULLABLE:
if (blobio_readi32(io) == 0)
break;
- case EZ_BLOB_POINTER: {
- void *mem = malloc(d->bd_table->bd_offset);
-
- if (!mem)
- goto error;
-
- *(void **)v = mem;
- xdrn_decode_raw(io, d->bd_table, mem);
- break;
- }
- case EZ_BLOB_LIST: {
+ // falls through
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP:
+ *(ez_list **)v = malloc(sizeof(ez_list));
+ v = *(void **)v;
+ if (!v) {
+ io->error = ENOMEM;
+ return;
+ }
+ ez_list_init((ez_list *)v);
+ // falls through
+ case EZ_BLOB_STRUCT | EZ_BLOB_LIST: {
uint32_t count = blobio_readi32(io);
for (int j=0;j<count;j++) {
- void *node = malloc(d->bd_table->bd_offset);
-
- if (!node)
- goto error;
-
- xdrn_decode_raw(io, d->bd_table, node);
- ez_list_addtail((ez_list *)v, node);
+ void *node = ez_blob_alloc(d->bd_table);
+
+ if (node) {
+ xdrn_decode_raw(io, d->bd_table, node);
+ ez_list_addtail((ez_list *)v, node);
+ } else {
+ io->error = ENOMEM;
+ return;
+ }
}
break;
}
default:
- goto error;
+ io->error = EILSEQ;
+ return;
}
}
- return;
- error:
- io->index = io->size;
- io->error = 1;
}
int ez_xdrn_decode_raw(const ez_blob_desc *desc, const ez_blob *blob, void *p) {
struct ez_blobio io = {
- .size = blob->size,
- .data = blob->data,
+ .size = blob->eb_size,
+ .data = blob->eb_data,
.mode = BLOBIO_READ
};
+ ez_blob_init(desc, p);
xdrn_decode_raw(&io, desc, p);
- if (io.error) {
- ez_blob_free_raw(desc, p);
- return -1;
- }
-
- return 0;
+ if (!io.error)
+ return 0;
+
+ ez_blob_free_raw(desc, p);
+ return io.error;
}
void *ez_xdrn_decode(const ez_blob_desc *desc, const ez_blob *blob) {
for (int i=0, dlen = desc->bd_length; i < dlen; i++) {
const ez_blob_desc *d = &desc[i+1];
void *v = p + d->bd_offset;
+ int st = d->bd_type & EZ_BLOB_STORAGE;
+ int dt = d->bd_type & EZ_BLOB_TYPE;
- switch (d->bd_type & EZ_BLOB_TYPE) {
- case EZ_BLOB_STRING:
- free(((char **)v)[0]);
+ switch (st) {
+ case EZ_BLOB_SINGLE:
+ if (dt == EZ_BLOB_STRUCT)
+ ez_blob_free_raw(d->bd_table, v);
+ break;
+ case EZ_BLOB_SINGLEP:
+ v = *(void **)v;
+ if (v) {
+ if (dt == EZ_BLOB_STRUCT)
+ ez_blob_free_raw(d->bd_table, v);
+ free(v);
+ }
break;
- case EZ_BLOB_BLOB:
- free(((struct ez_blob *)v)->data);
+ case EZ_BLOB_CSTRING:
+ free(((char **)v)[0]);
break;
- case EZ_BLOB_STRUCT:
- ez_blob_free_raw(d->bd_table, v);
+ case EZ_BLOB_VECTOR:
+ if (dt == EZ_BLOB_STRUCT) {
+ // FIXME: free elements
+ }
+ free(((struct ez_blob *)v)->eb_data);
break;
- case EZ_BLOB_POINTER:
- ez_blob_free(d->bd_table, ((void **)v)[0]);
+ case EZ_BLOB_VECTORP:
+ v = *(void **)v;
+ if (v) {
+ if (dt == EZ_BLOB_STRUCT) {
+ // FIXME: free elements
+ }
+ free(((struct ez_blob *)v)->eb_data);
+ }
break;
- case EZ_BLOB_LIST: {
- ez_list *l = (ez_list *)v;
- for (ez_node *w = ez_list_head(l), *n = ez_node_succ(w);
- n;
- w = n, n=ez_node_succ(n)) {
+ case EZ_BLOB_LIST:
+ for (ez_node *w = ez_list_head((ez_list *)v), *n = ez_node_succ(w); n; w = n, n=ez_node_succ(n))
ez_blob_free(d->bd_table, w);
+ break;
+ case EZ_BLOB_LISTP:
+ v = *(void **)v;
+ if (v) {
+ for (ez_node *w = ez_list_head((ez_list *)v), *n = ez_node_succ(w); n; w = n, n=ez_node_succ(n))
+ ez_blob_free(d->bd_table, w);
+ free(v);
}
break;
- }
default:
break;
}
for (int i=0, dlen = desc->bd_length; i < dlen; i++) {
const ez_blob_desc *d = &desc[i+1];
void *v = p + d->bd_offset;
+ int st = d->bd_type & EZ_BLOB_STORAGE;
+ int dt = d->bd_type & EZ_BLOB_TYPE;
- if (d->bd_type == EZ_BLOB_LIST)
+ switch (st) {
+ case EZ_BLOB_SINGLE:
+ if (dt == EZ_BLOB_STRUCT)
+ ez_blob_init(d->bd_table, v);
+ break;
+ case EZ_BLOB_LIST:
ez_list_init((ez_list *)v);
- else if (d->bd_type == EZ_BLOB_STRUCT)
- ez_blob_init(d->bd_table, v);
+ break;
+ }
}
}
* including nested and linked structures.
*
* A structure is described by an array of ez_blob_desc. The first
- * entry must be of type EZ_BLOB_PK, it's 'offset' must be the size
- * of the structure, and .u.count must be the number of fields
- * following.
+ * entry must have bd_offset=sizeof(structure), and bd_length=the
+ * number of field annotats which follow.
*
* As an example:
*
*/
typedef struct ez_blob_desc {
unsigned short bd_type; // type of field
- unsigned short bd_id; // used to tag encoded entries (currently unused)
+ unsigned short bd_id; // used to tag encoded entries
unsigned int bd_offset; // offset into structure, if type == EZ_BLOB_PK then this is sizeof(struct)
union {
- const struct ez_blob_desc *table;// embedded structure or pointer
- unsigned int length;
- } u;
-#define bd_table u.table
-#define bd_length u.length
+ const struct ez_blob_desc *bd_table;// embedded structure or pointer
+ unsigned int bd_length;
+ };
} ez_blob_desc;
/**
* Field type
*/
typedef enum ez_blob_desc_type {
- EZ_BLOB_INT8,
+ /* Data type */
+ EZ_BLOB_INT8, // (type & 3) = log2(element size)
EZ_BLOB_INT16,
EZ_BLOB_INT32,
EZ_BLOB_INT64,
- EZ_BLOB_FLOAT32,
+ EZ_BLOB_FLOAT32 = 6,
EZ_BLOB_FLOAT64,
- EZ_BLOB_STRING, // normal c strring
- EZ_BLOB_BLOB, // embedded ez_blob for arbitrary bytes.
- EZ_BLOB_STRUCT, // bd_table points to another descriptor list, object embedded
- EZ_BLOB_POINTER, // bd_table points to another descriptor list, object pointer
- EZ_BLOB_LIST, // ez_list nodes.
- EZ_BLOB_LAST = EZ_BLOB_LIST,
- EZ_BLOB_PK = 16, // MUST always be first element in descriptor and occur only once
- EZ_BLOB_NULLABLE = 0x8000, // Pointer may be NULL for STRING, POINTER
- EZ_BLOB_TYPE = 0xff, // Type mask
- EZ_BLOB_END
+ EZ_BLOB_STRUCT = 15, // bd_table points to another descriptor list
+
+ /* Data Storage */
+ EZ_BLOB_SINGLE = 0x00, // the value at bd_offset
+ EZ_BLOB_SINGLEP = 0x10, // pointer to value at bd_offset
+ EZ_BLOB_CSTRING = 0x20, // 0-terminated string pointer
+
+ EZ_BLOB_VECTOR = 0x40, // ez_blob at bd_offset
+ EZ_BLOB_VECTORP = 0x50, // pointer to ez_blob at bd_offset
+ EZ_BLOB_LIST = 0x60, // ez_list at bd_offset
+ EZ_BLOB_LISTP = 0x70, // pointer to ez_list at bd_offset
+
+ /* Options */
+ EZ_BLOB_ISNULLABLE = (1<<8),
+
+ /* meta */
+ EZ_BLOB_SIZE = 0x03, // size mask for int or float types
+ EZ_BLOB_TYPE = 0x0f, // Type mask
+ EZ_BLOB_STORAGE = 0xf0, // Storage mask
+
+ EZ_BLOB_MAGIC = 0x10f5
} ez_blob_desc_type;
/**
* This is compatible with lmdb MDB_val
*/
typedef struct ez_blob {
- size_t size;
- void *data;
+ size_t eb_size;
+ union {
+ void *eb_data;
+ uint8_t eb_data8;
+ uint16_t eb_data16;
+ uint32_t eb_data32;
+ uint64_t eb_data64;
+ float *eb_float;
+ double *eb_double;
+ };
} ez_blob;
-#define EZ_BLOB_START(s, id, len) { EZ_BLOB_PK, 0, sizeof(s), .u.length = len }
-#define EZ_BLOB_INT8(s, id, f) { EZ_BLOB_INT8, id, offsetof(s, f) }
-#define EZ_BLOB_INT16(s, id, f) { EZ_BLOB_INT16, id, offsetof(s, f) }
-#define EZ_BLOB_INT32(s, id, f) { EZ_BLOB_INT32, id, offsetof(s, f) }
-#define EZ_BLOB_INT64(s, id, f) { EZ_BLOB_INT64, id, offsetof(s, f) }
-#define EZ_BLOB_FLOAT32(s, id, f) { EZ_BLOB_FLOAT32, id, offsetof(s, f) }
-#define EZ_BLOB_FLOAT64(s, id, f) { EZ_BLOB_FLOAT64, id, offsetof(s, f) }
-#define EZ_BLOB_STRING(s, id, f) { EZ_BLOB_STRING, id, offsetof(s, f) }
-#define EZ_BLOB_STRING_NULL(s, id, f) { EZ_BLOB_STRING | EZ_BLOB_NULLABLE, id, offsetof(s, f) }
-#define EZ_BLOB_BLOB(s, id, f) { EZ_BLOB_BLOB, id, offsetof(s, f) }
-#define EZ_BLOB_STRUCT(s, id, f, other) { EZ_BLOB_STRUCT, id, offsetof(s, f), .u.table = other }
-#define EZ_BLOB_POINTER(s, id, f, other) { EZ_BLOB_POINTER, id, offsetof(s, f), .u.table = other }
-#define EZ_BLOB_POINTER_NULL(s, id, f, other) { EZ_BLOB_POINTER | EZ_BLOB_NULLABLE, id, offsetof(s, f), .u.table = other }
-#define EZ_BLOB_LIST(s, id, f, other) { EZ_BLOB_LIST, id, offsetof(s, f), .u.table = other }
+#define EZ_BLOB_START(s, id, len) { EZ_BLOB_MAGIC, id, sizeof(s), .bd_length = len }
+
+#define EZ_BLOB_INT8(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
+#define EZ_BLOB_INT16(s, id, f) { EZ_BLOB_INT16 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
+#define EZ_BLOB_INT32(s, id, f) { EZ_BLOB_INT32 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
+#define EZ_BLOB_INT64(s, id, f) { EZ_BLOB_INT64 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
+#define EZ_BLOB_FLOAT32(s, id, f) { EZ_BLOB_FLOAT32 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
+#define EZ_BLOB_FLOAT64(s, id, f) { EZ_BLOB_FLOAT64 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
+
+#define EZ_BLOB_INT8V(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
+#define EZ_BLOB_INT16V(s, id, f) { EZ_BLOB_INT16 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
+#define EZ_BLOB_INT32V(s, id, f) { EZ_BLOB_INT32 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
+#define EZ_BLOB_INT64V(s, id, f) { EZ_BLOB_INT64 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
+#define EZ_BLOB_FLOAT32V(s, id, f) { EZ_BLOB_FLOAT32 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
+#define EZ_BLOB_FLOAT64V(s, id, f) { EZ_BLOB_FLOAT64 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
+
+#define EZ_BLOB_STRING(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_CSTRING, id, offsetof(s, f) }
+#define EZ_BLOB_STRINGN(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_CSTRING | EZ_BLOB_ISNULLABLE, id, offsetof(s, f) }
+
+#define EZ_BLOB_STRUCT(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_SINGLE, id, offsetof(s, f), .bd_table = other }
+#define EZ_BLOB_STRUCTP(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP, id, offsetof(s, f), .bd_table = other }
+#define EZ_BLOB_STRUCTPN(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), .bd_table = other }
+
+#define EZ_BLOB_LIST(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_LIST, id, offsetof(s, f), .bd_table = other }
+#define EZ_BLOB_LISTPN(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_LISTP | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), .bd_table = other }
/**
* Allocate a new structure to hold a blob.
void ez_blob_free_raw(const ez_blob_desc *d, void *p);
/**
- * Debug function to dump blob contents.
+ * Debug function to dump structured blob contents.
*/
void ez_blob_print(const ez_blob_desc *d, const void *a, int depth);
+/**
+ * Debug/utility function to dump hexadeximal+ascii display.
+ */
+void ez_blob_dump(const ez_blob *blob, const char *prefix);
+
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <assert.h>
+#include <errno.h>
#include "ez-blob.h"
#include "ez-list.h"
-#include "ez-blob-blob.h"
#include "ez-blob-tagz.h"
#include "ez-blob-xdrn.h"
With explicit knowledge of format, it should fail on corrupt meta-data.
*/
+static int doprint = 1;
+static int dolarge = 0;
+
struct simple {
char b;
short s;
EZ_BLOB_START(struct arrays, 0, 3),
EZ_BLOB_INT32(struct arrays, 1, count),
EZ_BLOB_STRING(struct arrays, 2, string),
- EZ_BLOB_BLOB(struct arrays, 3, array),
+ EZ_BLOB_INT8V(struct arrays, 3, array),
};
struct embedded {
static const ez_blob_desc tree_DESC[] = {
EZ_BLOB_START(struct tree, 0, 3),
EZ_BLOB_STRING(struct tree, 1, s),
- EZ_BLOB_POINTER_NULL(struct tree, 2, left, tree_DESC),
- EZ_BLOB_POINTER_NULL(struct tree, 3, right, tree_DESC),
+ EZ_BLOB_STRUCTPN(struct tree, 2, left, tree_DESC),
+ EZ_BLOB_STRUCTPN(struct tree, 3, right, tree_DESC),
};
struct listnode {
static const ez_blob_desc listnode_DESC[] = {
EZ_BLOB_START(struct listnode, 0, 2),
EZ_BLOB_STRING(struct listnode, 1, name),
- EZ_BLOB_BLOB(struct listnode, 2, value),
+ EZ_BLOB_INT8V(struct listnode, 2, value),
};
struct list {
};
static void dumphex(const char *data, size_t size, const char *prefix) {
- blobio_dumphex(data, size, prefix);
+ ez_blob blob = { .eb_size = size, .eb_data = (void *)data };
+ ez_blob_dump(&blob, prefix);
}
static void blob_print(const ez_blob_desc *d, const void *a, int depth) {
case EZ_BLOB_FLOAT64:
e &= (*(double *)u) == (*(double *)v);
break;
- case EZ_BLOB_STRING | EZ_BLOB_NULLABLE:
+
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8 | EZ_BLOB_ISNULLABLE:
if (!*(char **)u || !*(char **)v) {
e &= (*(char **)u) == (*(char **)v);
break;
}
- // falls through
- case EZ_BLOB_STRING:
+ case EZ_BLOB_CSTRING | EZ_BLOB_INT8:
if (!*(char **)u || !*(char **)v) {
printf("strings can't be null\n");
e = 0;
e &= strcmp(*(char **)u, *(char **)v) == 0;
}
break;
- case EZ_BLOB_BLOB: {
+
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT8:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT16:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_INT64:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT32:
+ case EZ_BLOB_VECTOR | EZ_BLOB_FLOAT64: {
const struct ez_blob *ua = u;
const struct ez_blob *va = v;
- e &= ua->size == va->size
- && memcmp(ua->data, va->data, ua->size) == 0;
+ e &= ua->eb_size == va->eb_size
+ && memcmp(ua->eb_data, va->eb_data, ua->eb_size) == 0;
break;
}
- case EZ_BLOB_STRUCT:
- e &= blob_equals(d->bd_table, u, v);
- break;
- case EZ_BLOB_POINTER | EZ_BLOB_NULLABLE:
+
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE:
if (!*(void **)u || !*(void **)v) {
e &= *(void **)u == *(void **)v;
break;
}
- // falls through
- case EZ_BLOB_POINTER:
- e &= blob_equals(d->bd_table, *(void **)u, *(void **)v);
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP:
+ u = *(void **)u;
+ v = *(void **)v;
+ case EZ_BLOB_STRUCT | EZ_BLOB_SINGLE:
+ if (!u || !v) {
+ printf("structs p can't be null\n");
+ e = 0;
+ } else {
+ e &= blob_equals(d->bd_table, u, v);
+ }
break;
- case EZ_BLOB_LIST: {
- ez_list *ul = (void *)u;
- ez_list *vl = (void *)v;
-
- e &= ez_list_size(ul) == ez_list_size(vl);
- for (ez_node *uw = ez_list_head(ul), *un = ez_node_succ(uw),
- *vw = ez_list_head(vl), *vn = ez_node_succ(uw);
- un && vn;
- uw = un, un = ez_node_succ(un),
- vw = vn, vn = ez_node_succ(vn)) {
- e &= blob_equals(d->bd_table, uw, vw);
+
+
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP | EZ_BLOB_ISNULLABLE:
+ if (!*(void **)u || !*(void **)v) {
+ e &= *(void **)u == *(void **)v;
+ break;
}
+ case EZ_BLOB_STRUCT | EZ_BLOB_LISTP:
+ u = *(void **)u;
+ v = *(void **)v;
+ case EZ_BLOB_STRUCT | EZ_BLOB_LIST:
+ if (!u || !v) {
+ printf("lists p can't be null\n");
+ e = 0;
+ } else {
+ ez_list *ul = (void *)u;
+ ez_list *vl = (void *)v;
+
+ e &= ez_list_size(ul) == ez_list_size(vl);
+ for (ez_node *uw = ez_list_head(ul), *un = ez_node_succ(uw),
+ *vw = ez_list_head(vl), *vn = ez_node_succ(uw);
+ e && un && vn;
+ uw = un, un = ez_node_succ(un),
+ vw = vn, vn = ez_node_succ(vn)) {
+ e &= blob_equals(d->bd_table, uw, vw);
+ }
+ }
break;
- }
+
default:
printf("cmp unknown field type=%d id=%d\n", d->bd_type, d->bd_id);
e = 0;
break;
}
+
if (!e) {
printf("cmp failed in struct %d at field %d type %04x\n", desc->bd_id, d->bd_id, d->bd_type);
abort();
int (*blob_decode_raw)(const ez_blob_desc *desc, const ez_blob *blob, void *p);
};
-static int doprint = 1;
-
static void test_basics(const ez_blob_desc *d, void *src, struct test_funcs *funcs) {
ez_blob blob, blob2;
void *t;
}
res = funcs->blob_encode(d, src, &blob);
- if (res != 0) {
+ if (res == ENOMEM) {
printf(" encode failed: probably out of memory, skipped testing this\n");
return;
}
+ assert(res == 0);
+
if (doprint)
- dumphex(blob.data, blob.size, "serial: ");
+ dumphex(blob.eb_data, blob.eb_size, "serial: ");
else
- dumphex(blob.data, blob.size < 256 ? blob.size : 256, "header: ");
+ dumphex(blob.eb_data, blob.eb_size < 256 ? blob.eb_size : 256, "header: ");
// check decode equals
t = funcs->blob_decode(d, &blob);
// check encode-decoded equals source
res = funcs->blob_encode(d, t, &blob2);
assert(res == 0);
- assert(blob.size == blob2.size);
- assert(memcmp(blob.data, blob2.data, blob2.size) == 0);
- free(blob2.data);
+ assert(blob.eb_size == blob2.eb_size);
+ assert(memcmp(blob.eb_data, blob2.eb_data, blob2.eb_size) == 0);
+ free(blob2.eb_data);
ez_blob_free(d, t);
assert((tmp[i + 32 + dsize] & 0xff) == 0xbe);
}
ez_blob_free_raw(d, tmp+32);
- free(blob.data);
+ free(blob.eb_data);
}
static void test_simple(struct test_funcs *funcs) {
struct arrays src = {
32,
"Bob was here.",
- .array.size = 7,
- .array.data = data
+ .array.eb_size = 7,
+ .array.eb_data = data
};
const ez_blob_desc *d = array_DESC;
-1, -1, -1, -1, 1337.4004, 6.022E23,
},
{
- 55, "Jane was there.", .array.size = 10, .array.data = data
+ 55, "Jane was there.", .array.eb_size = 10, .array.eb_data = data
}
};
const ez_blob_desc *d = embed_DESC;
.list = EZ_INIT_LIST(list.list)
};
struct listnode nodes[3] = {
- { .name = "node 0", .value.size = 5, .value.data = "data0" },
- { .name = "node 1", .value.size = 5, .value.data = "data1" },
- { .name = "node 2", .value.size = 5, .value.data = "data2" },
+ { .name = "node 0", .value.eb_size = 5, .value.eb_data = "data0" },
+ { .name = "node 1", .value.eb_size = 5, .value.eb_data = "data1" },
+ { .name = "node 2", .value.eb_size = 5, .value.eb_data = "data2" },
};
list.name = "a list";
size_t size = sizes[i];
// only tagz supports >32 bit counts
- if (size >= 0x100000000ULL
- && strcmp(funcs->name, "tagz") != 0) {
+ if (!dolarge
+ || (size >= 0x100000000ULL
+ && strcmp(funcs->name, "tagz") != 0)) {
printf("skip string size %zd\n", size);
continue;
}
// however they should not crash, cause leaks, or valgrind oddness.
static void test_corrupt_bit(struct test_funcs *funcs) {
- // this is definitely not robust
- if (strcmp(funcs->name, "legacy") == 0) {
- printf("Not supposed to be safe\n");
- return;
- }
-
char data[10] = { 1, 2, 3, 4, 5, 6, 7, 1, 2, 3 };
struct embedded src = {
{
-1, -1, -1, -1, 1337.4004, 6.022E23,
},
{
- 55, "Jane was there.", .array.size = 10, .array.data = data
+ 55, "Jane was there.", .array.eb_size = 10, .array.eb_data = data
}
};
const ez_blob_desc *d = embed_DESC;
int good = 0, bad = 0;
res = funcs->blob_encode(d, &src, &blob);
assert(res == 0);
- for (int i=0;i<blob.size;i++) {
- uint8_t *data = blob.data;
+ for (int i=0;i<blob.eb_size;i++) {
+ uint8_t *data = blob.eb_data;
for (int j=0;j<8;j++) {
data[i] ^= (1<<j);
dst = funcs->blob_decode(d, &blob);
}
}
}
- free(blob.data);
+ free(blob.eb_data);
printf(" info: %d failed, %d decoded - but not important\n", bad, good);
}
static void test_corrupt_byte(struct test_funcs *funcs) {
- // this is definitely not robust
- if (strcmp(funcs->name, "legacy") == 0) {
- printf("Not supposed to be safe\n");
- return;
- }
-
char data[10] = { 1, 2, 3, 4, 5, 6, 7, 1, 2, 3 };
struct embedded src = {
{
-1, -1, -1, -1, 1337.4004, 6.022E23,
},
{
- 55, "Jane was there.", .array.size = 10, .array.data = data
+ 55, "Jane was there.", .array.eb_size = 10, .array.eb_data = data
}
};
const ez_blob_desc *d = embed_DESC;
int good = 0, bad = 0;
res = funcs->blob_encode(d, &src, &blob);
assert(res == 0);
- for (int i=0;i<blob.size;i++) {
- uint8_t *data = blob.data;
+ for (int i=0;i<blob.eb_size;i++) {
+ uint8_t *data = blob.eb_data;
uint8_t save = data[i];
for (int j=0;j<256;j++) {
}
data[i] = save;
}
- free(blob.data);
+ free(blob.eb_data);
printf(" info: %d failed, %d decoded - but not important\n", bad, good);
}
struct test_funcs backends[] = {
- {
- "legacy",
- ez_blob_encode,
- ez_blob_decode,
- ez_blob_decode_raw
- },
{
"tagz",
ez_tagz_encode,
int nfunc = sizeof(backends)/sizeof(backends[0]);
int ntest = sizeof(tests)/sizeof(tests[0]);
+ dolarge = (argc >= 2);
+
for (int i=0;i<nfunc;i++) {
struct test_funcs *f = &backends[i];