symphonia_core/io/
buf_reader.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};
12
13#[inline(always)]
14fn underrun_error<T>() -> io::Result<T> {
15    Err(io::Error::new(io::ErrorKind::UnexpectedEof, "buffer underrun"))
16}
17
18/// A `BufReader` reads bytes from a byte buffer.
19pub struct BufReader<'a> {
20    buf: &'a [u8],
21    pos: usize,
22}
23
24impl<'a> BufReader<'a> {
25    /// Instantiate a new `BufReader` with a given byte buffer.
26    pub fn new(buf: &'a [u8]) -> Self {
27        BufReader { buf, pos: 0 }
28    }
29
30    /// Scans up-to `scan_len` bytes from the stream until a byte pattern is matched. A reference to
31    /// scanned bytes including the matched pattern are returned. If `scan_len` bytes are scanned
32    /// without matching the pattern, a reference to the scanned bytes are also returned. Likewise,
33    /// if the underlying buffer is exhausted before matching the pattern, remainder of the buffer
34    /// is returned.
35    #[inline(always)]
36    pub fn scan_bytes_ref(&mut self, pattern: &[u8], scan_len: usize) -> io::Result<&'a [u8]> {
37        self.scan_bytes_aligned_ref(pattern, 1, scan_len)
38    }
39
40    /// Scans up-to `scan_len` bytes from the stream until a byte pattern is matched on the
41    /// specified byte alignment boundary. Operation is otherwise identical to `scan_bytes_ref`.
42    pub fn scan_bytes_aligned_ref(
43        &mut self,
44        pattern: &[u8],
45        align: usize,
46        scan_len: usize,
47    ) -> io::Result<&'a [u8]> {
48        // The pattern must be atleast one byte.
49        debug_assert!(!pattern.is_empty());
50
51        let start = self.pos;
52        let remaining = self.buf.len() - start;
53        let end = start + cmp::min(remaining, scan_len);
54
55        // If the pattern is longer than amount of bytes remaining, or the scan length is shorter
56        // than the pattern, then the pattern will never match. However, since unmatched patterns
57        // return the remainder of the buffer or scan_length bytes, which ever is shorter, we return
58        // that here.
59        if remaining < pattern.len() || scan_len < pattern.len() {
60            self.pos = end;
61            return Ok(&self.buf[start..end]);
62        }
63
64        let mut i = start;
65        let mut j = start + pattern.len();
66
67        while j < end {
68            if &self.buf[i..j] == pattern {
69                break;
70            }
71            j += align;
72            i += align;
73        }
74
75        self.pos = cmp::min(j, self.buf.len());
76        Ok(&self.buf[start..self.pos])
77    }
78
79    /// Returns a reference to the next `len` bytes in the buffer and advances the stream.
80    pub fn read_buf_bytes_ref(&mut self, len: usize) -> io::Result<&'a [u8]> {
81        if self.pos + len > self.buf.len() {
82            return underrun_error();
83        }
84        self.pos += len;
85        Ok(&self.buf[self.pos - len..self.pos])
86    }
87
88    /// Returns a reference to the remaining bytes in the buffer and advances the stream to the end.
89    pub fn read_buf_bytes_available_ref(&mut self) -> &'a [u8] {
90        let pos = self.pos;
91        self.pos = self.buf.len();
92        &self.buf[pos..]
93    }
94}
95
96impl ReadBytes for BufReader<'_> {
97    #[inline(always)]
98    fn read_byte(&mut self) -> io::Result<u8> {
99        if self.buf.len() - self.pos < 1 {
100            return underrun_error();
101        }
102
103        self.pos += 1;
104        Ok(self.buf[self.pos - 1])
105    }
106
107    #[inline(always)]
108    fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> {
109        if self.buf.len() - self.pos < 2 {
110            return underrun_error();
111        }
112
113        let mut bytes: [u8; 2] = [0u8; 2];
114        bytes.copy_from_slice(&self.buf[self.pos..self.pos + 2]);
115        self.pos += 2;
116
117        Ok(bytes)
118    }
119
120    #[inline(always)]
121    fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> {
122        if self.buf.len() - self.pos < 3 {
123            return underrun_error();
124        }
125
126        let mut bytes: [u8; 3] = [0u8; 3];
127        bytes.copy_from_slice(&self.buf[self.pos..self.pos + 3]);
128        self.pos += 3;
129
130        Ok(bytes)
131    }
132
133    #[inline(always)]
134    fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> {
135        if self.buf.len() - self.pos < 4 {
136            return underrun_error();
137        }
138
139        let mut bytes: [u8; 4] = [0u8; 4];
140        bytes.copy_from_slice(&self.buf[self.pos..self.pos + 4]);
141        self.pos += 4;
142
143        Ok(bytes)
144    }
145
146    fn read_buf(&mut self, buf: &mut [u8]) -> io::Result<usize> {
147        let len = cmp::min(self.buf.len() - self.pos, buf.len());
148        buf[..len].copy_from_slice(&self.buf[self.pos..self.pos + len]);
149        self.pos += len;
150
151        Ok(len)
152    }
153
154    fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
155        let len = buf.len();
156
157        if self.buf.len() - self.pos < len {
158            return underrun_error();
159        }
160
161        buf.copy_from_slice(&self.buf[self.pos..self.pos + len]);
162        self.pos += len;
163
164        Ok(())
165    }
166
167    fn scan_bytes_aligned<'b>(
168        &mut self,
169        pattern: &[u8],
170        align: usize,
171        buf: &'b mut [u8],
172    ) -> io::Result<&'b mut [u8]> {
173        let scanned = self.scan_bytes_aligned_ref(pattern, align, buf.len())?;
174        buf[..scanned.len()].copy_from_slice(scanned);
175
176        Ok(&mut buf[..scanned.len()])
177    }
178
179    fn ignore_bytes(&mut self, count: u64) -> io::Result<()> {
180        if self.buf.len() - self.pos < count as usize {
181            return underrun_error();
182        }
183
184        self.pos += count as usize;
185        Ok(())
186    }
187
188    #[inline(always)]
189    fn pos(&self) -> u64 {
190        self.pos as u64
191    }
192}
193
194impl FiniteStream for BufReader<'_> {
195    #[inline(always)]
196    fn byte_len(&self) -> u64 {
197        self.buf.len() as u64
198    }
199
200    #[inline(always)]
201    fn bytes_read(&self) -> u64 {
202        self.pos as u64
203    }
204
205    #[inline(always)]
206    fn bytes_available(&self) -> u64 {
207        (self.buf.len() - self.pos) as u64
208    }
209}