Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10/src/gz/read.rs
Line
Count
Source
1
use crate::io;
2
use crate::io::{Read, Write};
3
4
use super::bufread;
5
use super::{GzBuilder, GzHeader};
6
use crate::bufreader::BufReader;
7
use crate::Compression;
8
9
/// A gzip streaming encoder
10
///
11
/// This structure implements a [`Read`] interface. When read from, it reads
12
/// uncompressed data from the underlying [`Read`] and provides the compressed data.
13
///
14
/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
15
///
16
/// # Examples
17
///
18
/// ```
19
/// use std::io::prelude::*;
20
/// use std::io;
21
/// use flate2::Compression;
22
/// use flate2::read::GzEncoder;
23
///
24
/// // Return a vector containing the GZ compressed version of hello world
25
///
26
/// fn gzencode_hello_world() -> io::Result<Vec<u8>> {
27
///     let mut ret_vec = Vec::new();
28
///     let bytestring = b"hello world";
29
///     let mut gz = GzEncoder::new(&bytestring[..], Compression::fast());
30
///     gz.read_to_end(&mut ret_vec)?;
31
///     Ok(ret_vec)
32
/// }
33
/// ```
34
#[derive(Debug)]
35
pub struct GzEncoder<R> {
36
    inner: bufread::GzEncoder<BufReader<R>>,
37
}
38
39
0
pub fn gz_encoder<R: Read>(inner: bufread::GzEncoder<BufReader<R>>) -> GzEncoder<R> {
40
0
    GzEncoder { inner }
41
0
}
42
43
impl<R: Read> GzEncoder<R> {
44
    /// Creates a new encoder which will use the given compression level.
45
    ///
46
    /// The encoder is not configured specially for the emitted header. For
47
    /// header configuration, see the `GzBuilder` type.
48
    ///
49
    /// The data read from the stream `r` will be compressed and available
50
    /// through the returned reader.
51
0
    pub fn new(r: R, level: Compression) -> GzEncoder<R> {
52
0
        GzBuilder::new().read(r, level)
53
0
    }
54
}
55
56
impl<R> GzEncoder<R> {
57
    /// Acquires a reference to the underlying reader.
58
0
    pub fn get_ref(&self) -> &R {
59
0
        self.inner.get_ref().get_ref()
60
0
    }
61
62
    /// Acquires a mutable reference to the underlying reader.
63
    ///
64
    /// The underlying reader may be mutated as long as its unread input and
65
    /// current position are preserved for subsequent reads by this encoder.
66
    ///
67
    /// To process a new stream, wait for this encoder to reach EOF and create a
68
    /// new encoder; replacing the reader directly does not reset it.
69
0
    pub fn get_mut(&mut self) -> &mut R {
70
0
        self.inner.get_mut().get_mut()
71
0
    }
72
73
    /// Returns the underlying stream, consuming this encoder
74
0
    pub fn into_inner(self) -> R {
75
0
        self.inner.into_inner().into_inner()
76
0
    }
77
}
78
79
impl<R: Read> Read for GzEncoder<R> {
80
0
    fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
81
0
        self.inner.read(into)
82
0
    }
83
}
84
85
impl<R: Read + Write> Write for GzEncoder<R> {
86
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
87
0
        self.get_mut().write(buf)
88
0
    }
89
90
0
    fn flush(&mut self) -> io::Result<()> {
91
0
        self.get_mut().flush()
92
0
    }
