ryg_rans_rs_cli/container/
block.rs1use crate::container::codec;
4use crate::container::{
5 BLOCK_HEADER_SIZE, BLOCK_KIND_RANS, BLOCK_KIND_RAW, BLOCK_KIND_RLE, BLOCK_TAG,
6};
7use crate::error::{AppError, FormatError, IntegrityError};
8use sha2::{Digest, Sha256};
9
10#[derive(Debug, Clone)]
12pub struct Block {
13 pub block_index: u64,
14 pub block_kind: u8,
15 pub codec_id: u16,
16 pub scale_bits: u8,
17 pub state_count: u8,
18 pub uncompressed_length: u32,
19 pub payload: Vec<u8>,
20 pub model_data: Vec<u8>,
21 pub payload_sha256: [u8; 32],
22 pub decoded_sha256: [u8; 32],
23}
24
25impl Block {
26 pub fn new_rans(
28 block_index: u64,
29 codec_id: u16,
30 scale_bits: u8,
31 state_count: u8,
32 uncompressed_length: u32,
33 payload: Vec<u8>,
34 model_data: Vec<u8>,
35 ) -> Self {
36 let payload_sha256 = sha256(&payload);
37 let decoded_sha256 = [0u8; 32]; Self {
39 block_index,
40 block_kind: BLOCK_KIND_RANS,
41 codec_id,
42 scale_bits,
43 state_count,
44 uncompressed_length,
45 payload,
46 model_data,
47 payload_sha256,
48 decoded_sha256,
49 }
50 }
51
52 pub fn new_raw(block_index: u64, data: Vec<u8>) -> Self {
54 let payload_sha256 = sha256(&data);
55 let decoded_sha256 = payload_sha256; Self {
57 block_index,
58 block_kind: BLOCK_KIND_RAW,
59 codec_id: 0,
60 scale_bits: 0,
61 state_count: 0,
62 uncompressed_length: data.len() as u32,
63 payload: data,
64 model_data: Vec::new(),
65 payload_sha256,
66 decoded_sha256,
67 }
68 }
69
70 pub fn new_rle(block_index: u64, symbol: u8, count: u32) -> Self {
72 let payload = vec![symbol];
73 let payload_sha256 = sha256(&payload);
74 let decoded_data = vec![symbol; count as usize];
75 let decoded_sha256 = sha256(&decoded_data);
76 Self {
77 block_index,
78 block_kind: BLOCK_KIND_RLE,
79 codec_id: 0,
80 scale_bits: 0,
81 state_count: 0,
82 uncompressed_length: count,
83 payload,
84 model_data: Vec::new(),
85 payload_sha256,
86 decoded_sha256,
87 }
88 }
89
90 pub fn header_to_bytes(&self) -> Vec<u8> {
92 let mut buf = Vec::with_capacity(BLOCK_HEADER_SIZE);
93 buf.extend_from_slice(BLOCK_TAG);
94 buf.extend_from_slice(&(BLOCK_HEADER_SIZE as u16).to_le_bytes());
95 buf.push(1); buf.push(self.block_kind);
97 buf.extend_from_slice(&self.block_index.to_le_bytes());
98 buf.extend_from_slice(&self.codec_id.to_le_bytes());
99 buf.push(self.scale_bits);
100 buf.push(self.state_count);
101 buf.push(if self.model_data.is_empty() { 0 } else { 0 }); buf.push(0); buf.extend_from_slice(&[0u8; 2]); buf.extend_from_slice(&self.uncompressed_length.to_le_bytes());
105 buf.extend_from_slice(&(self.payload.len() as u32).to_le_bytes());
106 buf.extend_from_slice(&(self.model_data.len() as u32).to_le_bytes());
107 buf.extend_from_slice(&[0u8; 4]); buf.extend_from_slice(&self.payload_sha256);
109 buf.extend_from_slice(&self.decoded_sha256);
110 buf
111 }
112
113 pub fn parse_header(
115 bytes: &[u8],
116 expected_index: u64,
117 ) -> Result<(BlockHeaderInfo, usize), AppError> {
118 if bytes.len() < BLOCK_HEADER_SIZE {
119 return Err(AppError::Format(FormatError {
120 detail: "block header too short".into(),
121 block_index: Some(expected_index),
122 offset: Some(0),
123 }));
124 }
125
126 let tag = &bytes[0..4];
127 if tag != BLOCK_TAG {
128 return Err(AppError::Format(FormatError {
129 detail: format!("bad block tag: {:02x?}", tag),
130 block_index: Some(expected_index),
131 offset: Some(0),
132 }));
133 }
134
135 let _block_header_length = u16::from_le_bytes([bytes[4], bytes[5]]);
136 let block_version = bytes[6];
137 if block_version != 1 {
138 return Err(AppError::Format(FormatError {
139 detail: format!("unsupported block version: {}", block_version),
140 block_index: Some(expected_index),
141 offset: Some(6),
142 }));
143 }
144
145 let block_kind = bytes[7];
146 if block_kind > 2 {
147 return Err(AppError::Format(FormatError {
148 detail: format!("unknown block kind: {}", block_kind),
149 block_index: Some(expected_index),
150 offset: Some(7),
151 }));
152 }
153
154 let block_index = u64::from_le_bytes([
155 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
156 ]);
157 if block_index != expected_index {
158 return Err(AppError::Format(FormatError {
159 detail: format!("expected block {}, got {}", expected_index, block_index),
160 block_index: Some(expected_index),
161 offset: Some(8),
162 }));
163 }
164
165 let codec_id = u16::from_le_bytes([bytes[16], bytes[17]]);
166 if block_kind == BLOCK_KIND_RANS && !codec::is_supported(codec_id) {
167 return Err(AppError::Format(FormatError {
168 detail: format!("unsupported codec id: {}", codec_id),
169 block_index: Some(block_index),
170 offset: Some(16),
171 }));
172 }
173
174 let scale_bits = bytes[18];
175 let state_count = bytes[19];
176
177 if bytes[22] != 0 || bytes[23] != 0 {
179 return Err(AppError::Format(FormatError {
180 detail: "non-zero reserved bytes in block header".into(),
181 block_index: Some(block_index),
182 offset: Some(22),
183 }));
184 }
185
186 let uncompressed_length = u32::from_le_bytes([bytes[24], bytes[25], bytes[26], bytes[27]]);
187 let payload_length = u32::from_le_bytes([bytes[28], bytes[29], bytes[30], bytes[31]]);
188 let model_length = u32::from_le_bytes([bytes[32], bytes[33], bytes[34], bytes[35]]);
189
190 if bytes[36..40].iter().any(|&b| b != 0) {
192 return Err(AppError::Format(FormatError {
193 detail: "non-zero reserved2 bytes in block header".into(),
194 block_index: Some(block_index),
195 offset: Some(36),
196 }));
197 }
198
199 let mut payload_sha256 = [0u8; 32];
200 payload_sha256.copy_from_slice(&bytes[40..72]);
201 let mut decoded_sha256 = [0u8; 32];
202 decoded_sha256.copy_from_slice(&bytes[72..104]);
203
204 Ok((
205 BlockHeaderInfo {
206 block_index,
207 block_kind,
208 codec_id,
209 scale_bits,
210 state_count,
211 uncompressed_length,
212 payload_length,
213 model_length,
214 payload_sha256,
215 decoded_sha256,
216 },
217 BLOCK_HEADER_SIZE,
218 ))
219 }
220
221 pub fn to_bytes(&self) -> Vec<u8> {
223 let mut buf = self.header_to_bytes();
224 buf.extend_from_slice(&self.model_data);
225 buf.extend_from_slice(&self.payload);
226 buf
227 }
228}
229
230#[derive(Debug, Clone)]
232pub struct BlockHeaderInfo {
233 pub block_index: u64,
234 pub block_kind: u8,
235 pub codec_id: u16,
236 pub scale_bits: u8,
237 pub state_count: u8,
238 pub uncompressed_length: u32,
239 pub payload_length: u32,
240 pub model_length: u32,
241 pub payload_sha256: [u8; 32],
242 pub decoded_sha256: [u8; 32],
243}
244
245fn sha256(data: &[u8]) -> [u8; 32] {
247 let mut hasher = Sha256::new();
248 hasher.update(data);
249 let result = hasher.finalize();
250 let mut hash = [0u8; 32];
251 hash.copy_from_slice(&result);
252 hash
253}