Coverage Report

Created: 2026-09-28 07:16

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/write.rs
Line
Count
Source
1
use crate::io;
2
use crate::io::{Read, Write};
3
use alloc::vec::Vec;
4
use core::cmp;
5
6
use super::{corrupt, GzBuilder, GzHeader, GzHeaderParser};
7
use crate::crc::{Crc, CrcWriter};
8
use crate::zio;
9
use crate::{Compress, Compression, Decompress, Status};
10
11
// Non-gzip writer paths flush through zio::Writer::dump, which converts
12
// Ok(0) on a non-empty buffer into WriteZero. Gzip writes its header and footer
13
// directly, so keep the same progress rule here.
14
0
fn write_nonzero<W: Write>(writer: &mut W, buf: &[u8]) -> io::Result<usize> {
15
0
    let n = writer.write(buf)?;
16
0
    if n == 0 && !buf.is_empty() {
17
0
        Err(io::ErrorKind::WriteZero.into())
18
    } else {
19
0
        Ok(n)
20
    }
21
0
}
22
23
/// A gzip streaming encoder
24
///
25
/// This structure exposes a [`Write`] interface that will emit compressed data
26
/// to the underlying writer `W`.
27
///
28
/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
29
///
30
/// # Examples
31
///
32
/// ```
33
/// use std::io::prelude::*;
34
/// use flate2::Compression;
35
/// use flate2::write::GzEncoder;
36
///
37
/// // Vec<u8> implements Write to print the compressed bytes of sample string
38
/// # fn main() {
39
///
40
/// let mut e = GzEncoder::new(Vec::new(), Compression::default());
41
/// e.write_all(b"Hello World").unwrap();
42
/// println!("{:?}", e.finish().unwrap());
43
/// # }
44
/// ```
45
#[derive(Debug)]
46
pub struct GzEncoder<W: Write> {
47
    inner: zio::Writer<W, Compress>,
48
    crc: Crc,
49
    crc_bytes_written: usize,
50
    header: Vec<u8>,
51
}
52
53
0
pub fn gz_encoder<W: Write>(header: Vec<u8>, w: W, lvl: Compression) -> GzEncoder<W> {
54
0
    GzEncoder {
55
0
        inner: zio::Writer::new(w, Compress::new(lvl, false)),
56
0
        crc: Crc::new(),
57
0
        header,
58
0
        crc_bytes_written: 0,
59
0
    }
60
0
}
61
62
impl<W: Write> GzEncoder<W> {
63
    /// Creates a new encoder which will use the given compression level.
64
    ///
65
    /// The encoder is not configured specially for the emitted header. For
66
    /// header configuration, see the `GzBuilder` type.
67
    ///
68
    /// The data written to the returned encoder will be compressed and then
69
    /// written to the stream `w`.
70
0
    pub fn new(w: W, level: Compression) -> GzEncoder<W> {
71
0
        GzBuilder::new().write(w, level)
72
0
    }
73
74
    /// Acquires a reference to the underlying writer.
75
0
    pub fn get_ref(&self) -> &W {
76
0
        self.inner.get_ref()
77
0
    }
78
79
    /// Acquires a mutable reference to the underlying writer.
80
    ///
81
    /// The underlying writer may be mutated or replaced as long as this
82
    /// preserves the bytes and ordering of the logical output stream.
83
    /// Concatenate output from each writer to reconstruct the complete stream.
84
    ///
85
    /// Replacing the writer does not require [`flush`](Write::flush). Call it
86
    /// first when all input accepted so far must be decodable without output
87
    /// from later writes. This inserts a sync-flush point and changes the output
88
    /// bitstream. This is useful before applying [`std::mem::take`] to
89
    /// [`get_mut`](Self::get_mut) when forwarding the stream incrementally.
90
    ///
91
    /// To start a new stream, call [`finish`](Self::finish) and create a new
92
    /// encoder; replacing the writer does not reset it.
93
0
    pub fn get_mut(&mut self) -> &mut W {
94
0
        self.inner.get_mut()
95
0
    }
96
97
    /// Attempt to finish this output stream, writing out final chunks of data.
98
    ///
99
    /// Note that this function can only be used once data has finished being
100
    /// written to the output stream. After this function is called then further
101
    /// calls to `write` may result in a panic.
102
    ///
103
    /// # Panics
104
    ///
105
    /// Attempts to write data to this stream may result in a panic after this
106
    /// function is called.
107
    ///
108
    /// # Errors
109
    ///
110
    /// This function will perform I/O to complete this stream, and any I/O
111
    /// errors which occur will be returned from this function.
112
0
    pub fn try_finish(&mut self) -> io::Result<()> {
113
0
        self.write_header()?;
114
0
        self.inner.finish()?;
115
116
0
        while self.crc_bytes_written < 8 {
117
0
            let (sum, amt) = (self.crc.sum(), self.crc.amount());
118
0
            let buf = [
119
0
                sum as u8,
120
0
                (sum >> 8) as u8,
121
0
                (sum >> 16) as u8,
122
0
                (sum >> 24) as u8,
123
0
                amt as u8,
124
0
                (amt >> 8) as u8,
125
0
                (amt >> 16) as u8,
126
0
                (amt >> 24) as u8,
127
0
            ];
128
0
            let inner = self.inner.get_mut();
129
0
            let n = write_nonzero(inner, &buf[self.crc_bytes_written..])?;
130
0
            self.crc_bytes_written += n;
131
        }
132
0
        Ok(())
133
0
    }
134
135
    /// Finish encoding this stream, returning the underlying writer once the
136
    /// encoding is done.
137
    ///
138
    /// Note that this function may not be suitable to call in a situation where
139
    /// the underlying stream is an asynchronous I/O stream. To finish a stream
140
    /// the `try_finish` (or `shutdown`) method should be used instead. To
141
    /// re-acquire ownership of a stream it is safe to call this method after
142
    /// `try_finish` or `shutdown` has returned `Ok`.
143
    ///
144
    /// # Errors
145
    ///
146
    /// This function will perform I/O to complete this stream, and any I/O
147
    /// errors which occur will be returned from this function.
148
0
    pub fn finish(mut self) -> io::Result<W> {
149
0
        self.try_finish()?;
150
0
        Ok(self.inner.take_inner())
151
0
    }
152
153
0
    fn write_header(&mut self) -> io::Result<()> {
154
0
        while !self.header.is_empty() {
155
0
            let n = write_nonzero(self.inner.get_mut(), &self.header)?;
156
0
            self.header.drain(..n);
157
        }
158
0
        Ok(())
159
0
    }
160
}
161
162
impl<W: Write> Write for GzEncoder<W> {
163
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
164
0
        assert_eq!(self.crc_bytes_written, 0);
165
0
        self.write_header()?;
166
0
        let n = self.inner.write(buf)?;
167
0
        self.crc.update(&buf[..n]);
168
0
        Ok(n)
169
0
    }