93
}
94
95
/// A decoder for a single member of a [gzip file].
96
///
97
/// This structure implements a [`Read`] interface. When read from, it reads
98
/// compressed data from the underlying [`Read`] and provides the uncompressed data.
99
///
100
/// After reading a single member of the gzip data this reader will return
101
/// Ok(0) even if there are more bytes available in the underlying reader.
102
/// `GzDecoder` may have read additional bytes past the end of the gzip data.
103
/// If you need the following bytes, wrap the `Reader` in a `std::io::BufReader`
104
/// and use `bufread::GzDecoder` instead.
105
///
106
/// To handle gzip files that may have multiple members, see [`MultiGzDecoder`]
107
/// or read more
108
/// [in the introduction](../index.html#about-multi-member-gzip-files).
109
///
110
/// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5
111
///
112
/// # Examples
113
///
114
/// ```
115
/// use std::io::prelude::*;
116
/// use std::io;
117
/// # use flate2::Compression;
118
/// # use flate2::write::GzEncoder;
119
/// use flate2::read::GzDecoder;
120
///
121
/// # fn main() {
122
/// #    let mut e = GzEncoder::new(Vec::new(), Compression::default());
123
/// #    e.write_all(b"Hello World").unwrap();
124
/// #    let bytes = e.finish().unwrap();
125
/// #    println!("{}", decode_reader(bytes).unwrap());
126
/// # }
127
/// #
128
/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error
129
/// // Here &[u8] implements Read
130
///
131
/// fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
132
///    let mut gz = GzDecoder::new(&bytes[..]);
133
///    let mut s = String::new();
134
///    gz.read_to_string(&mut s)?;
135
///    Ok(s)
136
/// }
137
/// ```
138
#[derive(Debug)]
139
pub struct GzDecoder<R> {
140
    inner: bufread::GzDecoder<BufReader<R>>,
141
}
142
143
impl<R: Read> GzDecoder<R> {
144
    /// Creates a new decoder from the given reader, immediately parsing the
145
    /// gzip header.
146
0
    pub fn new(r: R) -> GzDecoder<R> {
147
0
        GzDecoder {
148
0
            inner: bufread::GzDecoder::new(BufReader::new(r)),
149
0
        }
150
0
    }
151
}
152
153
impl<R> GzDecoder<R> {
154
    /// Returns the header associated with this stream, if it was valid.
155
0
    pub fn header(&self) -> Option<&GzHeader> {
156
0
        self.inner.header()
157
0
    }
158
159
    /// Acquires a reference to the underlying reader.
160
    ///
161
    /// Note that the decoder may have read past the end of the gzip data.
162
    /// To prevent this use [`bufread::GzDecoder`] instead.
163
0
    pub fn get_ref(&self) -> &R {
164
0
        self.inner.get_ref().get_ref()
165
0
    }
166
167
    /// Acquires a mutable reference to the underlying stream.
168
    ///
169
    /// The underlying reader may be mutated as long as its unread input and
170
    /// current position are preserved for subsequent reads by this decoder.
171
    ///
172
    /// To process a new stream, wait for this decoder to reach EOF and use
173
    /// [`reset`](Self::reset); replacing the reader directly does not reset it.
174
    ///
175
    /// Note that the decoder may have read past the end of the gzip data.
176
    /// To prevent this use [`bufread::GzDecoder`] instead.
177
0
    pub fn get_mut(&mut self) -> &mut R {
178
0
        self.inner.get_mut().get_mut()
179
0
    }
180
181
    /// Consumes this decoder, returning the underlying reader.
182
    ///
183
    /// Note that the decoder may have read past the end of the gzip data.
184
    /// Subsequent reads will skip those bytes. To prevent this use
185
    /// [`bufread::GzDecoder`] instead.
186
0
    pub fn into_inner(self) -> R {
187
0
        self.inner.into_inner().into_inner()
188
0
    }
189
190
    /// Resets the state of this decoder entirely, swapping out the input
191
    /// stream for another.
192
    ///
193
    /// This will reset the internal state of this decoder and replace the
194
    /// input stream with the one provided, returning the previous input
195
    /// stream. Future data read from this decoder will be the decompressed
196
    /// version of `r`'s data.
197
    ///
198
    /// Note that there may be currently buffered data when this function is
199
    /// called, and in that case the buffered data is discarded.
200
0
    pub fn reset(&mut self, r: R) -> R {
201
0
        super::bufread::reset_decoder_data(&mut self.inner);
202
0
        self.inner.get_mut().reset(r)
203
0
    }
204
}
205
206
impl<R: Read> Read for GzDecoder<R> {
207
0
    fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
208
0
        self.inner.read(into)
209
0
    }
210
}
211
212
impl<R: Read + Write> Write for GzDecoder<R> {
213
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
214
0
        self.get_mut().write(buf)
215
0
    }
