0 1 byte
1 2 byte
2 4 byte
- 3 reserved, no tag?
+ 3 use the count size for tt instead, and there is no count byte
cc log2 of count size in bytes, used to indicate sequence length or non-sequence.
0 1 byte
1 2 byte
2 4 byte
- 3 none, single item follows
+ 3 8 byte
ff is struct-end code
A header is a control byte followed by an optional 1/2/4 byte-length tag,
- followed by an optional 1/2/4 byte-length count.
+ followed by an optional 1/2/4/8 byte-length count.
A structure payload is a list of tagged fields until a struct-end
code. A structure sequence is a list of count struct-encoded blocks.
#define EZT_TAGSIZE (0x3 << EZT_TAGSHIFT)
#define EZT_DATASIZE (0x3 << EZT_DATASHIFT)
-#define EZT_NOCOUNT (0x3 << EZT_COUNTSHIFT)
+#define EZT_NOCOUNT (0x3 << EZT_TAGSHIFT)
#define EZT_END 0xff // well, end-struct
return 0x3;
}
-static int count_code(uint32_t size) {
+static int tag_code(uint32_t size) {
if (size <= 0xff)
return 0x0;
else if (size <= 0xffff)
return 0x2;
}
+// tag single item, tt=11 and cc=tag
static void blobio_writet(struct ez_blobio *io, uint8_t type, uint32_t tag) {
- int tc = size_code(tag);
+ int tc = tag_code(tag);
- blobio_writeb(io, type | (tc << EZT_TAGSHIFT));
+ blobio_writeb(io, type | EZT_NOCOUNT | (tc << EZT_COUNTSHIFT));
blobio_writei(io, tc, tag);
}
+// tag counted item, tt=tag, cc=count
+static void blobio_writetc(struct ez_blobio *io, uint8_t type, uint32_t tag, uint64_t count) {
+ int tc = tag_code(tag);
+ int cc = size_code(count);
+
+ blobio_writeb(io, type | (tc << EZT_TAGSHIFT) | (cc << EZT_COUNTSHIFT));
+ blobio_writei(io, tc, tag);
+ blobio_writei(io, cc, count);
+}
+
static void tagz_encode_struct(struct ez_blobio *io, int id, const ez_blob_desc *desc, const void *p) {
- blobio_writet(io, EZT_STRUCT | EZT_NOCOUNT, id);
+ 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;
- uint32_t count = 0;
+ uint64_t count = 0;
const void *ptr = NULL;
switch (d->bd_type & EZ_BLOB_TYPE) {
if (val) {
int sc = size_code(val);
- blobio_writet(io, EZT_INT8 | EZT_NOCOUNT | (sc << EZT_DATASHIFT), d->bd_id);
+ blobio_writet(io, EZT_INT8 | (sc << EZT_DATASHIFT), d->bd_id);
blobio_writei(io, sc, val);
}
break;
case EZ_BLOB_FLOAT32:
- blobio_writet(io, EZT_FLOAT32 | EZT_NOCOUNT, d->bd_id);
+ blobio_writet(io, EZT_FLOAT32, d->bd_id);
blobio_writef(io, *(const float *)v);
break;
case EZ_BLOB_FLOAT64:
- blobio_writet(io, EZT_FLOAT64 | EZT_NOCOUNT, d->bd_id);
+ blobio_writet(io, EZT_FLOAT64, d->bd_id);
blobio_writed(io, *(const double *)v);
break;
case EZ_BLOB_STRING:
// empty blobs are the default, so implement same, empty are not encoded
count = ((ez_blob *)v)->size;
if (count) {
- int cc;
-
ptr = ((ez_blob *)v)->data;
doblob:
- cc = count_code(count);
- blobio_writet(io, EZT_INT8 | (cc << EZT_COUNTSHIFT), d->bd_id);
- blobio_writei(io, cc, count);
+ blobio_writetc(io, EZT_INT8, d->bd_id, count);
blobio_write(io, ptr, count);
}
break;
case EZ_BLOB_LIST:
count = ez_list_size((ez_list *)v);
if (count) {
- int cc = count_code(count);
-
- blobio_writet(io, EZT_STRUCT | (cc << EZT_COUNTSHIFT), d->bd_id);
- blobio_writei(io, cc, 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;
blob->data = io.data;
return 0;
}
- free(blob->data);
+ free(io.data);
blob->data = 0;
blob->size = 0;
while ((h = blobio_readb(io)) != EZT_END) {
uint32_t ftag;
- uint32_t fcount = 0;
- int sc = (h & EZT_DATASIZE) >> EZT_DATASHIFT; /* for primitives */
- int use_count = 0;
-
- ftag = blobio_readi(io, (h & EZT_TAGSIZE) >> EZT_TAGSHIFT);
- if ((h & EZT_COUNTSIZE) != EZT_NOCOUNT) {
- fcount = blobio_readi(io, (h & EZT_COUNTSIZE) >> EZT_COUNTSHIFT);
- use_count = 1;
- }
+ uint64_t fcount;
+ int sc = (h >> EZT_DATASHIFT) & 3;
+ int tc = (h >> EZT_TAGSHIFT) & 3;
+ int cc = (h >> EZT_COUNTSHIFT) & 3;
+ int use_count = tc != 3;
+
+ tc = tc != 3 ? tc : cc;
+ ftag = blobio_readi(io, tc);
+ fcount = use_count ? blobio_readi(io, cc) : 1;
// This forces the tags to be in order
// It ensures each field can only be visited once
}
}
break;
+ default:
+ goto error;
}
} else {
// Just skip fields
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;
- //uint32_t scount = 1;
-
- // must be a struct
- // what about a struct list? hmm
- if (io->error || (h & EZT_TYPE) != EZT_STRUCT) {
- //io->error = 1;
- return;
- }
+ int tc = (h >> EZT_TAGSHIFT) & 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;
- stag = blobio_readi(io, (h & EZT_TAGSIZE) >> EZT_TAGSHIFT);
+ // unused, but could check against desc->bd_id
+ stag = blobio_readi(io, cc);
stag = stag;
- //if (stag != desc->bd_id) {
- // ??
- //}
- //if (h & EZT_COUNTSIZE)
- // count = blobio_readi(io, (h & EZT_COUNTSIZE) >> EZT_COUNTSHIFT);
- // read fields
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) {
/* ********************************************************************** */
// TODO: move to separate .o
+// TODO: copy fail behaviour of decode()
static void tagz_dump_struct(struct ez_blobio *io, int depth);
static void tagz_dump_fields(struct ez_blobio *io, int depth);
static void tagz_dump_struct(struct ez_blobio *io, int depth) {
uint8_t h = blobio_readb(io);
uint32_t stag;
- //uint32_t scount = 1;
+ int tc = (h >> EZT_TAGSHIFT) & 3;
+ int cc = (h >> EZT_COUNTSHIFT) & 3;
char s[depth+1];
memset(s, ' ', depth);
s[depth] = 0;
- // must be a struct
- // what about a struct list? hmm
- if ((h & EZT_TYPE) != EZT_STRUCT)
+ // must be a struct with tc=11 and cc!=11
+ if ((h & EZT_TYPE) != EZT_STRUCT) {
+ printf(" not a struct\n");
+ return;
+ }
+ if (tc != 3) {
+ printf(" not a unitary object tc=%d\n", tc);
+ return;
+ }
+ if (cc == 3) {
+ printf(" invalid tag size %d\n", cc);
return;
+ }
- stag = blobio_readi(io, (h & EZT_TAGSIZE) >> EZT_TAGSHIFT);
- //if (h & EZT_COUNTSIZE)
- // count = blob_readi(io, (h & EZT_COUNTSIZE) >> EZT_COUNTSHIFT);
+ stag = blobio_readi(io, cc);
printf("%s[%02x] %d = {\n", s, h, stag);
// read fields
while ((h = blobio_readb(io)) != EZT_END) {
uint32_t ftag;
- uint32_t fcount = 0;
- int sc = (h & EZT_DATASIZE) >> EZT_DATASHIFT;
- int use_count = 0;
-
- ftag = blobio_readi(io, (h & EZT_TAGSIZE) >> EZT_TAGSHIFT);
- if ((h & EZT_COUNTSIZE) != EZT_NOCOUNT) {
- fcount = blobio_readi(io, (h & EZT_COUNTSIZE) >> EZT_COUNTSHIFT);
- use_count = 1;
- }
+ uint64_t fcount;
+ int sc = (h >> EZT_DATASHIFT) & 3;
+ int tc = (h >> EZT_TAGSHIFT) & 3;
+ int cc = (h >> EZT_COUNTSHIFT) & 3;
+ int use_count = tc != 3;
+
+ tc = tc != 3 ? tc : cc;
+ ftag = blobio_readi(io, tc);
+ fcount = use_count ? blobio_readi(io, cc) : 1;
switch (h & EZT_TYPE) {
case EZT_INT8:
if (use_count) {
void *v = blobio_take(io, fcount * (1<<sc));
if (v) {
- printf("%s[%02x] integer-%-2d %d [%d] = {\n", s, h, (1<<sc)*8, ftag, fcount);
+ printf("%s[%02x] integer-%-2d %d [%ld] = {\n", s, h, (1<<sc)*8, ftag, fcount);
blobio_dumphex(v, fcount * (1<<sc), s);
printf("%s}\n", s);
}
break;
case EZT_FLOAT32:
if (use_count) {
- printf("%sfloat %d [%d] = {\n", s, ftag, fcount);
+ printf("%sfloat %d [%ld] = {\n", s, ftag, fcount);
for (int i=0;i<fcount;i++)
printf(" %f\n", blobio_readf(io));
printf("%s}\n", s);
break;
case EZT_FLOAT64:
if (use_count) {
- printf("%s%d double[%d] = {\n", s, ftag, fcount);
+ printf("%s%d double[%ld] = {\n", s, ftag, fcount);
for (int i=0;i<fcount;i++)
printf("%s %f\n", s, blobio_readd(io));
printf("%s}\n", s);
break;
case EZT_STRUCT:
if (use_count) {
- printf("%sstruct %d [%d] = {\n", s, ftag, fcount);
+ printf("%sstruct %d [%ld] = {\n", s, ftag, fcount);
for (int i=0;i<fcount;i++) {
tagz_dump_struct(io, depth+4);
}
printf("%s[%02x] ??\n", s, h);
break;
}
- printf("%s[%02x] END $%04lx\n", s, h, io->index-1);
- printf("%s}\n", s);
}
+ printf("%s[%02x] END $%04lx\n", s, h, io->index-1);
+ printf("%s}\n", s);
}
/**
}
res = funcs->blob_encode(d, src, &blob);
- assert(res == 0);
+ if (res != 0) {
+ printf(" encode failed: probably out of memory, skipped testing this\n");
+ return;
+ }
if (doprint)
dumphex(blob.data, blob.size, "serial: ");
-
+ else
+ dumphex(blob.data, blob.size < 256 ? blob.size : 256, "header: ");
+
// check decode equals
t = funcs->blob_decode(d, &blob);
assert(t != NULL);
assert(blob_equals(d, t, src));
// check encode-decoded equals source
- funcs->blob_encode(d, t, &blob2);
+ 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);
-
+
ez_blob_free(d, t);
// check raw decode stays within bounds of struct
}
static void test_stringsize(struct test_funcs *funcs) {
- int sizes[6] = { 0, 1, 255, 256, 65535, 65536 };
+ size_t sizes[7] = { 0, 1, 255, 256, 65535, 65536, 0x100000000ULL };
const ez_blob_desc *d = stringsize_DESC;
struct stringsize src;
int sprint = doprint;
- for (int i=0;i<6;i++) {
- int size = sizes[i];
+ for (int i=0;i<7;i++) {
+ size_t size = sizes[i];
+
+ // only tagz supports >32 bit counts
+ if (size >= 0x100000000ULL
+ && strcmp(funcs->name, "tagz") != 0) {
+ printf("skip string size %zd\n", size);
+ continue;
+ }
+
src.value = malloc(size+1);
- memset(src.value, ' ', size);
- src.value[size] = 0;
- printf("test string size %d\n", size);
- doprint = size <= 256;
- test_basics(d, &src, funcs);
- free(src.value);
+ if (src.value) {
+ memset(src.value, ' ', size);
+ src.value[size] = 0;
+ printf("test string size %zd\n", size);
+ doprint = size <= 256;
+ test_basics(d, &src, funcs);
+ free(src.value);
+ } else {
+ printf("skip string size %zd: memory allocation failed\n", size);
+ }
}
doprint = sprint;
}