170
171
0
    fn flush(&mut self) -> io::Result<()> {
172
0
        assert_eq!(self.crc_bytes_written, 0);
173
0
        self.write_header()?;
174
0
        self.inner.flush()
175
0
    }
176
}
177
178
impl<R: Read + Write> Read for GzEncoder<R> {
179
0
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
180
0
        self.get_mut().read(buf)
181
0
    }
182
}
183
184
impl<W: Write> Drop for GzEncoder<W> {
185
0
    fn drop(&mut self) {
186
0
        if self.inner.is_present() {
187
0
            let _ = self.try_finish();
188
0
        }
189
0
    }
190
}
191
192
/// A decoder for a single member of a [gzip file].
193
///
194
/// This structure exposes a [`Write`] interface, receiving compressed data and
195
/// writing uncompressed data to the underlying writer.
196
///
197
/// After decoding a single member of the gzip data this writer will return the number of bytes up to
198
/// to the end of the gzip member and subsequent writes will return Ok(0) allowing the caller to
199
/// handle any data following the gzip member.
200
///
201
/// To handle gzip files that may have multiple members, see [`MultiGzDecoder`]
202
/// or read more
203
/// [in the introduction](../index.html#about-multi-member-gzip-files).
204
///
205
/// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5
206
/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
207
///
208
/// # Examples
209
///
210
/// ```
211
/// use std::io::prelude::*;
212
/// use std::io;
213
/// use flate2::Compression;
214
/// use flate2::write::{GzEncoder, GzDecoder};
215
///
216
/// # fn main() {
217
/// #    let mut e = GzEncoder::new(Vec::new(), Compression::default());
218
/// #    e.write(b"Hello World").unwrap();
219
/// #    let bytes = e.finish().unwrap();
220
/// #    assert_eq!("Hello World", decode_writer(bytes).unwrap());
221
/// # }
222
/// // Uncompresses a gzip encoded vector of bytes and returns a string or error
223
/// // Here Vec<u8> implements Write
224
/// fn decode_writer(bytes: Vec<u8>) -> io::Result<String> {
225
///    let mut writer = Vec::new();
226
///    let mut decoder = GzDecoder::new(writer);
227
///    decoder.write_all(&bytes[..])?;
228
///    writer = decoder.finish()?;
229
///    let return_string = String::from_utf8(writer).expect("String parsing error");
230
///    Ok(return_string)
231
/// }
232
/// ```
233
#[derive(Debug)]
234
pub struct GzDecoder<W: Write> {
235
    inner: zio::Writer<CrcWriter<W>, Decompress>,
236
    crc_bytes: Vec<u8>,
237
    header_parser: GzHeaderParser,
238
}
239
240
const CRC_BYTES_LEN: usize = 8;
241
242
impl<W: Write> GzDecoder<W> {
243
    /// Creates a new decoder which will write uncompressed data to the stream.
244
    ///
245
    /// When this encoder is dropped or unwrapped the final pieces of data will
246
    /// be flushed.
247
0
    pub fn new(w: W) -> GzDecoder<W> {
248
0
        GzDecoder {
249
0
            inner: zio::Writer::new(CrcWriter::new(w), Decompress::new(false)),
250
0
            crc_bytes: Vec::with_capacity(CRC_BYTES_LEN),
251
0
            header_parser: GzHeaderParser::new(),
252
0
        }
253
0
    }
254
255
    /// Returns the header associated with this stream.
256
0
    pub fn header(&self) -> Option<&GzHeader> {
257
0
        self.header_parser.header()
258
0
    }
259
260
    /// Acquires a reference to the underlying writer.
261
0
    pub fn get_ref(&self) -> &W {
262
0
        self.inner.get_ref().get_ref()
263
0
    }
264
265
    /// Acquires a mutable reference to the underlying writer.
266
    ///
267
    /// The underlying writer may be mutated or replaced as long as this
268
    /// preserves the bytes and ordering of the logical output stream.
269
    /// Concatenate output from each writer to reconstruct the complete stream.
270
    ///
271
    /// Replacing the writer does not require [`flush`](Write::flush). Call it
272
    /// first to write all decompressed output currently available to the
273
    /// current writer. This is useful before applying [`std::mem::take`] to
274
    /// [`get_mut`](Self::get_mut) when forwarding output incrementally.
275
    ///
276
    /// To start a new stream, call [`finish`](Self::finish) and create a new
277
    /// decoder; replacing the writer does not reset it.
278
0
    pub fn get_mut(&mut self) -> &mut W {
279
0
        self.inner.get_mut().get_mut()
280
0
    }
281
282
    /// Attempt to finish this output stream, writing out final chunks of data.
283
    ///
284
    /// Note that this function can only be used once data has finished being
285
    /// written to the output stream. After this function is called then further
286
    /// calls to `write` may result in a panic.
287
    ///
288
    /// # Panics
289
    ///
290
    /// Attempts to write data to this stream may result in a panic after this
291
    /// function is called.
292
    ///
293
    /// # Errors
294
    ///
295
    /// This function will perform I/O to finish the stream, returning any
296
    /// errors which happen.
297
0
    pub fn try_finish(&mut self) -> io::Result<()> {
298
0
        self.finish_and_check_crc()?;
299
0
        Ok(())
300
0
    }
301
302
    /// Consumes this decoder, flushing the output stream.
303
    ///
304
    /// This will flush the underlying data stream and then return the contained
305
    /// writer if the flush succeeded.
306
    ///
307
    /// Note that this function may not be suitable to call in a situation where
308
    /// the underlying stream is an asynchronous I/O stream. To finish a stream
309
    /// the `try_finish` (or `shutdown`) method should be used instead. To
310
    /// re-acquire ownership of a stream it is safe to call this method after
311
    /// `try_finish` or `shutdown` has returned `Ok`.
312
    ///
313
    /// # Errors
314
    ///
315
    /// This function will perform I/O to complete this stream, and any I/O
316
    /// errors which occur will be returned from this function.
317
0
    pub fn finish(mut self) -> io::Result<W> {
318
0
        self.finish_and_check_crc()?;
319
0
        Ok(self.inner.take_inner().into_inner())
320
0
    }
321
322
0
    fn finish_and_check_crc(&mut self) -> io::Result<()> {
323
0
        self.inner.finish()?;
324
325
0
        if self.crc_bytes.len() != 8 {
326
0
            return Err(corrupt());
327
0
        }
328
329
0
        let crc = (self.crc_bytes[0] as u32)
330
0
            | ((self.crc_bytes[1] as u32) << 8)
331
0
            | ((self.crc_bytes[2] as u32) << 16)
332
0
            | ((self.crc_bytes[3] as u32) << 24);
333
0
        let amt = (self.crc_bytes[4] as u32)
334
0
            | ((self.crc_bytes[5] as u32) << 8)
335
0
            | ((self.crc_bytes[6] as u32) << 16)
336
0
            | ((self.crc_bytes[7] as u32) << 24);
337
0
        if crc != self.inner.get_ref().crc().sum() {
338
0
            return Err(corrupt());
339
0
        }
340
0
        if amt != self.inner.get_ref().crc().amount() {
341
0
            return Err(corrupt());
342
0
        }
343
0
        Ok(())
344
0
    }
345
}
346
347
impl<W: Write> Write for GzDecoder<W> {
348
0
    fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
349
0
        let buflen = buf.len();
350
0
        if self.header().is_none() {
351
0
            match self.header_parser.parse(&mut buf) {
352
0
                Err(err) => {
353
0
                    if err.kind() == io::ErrorKind::UnexpectedEof {
354
                        // all data read but header still not complete
355
0
                        Ok(buflen)
356
                    } else {
357
0
                        Err(err)
358
                    }
359
                }
360
                Ok(_) => {
361
0
                    debug_assert!(self.header().is_some());
362
                    // buf now contains the unread part of the original buf
363
0
                    let n = buflen - buf.len();
364
0
                    Ok(n)
365
                }
366
            }
367
        } else {
368
0
            let (n, status) = self.inner.write_with_status(buf)?;
369
370
0
            if status == Status::StreamEnd && n < buf.len() && self.crc_bytes.len() < 8 {
371
0
                let remaining = buf.len() - n;
372
0
                let crc_bytes = cmp::min(remaining, CRC_BYTES_LEN - self.crc_bytes.len());
373
0
                self.crc_bytes.extend(&buf[n..n + crc_bytes]);
374
0
                return Ok(n + crc_bytes);
375
0
            }
376
0
            Ok(n)
377
        }
378
0
    }
