use crate::BaleError;
use zerocopy::byteorder::little_endian::{U32, U64};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
#[repr(C)]
pub struct Zip64EocdLocator {
pub signature: U32,
pub zip64_eocd_disk: U32,
pub zip64_eocd_offset: U64,
pub total_disks: U32,
}
impl Zip64EocdLocator {
pub const SIGNATURE: u32 = 0x07064b50;
pub const SIZE: usize = 20;
#[must_use]
pub fn new(zip64_eocd_offset: u64) -> Self {
Self {
signature: U32::new(Self::SIGNATURE),
zip64_eocd_disk: U32::new(0),
zip64_eocd_offset: U64::new(zip64_eocd_offset),
total_disks: U32::new(1),
}
}
#[must_use]
pub const fn zip64_eocd_offset(&self) -> u64 {
self.zip64_eocd_offset.get()
}
#[must_use]
pub const fn is_valid(&self) -> bool {
self.signature.get() == Self::SIGNATURE && self.total_disks.get() == 1
}
pub fn validated(&self) -> Result<&Self, BaleError> {
if self.is_valid() {
Ok(self)
} else {
Err(BaleError::InvalidSignature {
expected: Self::SIGNATURE,
found: self.signature.get(),
})
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn size_is_20_bytes() {
assert_eq!(
std::mem::size_of::<Zip64EocdLocator>(),
Zip64EocdLocator::SIZE
);
assert_eq!(Zip64EocdLocator::SIZE, 20);
}
#[test]
fn new_has_correct_signature() {
let locator = Zip64EocdLocator::new(0);
assert!(locator.is_valid());
assert_eq!(locator.signature.get(), Zip64EocdLocator::SIGNATURE);
assert_eq!(locator.zip64_eocd_disk.get(), 0);
assert_eq!(locator.total_disks.get(), 1);
}
#[test]
fn roundtrip_with_offset() {
let locator = Zip64EocdLocator::new(5_000_000_000);
let bytes = locator.as_bytes();
assert_eq!(bytes.len(), Zip64EocdLocator::SIZE);
let restored = Zip64EocdLocator::ref_from_bytes(bytes).unwrap();
assert!(restored.is_valid());
assert_eq!(restored.zip64_eocd_offset(), 5_000_000_000);
}
#[test]
fn accessor() {
let locator = Zip64EocdLocator::new(12345);
assert_eq!(locator.zip64_eocd_offset(), 12345);
}
#[test]
fn invalid_signature_fails_validation() {
let mut locator = Zip64EocdLocator::new(0);
locator.signature = U32::new(0x12345678);
assert!(!locator.is_valid());
}
#[test]
fn invalid_total_disks_fails_validation() {
let mut locator = Zip64EocdLocator::new(0);
locator.total_disks = U32::new(2); assert!(!locator.is_valid());
}
#[test]
fn validated_returns_ok_for_valid() {
let locator = Zip64EocdLocator::new(0);
assert!(locator.validated().is_ok());
}
#[test]
fn validated_returns_err_for_invalid() {
let mut locator = Zip64EocdLocator::new(0);
locator.signature = U32::new(0xDEADBEEF);
let err = locator.validated().unwrap_err();
assert!(matches!(
err,
BaleError::InvalidSignature {
expected: 0x07064b50,
found: 0xDEADBEEF
}
));
}
}