Skip to content

Commit 77a7bd1

Browse files
committed
Ensure TakeSeek::seek uses correct stream end position
The purpose of `TakeSeek` is to be a binrw-compatible version of `std::io::Take`, and the purpose of `std::io::Take` is only to truncate the stream to a certain number of bytes, not to extend the stream if a limit beyond the length of the inner stream is given. Thus, `TakeSeek` also needs to pay attention to the true end of the inner stream and use that as the `SeekFrom::End(0)` position if it is less than the limit. Refs jam1garner#291.
1 parent 49e811a commit 77a7bd1

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

binrw/src/io/take_seek.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,18 @@ impl<T: Read> Read for TakeSeek<T> {
9191
impl<T: Seek> Seek for TakeSeek<T> {
9292
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
9393
let pos = match pos {
94-
SeekFrom::End(end) => match self.end.checked_add_signed(end) {
95-
Some(pos) => SeekFrom::Start(pos),
96-
None => {
97-
return Err(super::Error::new(
98-
super::ErrorKind::InvalidInput,
99-
"invalid seek to a negative or overflowing position",
100-
))
94+
SeekFrom::End(end) => {
95+
let inner_end = self.inner.seek(SeekFrom::End(0))?;
96+
match self.end.min(inner_end).checked_add_signed(end) {
97+
Some(pos) => SeekFrom::Start(pos),
98+
None => {
99+
return Err(super::Error::new(
100+
super::ErrorKind::InvalidInput,
101+
"invalid seek to a negative or overflowing position",
102+
))
103+
}
101104
}
102-
},
105+
}
103106
pos => pos,
104107
};
105108
self.pos = self.inner.seek(pos)?;

binrw/tests/io/take_seek.rs

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use binrw::io::{Cursor, Read, Seek, SeekFrom, TakeSeekExt};
44
#[test]
55
fn take_seek() {
66
let data = &mut Cursor::new(b"hello world".to_vec());
7+
let data_size = u64::try_from(data.get_ref().len()).unwrap();
78
let mut buf = [0; 5];
89
let mut take = data.take_seek(6);
910

@@ -99,6 +100,14 @@ fn take_seek() {
99100
take.seek(SeekFrom::End(-5))
100101
.expect_err("out-of-range `SeekFrom::End` backward seek should fail");
101102

103+
take.set_limit(data_size + 1);
104+
take.seek(SeekFrom::End(-1)).unwrap();
105+
assert_eq!(
106+
take.read(&mut buf).unwrap(),
107+
1,
108+
"`SeekFrom::End` did not bound to the true end of the stream"
109+
);
110+
102111
take.seek(SeekFrom::Start(0)).unwrap();
103112
take.set_limit(10);
104113
assert_eq!(

0 commit comments

Comments
 (0)