* fix: format with clang-format-20 * fix: fix clang-format linter with rewrite '^#define.*/\*.*\\$' * fix: update clang-format to version 20 in workflows and documentation * fix: add SPDX license information to .git-blame-ignore-revs
1664 lines
41 KiB
C
1664 lines
41 KiB
C
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include "rz_util.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#define NELEM(N, ELEMPER) ((N + (ELEMPER) - 1) / (ELEMPER))
|
|
#define BV_ELEM_SIZE 8U
|
|
|
|
// optimization for reversing 8 bits which uses 32 bits
|
|
// https://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
|
|
#define reverse_byte(x) ((((x) * 0x0802LU & 0x22110LU) | ((x) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
|
|
|
|
// https://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious
|
|
// With changes.
|
|
ut8 reverse_lt_8bits(ut8 x, ut8 w) {
|
|
ut8 m = ~(UT8_MAX << w); // values bitmask
|
|
ut8 v = (x & m); // input bits to be reversed
|
|
ut8 r = v; // r will be reversed bits of v; first get LSB of v
|
|
int s = w - 1; // extra shift needed at end
|
|
|
|
for (v >>= 1; v; v >>= 1) {
|
|
r <<= 1;
|
|
r |= v & 1;
|
|
s--;
|
|
}
|
|
r <<= s; // shift when v's highest bits are zero
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* \brief Initialize a RzBitVector structure
|
|
* \param bv Pointer to a uninitialized RzBitVector instance
|
|
* \param length int, the length of bitvector
|
|
* \return true if succeed
|
|
*/
|
|
RZ_API bool rz_bv_init(RZ_NONNULL RzBitVector *bv, ut32 length) {
|
|
rz_return_val_if_fail(bv && length, false);
|
|
memset(bv, 0, sizeof(RzBitVector));
|
|
if (length > 64) {
|
|
// how much ut8 do we need to represent `length` bits ?
|
|
size_t real_elem_cnt = NELEM(length, BV_ELEM_SIZE);
|
|
ut8 *tmp = RZ_NEWS0(ut8, real_elem_cnt);
|
|
if (!tmp) {
|
|
return false;
|
|
}
|
|
bv->bits.large_a = tmp;
|
|
bv->_elem_len = real_elem_cnt;
|
|
}
|
|
bv->len = length;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* \brief Clear a RzBitVector structure
|
|
*/
|
|
RZ_API void rz_bv_fini(RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_if_fail(bv);
|
|
if (bv->len > 64) {
|
|
free(bv->bits.large_a);
|
|
}
|
|
memset(bv, 0, sizeof(RzBitVector));
|
|
}
|
|
|
|
/**
|
|
* New a `length`-bits bitvector
|
|
* \param length int, the length of bitvector
|
|
* \return bv RzBitVector, pointer to the new bitvector instance
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_new(ut32 length) {
|
|
rz_return_val_if_fail(length, NULL);
|
|
RzBitVector *bv = RZ_NEW0(RzBitVector);
|
|
if (!bv || !rz_bv_init(bv, length)) {
|
|
free(bv);
|
|
return NULL;
|
|
}
|
|
return bv;
|
|
}
|
|
|
|
/**
|
|
* Free a bitvector
|
|
* \param bv RzBitVector, pointer to the bitvector you want to free
|
|
*/
|
|
RZ_API void rz_bv_free(RZ_NULLABLE RzBitVector *bv) {
|
|
if (!bv) {
|
|
return;
|
|
}
|
|
rz_bv_fini(bv);
|
|
free(bv);
|
|
}
|
|
|
|
/**
|
|
* Return bitvector string
|
|
* \param bv RzBitVector, pointer to bitvector
|
|
* \return str char*, bitvector string
|
|
*/
|
|
RZ_API RZ_OWN char *rz_bv_as_string(RZ_NONNULL const RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
char *str = (char *)malloc(bv->len + 1);
|
|
if (!str) {
|
|
return NULL;
|
|
}
|
|
|
|
for (ut32 i = bv->len - 1, j = 0; i > 0; --i, j++) {
|
|
str[j] = rz_bv_get(bv, i) ? '1' : '0';
|
|
}
|
|
str[bv->len - 1] = rz_bv_get(bv, 0) ? '1' : '0';
|
|
str[bv->len] = '\0';
|
|
|
|
return str;
|
|
}
|
|
|
|
/**
|
|
* Return bitvector string in hexadecimal format
|
|
* \param bv RzBitVector, pointer to bitvector
|
|
* \param pad whether to prepend leading zeroes to indicate the bitvector size
|
|
* \return str char*, bitvector string in hexadecimal format
|
|
*/
|
|
RZ_API RZ_OWN char *rz_bv_as_hex_string(RZ_NONNULL const RzBitVector *bv, bool pad) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
if (bv->len <= 64) {
|
|
if (pad) {
|
|
char format[32] = { 0 };
|
|
rz_strf(format, "0x%%0%d" PFMT64x, (bv->len + 3) / 4);
|
|
return rz_str_newf(format, bv->bits.small_u);
|
|
} else {
|
|
return rz_str_newf("0x%" PFMT64x, bv->bits.small_u);
|
|
}
|
|
}
|
|
|
|
const char *hex = "0123456789abcdef";
|
|
size_t str_len = (bv->_elem_len << 1) + 3; // 0x + \0
|
|
char *str = (char *)malloc(str_len);
|
|
if (!str) {
|
|
return NULL;
|
|
}
|
|
|
|
str[0] = '0';
|
|
str[1] = 'x';
|
|
ut32 j = 2;
|
|
for (ut32 i = 0; i < bv->_elem_len; i++) {
|
|
ut8 b8 = bv->bits.large_a[bv->_elem_len - i - 1];
|
|
ut8 high = b8 >> 4;
|
|
ut8 low = b8 & 15;
|
|
if (pad || high) {
|
|
str[j++] = hex[high];
|
|
pad = true; // pad means "print all" from now on
|
|
}
|
|
if (pad || low || i == bv->_elem_len - 1) {
|
|
str[j++] = hex[low];
|
|
pad = true; // pad means "print all" from now on
|
|
}
|
|
}
|
|
str[j] = '\0';
|
|
|
|
return str;
|
|
}
|
|
|
|
/**
|
|
* Clone a bitvector
|
|
* \param bv RzBitVector, pointer to the source bitvector
|
|
* \return dup RzBitVector, pointer to a new bitvector, which is a copy of source
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_dup(const RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
RzBitVector *new_bv = rz_bv_new(bv->len);
|
|
if (!new_bv || !rz_bv_copy(bv, new_bv)) {
|
|
rz_bv_free(new_bv);
|
|
return NULL;
|
|
}
|
|
|
|
return new_bv;
|
|
}
|
|
|
|
/**
|
|
* Copy from source bitvector to destination bitvector.
|
|
* The bitvectors must have the same length.
|
|
*
|
|
* \param src RzBitVector, the source bitvector
|
|
* \param dst RzBitVector, the destination bitvector
|
|
* \return Actual size of copy
|
|
*/
|
|
RZ_API ut32 rz_bv_copy(RZ_NONNULL const RzBitVector *src, RZ_NONNULL RzBitVector *dst) {
|
|
rz_return_val_if_fail(src && dst, 0);
|
|
|
|
if (dst->len != src->len) {
|
|
rz_warn_if_reached();
|
|
return 0;
|
|
} else if (dst->len <= 64) {
|
|
dst->bits.small_u = src->bits.small_u;
|
|
return sizeof(dst->bits.small_u);
|
|
}
|
|
|
|
rz_return_val_if_fail(src->bits.large_a && dst->bits.large_a, 0);
|
|
memcpy(dst->bits.large_a, src->bits.large_a, dst->_elem_len);
|
|
return dst->_elem_len;
|
|
}
|
|
|
|
/**
|
|
* Copy n bits from start position of source to start position of dest, return num of copied bits
|
|
* \param src RzBitVector, data source
|
|
* \param src_start_pos ut32, start position in source bitvector of copy
|
|
* \param dst RzBitVector, destination of copy
|
|
* \param dst_start_pos ut32, start position in destination bitvector
|
|
* \param nbit ut32, control the size of copy (in bits)
|
|
* \return copied_size ut32, Actual copied size
|
|
*/
|
|
RZ_API ut32 rz_bv_copy_nbits(RZ_NONNULL const RzBitVector *src, ut32 src_start_pos, RZ_NONNULL RzBitVector *dst, ut32 dst_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;
|
|
}
|
|
|
|
// normal case here
|
|
for (ut32 i = 0; i < nbit; ++i) {
|
|
bool c = rz_bv_get(src, src_start_pos + i);
|
|
rz_bv_set(dst, dst_start_pos + i, c);
|
|
}
|
|
|
|
return nbit;
|
|
}
|
|
|
|
/**
|
|
* Return a new bitvector prepended with bv with n zero bits
|
|
* \param bv RzBitVector, pointer to bitvector instance
|
|
* \param delta_len ut32, the number of zero bits
|
|
* \return ret RzBitVector, pointer to the new bitvector instance
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_prepend_zero(RZ_NONNULL RzBitVector *bv, ut32 delta_len) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
ut32 new_len = bv->len + delta_len;
|
|
RzBitVector *ret = rz_bv_new(new_len);
|
|
if (ret == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
for (ut32 i = 0; i < bv->len; ++i) {
|
|
rz_bv_set(ret, i, rz_bv_get(bv, i));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Return a new bitvector appended with n zero bits
|
|
* \param bv RzBitVector, pointer to bitvector
|
|
* \param delta_len, the number of zero bits
|
|
* \return ret RzBitVector, pointert to the new btivector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_append_zero(RZ_NONNULL RzBitVector *bv, ut32 delta_len) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
ut32 new_len = bv->len + delta_len;
|
|
RzBitVector *ret = rz_bv_new(new_len);
|
|
if (ret == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
ut32 pos = delta_len;
|
|
for (ut32 i = 0; i < bv->len; ++i, ++pos) {
|
|
rz_bv_set(ret, pos, rz_bv_get(bv, i));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Return a new bitvector, cut n zero bits from head
|
|
* \param bv RzBitVector, pointer to bitvector
|
|
* \param delta_len, the number of zero bits
|
|
* \return ret RzBitVector, pointert to the new btivector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_cut_head(RZ_NONNULL RzBitVector *bv, ut32 delta_len) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
ut32 new_len = bv->len - delta_len;
|
|
RzBitVector *ret = rz_bv_new(new_len);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
|
|
for (ut32 pos = 0; pos < new_len; ++pos) {
|
|
rz_bv_set(ret, pos, rz_bv_get(bv, pos));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Return a new bitvector, cut n zero bits from tail
|
|
* \param bv RzBitVector, pointer to bitvector
|
|
* \param delta_len, the number of zero bits
|
|
* \return ret RzBitVector, pointert to the new btivector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_cut_tail(RZ_NONNULL RzBitVector *bv, ut32 delta_len) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
ut32 new_len = bv->len - delta_len;
|
|
RzBitVector *ret = rz_bv_new(new_len);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
|
|
ut32 pos, i;
|
|
for (pos = 0, i = delta_len; pos < new_len; ++i, ++pos) {
|
|
rz_bv_set(ret, pos, rz_bv_get(bv, i));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Append bv2 to bv1 to get new bitvector
|
|
* \param high bitvector to occupy the most significant part of the result
|
|
* \param low bitvector to occupy the least significant part of the result
|
|
* \return ret RzBitVector, the new bitvector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_append(RZ_NONNULL RzBitVector *high, RZ_NONNULL RzBitVector *low) {
|
|
rz_return_val_if_fail(high && low, NULL);
|
|
RzBitVector *ret = rz_bv_new(high->len + low->len);
|
|
rz_bv_copy_nbits(low, 0, ret, 0, low->len);
|
|
rz_bv_copy_nbits(high, 0, ret, low->len, high->len);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Set a bit at position to true or false
|
|
* \param bv RzBitVector, pointer to bv
|
|
* \param pos ut32, position
|
|
* \param b bit, true or false (set or unset)
|
|
* \return ret bool, bool value at `pos` after this operation
|
|
*/
|
|
RZ_API bool rz_bv_set(RZ_NONNULL RzBitVector *bv, ut32 pos, bool b) {
|
|
rz_return_val_if_fail(bv && pos < bv->len, false);
|
|
if (bv->len <= 64) {
|
|
if (b) {
|
|
bv->bits.small_u |= (1ull << pos);
|
|
} else {
|
|
bv->bits.small_u &= ~(1ull << pos);
|
|
}
|
|
return b;
|
|
}
|
|
rz_return_val_if_fail(bv->bits.large_a, false);
|
|
|
|
if (b) {
|
|
bv->bits.large_a[pos / BV_ELEM_SIZE] |= (1u << (pos % BV_ELEM_SIZE));
|
|
} else {
|
|
bv->bits.large_a[pos / BV_ELEM_SIZE] &= ~(1u << (pos % BV_ELEM_SIZE));
|
|
}
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Set all bits to true or false
|
|
* \param bv RzBitVector, pointer to bv
|
|
* \param b bit, true or false (set or unset)
|
|
* \return ret bool, bool value at every positions after this operation
|
|
*/
|
|
RZ_API bool rz_bv_set_all(RZ_NONNULL RzBitVector *bv, bool b) {
|
|
rz_return_val_if_fail(bv, false);
|
|
|
|
if (bv->len <= 64) {
|
|
bv->bits.small_u = b ? UT64_MAX >> (64 - bv->len) : 0;
|
|
return b;
|
|
}
|
|
|
|
rz_return_val_if_fail(bv->bits.large_a, false);
|
|
if (b) {
|
|
memset(bv->bits.large_a, 0xff, bv->_elem_len);
|
|
ut32 mod = bv->len % BV_ELEM_SIZE;
|
|
if (mod) {
|
|
bv->bits.large_a[bv->len / BV_ELEM_SIZE] = rz_num_bitmask(mod);
|
|
}
|
|
} else {
|
|
memset(bv->bits.large_a, 0, bv->_elem_len);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Invert a bit at position
|
|
* \param bv RzBitVector, pointer to bv
|
|
* \param pos ut32, position
|
|
* \param b bit, true or false (set or unset)
|
|
* \return ret bool, bool value at `pos` after this operation
|
|
*/
|
|
RZ_API bool rz_bv_toggle(RZ_NONNULL RzBitVector *bv, ut32 pos) {
|
|
rz_return_val_if_fail(bv, false);
|
|
bool cur_bit = rz_bv_get(bv, pos);
|
|
bool new_bit = !cur_bit;
|
|
rz_bv_set(bv, pos, new_bit);
|
|
return new_bit;
|
|
}
|
|
|
|
/**
|
|
* Invert all bits
|
|
* \param bv RzBitVector, pointer to bv
|
|
* \param b bit, true or false (set or unset)
|
|
* \return ret bool, bool value at every positions after this operation
|
|
*/
|
|
RZ_API bool rz_bv_toggle_all(RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, false);
|
|
if (bv->len <= 64) {
|
|
bv->bits.small_u = ~(bv->bits.small_u);
|
|
}
|
|
|
|
rz_return_val_if_fail(bv->bits.large_a, false);
|
|
for (ut32 i = 0; i < bv->_elem_len; ++i) {
|
|
bv->bits.large_a[i] = ~(bv->bits.large_a[i]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get bit at position from bitvector
|
|
* \param bv RzBitVector, pointer to bv
|
|
* \param pos int, position
|
|
* \return ret bit, bool value of bit
|
|
*/
|
|
RZ_API bool rz_bv_get(RZ_NONNULL const RzBitVector *bv, ut32 pos) {
|
|
rz_return_val_if_fail(bv && pos < bv->len, false);
|
|
if (bv->len <= 64) {
|
|
return (bv->bits.small_u >> pos) & 1;
|
|
}
|
|
|
|
rz_return_val_if_fail(bv->bits.large_a, false);
|
|
return ((bv->bits.large_a)[pos / BV_ELEM_SIZE] & (1u << (pos % BV_ELEM_SIZE)));
|
|
}
|
|
|
|
/**
|
|
* Left shift bitvector (WARN : This operation will change the bitvector in argument)
|
|
* Fill with zero bits when shift
|
|
* \param bv RzBitVector, pointert to bv
|
|
* \param size int, shift bits
|
|
* \return flag bool, success or not
|
|
*/
|
|
RZ_API bool rz_bv_lshift(RZ_NONNULL RzBitVector *bv, ut32 size) {
|
|
return rz_bv_lshift_fill(bv, size, false);
|
|
}
|
|
|
|
/**
|
|
* Right shift bitvector (WARN : This operation will change the bitvector in argument)
|
|
* Fill with zero bits when shift
|
|
* \param bv RzBitVector, pointert to bv
|
|
* \param size int, shift bits
|
|
* \return flag bool, success or not
|
|
*/
|
|
RZ_API bool rz_bv_rshift(RZ_NONNULL RzBitVector *bv, ut32 size) {
|
|
return rz_bv_rshift_fill(bv, size, false);
|
|
}
|
|
|
|
/**
|
|
* Left shift bitvector (WARN : This operation will change the bitvector in argument)
|
|
* Fill the bitvector with `fill_bit`
|
|
* \param bv RzBitVector, pointert to bv
|
|
* \param size int, shift bits
|
|
* \param fill_bit bool, bit used in filling
|
|
* \return flag bool, success or not
|
|
*/
|
|
RZ_API bool rz_bv_lshift_fill(RZ_NONNULL RzBitVector *bv, ut32 size, bool fill_bit) {
|
|
rz_return_val_if_fail(bv, false);
|
|
|
|
// left shift
|
|
if (size == 0) {
|
|
return false;
|
|
}
|
|
|
|
if (size >= bv->len) {
|
|
rz_bv_set_all(bv, fill_bit);
|
|
return true;
|
|
}
|
|
|
|
RzBitVector tmp;
|
|
if (!rz_bv_init(&tmp, bv->len)) {
|
|
return false;
|
|
}
|
|
rz_bv_set_all(&tmp, fill_bit);
|
|
|
|
int copied_size = rz_bv_copy_nbits(bv, 0, &tmp, size, bv->len - size);
|
|
if (copied_size == 0) {
|
|
rz_bv_fini(&tmp);
|
|
return false;
|
|
}
|
|
|
|
rz_bv_copy(&tmp, bv);
|
|
rz_bv_fini(&tmp);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Right shift bitvector (WARN : This operation will change the bitvector in argument)
|
|
* Fill the bitvector with `fill_bit`
|
|
* \param bv RzBitVector, pointert to bv
|
|
* \param size int, shift bits
|
|
* \param fill_bit bool, bit used in filling
|
|
* \return flag bool, success or not
|
|
*/
|
|
RZ_API bool rz_bv_rshift_fill(RZ_NONNULL RzBitVector *bv, ut32 size, bool fill_bit) {
|
|
rz_return_val_if_fail(bv, false);
|
|
|
|
// left shift
|
|
if (size == 0) {
|
|
return false;
|
|
}
|
|
|
|
if (size >= bv->len) {
|
|
rz_bv_set_all(bv, fill_bit);
|
|
return true;
|
|
}
|
|
|
|
RzBitVector tmp;
|
|
if (!rz_bv_init(&tmp, bv->len)) {
|
|
return false;
|
|
}
|
|
rz_bv_set_all(&tmp, fill_bit);
|
|
|
|
int copied_size = rz_bv_copy_nbits(bv, size, &tmp, 0, bv->len - size);
|
|
if (copied_size == 0) {
|
|
rz_bv_fini(&tmp);
|
|
return false;
|
|
}
|
|
|
|
rz_bv_copy(&tmp, bv);
|
|
rz_bv_fini(&tmp);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Result of x AND y (`and` operation to every bits)
|
|
* Both operands must have the same length.
|
|
* \param x RzBitVector, operand
|
|
* \param y RzBitVector, operand
|
|
* \return ret RzBitVector, a new bitvector, which is the result of AND
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_and(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, NULL);
|
|
if (x->len != y->len) {
|
|
rz_warn_if_reached();
|
|
return NULL;
|
|
}
|
|
|
|
RzBitVector *ret = rz_bv_new(x->len);
|
|
if (!ret) {
|
|
return NULL;
|
|
} else if (x->len <= 64) {
|
|
ret->bits.small_u = x->bits.small_u & y->bits.small_u;
|
|
return ret;
|
|
}
|
|
|
|
for (ut32 i = 0; i < ret->_elem_len; ++i) {
|
|
ret->bits.large_a[i] = x->bits.large_a[i] & y->bits.large_a[i];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Result of x OR y (`or` operation to every bits)
|
|
* Both operands must have the same length.
|
|
* \param x RzBitVector, operand
|
|
* \param y RzBitVector, operand
|
|
* \return ret RzBitVector, a new bitvector, which is the result of OR
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_or(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, NULL);
|
|
if (x->len != y->len) {
|
|
rz_warn_if_reached();
|
|
return NULL;
|
|
}
|
|
|
|
RzBitVector *ret = rz_bv_new(x->len);
|
|
if (!ret) {
|
|
return NULL;
|
|
} else if (x->len <= 64) {
|
|
ret->bits.small_u = x->bits.small_u | y->bits.small_u;
|
|
return ret;
|
|
}
|
|
|
|
for (ut32 i = 0; i < ret->_elem_len; ++i) {
|
|
ret->bits.large_a[i] = x->bits.large_a[i] | y->bits.large_a[i];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Result of x XOR y (`xor` operation to every bits)
|
|
* Both operands must have the same length.
|
|
* \param x RzBitVector, operand
|
|
* \param y RzBitVector, operand
|
|
* \return ret RzBitVector, a new bitvector, which is the result of XOR
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_xor(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, NULL);
|
|
if (x->len != y->len) {
|
|
rz_warn_if_reached();
|
|
return NULL;
|
|
}
|
|
|
|
RzBitVector *ret = rz_bv_new(x->len);
|
|
if (!ret) {
|
|
return NULL;
|
|
} else if (x->len <= 64) {
|
|
ret->bits.small_u = x->bits.small_u ^ y->bits.small_u;
|
|
return ret;
|
|
}
|
|
|
|
for (ut32 i = 0; i < ret->_elem_len; ++i) {
|
|
ret->bits.large_a[i] = x->bits.large_a[i] ^ y->bits.large_a[i];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Get the 1's complement of bv
|
|
* \param bv RzBitVector, operand
|
|
* \return ret RzBitVector, a new bitvector, which is the 1's complement of bv
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_complement_1(RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
RzBitVector *ret = rz_bv_new(bv->len);
|
|
if (!ret) {
|
|
return NULL;
|
|
} else if (ret->len <= 64) {
|
|
ret->bits.small_u = ~bv->bits.small_u;
|
|
ret->bits.small_u &= UT64_MAX >> (64 - ret->len);
|
|
return ret;
|
|
}
|
|
|
|
if (!(ret->bits.large_a && bv->bits.large_a)) {
|
|
rz_bv_free(ret);
|
|
rz_return_val_if_reached(NULL);
|
|
}
|
|
for (ut32 i = 0; i < bv->_elem_len; ++i) {
|
|
ret->bits.large_a[i] = ~bv->bits.large_a[i];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Get the 2's complement of bv
|
|
* \param bv RzBitVector, operand
|
|
* \return ret RzBitVector, a new bitvector, which is the 2's complement of bv
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_complement_2(RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
// from right side to left, find the 1st 1 bit
|
|
// flip/toggle every bit before it
|
|
RzBitVector *ret = rz_bv_dup(bv);
|
|
|
|
ut32 i;
|
|
for (i = 0; i < bv->len; ++i) {
|
|
if (rz_bv_get(bv, i) == true) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// assert bv[i] == true now
|
|
i += 1;
|
|
for (; i < bv->len; ++i) {
|
|
rz_bv_toggle(ret, i);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Result of (x + y) mod 2^length
|
|
* Both operands must have the same length.
|
|
* \param x RzBitVector, Operand
|
|
* \param y RzBitVector, Operand
|
|
* \param carry bool*, bool pointer to where to save the carry value.
|
|
* \return ret RzBitVector, point to the new bitvector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_add(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y, RZ_NULLABLE bool *carry) {
|
|
rz_return_val_if_fail(x && y, NULL);
|
|
|
|
if (x->len != y->len) {
|
|
rz_warn_if_reached();
|
|
return NULL;
|
|
}
|
|
|
|
bool a = false, b = false, _carry = false;
|
|
RzBitVector *ret = rz_bv_new(x->len);
|
|
|
|
for (ut32 pos = 0; pos < x->len; ++pos) {
|
|
a = rz_bv_get(x, 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;
|
|
}
|
|
|
|
/**
|
|
* Result of (x - y) mod 2^length
|
|
* Both operands must have the same length.
|
|
* \param x RzBitVector, Operand
|
|
* \param y RzBitVector, Operand
|
|
* \param borrow bool*, bool pointer to where to save the borrow value.
|
|
* \return ret RzBitVector, point to the new bitvector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_sub(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y, RZ_NULLABLE bool *borrow) {
|
|
rz_return_val_if_fail(x && y, NULL);
|
|
|
|
RzBitVector *ret;
|
|
RzBitVector *neg_y;
|
|
|
|
neg_y = rz_bv_neg(y);
|
|
ret = rz_bv_add(x, neg_y, borrow);
|
|
rz_bv_free(neg_y);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Result of (x * y) mod 2^length
|
|
* Both operands must have the same length.
|
|
* \param x RzBitVector, Operand
|
|
* \param y RzBitVector, Operand
|
|
* \return ret RzBitVector, point to the new bitvector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_mul(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, NULL);
|
|
|
|
RzBitVector dump;
|
|
bool cur_bit = false;
|
|
|
|
if (x->len != y->len) {
|
|
rz_warn_if_reached();
|
|
return NULL;
|
|
}
|
|
|
|
if (!rz_bv_init(&dump, x->len)) {
|
|
return NULL;
|
|
}
|
|
RzBitVector *result = rz_bv_new(x->len);
|
|
if (!result) {
|
|
goto exit;
|
|
}
|
|
rz_bv_copy(x, &dump);
|
|
|
|
for (ut32 i = 0; i < y->len; ++i) {
|
|
cur_bit = rz_bv_get(y, i);
|
|
if (cur_bit) {
|
|
RzBitVector *tmp = rz_bv_add(result, &dump, NULL);
|
|
rz_bv_free(result);
|
|
result = tmp;
|
|
}
|
|
rz_bv_lshift(&dump, 1);
|
|
}
|
|
|
|
exit:
|
|
rz_bv_fini(&dump);
|
|
return result;
|
|
}
|
|
|
|
/* Treat x, y as unsigned
|
|
* Both operands must have the same length.
|
|
* if x < y return negtive (-1)
|
|
* if x == y return 0
|
|
* if x > y return positive (+1)
|
|
*/
|
|
int bv_unsigned_cmp(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, 0);
|
|
|
|
if (x->len != y->len) {
|
|
rz_warn_if_reached();
|
|
return 0;
|
|
}
|
|
|
|
ut32 len = x->len;
|
|
int pos;
|
|
bool x_bit, y_bit;
|
|
for (ut32 i = 0; i < len; ++i) {
|
|
pos = len - 1 - i;
|
|
x_bit = rz_bv_get(x, pos);
|
|
y_bit = rz_bv_get(y, pos);
|
|
if (x_bit ^ y_bit) {
|
|
return x_bit ? 1 : -1;
|
|
}
|
|
}
|
|
|
|
// equal
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Result of (x / y) mod 2^length
|
|
* Both operands must have the same length.
|
|
* If \p y is a zero vector, the result defined as a vector of all ones.
|
|
*
|
|
* \param x dividend
|
|
* \param y divisor
|
|
* \return ret quotient, of the same length as the operands
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_div(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y && x->len == y->len, NULL);
|
|
|
|
if (rz_bv_is_zero_vector(y)) {
|
|
RzBitVector *ret = rz_bv_new(y->len);
|
|
rz_bv_set_all(ret, true);
|
|
return ret;
|
|
}
|
|
|
|
if (x->len <= 64) {
|
|
return rz_bv_new_from_ut64(x->len, rz_bv_to_ut64(x) / rz_bv_to_ut64(y));
|
|
}
|
|
|
|
int compare_result = bv_unsigned_cmp(x, y);
|
|
// dividend < divisor
|
|
// remainder = dividend, quotient = 0
|
|
if (compare_result < 0) {
|
|
return rz_bv_new(x->len);
|
|
}
|
|
// dividend == divisor
|
|
// remainder = 0, quotient = 1
|
|
if (compare_result == 0) {
|
|
return rz_bv_new_one(rz_bv_len(x));
|
|
}
|
|
|
|
// dividend > divisor
|
|
// do typical division by shift and subtract
|
|
RzBitVector *dend = rz_bv_dup(x);
|
|
RzBitVector *sor = rz_bv_dup(y);
|
|
// shift the divisor left to align both highest bits
|
|
ut32 sorlz = rz_bv_clz(sor);
|
|
ut32 shift = sorlz - rz_bv_clz(dend);
|
|
rz_bv_lshift(sor, shift);
|
|
RzBitVector *quot = rz_bv_new_zero(rz_bv_len(x));
|
|
for (ut32 b = shift + 1; b; b--) {
|
|
if (rz_bv_ule(sor, dend)) {
|
|
rz_bv_set(quot, b - 1, true);
|
|
RzBitVector *tmp = rz_bv_sub(dend, sor, NULL);
|
|
rz_bv_free(dend);
|
|
dend = tmp;
|
|
}
|
|
rz_bv_rshift(sor, 1);
|
|
}
|
|
rz_bv_free(dend);
|
|
rz_bv_free(sor);
|
|
return quot;
|
|
}
|
|
|
|
/**
|
|
* Result of (x mod y) mod 2^length
|
|
* Both operands must have the same length.
|
|
* If \p y == 0, the result is \p x
|
|
*
|
|
* \param x dividend
|
|
* \param y divisor
|
|
* \return x - ((x / y) * y)
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_mod(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y && x->len == y->len, NULL);
|
|
if (rz_bv_is_zero_vector(y)) {
|
|
return rz_bv_dup(x);
|
|
}
|
|
RzBitVector *quot = rz_bv_div(x, y);
|
|
RzBitVector *remul = rz_bv_mul(quot, y);
|
|
RzBitVector *r = rz_bv_sub(x, remul, NULL);
|
|
rz_bv_free(quot);
|
|
rz_bv_free(remul);
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Result of (x / y) mod 2^length (signed algorithm)
|
|
* /
|
|
* | div x y : if not mx /\ not my
|
|
* | neg (div (neg x) y) if mx /\ not my
|
|
* x sdiv y = <
|
|
* | neg (div x (neg y)) if not mx /\ my
|
|
* | div (neg x) (neg y) if mx /\ my
|
|
* \
|
|
*
|
|
* where mx = msb x, and my = msb y.
|
|
* \param x RzBitVector, Operand
|
|
* \param y RzBitVector, Operand
|
|
* \return ret RzBitVector, point to the new bitvector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_sdiv(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, NULL);
|
|
bool mx = rz_bv_msb(x);
|
|
bool my = rz_bv_msb(y);
|
|
|
|
RzBitVector *neg_x, *neg_y, *tmp, *ret;
|
|
|
|
if ((!mx) && (!my)) {
|
|
return rz_bv_div(x, y);
|
|
}
|
|
|
|
if ((mx) && (!my)) {
|
|
neg_x = rz_bv_neg(x);
|
|
tmp = rz_bv_div(neg_x, y);
|
|
ret = rz_bv_neg(tmp);
|
|
|
|
rz_bv_free(tmp);
|
|
rz_bv_free(neg_x);
|
|
return ret;
|
|
}
|
|
|
|
if ((!mx) && (my)) {
|
|
neg_y = rz_bv_neg(y);
|
|
tmp = rz_bv_div(x, neg_y);
|
|
ret = rz_bv_neg(tmp);
|
|
|
|
rz_bv_free(tmp);
|
|
rz_bv_free(neg_y);
|
|
return ret;
|
|
}
|
|
|
|
// mx && my
|
|
neg_x = rz_bv_neg(x);
|
|
neg_y = rz_bv_neg(y);
|
|
|
|
ret = rz_bv_div(neg_x, neg_y);
|
|
rz_bv_free(neg_x);
|
|
rz_bv_free(neg_y);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Result of (x mod y) mod 2^length (signed algorithm)
|
|
* /
|
|
* | x % y : if not mx /\ not my
|
|
* | neg (neg x % y) if mx /\ not my
|
|
* x smodulo y = <
|
|
* | neg (x % (neg y)) if not mx /\ my
|
|
* | neg (neg x % neg y) mod m if mx /\ my
|
|
* \
|
|
*
|
|
* where mx = msb x and my = msb y.
|
|
* \param x RzBitVector, Operand
|
|
* \param y RzBitVector, Operand
|
|
* \return ret RzBitVector, point to the new bitvector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_smod(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, NULL);
|
|
bool mx = rz_bv_msb(x);
|
|
bool my = rz_bv_msb(y);
|
|
|
|
RzBitVector *neg_x, *neg_y, *tmp, *ret;
|
|
|
|
if ((!mx) && (!my)) {
|
|
return rz_bv_mod(x, y);
|
|
}
|
|
|
|
if ((mx) && (!my)) {
|
|
neg_x = rz_bv_neg(x);
|
|
tmp = rz_bv_mod(neg_x, y);
|
|
ret = rz_bv_neg(tmp);
|
|
|
|
rz_bv_free(tmp);
|
|
rz_bv_free(neg_x);
|
|
return ret;
|
|
}
|
|
|
|
if ((!mx) && (my)) {
|
|
neg_y = rz_bv_neg(y);
|
|
tmp = rz_bv_mod(x, neg_y);
|
|
ret = rz_bv_neg(tmp);
|
|
|
|
rz_bv_free(tmp);
|
|
rz_bv_free(neg_y);
|
|
return ret;
|
|
}
|
|
|
|
// mx && my
|
|
neg_x = rz_bv_neg(x);
|
|
neg_y = rz_bv_neg(y);
|
|
|
|
tmp = rz_bv_mod(neg_x, neg_y);
|
|
ret = rz_bv_neg(tmp);
|
|
rz_bv_free(neg_x);
|
|
rz_bv_free(neg_y);
|
|
rz_bv_free(tmp);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Get the most significant bit of bitvector
|
|
* \param bv RzBitVector, operand
|
|
* \return b bit, bool value of MSB
|
|
*/
|
|
RZ_API bool rz_bv_msb(RZ_NONNULL RzBitVector *bv) {
|
|
return rz_bv_get(bv, bv->len - 1);
|
|
}
|
|
|
|
/**
|
|
* Get the least significant bit of bitvector
|
|
* \param bv RzBitVector, operand
|
|
* \return b bit, bool value of LSB
|
|
*/
|
|
RZ_API bool rz_bv_lsb(RZ_NONNULL RzBitVector *bv) {
|
|
return rz_bv_get(bv, 0);
|
|
}
|
|
|
|
/**
|
|
* Check if the bitvector is zero
|
|
* \param x RzBitVector, pointer to bv
|
|
* \return ret bool, return true if bv is a zero bitvector, false if not
|
|
*/
|
|
RZ_API bool rz_bv_is_zero_vector(RZ_NONNULL const RzBitVector *x) {
|
|
rz_return_val_if_fail(x, false);
|
|
|
|
if (x->len <= 64) {
|
|
return x->bits.small_u == 0;
|
|
}
|
|
|
|
rz_return_val_if_fail(x->bits.large_a, false);
|
|
|
|
for (ut32 i = 0; i < x->_elem_len; ++i) {
|
|
if (x->bits.large_a[i] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if x == y
|
|
*/
|
|
RZ_API bool rz_bv_eq(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
return rz_bv_len(x) == rz_bv_len(y) && bv_unsigned_cmp(x, y) == 0;
|
|
}
|
|
|
|
/**
|
|
* Check if x <= y (as unsigned value)
|
|
* \param x RzBitVector, operand
|
|
* \param y RzBitVector, operand
|
|
* \return ret bool, return true if x <= y, else return false
|
|
*/
|
|
RZ_API bool rz_bv_ule(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
// x > y ? return false : return true
|
|
return bv_unsigned_cmp(x, y) <= 0;
|
|
}
|
|
|
|
/**
|
|
* Check if x <= y (as signed value)
|
|
* \param x RzBitVector, operand
|
|
* \param y RzBitVector, operand
|
|
* \return ret bool, return true if x <= y, else return false
|
|
*/
|
|
RZ_API bool rz_bv_sle(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
bool x_msb = rz_bv_msb(x);
|
|
bool y_msb = rz_bv_msb(y);
|
|
|
|
if (x_msb == y_msb) {
|
|
return rz_bv_ule(x, y);
|
|
}
|
|
|
|
// if x_msb set, y_msb unset => x < y
|
|
// if x_msb unset, y_msb set => x > y
|
|
// x != y when reaches here
|
|
return x_msb;
|
|
}
|
|
|
|
/**
|
|
* Check if x equals to y
|
|
* Both operands must have the same length.
|
|
* \param x RzBitVector, operand
|
|
* \param y RzBitVector, operand
|
|
* \return ret int, return 1 if x != y, return 0 if x == y
|
|
*/
|
|
RZ_API bool rz_bv_cmp(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, 0);
|
|
|
|
if (x->len != y->len) {
|
|
rz_warn_if_reached();
|
|
return true;
|
|
}
|
|
|
|
for (ut32 i = 0; i < x->len; ++i) {
|
|
if (rz_bv_get(x, i) != rz_bv_get(y, i)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Count leading (most significant) zeroes
|
|
* All bits are considered leading zeroes for a zero bitvector.
|
|
*/
|
|
RZ_API ut32 rz_bv_clz(RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, 0);
|
|
ut32 r = 0;
|
|
for (ut32 i = rz_bv_len(bv); i; i--) {
|
|
if (rz_bv_get(bv, i - 1)) {
|
|
break;
|
|
}
|
|
r++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Count trailing (least significant) zeroes
|
|
* All bits are considered trailing zeroes for a zero bitvector.
|
|
*/
|
|
RZ_API ut32 rz_bv_ctz(RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, 0);
|
|
ut32 r = 0;
|
|
for (ut32 i = 0; i < rz_bv_len(bv); i++) {
|
|
if (rz_bv_get(bv, i)) {
|
|
break;
|
|
}
|
|
r++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Get the length of bitvector in bits
|
|
* \param bv RzBitVector
|
|
* \return len ut32, length of bitvector in bits
|
|
*/
|
|
RZ_API ut32 rz_bv_len(RZ_NONNULL const RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, 0);
|
|
return bv->len;
|
|
}
|
|
|
|
/**
|
|
* Get the length of bitvector in bytes
|
|
* \param bv RzBitVector
|
|
* \return len ut32, length of bitvector in bytes
|
|
*/
|
|
RZ_API ut32 rz_bv_len_bytes(RZ_NONNULL const RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, 0);
|
|
return (bv->len + 7) >> 3;
|
|
}
|
|
|
|
/**
|
|
* Convert ut64 to `length`-bits bitvector
|
|
* \param length ut32, length of bitvector
|
|
* \param value ut64, the value to convert
|
|
* \return bv RzBitVector, pointer to new bitvector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_ut64(ut32 length, ut64 value) {
|
|
rz_return_val_if_fail(length > 0, NULL);
|
|
|
|
RzBitVector *bv = rz_bv_new(length);
|
|
if (!bv) {
|
|
RZ_LOG_ERROR("RzIL: failed to allocate RzBitVector\n");
|
|
return NULL;
|
|
}
|
|
rz_bv_set_from_ut64(bv, value);
|
|
return bv;
|
|
}
|
|
|
|
/**
|
|
* Convert st64 to `length`-bits bitvector
|
|
* \param length ut32, length of bitvector
|
|
* \param value st64, the value to convert
|
|
* \return bv RzBitVector, pointer to new bitvector
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_st64(ut32 length, st64 value) {
|
|
rz_return_val_if_fail(length > 0, NULL);
|
|
|
|
RzBitVector *bv = rz_bv_new(length);
|
|
if (!bv) {
|
|
RZ_LOG_ERROR("RzIL: failed to allocate RzBitVector\n");
|
|
return NULL;
|
|
}
|
|
rz_bv_set_from_st64(bv, value);
|
|
return bv;
|
|
}
|
|
|
|
/**
|
|
* Create a new bitvector of \p size bits and apply rz_bv_set_from_bytes_le() to it
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_bytes_le(RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size) {
|
|
rz_return_val_if_fail(buf, NULL);
|
|
RzBitVector *bv = rz_bv_new(size);
|
|
if (!bv) {
|
|
return NULL;
|
|
}
|
|
rz_bv_set_from_bytes_le(bv, buf, bit_offset, size);
|
|
return bv;
|
|
}
|
|
|
|
/**
|
|
* Create a new bitvector of \p size bits and apply rz_bv_set_from_bytes_be() to it
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_bytes_be(RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size) {
|
|
rz_return_val_if_fail(buf, NULL);
|
|
RzBitVector *bv = rz_bv_new(size);
|
|
if (!bv) {
|
|
return NULL;
|
|
}
|
|
rz_bv_set_from_bytes_be(bv, buf, bit_offset, size);
|
|
return bv;
|
|
}
|
|
|
|
/**
|
|
* Convert ut64 to N-bits bitvector
|
|
* \param bv RzBitVector, pointer to bitvector
|
|
* \param value ut64, the value to convert
|
|
*/
|
|
RZ_API bool rz_bv_set_from_ut64(RZ_NONNULL RzBitVector *bv, ut64 value) {
|
|
rz_return_val_if_fail(bv, false);
|
|
|
|
if (bv->len <= 64) {
|
|
bv->bits.small_u = value;
|
|
bv->bits.small_u &= (UT64_MAX >> (64 - bv->len));
|
|
return true;
|
|
}
|
|
|
|
for (ut32 i = 0; i < bv->len; ++i) {
|
|
rz_bv_set(bv, i, value & 1);
|
|
value >>= 1;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Convert st64 to N-bits bitvector
|
|
* \param bv RzBitVector, pointer to bitvector
|
|
* \param value st64, the value to convert
|
|
*/
|
|
RZ_API bool rz_bv_set_from_st64(RZ_NONNULL RzBitVector *bv, st64 value) {
|
|
rz_return_val_if_fail(bv, false);
|
|
if (bv->len <= 64) {
|
|
bv->bits.small_u = *((ut64 *)&value);
|
|
bv->bits.small_u &= (UT64_MAX >> (64 - bv->len));
|
|
return true;
|
|
}
|
|
|
|
for (ut32 i = 0; i < bv->len; ++i) {
|
|
rz_bv_set(bv, i, value & 1);
|
|
value >>= 1;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set the bitvector's contents from the given bits. The bitvector's size is unchanged.
|
|
* If bv->len < size, additional bits are cut off, if bv->len > size, the rest is filled up with 0.
|
|
* \param buf little endian buffer of at least (bit_offset + size + 7) / 8 bytes
|
|
* \param bit_offset offset inside buf to start reading from, in bits
|
|
* \param size number of bits to read from buf
|
|
*/
|
|
RZ_API void rz_bv_set_from_bytes_le(RZ_NONNULL RzBitVector *bv, RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size) {
|
|
rz_return_if_fail(buf && size);
|
|
size = RZ_MIN(size, bv->len);
|
|
if (!bit_offset && size <= 64) {
|
|
ut64 val = 0;
|
|
for (ut32 i = 0; i < (size + 7) / 8; i++) {
|
|
val |= (ut64)buf[i] << (i * 8);
|
|
}
|
|
val &= (UT64_MAX >> (64 - size));
|
|
rz_bv_set_from_ut64(bv, val);
|
|
return;
|
|
}
|
|
for (ut32 i = 0; i < bv->len; i++) {
|
|
bool bit = false;
|
|
if (i < size) {
|
|
ut32 idx = (bit_offset + i) >> 3;
|
|
ut32 sh = (bit_offset + i) & 7;
|
|
bit = (buf[idx] >> sh) & 1;
|
|
}
|
|
rz_bv_set(bv, i, bit);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Set the bitvector's contents from the given bits. The bitvector's size is unchanged.
|
|
* If bv->len < size, additional bits are cut off, if bv->len > size, the rest is filled up with 0.
|
|
*
|
|
* \param buf big endian buffer of at least (bit_offset + size + 7) / 8 bytes
|
|
* \param bit_offset offset inside buf to start reading from, in bits
|
|
* \param size number of bits to read from buf
|
|
*/
|
|
RZ_API void rz_bv_set_from_bytes_be(RZ_NONNULL RzBitVector *bv, RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size) {
|
|
rz_return_if_fail(buf && size);
|
|
size = RZ_MIN(size, bv->len);
|
|
// upper bits goes always in the upper bit of the bitv
|
|
for (ut32 i = 0; i < bv->len; i++) {
|
|
bool bit = false;
|
|
if (i < size) {
|
|
ut32 idx = (bit_offset + i) >> 3;
|
|
ut32 sh = ((bit_offset + i) & 7);
|
|
ut8 b8 = buf[idx];
|
|
b8 = (size < 8) ? reverse_lt_8bits(b8, size) : (ut8)reverse_byte(b8);
|
|
bit = (b8 >> sh) & 1;
|
|
}
|
|
rz_bv_set(bv, bv->len - 1 - i, bit);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Set the buffer contents from the given bitvector's bits in little endian format.
|
|
* \param bv BitVector to use as source of the bits
|
|
* \param buf buffer to write little endian data.
|
|
*/
|
|
RZ_API void rz_bv_set_to_bytes_le(RZ_NONNULL const RzBitVector *bv, RZ_OUT RZ_NONNULL ut8 *buf) {
|
|
rz_return_if_fail(bv && buf);
|
|
ut32 bytes = rz_bv_len_bytes(bv);
|
|
if (bv->len > 64) {
|
|
for (ut32 i = 0; i < bytes; i++) {
|
|
if (i + 1 == bytes && bv->len % 8) {
|
|
buf[i] &= (0xff << (bv->len % 8)) & 0xff;
|
|
buf[i] |= bv->bits.large_a[i];
|
|
} else {
|
|
buf[i] = bv->bits.large_a[i];
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
ut64 val = bv->bits.small_u;
|
|
for (ut32 i = 0; i < bytes; i++) {
|
|
if (i + 1 == bytes && bv->len % 8) {
|
|
buf[i] &= (0xff << (bv->len % 8)) & 0xff;
|
|
buf[i] |= val & 0xff;
|
|
} else {
|
|
buf[i] = val & 0xff;
|
|
}
|
|
val >>= 8;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Set the buffer contents from the given bitvector's bits in big endian format.
|
|
* \param bv BitVector to use as source of the bits
|
|
* \param buf buffer to write big endian data.
|
|
*/
|
|
RZ_API void rz_bv_set_to_bytes_be(RZ_NONNULL const RzBitVector *bv, RZ_OUT RZ_NONNULL ut8 *buf) {
|
|
rz_return_if_fail(bv && buf);
|
|
ut32 bytes = rz_bv_len_bytes(bv);
|
|
if (bv->len > 64) {
|
|
ut32 end = bytes - 1;
|
|
for (ut32 i = 0; i < bytes; i++) {
|
|
buf[end - i] = bv->bits.large_a[i];
|
|
}
|
|
return;
|
|
}
|
|
ut64 val = bv->bits.small_u;
|
|
for (ut32 i = bytes - 1; i; i--) {
|
|
buf[i] = val & 0xFF;
|
|
val >>= 8;
|
|
}
|
|
buf[0] = val & 0xFF;
|
|
}
|
|
|
|
/**
|
|
* Calculates the hash from the bitvector data
|
|
* \param x BitVector
|
|
* \return ut32 bitvector hash
|
|
*/
|
|
RZ_API ut32 rz_bv_hash(RZ_NULLABLE RzBitVector *x) {
|
|
ut32 h = 5381;
|
|
if (!x) {
|
|
return h;
|
|
}
|
|
|
|
ut32 size = (x->len > 64) ? x->_elem_len : sizeof(x->bits.small_u);
|
|
ut8 *bits = (x->len > 64) ? x->bits.large_a : (ut8 *)&x->bits.small_u;
|
|
if (!size || !bits) {
|
|
return h;
|
|
}
|
|
|
|
for (ut32 i = 0; i < size; ++i) {
|
|
h = (h + (h << 5)) ^ bits[i];
|
|
}
|
|
|
|
h ^= x->len;
|
|
return h;
|
|
}
|
|
|
|
/**
|
|
* Convert bitv to a ut8 value
|
|
* \param x BitVector
|
|
* \return ut8 value
|
|
*/
|
|
RZ_API ut8 rz_bv_to_ut8(RZ_NONNULL const RzBitVector *x) {
|
|
rz_return_val_if_fail(x, 0);
|
|
if (x->len <= 64) {
|
|
return (ut8)x->bits.small_u & UT8_MAX;
|
|
}
|
|
ut8 ret = 0;
|
|
for (ut32 i = 0; i < x->len && i < 8; ++i) {
|
|
if (rz_bv_get(x, i)) {
|
|
ret |= 1 << i;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Convert bitv to ut16 value
|
|
* \param x BitVector
|
|
* \return ut16 value
|
|
*/
|
|
RZ_API ut16 rz_bv_to_ut16(RZ_NONNULL const RzBitVector *x) {
|
|
rz_return_val_if_fail(x, 0);
|
|
if (x->len <= 64) {
|
|
return (ut16)x->bits.small_u & UT16_MAX;
|
|
}
|
|
ut16 ret = 0;
|
|
for (ut32 i = 0; i < x->len && i < 16; ++i) {
|
|
if (rz_bv_get(x, i)) {
|
|
ret |= 1 << i;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Convert bitv to ut32 value
|
|
* \param x BitVector
|
|
* \return ut32 value
|
|
*/
|
|
RZ_API ut32 rz_bv_to_ut32(RZ_NONNULL const RzBitVector *x) {
|
|
rz_return_val_if_fail(x, 0);
|
|
if (x->len <= 64) {
|
|
return (ut32)x->bits.small_u & UT32_MAX;
|
|
}
|
|
ut32 ret = 0;
|
|
for (ut32 i = 0; i < x->len && i < 32; ++i) {
|
|
if (rz_bv_get(x, i)) {
|
|
ret |= 1 << i;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Convert RzBitVector to ut64
|
|
* \param x RzBitVector, pointer to the bitvector
|
|
* \return ret ut64, num value of bitvector
|
|
*/
|
|
RZ_API ut64 rz_bv_to_ut64(RZ_NONNULL const RzBitVector *x) {
|
|
rz_return_val_if_fail(x, 0);
|
|
if (x->len <= 64) {
|
|
return x->bits.small_u;
|
|
}
|
|
ut64 ret = 0;
|
|
for (ut32 i = 0; i < x->len && i < 64; ++i) {
|
|
if (rz_bv_get(x, i)) {
|
|
ret |= 1ULL << i;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* set a range of bits to bool value `b`, the range is inclusive
|
|
* pos_end element is also included
|
|
* \param bv RzBitVector
|
|
* \param pos_start start index of range
|
|
* \param pos_end end index of range
|
|
* \param b bool value
|
|
* \return return true if success, else return false
|
|
*/
|
|
RZ_API bool rz_bv_set_range(RZ_NONNULL RzBitVector *bv, ut32 pos_start, ut32 pos_end, bool b) {
|
|
rz_return_val_if_fail(bv, false);
|
|
if (pos_start > bv->len - 1 || pos_end > bv->len - 1) {
|
|
return false;
|
|
}
|
|
|
|
for (ut32 i = pos_start; i <= pos_end; ++i) {
|
|
rz_bv_set(bv, i, b);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* check if bitvector's bits are all set to bit 1
|
|
* \param x RzBitVector
|
|
* \return true if all bits of bv `x` are set to 1
|
|
*/
|
|
RZ_API bool rz_bv_is_all_one(RZ_NONNULL const RzBitVector *x) {
|
|
rz_return_val_if_fail(x, false);
|
|
// could not use ~0 as full-vector when bits < 64
|
|
|
|
for (ut32 i = 0; i < x->len; ++i) {
|
|
if (rz_bv_get(x, i) == 0) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* get predecessor of bv (dec 1) in 2^n modulo
|
|
* \param bv
|
|
* \return predecessor of bv
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_pred(RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
ut32 len = bv->len;
|
|
if (len <= 64) {
|
|
ut64 val = rz_bv_to_ut64(bv);
|
|
val -= 1;
|
|
return rz_bv_new_from_ut64(len, val);
|
|
}
|
|
|
|
RzBitVector *one = rz_bv_new_one(len);
|
|
RzBitVector *result = rz_bv_sub(bv, one, NULL);
|
|
rz_bv_free(one);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* get successor of bv (inc 1) in 2^n modulo
|
|
* \param bv
|
|
* \return successor of bv
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_succ(RZ_NONNULL RzBitVector *bv) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
ut32 len = bv->len;
|
|
if (len <= 64) {
|
|
ut64 val = rz_bv_to_ut64(bv);
|
|
val += 1;
|
|
return rz_bv_new_from_ut64(len, val);
|
|
}
|
|
|
|
RzBitVector *one = rz_bv_new_one(len);
|
|
RzBitVector *result = rz_bv_sub(bv, one, NULL);
|
|
rz_bv_free(one);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Arithmetic right shift of bv, shift right with (msb bv) bit filled
|
|
* \param bv
|
|
* \param dist shift distance
|
|
* \return true if success
|
|
*/
|
|
RZ_API bool rz_bv_arshift(RZ_NONNULL RzBitVector *bv, ut32 dist) {
|
|
rz_return_val_if_fail(bv, false);
|
|
bool msb = rz_bv_msb(bv);
|
|
return rz_bv_rshift_fill(bv, dist, msb);
|
|
}
|
|
|
|
/**
|
|
* cast bv to sort (to_size), fill with fill_bit. fill_bit has no effect if it's a narrowing cast
|
|
* If m = size s - size (sort b) > 0 then m bits b are prepended to the most significant part of the vector.
|
|
* \param bv
|
|
* \param to_size new bitvector length
|
|
* \param fill_bit specify filling bit if extend
|
|
* \return new bv with length (to_size)
|
|
*/
|
|
RZ_API RzBitVector *rz_bv_cast(RZ_NONNULL RzBitVector *bv, ut32 to_size, bool fill_bit) {
|
|
rz_return_val_if_fail(bv, NULL);
|
|
|
|
RzBitVector *ret = rz_bv_new(to_size);
|
|
rz_bv_set_all(ret, fill_bit);
|
|
rz_bv_copy_nbits(bv, 0, ret, 0, RZ_MIN(bv->len, to_size));
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* signed cast of bv, (signed_cast x n) = (cast x n (msb x))
|
|
* \param bv
|
|
* \param to_size cast bitvector length
|
|
* \return new bv with length (to_size)
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_signed_cast(RZ_NONNULL RzBitVector *bv, ut32 to_size) {
|
|
return rz_bv_cast(bv, to_size, rz_bv_msb(bv));
|
|
}
|
|
|
|
/**
|
|
* unsigned cast of bv, (unsigned_cast x n) = (cast x n 0)
|
|
* \param bv
|
|
* \param to_size cast bitvector length
|
|
* \return new bv with length (to_size)
|
|
*/
|
|
RZ_API RZ_OWN RzBitVector *rz_bv_unsigned_cast(RZ_NONNULL RzBitVector *bv, ut32 to_size) {
|
|
return rz_bv_cast(bv, to_size, false);
|
|
}
|
|
|
|
/**
|
|
* strict signed less than, x < y
|
|
* \param x bv as signed value
|
|
* \param y bv as signed value
|
|
* \return compare result as bool value
|
|
*/
|
|
RZ_API bool rz_bv_slt(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
// x < y === !(x >= y) === !(y <= x)
|
|
return !rz_bv_sle(y, x);
|
|
}
|
|
|
|
/**
|
|
* strict unsigned less than, x < y
|
|
* \param x bv as unsigned
|
|
* \param y bv as unsigned
|
|
* \return
|
|
*/
|
|
RZ_API bool rz_bv_ult(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
return !rz_bv_ule(y, x);
|
|
}
|
|
|
|
/**
|
|
* strict signed great then, x > y
|
|
* \param x bv as signed
|
|
* \param y bv as signed
|
|
* \return
|
|
*/
|
|
RZ_API bool rz_bv_sgt(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
return !rz_bv_sle(x, y);
|
|
}
|
|
|
|
/**
|
|
* strict unsigned great than, x > y
|
|
* \param x bv as unsigned
|
|
* \param y bv as unsigned
|
|
* \return
|
|
*/
|
|
RZ_API bool rz_bv_ugt(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
return !rz_bv_ule(x, y);
|
|
}
|
|
|
|
/**
|
|
* strict signed great than or equal, x >= y
|
|
* \param x bv as signed
|
|
* \param y bv as signed
|
|
* \return
|
|
*/
|
|
RZ_API bool rz_bv_sge(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
return rz_bv_sle(y, x);
|
|
}
|
|
|
|
/**
|
|
* strict unsigned great than or equal, x >= y
|
|
* \param x bv as unsigned
|
|
* \param y bv as unsigned
|
|
* \return
|
|
*/
|
|
RZ_API bool rz_bv_uge(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|
rz_return_val_if_fail(x && y, false);
|
|
return rz_bv_ule(y, x);
|
|
}
|