216
217
0
    fn flush(&mut self) -> io::Result<()> {
218
0
        self.get_mut().flush()
219
0
    }
220
}
221
222
/// A gzip streaming decoder that decodes a [gzip file] that may have multiple members.
223
///
224
/// This structure implements a [`Read`] interface. When read from, it reads
225
/// compressed data from the underlying [`Read`] and provides the uncompressed
226
/// data.
227
///
228
/// A gzip file consists of a series of *members* concatenated one after another.
229
/// MultiGzDecoder decodes all members of a file and returns Ok(0) once the
230
/// underlying reader does.
231
///
232
/// To handle members separately, see [GzDecoder] or read more
233
/// [in the introduction](../index.html#about-multi-member-gzip-files).
234
///
235
/// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5
236
///
237
/// # Examples
238
///
239
/// ```
240
/// use std::io::prelude::*;
241
/// use std::io;
242
/// # use flate2::Compression;
243
/// # use flate2::write::GzEncoder;
244
/// use flate2::read::MultiGzDecoder;
245
///
246
/// # fn main() {
247
/// #    let mut e = GzEncoder::new(Vec::new(), Compression::default());
248
/// #    e.write_all(b"Hello World").unwrap();
249
/// #    let bytes = e.finish().unwrap();
250
/// #    println!("{}", decode_reader(bytes).unwrap());
251
/// # }
252
/// #
253
/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error
254
/// // Here &[u8] implements Read
255
///
256
/// fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
257
///    let mut gz = MultiGzDecoder::new(&bytes[..]);
258
///    let mut s = String::new();
259
///    gz.read_to_string(&mut s)?;
260
///    Ok(s)
261
/// }
262
/// ```
263
#[derive(Debug)]
264
pub struct MultiGzDecoder<R> {
265
    inner: bufread::MultiGzDecoder<BufReader<R>>,
266
}
267
268
impl<R: Read> MultiGzDecoder<R> {
269
    /// Creates a new decoder from the given reader, immediately parsing the
270
    /// (first) gzip header. If the gzip stream contains multiple members all will
271
    /// be decoded.
272
0
    pub fn new(r: R) -> MultiGzDecoder<R> {
273
0
        MultiGzDecoder {
274
0
            inner: bufread::MultiGzDecoder::new(BufReader::new(r)),
275
0
        }
276
0
    }
277
}
278
279
impl<R> MultiGzDecoder<R> {
280
    /// Returns the current header associated with this stream, if it's valid.
281
0
    pub fn header(&self) -> Option<&GzHeader> {
282
0
        self.inner.header()
283
0
    }
284
285
    /// Acquires a reference to the underlying reader.
286
0
    pub fn get_ref(&self) -> &R {
287
0
        self.inner.get_ref().get_ref()
288
0
    }
289
290
    /// Acquires a mutable reference to the underlying stream.
291
    ///
292
    /// The underlying reader may be mutated as long as its unread input and
293
    /// current position are preserved for subsequent reads by this decoder.
294
    ///
295
    /// To process a new stream, wait for this decoder to reach EOF and create a
296
    /// new decoder; replacing the reader directly does not reset it.
297
0
    pub fn get_mut(&mut self) -> &mut R {
298
0
        self.inner.get_mut().get_mut()
299
0
    }
300
301
    /// Consumes this decoder, returning the underlying reader.
302
0
    pub fn into_inner(self) -> R {
303
0
        self.inner.into_inner().into_inner()
304
0
    }
305
}
306
307
impl<R: Read> Read for MultiGzDecoder<R> {
308
0
    fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
309
0
        self.inner.read(into)
310
0
    }
311
}
312
313
impl<R: Read + Write> Write for MultiGzDecoder<R> {
314
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
315
0
        self.get_mut().write(buf)
316
0
    }
317
318
0
    fn flush(&mut self) -> io::Result<()> {
319
0
        self.get_mut().flush()
320
0
    }
