use std::{fmt, io::Read, str};
#[cfg(feature = "crypto")]
use crate::crypto;
use super::{error::InternalError, result::InternalResult, flags::Flags};
#[derive(Debug, Clone, Copy)]
pub struct ArchiveConfig {
pub magic: [u8; crate::MAGIC_LENGTH],
#[cfg(feature = "crypto")]
#[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
pub public_key: Option<crypto::PublicKey>,
}
impl ArchiveConfig {
#[inline(always)]
#[cfg(feature = "crypto")]
#[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
pub const fn new(magic: [u8; crate::MAGIC_LENGTH], key: Option<crypto::PublicKey>) -> ArchiveConfig {
ArchiveConfig { magic, public_key: key }
}
#[cfg(not(feature = "crypto"))]
pub const fn new(magic: [u8; crate::MAGIC_LENGTH]) -> ArchiveConfig {
ArchiveConfig { magic }
}
#[inline]
#[cfg(feature = "crypto")]
#[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
pub fn load_public_key<T: Read>(&mut self, handle: T) -> InternalResult {
use crate::crypto_utils::read_public_key;
self.public_key = Some(read_public_key(handle)?);
Ok(())
}
#[cfg(feature = "crypto")]
#[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
pub fn key(mut self, public_key: crypto::PublicKey) -> ArchiveConfig {
self.public_key = Some(public_key);
self
}
pub fn magic(mut self, magic: [u8; crate::MAGIC_LENGTH]) -> ArchiveConfig {
self.magic = magic;
self
}
}
impl fmt::Display for ArchiveConfig {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[rustfmt::skip]
let has_pk = {
#[cfg(feature = "crypto")] { if self.public_key.is_some() { "true" } else { "false" } }
#[cfg(not(feature = "crypto"))] { "(crypto feature disabled)" }
};
write!(
f,
"[ArchiveConfig] magic: {}, has_public_key: {}",
match str::from_utf8(&self.magic) {
Ok(magic) => {
magic
},
Err(_) => {
return fmt::Result::Err(fmt::Error);
},
},
has_pk
)
}
}
#[cfg(feature = "crypto")]
impl Default for ArchiveConfig {
#[inline(always)]
fn default() -> Self {
ArchiveConfig::new(*crate::DEFAULT_MAGIC, None)
}
}
#[cfg(not(feature = "crypto"))]
impl Default for ArchiveConfig {
#[inline(always)]
fn default() -> Self {
ArchiveConfig::new(*crate::DEFAULT_MAGIC)
}
}
#[derive(Debug)]
pub(crate) struct Header {
pub magic: [u8; crate::MAGIC_LENGTH], pub flags: Flags,
pub arch_version: u16,
pub capacity: u16,
}
impl Default for Header {
#[inline(always)]
fn default() -> Header {
Header {
magic: *crate::DEFAULT_MAGIC,
flags: Flags::default(),
arch_version: crate::VERSION,
capacity: 0,
}
}
}
impl Header {
pub const BASE_SIZE: usize = crate::MAGIC_LENGTH + Flags::SIZE + Self::VERSION_SIZE + Self::CAPACITY_SIZE;
pub const VERSION_SIZE: usize = 2;
pub const CAPACITY_SIZE: usize = 2;
pub(crate) fn validate(config: &ArchiveConfig, header: &Header) -> InternalResult {
if header.magic != config.magic {
return Err(InternalError::MalformedArchiveSource(header.magic));
};
if crate::VERSION != header.arch_version {
return Err(InternalError::IncompatibleArchiveVersionError(header.arch_version));
};
Ok(())
}
pub(crate) fn from_handle<T: Read>(mut handle: T) -> InternalResult<Header> {
#![allow(clippy::uninit_assumed_init)]
let mut buffer: [u8; Header::BASE_SIZE] = [0u8; Header::BASE_SIZE];
handle.read_exact(&mut buffer)?;
Ok(Header {
magic: buffer[0..crate::MAGIC_LENGTH].try_into().unwrap(),
flags: Flags::from_bits(u32::from_le_bytes(buffer[crate::MAGIC_LENGTH..9].try_into().unwrap())),
arch_version: u16::from_le_bytes(buffer[9..11].try_into().unwrap()),
capacity: u16::from_le_bytes(buffer[11..13].try_into().unwrap()),
})
}
}