lofty/id3/v2/util/
synchsafe.rs1use crate::error::Result;
6
7use std::io::Read;
8
9pub struct UnsynchronizedStream<R> {
33 reader: R,
34 buf: [u8; 8 * 1024],
36 bytes_available: usize,
37 pos: usize,
38 encountered_ff: bool,
39}
40
41impl<R> UnsynchronizedStream<R> {
42 pub fn new(reader: R) -> Self {
54 Self {
55 reader,
56 buf: [0; 8 * 1024],
57 bytes_available: 0,
58 pos: 0,
59 encountered_ff: false,
60 }
61 }
62
63 pub fn into_inner(self) -> R {
79 self.reader
80 }
81
82 pub fn get_ref(&self) -> &R {
98 &self.reader
99 }
100}
101
102impl<R: Read> Read for UnsynchronizedStream<R> {
103 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
104 let dest_len = buf.len();
105 if dest_len == 0 {
106 return Ok(0);
107 }
108
109 let mut dest_pos = 0;
110 loop {
111 if dest_pos == dest_len {
112 break;
113 }
114
115 if self.pos >= self.bytes_available {
116 self.bytes_available = self.reader.read(&mut self.buf)?;
117 self.pos = 0;
118 }
119
120 if self.bytes_available == 0 {
122 break;
123 }
124
125 if self.encountered_ff {
126 self.encountered_ff = false;
127
128 if self.buf[self.pos] == 0 {
131 self.pos += 1;
132 continue;
133 }
134 }
135
136 let current_byte = self.buf[self.pos];
137 buf[dest_pos] = current_byte;
138 dest_pos += 1;
139 self.pos += 1;
140
141 if current_byte == 0xFF {
142 self.encountered_ff = true;
143 }
144 }
145
146 Ok(dest_pos)
147 }
148}
149
150pub trait SynchsafeInteger: Sized {
152 type WideningType;
154
155 fn synch(self) -> Result<Self>;
181
182 fn widening_synch(self) -> Self::WideningType;
202
203 fn unsynch(self) -> Self;
225}
226
227macro_rules! impl_synchsafe {
228 (
229 $ty:ty, $widening_ty:ty,
230 synch($n:ident) $body:block;
231 widening_synch($w:ident) $widening_body:block;
232 unsynch($u:ident) $unsynch_body:block
233 ) => {
234 #[allow(unused_parens)]
235 impl SynchsafeInteger for $ty {
236 type WideningType = $widening_ty;
237
238 fn synch(self) -> Result<Self> {
239 const MAXIMUM_INTEGER: $ty = {
240 let num_bytes = core::mem::size_of::<$ty>();
241 <$ty>::MAX >> num_bytes
243 };
244
245 if self > MAXIMUM_INTEGER {
246 crate::macros::err!(TooMuchData);
247 }
248
249 let $n = self;
250 Ok($body)
251 }
252
253 fn widening_synch(self) -> Self::WideningType {
254 let mut $w = <$widening_ty>::MIN;
255 let $n = self;
256 $widening_body;
257 $w
258 }
259
260 fn unsynch(self) -> Self {
261 let $u = self;
262 $unsynch_body
263 }
264 }
265 };
266}
267
268impl_synchsafe! {
269 u8, u16,
270 synch(n) {
271 (n & 0x7F)
272 };
273 widening_synch(w) {
274 w |= u16::from(n & 0x7F);
275 w |= u16::from(n & 0x80) << 1;
276 };
277 unsynch(u) {
278 (u & 0x7F)
279 }
280}
281
282impl_synchsafe! {
283 u16, u32,
284 synch(n) {
285 (n & 0x7F) |
286 ((n & (0x7F << 7)) << 1)
287 };
288 widening_synch(w) {
289 w |= u32::from(n & 0x7F);
290 w |= u32::from((n & (0x7F << 7)) << 1);
291 w |= u32::from(n & (0x03 << 14)) << 2;
292 };
293 unsynch(u) {
294 ((u & 0x7F00) >> 1) | (u & 0x7F)
295 }
296}
297
298impl_synchsafe! {
299 u32, u64,
300 synch(n) {
301 (n & 0x7F) |
302 ((n & (0x7F << 7)) << 1) |
303 ((n & (0x7F << 14)) << 2) |
304 ((n & (0x7F << 21)) << 3)
305 };
306 widening_synch(w) {
307 w |= u64::from(n & 0x7F);
308 w |= u64::from(n & (0x7F << 7)) << 1;
309 w |= u64::from(n & (0x7F << 14)) << 2;
310 w |= u64::from(n & (0x7F << 21)) << 3;
311 w |= u64::from(n & (0x0F << 28)) << 4;
312 };
313 unsynch(u) {
314 ((u & 0x7F00_0000) >> 3) | ((u & 0x7F_0000) >> 2) | ((u & 0x7F00) >> 1) | (u & 0x7F)
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 const UNSYNCHRONIZED_CONTENT: &[u8] =
321 &[0xFF, 0x00, 0x00, 0xFF, 0x12, 0xB0, 0x05, 0xFF, 0x00, 0x00];
322 const EXPECTED: &[u8] = &[0xFF, 0x00, 0xFF, 0x12, 0xB0, 0x05, 0xFF, 0x00];
323
324 #[test_log::test]
325 fn unsynchronized_stream() {
326 let reader = Cursor::new(UNSYNCHRONIZED_CONTENT);
327 let mut unsynchronized_reader = UnsynchronizedStream::new(reader);
328
329 let mut final_content = Vec::new();
330 unsynchronized_reader
331 .read_to_end(&mut final_content)
332 .unwrap();
333
334 assert_eq!(final_content, EXPECTED);
335 }
336
337 #[test_log::test]
338 fn unsynchronized_stream_large() {
339 let reader = Cursor::new(UNSYNCHRONIZED_CONTENT.repeat(1000));
341 let mut unsynchronized_reader = UnsynchronizedStream::new(reader);
342
343 let mut final_content = Vec::new();
344 unsynchronized_reader
345 .read_to_end(&mut final_content)
346 .unwrap();
347
348 assert_eq!(final_content, EXPECTED.repeat(1000));
350 }
351
352 #[test_log::test]
353 fn unsynchronized_stream_should_not_replace_unrelated() {
354 const ORIGINAL_CONTENT: &[u8] = &[0xFF, 0x1A, 0xFF, 0xC0, 0x10, 0x01];
355
356 let reader = Cursor::new(ORIGINAL_CONTENT);
357 let mut unsynchronized_reader = UnsynchronizedStream::new(reader);
358
359 let mut final_content = Vec::new();
360 unsynchronized_reader
361 .read_to_end(&mut final_content)
362 .unwrap();
363
364 assert_eq!(final_content, ORIGINAL_CONTENT);
365 }
366
367 use crate::id3::v2::util::synchsafe::{SynchsafeInteger, UnsynchronizedStream};
368 use std::io::{Cursor, Read};
369 macro_rules! synchsafe_integer_tests {
370 (
371 $($int:ty => {
372 synch: $original:literal, $new:literal;
373 unsynch: $original_unsync:literal, $new_unsynch:literal;
374 widen: $original_widen:literal, $new_widen:literal;
375 });+
376 ) => {
377 $(
378 paste::paste! {
379 #[test_log::test]
380 fn [<$int _synch>]() {
381 assert_eq!($original.synch().unwrap(), $new);
382 }
383
384 #[test_log::test]
385 fn [<$int _unsynch>]() {
386 assert_eq!($original_unsync.unsynch(), $new_unsynch);
387 }
388
389 #[test_log::test]
390 fn [<$int _widen>]() {
391 assert_eq!($original_widen.widening_synch(), $new_widen);
392 }
393 }
394 )+
395 };
396 }
397
398 synchsafe_integer_tests! {
399 u8 => {
400 synch: 0x7F_u8, 0x7F_u8;
401 unsynch: 0x7F_u8, 0x7F_u8;
402 widen: 0xFF_u8, 0x017F_u16;
403 };
404 u16 => {
405 synch: 0x3FFF_u16, 0x7F7F_u16;
406 unsynch: 0x7F7F_u16, 0x3FFF_u16;
407 widen: 0xFFFF_u16, 0x0003_7F7F_u32;
408 };
409 u32 => {
410 synch: 0xFFF_FFFF_u32, 0x7F7F_7F7F_u32;
411 unsynch: 0x7F7F_7F7F_u32, 0xFFF_FFFF_u32;
412 widen: 0xFFFF_FFFF_u32, 0x000F_7F7F_7F7F_u64;
413 }
414 }
415}