egs_api/api/types/
chunk.rs1use flate2::read::ZlibDecoder;
2use log::{debug, error};
3use std::io::Read;
4
5#[derive(Default, Debug, Clone, PartialEq)]
7pub struct Chunk {
8 header_version: u32,
9 header_size: u32,
10 compressed_size: u32,
11 pub guid: String,
13 pub hash: u64,
15 compressed: bool,
16 pub sha_hash: Option<Vec<u8>>,
18 pub hash_type: Option<u8>,
20 pub uncompressed_size: Option<u32>,
22 pub data: Vec<u8>,
24}
25
26impl Chunk {
27 pub fn from_vec(buffer: Vec<u8>) -> Option<Chunk> {
29 let mut position: usize = 0;
30 let magic = crate::api::utils::read_le(&buffer, &mut position);
31 if magic != 2986228386 {
32 error!("No header magic");
33 return None;
34 }
35 let mut res = Chunk {
36 header_version: crate::api::utils::read_le(&buffer, &mut position),
37 header_size: crate::api::utils::read_le(&buffer, &mut position),
38 compressed_size: crate::api::utils::read_le(&buffer, &mut position),
39 guid: format!(
40 "{:08x}{:08x}{:08x}{:08x}",
41 crate::api::utils::read_le(&buffer, &mut position),
42 crate::api::utils::read_le(&buffer, &mut position),
43 crate::api::utils::read_le(&buffer, &mut position),
44 crate::api::utils::read_le(&buffer, &mut position)
45 ),
46 hash: crate::api::utils::read_le_64(&buffer, &mut position),
47 compressed: !matches!(buffer[position], 0),
48 sha_hash: None,
49 hash_type: None,
50 uncompressed_size: None,
51 data: vec![],
52 };
53 position += 1;
54
55 if res.header_version >= 2 {
56 position += 20;
57 res.sha_hash = Some(buffer[position - 20..position].into());
58 res.hash_type = Some(buffer[position]);
59 position += 1;
60 }
61 if res.header_version >= 3 {
62 res.uncompressed_size = Some(crate::api::utils::read_le(&buffer, &mut position));
63 }
64 debug!("Got chunk: {:?}", res);
65 res.data = if res.compressed {
66 let mut z = ZlibDecoder::new(&buffer[position..]);
67 let mut data: Vec<u8> = Vec::new();
68 if z.read_to_end(&mut data).is_err() {
69 error!("Failed to decompress chunk data");
70 return None;
71 }
72 data
73 } else {
74 buffer[position..].to_vec()
75 };
76 Some(res)
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use flate2::Compression;
84 use flate2::write::ZlibEncoder;
85 use std::io::Write;
86
87 #[test]
88 fn from_vec_wrong_magic() {
89 let buffer = vec![0u8; 45];
90 assert_eq!(Chunk::from_vec(buffer), None);
91 }
92
93 #[test]
94 fn from_vec_valid_uncompressed() {
95 let mut buffer: Vec<u8> = Vec::new();
96 buffer.extend_from_slice(&2986228386u32.to_le_bytes());
97 buffer.extend_from_slice(&1u32.to_le_bytes());
98 buffer.extend_from_slice(&40u32.to_le_bytes());
99 buffer.extend_from_slice(&5u32.to_le_bytes());
100 buffer.extend_from_slice(&0u32.to_le_bytes());
101 buffer.extend_from_slice(&0u32.to_le_bytes());
102 buffer.extend_from_slice(&0u32.to_le_bytes());
103 buffer.extend_from_slice(&0u32.to_le_bytes());
104 buffer.extend_from_slice(&42u64.to_le_bytes());
105 buffer.push(0u8);
106 buffer.extend_from_slice(&[1, 2, 3, 4, 5]);
107
108 let chunk = Chunk::from_vec(buffer).unwrap();
109 assert!(chunk.guid.starts_with("00000000"));
110 assert_eq!(chunk.hash, 42);
111 assert_eq!(chunk.data, vec![1, 2, 3, 4, 5]);
112 assert!(!chunk.compressed);
113 }
114
115 #[test]
116 fn from_vec_valid_compressed() {
117 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
118 encoder.write_all(&[10, 20, 30]).unwrap();
119 let compressed = encoder.finish().unwrap();
120
121 let mut buffer: Vec<u8> = Vec::new();
122 buffer.extend_from_slice(&2986228386u32.to_le_bytes());
123 buffer.extend_from_slice(&1u32.to_le_bytes());
124 buffer.extend_from_slice(&40u32.to_le_bytes());
125 buffer.extend_from_slice(&(compressed.len() as u32).to_le_bytes());
126 buffer.extend_from_slice(&0u32.to_le_bytes());
127 buffer.extend_from_slice(&0u32.to_le_bytes());
128 buffer.extend_from_slice(&0u32.to_le_bytes());
129 buffer.extend_from_slice(&0u32.to_le_bytes());
130 buffer.extend_from_slice(&42u64.to_le_bytes());
131 buffer.push(1u8);
132 buffer.extend_from_slice(&compressed);
133
134 let chunk = Chunk::from_vec(buffer).unwrap();
135 assert_eq!(chunk.data, vec![10, 20, 30]);
136 }
137
138 #[test]
139 fn from_vec_version2_has_sha() {
140 let mut buffer: Vec<u8> = Vec::new();
141 buffer.extend_from_slice(&2986228386u32.to_le_bytes());
142 buffer.extend_from_slice(&2u32.to_le_bytes());
143 buffer.extend_from_slice(&40u32.to_le_bytes());
144 buffer.extend_from_slice(&5u32.to_le_bytes());
145 buffer.extend_from_slice(&0u32.to_le_bytes());
146 buffer.extend_from_slice(&0u32.to_le_bytes());
147 buffer.extend_from_slice(&0u32.to_le_bytes());
148 buffer.extend_from_slice(&0u32.to_le_bytes());
149 buffer.extend_from_slice(&42u64.to_le_bytes());
150 buffer.push(0u8);
151 buffer.extend_from_slice(&[0xAB; 20]);
152 buffer.push(2u8);
153 buffer.extend_from_slice(&[1, 2, 3, 4, 5]);
154
155 let chunk = Chunk::from_vec(buffer).unwrap();
156 assert_eq!(chunk.sha_hash, Some(vec![0xAB; 20]));
157 assert_eq!(chunk.hash_type, Some(2));
158 }
159}