Coverage Report

Created: 2025-11-16 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/bzip2-0.4.4/src/mem.rs
Line
Count
Source
1
//! Raw low-level manipulations of bz streams.
2
3
use std::error;
4
use std::fmt;
5
use std::marker;
6
use std::mem;
7
use std::slice;
8
9
use libc::{c_int, c_uint};
10
11
use {ffi, Compression};
12
13
/// Representation of an in-memory compression stream.
14
///
15
/// An instance of `Compress` can be used to compress a stream of bz2 data.
16
pub struct Compress {
17
    inner: Stream<DirCompress>,
18
}
19
20
/// Representation of an in-memory decompression stream.
21
///
22
/// An instance of `Decompress` can be used to inflate a stream of bz2-encoded
23
/// data.
24
pub struct Decompress {
25
    inner: Stream<DirDecompress>,
26
}
27
28
struct Stream<D: Direction> {
29
    // libbz2 requires a stable address for this stream.
30
    raw: Box<ffi::bz_stream>,
31
    _marker: marker::PhantomData<D>,
32
}
33
34
unsafe impl<D: Direction> Send for Stream<D> {}
35
unsafe impl<D: Direction> Sync for Stream<D> {}
36
37
trait Direction {
38
    unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int;
39
}
40
41
enum DirCompress {}
42
enum DirDecompress {}
43
44
/// Possible actions to take on compression.
45
#[derive(PartialEq, Eq, Copy, Debug, Clone)]
46
pub enum Action {
47
    /// Normal compression.
48
    Run = ffi::BZ_RUN as isize,
49
    /// Request that the current compression block is terminate.
50
    Flush = ffi::BZ_FLUSH as isize,
51
    /// Request that the compression stream be finalized.
52
    Finish = ffi::BZ_FINISH as isize,
53
}
54
55
/// Result of compression or decompression
56
#[derive(PartialEq, Eq, Copy, Debug, Clone)]
57
pub enum Status {
58
    /// Decompression went fine, nothing much to report.
59
    Ok,
60
61
    /// The Flush action on a compression went ok.
62
    FlushOk,
63
64
    /// THe Run action on compression went ok.
65
    RunOk,
66
67
    /// The Finish action on compression went ok.
68
    FinishOk,
69
70
    /// The stream's end has been met, meaning that no more data can be input.
71
    StreamEnd,
72
73
    /// There was insufficient memory in the input or output buffer to complete
74
    /// the request, but otherwise everything went normally.
75
    MemNeeded,
76
}
77
78
/// Fatal errors encountered when compressing/decompressing bytes.
79
///
80
/// These errors indicate that progress could not be made in any form due to
81
/// input or output parameters.
82
#[derive(PartialEq, Eq, Copy, Debug, Clone)]
83
pub enum Error {
84
    /// The sequence of operations called on a decompression/compression stream
85
    /// were invalid. See methods for details.
86
    Sequence,
87
88
    /// The data being decompressed was invalid, or it was not a valid bz2
89
    /// stream.
90
    Data,
91
92
    /// The magic bz2 header wasn't present when decompressing.
93
    DataMagic,
94
95
    /// The parameters to this function were invalid.
96
    Param,
97
}
98
99
impl Compress {
100
    /// Creates a new stream prepared for compression.
101
    ///
102
    /// The `work_factor` parameter controls how the compression phase behaves
103
    /// when presented with worst case, highly repetitive, input data. If
104
    /// compression runs into difficulties caused by repetitive data, the
105
    /// library switches from the standard sorting algorithm to a fallback
106
    /// algorithm. The fallback is slower than the standard algorithm by perhaps
107
    /// a factor of three, but always behaves reasonably, no matter how bad the
108
    /// input.
109
    ///
110
    /// Lower values of `work_factor` reduce the amount of effort the standard
111
    /// algorithm will expend before resorting to the fallback. You should set
112
    /// this parameter carefully; too low, and many inputs will be handled by
113
    /// the fallback algorithm and so compress rather slowly, too high, and your
114
    /// average-to-worst case compression times can become very large. The
115
    /// default value of 30 gives reasonable behaviour over a wide range of
116
    /// circumstances.
117
    ///
118
    /// Allowable values range from 0 to 250 inclusive. 0 is a special case,
119
    /// equivalent to using the default value of 30.
120
3.59k
    pub fn new(lvl: Compression, work_factor: u32) -> Compress {
121
        unsafe {
122
3.59k
            let mut raw = Box::new(mem::zeroed());
123
3.59k
            assert_eq!(
124
3.59k
                ffi::BZ2_bzCompressInit(&mut *raw, lvl.level() as c_int, 0, work_factor as c_int),
125
                0
126
            );
127
3.59k
            Compress {
128
3.59k
                inner: Stream {
129
3.59k
                    raw: raw,
130
3.59k
                    _marker: marker::PhantomData,
131
3.59k
                },
132
3.59k
            }
133
        }
134
3.59k
    }
135
136
    /// Compress a block of input into a block of output.
137
    ///
138
    /// If anything other than BZ_OK is seen, `Err` is returned. The action
139
    /// given must be one of Run, Flush or Finish.
140
7.19k
    pub fn compress(
141
7.19k
        &mut self,
142
7.19k
        input: &[u8],
143
7.19k
        output: &mut [u8],
144
7.19k
        action: Action,
145
7.19k
    ) -> Result<Status, Error> {
146
        // apparently 0-length compression requests which don't actually make
147
        // any progress are returned as BZ_PARAM_ERROR, which we don't want, to
148
        // just translate to a success here.
149
7.19k
        if input.len() == 0 && action == Action::Run {
150
0
            return Ok(Status::RunOk);
151
7.19k
        }
152
7.19k
        self.inner.raw.next_in = input.as_ptr() as *mut _;
153
7.19k
        self.inner.raw.avail_in = input.len().min(c_uint::MAX as usize) as c_uint;
154
7.19k
        self.inner.raw.next_out = output.as_mut_ptr() as *mut _;
155
7.19k
        self.inner.raw.avail_out = output.len().min(c_uint::MAX as usize) as c_uint;
156
        unsafe {
157
7.19k
            match ffi::BZ2_bzCompress(&mut *self.inner.raw, action as c_int) {
158
3.59k
                ffi::BZ_RUN_OK => Ok(Status::RunOk),
159
0
                ffi::BZ_FLUSH_OK => Ok(Status::FlushOk),
160
0
                ffi::BZ_FINISH_OK => Ok(Status::FinishOk),
161
3.59k
                ffi::BZ_STREAM_END => Ok(Status::StreamEnd),
162
0
                ffi::BZ_SEQUENCE_ERROR => Err(Error::Sequence),
163
0
                c => panic!("unknown return status: {}", c),
164
            }
165
        }
166
7.19k
    }
167
168
    /// Compress a block of input into an output vector.
169
    ///
170
    /// This function will not grow `output`, but it will fill the space after
171
    /// its current length up to its capacity. The length of the vector will be
172
    /// adjusted appropriately.
173
7.19k
    pub fn compress_vec(
174
7.19k
        &mut self,
175
7.19k
        input: &[u8],
176
7.19k
        output: &mut Vec<u8>,
177
7.19k
        action: Action,
178
7.19k
    ) -> Result<Status, Error> {
179
7.19k
        let cap = output.capacity();
180
7.19k
        let len = output.len();
181
182
        unsafe {
183
7.19k
            let before = self.total_out();
184
7.19k
            let ret = {
185
7.19k
                let ptr = output.as_mut_ptr().offset(len as isize);
186
7.19k
                let out = slice::from_raw_parts_mut(ptr, cap - len);
187
7.19k
                self.compress(input, out, action)
188
            };
189
7.19k
            output.set_len((self.total_out() - before) as usize + len);
190
7.19k
            return ret;
191
        }
192
7.19k
    }
193
194
    /// Total number of bytes processed as input
195
7.19k
    pub fn total_in(&self) -> u64 {
196
7.19k
        self.inner.total_in()
197
7.19k
    }
198
199
    /// Total number of bytes processed as output
200
14.3k
    pub fn total_out(&self) -> u64 {
201
14.3k
        self.inner.total_out()
202
14.3k
    }
203
}
204
205
impl Decompress {
206
    /// Creates a new stream prepared for decompression.
207
    ///
208
    /// If `small` is true, then the library will use an alternative
209
    /// decompression algorithm which uses less memory but at the cost of
210
    /// decompressing more slowly (roughly speaking, half the speed, but the
211
    /// maximum memory requirement drops to around 2300k). See
212
1.67k
    pub fn new(small: bool) -> Decompress {
213
        unsafe {
214
1.67k
            let mut raw = Box::new(mem::zeroed());
215
1.67k
            assert_eq!(ffi::BZ2_bzDecompressInit(&mut *raw, 0, small as c_int), 0);
216
1.67k
            Decompress {
217
1.67k
                inner: Stream {
218
1.67k
                    raw: raw,
219
1.67k
                    _marker: marker::PhantomData,
220
1.67k
                },
221
1.67k
            }
222
        }
223
1.67k
    }
224
225
    /// Decompress a block of input into a block of output.
226
2.51k
    pub fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<Status, Error> {
227
2.51k
        self.inner.raw.next_in = input.as_ptr() as *mut _;
228
2.51k
        self.inner.raw.avail_in = input.len().min(c_uint::MAX as usize) as c_uint;
229
2.51k
        self.inner.raw.next_out = output.as_mut_ptr() as *mut _;
230
2.51k
        self.inner.raw.avail_out = output.len().min(c_uint::MAX as usize) as c_uint;
231
        unsafe {
232
2.51k
            match ffi::BZ2_bzDecompress(&mut *self.inner.raw) {
233
903
                ffi::BZ_OK => Ok(Status::Ok),
234
0
                ffi::BZ_MEM_ERROR => Ok(Status::MemNeeded),
235
1.03k
                ffi::BZ_STREAM_END => Ok(Status::StreamEnd),
236
0
                ffi::BZ_PARAM_ERROR => Err(Error::Param),
237
288
                ffi::BZ_DATA_ERROR => Err(Error::Data),
238
286
                ffi::BZ_DATA_ERROR_MAGIC => Err(Error::DataMagic),
239
0
                ffi::BZ_SEQUENCE_ERROR => Err(Error::Sequence),
240
0
                c => panic!("wut: {}", c),
241
            }
242
        }
243
2.51k
    }
244
245
    /// Decompress a block of input into an output vector.
246
    ///
247
    /// This function will not grow `output`, but it will fill the space after
248
    /// its current length up to its capacity. The length of the vector will be
249
    /// adjusted appropriately.
250
0
    pub fn decompress_vec(&mut self, input: &[u8], output: &mut Vec<u8>) -> Result<Status, Error> {
251
0
        let cap = output.capacity();
252
0
        let len = output.len();
253
254
        unsafe {
255
0
            let before = self.total_out();
256
0
            let ret = {
257
0
                let ptr = output.as_mut_ptr().offset(len as isize);
258
0
                let out = slice::from_raw_parts_mut(ptr, cap - len);
259
0
                self.decompress(input, out)
260
            };
261
0
            output.set_len((self.total_out() - before) as usize + len);
262
0
            return ret;
263
        }
264
0
    }
265
266
    /// Total number of bytes processed as input
267
5.02k
    pub fn total_in(&self) -> u64 {
268
5.02k
        self.inner.total_in()
269
5.02k
    }
270
271
    /// Total number of bytes processed as output
272
5.02k
    pub fn total_out(&self) -> u64 {
273
5.02k
        self.inner.total_out()
274
5.02k
    }
275
}
276
277
impl<D: Direction> Stream<D> {
278
12.2k
    fn total_in(&self) -> u64 {
279
12.2k
        (self.raw.total_in_lo32 as u64) | ((self.raw.total_in_hi32 as u64) << 32)
280
12.2k
    }
<bzip2::mem::Stream<bzip2::mem::DirCompress>>::total_in
Line
Count
Source
278
7.19k
    fn total_in(&self) -> u64 {
279
7.19k
        (self.raw.total_in_lo32 as u64) | ((self.raw.total_in_hi32 as u64) << 32)
280
7.19k
    }
<bzip2::mem::Stream<bzip2::mem::DirDecompress>>::total_in
Line
Count
Source
278
5.02k
    fn total_in(&self) -> u64 {
279
5.02k
        (self.raw.total_in_lo32 as u64) | ((self.raw.total_in_hi32 as u64) << 32)
280
5.02k
    }
281
282
19.4k
    fn total_out(&self) -> u64 {
283
19.4k
        (self.raw.total_out_lo32 as u64) | ((self.raw.total_out_hi32 as u64) << 32)
284
19.4k
    }
<bzip2::mem::Stream<bzip2::mem::DirCompress>>::total_out
Line
Count
Source
282
14.3k
    fn total_out(&self) -> u64 {
283
14.3k
        (self.raw.total_out_lo32 as u64) | ((self.raw.total_out_hi32 as u64) << 32)
284
14.3k
    }
<bzip2::mem::Stream<bzip2::mem::DirDecompress>>::total_out
Line
Count
Source
282
5.02k
    fn total_out(&self) -> u64 {
283
5.02k
        (self.raw.total_out_lo32 as u64) | ((self.raw.total_out_hi32 as u64) << 32)
284
5.02k
    }
285
}
286
287
impl error::Error for Error {}
288
289
impl fmt::Display for Error {
290
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291
0
        let description = match self {
292
0
            Error::Sequence => "bzip2: sequence of operations invalid",
293
0
            Error::Data => "bzip2: invalid data",
294
0
            Error::DataMagic => "bzip2: bz2 header missing",
295
0
            Error::Param => "bzip2: invalid parameters",
296
        };
297
0
        f.write_str(description)
298
0
    }
