1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use crate::{Head, StreamId};
use anyhow::Result;
use std::convert::TryInto;
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom};
use std::path::Path;
pub struct StreamReader {
file: File,
id: StreamId,
start: u64,
len: u64,
pos: u64,
}
impl StreamReader {
pub(crate) fn new(path: &Path, head: &Head, start: u64, len: u64) -> Result<Self> {
if start + len > head.len {
return Err(anyhow::anyhow!(
"trying to read after the end of the stream"
));
}
let mut file = File::open(path)?;
file.seek(SeekFrom::Start(start))?;
Ok(Self {
file,
id: head.id,
start,
len,
pos: 0,
})
}
pub fn id(&self) -> &StreamId {
&self.id
}
}
impl Read for StreamReader {
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
if self.pos >= self.len {
return Ok(0);
}
if buf.len() as u64 >= self.len - self.pos {
let (vbuf, _) = buf.split_at_mut((self.len - self.pos).try_into().unwrap());
buf = vbuf;
}
let n = self.file.read(buf)?;
self.pos += n as u64;
Ok(n)
}
}
impl Seek for StreamReader {
fn seek(&mut self, seek: SeekFrom) -> io::Result<u64> {
fn add_offset(position: i128, offset: i128) -> io::Result<u64> {
let sum = position + offset;
if sum < 0 {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"seek before beginning",
))
} else if sum > u64::max_value() as i128 {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"seek target overflowed u64",
))
} else {
Ok(sum as u64)
}
}
let pos = match seek {
SeekFrom::Start(start) => start,
SeekFrom::Current(current) => add_offset(self.pos as _, current as _)?,
SeekFrom::End(end) => add_offset(self.len as _, end as _)?,
};
let start = add_offset(self.start as _, pos as _)?;
self.file.seek(SeekFrom::Start(start))?;
self.pos = pos;
Ok(self.pos)
}
fn stream_position(&mut self) -> io::Result<u64> {
Ok(self.pos)
}
}