use std::slice::{Iter, IterMut};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")]
use serde_big_array::BigArray;
use nom::number::complete::be_u24;
use crate::sector::{
SectorHeaderSize, SECTOR_DATA_SIZE, SECTOR_EXPANDED_DATA_SIZE, SECTOR_EXPANDED_HEADER_SIZE,
SECTOR_HEADER_SIZE,
};
pub const ARCHIVE_REF_LEN: usize = 6;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct ArchiveRef {
pub id: u32,
pub index_id: u8,
pub sector: usize,
pub length: usize,
}
impl ArchiveRef {
pub fn from_buffer(id: u32, index_id: u8, buffer: &[u8]) -> crate::Result<Self> {
let (buffer, len) = be_u24(buffer)?;
let (_, sec) = be_u24(buffer)?;
Ok(Self {
id,
index_id,
sector: sec as usize,
length: len as usize,
})
}
pub fn data_blocks(&self) -> DataBlocks {
let (header_len, data_len) = match SectorHeaderSize::from(self) {
SectorHeaderSize::Normal => (SECTOR_HEADER_SIZE, SECTOR_DATA_SIZE),
SectorHeaderSize::Expanded => (SECTOR_EXPANDED_HEADER_SIZE, SECTOR_EXPANDED_DATA_SIZE),
};
let n = self.length / data_len;
let rem = self.length % data_len;
let n = if rem > 0 { n + 1 } else { n };
DataBlocks {
count: n,
remainder: rem,
header_len,
data_len,
}
}
}
pub struct DataBlocks {
count: usize,
remainder: usize,
header_len: usize,
data_len: usize,
}
impl Iterator for DataBlocks {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.count == 0 {
return None;
}
let n = if self.count == 1 && self.remainder != 0 {
self.remainder
} else {
self.data_len
};
self.count -= 1;
Some(self.header_len + n)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct ArchiveMetadata {
pub id: u32,
pub name_hash: i32,
pub crc: u32,
pub hash: i32,
#[cfg_attr(feature = "serde", serde(with = "BigArray"))]
pub whirlpool: [u8; 64],
pub version: u32,
pub entry_count: usize,
pub valid_ids: Vec<u32>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct ArchiveFileData {
pub id: u32,
pub data: Vec<u8>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct ArchiveFileGroup(Vec<ArchiveFileData>);
impl ArchiveFileGroup {
pub fn from_buffer(buffer: &[u8], entry_count: usize) -> Self {
let chunks = buffer[buffer.len() - 1] as usize;
let mut data = Vec::with_capacity(chunks);
let mut cached_chunks = Vec::with_capacity(chunks);
let mut read_ptr = buffer.len() - 1 - chunks * entry_count * 4;
for _ in 0..chunks {
let mut chunk_size = 0;
for entry_id in 0..entry_count {
let mut bytes = [0; 4];
bytes.copy_from_slice(&buffer[read_ptr..read_ptr + 4]);
let delta = i32::from_be_bytes(bytes);
read_ptr += 4;
chunk_size += delta;
cached_chunks.push((entry_id as u32, chunk_size as usize));
}
}
read_ptr = 0;
for (entry_id, chunk_size) in cached_chunks {
let buf = buffer[read_ptr..read_ptr + chunk_size].to_vec();
data.push(ArchiveFileData {
id: entry_id,
data: buf,
});
read_ptr += chunk_size;
}
Self(data)
}
#[inline]
pub fn iter(&self) -> Iter<'_, ArchiveFileData> {
self.0.iter()
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, ArchiveFileData> {
self.0.iter_mut()
}
}
impl IntoIterator for ArchiveFileGroup {
type Item = ArchiveFileData;
type IntoIter = std::vec::IntoIter<ArchiveFileData>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a ArchiveFileGroup {
type Item = &'a ArchiveFileData;
type IntoIter = Iter<'a, ArchiveFileData>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
#[test]
fn parse_archive() -> crate::Result<()> {
let buffer = &[0, 0, 77, 0, 1, 196];
let archive = ArchiveRef::from_buffer(10, 255, buffer)?;
assert_eq!(
archive,
ArchiveRef {
id: 10,
index_id: 255,
sector: 452,
length: 77
}
);
Ok(())
}