From ca03b3431858a95e2c7e5aed80cfb1b9ff47a40b Mon Sep 17 00:00:00 2001 From: Steve Dee Date: Thu, 20 Feb 2014 17:12:59 -0800 Subject: [PATCH] Implement serialization to buffers --- capn-malloc.c | 58 ++++++++++++++++++++++++ capn-stream-test.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++ capn.h | 7 +++ 3 files changed, 168 insertions(+) diff --git a/capn-malloc.c b/capn-malloc.c index e1379c4..e98736b 100644 --- a/capn-malloc.c +++ b/capn-malloc.c @@ -155,3 +155,61 @@ int capn_init_mem(struct capn *c, const uint8_t *p, size_t sz, int packed) { z.avail_in = sz; return init_fp(c, NULL, &z, packed); } + +int +capn_write_mem(struct capn *c, uint8_t *p, size_t sz, int packed) +{ + struct capn_segment *seg; + struct capn_ptr root; + int i; + uint32_t headerlen; + size_t datasz; + uint32_t *header; + + if (c->segnum == 0) + return -1; + + root = capn_root(c); + /* segnum == 1: + * [segnum][segsiz] + * segnum == 2: + * [segnum][segsiz][segsiz][zeroes] + * segnum == 3: + * [segnum][segsiz][segsiz][segsiz] + * segnum == 4: + * [segnum][segsiz][segsiz][segsiz][segsiz][zeroes] + */ + headerlen = ((2 + c->segnum) / 2) * 2; + datasz = 4 * headerlen; + header = (uint32_t*) p; + + if (sz < datasz) + return -1; + + header[0] = capn_flip32(c->segnum - 1); + header[headerlen-1] = 0; + for (i = 0, seg = root.seg; i < c->segnum; i++, seg = seg->next) { + if (0 == seg) + return -1; + datasz += seg->len; + header[1 + i] = capn_flip32(seg->len / 8); + } + if (0 != seg) + return -1; + + if (sz < datasz) + return -1; + + p += 4 * headerlen; + sz -= 4 * headerlen; + + for (seg = root.seg; seg; seg = seg->next) { + if (sz < seg->len) + return -1; + memcpy(p, seg->data, seg->len); + p += seg->len; + sz -= seg->len; + } + + return datasz; +} diff --git a/capn-stream-test.cpp b/capn-stream-test.cpp index 9e137da..c5853bb 100644 --- a/capn-stream-test.cpp +++ b/capn-stream-test.cpp @@ -70,3 +70,106 @@ TEST(Stream, ReadStream_Even) { EXPECT_EQ(9, ctx.seglist->next->data[0]); capn_free(&ctx); } + +TEST(Stream, WriteEmptyStream) { + uint8_t buf[2048]; + + struct capn ctx1, ctx2; + capn_init_malloc(&ctx1); + struct capn_ptr root = capn_root(&ctx1); + ASSERT_EQ(CAPN_PTR_LIST, root.type); + EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 2*8-1, 0)); + EXPECT_EQ(2*8, capn_write_mem(&ctx1, buf, 2048, 0)); + ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 0)); + EXPECT_EQ(1, ctx2.segnum); + EXPECT_EQ(8, ctx2.seglist->len); + EXPECT_EQ(0, ctx2.seglist->next); + + capn_free(&ctx1); + capn_free(&ctx2); +} + +TEST(Stream, WriteOneSegment) { + uint8_t buf[2048]; + + struct capn ctx1, ctx2; + capn_init_malloc(&ctx1); + + struct capn_ptr root = capn_root(&ctx1); + struct capn_ptr ptr = capn_new_struct(root.seg, 8, 0); + EXPECT_EQ(0, capn_setp(root, 0, ptr)); + EXPECT_EQ(0, capn_write64(ptr, 0, UINT64_C(0x1011121314151617))); + + EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 3*8-1, 0)); + EXPECT_EQ(3*8, capn_write_mem(&ctx1, buf, 2048, 0)); + ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 0)); + EXPECT_EQ(1, ctx2.segnum); + + root = capn_root(&ctx2); + ptr = capn_getp(root, 0, 1); + EXPECT_EQ(UINT64_C(0x1011121314151617), capn_read64(ptr, 0)); + + capn_free(&ctx1); + capn_free(&ctx2); +} + +static struct capn_segment *CreateSmallSegment(void *u, uint32_t id, int sz) { + struct capn_segment *s = (struct capn_segment*) calloc(1, sizeof(*s)); + s->data = (char*) calloc(1, sz); + s->cap = sz; + return s; +} + +TEST(Stream, WriteTwoSegments) { + struct capn ctx1, ctx2; + uint8_t buf[5*8]; + + capn_init_malloc(&ctx1); + ctx1.create = &CreateSmallSegment; + struct capn_ptr root = capn_root(&ctx1); + struct capn_ptr ptr1 = capn_new_struct(root.seg, 8, 0); + EXPECT_EQ(0, capn_setp(root, 0, ptr1)); + EXPECT_EQ(0, capn_write64(ptr1, 0, UINT64_C(0xfffefdfcfbfaf9f8))); + EXPECT_EQ(2, ctx1.segnum); + + /* 2 words: header + * 1 word: segment 1 + * 2 words: segment 2 + */ + EXPECT_EQ(5*8, capn_write_mem(&ctx1, buf, 5*8, 0)); + + ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 0)); + root = capn_root(&ctx2); + ptr1 = capn_getp(root, 0, 1); + EXPECT_EQ(UINT64_C(0xfffefdfcfbfaf9f8), capn_read64(ptr1, 0)); + + capn_free(&ctx1); + capn_free(&ctx2); +} + +TEST(Stream, WriteThreeSegments) { + struct capn ctx1, ctx2; + uint8_t buf[2048]; + + capn_init_malloc(&ctx1); + ctx1.create = &CreateSmallSegment; + struct capn_ptr root = capn_root(&ctx1); + struct capn_ptr ptr1 = capn_new_struct(root.seg, 0, 1); + EXPECT_EQ(0, capn_setp(root, 0, ptr1)); + struct capn_ptr ptr2 = capn_new_struct(ptr1.seg, 4, 0); + EXPECT_EQ(0, capn_setp(ptr1, 0, ptr2)); + EXPECT_EQ(0, capn_write32(ptr2, 0, 0x12345678)); + EXPECT_EQ(3, ctx1.segnum); + + EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 7*8-1, 0)); + EXPECT_EQ(7*8, capn_write_mem(&ctx1, buf, 2048, 0)); + + EXPECT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 0)); + root = capn_root(&ctx2); + ptr1 = capn_getp(root, 0, 1); + ptr2 = capn_getp(ptr1, 0, 1); + EXPECT_EQ(0x12345678, capn_read32(ptr2, 0)); + + capn_free(&ctx1); + capn_free(&ctx2); +} diff --git a/capn.h b/capn.h index 1b28b63..e24aca2 100644 --- a/capn.h +++ b/capn.h @@ -241,6 +241,13 @@ void capn_init_malloc(struct capn *c); int capn_init_fp(struct capn *c, FILE *f, int packed); int capn_init_mem(struct capn *c, const uint8_t *p, size_t sz, int packed); +/* capn_write_(fp|mem) writes segments to the file/memory buffer in + * serialized form and returns the number of bytes written. + */ +/* TODO */ +/*int capn_write_fp(struct capn *c, FILE *f, int packed);*/ +int capn_write_mem(struct capn *c, uint8_t *p, size_t sz, int packed); + void capn_free(struct capn *c); void capn_reset_copy(struct capn *c);