ms_pdb/
container.rs

1//! Provides an abstraction over MSF and MSFZ files.
2
3use super::*;
4use std::io::{Read, Seek, SeekFrom};
5
6/// An abstraction over MSF and MSFZ files. Both types of files contain a set of streams.
7pub enum Container<F> {
8    /// The underlying file is an MSF file.
9    Msf(msf::Msf<F>),
10    /// The underlying file is an MSFZ file.
11    Msfz(msfz::Msfz<F>),
12}
13
14impl<F: ReadAt> Container<F> {
15    /// Provides direct access to the MSF layer. If this PDB file is using MSFZ instead of MSF,
16    /// then this function returns `None`.
17    pub fn msf(&self) -> Option<&msf::Msf<F>> {
18        match self {
19            Container::Msf(msf) => Some(msf),
20            _ => None,
21        }
22    }
23
24    /// Provides direct, mutable access to the MSF layer. If this PDB file is using MSFZ instead of
25    /// MSF, then this function returns `None`.
26    pub fn msf_mut(&mut self) -> Option<&mut msf::Msf<F>> {
27        match self {
28            Container::Msf(msf) => Some(msf),
29            _ => None,
30        }
31    }
32
33    /// Provides direct, mutable access to the MSF layer. If this PDB file is using MSFZ instead of
34    /// MSF, then this function returns `None`.
35    pub fn msf_mut_err(&mut self) -> anyhow::Result<&mut msf::Msf<F>> {
36        match self {
37            Container::Msf(msf) => Ok(msf),
38            _ => bail!("This operation requires a PDB/MSF file. It cannot use a PDB/MSFZ file."),
39        }
40    }
41
42    /// The total number of streams in this PDB.
43    ///
44    /// Some streams may be NIL.
45    pub fn num_streams(&self) -> u32 {
46        match self {
47            Self::Msf(m) => m.num_streams(),
48            Self::Msfz(m) => m.num_streams(),
49        }
50    }
51
52    /// Returns an object which can read from a given stream.  The returned object implements
53    /// the [`Read`], [`Seek`], and [`ReadAt`] traits.
54    pub fn get_stream_reader(&self, stream: u32) -> anyhow::Result<StreamReader<'_, F>> {
55        match self {
56            Self::Msf(m) => Ok(StreamReader::Msf(m.get_stream_reader(stream)?)),
57            Self::Msfz(m) => Ok(StreamReader::Msfz(m.get_stream_reader(stream)?)),
58        }
59    }
60
61    /// Reads an entire stream to a vector.
62    pub fn read_stream_to_vec(&self, stream: u32) -> anyhow::Result<Vec<u8>> {
63        match self {
64            Self::Msf(m) => m.read_stream_to_vec(stream),
65            Self::Msfz(m) => Ok(m.read_stream(stream)?.into_vec()),
66        }
67    }
68
69    /// Reads an entire stream to a vector.
70    ///
71    /// If the stream data is stored within a single compressed chunk, then this function returns
72    /// a reference to the decompressed stream data.
73    pub fn read_stream(&self, stream: u32) -> anyhow::Result<StreamData> {
74        match self {
75            Self::Msf(m) => Ok(StreamData::Box(m.read_stream_to_box(stream)?)),
76            Self::Msfz(m) => m.read_stream(stream),
77        }
78    }
79
80    /// Reads an entire stream into an existing vector.
81    pub fn read_stream_to_vec_mut(
82        &self,
83        stream: u32,
84        stream_data: &mut Vec<u8>,
85    ) -> anyhow::Result<()> {
86        match self {
87            Self::Msf(m) => m.read_stream_to_vec_mut(stream, stream_data),
88            Self::Msfz(m) => {
89                let src = m.read_stream(stream)?;
90                stream_data.clear();
91                stream_data.extend_from_slice(&src);
92                Ok(())
93            }
94        }
95    }
96
97    /// Gets the length of a given stream, in bytes.
98    ///
99    /// The `stream` value must be in a valid range of `0..num_streams()`.
100    ///
101    /// If `stream` is a NIL stream, this function returns 0.
102    pub fn stream_len(&self, stream: u32) -> u64 {
103        match self {
104            Self::Msf(m) => m.stream_size(stream) as u64,
105            Self::Msfz(m) => m.stream_size(stream).unwrap_or_default(),
106        }
107    }
108
109    /// Returns `true` if `stream` is a valid stream index and is not a nil stream.
110    pub fn is_stream_valid(&self, stream: u32) -> bool {
111        match self {
112            Self::Msf(m) => m.is_stream_valid(stream),
113            Self::Msfz(m) => m.is_stream_valid(stream),
114        }
115    }
116}
117
118/// Allows reading a stream using the [`Read`], [`Seek`], and [`ReadAt`] traits.
119pub enum StreamReader<'a, F> {
120    /// A stream stored within an MSF file.
121    Msf(msf::StreamReader<'a, F>),
122    /// A stream stored within an MSFZ file.
123    Msfz(msfz::StreamReader<'a, F>),
124}
125
126impl<'a, F: ReadAt> StreamReader<'a, F> {
127    /// Tests whether this stream is empty (zero-length)
128    pub fn is_empty(&self) -> bool {
129        match self {
130            Self::Msf(s) => s.is_empty(),
131            Self::Msfz(s) => s.is_empty(),
132        }
133    }
134}
135
136impl<'a, F: ReadAt> ReadAt for StreamReader<'a, F> {
137    fn read_at(&self, buf: &mut [u8], offset: u64) -> std::io::Result<usize> {
138        match self {
139            Self::Msf(s) => s.read_at(buf, offset),
140            Self::Msfz(s) => s.read_at(buf, offset),
141        }
142    }
143
144    fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> std::io::Result<()> {
145        match self {
146            Self::Msf(s) => s.read_exact_at(buf, offset),
147            Self::Msfz(s) => s.read_exact_at(buf, offset),
148        }
149    }
150}
151
152impl<'a, F: ReadAt> Read for StreamReader<'a, F> {
153    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
154        match self {
155            Self::Msf(s) => s.read(buf),
156            Self::Msfz(s) => s.read(buf),
157        }
158    }
159
160    fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
161        match self {
162            Self::Msf(s) => s.read_exact(buf),
163            Self::Msfz(s) => s.read_exact(buf),
164        }
165    }
166}
167
168impl<'a, F: ReadAt> Seek for StreamReader<'a, F> {
169    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
170        match self {
171            Self::Msf(s) => s.seek(pos),
172            Self::Msfz(s) => s.seek(pos),
173        }
174    }
175}