#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <time.h> #include <stdbool.h> #include <errno.h> #include <osmocom/core/utils.h> #include <osmocom/core/bitvec.h> #include <osmocom/core/bits.h> static char lol[1024]; // we pollute this with printed vectors static inline void test_rl(const struct bitvec *bv) { bitvec_to_string_r(bv, lol); printf("%s [%d] RL0=%d, RL1=%d\n", lol, bv->cur_bit, bitvec_rl(bv, false), bitvec_rl(bv, true)); } static inline void test_shift(struct bitvec *bv, unsigned n) { bitvec_to_string_r(bv, lol); printf("%s << %d:\n", lol, n); bitvec_shiftl(bv, n); bitvec_to_string_r(bv, lol); printf("%s\n", lol); } static inline void test_get(struct bitvec *bv, unsigned n) { bitvec_to_string_r(bv, lol); printf("%s [%d]", lol, bv->cur_bit); int16_t x = bitvec_get_int16_msb(bv, n); uint8_t tmp[2]; osmo_store16be(x, &tmp); printf(" -> %d (%u bit) ["OSMO_BIN_SPEC" "OSMO_BIN_SPEC"]:\n", x, n, OSMO_BIN_PRINT(tmp[0]), OSMO_BIN_PRINT(tmp[1])); bitvec_to_string_r(bv, lol); printf("%s [%d]\n", lol, bv->cur_bit); } static inline void test_fill(struct bitvec *bv, unsigned n, enum bit_value val) { bitvec_to_string_r(bv, lol); unsigned bvlen = bv->cur_bit; int fi = bitvec_fill(bv, n, val); printf("%c> FILL %s [%d] -%d-> [%d]:\n", bit_value_to_char(val), lol, bvlen, n, fi); bitvec_to_string_r(bv, lol); printf(" %s [%d]\n\n", lol, bv->cur_bit); } static inline void test_spare(struct bitvec *bv, unsigned n) { bitvec_to_string_r(bv, lol); unsigned bvlen = bv->cur_bit; int sp = bitvec_spare_padding(bv, n); printf("%c> SPARE %s [%d] -%d-> [%d]:\n", bit_value_to_char(L), lol, bvlen, n, sp); bitvec_to_string_r(bv, lol); printf(" %s [%d]\n\n", lol, bv->cur_bit); } static inline void test_set(struct bitvec *bv, enum bit_value bit) { bitvec_to_string_r(bv, lol); unsigned bvlen = bv->cur_bit; int set = bitvec_set_bit(bv, bit); printf("%c> SET %s [%d] ++> [%d]:\n", bit_value_to_char(bit), lol, bvlen, set); bitvec_to_string_r(bv, lol); printf(" %s [%d]\n\n", lol, bv->cur_bit); } static void test_byte_ops(void) { struct bitvec bv; const uint8_t *in = (const uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint8_t out[26 + 2]; uint8_t data[64]; int i; int rc; int in_size = strlen((const char *)in); printf("=== start %s ===\n", __func__); bv.data = data; bv.data_len = sizeof(data); for (i = 0; i < 32; i++) { /* Write to bitvec */ memset(data, 0x00, sizeof(data)); bv.cur_bit = i; rc = bitvec_set_uint(&bv, 0x7e, 8); OSMO_ASSERT(rc >= 0); rc = bitvec_set_bytes(&bv, in, in_size); OSMO_ASSERT(rc >= 0); rc = bitvec_set_uint(&bv, 0x7e, 8); OSMO_ASSERT(rc >= 0); printf("bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len)); /* Read from bitvec */ memset(out, 0xff, sizeof(out)); bv.cur_bit = i; rc = bitvec_get_uint(&bv, 8); OSMO_ASSERT(rc == 0x7e); rc = bitvec_get_bytes(&bv, out + 1, in_size); OSMO_ASSERT(rc >= 0); rc = bitvec_get_uint(&bv, 8); OSMO_ASSERT(rc == 0x7e); printf("out: %s\n", osmo_hexdump(out, sizeof(out))); OSMO_ASSERT(out[0] == 0xff); OSMO_ASSERT(out[in_size+1] == 0xff); OSMO_ASSERT(memcmp(in, out + 1, in_size) == 0); } printf("=== end %s ===\n", __func__); } static void test_unhex(const char *hex) { int rc; struct bitvec b; uint8_t d[64] = {0}; b.data = d; b.data_len = sizeof(d); b.cur_bit = 0; rc = bitvec_unhex(&b, hex); printf("%d -=> cur_bit=%u\n", rc, b.cur_bit); printf("%s\n", osmo_hexdump_nospc(d, 64)); printf("%s\n", hex); } static inline void test_array_item(unsigned t, struct bitvec *b, unsigned int n, uint32_t *array, unsigned int p) { unsigned int i, x, y; bitvec_zero(b); x = b->cur_bit; i = bitvec_add_array(b, array, n, true, t); y = b->cur_bit; bitvec_add_array(b, array, n, false, t); printf("\nbits: %u, est: %u, real: %u, x: %u, y: %u\n", t, i, b->cur_bit, x, y); for (i = 0; i < p; i++) { printf(OSMO_BIT_SPEC " ", OSMO_BIT_PRINT(b->data[i])); if (0 == (i + 1) % 15) printf("\n"); } } static inline void test_bitvec_rl_curbit(struct bitvec *bv, bool b, int max_bits, int result ) { int num = 0; int readIndex = bv->cur_bit; OSMO_ASSERT(bv->cur_bit < max_bits); num = bitvec_rl_curbit(bv, b, max_bits); readIndex += num; OSMO_ASSERT(bv->cur_bit == readIndex); OSMO_ASSERT(num == result); } static void test_array(void) { struct bitvec b; uint8_t d[4096]; b.data = d; b.data_len = sizeof(d); unsigned int i, n = 64; uint32_t array[n]; for (i = 0; i < n; i++) { array[i] = i * i * i + i; printf("0x%x ", array[i]); } test_array_item(3, &b, n, array, n); test_array_item(9, &b, n, array, n * 2); test_array_item(17, &b, n, array, n * 3); } static void test_used_bytes(void) { struct bitvec b; uint8_t d[32]; unsigned int i; b.data = d; b.data_len = sizeof(d); bitvec_zero(&b); OSMO_ASSERT(bitvec_used_bytes(&b) == 0); for (i = 0; i < 8; i++) { bitvec_set_bit(&b, 1); OSMO_ASSERT(bitvec_used_bytes(&b) == 1); } for (i = 8; i < 16; i++) { bitvec_set_bit(&b, 1); OSMO_ASSERT(bitvec_used_bytes(&b) == 2); } } static void test_tailroom(void) { struct bitvec b; uint8_t d[32]; unsigned int i; b.data = d; b.data_len = sizeof(d); bitvec_zero(&b); OSMO_ASSERT(bitvec_tailroom_bits(&b) == sizeof(d)*8); for (i = 0; i < 8*sizeof(d); i++) { bitvec_set_bit(&b, 1); OSMO_ASSERT(bitvec_tailroom_bits(&b) == sizeof(d)*8-(i+1)); } } static void test_bitvec_read_field(void) { uint8_t data[8] = { 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xeb, 0xda, 0xed }; struct bitvec bv = { .data_len = sizeof(data), .data = data, .cur_bit = 0, }; unsigned int readIndex; uint64_t field; #define _bitvec_read_field(idx, len) \ readIndex = idx; \ field = bitvec_read_field(&bv, &readIndex, len); \ printf("bitvec_read_field(idx=%u, len=%u) => %" PRIx64 " (%s)\n", \ idx, len, field, errno == 0 ? "success" : "error"); _bitvec_read_field(0, 64); _bitvec_read_field(0, 32); _bitvec_read_field(0, 16); _bitvec_read_field(0, 8); _bitvec_read_field(0, 0); _bitvec_read_field(8, 8); _bitvec_read_field(8, 4); _bitvec_read_field(8, 0); _bitvec_read_field(10, 9); _bitvec_read_field(10, 7); _bitvec_read_field(10, 5); _bitvec_read_field(10, 3); _bitvec_read_field(10, 1); /* Out of bounds (see OS#4388) */ _bitvec_read_field(8 * 8 * 8, 16); /* index too far */ _bitvec_read_field(0, 8 * 8 + 1); /* too many bits */ _bitvec_read_field(8 * 8, 16); /* 16 bits past */ } int main(int argc, char **argv) { struct bitvec bv; uint8_t i = 8, test[i]; memset(test, 0, i); bv.data_len = i; bv.data = test; bv.cur_bit = 0; printf("test shifting...\n"); bitvec_set_uint(&bv, 0x0E, 7); test_shift(&bv, 3); test_shift(&bv, 17); bitvec_set_uint(&bv, 0, 32); bitvec_set_uint(&bv, 0x0A, 7); test_shift(&bv, 24); printf("checking RL functions...\n"); bitvec_zero(&bv); test_rl(&bv); bitvec_set_uint(&bv, 0x000F, 32); test_rl(&bv); bitvec_shiftl(&bv, 18); test_rl(&bv); bitvec_set_uint(&bv, 0x0F, 8); test_rl(&bv); bitvec_zero(&bv); bitvec_set_uint(&bv, 0xFF, 8); test_rl(&bv); bitvec_set_uint(&bv, 0xFE, 7); test_rl(&bv); bitvec_set_uint(&bv, 0, 17); test_rl(&bv); bitvec_shiftl(&bv, 18); test_rl(&bv); printf("probing bit access...\n"); bitvec_zero(&bv); bitvec_set_uint(&bv, 0x3747817, 32); bitvec_shiftl(&bv, 10); test_get(&bv, 2); test_get(&bv, 7); test_get(&bv, 9); test_get(&bv, 13); test_get(&bv, 16); test_get(&bv, 42); printf("feeling bit fills...\n"); test_set(&bv, ONE); test_fill(&bv, 3, ZERO); test_spare(&bv, 38); test_spare(&bv, 43); test_spare(&bv, 1); test_spare(&bv, 7); test_fill(&bv, 5, ONE); test_fill(&bv, 3, L); printf("byte me...\n"); test_byte_ops(); test_unhex("48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b"); test_unhex("47240c00400000000000000079eb2ac9402b2b2b2b2b2b"); test_unhex("47283c367513ba333004242b2b2b2b2b2b2b2b2b2b2b2b"); test_unhex("DEADFACE000000000000000000000000000000BEEFFEED"); test_unhex("FFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); printf("arrr...\n"); test_array(); printf("\nbitvec_runlength....\n"); bitvec_zero(&bv); bitvec_set_uint(&bv, 0xff, 8); bv.cur_bit -= 8; test_bitvec_rl_curbit(&bv, 1, 64, 8); bitvec_zero(&bv); bitvec_set_uint(&bv, 0xfc, 8); bv.cur_bit -= 8; test_bitvec_rl_curbit(&bv, 1, 64, 6); bitvec_zero(&bv); test_bitvec_rl_curbit(&bv, 0, 52, 52); bitvec_zero(&bv); bitvec_set_uint(&bv, 0xfc, 8); bv.cur_bit -= 2; test_bitvec_rl_curbit(&bv, 0, 64, 58); bitvec_zero(&bv); bitvec_set_uint(&bv, 0x07, 8); bitvec_set_uint(&bv, 0xf8, 8); bv.cur_bit -= 11; test_bitvec_rl_curbit(&bv, 1, 64, 8); bitvec_zero(&bv); test_bitvec_rl_curbit(&bv, 1, 64, 0); printf("\nbitvec bytes used.\n"); test_used_bytes(); test_tailroom(); printf("\ntest bitvec_read_field():\n"); test_bitvec_read_field(); printf("\nbitvec ok.\n"); return 0; }