Skip to content

Commit 0466a72

Browse files
author
Evgeny Khramtsov
committed
Improve EOF processing for potential re-reading
1 parent 4b22c17 commit 0466a72

File tree

2 files changed

+91
-18
lines changed

2 files changed

+91
-18
lines changed

src/reading.rs

+46-14
Original file line numberDiff line numberDiff line change
@@ -754,32 +754,63 @@ impl<T :io::Read + io::Seek> PacketReader<T> {
754754
///
755755
/// Ok(None) is returned if the physical stream has ended.
756756
pub fn read_packet(&mut self) -> Result<Option<Packet>, OggReadError> {
757+
self.do_read_packet(false)
758+
}
759+
760+
/// Reads a packet and returns it on success.
761+
///
762+
/// Unlike the `read_packet` function, this function returns an `Err(_)`
763+
/// if the physical stream has ended, with an error kind of
764+
/// [`UnexpectedEof`](std::io::ErrorKind::UnexpectedEof).
765+
///
766+
/// This function might be useful in the following scenarios:
767+
/// 1. When you expect a new packet to arrive.
768+
/// 2. When the underlying reader's buffer is incomplete, allowing you to add more data
769+
/// and re-read upon encountering `UnexpectedEof`.
770+
///
771+
/// Note: This function incurs negligible overhead by reading the current
772+
/// stream position before reading an Ogg page.
773+
pub fn read_packet_expected(&mut self) -> Result<Packet, OggReadError> {
774+
match tri!(self.do_read_packet(true)) {
775+
Some(p) => Ok(p),
776+
None => tri!(Err(Error::new(ErrorKind::UnexpectedEof,
777+
"Expected ogg packet but found end of physical stream"))),
778+
}
779+
}
780+
781+
fn do_read_packet(&mut self, restore_position: bool) -> Result<Option<Packet>, OggReadError> {
757782
// Read pages until we got a valid entire packet
758783
// (packets may span multiple pages, so reading one page
759784
// doesn't always suffice to give us a valid packet)
760785
loop {
761786
if let Some(pck) = self.base_pck_rdr.read_packet() {
762787
return Ok(Some(pck));
763788
}
764-
let page = tri!(self.read_ogg_page());
789+
let page = if restore_position {
790+
// Save the current position to rewind if EOF is reached.
791+
let pos = tri!(self.rdr.stream_position());
792+
tri!(match self.read_ogg_page() {
793+
Err(OggReadError::ReadError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
794+
// Rewind to the saved position to allow for potential re-reading.
795+
self.rdr.seek(SeekFrom::Start(pos))?;
796+
Err(OggReadError::ReadError(e))
797+
}
798+
Ok(None) => {
799+
// Rewind to the saved position to allow for potential re-reading.
800+
self.rdr.seek(SeekFrom::Start(pos))?;
801+
Ok(None)
802+
}
803+
ret => ret,
804+
})
805+
} else {
806+
tri!(self.read_ogg_page())
807+
};
765808
match page {
766809
Some(page) => tri!(self.base_pck_rdr.push_page(page)),
767810
None => return Ok(None),
768811
}
769812
}
770813
}
771-
/// Reads a packet, and returns it on success.
772-
///
773-
/// The difference to the `read_packet` function is that this function
774-
/// returns an Err(_) if the physical stream has ended.
775-
/// This function is useful if you expect a new packet to come.
776-
pub fn read_packet_expected(&mut self) -> Result<Packet, OggReadError> {
777-
match tri!(self.read_packet()) {
778-
Some(p) => Ok(p),
779-
None => tri!(Err(Error::new(ErrorKind::UnexpectedEof,
780-
"Expected ogg packet but found end of physical stream"))),
781-
}
782-
}
783814

784815
/// Reads until the new page header, and then returns the page header array.
785816
///
@@ -818,7 +849,8 @@ impl<T :io::Read + io::Seek> PacketReader<T> {
818849
let header_buf :[u8; 27] = match tri!(self.read_until_pg_header()) {
819850
Some(s) => s,
820851
None if self.read_some_pg => return Ok(None),
821-
None => return Err(OggReadError::NoCapturePatternFound)
852+
None => tri!(Err(Error::new(ErrorKind::UnexpectedEof,
853+
"Expected ogg packet but found end of physical stream"))),
822854
};
823855
let (mut pg_prs, page_segments) = tri!(PageParser::new(header_buf));
824856

src/test.rs

+45-4
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,8 @@ fn test_issue_14() {
542542
// data is treated as invalid.
543543
#[test]
544544
fn test_issue_7() {
545+
use std::io::ErrorKind::UnexpectedEof;
546+
545547
let mut c = Cursor::new(Vec::new());
546548
let test_arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
547549
let test_arr_2 = [2, 4, 8, 16, 32, 64, 128, 127, 126, 125, 124];
@@ -564,17 +566,56 @@ fn test_issue_7() {
564566
assert!(r.read_packet().unwrap().is_none());
565567
}
566568

567-
// Non-Ogg data should return an error.
569+
// Truncated data should return the UnexpectedEof error.
568570
let c = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
569571
{
570572
let mut r = PacketReader::new(c);
571-
assert!(matches!(r.read_packet(), Err(OggReadError::NoCapturePatternFound)));
573+
assert!(matches!(r.read_packet(),
574+
Err(OggReadError::ReadError(e)) if e.kind() == UnexpectedEof));
572575
}
573576

574-
// Empty data is considered non-Ogg data.
577+
// Empty data should return the UnexpectedEof error.
575578
let c = Cursor::new(&[]);
576579
{
577580
let mut r = PacketReader::new(c);
578-
assert!(matches!(r.read_packet(), Err(OggReadError::NoCapturePatternFound)));
581+
assert!(matches!(r.read_packet(),
582+
Err(OggReadError::ReadError(e)) if e.kind() == UnexpectedEof));
579583
}
580584
}
585+
586+
#[test]
587+
fn test_read_with_append() {
588+
use reading::PacketReader;
589+
use OggReadError;
590+
use std::io::ErrorKind::UnexpectedEof;
591+
592+
let first_chunk =
593+
[79, 103, 103, 83, 0, 2, 0, 0, 0,
594+
0, 0, 0, 0, 0, 14, 247, 95, 68, 0];
595+
let second_chunk =
596+
[0, 0, 0, 139, 130, 226, 240, 1, 30, 1, 118, 111, 114,
597+
98, 105, 115, 0, 0, 0, 0, 1, 128, 187, 0, 0, 0, 0, 0,
598+
0, 128, 56, 1, 0, 0, 0, 0, 0, 184, 1];
599+
600+
let cursor = Cursor::new(Vec::new());
601+
let mut packet_reader = PacketReader::new(cursor);
602+
603+
// Add the first chunk
604+
let cursor = packet_reader.get_mut();
605+
cursor.get_mut().extend(first_chunk);
606+
// Attempt to read an incomplete page
607+
assert!(matches!(packet_reader.read_packet_expected(),
608+
Err(OggReadError::ReadError(ref e)) if e.kind() == UnexpectedEof
609+
));
610+
611+
// Add the second chunk
612+
let cursor = packet_reader.get_mut();
613+
cursor.get_mut().extend(second_chunk);
614+
// Attempt to read a complete page
615+
let _pkt = packet_reader.read_packet_expected().unwrap();
616+
617+
// No data left in the buffer
618+
assert!(matches!(packet_reader.read_packet_expected(),
619+
Err(OggReadError::ReadError(ref e)) if e.kind() == UnexpectedEof
620+
));
621+
}

0 commit comments

Comments
 (0)