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#[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 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 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
71pub 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#[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#[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#[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 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}