rizin/test/unit/test_bitvector.c
Florian Märkl ff4d6608c0
Add rz_bv_append_inplace() (#6592)
Warning: this also swaps the arguments of the old rz_bv_append() to be
consistend with the new inplace variant.
The reason why the inplace function has the low as the first operand is
that it can be more efficient to append to an existing vector inplace
than to prepend to it. Then, the first argument is being used as the
in-out one in all other inplace functions.
2026-07-03 23:31:30 +08:00

2025 lines
68 KiB
C

// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_util.h>
#include "minunit.h"
#define is_equal_bv(x, y) (!rz_bv_cmp(x, y))
bool test_rz_bv_init32(void) {
char *s = NULL;
// create by given unsigned 32 bit
RzBitVector *bits = rz_bv_new_from_ut64(32, 100);
RzBitVector *bits_cmp = rz_bv_new(32);
// 100 = 64 + 32 + 4 == 0b 0000 0000 0000 0000 0000 0000 0110 0100
rz_bv_set(bits_cmp, 2, true);
rz_bv_set(bits_cmp, 5, true);
rz_bv_set(bits_cmp, 6, true);
mu_assert("new from 32", is_equal_bv(bits, bits_cmp));
// dup
RzBitVector *bits_dup = rz_bv_dup(bits);
mu_assert("dup from bits 32", is_equal_bv(bits_dup, bits));
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "00000000000000000000000001100100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0x00000064", "string hex value of bv");
rz_bv_free(bits);
rz_bv_free(bits_cmp);
rz_bv_free(bits_dup);
mu_end;
}
bool test_rz_bv_init64(void) {
char *s = NULL;
// create by given unsigned 64 bits
RzBitVector *bits = rz_bv_new_from_ut64(64, 100);
RzBitVector *bits_cmp = rz_bv_new(64);
// 100 = 64 + 32 + 4 == 0b 0000 0000 0000 0000 0000 0000 0110 0100
rz_bv_set(bits_cmp, 2, true);
rz_bv_set(bits_cmp, 5, true);
rz_bv_set(bits_cmp, 6, true);
mu_assert("new from 64", is_equal_bv(bits, bits_cmp));
// dup
RzBitVector *bits_dup = rz_bv_dup(bits);
mu_assert("dup from bits 64", is_equal_bv(bits_dup, bits));
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0x0000000000000064", "string hex value of bv");
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "0000000000000000000000000000000000000000000000000000000001100100", "string bit value of bv");
rz_bv_free(bits);
rz_bv_free(bits_cmp);
rz_bv_free(bits_dup);
mu_end;
}
bool test_rz_bv_init128(void) {
char *s = NULL;
// create by given unsigned 128 bits
RzBitVector *bits = rz_bv_new_from_ut64(128, 100);
RzBitVector *bits_cmp = rz_bv_new(128);
// 100 = 64 + 32 + 4 == 0b 0000 0000 0000 0000 0000 0000 0110 0100
rz_bv_set(bits_cmp, 2, true);
rz_bv_set(bits_cmp, 5, true);
rz_bv_set(bits_cmp, 6, true);
mu_assert("new from 128", is_equal_bv(bits, bits_cmp));
// dup
RzBitVector *bits_dup = rz_bv_dup(bits);
mu_assert("dup from bits 128", is_equal_bv(bits_dup, bits));
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0x00000000000000000000000000000064", "string hex value of bv");
rz_bv_set_from_ut64(bits, 0);
mu_assert_eq(rz_bv_to_ut64(bits), 0, "Did not set to zero");
rz_bv_set(bits, 2, true);
rz_bv_set(bits, 5, true);
rz_bv_set(bits, 6, true);
mu_assert("new from 128", is_equal_bv(bits, bits_cmp));
rz_bv_set_from_st64(bits, 0);
mu_assert_eq(rz_bv_to_ut64(bits), 0, "Did not set to zero");
rz_bv_free(bits);
rz_bv_free(bits_cmp);
rz_bv_free(bits_dup);
mu_end;
}
bool test_rz_bv_init70(void) {
char *s = NULL;
// create by given unsigned 70 bits
RzBitVector *bits = rz_bv_new_from_ut64(70, 100);
RzBitVector *bits_cmp = rz_bv_new(70);
// 100 = 64 + 32 + 4 == 0b 0000 0000 0000 0000 0000 0000 0110 0100
rz_bv_set(bits_cmp, 2, true);
rz_bv_set(bits_cmp, 5, true);
rz_bv_set(bits_cmp, 6, true);
mu_assert("new from 70", is_equal_bv(bits, bits_cmp));
// dup
RzBitVector *bits_dup = rz_bv_dup(bits);
mu_assert("dup from bits 70", is_equal_bv(bits_dup, bits));
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "0000000000000000000000000000000000000000000000000000000000000001100100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0x000000000000000064", "string hex value of bv");
rz_bv_free(bits);
rz_bv_free(bits_cmp);
rz_bv_free(bits_dup);
mu_end;
}
bool test_rz_bv_init_signed(void) {
char *s = NULL;
RzBitVector *bits = NULL;
// create by given signed 10 bits
bits = rz_bv_new_from_st64(10, -100);
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "1110011100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0x39c", "string hex value of bv");
rz_bv_free(bits);
// create by given signed 16 bits
bits = rz_bv_new_from_st64(16, -100);
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "1111111110011100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0xff9c", "string hex value of bv");
rz_bv_free(bits);
// create by given signed 24 bits
bits = rz_bv_new_from_st64(24, -100);
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "111111111111111110011100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0xffff9c", "string hex value of bv");
rz_bv_free(bits);
// create by given signed 32 bits
bits = rz_bv_new_from_st64(32, -100);
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "11111111111111111111111110011100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0xffffff9c", "string hex value of bv");
rz_bv_free(bits);
// create by given signed 64 bits
bits = rz_bv_new_from_st64(64, -100);
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "1111111111111111111111111111111111111111111111111111111110011100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0xffffffffffffff9c", "string hex value of bv");
rz_bv_free(bits);
// create by given signed 128 bits
bits = rz_bv_new_from_st64(128, -100);
s = rz_bv_as_string(bits);
mu_assert_streq_free(s, "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110011100", "string bit value of bv");
s = rz_bv_as_hex_string(bits, true);
mu_assert_streq_free(s, "0xffffffffffffffffffffffffffffff9c", "string hex value of bv");
rz_bv_free(bits);
mu_end;
}
bool test_rz_bv_logic_large(void) {
RzBitVector *x, *y, *z;
RzBitVector *result;
const ut8 array_128[128] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
const ut8 array_128_01[128] = {
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
};
const ut8 array_128_10[128] = {
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
};
// Expected
const char *not = "0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0"; // ~x
const char *and = "0x00010001000100010001000100010001"; // x & y
const char *or = "0x101112131415161718191a1b1c1d1e1f"; // x | z
const char *xor = "0x010003020504070609080b0a0d0c0f0e"; // x ^ y
const char *neg = "0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f1"; // -x
x = rz_bv_new_from_bytes_be(array_128, 0, 128);
y = rz_bv_new_from_bytes_be(array_128_01, 0, 128);
z = rz_bv_new_from_bytes_be(array_128_10, 0, 128);
result = rz_bv_not(x);
mu_assert_streq_free(rz_bv_as_hex_string(result, false), not, "not result off");
rz_bv_free(result);
result = rz_bv_and(x, y);
mu_assert_streq_free(rz_bv_as_hex_string(result, true), and, "and result off");
rz_bv_free(result);
result = rz_bv_or(x, z);
mu_assert_streq_free(rz_bv_as_hex_string(result, true), or, "or result off");
rz_bv_free(result);
result = rz_bv_xor(x, y);
mu_assert_streq_free(rz_bv_as_hex_string(result, true), xor, "xor result off");
rz_bv_free(result);
result = rz_bv_neg(x);
mu_assert_streq_free(rz_bv_as_hex_string(result, true), neg, "neg result off");
rz_bv_free(result);
rz_bv_free(x);
rz_bv_free(y);
rz_bv_free(z);
mu_end;
}
bool test_rz_bv_logic(void) {
RzBitVector *x, *y;
RzBitVector *result;
RzBitVector *and, *or, *xor, *neg, *not, *ls, *rs, *ls_fill, *rs_fill;
// x : 0101 0101
x = rz_bv_new(8);
rz_bv_set(x, 0, true);
rz_bv_set(x, 2, true);
rz_bv_set(x, 4, true);
rz_bv_set(x, 6, true);
// y : 1010 1001
y = rz_bv_new(8);
rz_bv_set(y, 0, true);
rz_bv_set(y, 3, true);
rz_bv_set(y, 5, true);
rz_bv_set(y, 7, true);
// and : 0000 0001
and = rz_bv_new(8);
rz_bv_set(and, 0, true);
// xor : 1111 1100
xor = rz_bv_new(8);
rz_bv_toggle_all(xor);
rz_bv_set(xor, 0, false);
rz_bv_set(xor, 1, false);
// or : 1111 1101
or = rz_bv_new(8);
rz_bv_toggle_all(or);
rz_bv_set(or, 1, false);
// not of x : 1010 1010
not = rz_bv_new(8);
rz_bv_set(not, 1, true);
rz_bv_set(not, 3, true);
rz_bv_set(not, 5, true);
rz_bv_set(not, 7, true);
// neg of x : 1010 1011
neg = rz_bv_new(8);
rz_bv_set(neg, 0, true);
rz_bv_set(neg, 1, true);
rz_bv_set(neg, 3, true);
rz_bv_set(neg, 5, true);
rz_bv_set(neg, 7, true);
// left shift (3 bits) of y : 0100 1000
ls = rz_bv_new(8);
rz_bv_set(ls, 3, true);
rz_bv_set(ls, 6, true);
// left shift (3 bits) of y : 0100 1111
ls_fill = rz_bv_new(8);
rz_bv_set(ls_fill, 0, true);
rz_bv_set(ls_fill, 1, true);
rz_bv_set(ls_fill, 2, true);
rz_bv_set(ls_fill, 3, true);
rz_bv_set(ls_fill, 6, true);
// right shift (3 bits) of y : 0001 0101
rs = rz_bv_new(8);
rz_bv_set(rs, 0, true);
rz_bv_set(rs, 2, true);
rz_bv_set(rs, 4, true);
// right shift (3 bits) of y : 1111 0101
rs_fill = rz_bv_new(8);
rz_bv_toggle_all(rs_fill);
rz_bv_set(rs_fill, 1, false);
rz_bv_set(rs_fill, 3, false);
// test and
result = rz_bv_and(x, y);
mu_assert("and x y", is_equal_bv(result, and));
rz_bv_free(result);
rz_bv_free(and);
result = rz_bv_or(x, y);
mu_assert("or x y", is_equal_bv(result, or));
rz_bv_free(result);
rz_bv_free(or);
result = rz_bv_xor(x, y);
mu_assert("xor x y", is_equal_bv(result, xor));
rz_bv_free(result);
rz_bv_free(xor);
result = rz_bv_not(x);
mu_assert("not x", is_equal_bv(result, not));
rz_bv_free(result);
rz_bv_free(not);
result = rz_bv_neg(x);
mu_assert("neg x", is_equal_bv(result, neg));
rz_bv_free(result);
rz_bv_free(neg);
result = rz_bv_dup(y);
mu_assert_true(rz_bv_lshift(result, 3), "Shift failed");
mu_assert("left shift y", is_equal_bv(result, ls));
rz_bv_free(result);
rz_bv_free(ls);
result = rz_bv_dup(y);
mu_assert_true(rz_bv_lshift_fill(result, 3, true), "Shift failed");
mu_assert("left shift y filling 1", is_equal_bv(result, ls_fill));
rz_bv_free(result);
rz_bv_free(ls_fill);
result = rz_bv_dup(y);
mu_assert_true(rz_bv_rshift(result, 3), "Shift failed");
mu_assert("right shift y", is_equal_bv(result, rs));
rz_bv_free(result);
rz_bv_free(rs);
result = rz_bv_dup(y);
mu_assert_true(rz_bv_rshift_fill(result, 3, true), "Shift failed");
mu_assert("right shift y", is_equal_bv(result, rs_fill));
ut64 before = rz_bv_to_ut64(result);
mu_assert_true(rz_bv_rshift_fill(result, 0, true), "Shift failed");
mu_assert_eq(rz_bv_to_ut64(result), before, "right shift 0 failed");
mu_assert_true(rz_bv_lshift_fill(result, 0, true), "Shift failed");
mu_assert_eq(rz_bv_to_ut64(result), before, "left shift 0 failed");
rz_bv_free(result);
rz_bv_free(rs_fill);
rz_bv_free(x);
rz_bv_free(y);
mu_end;
}
bool test_rz_bv_algorithm32(void) {
RzBitVector *x, *y;
RzBitVector *result;
RzBitVector *add, *sub, *mul, *div, *mod;
x = rz_bv_new_from_ut64(32, 121);
y = rz_bv_new_from_ut64(32, 33);
add = rz_bv_new_from_ut64(32, 154);
sub = rz_bv_new_from_ut64(32, 121 - 33);
div = rz_bv_new_from_ut64(32, 121 / 33);
mul = rz_bv_new_from_ut64(32, 121 * 33);
mod = rz_bv_new_from_ut64(32, 121 % 33);
result = rz_bv_add(x, y, NULL);
mu_assert("Add x y", rz_bv_cmp(result, add) == 0);
rz_bv_free(result);
result = rz_bv_sub(x, y, NULL);
mu_assert("Sub x y", rz_bv_cmp(result, sub) == 0);
rz_bv_free(result);
result = rz_bv_mul(x, y);
mu_assert("Mul x y", rz_bv_cmp(result, mul) == 0);
rz_bv_free(result);
result = rz_bv_div(x, y);
mu_assert("Div x y", rz_bv_cmp(result, div) == 0);
rz_bv_free(result);
result = rz_bv_mod(x, y);
mu_assert("Mod x y", rz_bv_cmp(result, mod) == 0);
rz_bv_free(result);
rz_bv_free(x);
rz_bv_free(y);
rz_bv_free(add);
rz_bv_free(sub);
rz_bv_free(div);
rz_bv_free(mul);
rz_bv_free(mod);
mu_end;
}
bool test_rz_bv_algorithm128(void) {
RzBitVector *x, *y;
RzBitVector *result;
RzBitVector *add, *sub, *mul, *div, *mod;
x = rz_bv_new_from_ut64(128, 121);
y = rz_bv_new_from_ut64(128, 33);
add = rz_bv_new_from_ut64(128, 154);
sub = rz_bv_new_from_ut64(128, 121 - 33);
div = rz_bv_new_from_ut64(128, 121 / 33);
mul = rz_bv_new_from_ut64(128, 121 * 33);
mod = rz_bv_new_from_ut64(128, 121 % 33);
result = rz_bv_add(x, y, NULL);
mu_assert("Add x y", rz_bv_cmp(result, add) == 0);
rz_bv_free(result);
result = rz_bv_sub(x, y, NULL);
mu_assert("Sub x y", rz_bv_cmp(result, sub) == 0);
rz_bv_free(result);
result = rz_bv_mul(x, y);
mu_assert("Mul x y", rz_bv_cmp(result, mul) == 0);
rz_bv_free(result);
result = rz_bv_div(x, y);
mu_assert("Div x y", rz_bv_cmp(result, div) == 0);
rz_bv_free(result);
result = rz_bv_mod(x, y);
mu_assert("Mod x y", rz_bv_cmp(result, mod) == 0);
rz_bv_free(result);
rz_bv_free(x);
rz_bv_free(y);
rz_bv_free(add);
rz_bv_free(sub);
rz_bv_free(div);
rz_bv_free(mul);
rz_bv_free(mod);
mu_end;
}
/**
* \brief Reference implementation of rz_bv_add() to test against
*/
static RzBitVector *rz_bv_add_ref(RZ_INOUT RZ_NONNULL RZ_BORROW RzBitVector *x, const RZ_NONNULL RzBitVector *y, RZ_NULLABLE bool *carry) {
rz_return_val_if_fail(x && y, false);
if (x->len != y->len || x->len == 0) {
rz_warn_if_reached();
return NULL;
}
RzBitVector *ret = rz_bv_dup(x);
bool a = false, b = false, _carry = false;
for (ut32 pos = 0; pos < ret->len; ++pos) {
a = rz_bv_get(ret, pos);
b = rz_bv_get(y, pos);
rz_bv_set(ret, pos, a ^ b ^ _carry);
_carry = ((a & b) | (a & _carry)) | (b & _carry);
}
if (carry) {
*carry = _carry;
}
return ret;
}
/**
* \brief This function calls `rz_bv_add()` and it related baseline implementation `rz_bv_add_ref()` and then
* compares the resultant bitvector and carry flag and returns an error if there is a difference.
*/
static const char *test_rz_bv_add_against_ref(ut64 size, const ut8 *a_bytes, const ut8 *b_bytes) {
bool carry_a = false;
bool carry_b = false;
const char *error = NULL;
RzBitVector *a = rz_bv_new_from_bytes_be(a_bytes, 0, size);
RzBitVector *b = rz_bv_new_from_bytes_be(b_bytes, 0, size);
RzBitVector *result = rz_bv_add(a, b, &carry_a);
RzBitVector *ref = rz_bv_add_ref(a, b, &carry_b);
if (rz_bv_cmp(result, ref)) {
error = "rz_bv_add() result differs from reference";
goto finally;
}
if (carry_a != carry_b) {
error = "rz_bv_add() carry flag differs from reference";
goto finally;
}
finally:
rz_bv_free(result);
rz_bv_free(ref);
rz_bv_free(a);
rz_bv_free(b);
return error;
}
bool test_rz_bv_add(void) {
const char *error = NULL;
// Add 5-bit vectors with carry
error = test_rz_bv_add_against_ref(
5,
(ut8[1]){ 0x1f },
(ut8[1]){ 0x01 });
mu_assert_null(error, error);
// Add 5-bit vectors without carry
error = test_rz_bv_add_against_ref(
5,
(ut8[1]){ 0x10 },
(ut8[1]){ 0x01 });
mu_assert_null(error, error);
// Add 64-bit vectors with carry
error = test_rz_bv_add_against_ref(
64,
(ut8[8]){ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
(ut8[8]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 });
mu_assert_null(error, error);
// Add 64-bit vectors without carry
error = test_rz_bv_add_against_ref(
64,
(ut8[8]){ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
(ut8[8]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 });
mu_assert_null(error, error);
// Add 128-bit vectors with carry
error = test_rz_bv_add_against_ref(
128,
(ut8[16]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
(ut8[16]){ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });
mu_assert_null(error, error);
// Add 128-bit vectors without carry
error = test_rz_bv_add_against_ref(
128,
(ut8[16]){ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
(ut8[16]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F });
mu_assert_null(error, error);
// Add 125-bit vectors with carry
error = test_rz_bv_add_against_ref(
125,
(ut8[16]){ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F },
(ut8[16]){ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
mu_assert_null(error, error);
// Add 125-bit vectors without carry
error = test_rz_bv_add_against_ref(
125,
(ut8[16]){ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x10 },
(ut8[16]){ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00 });
mu_assert_null(error, error);
mu_end;
}
bool test_rz_bv_cmp(void) {
RzBitVector *x, *y;
// x : 1000 0111, y : 0000 0111
x = rz_bv_new(8);
rz_bv_set(x, 0, true);
rz_bv_set(x, 1, true);
rz_bv_set(x, 2, true);
rz_bv_set(x, 7, true);
y = rz_bv_new(8);
rz_bv_set(y, 0, true);
rz_bv_set(y, 1, true);
rz_bv_set(y, 2, true);
// get msb and lsb of y
bool msb, lsb;
msb = rz_bv_msb(y);
lsb = rz_bv_lsb(y);
mu_assert("msb", msb == false);
mu_assert("lsb", lsb == true);
mu_assert_false(rz_bv_ule(x, y), "ule of -/+");
mu_assert_true(rz_bv_ule(y, x), "ule of +/-");
mu_assert_true(rz_bv_sle(x, y), "sle of -/+");
mu_assert_false(rz_bv_sle(y, x), "sle of +/-");
rz_bv_free(x);
rz_bv_free(y);
x = rz_bv_new_from_st64(32, -42);
y = rz_bv_new_from_st64(32, -20);
mu_assert_true(rz_bv_sle(x, y), "sle of -/-");
mu_assert_false(rz_bv_sle(y, x), "sle of -/-");
mu_assert_true(rz_bv_ule(x, y), "sle of -/-");
mu_assert_false(rz_bv_ule(y, x), "sle of -/-");
rz_bv_free(x);
rz_bv_free(y);
x = rz_bv_new_from_st64(32, 42);
y = rz_bv_new_from_st64(32, 20);
mu_assert_false(rz_bv_sle(x, y), "sle of +/+");
mu_assert_true(rz_bv_sle(y, y), "sle of +/+");
mu_assert_false(rz_bv_ule(x, y), "ule of +/+");
mu_assert_true(rz_bv_ule(y, y), "ule of +/+");
rz_bv_free(x);
rz_bv_free(y);
x = rz_bv_new_from_st64(32, 42);
y = rz_bv_new_from_st64(32, 42);
mu_assert_true(rz_bv_sle(x, y), "sle of ==");
mu_assert_true(rz_bv_ule(x, y), "ule of ==");
rz_bv_free(x);
rz_bv_free(y);
mu_end;
}
bool test_rz_bv_eq(void) {
RzBitVector *x = rz_bv_new_from_ut64(8, 42);
RzBitVector *y = rz_bv_new_from_ut64(8, 42);
bool r = rz_bv_eq(x, y);
mu_assert_true(r, "equal");
rz_bv_free(y);
y = rz_bv_new_from_ut64(8, 41);
r = rz_bv_eq(x, y);
mu_assert_false(r, "not equal");
rz_bv_free(y);
y = rz_bv_new_from_ut64(16, 42);
r = rz_bv_eq(x, y);
mu_assert_false(r, "not equal");
rz_bv_free(y);
rz_bv_free(x);
mu_end;
}
bool test_rz_bv_operation(void) {
RzBitVector *x, *y, *res, *prep, *append, *cut_h, *cut_t, *concat;
char *s;
// 0000 1000
x = rz_bv_new(8);
rz_bv_set(x, 3, true);
// prepend 3 : 000 0000 1000
prep = rz_bv_new(11);
rz_bv_set(prep, 3, true);
// append 5 : 0000 1000 0000 0
append = rz_bv_new(13);
rz_bv_set(append, 8, true);
// cut head 2: 00 1000
cut_h = rz_bv_new(6);
rz_bv_set(cut_h, 3, true);
// cut tail 4: 0000
cut_t = rz_bv_new(4);
// y : 1011
y = rz_bv_new(4);
rz_bv_set(y, 0, true);
rz_bv_set(y, 1, true);
rz_bv_set(y, 3, true);
concat = rz_bv_new(12);
rz_bv_set(concat, 0, true);
rz_bv_set(concat, 1, true);
rz_bv_set(concat, 3, true);
rz_bv_set(concat, 7, true);
res = rz_bv_prepend_zero(x, 3);
mu_assert("prepend 3 zero", is_equal_bv(res, prep));
s = rz_bv_as_string(res);
mu_assert_streq_free(s, "00000001000", "string bit value of bv");
s = rz_bv_as_hex_string(res, true);
mu_assert_streq_free(s, "0x008", "string hex value of bv");
rz_bv_free(res);
res = rz_bv_append_zero(x, 5);
mu_assert("append 5 zero", is_equal_bv(res, append));
s = rz_bv_as_string(res);
mu_assert_streq_free(s, "0000100000000", "string bit value of bv");
s = rz_bv_as_hex_string(res, true);
mu_assert_streq_free(s, "0x0100", "string hex value of bv");
rz_bv_free(res);
res = rz_bv_cut_head(x, 2);
mu_assert("cut head 2 zero", is_equal_bv(res, cut_h));
s = rz_bv_as_string(res);
mu_assert_streq_free(s, "001000", "string bit value of bv");
s = rz_bv_as_hex_string(res, true);
mu_assert_streq_free(s, "0x08", "string hex value of bv");
rz_bv_free(res);
res = rz_bv_cut_tail(x, 4);
mu_assert("cut tail 4 zero", is_equal_bv(res, cut_t));
s = rz_bv_as_string(res);
mu_assert_streq_free(s, "0000", "string bit value of bv");
s = rz_bv_as_hex_string(res, true);
mu_assert_streq_free(s, "0x0", "string hex value of bv");
rz_bv_free(res);
res = rz_bv_append(y, x);
mu_assert("append x and y", is_equal_bv(res, concat));
s = rz_bv_as_string(res);
mu_assert_streq_free(s, "000010001011", "string bit value of bv");
s = rz_bv_as_hex_string(res, true);
mu_assert_streq_free(s, "0x08b", "string hex value of bv");
rz_bv_free(res);
res = rz_bv_new_from_ut64(4, 0x5);
rz_bv_append_inplace(res, x);
s = rz_bv_as_hex_string(res, true);
mu_assert_streq_free(s, "0x085", "string hex value of bv");
rz_bv_free(res);
rz_bv_free(prep);
rz_bv_free(append);
rz_bv_free(cut_h);
rz_bv_free(cut_t);
rz_bv_free(concat);
rz_bv_free(x);
rz_bv_free(y);
mu_end;
}
bool test_rz_bv_cast(void) {
ut32 normal, shadow;
normal = 2021;
RzBitVector *bv = rz_bv_new_from_ut64(32, normal);
shadow = rz_bv_to_ut32(bv);
rz_bv_free(bv);
mu_assert("cast bv<->ut32", normal == shadow);
RzBitVector *one32 = rz_bv_new_one(32);
RzBitVector *one78 = rz_bv_new_one(78);
RzBitVector *one32_as78 = rz_bv_cast(one32, 78, 0);
mu_assert_true(rz_bv_eq(one78, one32_as78), "test one cast");
rz_bv_free(one32);
rz_bv_free(one78);
rz_bv_free(one32_as78);
RzBitVector *bv32 = rz_bv_new_from_ut64(32, 123);
RzBitVector *bv32_as64 = rz_bv_cast(bv32, 64, 0);
RzBitVector *bv64 = rz_bv_new_from_ut64(64, 123);
mu_assert_true(rz_bv_eq(bv64, bv32_as64), "test 123 from bv32 to bv64");
rz_bv_free(bv32);
rz_bv_free(bv32_as64);
rz_bv_free(bv64);
// narrow cast
ut64 val64 = 34017;
val64 <<= 32;
val64 |= 202301;
bv64 = rz_bv_new_from_ut64(64, val64);
bv32 = rz_bv_new_from_ut64(32, 202301);
RzBitVector *bv64_as32 = rz_bv_cast(bv64, 32, 0);
mu_assert_true(rz_bv_eq(bv64_as32, bv32), "test narrow cast from 64 to 32");
rz_bv_free(bv64);
rz_bv_free(bv32);
rz_bv_free(bv64_as32);
// signed cast
RzBitVector *neg_one32 = rz_bv_new_minus_one(32);
RzBitVector *neg_one64 = rz_bv_new_minus_one(64);
RzBitVector *neg_one32_as64 = rz_bv_signed_cast(neg_one32, 64);
RzBitVector *neg_one32_asu64 = rz_bv_unsigned_cast(neg_one32, 64);
mu_assert_true(rz_bv_eq(neg_one64, neg_one32_as64), "test signed cast from 32 to 64");
mu_assert_eq(rz_bv_to_ut64(neg_one32_asu64), (ut64)(ut32)(-1), "test unsigned cast for -1 from 32-bit to 64-bit");
mu_assert_eq(rz_bv_to_ut64(neg_one32_asu64),
rz_bv_to_ut64(neg_one32),
"test unsigned cast and convert to ut64 val");
rz_bv_free(neg_one32);
rz_bv_free(neg_one64);
rz_bv_free(neg_one32_asu64);
rz_bv_free(neg_one32_as64);
mu_end;
}
bool test_rz_bv_set_from_bytes_be(void) {
const ut8 data[0x10] = {
0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01,
0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe
};
RzBitVector bv;
rz_bv_init(&bv, 64);
rz_bv_set_from_bytes_be(&bv, data, 0, 64);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xefcdab8967452301", "aligned 64");
rz_bv_set_from_bytes_be(&bv, data, 0, 62);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xefcdab8967452300", "aligned 64, padding");
rz_bv_set_from_bytes_be(&bv, data, 0, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xefcdab8967452301", "aligned 64, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 42);
rz_bv_set_from_bytes_be(&bv, data, 0, 42);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x3bf36ae259d", "aligned 42");
rz_bv_set_from_bytes_be(&bv, data, 0, 40);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x3bf36ae259c", "aligned 42, padding");
rz_bv_set_from_bytes_be(&bv, data, 0, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x3bf36ae259d", "aligned 42, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 80);
rz_bv_set_from_bytes_be(&bv, data, 0, 80);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xefcdab89674523011032", "aligned 80");
rz_bv_set_from_bytes_be(&bv, data, 0, 78);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xefcdab89674523011030", "aligned 80, padding");
rz_bv_set_from_bytes_be(&bv, data, 0, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xefcdab89674523011032", "aligned 80, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 64);
rz_bv_set_from_bytes_be(&bv, data, 1, 64);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xdf9b5712ce8a4602", "off+1 64");
rz_bv_set_from_bytes_be(&bv, data, 1, 62);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xdf9b5712ce8a4600", "off+1, padding");
rz_bv_set_from_bytes_be(&bv, data, 1, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xdf9b5712ce8a4602", "off+1 64, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 42);
rz_bv_set_from_bytes_be(&bv, data, 1, 42);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x37e6d5c4b3a", "off+1 42");
rz_bv_set_from_bytes_be(&bv, data, 1, 40);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x37e6d5c4b38", "off+1 42, padding");
rz_bv_set_from_bytes_be(&bv, data, 1, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x37e6d5c4b3a", "off+1 42, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 80);
rz_bv_set_from_bytes_be(&bv, data, 1, 80);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xdf9b5712ce8a46022064", "off+1 80");
rz_bv_set_from_bytes_be(&bv, data, 1, 78);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xdf9b5712ce8a46022064", "off+1 80, padding");
rz_bv_set_from_bytes_be(&bv, data, 1, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xdf9b5712ce8a46022064", "off+1 80, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 64);
rz_bv_set_from_bytes_be(&bv, data, 7, 64);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe6d5c4b3a2918088", "off+7 64");
rz_bv_set_from_bytes_be(&bv, data, 7, 62);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe6d5c4b3a2918088", "off+7, padding");
rz_bv_set_from_bytes_be(&bv, data, 7, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe6d5c4b3a2918088", "off+7 64, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 42);
rz_bv_set_from_bytes_be(&bv, data, 7, 42);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x39b5712ce8a", "off+7 42");
rz_bv_set_from_bytes_be(&bv, data, 7, 40);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x39b5712ce88", "off+7 42, padding");
rz_bv_set_from_bytes_be(&bv, data, 7, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x39b5712ce8a", "off+7 42, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 80);
rz_bv_set_from_bytes_be(&bv, data, 7, 80);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe6d5c4b3a2918088192a", "off+7 80");
rz_bv_set_from_bytes_be(&bv, data, 7, 78);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe6d5c4b3a29180881928", "off+7 80, padding");
rz_bv_set_from_bytes_be(&bv, data, 7, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe6d5c4b3a2918088192a", "off+7 80, cut off");
rz_bv_fini(&bv);
const ut8 data_4[] = { 0xe };
rz_bv_init(&bv, 4);
rz_bv_set_from_bytes_be(&bv, data_4, 0, 4);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe", "off+0 4");
rz_bv_set_from_bytes_be(&bv, data_4, 0, 2);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x8", "off+0 4, padding");
rz_bv_set_from_bytes_be(&bv, data_4, 0, 8);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe", "off+0 4, cut off");
rz_bv_fini(&bv);
RzBitVector *hbv = rz_bv_new_from_bytes_be(data, 0, 64);
mu_assert_streq_free(rz_bv_as_hex_string(hbv, true), "0xefcdab8967452301", "aligned 64");
rz_bv_free(hbv);
mu_end;
}
bool test_rz_bv_set_from_bytes_le(void) {
const ut8 data[0x10] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
};
RzBitVector bv;
rz_bv_init(&bv, 64);
rz_bv_set_from_bytes_le(&bv, data, 0, 64);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xefcdab8967452301", "aligned 64");
rz_bv_set_from_bytes_le(&bv, data, 0, 62);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x2fcdab8967452301", "aligned 64, padding");
rz_bv_set_from_bytes_le(&bv, data, 0, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xefcdab8967452301", "aligned 64, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 42);
rz_bv_set_from_bytes_le(&bv, data, 0, 42);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x38967452301", "aligned 42");
rz_bv_set_from_bytes_le(&bv, data, 0, 40);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x08967452301", "aligned 42, padding");
rz_bv_set_from_bytes_le(&bv, data, 0, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x38967452301", "aligned 42, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 80);
rz_bv_set_from_bytes_le(&bv, data, 0, 80);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xdcfeefcdab8967452301", "aligned 80");
rz_bv_set_from_bytes_le(&bv, data, 0, 78);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x1cfeefcdab8967452301", "aligned 80, padding");
rz_bv_set_from_bytes_le(&bv, data, 0, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xdcfeefcdab8967452301", "aligned 80, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 64);
rz_bv_set_from_bytes_le(&bv, data, 1, 64);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x77e6d5c4b3a29180", "off+1 64");
rz_bv_set_from_bytes_le(&bv, data, 1, 62);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x37e6d5c4b3a29180", "off+1, padding");
rz_bv_set_from_bytes_le(&bv, data, 1, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x77e6d5c4b3a29180", "off+1 64, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 42);
rz_bv_set_from_bytes_le(&bv, data, 1, 42);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x1c4b3a29180", "off+1 42");
rz_bv_set_from_bytes_le(&bv, data, 1, 40);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x0c4b3a29180", "off+1 42, padding");
rz_bv_set_from_bytes_le(&bv, data, 1, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x1c4b3a29180", "off+1 42, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 80);
rz_bv_set_from_bytes_le(&bv, data, 1, 80);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x6e7f77e6d5c4b3a29180", "off+1 80");
rz_bv_set_from_bytes_le(&bv, data, 1, 78);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x2e7f77e6d5c4b3a29180", "off+1 80, padding");
rz_bv_set_from_bytes_le(&bv, data, 1, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x6e7f77e6d5c4b3a29180", "off+1 80, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 64);
rz_bv_set_from_bytes_le(&bv, data, 7, 64);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xfddf9b5712ce8a46", "off+7 64");
rz_bv_set_from_bytes_le(&bv, data, 7, 62);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x3ddf9b5712ce8a46", "off+7, padding");
rz_bv_set_from_bytes_le(&bv, data, 7, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xfddf9b5712ce8a46", "off+7 64, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 42);
rz_bv_set_from_bytes_le(&bv, data, 7, 42);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x35712ce8a46", "off+7 42");
rz_bv_set_from_bytes_le(&bv, data, 7, 40);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x05712ce8a46", "off+7 42, padding");
rz_bv_set_from_bytes_le(&bv, data, 7, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x35712ce8a46", "off+7 42, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 80);
rz_bv_set_from_bytes_le(&bv, data, 7, 80);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x75b9fddf9b5712ce8a46", "off+7 80");
rz_bv_set_from_bytes_le(&bv, data, 7, 78);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x35b9fddf9b5712ce8a46", "off+7 80, padding");
rz_bv_set_from_bytes_le(&bv, data, 7, 100);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x75b9fddf9b5712ce8a46", "off+7 80, cut off");
rz_bv_fini(&bv);
rz_bv_init(&bv, 1);
rz_bv_set_from_bytes_le(&bv, data, 0, 1);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x1", "off+0 1");
rz_bv_fini(&bv);
const ut8 data_4[] = { 0xe };
rz_bv_init(&bv, 4);
rz_bv_set_from_bytes_le(&bv, data_4, 0, 4);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe", "off+0 4");
rz_bv_set_from_bytes_le(&bv, data_4, 0, 2);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0x2", "off+0 4, padding");
rz_bv_set_from_bytes_le(&bv, data_4, 0, 8);
mu_assert_streq_free(rz_bv_as_hex_string(&bv, true), "0xe", "off+0 4, cut off");
rz_bv_fini(&bv);
RzBitVector *hbv = rz_bv_new_from_bytes_le(data, 0, 64);
mu_assert_streq_free(rz_bv_as_hex_string(hbv, true), "0xefcdab8967452301", "aligned 64");
rz_bv_free(hbv);
mu_end;
}
bool test_rz_bv_set_from_buffer_ble(bool big_endian) {
const ut8 data[0x10] = {
0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01,
0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe
};
const ut8 len[5] = {
4, 42, 64, 80, 82
};
RzBuffer *buf = rz_buf_new_with_bytes(data, 0x10);
char *error = NULL;
for (int i = 0; i < sizeof(len); i++) {
RzBitVector bv;
rz_bv_init(&bv, len[i]);
for (ut32 bits_to_copy = 1; bits_to_copy < bv.len + 10; bits_to_copy++) {
rz_buf_seek(buf, 0, RZ_BUF_SET);
rz_bv_set_from_buffer_ble(&bv, buf, bits_to_copy, big_endian);
char *result = rz_bv_as_hex_string(&bv, true);
rz_bv_set_from_bytes_ble(&bv, data, 0, bits_to_copy, big_endian);
char *ref = rz_bv_as_hex_string(&bv, true);
if (strcmp(result, ref)) {
error = rz_str_newf(
"%s result (%s) doesn't match reference (%s) for bit_size: %" PFMT32u " and bitvector length: %" PFMT32u,
big_endian ? "rz_bv_set_from_buffer_be()" : "rz_bv_set_from_buffer_le()",
result,
ref,
bits_to_copy,
bv.len);
mu_fail(error);
}
free(result);
free(ref);
}
rz_bv_fini(&bv);
}
rz_buf_free(buf);
mu_end;
}
bool test_rz_bv_as_hex_string(void) {
char *s = NULL;
// small
RzBitVector *bv = rz_bv_new_from_ut64(32, 42);
s = rz_bv_as_hex_string(bv, true);
mu_assert_streq_free(s, "0x0000002a", "string hex value of bv");
s = rz_bv_as_hex_string(bv, false);
mu_assert_streq_free(s, "0x2a", "string hex value of bv");
rz_bv_set_from_ut64(bv, 0x32a);
s = rz_bv_as_hex_string(bv, true);
mu_assert_streq_free(s, "0x0000032a", "string hex value of bv");
s = rz_bv_as_hex_string(bv, false);
mu_assert_streq_free(s, "0x32a", "string hex value of bv");
rz_bv_set_from_ut64(bv, 0x0);
s = rz_bv_as_hex_string(bv, true);
mu_assert_streq_free(s, "0x00000000", "string hex value of bv");
s = rz_bv_as_hex_string(bv, false);
mu_assert_streq_free(s, "0x0", "string hex value of bv");
rz_bv_free(bv);
bv = rz_bv_new_from_ut64(1, 1);
mu_assert_streq_free(rz_bv_as_hex_string(bv, true), "0x1", "string hex value of bv");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x1", "string hex value of bv");
rz_bv_set_from_ut64(bv, 0);
mu_assert_streq_free(rz_bv_as_hex_string(bv, true), "0x0", "string hex value of bv");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "string hex value of bv");
rz_bv_free(bv);
bv = rz_bv_new_from_ut64(7, 0x7f);
mu_assert_streq_free(rz_bv_as_hex_string(bv, true), "0x7f", "string hex value of bv");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x7f", "string hex value of bv");
rz_bv_set_from_ut64(bv, 0x70);
mu_assert_streq_free(rz_bv_as_hex_string(bv, true), "0x70", "string hex value of bv");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x70", "string hex value of bv");
rz_bv_free(bv);
// big
bv = rz_bv_new_from_ut64(128, 100);
rz_bv_set(bv, 2, true);
rz_bv_set(bv, 5, true);
rz_bv_set(bv, 6, true);
s = rz_bv_as_hex_string(bv, true);
mu_assert_streq_free(s, "0x00000000000000000000000000000064", "string hex value of bv");
s = rz_bv_as_hex_string(bv, false);
mu_assert_streq_free(s, "0x64", "string hex value of bv");
rz_bv_set(bv, 16, true);
s = rz_bv_as_hex_string(bv, true);
mu_assert_streq_free(s, "0x00000000000000000000000000010064", "string hex value of bv");
s = rz_bv_as_hex_string(bv, false);
mu_assert_streq_free(s, "0x10064", "string hex value of bv");
rz_bv_set_from_ut64(bv, 0x0);
s = rz_bv_as_hex_string(bv, true);
mu_assert_streq_free(s, "0x00000000000000000000000000000000", "string hex value of bv");
s = rz_bv_as_hex_string(bv, false);
mu_assert_streq_free(s, "0x0", "string hex value of bv");
rz_bv_free(bv);
bv = rz_bv_new_from_st64(64 + 7, -1);
mu_assert_streq_free(rz_bv_as_hex_string(bv, true), "0x7fffffffffffffffff", "string hex value of bv");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x7fffffffffffffffff", "string hex value of bv");
rz_bv_set_from_ut64(bv, 0);
mu_assert_streq_free(rz_bv_as_hex_string(bv, true), "0x000000000000000000", "string hex value of bv");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "string hex value of bv");
rz_bv_free(bv);
mu_end;
}
bool test_rz_bv_clz(void) {
#define TEST_CLZ(bva, expect) \
do { \
RzBitVector *a = bva; \
ut32 r = rz_bv_clz(a); \
mu_assert_eq(r, expect, "clz"); \
rz_bv_free(a); \
} while (0)
TEST_CLZ(rz_bv_new_from_ut64(32, 0x2a), 26);
TEST_CLZ(rz_bv_new_from_ut64(32, 0x0), 32);
TEST_CLZ(rz_bv_new_from_ut64(32, 0xffffffff), 0);
TEST_CLZ(rz_bv_new_from_ut64(64, 0xffffffffffffffff), 0);
TEST_CLZ(rz_bv_new_from_ut64(64, 0x2a), 58);
TEST_CLZ(rz_bv_new_from_ut64(74, 0x2a), 68);
TEST_CLZ(rz_bv_new_from_st64(74, -1), 0);
TEST_CLZ(rz_bv_new_from_ut64(74, 0), 74);
#undef TEST_CLZ
mu_end;
}
bool test_rz_bv_ctz(void) {
#define TEST_CTZ(bva, expect) \
do { \
RzBitVector *a = bva; \
ut32 r = rz_bv_ctz(a); \
mu_assert_eq(r, expect, "clz"); \
rz_bv_free(a); \
} while (0)
TEST_CTZ(rz_bv_new_from_ut64(32, 0x1), 0);
TEST_CTZ(rz_bv_new_from_ut64(32, 0x0), 32);
TEST_CTZ(rz_bv_new_from_ut64(32, 0xffffff00), 8);
TEST_CTZ(rz_bv_new_from_ut64(64, 0xfffffffffffff800), 11);
TEST_CTZ(rz_bv_new_from_ut64(74, 0x8), 3);
TEST_CTZ(rz_bv_new_from_st64(74, -1), 0);
TEST_CTZ(rz_bv_new_from_ut64(74, 0), 74);
#undef TEST_CTZ
mu_end;
}
bool test_rz_bv_div(void) {
#define TEST_DIV(bva, bvb, sr) \
do { \
RzBitVector *a = bva; \
RzBitVector *b = bvb; \
RzBitVector *r = rz_bv_div(a, b); \
mu_assert_notnull(r, "division succes"); \
mu_assert_eq(rz_bv_len(r), rz_bv_len(a), "division result len"); \
mu_assert_streq_free(rz_bv_as_hex_string(r, false), sr, "division result"); \
rz_bv_free(a); \
rz_bv_free(b); \
rz_bv_free(r); \
} while (0)
// small
TEST_DIV(rz_bv_new_from_ut64(32, 42), rz_bv_new_from_ut64(32, 3), "0xe");
TEST_DIV(rz_bv_new_from_ut64(32, 42), rz_bv_new_from_ut64(32, 0), "0xffffffff");
TEST_DIV(rz_bv_new_from_ut64(32, 0), rz_bv_new_from_ut64(32, 0), "0xffffffff");
TEST_DIV(rz_bv_new_from_ut64(32, 0xffffffd6), rz_bv_new_from_ut64(32, 42), "0x6186185");
TEST_DIV(rz_bv_new_from_ut64(32, 42), rz_bv_new_from_ut64(32, 42), "0x1");
// big
TEST_DIV(rz_bv_new_from_ut64(70, 42), rz_bv_new_from_ut64(70, 3), "0xe");
TEST_DIV(rz_bv_new_from_ut64(70, 42), rz_bv_new_from_ut64(70, 0), "0x3fffffffffffffffff");
TEST_DIV(rz_bv_new_from_ut64(70, 0), rz_bv_new_from_ut64(70, 0), "0x3fffffffffffffffff");
TEST_DIV(rz_bv_new_from_ut64(70, 0xffffffd6), rz_bv_new_from_ut64(70, 42), "0x6186185");
TEST_DIV(rz_bv_new_from_ut64(70, 42), rz_bv_new_from_ut64(70, 42), "0x1");
RzBitVector *superbig = rz_bv_new_from_ut64(80, 42);
mu_assert_true(rz_bv_lshift(superbig, 70), "Shift failed");
TEST_DIV(superbig, rz_bv_new_from_ut64(80, 2), "0x5400000000000000000");
#undef TEST_DIV
mu_end;
}
bool test_rz_bv_mod(void) {
#define TEST_MOD(bva, bvb, sr) \
do { \
RzBitVector *a = bva; \
RzBitVector *b = bvb; \
RzBitVector *r = rz_bv_mod(a, b); \
mu_assert_notnull(r, "division succes"); \
mu_assert_eq(rz_bv_len(r), rz_bv_len(a), "division result len"); \
mu_assert_streq_free(rz_bv_as_hex_string(r, false), sr, "division result"); \
rz_bv_free(a); \
rz_bv_free(b); \
rz_bv_free(r); \
} while (0)
// small
TEST_MOD(rz_bv_new_from_ut64(32, 42), rz_bv_new_from_ut64(32, 3), "0x0");
TEST_MOD(rz_bv_new_from_ut64(32, 42), rz_bv_new_from_ut64(32, 0), "0x2a");
TEST_MOD(rz_bv_new_from_ut64(32, 0), rz_bv_new_from_ut64(32, 0), "0x0");
TEST_MOD(rz_bv_new_from_ut64(32, 0xffffffd6), rz_bv_new_from_ut64(32, 42), "0x4");
TEST_MOD(rz_bv_new_from_ut64(32, 42), rz_bv_new_from_ut64(32, 42), "0x0");
// big
TEST_MOD(rz_bv_new_from_ut64(70, 42), rz_bv_new_from_ut64(70, 3), "0x0");
TEST_MOD(rz_bv_new_from_ut64(70, 42), rz_bv_new_from_ut64(70, 0), "0x2a");
TEST_MOD(rz_bv_new_from_ut64(70, 0), rz_bv_new_from_ut64(70, 0), "0x0");
TEST_MOD(rz_bv_new_from_ut64(70, 0xffffffd6), rz_bv_new_from_ut64(70, 42), "0x4");
TEST_MOD(rz_bv_new_from_ut64(70, 42), rz_bv_new_from_ut64(70, 42), "0x0");
RzBitVector *superbig = rz_bv_new_from_ut64(80, 42);
mu_assert_true(rz_bv_lshift(superbig, 70), "Shift failed");
TEST_MOD(rz_bv_dup(superbig), rz_bv_new_from_ut64(80, 2), "0x0");
rz_bv_set(superbig, 0, true);
rz_bv_set(superbig, 1, true);
TEST_MOD(superbig, rz_bv_new_from_ut64(80, 64), "0x3");
#undef TEST_DIV
mu_end;
}
static bool test_rz_bv_len_bytes(void) {
#define TEST_LEN_BYTES(bits, bytes) \
do { \
RzBitVector *bv = rz_bv_new_from_ut64(bits, 0); \
mu_assert_eq(rz_bv_len_bytes(bv), bytes, "len"); \
rz_bv_free(bv); \
} while (0);
TEST_LEN_BYTES(1, 1);
TEST_LEN_BYTES(2, 1);
TEST_LEN_BYTES(3, 1);
TEST_LEN_BYTES(4, 1);
TEST_LEN_BYTES(5, 1);
TEST_LEN_BYTES(6, 1);
TEST_LEN_BYTES(7, 1);
TEST_LEN_BYTES(8, 1);
TEST_LEN_BYTES(9, 2);
TEST_LEN_BYTES(0x10, 2);
TEST_LEN_BYTES(0x11, 3);
TEST_LEN_BYTES(128, 16);
TEST_LEN_BYTES(129, 17);
#undef TEST_LEN_BYTES
mu_end;
}
bool test_rz_bv_set_operations(void) {
RzBitVector *bv = rz_bv_new(43);
rz_bv_set_all(bv, true);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x7ffffffffff", "set all 1");
mu_assert_true(rz_bv_is_all_one(bv), "all bits are 1");
rz_bv_set_all(bv, false);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "set all 0");
mu_assert_false(rz_bv_is_all_one(bv), "not all 1");
rz_bv_free(bv);
bv = rz_bv_new(64);
rz_bv_set_all(bv, true);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0xffffffffffffffff", "set all 1");
mu_assert_true(rz_bv_is_all_one(bv), "all bits are 1");
rz_bv_set_all(bv, false);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "set all 0");
mu_assert_false(rz_bv_is_all_one(bv), "not all 1");
rz_bv_free(bv);
bv = rz_bv_new(73);
rz_bv_set_all(bv, true);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x1ffffffffffffffffff", "set all 1");
mu_assert_true(rz_bv_is_all_one(bv), "all bits are 1");
rz_bv_set_all(bv, false);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "set all 0");
mu_assert_false(rz_bv_is_all_one(bv), "not all 1");
rz_bv_free(bv);
bv = rz_bv_new(80);
rz_bv_set_all(bv, true);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0xffffffffffffffffffff", "set all 1");
mu_assert_true(rz_bv_is_all_one(bv), "all bits are 1");
rz_bv_set_all(bv, false);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "set all 0");
mu_assert_false(rz_bv_is_all_one(bv), "not all 1");
rz_bv_free(bv);
bv = rz_bv_new(42);
rz_bv_set_range(bv, 0, bv->len - 1, true);
mu_assert_true(rz_bv_is_all_one(bv), "set all 1 by set_range");
// 11 1111 1111 1111 1100 0000 0011 1111 1111 1111 1111
rz_bv_set_range(bv, 18, 25, false);
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x3fffc03ffff", "range set 18~25 to 0");
rz_bv_free(bv);
bv = rz_bv_new(16);
mu_assert_false(rz_bv_set_range(bv, 16, 20, true), "set out of range");
rz_bv_free(bv);
mu_end;
}
bool test_rz_bv_set_range_large(void) {
RzBitVector *bv = rz_bv_new(128);
// Expect failure on inverted range
mu_assert_false(rz_bv_set_range(bv, 20, 10, true), "expected failure for inverse range");
// Bitrange with unalign prefix bits
mu_assert_true(rz_bv_set_range(bv, 5, 7, true), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0xe0", "range set 5~7 to 1");
mu_assert_true(rz_bv_set_range(bv, 5, 7, false), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "range set 5~7 to 0");
// Bitrange with unalign prefix and suffix bits
mu_assert_true(rz_bv_set_range(bv, 5, 8, true), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x1e0", "range set 5~8 to 1");
mu_assert_true(rz_bv_set_range(bv, 5, 8, false), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "range set 5~8 to 0");
// Only suffix bit
mu_assert_true(rz_bv_set_range(bv, 8, 8, true), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x100", "range set 8~8 to 1");
mu_assert_true(rz_bv_set_range(bv, 8, 8, false), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "range set 8~8 to 0");
// Bitrange with unaligned prefix, suffix bits and aligned middle bytes
mu_assert_true(rz_bv_set_range(bv, 5, 24, true), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x1ffffe0", "range set 5~24 to 1");
mu_assert_true(rz_bv_set_range(bv, 5, 24, false), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "range set 5~24 to 0");
// Aligned
mu_assert_true(rz_bv_set_range(bv, 16, 31, true), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0xffff0000", "range set 16~31 to 1");
mu_assert_true(rz_bv_set_range(bv, 16, 31, false), "expect rz_bv_set_range() success");
mu_assert_streq_free(rz_bv_as_hex_string(bv, false), "0x0", "range set 16~31 to 0");
rz_bv_free(bv);
mu_end;
}
static bool test_rz_bv_set_to_bytes_le(void) {
{
ut8 buf8[8] = { 0 };
RzBitVector *bv = rz_bv_new_from_ut64(64, 0xc0ffee4201234567);
rz_bv_set_to_bytes_le(bv, buf8);
const ut8 expect8[8] = { 0x67, 0x45, 0x23, 0x01, 0x42, 0xee, 0xff, 0xc0 };
mu_assert_memeq(buf8, expect8, sizeof(expect8), "set to bytes le");
rz_bv_free(bv);
}
{
ut8 buf4[4] = { 0 };
RzBitVector *bv = rz_bv_new_from_ut64(32, 0xc0ffee42);
rz_bv_set_to_bytes_le(bv, buf4);
const ut8 expect4[4] = { 0x42, 0xee, 0xff, 0xc0 };
mu_assert_memeq(buf4, expect4, sizeof(expect4), "set to bytes le");
rz_bv_free(bv);
}
{
ut8 buf2[2] = { 0xff, 0xff }; // make sure these trailing bits are not overwritten
RzBitVector *bv = rz_bv_new_from_ut64(13, 0x0);
rz_bv_set_to_bytes_le(bv, buf2);
const ut8 expect2[2] = { 0x0, 0xe0 };
mu_assert_memeq(buf2, expect2, sizeof(expect2), "set to bytes le");
rz_bv_free(bv);
}
{
ut8 buf9[9] = { 0 };
RzBitVector *bv = rz_bv_new_from_ut64(64 + 8, 0xc0ffee4200000000);
mu_assert_true(rz_bv_lshift_fill(bv, 8, true), "Shift failed");
rz_bv_set_to_bytes_le(bv, buf9);
const ut8 expect9[9] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0x42, 0xee, 0xff, 0xc0 };
mu_assert_memeq(buf9, expect9, sizeof(expect9), "set to bytes le");
rz_bv_free(bv);
}
{
ut8 buf9[9] = { 0 };
buf9[8] = 0xff; // make sure these trailing bits are not overwritten
RzBitVector *bv = rz_bv_new_from_ut64(64 + 6, 0xffffee00000000);
mu_assert_true(rz_bv_lshift_fill(bv, 8, true), "Shift failed");
rz_bv_set_to_bytes_le(bv, buf9);
const ut8 expect9[9] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0xee, 0xff, 0xff, 0xc0 };
mu_assert_memeq(buf9, expect9, sizeof(expect9), "set to bytes le");
rz_bv_free(bv);
}
mu_end;
}
bool test_rz_bv_copy_nbits(void) {
const ut32 size = 20;
const ut32 part_sz = 8;
ut32 actual_copy = 0;
/// 1010 0000 0000 1111 1111
RzBitVector *src = rz_bv_new(size);
for (ut32 i = 0; i < part_sz; ++i) {
rz_bv_set(src, i, true);
}
rz_bv_set(src, src->len - 1, true);
rz_bv_set(src, src->len - 3, true);
/// copy part of bv to a new one with the same size
RzBitVector *small = rz_bv_new(part_sz);
actual_copy = rz_bv_copy_nbits(small, 0, src, 0, part_sz);
mu_assert_eq(actual_copy, part_sz, "copy part_sz to normal");
mu_assert_streq_free(rz_bv_as_string(small), "11111111", "copy nbits small bv");
/// copy part of bv to a new one which has more spaces
RzBitVector *normal = rz_bv_new(size);
actual_copy = rz_bv_copy_nbits(normal, 0, src, 0, part_sz);
mu_assert_eq(actual_copy, part_sz, "copy part_sz bits to normal");
mu_assert_streq_free(rz_bv_as_string(normal), "00000000000011111111", "copy nbits normal length bv");
/// copy part of bv to the medium
RzBitVector *res = rz_bv_new(size);
actual_copy = rz_bv_copy_nbits(res, 8, src, 0, part_sz);
mu_assert_eq(actual_copy, part_sz, "copy part_sz bits to medium");
mu_assert_streq_free(rz_bv_as_string(res), "00001111111100000000", "copy nbits to medium");
/// copy non-zero, copy last 11 bits of `b` to the head of `a`
/// dst : a = 0001 0010 0011 ...
/// src : b = ... .001 1000 0110
/// expect : 0011 0000 1101 ... = 0x30d45678
RzBitVector *a = rz_bv_new_from_ut64(32, 0x12345678);
RzBitVector *b = rz_bv_new_from_ut64(32, 0x1986);
actual_copy = rz_bv_copy_nbits(a, a->len - 11, b, 0, 11);
mu_assert_eq(actual_copy, 11, "copy non-zero 11 bits");
mu_assert_streq_free(rz_bv_as_hex_string(a, false), "0x30d45678", "copy non zero");
/// would fail (do nothing) if copy overflow is possible
RzBitVector *too_small = rz_bv_new(part_sz);
actual_copy = rz_bv_copy_nbits(too_small, 0, src, 0, part_sz + 2);
mu_assert_eq(actual_copy, 0, "copy 0 bits");
mu_assert_true(rz_bv_is_zero_vector(too_small), "copy nothing");
rz_bv_free(src);
rz_bv_free(small);
rz_bv_free(normal);
rz_bv_free(res);
rz_bv_free(too_small);
rz_bv_free(a);
rz_bv_free(b);
mu_end;
}
bool test_rz_bv_copy_nbits_inplace(void) {
const ut8 array_128[128] = {
0x00,
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x0b,
0x0c,
0x0d,
0x0e,
0x0f,
};
const char *large_exp_1 = "0x0e0f02030405060708090a0b0c0d0e0f";
const char *large_exp_2 = "0x0e0f02030405060708090a0b0c0d0e1f";
RzBitVector *small_20 = rz_bv_new_from_ut64(20, 0x01234);
RzBitVector *large_128 = rz_bv_new_from_bytes_be(array_128, 0, 128);
mu_assert_eq(rz_bv_copy_nbits(small_20, 1, small_20, 5, 7), 7, "wrong num bits copied");
mu_assert_eq(rz_bv_to_ut64(small_20), 0x01222, "Mismatch in place copy");
mu_assert_eq(rz_bv_copy_nbits(small_20, 0, small_20, 0, 21), 0, "copy overflow");
mu_assert_eq(rz_bv_to_ut64(small_20), 0x01222, "Mismatch in place copy");
mu_assert_eq(rz_bv_copy_nbits(small_20, 1, small_20, 0, 20), 0, "copy overflow");
mu_assert_eq(rz_bv_to_ut64(small_20), 0x01222, "Mismatch in place copy");
mu_assert_eq(rz_bv_copy_nbits(small_20, 0, small_20, 1, 20), 0, "copy overflow");
mu_assert_eq(rz_bv_to_ut64(small_20), 0x01222, "Mismatch in place copy");
mu_assert_eq(rz_bv_copy_nbits(small_20, 0, small_20, 0, 20), 20, "one to one copy");
mu_assert_eq(rz_bv_to_ut64(small_20), 0x01222, "Mismatch in place copy");
mu_assert_eq(rz_bv_copy_nbits(small_20, 0, small_20, 0, 20), 20, "one to one copy");
mu_assert_eq(rz_bv_to_ut64(small_20), 0x01222, "Mismatch in place copy");
mu_assert_eq(rz_bv_copy_nbits(large_128, 112, large_128, 0, 16), 16, "wrong num bits copied");
mu_assert_streq_free(rz_bv_as_hex_string(large_128, true), large_exp_1, "copy to limits aligned");
mu_assert_eq(rz_bv_copy_nbits(large_128, 2, large_128, 1, 7), 7, "wrong num bits copied");
mu_assert_streq_free(rz_bv_as_hex_string(large_128, true), large_exp_2, "copy overlap unaligned");
mu_assert_eq(rz_bv_copy_nbits(large_128, 120, large_128, 0, 16), 0, "wrong num bits copied");
rz_bv_free(small_20);
rz_bv_free(large_128);
mu_end;
}
bool test_rz_bv_cast_inplace(void) {
const ut8 array_128[128] = {
0x00,
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x0b,
0x0c,
0x0d,
0x0e,
0x0f,
};
RzBitVector *small = rz_bv_new_from_ut64(20, 0x01234);
RzBitVector *large = rz_bv_new_from_bytes_be(array_128, 0, 128);
mu_assert_true(rz_bv_cast_inplace(small, 5, true), "Cast failed");
mu_assert_eq(rz_bv_to_ut64(small), 0x14, "Mismatch after cast");
mu_assert_eq(small->len, 5, "New size is off");
mu_assert_null(small->bits.large_a, "Should have been NULL");
mu_assert_eq(small->_elem_len, 0, "Should be 0");
mu_assert_true(rz_bv_cast_inplace(small, 64, true), "Cast failed");
mu_assert_eq(rz_bv_to_ut64(small), 0xfffffffffffffff4ULL, "Mismatch after cast");
mu_assert_eq(small->len, 64, "New size is off");
mu_assert_null(small->bits.large_a, "Should have been NULL");
mu_assert_eq(small->_elem_len, 0, "Should be 0");
mu_assert_true(rz_bv_cast_inplace(small, 65, true), "Cast failed");
mu_assert_streq_free(rz_bv_as_hex_string(small, false), "0x1fffffffffffffff4", "small to large cast failed");
mu_assert_eq(small->len, 65, "New size is off");
mu_assert_notnull(small->bits.large_a, "Buffer not set");
mu_assert_eq(small->_elem_len, 9, "Buffer length wrong");
rz_bv_free(small);
small = rz_bv_new_from_ut64(20, 0x01234);
mu_assert_true(rz_bv_cast_inplace(small, 5, false), "Cast failed");
mu_assert_eq(rz_bv_to_ut64(small), 0x14, "Mismatch after cast");
mu_assert_eq(small->len, 5, "New size is off");
mu_assert_null(small->bits.large_a, "Should have been NULL");
mu_assert_eq(small->_elem_len, 0, "Should be 0");
mu_assert_true(rz_bv_cast_inplace(small, 64, false), "Cast failed");
mu_assert_eq(rz_bv_to_ut64(small), 0x14, "Mismatch after cast");
mu_assert_eq(small->len, 64, "New size is off");
mu_assert_null(small->bits.large_a, "Should have been NULL");
mu_assert_eq(small->_elem_len, 0, "Should be 0");
mu_assert_true(rz_bv_cast_inplace(small, 65, true), "Cast failed");
mu_assert_streq_free(rz_bv_as_hex_string(small, false), "0x10000000000000014", "small to large cast failed");
mu_assert_eq(small->len, 65, "New size is off");
mu_assert_notnull(small->bits.large_a, "Buffer not set");
mu_assert_eq(small->_elem_len, 9, "Buffer length wrong");
// Cast down again
mu_assert_true(rz_bv_cast_inplace(small, 17, true), "Cast failed");
mu_assert_eq(rz_bv_to_ut64(small), 0x14, "Mismatch after cast");
mu_assert_streq_free(rz_bv_as_hex_string(small, true), "0x00014", "small to large cast failed");
mu_assert_eq(small->len, 17, "New size is off");
// buffer is not freed
mu_assert_notnull(small->bits.large_a, "Buffer not set");
mu_assert_eq(small->_elem_len, 9, "Buffer length wrong");
mu_assert_true(rz_bv_cast_inplace(small, 66, true), "Cast failed");
mu_assert_streq_free(rz_bv_as_hex_string(small, true), "0x03fffffffffffe0014", "small to large cast failed");
mu_assert_eq(small->len, 66, "New size is off");
mu_assert_notnull(small->bits.large_a, "Buffer not set");
mu_assert_eq(small->_elem_len, 9, "Buffer length wrong");
// Cast large to small
mu_assert_true(rz_bv_cast_inplace(large, 32, true), "Cast failed");
mu_assert_eq(rz_bv_to_ut64(large), 0x0c0d0e0f, "Mismatch after cast");
mu_assert_streq_free(rz_bv_as_hex_string(large, true), "0x0c0d0e0f", "small to large cast failed");
mu_assert_eq(large->len, 32, "New size is off");
mu_assert_notnull(large->bits.large_a, "Buffer not set");
mu_assert_eq(large->_elem_len, 16, "Buffer length wrong");
// Cast small to large
mu_assert_true(rz_bv_cast_inplace(large, 256, true), "Cast failed");
mu_assert_streq_free(rz_bv_as_hex_string(large, false), "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff0c0d0e0f", "small to large cast failed");
mu_assert_eq(large->len, 256, "New size is off");
mu_assert_notnull(large->bits.large_a, "Buffer not set");
mu_assert_eq(large->_elem_len, 32, "Buffer length wrong");
// Cast large 256 bit to 128 bit.
mu_assert_true(rz_bv_cast_inplace(large, 128, true), "Cast failed");
mu_assert_streq_free(rz_bv_as_hex_string(large, false), "0xffffffffffffffffffffffff0c0d0e0f", "large to large cast failed");
mu_assert_eq(large->len, 128, "New size is off");
mu_assert_notnull(large->bits.large_a, "Buffer not set");
mu_assert_eq(large->_elem_len, 32, "Buffer length wrong");
rz_bv_free(small);
rz_bv_free(large);
small = rz_bv_new_from_ut64(20, 0xe1234);
mu_assert_true(rz_bv_unsigned_cast_inplace(small, 24), "Cast failed");
mu_assert_eq(small->len, 24, "new size");
mu_assert_streq_free(rz_bv_as_hex_string(small, false), "0xe1234", "unsigned cast inplace result");
rz_bv_free(small);
small = rz_bv_new_from_ut64(20, 0x31234);
mu_assert_true(rz_bv_unsigned_cast_inplace(small, 24), "Cast failed");
mu_assert_eq(small->len, 24, "new size");
mu_assert_streq_free(rz_bv_as_hex_string(small, false), "0x31234", "unsigned cast inplace result");
rz_bv_free(small);
small = rz_bv_new_from_ut64(20, 0xe1234);
mu_assert_true(rz_bv_signed_cast_inplace(small, 24), "Cast failed");
mu_assert_eq(small->len, 24, "new size");
mu_assert_streq_free(rz_bv_as_hex_string(small, false), "0xfe1234", "signed cast inplace result");
rz_bv_free(small);
small = rz_bv_new_from_ut64(20, 0x31234);
mu_assert_true(rz_bv_signed_cast_inplace(small, 24), "Cast failed");
mu_assert_eq(small->len, 24, "new size");
mu_assert_streq_free(rz_bv_as_hex_string(small, false), "0x31234", "signed cast inplace result");
rz_bv_free(small);
mu_end;
}
/**
* \brief Reference implementation of rz_bv_copy_nbits() to test against
*/
static ut32 rz_bv_copy_nbits_ref(RzBitVector *dst, ut32 dst_start_pos, const RzBitVector *src, ut32 src_start_pos, ut32 nbit) {
rz_return_val_if_fail(src && dst, 0);
ut32 max_nbit = RZ_MIN((src->len - src_start_pos), (dst->len - dst_start_pos));
// prevent overflow
if (max_nbit < nbit) {
return 0;
}
for (ut32 i = 0; i < nbit; ++i) {
rz_bv_set(dst, dst_start_pos + i, rz_bv_get(src, src_start_pos + i));
}
return nbit;
}
/**
* \brief Performs rz_bv_copy_nbits() with actual and reference implementation and compares results
*/
static const char *test_rz_bv_copy_nbits_against_ref(const RzBitVector *src, ut32 src_pos, RzBitVector *dst, ut32 dst_pos, ut32 nbit) {
RzBitVector *src_copy = rz_bv_new(rz_bv_len(src));
RzBitVector *dst_copy = rz_bv_new(rz_bv_len(dst));
RzBitVector *dst_copy_ref = rz_bv_new(rz_bv_len(dst));
const char *error = NULL;
rz_bv_copy(src_copy, src);
rz_bv_copy(dst_copy, dst);
rz_bv_copy(dst_copy_ref, dst);
if (rz_bv_copy_nbits(dst_copy, dst_pos, src_copy, src_pos, nbit) != nbit) {
error = "rz_bv_copy_nbits() incorrect number of bits copied";
goto finally;
}
if (rz_bv_copy_nbits_ref(dst_copy_ref, dst_pos, src_copy, src_pos, nbit) != nbit) {
error = "rz_bv_copy_nbits_ref() incorrect number of bits copied";
goto finally;
}
if (rz_bv_cmp(dst_copy, dst_copy_ref)) {
error = "rz_bv_copy_nbits() result differs from reference";
goto finally;
}
// Test with inverted src/dst for extra certainty
rz_bv_copy(dst_copy, dst);
rz_bv_toggle_all(src_copy);
rz_bv_toggle_all(dst_copy);
if (rz_bv_copy_nbits(dst_copy, dst_pos, src_copy, src_pos, nbit) != nbit) {
error = "rz_bv_copy_nbits() incorrect number of bits copied";
goto finally;
}
rz_bv_toggle_all(dst_copy);
if (rz_bv_cmp(dst_copy, dst_copy_ref)) {
error = "rz_bv_copy_nbits() result differs from reference";
goto finally;
}
finally:
rz_bv_free(src_copy);
rz_bv_free(dst_copy);
rz_bv_free(dst_copy_ref);
return error;
}
bool test_rz_bv_copy_nbits_small(void) {
RzBitVector *a = rz_bv_new_from_ut64(64, 0x67452301);
RzBitVector *b = rz_bv_new_from_ut64(64, 0x0);
const char *error;
error = test_rz_bv_copy_nbits_against_ref(a, 1, b, 2, 62);
mu_assert_null(error, error);
error = test_rz_bv_copy_nbits_against_ref(a, 0, b, 63, 1);
mu_assert_null(error, error);
rz_bv_free(a);
rz_bv_free(b);
mu_end;
}
bool test_rz_bv_copy_nbits_large_aligned(void) {
RzBitVector *a = rz_bv_new(128);
RzBitVector *b = rz_bv_new_from_ut64(128, 0x0);
const char *error;
rz_bv_set_all(a, true);
/// copy same offset at same byte
error = test_rz_bv_copy_nbits_against_ref(a, 5, b, 5, 3);
mu_assert_null(error, error);
/// copy with front/end byte trailing bits, but no middle bytes
error = test_rz_bv_copy_nbits_against_ref(a, 3, b, 3, 7);
mu_assert_null(error, error);
/// copy with front and end trailing bits and middle bytes
error = test_rz_bv_copy_nbits_against_ref(a, 3, b, 3, 16);
mu_assert_null(error, error);
/// copy without front/trailing bits
error = test_rz_bv_copy_nbits_against_ref(a, 8, b, 8, 32);
mu_assert_null(error, error);
/// copy 1 bit
error = test_rz_bv_copy_nbits_against_ref(a, 13, b, 13, 1);
mu_assert_null(error, error);
/// copy all except 1 bit
error = test_rz_bv_copy_nbits_against_ref(a, 1, b, 1, 127);
mu_assert_null(error, error);
/// Copy bits within the same bitvector
rz_bv_set_from_ut64(b, 0xAAAABBBBCCCCDDDD);
ut32 actual_copy = rz_bv_copy_nbits(b, 16, b, 8, 32);
mu_assert_eq(actual_copy, 32, "copy 32 bits");
mu_assert_streq_free(rz_bv_as_hex_string(b, false), "0xaaaabbccccdddddd", "copy large aligned");
rz_bv_free(a);
rz_bv_free(b);
mu_end;
}
bool test_rz_bv_copy_nbits_large_unaligned(void) {
RzBitVector *a = rz_bv_new(128);
RzBitVector *b = rz_bv_new(128);
const char *error;
rz_bv_set_all(a, true);
/// copy different offset but same byte
error = test_rz_bv_copy_nbits_against_ref(a, 5, b, 2, 20);
mu_assert_null(error, error);
/// copy different offset and different byte
error = test_rz_bv_copy_nbits_against_ref(a, 10, b, 20, 10);
mu_assert_null(error, error);
/// copy at bit boundary
error = test_rz_bv_copy_nbits_against_ref(a, 48, b, 1, 22);
mu_assert_null(error, error);
/// copy 1 bit
error = test_rz_bv_copy_nbits_against_ref(a, 55, b, 13, 1);
mu_assert_null(error, error);
/// copy all except 1 bit
error = test_rz_bv_copy_nbits_against_ref(a, 0, b, 1, 127);
mu_assert_null(error, error);
/// Copy bits within the same bitvector
rz_bv_set_from_ut64(b, 0xAAAABBBBCCCCDDDD);
ut32 actual_copy = rz_bv_copy_nbits(b, 2, b, 0, 30);
mu_assert_eq(actual_copy, 30, "copy 30 bits");
mu_assert_streq_free(rz_bv_as_hex_string(b, false), "0xaaaabbbb33337775", "copy large aligned");
rz_bv_free(a);
rz_bv_free(b);
mu_end;
}
bool test_rz_bv_copy_nbits_large_to_small(void) {
RzBitVector *a = rz_bv_new_from_ut64(128, 0x67452301);
RzBitVector *b = rz_bv_new_from_ut64(64, 0x0);
const char *error;
/// copy aligned
error = test_rz_bv_copy_nbits_against_ref(a, 8, b, 8, 16);
mu_assert_null(error, error);
/// copy unaligned
error = test_rz_bv_copy_nbits_against_ref(a, 1, b, 0, 31);
mu_assert_null(error, error);
/// copy 1 unaligned bit
error = test_rz_bv_copy_nbits_against_ref(a, 3, b, 5, 1);
mu_assert_null(error, error);
/// copy unaligned with dst start_bits > 0
error = test_rz_bv_copy_nbits_against_ref(a, 0, b, 1, 31);
mu_assert_null(error, error);
/// copy different bit sizes from 8 to 64 bits
for (ut8 size = 8; size <= 64; size += 8) {
error = test_rz_bv_copy_nbits_against_ref(a, size - 1, b, 0, size);
mu_assert_null(error, error);
}
rz_bv_free(a);
rz_bv_free(b);
mu_end;
}
bool test_rz_bv_copy_nbits_small_to_large(void) {
RzBitVector *a = rz_bv_new_from_ut64(64, 0x67452301);
RzBitVector *b = rz_bv_new_from_ut64(128, 0x0);
const char *error;
/// copy aligned
error = test_rz_bv_copy_nbits_against_ref(a, 8, b, 8, 16);
mu_assert_null(error, error);
/// copy unaligned
error = test_rz_bv_copy_nbits_against_ref(a, 1, b, 0, 31);
mu_assert_null(error, error);
/// copy 1 unaligned bit
error = test_rz_bv_copy_nbits_against_ref(a, 3, b, 5, 1);
mu_assert_null(error, error);
/// copy unaligned with dst start_bits > 0
error = test_rz_bv_copy_nbits_against_ref(a, 0, b, 1, 31);
mu_assert_null(error, error);
/// copy different bit sizes from 8 to 64 bits
for (ut8 size = 8; size <= 64; size += 8) {
error = test_rz_bv_copy_nbits_against_ref(a, 0, b, size - 1, size);
mu_assert_null(error, error);
}
rz_bv_free(a);
rz_bv_free(b);
mu_end;
}
bool test_rz_bv_extra_operations(void) {
// arithmetic rshift
RzBitVector *bv1 = rz_bv_new_from_ut64(32, 73 * 16);
rz_bv_arshift(bv1, 4);
ut32 val1 = rz_bv_to_ut32(bv1);
mu_assert_eq(73, val1, "test arshift for positive value");
RzBitVector *bv2 = rz_bv_new_from_st64(32, -73 * 16);
rz_bv_arshift(bv2, 4);
st32 val2 = (st32)rz_bv_to_ut32(bv2);
mu_assert_eq(-73, val2, "test arshift for negative value");
rz_bv_free(bv1);
rz_bv_free(bv2);
// pred and succ
RzBitVector *x = rz_bv_new_from_ut64(32, 'X');
RzBitVector *pred_x = rz_bv_pred(x);
RzBitVector *succ_x = rz_bv_succ(x);
mu_assert_eq('W', rz_bv_to_ut32(pred_x), "test normal (pred x)");
mu_assert_eq('Y', rz_bv_to_ut32(succ_x), "test normal (succ x)");
RzBitVector *mo = rz_bv_new_minus_one(32);
RzBitVector *pred_mo = rz_bv_pred(mo);
RzBitVector *succ_mo = rz_bv_succ(mo);
mu_assert_eq((ut32)(-2), rz_bv_to_ut32(pred_mo), "test (pred -1)");
mu_assert_eq(0, rz_bv_to_ut32(succ_mo), "test (succ -1)");
rz_bv_free(pred_x);
rz_bv_free(succ_x);
rz_bv_free(pred_mo);
rz_bv_free(succ_mo);
rz_bv_free(mo);
// zero pred and succ
// forward
RzBitVector *zero = rz_bv_new_zero(32);
RzBitVector *zero_pred = rz_bv_pred(zero);
RzBitVector *zero_pp = rz_bv_pred(zero_pred);
mu_assert_true(rz_bv_is_all_one(zero_pred), "pred 0 -> 0xffff...");
mu_assert_eq((st32)rz_bv_to_ut32(zero_pp), -2, "pred -1 -> -2");
// backward
RzBitVector *n1 = rz_bv_new_minus_one(32);
RzBitVector *n1_next = rz_bv_succ(n1);
mu_assert_true(rz_bv_is_zero_vector(n1_next), "succ -1 -> 0");
rz_bv_free(zero);
rz_bv_free(zero_pred);
rz_bv_free(zero_pp);
rz_bv_free(n1);
rz_bv_free(n1_next);
// test compare
RzBitVector *y = rz_bv_new_from_ut64(32, 'Y');
RzBitVector *xx = rz_bv_new_from_ut64(32, 'X');
mu_assert_true(rz_bv_ult(x, y), "test unsigned X < Y");
mu_assert_true(rz_bv_ugt(y, x), "test unsigned Y > X");
mu_assert_true(rz_bv_uge(y, x), "test unsigned Y >= X");
mu_assert_true(rz_bv_uge(x, xx), "test unsigned X >= X");
mu_assert_false(rz_bv_ult(y, x), "test unsigned Y < X is false");
mu_assert_false(rz_bv_ugt(x, y), "test unsgined X > Y is false");
mu_assert_false(rz_bv_uge(x, y), "test unsigned X >= Y is false");
mu_assert_false(rz_bv_ult(x, xx), "test unsigned X < X is false");
mu_assert_false(rz_bv_ugt(x, xx), "test unsigned X > X is false");
RzBitVector *ny = rz_bv_new_from_ut64(32, -'Y');
RzBitVector *nx = rz_bv_new_from_ut64(32, -'X');
mu_assert_true(rz_bv_ult(ny, nx), "test signed -Y < -X");
mu_assert_true(rz_bv_ugt(nx, ny), "test unsigned -Y < -X");
mu_assert_true(rz_bv_uge(nx, ny), "test unsigned -X >= -Y");
mu_assert_false(rz_bv_ult(nx, ny), "test unsigned -X < -Y is false");
mu_assert_false(rz_bv_ugt(ny, nx), "test unsgined -X < -Y is false");
mu_assert_false(rz_bv_uge(ny, nx), "test unsigned -X <= -Y is false");
mu_assert_false(rz_bv_slt(nx, nx), "test signed -X > -X is false");
mu_assert_false(rz_bv_sgt(nx, nx), "test signed -X < -X is false");
mu_assert_true(rz_bv_sge(nx, nx), "test signed -X >= -X");
mu_assert_true(rz_bv_sge(nx, ny), "test signed -X >= -Y");
mu_assert_true(rz_bv_sge(x, nx), "test signed X >= -X");
mu_assert_true(rz_bv_sgt(x, nx), "test signed X > -X");
mu_assert_true(rz_bv_slt(nx, x), "test signed -X < X");
mu_assert_true(rz_bv_ult(x, nx), "test unsigned X < -X");
mu_assert_true(rz_bv_ugt(nx, x), "test unsigned -X > X");
rz_bv_free(x);
rz_bv_free(y);
rz_bv_free(xx);
rz_bv_free(nx);
rz_bv_free(ny);
mu_end;
}
bool test_rz_bv_hash(void) {
RzBitVector *bv_small_1 = rz_bv_new_from_ut64(32, 1);
RzBitVector *bv_small_2 = rz_bv_new_from_ut64(32, 1);
RzBitVector *bv_large_1 = rz_bv_new_from_ut64(128, 2);
RzBitVector *bv_large_2 = rz_bv_new_from_ut64(128, 2);
mu_assert_eq(rz_bv_hash(bv_small_1), rz_bv_hash(bv_small_2), "Non repeatable hashing small");
mu_assert_eq(rz_bv_hash(bv_large_1), rz_bv_hash(bv_large_2), "Non repeatable hashing large");
mu_assert_neq(rz_bv_hash(bv_small_1), rz_bv_hash(bv_large_1), "Size doesn't affect hash but should");
mu_assert_neq(rz_bv_hash(bv_small_2), rz_bv_hash(bv_large_2), "Size doesn't affect hash but should");
rz_bv_free(bv_small_1);
rz_bv_free(bv_small_2);
rz_bv_free(bv_large_1);
rz_bv_free(bv_large_2);
mu_end;
}
bool all_tests() {
mu_run_test(test_rz_bv_init32);
mu_run_test(test_rz_bv_init64);
mu_run_test(test_rz_bv_init128);
mu_run_test(test_rz_bv_init70);
mu_run_test(test_rz_bv_init_signed);
mu_run_test(test_rz_bv_cmp);
mu_run_test(test_rz_bv_eq);
mu_run_test(test_rz_bv_cast);
mu_run_test(test_rz_bv_operation);
mu_run_test(test_rz_bv_logic);
mu_run_test(test_rz_bv_logic_large);
mu_run_test(test_rz_bv_algorithm32);
mu_run_test(test_rz_bv_algorithm128);
mu_run_test(test_rz_bv_add);
mu_run_test(test_rz_bv_set_from_bytes_le);
mu_run_test(test_rz_bv_set_from_bytes_be);
mu_run_test(test_rz_bv_set_from_buffer_ble, true);
mu_run_test(test_rz_bv_set_from_buffer_ble, false);
mu_run_test(test_rz_bv_as_hex_string);
mu_run_test(test_rz_bv_clz);
mu_run_test(test_rz_bv_ctz);
mu_run_test(test_rz_bv_div);
mu_run_test(test_rz_bv_mod);
mu_run_test(test_rz_bv_len_bytes);
mu_run_test(test_rz_bv_set_operations);
mu_run_test(test_rz_bv_set_range_large);
mu_run_test(test_rz_bv_set_to_bytes_le);
mu_run_test(test_rz_bv_copy_nbits);
mu_run_test(test_rz_bv_copy_nbits_small);
mu_run_test(test_rz_bv_copy_nbits_large_aligned);
mu_run_test(test_rz_bv_copy_nbits_large_unaligned);
mu_run_test(test_rz_bv_copy_nbits_small_to_large);
mu_run_test(test_rz_bv_copy_nbits_large_to_small);
mu_run_test(test_rz_bv_copy_nbits_inplace);
mu_run_test(test_rz_bv_cast_inplace);
mu_run_test(test_rz_bv_extra_operations);
mu_run_test(test_rz_bv_hash);
return tests_passed != tests_run;
}
mu_main(all_tests)