flate2/gz/write.rs
1use crate::io;
2use crate::io::{Read, Write};
3use alloc::vec::Vec;
4use core::cmp;
5
6use super::{corrupt, GzBuilder, GzHeader, GzHeaderParser};
7use crate::crc::{Crc, CrcWriter};
8use crate::zio;
9use 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.
14fn write_nonzero<W: Write>(writer: &mut W, buf: &[u8]) -> io::Result<usize> {
15 let n = writer.write(buf)?;
16 if n == 0 && !buf.is_empty() {
17 Err(io::ErrorKind::WriteZero.into())
18 } else {
19 Ok(n)
20 }
21}
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)]
46pub struct GzEncoder<W: Write> {
47 inner: zio::Writer<W, Compress>,
48 crc: Crc,
49 crc_bytes_written: usize,
50 header: Vec<u8>,
51}
52
53pub fn gz_encoder<W: Write>(header: Vec<u8>, w: W, lvl: Compression) -> GzEncoder<W> {
54 GzEncoder {
55 inner: zio::Writer::new(w, Compress::new(lvl, false)),
56 crc: Crc::new(),
57 header,
58 crc_bytes_written: 0,
59 }
60}
61
62impl<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 pub fn new(w: W, level: Compression) -> GzEncoder<W> {
71 GzBuilder::new().write(w, level)
72 }
73
74 /// Acquires a reference to the underlying writer.
75 pub fn get_ref(&self) -> &W {
76 self.inner.get_ref()
77 }
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 pub fn get_mut(&mut self) -> &mut W {
94 self.inner.get_mut()
95 }
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 pub fn try_finish(&mut self) -> io::Result<()> {
113 self.write_header()?;
114 self.inner.finish()?;
115
116 while self.crc_bytes_written < 8 {
117 let (sum, amt) = (self.crc.sum(), self.crc.amount());
118 let buf = [
119 sum as u8,
120 (sum >> 8) as u8,
121 (sum >> 16) as u8,
122 (sum >> 24) as u8,
123 amt as u8,
124 (amt >> 8) as u8,
125 (amt >> 16) as u8,
126 (amt >> 24) as u8,
127 ];
128 let inner = self.inner.get_mut();
129 let n = write_nonzero(inner, &buf[self.crc_bytes_written..])?;
130 self.crc_bytes_written += n;
131 }
132 Ok(())
133 }
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 pub fn finish(mut self) -> io::Result<W> {
149 self.try_finish()?;
150 Ok(self.inner.take_inner())
151 }
152
153 fn write_header(&mut self) -> io::Result<()> {
154 while !self.header.is_empty() {
155 let n = write_nonzero(self.inner.get_mut(), &self.header)?;
156 self.header.drain(..n);
157 }
158 Ok(())
159 }
160}
161
162impl<W: Write> Write for GzEncoder<W> {
163 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
164 assert_eq!(self.crc_bytes_written, 0);
165 self.write_header()?;
166 let n = self.inner.write(buf)?;
167 self.crc.update(&buf[..n]);
168 Ok(n)
169 }
170
171 fn flush(&mut self) -> io::Result<()> {
172 assert_eq!(self.crc_bytes_written, 0);
173 self.write_header()?;
174 self.inner.flush()
175 }
176}
177
178impl<R: Read + Write> Read for GzEncoder<R> {
179 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
180 self.get_mut().read(buf)
181 }
182}
183
184impl<W: Write> Drop for GzEncoder<W> {
185 fn drop(&mut self) {
186 if self.inner.is_present() {
187 let _ = self.try_finish();
188 }
189 }
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)]
234pub struct GzDecoder<W: Write> {
235 inner: zio::Writer<CrcWriter<W>, Decompress>,
236 crc_bytes: Vec<u8>,
237 header_parser: GzHeaderParser,
238}
239
240const CRC_BYTES_LEN: usize = 8;
241
242impl<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 pub fn new(w: W) -> GzDecoder<W> {
248 GzDecoder {
249 inner: zio::Writer::new(CrcWriter::new(w), Decompress::new(false)),
250 crc_bytes: Vec::with_capacity(CRC_BYTES_LEN),
251 header_parser: GzHeaderParser::new(),
252 }
253 }
254
255 /// Returns the header associated with this stream.
256 pub fn header(&self) -> Option<&GzHeader> {
257 self.header_parser.header()
258 }
259
260 /// Acquires a reference to the underlying writer.
261 pub fn get_ref(&self) -> &W {
262 self.inner.get_ref().get_ref()
263 }
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 pub fn get_mut(&mut self) -> &mut W {
279 self.inner.get_mut().get_mut()
280 }
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 pub fn try_finish(&mut self) -> io::Result<()> {
298 self.finish_and_check_crc()?;
299 Ok(())
300 }
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 pub fn finish(mut self) -> io::Result<W> {
318 self.finish_and_check_crc()?;
319 Ok(self.inner.take_inner().into_inner())
320 }
321
322 fn finish_and_check_crc(&mut self) -> io::Result<()> {
323 self.inner.finish()?;
324
325 if self.crc_bytes.len() != 8 {
326 return Err(corrupt());
327 }
328
329 let crc = (self.crc_bytes[0] as u32)
330 | ((self.crc_bytes[1] as u32) << 8)
331 | ((self.crc_bytes[2] as u32) << 16)
332 | ((self.crc_bytes[3] as u32) << 24);
333 let amt = (self.crc_bytes[4] as u32)
334 | ((self.crc_bytes[5] as u32) << 8)
335 | ((self.crc_bytes[6] as u32) << 16)
336 | ((self.crc_bytes[7] as u32) << 24);
337 if crc != self.inner.get_ref().crc().sum() {
338 return Err(corrupt());
339 }
340 if amt != self.inner.get_ref().crc().amount() {
341 return Err(corrupt());
342 }
343 Ok(())
344 }
345}
346
347impl<W: Write> Write for GzDecoder<W> {
348 fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
349 let buflen = buf.len();
350 if self.header().is_none() {
351 match self.header_parser.parse(&mut buf) {
352 Err(err) => {
353 if err.kind() == io::ErrorKind::UnexpectedEof {
354 // all data read but header still not complete
355 Ok(buflen)
356 } else {
357 Err(err)
358 }
359 }
360 Ok(_) => {
361 debug_assert!(self.header().is_some());
362 // buf now contains the unread part of the original buf
363 let n = buflen - buf.len();
364 Ok(n)
365 }
366 }
367 } else {
368 let (n, status) = self.inner.write_with_status(buf)?;
369
370 if status == Status::StreamEnd && n < buf.len() && self.crc_bytes.len() < 8 {
371 let remaining = buf.len() - n;
372 let crc_bytes = cmp::min(remaining, CRC_BYTES_LEN - self.crc_bytes.len());
373 self.crc_bytes.extend(&buf[n..n + crc_bytes]);
374 return Ok(n + crc_bytes);
375 }
376 Ok(n)
377 }
378 }
379
380 fn flush(&mut self) -> io::Result<()> {
381 self.inner.flush()
382 }
383}
384
385impl<W: Read + Write> Read for GzDecoder<W> {
386 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
387 self.inner.get_mut().get_mut().read(buf)
388 }
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)]
405pub struct MultiGzDecoder<W: Write> {
406 inner: GzDecoder<W>,
407}
408
409impl<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 pub fn new(w: W) -> MultiGzDecoder<W> {
413 MultiGzDecoder {
414 inner: GzDecoder::new(w),
415 }
416 }
417
418 /// Returns the header associated with the current member.
419 pub fn header(&self) -> Option<&GzHeader> {
420 self.inner.header()
421 }
422
423 /// Acquires a reference to the underlying writer.
424 pub fn get_ref(&self) -> &W {
425 self.inner.get_ref()
426 }
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 pub fn get_mut(&mut self) -> &mut W {
442 self.inner.get_mut()
443 }
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 pub fn try_finish(&mut self) -> io::Result<()> {
461 self.inner.try_finish()
462 }
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 pub fn finish(self) -> io::Result<W> {
480 self.inner.finish()
481 }
482}
483
484impl<W: Write> Write for MultiGzDecoder<W> {
485 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
486 if buf.is_empty() {
487 Ok(0)
488 } else {
489 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 self.inner.try_finish()?;
494 let w = self.inner.inner.take_inner().into_inner();
495 self.inner = GzDecoder::new(w);
496 self.inner.write(buf)
497 }
498 res => res,
499 }
500 }
501 }
502
503 fn flush(&mut self) -> io::Result<()> {
504 self.inner.flush()
505 }
506}
507
508#[cfg(test)]
509mod 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}