Coverage Report

Created: 2025-07-23 07:29

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