symphonia_core/io/
scoped_stream.rs

1// Symphonia
2// Copyright (c) 2019-2022 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8use std::cmp;
9use std::io;
10
11use super::{FiniteStream, ReadBytes, SeekBuffered};
12
13#[inline(always)]
14fn out_of_bounds_error<T>() -> io::Result<T> {
15    Err(io::Error::new(io::ErrorKind::UnexpectedEof, "out of bounds"))
16}
17
18/// A `ScopedStream` restricts the number of bytes that may be read to an upper limit.
19pub struct ScopedStream<B: ReadBytes> {
20    inner: B,
21    start: u64,
22    len: u64,
23    read: u64,
24}
25
26impl<B: ReadBytes> ScopedStream<B> {
27    /// Instantiates a new `ScopedStream` with an upper limit on the number of bytes that can be
28    /// read from the inner source.
29    pub fn new(inner: B, len: u64) -> Self {
30        ScopedStream { start: inner.pos(), inner, len, read: 0 }
31    }
32
33    /// Returns an immutable reference to the inner stream.
34    pub fn inner(&self) -> &B {
35        &self.inner
36    }
37
38    /// Returns a mutable reference to the inner stream.
39    pub fn inner_mut(&mut self) -> &mut B {
40        &mut self.inner
41    }
42
43    /// Ignores the remainder of the `ScopedStream`.
44    pub fn ignore(&mut self) -> io::Result<()> {
45        self.inner.ignore_bytes(self.len - self.read)
46    }
47
48    /// Convert the `ScopedStream` to the inner stream.
49    pub fn into_inner(self) -> B {
50        self.inner
51    }
52}
53
54impl<B: ReadBytes> FiniteStream for ScopedStream<B> {
55    /// Returns the length of the the `ScopedStream`.
56    fn byte_len(&self) -> u64 {
57        self.len
58    }
59
60    /// Returns the number of bytes read.
61    fn bytes_read(&self) -> u64 {
62        self.read
63    }
64
65    /// Returns the number of bytes available to read.
66    fn bytes_available(&self) -> u64 {
67        self.len - self.read
68    }
69}
70
71impl<B: ReadBytes> ReadBytes for ScopedStream<B> {
72    #[inline(always)]
73    fn read_byte(&mut self) -> io::Result<u8> {
74        if self.len - self.read < 1 {
75            return out_of_bounds_error();
76        }
77
78        self.read += 1;
79        self.inner.read_byte()
80    }
81
82    #[inline(always)]
83    fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> {
84        if self.len - self.read < 2 {
85            return out_of_bounds_error();
86        }
87
88        self.read += 2;
89        self.inner.read_double_bytes()
90    }
91
92    #[inline(always)]
93    fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> {
94        if self.len - self.read < 3 {
95            return out_of_bounds_error();
96        }
97
98        self.read += 3;
99        self.inner.read_triple_bytes()
100    }
101
102    #[inline(always)]
103    fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> {
104        if self.len - self.read < 4 {
105            return out_of_bounds_error();
106        }
107
108        self.read += 4;
109        self.inner.read_quad_bytes()
110    }
111
112    fn read_buf(&mut self, buf: &mut [u8]) -> io::Result<usize> {
113        // Limit read_buf() to the remainder of the scoped bytes if buf has a greater length.
114        let scoped_len = cmp::min(self.len - self.read, buf.len() as u64) as usize;
115        let result = self.inner.read_buf(&mut buf[0..scoped_len])?;
116        self.read += result as u64;
117        Ok(result)
118    }
119
120    fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
121        if self.len - self.read < buf.len() as u64 {
122            return out_of_bounds_error();
123        }
124
125        self.read += buf.len() as u64;
126        self.inner.read_buf_exact(buf)
127    }
128
129    #[inline(always)]
130    fn scan_bytes_aligned<'a>(
131        &mut self,
132        pattern: &[u8],
133        align: usize,
134        buf: &'a mut [u8],
135    ) -> io::Result<&'a mut [u8]> {
136        if self.len - self.read < buf.len() as u64 {
137            return out_of_bounds_error();
138        }
139
140        let result = self.inner.scan_bytes_aligned(pattern, align, buf)?;
141        self.read += result.len() as u64;
142        Ok(result)
143    }
144
145    #[inline(always)]
146    fn ignore_bytes(&mut self, count: u64) -> io::Result<()> {
147        if self.len - self.read < count {
148            return out_of_bounds_error();
149        }
150
151        self.read += count;
152        self.inner.ignore_bytes(count)
153    }
154
155    #[inline(always)]
156    fn pos(&self) -> u64 {
157        self.inner.pos()
158    }
159}
160
161impl<B: ReadBytes + SeekBuffered> SeekBuffered for ScopedStream<B> {
162    #[inline(always)]
163    fn ensure_seekback_buffer(&mut self, len: usize) {
164        self.inner.ensure_seekback_buffer(len)
165    }
166
167    #[inline(always)]
168    fn unread_buffer_len(&self) -> usize {
169        self.inner.unread_buffer_len().min((self.len - self.read) as usize)
170    }
171
172    #[inline(always)]
173    fn read_buffer_len(&self) -> usize {
174        self.inner.read_buffer_len().min(self.read as usize)
175    }
176
177    #[inline(always)]
178    fn seek_buffered(&mut self, pos: u64) -> u64 {
179        // Clamp the seekable position to within the bounds of the ScopedStream.
180        self.inner.seek_buffered(pos.clamp(self.start, self.start + self.len))
181    }
182
183    #[inline(always)]
184    fn seek_buffered_rel(&mut self, delta: isize) -> u64 {
185        // Clamp the delta value such that the absolute position after the buffered seek will be
186        // within the bounds of the ScopedStream.
187        let max_back = self.read.min(std::isize::MAX as u64) as isize;
188        let max_forward = (self.len - self.read).min(std::isize::MAX as u64) as isize;
189        self.inner.seek_buffered_rel(delta.clamp(-max_back, max_forward))
190    }
191}