use std::{fmt, mem, ptr, str};
use std::io::Seek;
use super::from_bytes::FromBytes;
const MZAP_ENT_LEN: usize = 64;
const MZAP_NAME_LEN: usize = MZAP_ENT_LEN - 8 - 4 - 2;
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum ZapObjectType {
Micro = (1 << 63) + 3,
Header = (1 << 63) + 1,
Leaf = 1 << 63,
}
#[repr(packed)]
pub struct MZapPhys {
pub block_type: ZapObjectType, pub salt: u64,
pub norm_flags: u64,
pad: [u64; 5],
}
pub struct MZapWrapper {
pub phys: MZapPhys,
pub chunks: Vec<MZapEntPhys>, }
impl FromBytes for MZapWrapper {
fn from_bytes(data: &[u8]) -> Result<Self, &str> {
if data.len() >= mem::size_of::<MZapPhys>() {
let mzap_phys = unsafe { ptr::read(data.as_ptr() as *const MZapPhys) };
let mut mzap_entries = Vec::new();
let num_entries = (data.len() - mem::size_of::<MZapPhys>()) /
mem::size_of::<MZapEntPhys>();
for i in 0..num_entries {
let entry_pos = mem::size_of::<MZapPhys>() + i * mem::size_of::<MZapEntPhys>();
let mzap_ent = unsafe {
ptr::read(data[entry_pos..].as_ptr() as *const MZapEntPhys)
};
mzap_entries.push(mzap_ent);
}
Ok(MZapWrapper {
phys: mzap_phys,
chunks: mzap_entries,
})
} else {
Err("Error: needs a proper error message")
}
}
}
impl fmt::Debug for MZapWrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f,
"MZapPhys {{\nblock_type: {:?},\nsalt: {:X},\nnorm_flags: {:X},\nchunk: [\n",
self.phys.block_type,
self.phys.salt,
self.phys.norm_flags));
for chunk in &self.chunks {
try!(write!(f, "{:?}\n", chunk));
}
try!(write!(f, "] }}\n"));
Ok(())
}
}
#[repr(packed)]
pub struct MZapEntPhys {
pub value: u64,
pub cd: u32,
pub pad: u16,
pub name: [u8; MZAP_NAME_LEN],
}
impl MZapEntPhys {
pub fn name(&self) -> Option<&str> {
let mut len = 0;
for c in &self.name[..] {
if *c == 0 {
break;
}
len += 1;
}
str::from_utf8(&self.name[..len]).ok()
}
}
impl fmt::Debug for MZapEntPhys {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f,
"MZapEntPhys {{\nvalue: {:X},\ncd: {:X},\nname: ",
self.value,
self.cd));
for i in 0..MZAP_NAME_LEN {
if self.name[i] == 0 {
break;
}
try!(write!(f, "{}", self.name[i] as char));
}
try!(write!(f, "\n}}\n"));
Ok(())
}
}
#[repr(packed)]
pub struct ZapPhys {
pub block_type: ZapObjectType, pub magic: u64,
pub ptr_table: ZapTablePhys,
pub free_block: u64,
pub num_leafs: u64,
pub num_entries: u64,
pub salt: u64,
pub pad: [u64; 8181],
pub leafs: [u64; 8192],
}
#[repr(packed)]
pub struct ZapTablePhys {
pub block: u64,
pub num_blocks: u64,
pub shift: u64,
pub next_block: u64,
pub block_copied: u64,
}
const ZAP_LEAF_MAGIC: u32 = 0x2AB1EAF;
const ZAP_LEAF_CHUNKSIZE: usize = 24;
const ZAP_LEAF_ARRAY_BYTES: usize = ZAP_LEAF_CHUNKSIZE - 3;
#[repr(packed)]
pub struct ZapLeafHeader {
pub block_type: ZapObjectType, pub next: u64,
pub prefix: u64,
pub magic: u32,
pub n_free: u16,
pub n_entries: u16,
pub prefix_len: u16,
pub free_list: u16,
pad2: [u8; 12],
}
#[repr(packed)]
struct ZapLeafEntry {
leaf_type: u8,
int_size: u8,
next: u16,
name_chunk: u16,
name_length: u16,
value_chunk: u16,
value_length: u16,
cd: u16,
pad: [u8; 2],
hash: u64,
}
#[repr(packed)]
struct ZapLeafArray {
leaf_type: u8,
array: [u8; ZAP_LEAF_ARRAY_BYTES],
next: u16,
}
#[repr(packed)]
struct ZapLeafFree {
free_type: u8,
pad: [u8; ZAP_LEAF_ARRAY_BYTES],
next: u16,
}