use std::fmt;
use std::io;
use std::io::Read;
use std::slice;
pub const B_HPKG_COMPRESSION_NONE: u16 = 0;
pub const B_HPKG_COMPRESSION_ZLIB: u16 = 1;
pub const B_HPKG_COMPRESSION_ZSTD: u16 = 2;
pub const HPKG_ATTR_TYPE_INT: u16 = 1;
pub const HPKG_ATTR_TYPE_UINT: u16 = 2;
pub const HPKG_ATTR_TYPE_STRING: u16 = 3;
pub const HPKG_ATTR_TYPE_RAW: u16 = 4;
pub const HPKG_ATTR_ENCODING_INT_8_BIT: u16 = 0;
pub const HPKG_ATTR_ENCODING_INT_16_BIT: u16 = 1;
pub const HPKG_ATTR_ENCODING_INT_32_BIT: u16 = 2;
pub const HPKG_ATTR_ENCODING_INT_64_BIT: u16 = 3;
pub const HPKG_ATTR_ENCODING_STRING_INLINE: u16 = 0;
pub const HPKG_ATTR_ENCODING_STRING_TABLE: u16 = 1;
pub const HPKG_ATTR_ENCODING_RAW_INLINE: u16 = 0;
pub const HPKG_ATTR_ENCODING_RAW_HEAP: u16 = 1;
pub const ARCH_ANY: u64 = 0;
pub const ARCH_X86: u64 = 1;
pub const ARCH_X86_GCC2: u64 = 2;
pub const ARCH_SOURCE: u64 = 3;
pub const ARCH_X86_64: u64 = 4;
pub const ARCH_PPC: u64 = 5;
pub const ARCH_ARM: u64 = 6;
pub const ARCH_M68K: u64 = 7;
pub const ARCH_SPARC: u64 = 8;
pub const ARCH_ARM64: u64 = 9;
pub const ARCH_RISCV64: u64 = 10;
#[derive(Debug, Clone)]
pub enum AttrValue {
Int(i64),
Uint(u64),
String(String),
Raw(Vec<u8>),
}
pub fn read_unsigned_leb128(data: &[u8], offset: &mut usize) -> Result<u64, Box<dyn std::error::Error>> {
let mut result: u64 = 0;
let mut shift = 0;
loop {
if *offset >= data.len() {
return Err(From::from("Unexpected end of data while reading LEB128".to_string()));
}
let byte = data[*offset];
*offset += 1;
result |= ((byte & 0x7f) as u64) << shift;
if byte & 0x80 == 0 {
return Ok(result);
}
shift += 7;
if shift >= 64 {
return Err(From::from("LEB128 integer too large".to_string()));
}
}
}
pub fn decode_attribute_tag(tag: u64) -> (u16, u16, u16, bool) {
let raw = (tag as u16).wrapping_sub(1);
let id = raw & 0x7f;
let type_ = (raw >> 7) & 0x7;
let has_children = (raw >> 10) & 0x1 != 0;
let encoding = (raw >> 11) & 0x3;
(id, type_, encoding, has_children)
}
pub fn arch_to_string(value: u64) -> String {
match value {
ARCH_ANY => "any".to_string(),
ARCH_X86 => "x86".to_string(),
ARCH_X86_GCC2 => "x86_gcc2".to_string(),
ARCH_SOURCE => "source".to_string(),
ARCH_X86_64 => "x86_64".to_string(),
ARCH_PPC => "ppc".to_string(),
ARCH_ARM => "arm".to_string(),
ARCH_M68K => "m68k".to_string(),
ARCH_SPARC => "sparc".to_string(),
ARCH_ARM64 => "arm64".to_string(),
ARCH_RISCV64 => "riscv64".to_string(),
_ => format!("arch_{}", value),
}
}
pub fn read_struct<T, R: Read>(mut read: R) -> io::Result<T> {
let num_bytes = ::std::mem::size_of::<T>();
unsafe {
let mut s = ::std::mem::zeroed();
let buffer = slice::from_raw_parts_mut(&mut s as *mut T as *mut u8, num_bytes);
match read.read_exact(buffer) {
Ok(()) => Ok(s),
Err(e) => Err(e),
}
}
}
impl fmt::Display for AttrValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AttrValue::Int(v) => write!(f, "int({})", v),
AttrValue::Uint(v) => write!(f, "uint({})", v),
AttrValue::String(s) => write!(f, "\"{}\"", s),
AttrValue::Raw(r) => write!(f, "raw({} bytes)", r.len()),
}
}
}
pub(crate) fn write_unsigned_leb128(buf: &mut Vec<u8>, mut value: u64) {
loop {
let mut byte = (value as u8) & 0x7f;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
buf.push(byte);
if value == 0 {
break;
}
}
}
pub(crate) fn write_attr_tag(buf: &mut Vec<u8>, id: u16, type_: u16, encoding: u16, has_children: bool) {
let tag: u64 = 1
+ ((encoding as u64) << 11)
+ ((has_children as u64) << 10)
+ ((type_ as u64) << 7)
+ (id as u64);
write_unsigned_leb128(buf, tag);
}
pub(crate) fn write_string_inline(buf: &mut Vec<u8>, s: &str) {
buf.extend_from_slice(s.as_bytes());
buf.push(0);
}
pub(crate) fn uint_encoding(value: u64) -> u16 {
if value <= u8::MAX as u64 {
0
} else if value <= u16::MAX as u64 {
1
} else if value <= u32::MAX as u64 {
2
} else {
3
}
}
pub(crate) fn write_int_value(buf: &mut Vec<u8>, value: u64, encoding: u16) {
match encoding {
0 => buf.push(value as u8),
1 => buf.extend_from_slice(&(value as u16).to_be_bytes()),
2 => buf.extend_from_slice(&(value as u32).to_be_bytes()),
3 => buf.extend_from_slice(&value.to_be_bytes()),
_ => buf.extend_from_slice(&(value as u32).to_be_bytes()),
}
}