use crate::envi::constants::{ARCH_NAMES, ARCH_NAMES_REV};
use crate::envi::ArchitectureModule;
use crate::envi::Result;
use crate::error::Error::InvalidState;
use lazy_static::lazy_static;
use std::rc::Rc;
pub const MAX_WORD: i32 = 32;
lazy_static! {
static ref U_MAXES: Vec<i32> = {
let mut u_maxes: Vec<i32> = (0..MAX_WORD + 1)
.map(|i| (2i32.pow(8 * i as u32) - 1))
.collect();
u_maxes[0] = 0;
u_maxes
};
static ref BU_MAXES: Vec<i32> = (0..8 * MAX_WORD + 1)
.map(|i| 2i32.pow(i as u32) - 1)
.collect();
static ref SIGN_BITS: Vec<i32> = {
let mut sign_bits: Vec<i32> = (0..MAX_WORD + 1)
.map(|i| 2i32.pow(8 * i as u32) >> 1)
.collect();
sign_bits[0] = 0;
sign_bits
};
static ref B_SIGN_BITS: Vec<i32> = (0..8 * MAX_WORD + 1)
.map(|i| 2i32.pow(i as u32) >> 1)
.collect();
static ref S_MAXES: Vec<i32> = {
let mut s_maxes: Vec<i32> = (0..MAX_WORD + 1)
.map(|i| U_MAXES[i as usize] ^ SIGN_BITS[i as usize])
.collect();
s_maxes[0] = 0;
s_maxes
};
static ref B_MASKS: Vec<i32> = {
let mut b_masks: Vec<i32> = (0..MAX_WORD * 8).map(|i| 2i32.pow(i as u32) - 1).collect();
b_masks[0] = 0;
b_masks
};
static ref PARITY_TABLE: Vec<bool> = (0..256).map(|i| is_parity(i)).collect();
static ref LE_FMT_CHARS: Vec<Option<&'static str>> = vec![
None,
Some("B"),
Some("<H"),
None,
Some("<I"),
None,
None,
None,
Some("<Q")
];
static ref BE_FMT_CHARS: Vec<Option<&'static str>> = vec![
None,
Some("B"),
Some(">H"),
None,
Some(">I"),
None,
None,
None,
Some(">Q")
];
static ref FMT_CHARS: Vec<Vec<Option<&'static str>>> =
vec![LE_FMT_CHARS.clone(), BE_FMT_CHARS.clone()];
static ref LE_FMT_SCHARS: Vec<Option<&'static str>> = vec![
None,
Some("b"),
Some("<h"),
None,
Some("<i"),
None,
None,
None,
Some("<q")
];
static ref BE_FMT_SCHARS: Vec<Option<&'static str>> = vec![
None,
Some("b"),
Some(">h"),
None,
Some(">i"),
None,
None,
None,
Some(">q")
];
static ref FMT_SCHARS: Vec<Vec<Option<&'static str>>> =
vec![LE_FMT_SCHARS.clone(), BE_FMT_SCHARS.clone()];
static ref MASTER_FMTS: Vec<Vec<Vec<Option<&'static str>>>> =
vec![FMT_CHARS.clone(), FMT_SCHARS.clone()];
static ref FMT_SIZES: Vec<Option<i32>> = vec![
None,
Some(1),
Some(2),
Some(4),
Some(4),
Some(8),
Some(8),
Some(8),
Some(8)
];
static ref LE_FMT_FLOAT: Vec<Option<&'static str>> = vec![
None,
None,
None,
None,
Some("<f"),
None,
None,
None,
Some("<d")
];
static ref BE_FMT_FLOAT: Vec<Option<&'static str>> = vec![
None,
None,
None,
None,
Some(">f"),
None,
None,
None,
Some(">d")
];
static ref FMT_FLOATS: Vec<Vec<Option<&'static str>>> =
vec![LE_FMT_FLOAT.clone(), BE_FMT_FLOAT.clone()];
}
pub fn signed(value: i32, size: i32) -> i32 {
let x = unsigned(value, size);
if x & SIGN_BITS[size as usize] != 0 {
x - U_MAXES[size as usize] - 1
} else {
x
}
}
pub fn unsigned(value: i32, size: i32) -> i32 {
value & U_MAXES[size as usize]
}
pub fn b_signed(value: i32, size: i32) -> i32 {
if value & B_SIGN_BITS[size as usize] != 0 {
value - BU_MAXES[size as usize] - 1
} else {
value
}
}
pub fn is_signed(value: i32, size: i32) -> bool {
let x = unsigned(value, size);
x & SIGN_BITS[size as usize] != 0
}
pub fn sign_extend(value: i32, cursize: i32, newsize: i32) -> i32 {
let mut x = unsigned(value, cursize);
if cursize != newsize && x & SIGN_BITS[cursize as usize] != 0 {
let delta = newsize - cursize;
let highbits = U_MAXES[delta as usize];
x |= highbits << (8 * cursize);
}
x
}
pub fn bsign_extend(value: i32, cursize: i32, newsize: i32) -> i32 {
let mut x = value;
if cursize != newsize && x & B_SIGN_BITS[cursize as usize] != 0 {
let delta = newsize - cursize;
let highbits = BU_MAXES[delta as usize];
x |= highbits << cursize;
}
x
}
pub fn is_parity(val: i32) -> bool {
let mut s = 0;
let mut val = val;
while val != 0 {
s ^= val & 1;
val >>= 1;
}
s == 0
}
pub fn lsb(value: i32) -> i32 {
value & 0x1
}
pub fn msb(value: i32, size: i32) -> bool {
value & SIGN_BITS[size as usize] != 0
}
pub fn msb_minus_one(value: i32, size: i32) -> bool {
let bsize = size << 3;
value & B_SIGN_BITS[bsize as usize] != 0
}
pub fn is_signed_half_carry(value: i32, size: i32, src: i32) -> bool {
let bitsize = (size << 3) - 5;
let mask = 1 << bitsize;
let p1 = value & mask;
let p2 = src & mask;
(p1 ^ p2) != 0
}
pub fn is_signed_carry(value: i32, size: i32, src: i32) -> bool {
let smax = S_MAXES[size as usize];
if value > smax && smax > src {
true
} else if value < -smax && -smax < -src {
true
} else {
false
}
}
pub fn get_arch_by_name(arch_name: &str) -> Option<i32> {
ARCH_NAMES_REV.get(arch_name).cloned()
}
pub fn get_arch_by_id(arch_id: i32) -> Option<&'static str> {
ARCH_NAMES.get(&arch_id).cloned()
}
pub fn get_current_arch() -> Option<&'static str> {
None
}
pub fn get_arch_modules(arch: Option<i32>) -> Vec<Rc<dyn ArchitectureModule>> {
vec![]
}
pub fn align(val: i32, align: i32) -> i32 {
let remainder = val % align;
if remainder == 0 {
val
} else {
val + (align - remainder)
}
}
pub fn mem_diff(mem1: Vec<u8>, mem2: Vec<u8>) -> Result<Vec<(i32, i32)>> {
if mem1 == mem2 {
return Ok(Vec::new());
}
let size = mem1.len();
if size != mem2.len() {
return Err(InvalidState(
"mem_diff *requires* same size bytes.".to_string(),
));
}
let mut diffs = Vec::new();
let mut offset = 0;
while offset < size {
if mem1[offset] != mem2[offset] {
let begin_offset = offset;
while offset < size && mem1[offset] != mem2[offset] {
offset += 1;
}
diffs.push((begin_offset as i32, (offset - begin_offset) as i32));
}
offset += 1;
}
Ok(diffs)
}
pub fn parse_bits(bytes: Vec<u8>, offset: i32, bit_off: i32, bit_size: i32) -> u8 {
let mut val = 0;
let mut cnt = 0;
while cnt < bit_size {
let add_bit = bit_off + cnt;
let add_off = offset + (add_bit >> 3);
let mod_off = add_bit % 8;
let o = bytes[add_off as usize];
val = (val << 1) + ((o >> (7 - mod_off)) & 1);
cnt += 1;
}
val
}
pub fn parse_bytes(
bytes: Vec<i32>,
offset: i32,
size: i32,
sign: Option<bool>,
bigend: Option<bool>,
) -> Vec<i32> {
let sign = sign.unwrap_or_default();
let bigend = bigend.unwrap_or_default();
if size > 8 {
return slow_parse_bytes(bytes, offset, size, Some(sign), Some(bigend));
}
let f = if bigend {
LE_FMT_CHARS[size as usize]
} else {
BE_FMT_CHARS[size as usize]
};
if f.is_none() {
return slow_parse_bytes(bytes, offset, size, Some(sign), Some(bigend));
}
let d = &bytes[offset as usize..(offset + size) as usize];
let x = match f.unwrap() {
"B" => vec![d[0]],
"H" => d.chunks(2).map(|c| c[0] | (c[1] << 8)).collect(),
"I" => d
.chunks(4)
.map(|c| c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24))
.collect(),
_ => return slow_parse_bytes(bytes, offset, size, Some(sign), Some(bigend)),
};
if sign {
x.iter().map(|v| signed(*v, size)).collect()
} else {
x
}
}
pub fn slow_parse_bytes(
bytes: Vec<i32>,
offset: i32,
size: i32,
sign: Option<bool>,
bigend: Option<bool>,
) -> Vec<i32> {
let sign = sign.unwrap_or_default();
let bigend = bigend.unwrap_or_default();
let (begin, inc) = if bigend {
(offset, 1)
} else {
(offset + size - 1, -1)
};
let mut ret = 0;
let mut ioff = 0;
let mut x = Vec::new();
for _ in 0..size {
ret = ret << 8;
ret |= bytes[(begin + ioff) as usize] as i32;
ioff += inc;
}
if sign {
x.push(signed(ret, size));
} else {
x.push(ret);
}
x
}