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    /// Returns the length in bytes of the stream.
136    ///
137    /// If the stream is a nil stream, this returns 0.
138    pub fn stream_size(&self) -> u64 {
139        match self {
140            Self::Msf(s) => s.len() as u64,
141            Self::Msfz(s) => s.stream_size(),
142        }
143    }
144}
145
146impl<'a, F: ReadAt> ReadAt for StreamReader<'a, F> {
147    fn read_at(&self, buf: &mut [u8], offset: u64) -> std::io::Result<usize> {
148        match self {
149            Self::Msf(s) => s.read_at(buf, offset),
150            Self::Msfz(s) => s.read_at(buf, offset),
151        }
152    }
153
154    fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> std::io::Result<()> {
155        match self {
156            Self::Msf(s) => s.read_exact_at(buf, offset),
157            Self::Msfz(s) => s.read_exact_at(buf, offset),
158        }
159    }
160}
161
162impl<'a, F: ReadAt> Read for StreamReader<'a, F> {
163    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
164        match self {
165            Self::Msf(s) => s.read(buf),
166            Self::Msfz(s) => s.read(buf),
167        }
168    }
169
170    fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
171        match self {
172            Self::Msf(s) => s.read_exact(buf),
173            Self::Msfz(s) => s.read_exact(buf),
174        }
175    }
176}
177
178impl<'a, F: ReadAt> Seek for StreamReader<'a, F> {
179    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
180        match self {
181            Self::Msf(s) => s.seek(pos),
182            Self::Msfz(s) => s.seek(pos),
183        }
184    }
185}