From 3a5219ce4e5faaef68aa4f18dfa7980d43da746f Mon Sep 17 00:00:00 2001 From: Not Zed Date: Thu, 2 May 2019 18:00:49 +0930 Subject: [PATCH] Redid the way struct fields are described to allow for combinatorial variations. Added arrays of other primitives beyond bytes. Namespace cleanup. Exposed data-dump function. Delete old serialiser. Implement all changes in xdrn/tagz formats. --- Makefile | 7 +- ez-blob-blob.c | 367 ------------------------------------------ ez-blob-blob.h | 76 --------- ez-blob-dump.c | 48 ++++++ ez-blob-io.c | 32 +--- ez-blob-print.c | 75 +++++---- ez-blob-tagz.c | 420 ++++++++++++++++++++++++++---------------------- ez-blob-xdrn.c | 359 ++++++++++++++++++++++++++++------------- ez-blob.c | 66 +++++--- ez-blob.h | 109 ++++++++----- test-blob.c | 165 ++++++++++--------- 11 files changed, 784 insertions(+), 940 deletions(-) delete mode 100644 ez-blob-blob.c delete mode 100644 ez-blob-blob.h create mode 100644 ez-blob-dump.c diff --git a/Makefile b/Makefile index 5a3fc12..f16320f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ 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 @@ -11,7 +11,7 @@ SRCS= \ 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 \ @@ -22,7 +22,6 @@ HEADERS = \ ez-bitset.h \ ez-blob.h \ ez-blobio.h \ - ez-blob-blob.h \ ez-blob-tagz.h \ ez-blob-xdrn.h \ ez-list.h \ @@ -52,7 +51,7 @@ test-%: test-%.o 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) diff --git a/ez-blob-blob.c b/ez-blob-blob.c deleted file mode 100644 index ecc61a3..0000000 --- a/ez-blob-blob.c +++ /dev/null @@ -1,367 +0,0 @@ -/* 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 - . -*/ - -#include -#include -#include - -#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;ibd_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;ibd_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 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;ibd_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; -} diff --git a/ez-blob-blob.h b/ez-blob-blob.h deleted file mode 100644 index 53c9b8c..0000000 --- a/ez-blob-blob.h +++ /dev/null @@ -1,76 +0,0 @@ -/* 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 - . -*/ - -/* - * 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); - diff --git a/ez-blob-dump.c b/ez-blob-dump.c new file mode 100644 index 0000000..db46661 --- /dev/null +++ b/ez-blob-dump.c @@ -0,0 +1,48 @@ +/* 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 + . +*/ + +#include +#include +#include + +#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 #include #include -#include +#include #include "ez-blob.h" #include "ez-blob-io.h" @@ -50,7 +50,7 @@ void *blobio_reserve(struct ez_blobio * __restrict io, size_t len) { alloc = realloc(io->data, size); if (!alloc) { - io->error = 1; + io->error = ENOMEM; printf("realloc failed\n"); ABORT(); return NULL; @@ -65,7 +65,7 @@ void *blobio_reserve(struct ez_blobio * __restrict io, size_t len) { case BLOBIO_WRITE_FIXED: if (to > size) { - io->error = 1; + io->error = EOVERFLOW; ABORT(); return NULL; } @@ -75,7 +75,9 @@ void *blobio_reserve(struct ez_blobio * __restrict io, size_t len) { case BLOBIO_WRITE_SIZE: io->index = to; + return NULL; default: + io->error = EINVAL; return NULL; } } @@ -90,7 +92,7 @@ void *blobio_take(struct ez_blobio * __restrict io, size_t len) { } else { ABORT(); io->index = io->size; - io->error = 1; + io->error = EOVERFLOW; return NULL; } } @@ -110,25 +112,3 @@ void blobio_read_align(struct ez_blobio *io, unsigned int step) { blobio_take(io, skip); } - -void blobio_dumphex(const char *data, size_t size, const char *prefix) { - for (int i=0;i #include -#include #include "ez-blob.h" #include "ez-list.h" @@ -40,9 +39,9 @@ void ez_blob_print(const ez_blob_desc *d, const void *a, int depth) { 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; @@ -61,44 +60,64 @@ void ez_blob_print(const ez_blob_desc *d, const void *a, int depth) { 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; } } } diff --git a/ez-blob-tagz.c b/ez-blob-tagz.c index 1c6b7f1..467eba7 100644 --- a/ez-blob-tagz.c +++ b/ez-blob-tagz.c @@ -85,10 +85,31 @@ final note: */ +/* + 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 #include #include #include +#include #include "ez-list.h" @@ -99,6 +120,7 @@ final note: //#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 @@ -149,7 +171,7 @@ static int size_code(uint64_t size) { else if (size <= 0xffffffff) return 0x2; else - return 0x3; + return 0x3; } static int tag_code(uint32_t size) { @@ -181,81 +203,95 @@ static void blobio_writetc(struct ez_blobio *io, uint8_t type, uint32_t tag, uin 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;ibd_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; } } @@ -274,8 +310,8 @@ size_t ez_tagz_size(const ez_blob_desc *d, const void *p) { 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 }; @@ -292,15 +328,16 @@ int ez_tagz_encode(const ez_blob_desc *d, const void *p, ez_blob *blob) { 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) { @@ -325,6 +362,10 @@ static uint64_t blobio_readi(struct ez_blobio *io, int sc) { 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; @@ -355,131 +396,132 @@ static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, v 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<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 @@ -506,55 +548,48 @@ static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, v } 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) { @@ -578,7 +613,7 @@ static void tagz_dump_struct(struct ez_blobio *io, int depth) { 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); @@ -601,17 +636,17 @@ static void tagz_dump_struct(struct ez_blobio *io, int 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; @@ -633,8 +668,9 @@ static void tagz_dump_fields(struct ez_blobio *io, int depth) { if (use_count) { void *v = blobio_take(io, fcount * (1<data, - .size = blob->size, + .data = blob->eb_data, + .size = blob->eb_size, .mode = BLOBIO_READ }; diff --git a/ez-blob-xdrn.c b/ez-blob-xdrn.c index 28a94d2..057ff49 100644 --- a/ez-blob-xdrn.c +++ b/ez-blob-xdrn.c @@ -18,12 +18,30 @@ */ /* - 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. */ @@ -31,6 +49,8 @@ #include #include +#include + #include "ez-list.h" #include "ez-blob.h" @@ -42,76 +62,176 @@ static __inline__ size_t roundup(size_t v) { 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;ibd_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; } } @@ -128,8 +248,8 @@ size_t ez_xdrn_size(const ez_blob_desc *d, const void *p) { 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 }; @@ -146,135 +266,142 @@ int ez_xdrn_encode(const ez_blob_desc *d, const void *p, ez_blob *blob) { 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;ibd_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;jbd_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) { diff --git a/ez-blob.c b/ez-blob.c index 66b7856..683ac4e 100644 --- a/ez-blob.c +++ b/ez-blob.c @@ -30,29 +30,52 @@ void ez_blob_free_raw(const ez_blob_desc *desc, void *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; + 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; } @@ -72,11 +95,18 @@ void ez_blob_init(const ez_blob_desc *desc, void *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; + 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; + } } } diff --git a/ez-blob.h b/ez-blob.h index 6ee3f05..f316bd6 100644 --- a/ez-blob.h +++ b/ez-blob.h @@ -29,9 +29,8 @@ * 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: * @@ -56,60 +55,89 @@ */ 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. @@ -148,8 +176,13 @@ void ez_blob_free(const ez_blob_desc *d, void *p); 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 diff --git a/test-blob.c b/test-blob.c index 67f93c9..8ccb92f 100644 --- a/test-blob.c +++ b/test-blob.c @@ -3,14 +3,13 @@ #include #include #include -#include #include +#include #include "ez-blob.h" #include "ez-list.h" -#include "ez-blob-blob.h" #include "ez-blob-tagz.h" #include "ez-blob-xdrn.h" @@ -33,6 +32,9 @@ 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; @@ -62,7 +64,7 @@ static const ez_blob_desc array_DESC[] = { 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 { @@ -86,8 +88,8 @@ struct tree { 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 { @@ -99,7 +101,7 @@ 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 { @@ -136,7 +138,8 @@ static const ez_blob_desc stringsize_DESC[] = { }; 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) { @@ -169,13 +172,13 @@ static int blob_equals(const ez_blob_desc *desc, const void *a, const void *b) { 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; @@ -183,46 +186,73 @@ static int blob_equals(const ez_blob_desc *desc, const void *a, const void *b) { 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(); @@ -239,8 +269,6 @@ struct test_funcs { 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; @@ -254,14 +282,16 @@ static void test_basics(const ez_blob_desc *d, void *src, struct test_funcs *fun } 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); @@ -276,9 +306,9 @@ static void test_basics(const ez_blob_desc *d, void *src, struct test_funcs *fun // 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); @@ -295,7 +325,7 @@ static void test_basics(const ez_blob_desc *d, void *src, struct test_funcs *fun 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) { @@ -313,8 +343,8 @@ static void test_arrays(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; @@ -329,7 +359,7 @@ static void test_struct(struct test_funcs *funcs) { -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; @@ -359,9 +389,9 @@ static void test_list(struct test_funcs *funcs) { .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"; @@ -404,8 +434,9 @@ static void test_stringsize(struct test_funcs *funcs) { 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; } @@ -430,19 +461,13 @@ static void test_stringsize(struct test_funcs *funcs) { // 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; @@ -458,8 +483,8 @@ static void test_corrupt_bit(struct test_funcs *funcs) { int good = 0, bad = 0; res = funcs->blob_encode(d, &src, &blob); assert(res == 0); - for (int i=0;iblob_decode(d, &blob); @@ -473,24 +498,18 @@ static void test_corrupt_bit(struct test_funcs *funcs) { } } } - 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; @@ -501,8 +520,8 @@ static void test_corrupt_byte(struct test_funcs *funcs) { int good = 0, bad = 0; res = funcs->blob_encode(d, &src, &blob); assert(res == 0); - for (int i=0;i= 2); + for (int i=0;i