379
380
0
    fn flush(&mut self) -> io::Result<()> {
381
0
        self.inner.flush()
382
0
    }
383
}
384
385
impl<W: Read + Write> Read for GzDecoder<W> {
386
0
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
387
0
        self.inner.get_mut().get_mut().read(buf)
388
0
    }
389
}
390
391
/// A gzip streaming decoder that decodes a [gzip file] with multiple members.
392
///
393
/// This structure exposes a [`Write`] interface that will consume compressed data and
394
/// write uncompressed data to the underlying writer.
395
///
396
/// A gzip file consists of a series of *members* concatenated one after another.
397
/// `MultiGzDecoder` decodes all members of a file and writes them to the
398
/// underlying writer one after another.
399
///
400
/// To handle members separately, see [GzDecoder] or read more
401
/// [in the introduction](../index.html#about-multi-member-gzip-files).
402
///
403
/// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5
404
#[derive(Debug)]
405
pub struct MultiGzDecoder<W: Write> {
406
    inner: GzDecoder<W>,
407
}
408
409
impl<W: Write> MultiGzDecoder<W> {
410
    /// Creates a new decoder which will write uncompressed data to the stream.
411
    /// If the gzip stream contains multiple members all will be decoded.
412
0
    pub fn new(w: W) -> MultiGzDecoder<W> {
413
0
        MultiGzDecoder {
414
0
            inner: GzDecoder::new(w),
415
0
        }
416
0
    }
417
418
    /// Returns the header associated with the current member.
419
0
    pub fn header(&self) -> Option<&GzHeader> {
420
0
        self.inner.header()
421
0
    }
422
423
    /// Acquires a reference to the underlying writer.
424
0
    pub fn get_ref(&self) -> &W {
425
0
        self.inner.get_ref()
426
0
    }
427
428
    /// Acquires a mutable reference to the underlying writer.
429
    ///
430
    /// The underlying writer may be mutated or replaced as long as this
431
    /// preserves the bytes and ordering of the logical output stream.
432
    /// Concatenate output from each writer to reconstruct the complete stream.
433
    ///
434
    /// Replacing the writer does not require [`flush`](Write::flush). Call it
435
    /// first to write all decompressed output currently available to the
436
    /// current writer. This is useful before applying [`std::mem::take`] to
437
    /// [`get_mut`](Self::get_mut) when forwarding output incrementally.
438
    ///
439
    /// To start a new stream, call [`finish`](Self::finish) and create a new
440
    /// decoder; replacing the writer does not reset it.
441
0
    pub fn get_mut(&mut self) -> &mut W {
442
0
        self.inner.get_mut()
443
0
    }
444
445
    /// Attempt to finish this output stream, writing out final chunks of data.
446
    ///
447
    /// Note that this function can only be used once data has finished being
448
    /// written to the output stream. After this function is called then further
449
    /// calls to `write` may result in a panic.
450
    ///
451
    /// # Panics
452
    ///
453
    /// Attempts to write data to this stream may result in a panic after this
454
    /// function is called.
455
    ///
456
    /// # Errors
457
    ///
458
    /// This function will perform I/O to finish the stream, returning any
459
    /// errors which happen.
460
0
    pub fn try_finish(&mut self) -> io::Result<()> {
461
0
        self.inner.try_finish()
462
0
    }
463
464
    /// Consumes this decoder, flushing the output stream.
465
    ///
466
    /// This will flush the underlying data stream and then return the contained
467
    /// writer if the flush succeeded.
468
    ///
469
    /// Note that this function may not be suitable to call in a situation where
470
    /// the underlying stream is an asynchronous I/O stream. To finish a stream
471
    /// the `try_finish` (or `shutdown`) method should be used instead. To
472
    /// re-acquire ownership of a stream it is safe to call this method after
473
    /// `try_finish` or `shutdown` has returned `Ok`.
474
    ///
475
    /// # Errors
476
    ///
477
    /// This function will perform I/O to complete this stream, and any I/O
478
    /// errors which occur will be returned from this function.
479
0
    pub fn finish(self) -> io::Result<W> {
480
0
        self.inner.finish()
481
0
    }
482
}
483
484
impl<W: Write> Write for MultiGzDecoder<W> {
485
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
486
0
        if buf.is_empty() {
487
0
            Ok(0)
488
        } else {
489
0
            match self.inner.write(buf) {
490
                Ok(0) => {
491
                    // When the GzDecoder indicates that it has finished
492
                    // create a new GzDecoder to handle additional data.
493
0
                    self.inner.try_finish()?;
494
0
                    let w = self.inner.inner.take_inner().into_inner();
495
0
                    self.inner = GzDecoder::new(w);
496
0
                    self.inner.write(buf)
497
                }
498
0
                res => res,
499
            }
500
        }
501
0
    }
