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            return Ok(&self.buf[start..end]);
61        }
62
63        let mut j = start;
64        let mut i = start + pattern.len();
65
66        while i < end {
67            if &self.buf[j..i] == pattern {
68                break;
69            }
70            i += align;
71            j += align;
72        }
73
74        self.pos = cmp::min(i, self.buf.len());
75        Ok(&self.buf[start..self.pos])
76    }
77
78    /// Returns a reference to the next `len` bytes in the buffer and advances the stream.
79    pub fn read_buf_bytes_ref(&mut self, len: usize) -> io::Result<&'a [u8]> {
80        if self.pos + len > self.buf.len() {
81            return underrun_error();
82        }
83        self.pos += len;
84        Ok(&self.buf[self.pos - len..self.pos])
85    }
86
87    /// Returns a reference to the remaining bytes in the buffer and advances the stream to the end.
88    pub fn read_buf_bytes_available_ref(&mut self) -> &'a [u8] {
89        let pos = self.pos;
90        self.pos = self.buf.len();
91        &self.buf[pos..]
92    }
93}
94
95impl<'a> ReadBytes for BufReader<'a> {
96    #[inline(always)]
97    fn read_byte(&mut self) -> io::Result<u8> {
98        if self.buf.len() - self.pos < 1 {
99            return underrun_error();
100        }
101
102        self.pos += 1;
103        Ok(self.buf[self.pos - 1])
104    }
105
106    #[inline(always)]
107    fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> {
108        if self.buf.len() - self.pos < 2 {
109            return underrun_error();
110        }
111
112        let mut bytes: [u8; 2] = [0u8; 2];
113        bytes.copy_from_slice(&self.buf[self.pos..self.pos + 2]);
114        self.pos += 2;
115
116        Ok(bytes)
117    }
118
119    #[inline(always)]
120    fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> {
121        if self.buf.len() - self.pos < 3 {
122            return underrun_error();
123        }
124
125        let mut bytes: [u8; 3] = [0u8; 3];
126        bytes.copy_from_slice(&self.buf[self.pos..self.pos + 3]);
127        self.pos += 3;
128
129        Ok(bytes)
130    }
131
132    #[inline(always)]
133    fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> {
134        if self.buf.len() - self.pos < 4 {
135            return underrun_error();
136        }
137
138        let mut bytes: [u8; 4] = [0u8; 4];
139        bytes.copy_from_slice(&self.buf[self.pos..self.pos + 4]);
140        self.pos += 4;
141
142        Ok(bytes)
143    }
144
145    fn read_buf(&mut self, buf: &mut [u8]) -> io::Result<usize> {
146        let len = cmp::min(self.buf.len() - self.pos, buf.len());
147        buf[..len].copy_from_slice(&self.buf[self.pos..self.pos + len]);
148        self.pos += len;
149
150        Ok(len)
151    }
152
153    fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
154        let len = buf.len();
155
156        if self.buf.len() - self.pos < len {
157            return underrun_error();
158        }
159
160        buf.copy_from_slice(&self.buf[self.pos..self.pos + len]);
161        self.pos += len;
162
163        Ok(())
164    }
165
166    fn scan_bytes_aligned<'b>(
167        &mut self,
168        pattern: &[u8],
169        align: usize,
170        buf: &'b mut [u8],
171    ) -> io::Result<&'b mut [u8]> {
172        let scanned = self.scan_bytes_aligned_ref(pattern, align, buf.len())?;
173        buf[..scanned.len()].copy_from_slice(scanned);
174
175        Ok(&mut buf[..scanned.len()])
176    }
177
178    fn ignore_bytes(&mut self, count: u64) -> io::Result<()> {
179        if self.buf.len() - self.pos < count as usize {
180            return underrun_error();
181        }
182
183        self.pos += count as usize;
184        Ok(())
185    }
186
187    #[inline(always)]
188    fn pos(&self) -> u64 {
189        self.pos as u64
190    }
191}
192
193impl<'a> FiniteStream for BufReader<'a> {
194    #[inline(always)]
195    fn byte_len(&self) -> u64 {
196        self.buf.len() as u64
197    }
198
199    #[inline(always)]
200    fn bytes_read(&self) -> u64 {
201        self.pos as u64
202    }
203
204    #[inline(always)]
205    fn bytes_available(&self) -> u64 {
206        (self.buf.len() - self.pos) as u64
207    }
208}