321
}
322
323
#[cfg(test)]
324
mod tests {
325
    use crate::io::{Cursor, ErrorKind, Read, Result, Write};
326
    use alloc::vec::Vec;
327
328
    use super::GzDecoder;
329
330
    //a cursor turning EOF into blocking errors
331
    #[derive(Debug)]
332
    pub struct BlockingCursor {
333
        pub cursor: Cursor<Vec<u8>>,
334
    }
335
336
    impl BlockingCursor {
337
        pub fn new() -> BlockingCursor {
338
            BlockingCursor {
339
                cursor: Cursor::new(Vec::new()),
340
            }
341
        }
342
343
        pub fn set_position(&mut self, pos: u64) {
344
            self.cursor.set_position(pos)
345
        }
346
    }
347
348
    impl Write for BlockingCursor {
349
        fn write(&mut self, buf: &[u8]) -> Result<usize> {
350
            self.cursor.write(buf)
351
        }
352
        fn flush(&mut self) -> Result<()> {
353
            self.cursor.flush()
354
        }
355
    }
356
357
    impl Read for BlockingCursor {
358
        fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
359
            //use the cursor, except it turns eof into blocking error
360
            let r = self.cursor.read(buf);
361
            match r {
362
                Err(ref err) => {
363
                    if err.kind() == ErrorKind::UnexpectedEof {
364
                        return Err(ErrorKind::WouldBlock.into());
365
                    }
366
                }
367
                Ok(0) => {
368
                    //regular EOF turned into blocking error
369
                    return Err(ErrorKind::WouldBlock.into());
370
                }
371
                Ok(_n) => {}
372
            }
373
            r
374
        }
375
    }
376
377
    #[test]
378
    fn blocked_partial_header_read() {
379
        // this is a reader which receives data afterwards
380
        let mut r = BlockingCursor::new();
381
        let data = vec![1, 2, 3];
382
383
        match r.write_all(&data) {
384
            Ok(()) => {}
385
            _ => {
386
                panic!("Unexpected result for write_all");
387
            }
388
        }
389
        r.set_position(0);
390
391
        // this is unused except for the buffering
392
        let mut decoder = GzDecoder::new(r);
393
        let mut out = Vec::with_capacity(7);
394
        match decoder.read(&mut out) {
395
            Err(e) => {
396
                assert_eq!(e.kind(), ErrorKind::WouldBlock);
397
            }
398
            _ => {
399
                panic!("Unexpected result for decoder.read");
400
            }
401
        }
402
    }
403
404
    fn compress_data(data: &[u8]) -> Vec<u8> {
405
        use crate::write::GzEncoder;
406
        use crate::Compression;
407
408
        let mut e = GzEncoder::new(Vec::new(), Compression::default());
409
        e.write_all(data).unwrap();
410
        e.finish().unwrap()
411
    }
412
413
    #[test]
414
    fn decode_with_reset() {
415
        let data1 = b"Hello World";
416
        let data2 = b"Goodbye World";
417
418
        let compressed1 = compress_data(data1);
419
        let compressed2 = compress_data(data2);
420
421
        let mut output = Vec::new();
422
        let mut decoder = GzDecoder::new(compressed1.as_slice());
423
        decoder.read_to_end(&mut output).unwrap();
424
        assert_eq!(output, data1);
425
426
        output.clear();
427
        decoder.reset(compressed2.as_slice());
428
        decoder.read_to_end(&mut output).unwrap();
429
        assert_eq!(output, data2);
430
    }
431
432
    #[test]
433
    fn decode_with_reset_after_corruption() {
434
        let valid_data = b"Hello World";
435
        let valid_compressed = compress_data(valid_data);
436
437
        // Create a corrupted payload (valid gzip header but corrupted body)
438
        let mut corrupted = valid_compressed.clone();
439
        assert!(corrupted.len() > 13);
440
        corrupted[12] ^= 0xFF;
441
        corrupted[13] ^= 0xFF;
442
443
        // Try to decode corrupted data
444
        let mut decoder = GzDecoder::new(Cursor::new(corrupted));
445
        let mut output = Vec::new();
446
        let _ = decoder.read_to_end(&mut output).unwrap_err();
447
448
        // Reset with valid payload and decode
449
        decoder.reset(Cursor::new(valid_compressed));
450
        output.clear();
451
        decoder.read_to_end(&mut output).unwrap();
452
        assert_eq!(output, valid_data);
453
    }
454
}