1use crate::error::{LoftyError, Result};
4use crate::util::math::F80;
5
6use std::collections::VecDeque;
7use std::fs::File;
8use std::io::{Cursor, Read, Seek, SeekFrom, Write};
9
10pub(crate) trait SeekStreamLen: Seek {
12 fn stream_len_hack(&mut self) -> crate::error::Result<u64> {
13 use std::io::SeekFrom;
14
15 let current_pos = self.stream_position()?;
16 let len = self.seek(SeekFrom::End(0))?;
17
18 self.seek(SeekFrom::Start(current_pos))?;
19
20 Ok(len)
21 }
22}
23
24impl<T> SeekStreamLen for T where T: Seek {}
25
26pub trait Truncate {
45 type Error: Into<LoftyError>;
47
48 fn truncate(&mut self, new_len: u64) -> std::result::Result<(), Self::Error>;
54}
55
56impl Truncate for File {
57 type Error = std::io::Error;
58
59 fn truncate(&mut self, new_len: u64) -> std::result::Result<(), Self::Error> {
60 self.set_len(new_len)
61 }
62}
63
64impl Truncate for Vec<u8> {
65 type Error = std::convert::Infallible;
66
67 fn truncate(&mut self, new_len: u64) -> std::result::Result<(), Self::Error> {
68 self.truncate(new_len as usize);
69 Ok(())
70 }
71}
72
73impl Truncate for VecDeque<u8> {
74 type Error = std::convert::Infallible;
75
76 fn truncate(&mut self, new_len: u64) -> std::result::Result<(), Self::Error> {
77 self.truncate(new_len as usize);
78 Ok(())
79 }
80}
81
82impl<T> Truncate for Cursor<T>
83where
84 T: Truncate,
85{
86 type Error = <T as Truncate>::Error;
87
88 fn truncate(&mut self, new_len: u64) -> std::result::Result<(), Self::Error> {
89 self.get_mut().truncate(new_len)
90 }
91}
92
93impl<T> Truncate for Box<T>
94where
95 T: Truncate,
96{
97 type Error = <T as Truncate>::Error;
98
99 fn truncate(&mut self, new_len: u64) -> std::result::Result<(), Self::Error> {
100 self.as_mut().truncate(new_len)
101 }
102}
103
104impl<T> Truncate for &mut T
105where
106 T: Truncate,
107{
108 type Error = <T as Truncate>::Error;
109
110 fn truncate(&mut self, new_len: u64) -> std::result::Result<(), Self::Error> {
111 (**self).truncate(new_len)
112 }
113}
114
115pub trait Length {
132 type Error: Into<LoftyError>;
134
135 fn len(&self) -> std::result::Result<u64, Self::Error>;
141}
142
143impl Length for File {
144 type Error = std::io::Error;
145
146 fn len(&self) -> std::result::Result<u64, Self::Error> {
147 self.metadata().map(|m| m.len())
148 }
149}
150
151impl Length for Vec<u8> {
152 type Error = std::convert::Infallible;
153
154 fn len(&self) -> std::result::Result<u64, Self::Error> {
155 Ok(self.len() as u64)
156 }
157}
158
159impl Length for VecDeque<u8> {
160 type Error = std::convert::Infallible;
161
162 fn len(&self) -> std::result::Result<u64, Self::Error> {
163 Ok(self.len() as u64)
164 }
165}
166
167impl<T> Length for Cursor<T>
168where
169 T: Length,
170{
171 type Error = <T as Length>::Error;
172
173 fn len(&self) -> std::result::Result<u64, Self::Error> {
174 Length::len(self.get_ref())
175 }
176}
177
178impl<T> Length for Box<T>
179where
180 T: Length,
181{
182 type Error = <T as Length>::Error;
183
184 fn len(&self) -> std::result::Result<u64, Self::Error> {
185 Length::len(self.as_ref())
186 }
187}
188
189impl<T> Length for &T
190where
191 T: Length,
192{
193 type Error = <T as Length>::Error;
194
195 fn len(&self) -> std::result::Result<u64, Self::Error> {
196 Length::len(*self)
197 }
198}
199
200impl<T> Length for &mut T
201where
202 T: Length,
203{
204 type Error = <T as Length>::Error;
205
206 fn len(&self) -> std::result::Result<u64, Self::Error> {
207 Length::len(*self)
208 }
209}
210
211pub trait FileLike: Read + Write + Seek + Truncate + Length
219where
220 <Self as Truncate>::Error: Into<LoftyError>,
221 <Self as Length>::Error: Into<LoftyError>,
222{
223}
224
225impl<T> FileLike for T
226where
227 T: Read + Write + Seek + Truncate + Length,
228 <T as Truncate>::Error: Into<LoftyError>,
229 <T as Length>::Error: Into<LoftyError>,
230{
231}
232
233pub(crate) trait ReadExt: Read {
234 fn read_f80(&mut self) -> Result<F80>;
236}
237
238impl<R> ReadExt for R
239where
240 R: Read,
241{
242 fn read_f80(&mut self) -> Result<F80> {
243 let mut bytes = [0; 10];
244 self.read_exact(&mut bytes)?;
245
246 Ok(F80::from_be_bytes(bytes))
247 }
248}
249
250#[derive(Copy, Clone, Debug, Default, PartialEq)]
251pub(crate) enum RevSearchStart {
252 #[default]
254 FromEnd,
255 FromCurrent,
257}
258
259#[derive(Copy, Clone, Debug, Default, PartialEq)]
260pub(crate) enum RevSearchEnd {
261 StreamStart,
263 #[default]
267 FromCurrent,
268 Pos(u64),
270}
271
272pub(crate) struct RevPatternSearcher<'a, T> {
273 start: RevSearchStart,
274 end: RevSearchEnd,
275 buffer_size: u64,
276 pattern: &'a [u8],
277 reader: &'a mut T,
278}
279
280impl<T> RevPatternSearcher<'_, T>
281where
282 T: Read + Seek,
283{
284 pub(crate) fn buffer_size(&mut self, buffer_size: u64) -> &mut Self {
285 self.buffer_size = buffer_size;
286 self
287 }
288
289 pub(crate) fn start_pos(&mut self, start: RevSearchStart) -> &mut Self {
290 self.start = start;
291 self
292 }
293
294 pub(crate) fn end_pos(&mut self, end: RevSearchEnd) -> &mut Self {
295 self.end = end;
296 self
297 }
298
299 pub(crate) fn search(&mut self) -> std::io::Result<bool> {
304 if self.pattern.is_empty() {
305 return Ok(true);
306 }
307
308 let original_pos = self.reader.stream_position()?;
309 let pattern_len = self.pattern.len();
310
311 let start_pos = match self.start {
312 RevSearchStart::FromEnd => self.reader.seek(SeekFrom::End(0))?,
313 RevSearchStart::FromCurrent => original_pos,
314 };
315
316 let end_pos = match self.end {
317 RevSearchEnd::StreamStart => 0,
318 RevSearchEnd::FromCurrent => original_pos,
319 RevSearchEnd::Pos(p) => p,
320 };
321
322 if start_pos < end_pos
323 || (start_pos - end_pos) < pattern_len as u64
324 || self.buffer_size < pattern_len as u64
325 {
326 self.reader.seek(SeekFrom::Start(original_pos))?;
327 return Ok(false);
328 }
329
330 let overlap_step = self.buffer_size - ((pattern_len as u64) - 1);
333
334 let mut current_pos = start_pos;
335 let mut buf = vec![0; self.buffer_size as usize];
336
337 while current_pos > end_pos {
338 let window_size = current_pos - end_pos;
339 let read_size = std::cmp::min(self.buffer_size, window_size);
340
341 let read_start = current_pos - read_size;
342 self.reader.seek(SeekFrom::Start(read_start))?;
343
344 let window = &mut buf[..read_size as usize];
345 self.reader.read_exact(window)?;
346
347 if let Some(match_offset) = window
348 .windows(self.pattern.len())
349 .enumerate()
350 .rev()
351 .find_map(|(idx, window)| {
352 if window == self.pattern {
353 Some(idx)
354 } else {
355 None
356 }
357 }) {
358 self.reader
359 .seek(SeekFrom::Start(read_start + match_offset as u64))?;
360 return Ok(true);
361 }
362
363 current_pos -= std::cmp::min(read_size, overlap_step);
364 }
365
366 Ok(false)
367 }
368}
369
370pub(crate) trait ReadFindExt: Read + Seek + Sized {
371 fn rfind<'a>(&'a mut self, pattern: &'a [u8]) -> RevPatternSearcher<'a, Self> {
373 RevPatternSearcher {
374 start: RevSearchStart::default(),
375 end: RevSearchEnd::StreamStart,
376 buffer_size: 1024,
377 pattern,
378 reader: self,
379 }
380 }
381}
382
383impl<T> ReadFindExt for T where T: Read + Seek {}
384
385#[cfg(test)]
386mod tests {
387 use crate::config::{ParseOptions, WriteOptions};
388 use crate::file::AudioFile;
389 use crate::io::{ReadFindExt, RevSearchEnd, RevSearchStart};
390 use crate::mpeg::MpegFile;
391 use crate::tag::Accessor;
392
393 use std::io::{Cursor, Read, Seek, SeekFrom, Write};
394 use std::iter::repeat_n;
395 use std::ops::Neg;
396
397 const TEST_ASSET: &str = "tests/files/assets/minimal/full_test.mp3";
398
399 fn test_asset_contents() -> Vec<u8> {
400 std::fs::read(TEST_ASSET).unwrap()
401 }
402
403 fn file() -> MpegFile {
404 let file_contents = test_asset_contents();
405 let mut reader = Cursor::new(file_contents);
406 MpegFile::read_from(&mut reader, ParseOptions::new()).unwrap()
407 }
408
409 fn alter_tag(file: &mut MpegFile) {
410 let tag = file.id3v2_mut().unwrap();
411 tag.set_artist(String::from("Bar artist"));
412 }
413
414 fn revert_tag(file: &mut MpegFile) {
415 let tag = file.id3v2_mut().unwrap();
416 tag.set_artist(String::from("Foo artist"));
417 }
418
419 #[test_log::test]
420 fn io_save_to_file() {
421 let mut file = file();
423 alter_tag(&mut file);
424
425 let mut temp_file = tempfile::tempfile().unwrap();
426 let file_content = std::fs::read(TEST_ASSET).unwrap();
427 temp_file.write_all(&file_content).unwrap();
428 temp_file.rewind().unwrap();
429
430 file.save_to(&mut temp_file, WriteOptions::new().preferred_padding(0))
432 .expect("Failed to save to file");
433
434 temp_file.rewind().unwrap();
436 let mut file = MpegFile::read_from(&mut temp_file, ParseOptions::new()).unwrap();
437 revert_tag(&mut file);
438
439 temp_file.rewind().unwrap();
440 file.save_to(&mut temp_file, WriteOptions::new().preferred_padding(0))
441 .expect("Failed to save to file");
442
443 temp_file.rewind().unwrap();
445 let mut current_file_contents = Vec::new();
446 temp_file.read_to_end(&mut current_file_contents).unwrap();
447
448 assert_eq!(current_file_contents, test_asset_contents());
449 }
450
451 #[test_log::test]
452 fn io_save_to_vec() {
453 let mut file = file();
455 alter_tag(&mut file);
456
457 let file_content = std::fs::read(TEST_ASSET).unwrap();
458
459 let mut reader = Cursor::new(file_content);
460 file.save_to(&mut reader, WriteOptions::new().preferred_padding(0))
461 .expect("Failed to save to vec");
462
463 reader.rewind().unwrap();
464 let mut file = MpegFile::read_from(&mut reader, ParseOptions::new()).unwrap();
465 revert_tag(&mut file);
466
467 reader.rewind().unwrap();
468 file.save_to(&mut reader, WriteOptions::new().preferred_padding(0))
469 .expect("Failed to save to vec");
470
471 let current_file_contents = reader.into_inner();
472 assert_eq!(current_file_contents, test_asset_contents());
473 }
474
475 #[test_log::test]
476 fn io_save_using_references() {
477 struct File {
478 buf: Vec<u8>,
479 }
480
481 let mut f = File {
482 buf: std::fs::read(TEST_ASSET).unwrap(),
483 };
484
485 let mut file = file();
487 alter_tag(&mut file);
488
489 {
490 let mut reader = Cursor::new(&mut f.buf);
491 file.save_to(&mut reader, WriteOptions::new().preferred_padding(0))
492 .expect("Failed to save to vec");
493 }
494
495 {
496 let mut reader = Cursor::new(&f.buf[..]);
497 file = MpegFile::read_from(&mut reader, ParseOptions::new()).unwrap();
498 revert_tag(&mut file);
499 }
500
501 {
502 let mut reader = Cursor::new(&mut f.buf);
503 file.save_to(&mut reader, WriteOptions::new().preferred_padding(0))
504 .expect("Failed to save to vec");
505 }
506
507 let current_file_contents = f.buf;
508 assert_eq!(current_file_contents, test_asset_contents());
509 }
510
511 #[test_log::test]
512 fn rev_search() {
513 const PAT: &[u8] = b"PATTERN";
515 let mut data1 = PAT.to_vec();
516 data1.extend(repeat_n(0, 5000));
517
518 let mut stream1 = Cursor::new(data1);
519 assert!(stream1.rfind(PAT).search().unwrap());
520
521 let mut data2 = PAT.to_vec();
523 data2.extend(repeat_n(0, 1023));
524
525 let mut stream2 = Cursor::new(data2);
526 assert!(stream2.rfind(PAT).search().unwrap());
527
528 let mut data3 = PAT.to_vec();
530 let junk_len = 20;
531 data3.extend(repeat_n(0, junk_len));
532 data3.extend(PAT);
533 data3.extend(repeat_n(0, junk_len));
534 let last_occurence_offset = data3.len() - (junk_len + PAT.len());
535
536 let mut stream3 = Cursor::new(data3);
537 assert!(stream3.rfind(PAT).search().unwrap());
538 assert_eq!(stream3.position(), last_occurence_offset as u64);
539
540 let mut data4 = PAT.to_vec();
542 data4.extend(repeat_n(0, junk_len));
543 data4.extend(PAT);
544 data4.extend(repeat_n(0, junk_len));
545 data4.extend(PAT);
546
547 let middle_match_offset = PAT.len() + junk_len;
548
549 let mut stream4 = Cursor::new(data4);
550 stream4
552 .seek(SeekFrom::End(((PAT.len() - 3) as i64).neg()))
553 .unwrap();
554
555 assert!(
556 stream4
557 .rfind(PAT)
558 .start_pos(RevSearchStart::FromCurrent)
559 .end_pos(RevSearchEnd::StreamStart)
560 .search()
561 .unwrap()
562 );
563 assert_eq!(stream4.position(), middle_match_offset as u64);
564 }
565}