egdata_manifests_parser/types/
chunk.rs1use byteorder::{LittleEndian, ReadBytesExt};
2use hex;
3use log::debug;
4use serde::{Deserialize, Serialize};
5use std::io::{Read, Seek};
6use uuid::Uuid;
7
8use crate::error::Error;
9
10#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11pub struct Chunk {
12 pub guid: String,
13 pub hash: String, pub sha_hash: String,
15 pub group: u8,
16 pub window_size: u32,
17 pub file_size: String, }
19
20impl Chunk {
21 pub fn guid(&self) -> String {
22 self.guid.to_string()
23 }
24
25 pub fn hash(&self) -> String {
26 self.hash.to_string()
27 }
28
29 pub fn sha_hash(&self) -> String {
30 self.sha_hash.to_string()
31 }
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize, Default)]
35pub struct ChunkDataList {
36 pub data_size: u32,
37 pub data_version: u8,
38 pub count: u32,
39 pub elements: Vec<Chunk>,
40 #[serde(skip)]
41 pub chunk_lookup: std::collections::HashMap<String, u32>,
42}
43
44impl ChunkDataList {
45 pub fn read<R: Read + Seek>(mut rdr: R) -> Result<Self, Error> {
46 debug!(
47 "Reading chunk list at position: {} (0x{:x})",
48 rdr.stream_position()?,
49 rdr.stream_position()?
50 );
51
52 let data_size = rdr.read_u32::<LittleEndian>()?;
53 debug!(" Data size: {} (0x{:x})", data_size, data_size);
54
55 if data_size == 0 || data_size > 1024 * 1024 * 1024 {
56 return Err(Error::Invalid(format!(
58 "Invalid data size: {} (0x{:x}). Must be between 1 and 1GB",
59 data_size, data_size
60 )));
61 }
62
63 let data_version = rdr.read_u8()?;
64 debug!(" Data version: {} (0x{:x})", data_version, data_version);
65
66 let count = rdr.read_u32::<LittleEndian>()?;
67 debug!(" Count: {} (0x{:x})", count, count);
68
69 if count > 1_000_000 {
70 return Err(Error::Invalid(format!(
72 "Invalid count: {} (0x{:x}). Must be less than 1,000,000",
73 count, count
74 )));
75 }
76
77 let mut elements = Vec::with_capacity(count as usize);
78 let mut chunk_lookup = std::collections::HashMap::with_capacity(count as usize);
79
80 debug!("\nReading GUIDs...");
81 for i in 0..count {
82 let mut guid_bytes = [0u8; 16];
83 rdr.read_exact(&mut guid_bytes)?;
84 let guid = Uuid::from_bytes(guid_bytes);
85 let guid_str = guid.to_string();
86 chunk_lookup.insert(guid_str.clone(), i);
87 elements.push(Chunk {
88 guid: guid_str,
89 hash: String::new(),
90 sha_hash: String::new(),
91 group: 0,
92 window_size: 0,
93 file_size: String::new(),
94 });
95 }
96
97 debug!("\nReading hashes...");
98 for chunk in &mut elements {
99 let hash = rdr.read_u64::<LittleEndian>()?;
100 chunk.hash = format!("{:016x}", hash);
101 }
102
103 debug!("\nReading SHA hashes...");
104 for chunk in &mut elements {
105 let mut sha_hash = [0u8; 20];
106 rdr.read_exact(&mut sha_hash)?;
107 chunk.sha_hash = hex::encode(sha_hash);
108 }
109
110 debug!("\nReading groups...");
111 for chunk in &mut elements {
112 chunk.group = rdr.read_u8()?;
113 }
114
115 debug!("\nReading window sizes...");
116 for chunk in &mut elements {
117 chunk.window_size = rdr.read_u32::<LittleEndian>()?;
118 }
119
120 debug!("\nReading file sizes...");
121 for chunk in &mut elements {
122 let file_size = rdr.read_u64::<LittleEndian>()?;
123 chunk.file_size = file_size.to_string();
124 }
125
126 Ok(Self {
127 data_size,
128 data_version,
129 count,
130 elements,
131 chunk_lookup,
132 })
133 }
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize, Default)]
137pub struct ChunkPart {
138 pub data_size: u32,
139 pub parent_guid: String,
140 pub offset: u32,
141 pub size: u32,
142 #[serde(skip)]
143 pub chunk: Option<Chunk>, }
145
146impl ChunkPart {
147 pub fn read<R: Read + Seek>(
148 rdr: &mut R,
149 chunk_lookup: &std::collections::HashMap<String, u32>,
150 chunks: &[Chunk],
151 ) -> Result<Self, Error> {
152 let data_size = rdr.read_u32::<LittleEndian>()?;
153
154 let mut guid_bytes = [0u8; 16];
156 rdr.read_exact(&mut guid_bytes)?;
157 let parent_guid = Uuid::from_bytes(guid_bytes).to_string();
158
159 if !chunk_lookup.contains_key(&parent_guid) {
161 return Err(Error::Invalid(format!(
162 "Parent GUID {} not found in chunk lookup",
163 parent_guid
164 )));
165 }
166
167 let offset = rdr.read_u32::<LittleEndian>()?;
168 let size = rdr.read_u32::<LittleEndian>()?;
169
170 let chunk_idx = chunk_lookup[&parent_guid];
172 let chunk = chunks.get(chunk_idx as usize).cloned();
173
174 Ok(Self {
175 data_size,
176 parent_guid,
177 offset,
178 size,
179 chunk,
180 })
181 }
182}