1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use std::{
io,
collections::HashMap,
};
use nom::{
multi::{ many0, many_m_n },
combinator::cond,
bytes::complete::take,
number::complete::{
be_u8,
be_u16,
be_u32,
be_i16,
be_i32
},
};
use itertools::izip;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct Archive {
pub id: u32,
pub index_id: u8,
pub sector: u32,
pub length: usize
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct ArchiveData {
pub id: u16,
pub hash: i32,
pub crc: u32,
pub revision: u32,
pub entry_count: usize
}
#[inline]
pub fn parse_content(buffer: &[u8], entry_count: usize) -> io::Result<HashMap<u16, Vec<u8>>> {
let chunks = buffer[buffer.len() - 1] as usize;
let mut data = HashMap::new();
let mut cached_chunks = Vec::new();
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 u16, 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.insert(entry_id, buf);
read_ptr += chunk_size;
}
Ok(data)
}
#[inline]
pub fn parse_archive_data(buffer: &[u8]) -> crate::Result<Vec<ArchiveData>> {
let (buffer, protocol) = be_u8(buffer)?;
let (buffer, _) = cond(protocol >= 6, be_u32)(buffer)?;
let (buffer, identified) = parse_identified(buffer)?;
let (buffer, archive_count) = parse_usize_from_u16(buffer)?;
let (buffer, ids) = many_m_n(0, archive_count, be_i16)(buffer)?;
let (buffer, hashes) = parse_identifiers(buffer, identified, archive_count)?;
let (buffer, crcs) = many_m_n(0, archive_count, be_u32)(buffer)?;
let (buffer, revisions) = many_m_n(0, archive_count, be_u32)(buffer)?;
let (_, entry_counts) = many_m_n(0, archive_count, be_u16)(buffer)?;
let mut archives = Vec::with_capacity(archive_count);
let archive_data = izip!(&ids, &hashes, &crcs, &revisions, &entry_counts);
let mut last_archive_id = 0;
for (id, hash, crc, revision, entry_count) in archive_data {
last_archive_id += id;
archives.push(ArchiveData {
id: last_archive_id as u16,
hash: *hash,
crc: *crc,
revision: *revision,
entry_count: *entry_count as usize
});
}
Ok(archives)
}
fn parse_identified(buffer: &[u8]) -> crate::Result<(&[u8], bool)> {
let (buffer, identified) = be_u8(buffer)?;
Ok((buffer, (1 & identified) != 0))
}
fn parse_identifiers(buffer: &[u8], identified: bool, archive_count: usize) -> crate::Result<(&[u8], Vec<i32>)> {
let (buffer, taken) = cond(identified, take(archive_count * 4))(buffer)?;
let (_, mut identifiers) = many0(be_i32)(match taken {
Some(taken) => taken,
None => &[]
})?;
if identifiers.len() != archive_count {
identifiers = vec![0; archive_count];
}
Ok((buffer, identifiers))
}
fn parse_usize_from_u16(buffer: &[u8]) -> crate::Result<(&[u8], usize)> {
let (buffer, value) = be_u16(buffer)?;
Ok((buffer, value as usize))
}