diff --git a/include/lshpack.h b/include/lshpack.h index 6e5e493..a0ae5af 100644 --- a/include/lshpack.h +++ b/include/lshpack.h @@ -31,13 +31,8 @@ extern "C" { #include -/** - * Strings up to 65535 characters in length are supported. - */ -typedef uint16_t lshpack_strlen_t; - /** Maximum length is defined for convenience */ -#define LSHPACK_MAX_STRLEN UINT16_MAX +#define LSHPACK_MAX_STRLEN UINT_MAX struct lshpack_enc; struct lshpack_dec; @@ -72,8 +67,8 @@ lshpack_enc_cleanup (struct lshpack_enc *); */ unsigned char * lshpack_enc_encode (struct lshpack_enc *henc, unsigned char *dst, - unsigned char *dst_end, const char *name, lshpack_strlen_t name_len, - const char *value, lshpack_strlen_t value_len, int indexed_type); + unsigned char *dst_end, const char *name, unsigned name_len, + const char *value, unsigned value_len, int indexed_type); void lshpack_enc_set_max_capacity (struct lshpack_enc *, unsigned); @@ -99,8 +94,8 @@ lshpack_dec_cleanup (struct lshpack_dec *); int lshpack_dec_decode (struct lshpack_dec *dec, const unsigned char **src, const unsigned char *src_end, - char *dst, char *const dst_end, lshpack_strlen_t *name_len, - lshpack_strlen_t *val_len); + char *dst, char *const dst_end, unsigned *name_len, + unsigned *val_len); void lshpack_dec_set_max_capacity (struct lshpack_dec *, unsigned); diff --git a/src/lshpack.c b/src/lshpack.c index 98666ec..654eea6 100644 --- a/src/lshpack.c +++ b/src/lshpack.c @@ -50,8 +50,8 @@ SOFTWARE. static const struct { - lshpack_strlen_t name_len; - lshpack_strlen_t val_len; + unsigned name_len; + unsigned val_len; const char *name; const char *val; } @@ -5348,8 +5348,8 @@ struct lshpack_enc_table_entry unsigned ete_id; unsigned ete_nameval_hash; unsigned ete_name_hash; - lshpack_strlen_t ete_name_len; - lshpack_strlen_t ete_val_len; + unsigned ete_name_len; + unsigned ete_val_len; char ete_buf[0]; }; @@ -5441,7 +5441,7 @@ static #endif unsigned lshpack_enc_get_static_nameval (uint32_t nameval_hash, const char *name, - lshpack_strlen_t name_len, const char *val, lshpack_strlen_t val_len) + unsigned name_len, const char *val, unsigned val_len) { unsigned i; @@ -5466,7 +5466,7 @@ static #endif unsigned lshpack_enc_get_static_name (uint32_t name_hash, const char *name, - lshpack_strlen_t name_len) + unsigned name_len) { unsigned i; @@ -5499,8 +5499,8 @@ henc_calc_table_id (const struct lshpack_enc *enc, static unsigned henc_find_table_id (struct lshpack_enc *enc, uint32_t name_hash, uint32_t nameval_hash, const char *name, - lshpack_strlen_t name_len, const char *value, - lshpack_strlen_t value_len, int *val_matched) + unsigned name_len, const char *value, + unsigned value_len, int *val_matched) { struct lshpack_enc_table_entry *entry; unsigned buckno, static_table_id; @@ -5549,9 +5549,12 @@ henc_find_table_id (struct lshpack_enc *enc, uint32_t name_hash, } -static unsigned char * -henc_enc_int (unsigned char *dst, unsigned char *const end, uint32_t value, - uint8_t prefix_bits) +#if !LS_HPACK_EMIT_TEST_CODE +static +#endif + unsigned char * +lshpack_enc_enc_int (unsigned char *dst, unsigned char *const end, + uint32_t value, uint8_t prefix_bits) { unsigned char *const dst_orig = dst; @@ -5665,7 +5668,7 @@ static #endif int lshpack_enc_enc_str (unsigned char *const dst, size_t dst_len, - const unsigned char *str, lshpack_strlen_t str_len) + const unsigned char *str, unsigned str_len) { unsigned char size_buf[4]; unsigned char *p; @@ -5718,7 +5721,7 @@ lshpack_enc_enc_str (unsigned char *const dst, size_t dst_len, /* The guess of one-byte size was incorrect. Perform necessary * adjustments. */ - p = henc_enc_int(size_buf, size_buf + sizeof(size_buf), str_len, 7); + p = lshpack_enc_enc_int(size_buf, size_buf + sizeof(size_buf), str_len, 7); if (p == size_buf) return -1; @@ -5819,8 +5822,8 @@ static #endif int lshpack_enc_push_entry (struct lshpack_enc *enc, uint32_t name_hash, - uint32_t nameval_hash, const char *name, lshpack_strlen_t name_len, - const char *value, lshpack_strlen_t value_len) + uint32_t nameval_hash, const char *name, unsigned name_len, + const char *value, unsigned value_len) { struct lshpack_enc_table_entry *entry; unsigned buckno; @@ -5860,8 +5863,8 @@ lshpack_enc_push_entry (struct lshpack_enc *enc, uint32_t name_hash, unsigned char * lshpack_enc_encode (struct lshpack_enc *enc, unsigned char *dst, - unsigned char *dst_end, const char *name, lshpack_strlen_t name_len, - const char *value, lshpack_strlen_t value_len, int indexed_type) + unsigned char *dst_end, const char *name, unsigned name_len, + const char *value, unsigned value_len, int indexed_type) { //indexed_type: 0, Add, 1,: without, 2: never static const char indexed_prefix_number[] = {0x40, 0x00, 0x10}; @@ -5889,7 +5892,7 @@ lshpack_enc_encode (struct lshpack_enc *enc, unsigned char *dst, if (val_matched) { *dst = 0x80; - dst = henc_enc_int(dst, dst_end, table_id, 7); + dst = lshpack_enc_enc_int(dst, dst_end, table_id, 7); /* No need to check return value: we pass it up as-is because * the behavior is the same. */ @@ -5898,7 +5901,7 @@ lshpack_enc_encode (struct lshpack_enc *enc, unsigned char *dst, else { *dst = indexed_prefix_number[indexed_type]; - dst = henc_enc_int(dst, dst_end, table_id, + dst = lshpack_enc_enc_int(dst, dst_end, table_id, ((indexed_type == 0) ? 6 : 4)); if (dst == dst_org) return dst_org; @@ -5973,8 +5976,8 @@ lshpack_enc_iter_next (struct lshpack_enc *enc, void **iter, /* Dynamic table entry: */ struct dec_table_entry { - uint16_t dte_name_len; - uint16_t dte_val_len; + unsigned dte_name_len; + unsigned dte_val_len; char dte_buf[0]; /* Contains both name and value */ }; @@ -6019,37 +6022,60 @@ lshpack_dec_cleanup (struct lshpack_dec *dec) } +/* Maximum number of bytes required to encode a 32-bit integer */ +#define LSHPACK_UINT32_ENC_SZ 6 + + +/* Assumption: we have at least one byte to work with */ #if !LS_HPACK_EMIT_TEST_CODE static #endif int -lshpack_dec_dec_int (const unsigned char **src, const unsigned char *src_end, - uint8_t prefix_bits, uint32_t *value) +lshpack_dec_dec_int (const unsigned char **src_p, const unsigned char *src_end, + unsigned prefix_bits, uint32_t *value_p) { - uint32_t B, M; - uint8_t prefix_max = (1 << prefix_bits) - 1; + const unsigned char *const orig_src = *src_p; + const unsigned char *src; + unsigned prefix_max, M; + uint32_t val, B; - *value = (*(*src)++ & prefix_max); + src = *src_p; - if (*value < prefix_max) + prefix_max = (1 << prefix_bits) - 1; + val = *src++; + val &= prefix_max; + + if (val < prefix_max) + { + *src_p = src; + *value_p = val; return 0; + } - /* To optimize the loop for the normal case, the overflow is checked - * outside the loop. The decoder is limited to 28-bit integer values, - * which is far above limitations imposed by the APIs (16-bit integers). - */ M = 0; do { - if ((*src) >= src_end) + if (src < src_end) + { + B = *src++; + val = val + ((B & 0x7f) << M); + M += 7; + } + else if (src - orig_src < LSHPACK_UINT32_ENC_SZ) return -1; - B = *(*src)++; - *value = *value + ((B & 0x7f) << M); - M += 7; + else + return -2; } while (B & 0x80); - return -(M > sizeof(*value) * 8); + if (M <= 28 || (M == 35 && src[-1] <= 0xF && val - (src[-1] << 28) < val)) + { + *src_p = src; + *value_p = val; + return 0; + } + else + return -2; } @@ -6209,7 +6235,7 @@ static #endif int lshpack_dec_push_entry (struct lshpack_dec *dec, const char *name, - uint16_t name_len, const char *val, uint16_t val_len) + unsigned name_len, const char *val, unsigned val_len) { struct dec_table_entry *entry; size_t size; @@ -6237,7 +6263,7 @@ lshpack_dec_push_entry (struct lshpack_dec *dec, const char *name, int lshpack_dec_decode (struct lshpack_dec *dec, const unsigned char **src, const unsigned char *src_end, - char *dst, char *const dst_end, uint16_t *name_len, uint16_t *val_len) + char *dst, char *const dst_end, unsigned *name_len, unsigned *val_len) { struct dec_table_entry *entry; uint32_t index, new_capacity; @@ -6355,8 +6381,6 @@ lshpack_dec_decode (struct lshpack_dec *dec, len = hdec_dec_str((unsigned char *)name, dst_end - dst, src, src_end); if (len < 0) return len; //error - if (len > UINT16_MAX) - return -2; *name_len = len; } @@ -6364,8 +6388,6 @@ lshpack_dec_decode (struct lshpack_dec *dec, dst_end - dst - *name_len, src, src_end); if (len < 0) return len; //error - if (len > UINT16_MAX) - return -2; *val_len = len; if (indexed_type == 0) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a646549..fc00d3c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,3 +3,7 @@ ENABLE_TESTING() ADD_EXECUTABLE(test_hpack test_hpack.c ../deps/xxhash/xxhash.c) TARGET_LINK_LIBRARIES(test_hpack ls-hpack) ADD_TEST(hpack test_hpack) + +ADD_EXECUTABLE(test_int test_int.c ../deps/xxhash/xxhash.c) +TARGET_LINK_LIBRARIES(test_int ls-hpack) +ADD_TEST(int test_int) diff --git a/test/lshpack-test.h b/test/lshpack-test.h index 823002b..1dfdbc8 100644 --- a/test/lshpack-test.h +++ b/test/lshpack-test.h @@ -12,20 +12,20 @@ struct enc_dyn_table_entry unsigned lshpack_enc_get_static_name (uint32_t name_hash, const char *name, - lshpack_strlen_t name_len); + unsigned name_len); unsigned lshpack_enc_get_static_nameval (uint32_t nameval_hash, const char *name, - lshpack_strlen_t name_len, const char *val, lshpack_strlen_t val_len); + unsigned name_len, const char *val, unsigned val_len); int lshpack_enc_push_entry (struct lshpack_enc *enc, uint32_t name_hash, - uint32_t nameval_hash, const char *name, lshpack_strlen_t name_len, - const char *value, lshpack_strlen_t value_len); + uint32_t nameval_hash, const char *name, unsigned name_len, + const char *value, unsigned value_len); int lshpack_enc_enc_str (unsigned char *const dst, size_t dst_len, - const unsigned char *str, lshpack_strlen_t str_len); + const unsigned char *str, unsigned str_len); typedef void * enc_iter_t; @@ -39,10 +39,15 @@ lshpack_enc_iter_next (struct lshpack_enc *enc, void **iter, int lshpack_dec_dec_int (const unsigned char **src, const unsigned char *src_end, - uint8_t prefix_bits, uint32_t *value); + unsigned prefix_bits, uint32_t *value); int lshpack_dec_push_entry (struct lshpack_dec *dec, const char *name, - lshpack_strlen_t name_len, const char *val, - lshpack_strlen_t val_len); + unsigned name_len, const char *val, + unsigned val_len); + +unsigned char * +lshpack_enc_enc_int (unsigned char *dst, unsigned char *const end, uint32_t value, + uint8_t prefix_bits); + #endif diff --git a/test/test_hpack.c b/test/test_hpack.c index 56566ad..3035681 100644 --- a/test/test_hpack.c +++ b/test/test_hpack.c @@ -30,9 +30,9 @@ static struct http_header header_arr[N_HEADERS]; struct table_elem { const char *name; - lshpack_strlen_t name_len; + unsigned name_len; const char *val; - lshpack_strlen_t val_len; + unsigned val_len; }; static struct table_elem g_hpack_dyn_init_table_t[] = @@ -209,8 +209,8 @@ printTable (struct lshpack_enc *enc) static unsigned -lookup_static_table (const char *name, lshpack_strlen_t name_len, - const char *val, lshpack_strlen_t val_len, int *val_matched) +lookup_static_table (const char *name, unsigned name_len, + const char *val, unsigned val_len, int *val_matched) { uint32_t name_hash, nameval_hash; XXH32_state_t hash_state; @@ -245,8 +245,8 @@ void testNameValue(const char *name, const char *val, int result, int val_match_result) { int val_match; - int index = lookup_static_table((char *)name, (uint16_t)strlen(name) , - (char *)val, (uint16_t)strlen(val), &val_match); + int index = lookup_static_table((char *)name, (unsigned)strlen(name) , + (char *)val, (unsigned)strlen(val), &val_match); printf("name: %s, val: %s, index = %d match = %d\n", name, val, index, val_match); assert(index == result); @@ -391,8 +391,8 @@ test_hpack_test_RFC_Example (void) // char name[1024]; // char val[1024]; char out[2048]; - uint16_t name_len = 1024; - uint16_t val_len = 1024; + unsigned name_len = 1024; + unsigned val_len = 1024; while (pSrc < bufEnd) { rc = lshpack_dec_decode(&hdec, &pSrc, bufEnd, out, out + sizeof(out), @@ -456,7 +456,7 @@ test_decode_limits (void) char out[0x100]; struct lshpack_enc henc; struct lshpack_dec hdec; - uint16_t name_len, val_len; + unsigned name_len, val_len; int s; unsigned enough[] = { 33, 34, 40, 50, 100, }; unsigned not_enough[] = { 32, 31, 30, 10, 1, 0, }; @@ -515,8 +515,8 @@ test_hpack_self_enc_dec_test (void) // char name[1024]; // char val[1024]; char out[2048]; - uint16_t name_len = 0; - uint16_t val_len = 0; + unsigned name_len = 0; + unsigned val_len = 0; lshpack_enc_set_max_capacity(&henc, 256); lshpack_dec_set_max_capacity(&hdec, 256); @@ -692,7 +692,7 @@ test_hpack_encode_and_decode (void) STR_TO_IOVEC_TEST("www.example.com"), 0); assert(enc > buf); - uint16_t name_len, val_len; + unsigned name_len, val_len; int rc = lshpack_dec_decode(&hdec, &dec, enc, out, out + sizeof(out), &name_len, &val_len); assert(rc == 0); @@ -773,7 +773,7 @@ test_hpack_self_enc_dec_test_firefox_error (void) //AutoBuf autoBuf(2048); char out[2048]; - uint16_t name_len, val_len; + unsigned name_len, val_len; unsigned char *pBuf = respBuf; respBufEnd = respBuf + 8192; @@ -805,7 +805,7 @@ static void test_hdec_table_size_updates (void) { const unsigned char *src; - uint16_t name_len, val_len; + unsigned name_len, val_len; struct lshpack_dec hdec; char outbuf[0x100]; int s; @@ -951,7 +951,7 @@ test_henc_nonascii (void) const unsigned char *src; struct lshpack_enc henc; struct lshpack_dec hdec; - uint16_t name_len, val_len; + unsigned name_len, val_len; unsigned char comp[0x100]; char uncomp[0x100]; @@ -992,7 +992,7 @@ test_henc_long_compressable (void) const unsigned char *src; struct lshpack_enc henc; struct lshpack_dec hdec; - uint16_t name_len, val_len; + unsigned name_len, val_len; unsigned char comp[0x1000]; char uncomp[0x1000]; @@ -1040,7 +1040,7 @@ test_henc_long_uncompressable (void) const unsigned char *src; struct lshpack_enc henc; struct lshpack_dec hdec; - uint16_t name_len, val_len; + unsigned name_len, val_len; unsigned char comp[0x1000]; char uncomp[0x1000]; @@ -1128,89 +1128,6 @@ test_static_table_search_exhaustive (void) } -static void -test_integer_decoding (void) -{ - static const struct integer_decoding_test - { - int idt_lineno; - /* Input: */ - unsigned char idt_src_buf[40]; - unsigned idt_src_sz; - uint8_t idt_pfx_bits; - /* Output: */ - int idt_status; - uint32_t idt_value; - } - tests[] = { - { .idt_lineno = __LINE__, - .idt_src_buf = { 0xFE, }, - .idt_src_sz = 1, - .idt_pfx_bits = 4, - .idt_status = 0, - .idt_value = 0xE, - }, - { .idt_lineno = __LINE__, - .idt_src_buf = { 0x3F, 0x64, }, - .idt_src_sz = 2, - .idt_pfx_bits = 6, - .idt_status = 0, - .idt_value = 0x3F + 0x64, - }, - { .idt_lineno = __LINE__, - .idt_src_buf = { 0xFF, }, - .idt_src_sz = 1, - .idt_pfx_bits = 4, - .idt_status = -1, /* Ran out of buffer */ - .idt_value = 0, - }, - { .idt_lineno = __LINE__, - .idt_src_buf = { 0x87, 0xF0, 0x80, 0x7F, }, - .idt_src_sz = 4, - .idt_pfx_bits = 3, - .idt_status = 0, - .idt_value = 0b111111100000001110111, - }, - { .idt_lineno = __LINE__, - .idt_src_buf = { 0x87, 0x80, 0x80, 0x80, 0x01, }, - .idt_src_sz = 5, - .idt_pfx_bits = 3, - .idt_status = 0, - .idt_value = 0b1000000000000000000111, - }, - { .idt_lineno = __LINE__, - .idt_src_buf = { 0x87, 0x80, 0x80, 0x80, 0x01, }, - .idt_src_sz = 4, - .idt_pfx_bits = 3, - .idt_status = -1, /* Ran out of buffer */ - .idt_value = 0, - }, - { .idt_lineno = __LINE__, - .idt_src_buf = { 0x87, 0x80, 0x80, 0x80, 0x80, 0x01, }, - .idt_src_sz = 6, - .idt_pfx_bits = 3, - .idt_status = -1, /* Overflow */ - .idt_value = 0, - }, - }; - - const struct integer_decoding_test *test; - const unsigned char *src; - uint32_t value; - int s; - - for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test) - { - src = test->idt_src_buf; - s = lshpack_dec_dec_int(&src, src + test->idt_src_sz, - test->idt_pfx_bits, &value); - assert(s == test->idt_status); - if (0 == s) - assert(value == test->idt_value); - } -} - - static void test_huffman_encoding_corner_cases (void) { @@ -1254,7 +1171,7 @@ main (int argc, char **argv) } compressed = { NULL, 0, 0, }; unsigned char tmp_buf[0x100]; const unsigned char *end, *comp; - uint16_t name_len, val_len; + unsigned name_len, val_len; int s; char out[0x1000]; struct lshpack_dec hdec; @@ -1266,9 +1183,9 @@ main (int argc, char **argv) { end = lshpack_enc_encode(&henc, tmp_buf, tmp_buf + sizeof(tmp_buf), header_arr[i].name.iov_base, - (lshpack_strlen_t) header_arr[i].name.iov_len, + (unsigned) header_arr[i].name.iov_len, header_arr[i].value.iov_base, - (lshpack_strlen_t) header_arr[i].value.iov_len, 0); + (unsigned) header_arr[i].value.iov_len, 0); assert(end > tmp_buf); if (end - tmp_buf > (intptr_t) compressed.nalloc - (intptr_t) compressed.sz) { @@ -1300,7 +1217,6 @@ main (int argc, char **argv) free(compressed.buf); lshpack_dec_cleanup(&hdec); - test_integer_decoding(); test_decode_limits(); test_static_table_search_simple(); test_static_table_search_exhaustive(); diff --git a/test/test_int.c b/test/test_int.c new file mode 100644 index 0000000..5870ec1 --- /dev/null +++ b/test/test_int.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include + +#include "lshpack.h" +#include "lshpack-test.h" + +struct int_test +{ + int it_lineno; + unsigned it_prefix_bits; + unsigned char it_encoded[20]; + size_t it_enc_sz; + uint32_t it_decoded; + int it_dec_retval; +}; + +static const struct int_test tests[] = +{ + + { .it_lineno = __LINE__, + .it_prefix_bits = 7, + .it_encoded = { 0x7F, 0x02, }, + .it_enc_sz = 2, + .it_decoded = 0x81, + .it_dec_retval = 0, + }, + + /* RFC 7541, Appendinx C.1.1 */ + { .it_lineno = __LINE__, + .it_prefix_bits = 5, + .it_encoded = { 0b1010, 0x02, }, + .it_enc_sz = 1, + .it_decoded = 10, + .it_dec_retval = 0, + }, + + /* RFC 7541, Appendinx C.1.2 */ + { .it_lineno = __LINE__, + .it_prefix_bits = 5, + .it_encoded = { 0b11111, 0b10011010, 0b00001010, }, + .it_enc_sz = 3, + .it_decoded = 1337, + .it_dec_retval = 0, + }, + + /* RFC 7541, Appendinx C.1.3 */ + { .it_lineno = __LINE__, + .it_prefix_bits = 8, + .it_encoded = { 0b101010, }, + .it_enc_sz = 1, + .it_decoded = 42, + .it_dec_retval = 0, + }, + + { .it_lineno = __LINE__, + .it_prefix_bits = 7, + .it_encoded = { 0b01111111, 0b10000001, 0b10000010, 0b00000011, }, + .it_enc_sz = 4, + /* 01234560123456 */ + .it_decoded = 0b1100000100000001 + 0b1111111, + .it_dec_retval = 0, + }, + + { .it_lineno = __LINE__, + .it_prefix_bits = 7, + .it_encoded = { 0b01111111, 0b10000001, 0b10000010, 0b10000011, + 0b00000011, }, + .it_enc_sz = 5, + /* 012345601234560123456 */ + .it_decoded = 0b11000001100000100000001 + 0b1111111, + .it_dec_retval = 0, + }, + + { .it_lineno = __LINE__, + .it_prefix_bits = 7, + .it_encoded = { 0b01111111, 0b10000000, 0b11111111, 0b11111111, + 0b11111111, 0b00001111, }, + .it_enc_sz = 6, + .it_decoded = UINT32_MAX, + .it_dec_retval = 0, + }, + + { .it_lineno = __LINE__, + .it_prefix_bits = 7, + /* Same as above, but with extra bit that overflows it */ + /* ----v---- */ + .it_encoded = { 0b01111111, 0b10010000, 0b11111111, 0b11111111, + 0b11111111, 0b00001111, }, + .it_enc_sz = 6, + .it_dec_retval = -2, + }, + + { .it_lineno = __LINE__, + .it_prefix_bits = 7, + .it_encoded = { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, }, + .it_enc_sz = 11, + .it_dec_retval = -2, + }, + + { .it_lineno = __LINE__, + .it_encoded = { 0xFE, }, + .it_enc_sz = 1, + .it_prefix_bits = 4, + .it_dec_retval = 0, + .it_decoded = 0xE, + }, + + { .it_lineno = __LINE__, + .it_encoded = { 0x3F, 0x64, }, + .it_enc_sz = 2, + .it_prefix_bits = 6, + .it_dec_retval = 0, + .it_decoded = 0x3F + 0x64, + }, + + { .it_lineno = __LINE__, + .it_encoded = { 0xFF, }, + .it_enc_sz = 1, + .it_prefix_bits = 4, + .it_dec_retval = -1, /* Ran out of buffer */ + .it_decoded = 0, + }, + + { .it_lineno = __LINE__, + .it_encoded = { 0x87, 0xF0, 0x80, 0x7F, }, + .it_enc_sz = 4, + .it_prefix_bits = 3, + .it_dec_retval = 0, + .it_decoded = 0b111111100000001110111, + }, + + { .it_lineno = __LINE__, + .it_encoded = { 0x87, 0x80, 0x80, 0x80, 0x01, }, + .it_enc_sz = 5, + .it_prefix_bits = 3, + .it_dec_retval = 0, + .it_decoded = 0b1000000000000000000111, + }, + + { .it_lineno = __LINE__, + .it_encoded = { 0x87, 0x80, 0x80, 0x80, 0x01, }, + .it_enc_sz = 4, + .it_prefix_bits = 3, + .it_dec_retval = -1, /* Ran out of buffer */ + .it_decoded = 0, + }, + + { .it_lineno = __LINE__, + .it_encoded = { 0x87, 0x80, 0x80, 0x80, 0x80, 0x01, }, + .it_enc_sz = 6, + .it_prefix_bits = 3, + .it_dec_retval = 0, + .it_decoded = 0b10000000000000000000000000111, + }, + +}; + +int +main (void) +{ + const struct int_test *test; + const unsigned char *src; + unsigned char *dst; + unsigned char buf[ sizeof(((struct int_test *) NULL)->it_encoded) ]; + uint32_t val; + size_t sz; + int rv; + + /* Test the decoder */ + for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test) + { + for (sz = 0; sz < test->it_enc_sz - 1; ++sz) + { + src = test->it_encoded; + rv = lshpack_dec_dec_int(&src, src + sz, test->it_prefix_bits, &val); + if (test->it_dec_retval == -2) + assert(-1 == rv || -2 == rv); + else + assert(-1 == rv); + } + src = test->it_encoded; + rv = lshpack_dec_dec_int(&src, src + test->it_enc_sz, + test->it_prefix_bits, &val); + assert(rv == test->it_dec_retval); + if (0 == rv) + assert(val == test->it_decoded); + } + + /* Test the encoder */ + for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test) + { + if (test->it_dec_retval != 0) + continue; + for (sz = 1; sz < test->it_enc_sz; ++sz) + { + dst = lshpack_enc_enc_int(buf, buf + sz, test->it_decoded, + test->it_prefix_bits); + assert(dst == buf); /* Not enough room */ + } + for (; sz <= sizeof(buf); ++sz) + { + buf[0] = '\0'; + dst = lshpack_enc_enc_int(buf, buf + sz, test->it_decoded, + test->it_prefix_bits); + assert(dst - buf == (intptr_t) test->it_enc_sz); + assert((test->it_encoded[0] & ((1 << test->it_prefix_bits) - 1)) + == buf[0]); + if (test->it_enc_sz > 1) + assert(0 == memcmp(buf + 1, test->it_encoded + 1, + test->it_enc_sz - 1)); + } + } + + return 0; +}