use std::{cmp, fmt, mem, num, ops, slice, str};
use std::io::ErrorKind;
use dataview::Pod;
mod cipher;
mod crypt;
mod dir;
pub use self::dir::TreeArt;
mod directory;
pub use self::directory::*;
mod file_io;
pub use self::file_io::*;
mod memory;
pub use self::memory::*;
pub type Block = [u64; 2];
pub type Key = [u64; 2];
pub fn parse_key(s: &str) -> Result<Key, num::ParseIntError> {
u128::from_str_radix(s, 16).map(|val| [(val & 0xffffffffffffffff) as u64, (val >> 64) as u64])
}
const BLOCK_SIZE: usize = mem::size_of::<Block>();
#[derive(Copy, Clone, Default, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Section {
pub offset: u32,
pub size: u32,
pub nonce: Block,
pub mac: Block,
}
impl Section {
#[inline]
fn range_usize(&self) -> ops::Range<usize> {
self.offset as usize..(self.offset.wrapping_add(self.size)) as usize
}
}
impl fmt::Debug for Section {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Section")
.field("offset", &self.offset)
.field("size", &self.size)
.field("nonce", &format_args!("[{:#x}, {:#x}]", self.nonce[0], self.nonce[1]))
.field("mac", &format_args!("[{:#x}, {:#x}]", self.mac[0], self.mac[1]))
.finish()
}
}
unsafe impl Pod for Section {}
fn bytes2blocks(byte_size: u32) -> u32 {
if byte_size == 0 { 0 } else { (byte_size - 1) / BLOCK_SIZE as u32 + 1 }
}
#[derive(Copy, Clone, Default, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct InfoHeader {
pub version: u32,
pub _unused: u32,
pub directory: Section,
}
impl InfoHeader {
pub const VERSION: u32 = u32::from_ne_bytes(*b"PAK1");
}
impl fmt::Debug for InfoHeader {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("InfoHeader")
.field("version", &self.version)
.field("directory", &self.directory)
.finish()
}
}
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Header {
pub nonce: Block,
pub mac: Block,
pub info: InfoHeader,
}
impl Header {
const SECTION: Section = Section {
offset: Header::BLOCKS_LEN as u32 - InfoHeader::BLOCKS_LEN as u32,
size: InfoHeader::BLOCKS_LEN as u32,
nonce: [0, 0],
mac: [0, 0],
};
}
#[derive(Copy, Clone, Default, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Descriptor {
pub content_type: u32,
pub content_size: u32,
pub section: Section,
pub name: Name,
pub meta: Section,
}
impl Descriptor {
#[inline]
pub fn new(name: &[u8], content_type: u32, content_size: u32) -> Descriptor {
Descriptor {
content_type,
content_size,
name: Name::from(name),
..Descriptor::default()
}
}
#[inline]
pub fn file(name: &[u8]) -> Descriptor {
Descriptor::new(name, 1, 0)
}
#[inline]
pub fn dir(name: &[u8], len: u32) -> Descriptor {
Descriptor::new(name, 0, len)
}
#[inline]
pub fn name(&self) -> &[u8] {
self.name.get()
}
#[inline]
pub fn is_dir(&self) -> bool {
self.content_type == 0
}
#[inline]
pub fn is_file(&self) -> bool {
self.content_type != 0
}
}
impl fmt::Debug for Descriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Descriptor")
.field("name", &self.name)
.field("content_type", &self.content_type)
.field("content_size", &self.content_size)
.field("section", &self.section)
.finish()
}
}
const NAME_BUF_LEN: usize = 40;
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Name {
buffer: [u8; NAME_BUF_LEN],
}
impl Default for Name {
#[inline]
fn default() -> Name {
Name {
buffer: [0u8; NAME_BUF_LEN]
}
}
}
impl Name {
#[inline]
pub fn get(&self) -> &[u8] {
let len = usize::min(self.buffer[NAME_BUF_LEN - 1] as usize, NAME_BUF_LEN - 1);
&self.buffer[..len]
}
#[inline]
pub fn set(&mut self, name: &[u8]) {
self.buffer = [0u8; NAME_BUF_LEN];
let len = usize::min(name.len(), NAME_BUF_LEN - 1);
self.buffer[NAME_BUF_LEN - 1] = len as u8;
self.buffer[..len].copy_from_slice(&name[..len]);
}
}
impl<'a> From<&'a [u8]> for Name {
#[inline]
fn from(name: &'a [u8]) -> Name {
let mut x = Name::default();
x.set(name);
return x;
}
}
impl fmt::Debug for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
str::from_utf8(self.get()).unwrap_or("ERR").fmt(f)
}
}
macro_rules! impl_blocks {
($ty:ty) => {
const _: [(); 0] = [(); mem::size_of::<$ty>() % BLOCK_SIZE];
unsafe impl Pod for $ty {}
impl $ty {
const BLOCKS_LEN: usize = mem::size_of::<$ty>() / BLOCK_SIZE;
}
impl AsRef<[Block; Self::BLOCKS_LEN]> for $ty {
fn as_ref(&self) -> &[Block; Self::BLOCKS_LEN] {
unsafe { &*(self as *const _ as *const _) }
}
}
impl AsRef<$ty> for [Block; <$ty>::BLOCKS_LEN] {
fn as_ref(&self) -> &$ty {
unsafe { &*(self as *const _ as *const _) }
}
}
impl AsMut<[Block; Self::BLOCKS_LEN]> for $ty {
fn as_mut(&mut self) -> &mut [Block; Self::BLOCKS_LEN] {
unsafe { &mut *(self as *mut _ as *mut _) }
}
}
impl AsMut<$ty> for [Block; <$ty>::BLOCKS_LEN] {
fn as_mut(&mut self) -> &mut $ty {
unsafe { &mut *(self as *mut _ as *mut _) }
}
}
impl From<[Block; Self::BLOCKS_LEN]> for $ty {
fn from(blocks: [Block; Self::BLOCKS_LEN]) -> $ty {
unsafe { mem::transmute(blocks) }
}
}
impl From<$ty> for [Block; <$ty>::BLOCKS_LEN] {
fn from(header: $ty) -> [Block; <$ty>::BLOCKS_LEN] {
unsafe { mem::transmute(header) }
}
}
};
}
impl_blocks!(Header);
impl_blocks!(InfoHeader);
impl_blocks!(Descriptor);
#[test]
fn test_parse_key_examples() {
assert_eq!(parse_key("0").unwrap(), [0, 0]);
assert_eq!(parse_key("2a").unwrap(), [42, 0]);
assert_eq!(parse_key("112233445566778899aabbccddeeff00").unwrap(), [0x99aabbccddeeff00, 0x1122334455667788]);
assert!(parse_key("not-hex").is_err());
}
#[test]
fn test_print_sizes() {
fn print_size<T>(name: &str) {
println!("sizeof={:#x} (struct {})", std::mem::size_of::<T>(), name);
}
print_size::<Header>("Header");
print_size::<InfoHeader>("InfoHeader");
print_size::<Descriptor>("Descriptor");
print_size::<Section>("Section");
print_size::<Name>("Name");
}