From 81e46ff140dbafa401dddd95744d2f6d55f8a6bd Mon Sep 17 00:00:00 2001 From: falsycat Date: Mon, 12 Feb 2024 13:05:28 +0900 Subject: [PATCH] implement chunk write functions --- allcing.h | 108 +++++++++++++++++++++++++++++++++++++++++++++++++----- test.c | 72 +++++++++++++++++++++++++++++++++--- 2 files changed, 165 insertions(+), 15 deletions(-) diff --git a/allcing.h b/allcing.h index b9d57df..b4746e5 100644 --- a/allcing.h +++ b/allcing.h @@ -7,11 +7,15 @@ #include -#define ACG_CHUNK_BLOB 0x00 +#define ACG_CHUNK_PAD 0x00U +#define ACG_CHUNK_BLOB 0x01U +#define ACG_CHUNK_CTX 0x02U +#define ACG_CHUNK_LOC 0x03U +#define ACG_CHUNK_BEGIN 0x04U +#define ACG_CHUNK_END 0x05U +#define ACG_CHUNK_CHECK 0x06U -#define ACG_CHUNK_BEGIN 0x01 -#define ACG_CHUNK_END 0x02 -#define ACG_CHUNK_CHECK 0x03 +#define ACG_UNITBITS_CHUNK_ID 4U static inline uint64_t acg_util_fullbits(uint8_t bits) { @@ -29,7 +33,15 @@ struct acg_stream { uint64_t cursor_bits; }; +static inline bool acg_stream_write_pad(struct acg_stream* s) { + assert(NULL != s); + + s->cursor_bits = (s->cursor_bits+7U)/8U*8U; + return true; +} static inline bool acg_stream_write_bool(struct acg_stream* s, bool v) { + assert(NULL != s); + if (s->size_bytes <= s->cursor_bits) { return false; } @@ -39,14 +51,19 @@ static inline bool acg_stream_write_bool(struct acg_stream* s, bool v) { return true; } static inline bool acg_stream_write_uint(struct acg_stream* s, uint64_t v, uint8_t unit_bits) { - assert(unit_bits >= 2U); - assert(unit_bits <= 65U); + assert(NULL != s); + assert(2U <= unit_bits); + assert(65U >= unit_bits); uint8_t* const buf = s->buffer; uint64_t* const c = &s->cursor_bits; const uint8_t unit_data_bits = unit_bits - 1U; while (v) { + if (s->size_bytes*8U - *c < unit_bits) { + return false; + } + const uint64_t next_v = v >> unit_data_bits; acg_stream_write_bool(s, !!next_v); @@ -66,7 +83,80 @@ static inline bool acg_stream_write_uint(struct acg_stream* s, uint64_t v, uint8 return true; } static inline bool acg_stream_write_int(struct acg_stream* s, int64_t v, uint8_t unit_bits) { - assert(unit_bits > 0); - const uint64_t uv = v >= 0? ((uint64_t) v): (~((uint64_t) -v) + 1); - return acg_stream_write_uint(s, uv, unit_bits); + assert(NULL != s); + assert(2U <= unit_bits); + assert(65U >= unit_bits); + + if (v >= 0U) { + return + acg_stream_write_bool(s, false) && + acg_stream_write_uint(s, (uint64_t) v, unit_bits); + } else { + return + acg_stream_write_bool(s, true) && + acg_stream_write_uint(s, (uint64_t) -v, unit_bits); + } +} + +static inline bool acg_stream_write_chunk_pad(struct acg_stream* s) { + assert(NULL != s); + + if (s->cursor_bits%8U == 0U) { + return true; + } + if (s->size_bytes <= s->cursor_bits/8U) { + return false; + } + return + acg_stream_write_uint(s, ACG_CHUNK_PAD, ACG_UNITBITS_CHUNK_ID) && + acg_stream_write_pad(s); +} +static inline bool acg_stream_write_chunk_blob(struct acg_stream* s, uint64_t size_bytes, const uint8_t* buf) { + assert(NULL != s); + + if (!acg_stream_write_uint(s, ACG_CHUNK_BLOB, ACG_UNITBITS_CHUNK_ID)) { + return false; + } + if (!acg_stream_write_uint(s, size_bytes, 8U)) { + return false; + } + if (!acg_stream_write_pad(s)) { + return false; + } + + uint64_t* const c = &s->cursor_bits; + + const uint64_t avail_bytes = s->size_bytes - *c/8U; + if (avail_bytes < size_bytes) { + return false; + } + memcpy(&s->buffer[*c/8], buf, size_bytes); + + const uint64_t size_bits = size_bytes * 8U; + *c += size_bits; + return true; +} +static inline bool acg_stream_write_chunk_begin(struct acg_stream* s) { + assert(NULL != s); + + if (!acg_stream_write_uint(s, ACG_CHUNK_BEGIN, ACG_UNITBITS_CHUNK_ID)) { + return false; + } + return true; +} +static inline bool acg_stream_write_chunk_end(struct acg_stream* s) { + assert(NULL != s); + + if (!acg_stream_write_uint(s, ACG_CHUNK_END, ACG_UNITBITS_CHUNK_ID)) { + return false; + } + return true; +} +static inline bool acg_stream_write_chunk_check(struct acg_stream* s) { + assert(NULL != s); + + if (!acg_stream_write_uint(s, ACG_CHUNK_CHECK, ACG_UNITBITS_CHUNK_ID)) { + return false; + } + return true; } diff --git a/test.c b/test.c index a148d9f..ead04a2 100644 --- a/test.c +++ b/test.c @@ -11,12 +11,6 @@ int main(int, char**) { -# define DEFINE_STREAM(name, offset) \ - struct acg_stream s = { \ - .buffer = (uint8_t[1024U]) {0U}, \ - .size_bytes = 1024U, \ - .cursor_bits = (offset), \ - } # define STREAM(size, offset) \ (struct acg_stream) { \ .buffer = (uint8_t[size]) {0U}, \ @@ -24,6 +18,17 @@ int main(int, char**) { .cursor_bits = (offset), \ } + /* acg_stream_write_pad / without offset */ { + struct acg_stream s = STREAM(1024U, 0U); + assert(acg_stream_write_pad(&s)); + assert(s.cursor_bits == 0U); + } + /* acg_stream_write_pad / with offset */ { + struct acg_stream s = STREAM(1024U, 1U); + assert(acg_stream_write_pad(&s)); + assert(s.cursor_bits == 8U); + } + /* acg_stream_write_bool / value=true */ { struct acg_stream s = STREAM(1024U, 0U); assert(acg_stream_write_bool(&s, true)); @@ -64,5 +69,60 @@ int main(int, char**) { assert(s.cursor_bits == 11U); } + /* acg_stream_write_int */ { + struct acg_stream s = STREAM(1024U, 0U); + assert(acg_stream_write_int(&s, -1, 4U)); + assert(s.buffer[0U] == 0x05U); + assert(s.cursor_bits == 5U); + } + + /* acg_stream_write_chunk_pad / without offset */ { + struct acg_stream s = STREAM(1024U, 0U); + assert(acg_stream_write_chunk_pad(&s)); + assert(s.cursor_bits == 0U); + } + /* acg_stream_write_chunk_pad / with offset */ { + struct acg_stream s = STREAM(1024U, 1U); + assert(acg_stream_write_chunk_pad(&s)); + assert(s.buffer[0U] == 0U); + assert(s.cursor_bits == 8U); + } + + /* acg_stream_write_chunk_pad / without offset */ { + struct acg_stream s = STREAM(1024U, 0U); + assert(acg_stream_write_chunk_blob( + &s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03})); + assert(s.buffer[0U] == 0x82); + assert(s.buffer[1U] == 0x00); + assert(s.buffer[2U] == 0x00); + assert(s.buffer[3U] == 0x01); + assert(s.buffer[4U] == 0x02); + assert(s.buffer[5U] == 0x03); + assert(s.cursor_bits == 48U); + } + /* acg_stream_write_chunk_pad / with offset=1 */ { + struct acg_stream s = STREAM(1024U, 1U); + assert(acg_stream_write_chunk_blob( + &s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03})); + assert(s.buffer[0U] == 0x04); + assert(s.buffer[1U] == 0x01); + assert(s.buffer[2U] == 0x00); + assert(s.buffer[3U] == 0x01); + assert(s.buffer[4U] == 0x02); + assert(s.buffer[5U] == 0x03); + assert(s.cursor_bits == 48U); + } + /* acg_stream_write_chunk_pad / with offset=4 */ { + struct acg_stream s = STREAM(1024U, 4U); + assert(acg_stream_write_chunk_blob( + &s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03})); + assert(s.buffer[0U] == 0x20); + assert(s.buffer[1U] == 0x08); + assert(s.buffer[2U] == 0x00); + assert(s.buffer[3U] == 0x01); + assert(s.buffer[4U] == 0x02); + assert(s.buffer[5U] == 0x03); + assert(s.cursor_bits == 48U); + } return EXIT_SUCCESS; }