502
503
0
    fn flush(&mut self) -> io::Result<()> {
504
0
        self.inner.flush()
505
0
    }
506
}
507
508
#[cfg(test)]
509
mod tests {
510
    use super::*;
511
    use alloc::string::String;
512
513
    const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
514
                               Hello World Hello World Hello World Hello World Hello World \
515
                               Hello World Hello World Hello World Hello World Hello World \
516
                               Hello World Hello World Hello World Hello World Hello World \
517
                               Hello World Hello World Hello World Hello World Hello World";
518
519
    #[test]
520
    fn decode_writer_one_chunk() {
521
        let mut e = GzEncoder::new(Vec::new(), Compression::default());
522
        e.write_all(STR.as_ref()).unwrap();
523
        let bytes = e.finish().unwrap();
524
525
        let mut writer = Vec::new();
526
        let mut decoder = GzDecoder::new(writer);
527
        let n = decoder.write(&bytes[..]).unwrap();
528
        decoder.write_all(&bytes[n..]).unwrap();
529
        decoder.try_finish().unwrap();
530
        writer = decoder.finish().unwrap();
531
        let return_string = String::from_utf8(writer).expect("String parsing error");
532
        assert_eq!(return_string, STR);
533
    }
534
535
    #[test]
536
    fn decode_writer_partial_header() {
537
        let mut e = GzEncoder::new(Vec::new(), Compression::default());
538
        e.write_all(STR.as_ref()).unwrap();
539
        let bytes = e.finish().unwrap();
540
541
        let mut writer = Vec::new();
542
        let mut decoder = GzDecoder::new(writer);
543
        assert_eq!(decoder.write(&bytes[..5]).unwrap(), 5);
544
        let n = decoder.write(&bytes[5..]).unwrap();
545
        if n < bytes.len() - 5 {
546
            decoder.write_all(&bytes[n + 5..]).unwrap();
547
        }
548
        writer = decoder.finish().unwrap();
549
        let return_string = String::from_utf8(writer).expect("String parsing error");
550
        assert_eq!(return_string, STR);
551
    }
552
553
    #[test]
554
    fn decode_writer_partial_header_filename() {
555
        let filename = "test.txt";
556
        let mut e = GzBuilder::new()
557
            .filename(filename)
558
            .read(STR.as_bytes(), Compression::default());
559
        let mut bytes = Vec::new();
560
        e.read_to_end(&mut bytes).unwrap();
561
562
        let mut writer = Vec::new();
563
        let mut decoder = GzDecoder::new(writer);
564
        assert_eq!(decoder.write(&bytes[..12]).unwrap(), 12);
565
        let n = decoder.write(&bytes[12..]).unwrap();
566
        if n < bytes.len() - 12 {
567
            decoder.write_all(&bytes[n + 12..]).unwrap();
568
        }
569
        assert_eq!(
570
            decoder.header().unwrap().filename().unwrap(),
571
            filename.as_bytes()
572
        );
573
        writer = decoder.finish().unwrap();
574
        let return_string = String::from_utf8(writer).expect("String parsing error");
575
        assert_eq!(return_string, STR);
576
    }
577
578
    #[test]
579
    fn decode_writer_partial_header_comment() {
580
        let comment = "test comment";
581
        let mut e = GzBuilder::new()
582
            .comment(comment)
583
            .read(STR.as_bytes(), Compression::default());
584
        let mut bytes = Vec::new();
585
        e.read_to_end(&mut bytes).unwrap();
586
587
        let mut writer = Vec::new();
588
        let mut decoder = GzDecoder::new(writer);
589
        assert_eq!(decoder.write(&bytes[..12]).unwrap(), 12);
590
        let n = decoder.write(&bytes[12..]).unwrap();
591
        if n < bytes.len() - 12 {
592
            decoder.write_all(&bytes[n + 12..]).unwrap();
593
        }
594
        assert_eq!(
595
            decoder.header().unwrap().comment().unwrap(),
596
            comment.as_bytes()
597
        );
598
        writer = decoder.finish().unwrap();
599
        let return_string = String::from_utf8(writer).expect("String parsing error");
600
        assert_eq!(return_string, STR);
601
    }
602
603
    #[test]
604
    fn decode_writer_exact_header() {
605
        let mut e = GzEncoder::new(Vec::new(), Compression::default());
606
        e.write_all(STR.as_ref()).unwrap();
607
        let bytes = e.finish().unwrap();
608
609
        let mut writer = Vec::new();
610
        let mut decoder = GzDecoder::new(writer);
611
        assert_eq!(decoder.write(&bytes[..10]).unwrap(), 10);
612
        decoder.write_all(&bytes[10..]).unwrap();
613
        writer = decoder.finish().unwrap();
614
        let return_string = String::from_utf8(writer).expect("String parsing error");
615
        assert_eq!(return_string, STR);
616
    }
617
618
    #[test]
619
    fn decode_writer_partial_crc() {
620
        let mut e = GzEncoder::new(Vec::new(), Compression::default());
621
        e.write_all(STR.as_ref()).unwrap();
622
        let bytes = e.finish().unwrap();
623
624
        let mut writer = Vec::new();
625
        let mut decoder = GzDecoder::new(writer);
626
        let l = bytes.len() - 5;
627
        let n = decoder.write(&bytes[..l]).unwrap();
628
        decoder.write_all(&bytes[n..]).unwrap();
629
        writer = decoder.finish().unwrap();
630
        let return_string = String::from_utf8(writer).expect("String parsing error");
631
        assert_eq!(return_string, STR);
632
    }
633
634
    // Two or more gzip files concatenated form a multi-member gzip file. MultiGzDecoder will
635
    // concatenate the decoded contents of all members.
636
    #[test]
637
    fn decode_multi_writer() {
638
        let mut e = GzEncoder::new(Vec::new(), Compression::default());
639
        e.write_all(STR.as_ref()).unwrap();
640
        let bytes = e.finish().unwrap().repeat(2);
641
642
        let mut writer = Vec::new();
643
        let mut decoder = MultiGzDecoder::new(writer);
644
        let mut count = 0;
645
        while count < bytes.len() {
646
            let n = decoder.write(&bytes[count..]).unwrap();
647
            assert!(n != 0);
648
            count += n;
649
        }
650
        writer = decoder.finish().unwrap();
651
        let return_string = String::from_utf8(writer).expect("String parsing error");
652
        let expected = STR.repeat(2);
653
        assert_eq!(return_string, expected);
654
    }
655
656
    // GzDecoder consumes one gzip member and then returns 0 for subsequent writes, allowing any
657
    // additional data to be consumed by the caller.
658
    #[test]
659
    fn decode_extra_data() {
660
        let compressed = {
661
            let mut e = GzEncoder::new(Vec::new(), Compression::default());
662
            e.write_all(STR.as_ref()).unwrap();
663
            let mut b = e.finish().unwrap();
664
            b.push(b'x');
665
            b
666
        };
667
668
        let mut writer = Vec::new();
669
        let mut decoder = GzDecoder::new(writer);
670
        let mut consumed_bytes = 0;
671
        loop {
672
            let n = decoder.write(&compressed[consumed_bytes..]).unwrap();
673
            if n == 0 {
674
                break;
675
            }
676
            consumed_bytes += n;
677
        }
678
        writer = decoder.finish().unwrap();
679
        let actual = String::from_utf8(writer).expect("String parsing error");
680
        assert_eq!(actual, STR);
681
        assert_eq!(&compressed[consumed_bytes..], b"x");
682
    }
683
}