299
}
300
301
impl From<Error> for std::io::Error {
302
0
    fn from(data: Error) -> std::io::Error {
303
0
        std::io::Error::new(std::io::ErrorKind::Other, data)
304
0
    }
305
}
306
307
impl Direction for DirCompress {
308
3.59k
    unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int {
309
3.59k
        ffi::BZ2_bzCompressEnd(stream)
310
3.59k
    }
311
}
312
impl Direction for DirDecompress {
313
1.67k
    unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int {
314
1.67k
        ffi::BZ2_bzDecompressEnd(stream)
315
1.67k
    }
316
}
317
318
impl<D: Direction> Drop for Stream<D> {
319
5.27k
    fn drop(&mut self) {
320
5.27k
        unsafe {
321
5.27k
            let _ = D::destroy(&mut *self.raw);
322
5.27k
        }
323
5.27k
    }
<bzip2::mem::Stream<bzip2::mem::DirDecompress> as core::ops::drop::Drop>::drop
Line
Count
Source
319
1.67k
    fn drop(&mut self) {
320
1.67k
        unsafe {
321
1.67k
            let _ = D::destroy(&mut *self.raw);
322
1.67k
        }
323
1.67k
    }
Unexecuted instantiation: <bzip2::mem::Stream<_> as core::ops::drop::Drop>::drop
<bzip2::mem::Stream<bzip2::mem::DirCompress> as core::ops::drop::Drop>::drop
Line
Count
Source
319
3.59k
    fn drop(&mut self) {
320
3.59k
        unsafe {
321
3.59k
            let _ = D::destroy(&mut *self.raw);
322
3.59k
        }
323
3.59k
    }
324
}