1use crate::{Error, base::VInt64, functional::Encode, io::blocking_impl::ReadFrom};
4
5pub enum Lacer {
8 Xiph,
18
19 FixedSize,
21 Ebml,
35}
36
37impl Lacer {
38 pub fn lace(&self, frames: &[&[u8]]) -> Vec<u8> {
40 if frames.is_empty() {
41 return vec![];
42 }
43 let num_frames = frames.len();
44 let mut output = vec![];
45 output.push((num_frames - 1) as u8); match self {
48 Lacer::Xiph => {
49 for frame in &frames[..num_frames - 1] {
50 let mut size = frame.len();
51 while size >= 0xFF {
52 output.push(0xFF);
53 size -= 0xFF;
54 }
55 output.push(size as u8);
56 }
57 for frame in frames {
58 output.extend_from_slice(frame);
59 }
60 output
61 }
62 Lacer::FixedSize => {
63 let frame_size = frames[0].len();
64 if let Some((idx, bad_frame)) = frames
65 .iter()
66 .enumerate()
67 .find(|(_, f)| f.len() != frame_size)
68 {
69 panic!(
70 "All frames must have the same size for FixedSize lacing: expected size {}, but frame at index {} has size {}",
71 frame_size,
72 idx,
73 bad_frame.len()
74 );
75 }
76 for frame in frames {
77 output.extend_from_slice(frame);
78 }
79 output
80 }
81 Lacer::Ebml => {
82 if num_frames == 1 {
83 output.extend_from_slice(frames[0]);
84 return output;
85 }
86 let sizes = frames.iter().map(|f| f.len() as u64).collect::<Vec<_>>();
87 let diff_sizes = std::iter::once(
89 VInt64::new(sizes[0]),
91 )
92 .chain(sizes.windows(2).map(|w| {
93 let diff = w[1] as i64 - w[0] as i64;
94
95 let n = if diff > -(2i64.pow(6) - 1) && diff < (2i64.pow(6)) {
97 1
98 } else if diff > -(2i64.pow(13) - 1) && diff < (2i64.pow(13)) {
99 2
100 } else if diff > -(2i64.pow(20) - 1) && diff < (2i64.pow(20)) {
101 3
102 } else if diff > -(2i64.pow(27) - 1) && diff < (2i64.pow(27)) {
103 4
104 } else if diff > -(2i64.pow(34) - 1) && diff < (2i64.pow(34)) {
105 5
106 } else if diff > -(2i64.pow(41) - 1) && diff < (2i64.pow(41)) {
107 6
108 } else if diff > -(2i64.pow(48) - 1) && diff < (2i64.pow(48)) {
109 7
110 } else {
111 panic!("Frame size diff too large for EBML lacing: diff = {}", diff);
112 };
113
114 let diff_unsigned = diff + (2i64.pow(7 * n as u32 - 1) - 1);
116 VInt64::new(diff_unsigned as u64)
117 }))
118 .take(num_frames - 1);
120
121 for size in diff_sizes {
122 size.encode(&mut output).unwrap();
123 }
124 for frame in frames {
125 output.extend_from_slice(frame);
126 }
127 output
128 }
129 }
130 }
131
132 pub fn delace<'a>(&self, data: &'a [u8]) -> crate::Result<Vec<&'a [u8]>> {
134 if data.is_empty() {
140 return Ok(vec![]);
141 }
142 let num_frames = data[0] as usize + 1;
143 if num_frames == 1 {
144 return Ok(vec![&data[1..]]);
145 }
146
147 match self {
148 Lacer::Xiph => {
149 let mut out = Vec::with_capacity(num_frames);
150
151 let data_start_pos = data
152 .iter()
153 .enumerate()
154 .skip(1)
155 .filter(|(_, b)| **b != 0xFF)
156 .nth(num_frames - 2)
157 .map(|(i, _)| i)
158 .ok_or(Error::MalformedLacingData)?
159 + 1;
160
161 let laced_data = data
162 .get(data_start_pos..)
163 .ok_or(Error::MalformedLacingData)?;
164
165 let mut start = 0;
166 for size in data[1..data_start_pos]
167 .split_inclusive(|b| *b != 0xFF)
168 .map(|chunk| chunk.iter().map(|b| *b as usize).sum::<usize>())
169 {
170 out.push(
171 laced_data
172 .get(start..start + size)
173 .ok_or(Error::MalformedLacingData)?,
174 );
175 start += size;
176 }
177 out.push(laced_data.get(start..).ok_or(Error::MalformedLacingData)?);
178 Ok(out)
179 }
180 Lacer::FixedSize => {
181 let data_len = data.len() - 1;
182
183 if !data_len.is_multiple_of(num_frames) {
185 return Err(Error::MalformedLacingData);
186 }
187
188 Ok(data[1..].chunks(data_len / num_frames).collect())
189 }
190 Lacer::Ebml => {
191 let mut data_buf = &data[1..];
192 let mut out_sizes = Vec::with_capacity(num_frames - 1);
193 let first_size = VInt64::read_from(&mut data_buf)?;
194 out_sizes.push(*first_size as usize);
195 for _ in 1..(num_frames - 1) {
196 let oct_size = data_buf
197 .first()
198 .ok_or(Error::MalformedLacingData)?
199 .leading_zeros()
200 + 1;
201 let current_encoded_vint = VInt64::read_from(&mut data_buf)?;
202 let diff = *current_encoded_vint as i64 - (2i64.pow(7 * oct_size - 1) - 1);
204 let new_size = out_sizes
205 .last()
206 .unwrap()
207 .checked_add_signed(diff as isize)
208 .ok_or(Error::MalformedLacingData)?;
209 out_sizes.push(new_size);
210 }
211
212 let mut out = Vec::with_capacity(num_frames);
213
214 let mut start = 0;
215 for size in out_sizes {
216 out.push(
217 data_buf
218 .get(start..start + size)
219 .ok_or(Error::MalformedLacingData)?,
220 );
221 start += size;
222 }
223 out.push(data_buf.get(start..).ok_or(Error::MalformedLacingData)?);
224 Ok(out)
225 }
226 }
227 }
228}
229
230#[cfg(test)]
231mod lacer_tests {
232 use super::*;
233 #[test]
234 fn test_xiph_lacing() {
235 let laced = Lacer::Xiph.lace(&[]);
237 assert_eq!(laced, vec![]);
238 let frames: Vec<_> = Lacer::Xiph.delace(&[]).unwrap();
239 assert_eq!(frames.len(), 0);
240
241 let len = vec![0x03, 0xFF, 0x00, 0xFF, 0x1, 0x1];
243 let frame0 = vec![2u8; 255];
244 let frame1 = vec![42u8; 256];
245 let frame2 = vec![38u8; 1];
246 let frame3 = vec![100u8; 1];
247
248 let laced = Lacer::Xiph.lace(&[&frame0, &frame1, &frame2, &frame3]);
249 let data = [len, frame0, frame1, frame2, frame3].concat();
250 assert_eq!(laced, data);
251
252 let frames: Vec<_> = Lacer::Xiph.delace(&data).unwrap();
253 assert_eq!(frames.len(), 4);
254 assert_eq!(frames[0], &[2u8; 255]);
255 assert_eq!(frames[1], &[42u8; 256]);
256 assert_eq!(frames[2], &[38u8; 1]);
257 assert_eq!(frames[3], &[100u8; 1]);
258
259 let len = vec![0x00];
261 let frame0 = vec![2u8; 255];
262
263 let laced = Lacer::Xiph.lace(&[&frame0]);
264 let data = [len, frame0].concat();
265 assert_eq!(laced, data);
266
267 let frames: Vec<_> = Lacer::Xiph.delace(&data).unwrap();
268 assert_eq!(frames.len(), 1);
269 assert_eq!(frames[0], &[2u8; 255]);
270
271 let len = vec![0x01, 0x20];
273 let frame0 = vec![2u8; 32];
274 let frame1 = vec![42u8; 256];
275
276 let laced = Lacer::Xiph.lace(&[&frame0, &frame1]);
277 let data = [len, frame0, frame1].concat();
278 assert_eq!(laced, data);
279
280 let frames: Vec<_> = Lacer::Xiph.delace(&data).unwrap();
281 assert_eq!(frames.len(), 2);
282 assert_eq!(frames[0], &[2u8; 32]);
283 assert_eq!(frames[1], &[42u8; 256]);
284
285 let len = vec![0x03, 0xFF, 0xFF, 0x5A, 0x3, 0xFF, 0xFF, 0xA];
287 assert_eq!(0xff + 0xff + 0x5A, 600);
288 assert_eq!(0xff + 0xff + 0xA, 520);
289 let frame0 = vec![2u8; 600];
290 let frame1 = vec![42u8; 3];
291 let frame2 = vec![38u8; 520];
292 let frame3 = vec![100u8; 1];
293
294 let laced = Lacer::Xiph.lace(&[&frame0, &frame1, &frame2, &frame3]);
295 let data = [len, frame0, frame1, frame2, frame3].concat();
296 assert_eq!(laced, data);
297
298 let frames: Vec<_> = Lacer::Xiph.delace(&data).unwrap();
299 assert_eq!(frames.len(), 4);
300 assert_eq!(frames[0], &[2u8; 600]);
301 assert_eq!(frames[1], &[42u8; 3]);
302 assert_eq!(frames[2], &[38u8; 520]);
303 assert_eq!(frames[3], &[100u8; 1]);
304 }
305
306 #[test]
307 fn test_ebml_lacing() {
308 let laced = Lacer::Ebml.lace(&[]);
310 assert_eq!(laced, vec![]);
311 let frames: Vec<_> = Lacer::Ebml.delace(&[]).unwrap();
312 assert_eq!(frames.len(), 0);
313
314 let len = vec![0x02, 0x43, 0x20, 0x5E, 0xD3];
326 let frame0 = vec![2u8; 800];
327 let frame1 = vec![42u8; 500];
328 let frame2 = vec![38u8; 1000];
329 let laced = Lacer::Ebml.lace(&[&frame0, &frame1, &frame2]);
330 let data = [len, frame0, frame1, frame2].concat();
331 assert_eq!(laced, data);
332
333 let frames: Vec<_> = Lacer::Ebml.delace(&data).unwrap();
334 assert_eq!(frames.len(), 3);
335 assert_eq!(frames[0], &[2u8; 800]);
336 assert_eq!(frames[1], &[42u8; 500]);
337 assert_eq!(frames[2], &[38u8; 1000]);
338
339 let len = vec![
342 0x06, 0x82, 0x73, 0x85, 0xAB, 0x4E, 0x1B, 0x5E, 0x83, 0x67, 0xBB,
343 ];
344 let frame0 = vec![2u8; 2];
345 let frame1 = vec![42u8; 5000];
346 let frame2 = vec![38u8; 4980];
347 let frame3 = vec![100u8; 400];
348 let frame4 = vec![7u8; 20];
349 let frame5 = vec![8u8; 2000];
350 let frame6 = vec![9u8; 300];
351 let laced = Lacer::Ebml.lace(&[
352 &frame0, &frame1, &frame2, &frame3, &frame4, &frame5, &frame6,
353 ]);
354 let data = [len, frame0, frame1, frame2, frame3, frame4, frame5, frame6].concat();
355 assert_eq!(laced, data);
356 let frames: Vec<_> = Lacer::Ebml.delace(&data).unwrap();
357 assert_eq!(frames.len(), 7);
358 assert_eq!(frames[0], &[2u8; 2]);
359 assert_eq!(frames[1], &[42u8; 5000]);
360 assert_eq!(frames[2], &[38u8; 4980]);
361 assert_eq!(frames[3], &[100u8; 400]);
362 assert_eq!(frames[4], &[7u8; 20]);
363 assert_eq!(frames[5], &[8u8; 2000]);
364 assert_eq!(frames[6], &[9u8; 300]);
365 }
366
367 #[test]
368 fn test_fixed_size_lacing() {
369 let laced = Lacer::FixedSize.lace(&[]);
371 assert_eq!(laced, vec![]);
372 let frames: Vec<_> = Lacer::FixedSize.delace(&[]).unwrap();
373 assert_eq!(frames.len(), 0);
374
375 let len = vec![0x02];
377 let frame0 = vec![2u8; 500];
378 let frame1 = vec![42u8; 500];
379 let frame2 = vec![38u8; 500];
380 let laced = Lacer::FixedSize.lace(&[&frame0, &frame1, &frame2]);
381 let data = [len, frame0, frame1, frame2].concat();
382 assert_eq!(laced, data);
383
384 let frames: Vec<_> = Lacer::FixedSize.delace(&data).unwrap();
385 assert_eq!(frames.len(), 3);
386 assert_eq!(frames[0], &[2u8; 500]);
387 assert_eq!(frames[1], &[42u8; 500]);
388 assert_eq!(frames[2], &[38u8; 500]);
389 }
390}