runefs/
archive.rs

1use std::slice::{Iter, IterMut};
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5#[cfg(feature = "serde")]
6use serde_big_array::BigArray;
7
8use nom::number::complete::be_u24;
9
10use crate::sector::{
11    SectorHeaderSize, SECTOR_DATA_SIZE, SECTOR_EXPANDED_DATA_SIZE, SECTOR_EXPANDED_HEADER_SIZE,
12    SECTOR_HEADER_SIZE,
13};
14
15pub const ARCHIVE_REF_LEN: usize = 6;
16
17/// A reference to an archive segment.
18/// 
19/// Archives are not stored in a contiguous fashion.
20/// An `ArchiveRef` is _basically_ a wide pointer, like `&str` or `&[u8]`. When an `Archive` is fetched from the
21/// [`Dat2`](crate::Dat2) file it knows where the memory starts and its length. Each block of memory belong to the archive
22/// is viewed as a [`Sector`](crate::Sector), which contains a pointer to the next sector. Once this chain is 
23/// exhausted you are left with all of the archive data.
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
26pub struct ArchiveRef {
27    pub id: u32,
28    pub index_id: u8,
29    pub sector: usize,
30    pub length: usize,
31}
32
33impl ArchiveRef {
34    /// Transforms an [`Index`](crate::Index) sub-buffer into an archive reference.
35    /// 
36    /// # Errors
37    /// 
38    /// Will fail if the buffer is not exactly 6 bytes in length.
39    pub fn from_buffer(id: u32, index_id: u8, buffer: &[u8]) -> crate::Result<Self> {
40        let (buffer, len) = be_u24(buffer)?;
41        let (_, sec) = be_u24(buffer)?;
42
43        Ok(Self {
44            id,
45            index_id,
46            sector: sec as usize,
47            length: len as usize,
48        })
49    }
50
51    /// Generate a data block iterator from this archive reference.
52    pub fn data_blocks(&self) -> DataBlocks {
53        let (header_len, data_len) = match SectorHeaderSize::from(self) {
54            SectorHeaderSize::Normal => (SECTOR_HEADER_SIZE, SECTOR_DATA_SIZE),
55            SectorHeaderSize::Expanded => (SECTOR_EXPANDED_HEADER_SIZE, SECTOR_EXPANDED_DATA_SIZE),
56        };
57
58        let n = self.length / data_len;
59        let rem = self.length % data_len;
60        let n = if rem > 0 { n + 1 } else { n };
61
62        DataBlocks {
63            count: n,
64            remainder: rem,
65            header_len,
66            data_len,
67        }
68    }
69}
70
71/// Iterator to walk the archive reference chain.
72/// 
73/// When reading an `Archive` from [`Dat2`](crate::Dat2) it needs to know
74/// where to read and what the total data length is.
75/// By calling [`ArchiveRef::data_blocks`](ArchiveRef::data_blocks) you get a
76/// easy iterable struct that does all of the calculations for you.
77pub struct DataBlocks {
78    count: usize,
79    remainder: usize,
80    header_len: usize,
81    data_len: usize,
82}
83
84impl Iterator for DataBlocks {
85    type Item = usize;
86
87    fn next(&mut self) -> Option<Self::Item> {
88        if self.count == 0 {
89            return None;
90        }
91
92        let n = if self.count == 1 && self.remainder != 0 {
93            self.remainder
94        } else {
95            self.data_len
96        };
97
98        self.count -= 1;
99        Some(self.header_len + n)
100    }
101}
102
103/// Metadata on every archive.
104/// 
105/// # Example
106/// 
107/// TODO This type needs refining so be prepared for breaking changes when using it.
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
110pub struct ArchiveMetadata {
111    pub id: u32,
112    pub name_hash: i32,
113    pub crc: u32,
114    pub hash: i32,
115    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
116    pub whirlpool: [u8; 64],
117    pub version: u32,
118    pub entry_count: usize,
119    pub valid_ids: Vec<u32>,
120}
121
122/// Holds an archive file id with its data.
123#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
124#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
125pub struct ArchiveFileData {
126    pub id: u32,
127    pub data: Vec<u8>,
128}
129
130/// Holds all of the archive files that belong to a single archive.
131#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
132#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
133pub struct ArchiveFileGroup(Vec<ArchiveFileData>);
134
135impl ArchiveFileGroup {
136    /// Format a raw buffer into a list of `ArchiveFileData`'s.
137    /// 
138    /// # Panics
139    /// 
140    /// Whenever the buffer has a wrong format no files can be constructed.
141    pub fn from_buffer(buffer: &[u8], entry_count: usize) -> Self {
142        let chunks = buffer[buffer.len() - 1] as usize;
143        let mut data = Vec::with_capacity(chunks);
144        let mut cached_chunks = Vec::with_capacity(chunks);
145        let mut read_ptr = buffer.len() - 1 - chunks * entry_count * 4;
146
147        for _ in 0..chunks {
148            let mut chunk_size = 0;
149
150            for entry_id in 0..entry_count {
151                let mut bytes = [0; 4];
152                bytes.copy_from_slice(&buffer[read_ptr..read_ptr + 4]);
153                let delta = i32::from_be_bytes(bytes);
154                read_ptr += 4;
155                chunk_size += delta;
156
157                cached_chunks.push((entry_id as u32, chunk_size as usize));
158            }
159        }
160        read_ptr = 0;
161        for (entry_id, chunk_size) in cached_chunks {
162            let buf = buffer[read_ptr..read_ptr + chunk_size].to_vec();
163
164            data.push(ArchiveFileData {
165                id: entry_id,
166                data: buf,
167            });
168            read_ptr += chunk_size;
169        }
170
171        Self(data)
172    }
173
174    #[inline]
175    pub fn iter(&self) -> Iter<'_, ArchiveFileData> {
176        self.0.iter()
177    }
178
179    #[inline]
180    pub fn iter_mut(&mut self) -> IterMut<'_, ArchiveFileData> {
181        self.0.iter_mut()
182    }
183}
184
185impl IntoIterator for ArchiveFileGroup {
186    type Item = ArchiveFileData;
187    type IntoIter = std::vec::IntoIter<ArchiveFileData>;
188
189    #[inline]
190    fn into_iter(self) -> Self::IntoIter {
191        self.0.into_iter()
192    }
193}
194
195impl<'a> IntoIterator for &'a ArchiveFileGroup {
196    type Item = &'a ArchiveFileData;
197    type IntoIter = Iter<'a, ArchiveFileData>;
198
199    #[inline]
200    fn into_iter(self) -> Self::IntoIter {
201        self.0.iter()
202    }
203}
204
205#[test]
206fn parse_archive() -> crate::Result<()> {
207    let buffer = &[0, 0, 77, 0, 1, 196];
208    let archive = ArchiveRef::from_buffer(10, 255, buffer)?;
209
210    assert_eq!(
211        archive,
212        ArchiveRef {
213            id: 10,
214            index_id: 255,
215            sector: 452,
216            length: 77
217        }
218    );
219
220    Ok(())
221}