compress_lib/gzip.rs
1//! gzip framing (RFC 1952): a header, raw DEFLATE, and a CRC-32 and length
2//! of the data; several members may follow one another.
3//!
4//! ```
5//! use compress_lib::gzip;
6//!
7//! let packed = gzip::compress(b"hello, hello, hello");
8//! assert_eq!(gzip::decompress(&packed)?, b"hello, hello, hello");
9//! # Ok::<(), compress_lib::Error>(())
10//! ```
11
12use alloc::vec::Vec;
13
14use crate::{
15 Error, ErrorKind, Level, Limits, Progress, Status,
16 checksum::Crc32,
17 deflate::{Deflater, Flush, Inflater},
18 zlib::Sink,
19};
20
21const ID1: u8 = 0x1F;
22const ID2: u8 = 0x8B;
23const FTEXT: u8 = 1;
24const FHCRC: u8 = 2;
25const FEXTRA: u8 = 4;
26const FNAME: u8 = 8;
27const FCOMMENT: u8 = 16;
28/// Operating system "unknown": the same bytes on every platform.
29const OS_UNKNOWN: u8 = 255;
30
31/// Compresses `data` into a gzip member at level 6, with a header that has
32/// no name, no time stamp, and OS "unknown" (the same bytes everywhere).
33///
34/// # Examples
35///
36/// ```
37/// let packed = compress_lib::gzip::compress(b"data");
38/// assert_eq!(&packed[..3], &[0x1F, 0x8B, 0x08]);
39/// ```
40#[must_use]
41pub fn compress(data: &[u8]) -> Vec<u8> {
42 compress_with(data, Level::DEFAULT)
43}
44
45/// Compresses `data` into a gzip member at `level`.
46///
47/// # Examples
48///
49/// ```
50/// use compress_lib::{Level, gzip};
51///
52/// let packed = gzip::compress_with(b"data", Level::FAST);
53/// assert_eq!(gzip::decompress(&packed)?, b"data");
54/// # Ok::<(), compress_lib::Error>(())
55/// ```
56#[must_use]
57pub fn compress_with(data: &[u8], level: Level) -> Vec<u8> {
58 let mut encoder = Encoder::new(level);
59 let mut out = Vec::with_capacity(data.len() / 2 + 64);
60 // Fails only when the vector cannot grow, which aborts first.
61 let _ = encoder.compress_vec(data, &mut out, Flush::Finish);
62 out
63}
64
65/// Decompresses a complete gzip stream (all members) with the default
66/// [`Limits`].
67///
68/// # Errors
69///
70/// Any decoding error; `InvalidHeader`, `ChecksumMismatch`,
71/// `LengthMismatch`, `HeaderTooLarge`, `TooManyMembers`; `UnexpectedEnd`,
72/// `TrailingData`, `OutputLimit` as for raw DEFLATE.
73///
74/// # Examples
75///
76/// ```
77/// use compress_lib::gzip;
78///
79/// let mut two = gzip::compress(b"first ");
80/// two.extend_from_slice(&gzip::compress(b"second"));
81/// assert_eq!(gzip::decompress(&two)?, b"first second");
82/// # Ok::<(), compress_lib::Error>(())
83/// ```
84pub fn decompress(data: &[u8]) -> Result<Vec<u8>, Error> {
85 decompress_with(data, Limits::new())
86}
87
88/// Decompresses a complete gzip stream with the given limits.
89///
90/// # Errors
91///
92/// As [`decompress`].
93///
94/// # Examples
95///
96/// ```
97/// use compress_lib::{ErrorKind, Limits, gzip};
98///
99/// let packed = gzip::compress(&[0u8; 10_000]);
100/// let tight = Limits::new().with_max_output(100);
101/// assert_eq!(gzip::decompress_with(&packed, tight).unwrap_err().kind(), ErrorKind::OutputLimit);
102/// ```
103pub fn decompress_with(data: &[u8], limits: Limits) -> Result<Vec<u8>, Error> {
104 let mut decoder = Decoder::one_shot(limits);
105 let mut out = Vec::new();
106 let reserve = data.len().saturating_mul(4).clamp(64, 1 << 20);
107 let cap = usize::try_from(limits.max_output()).unwrap_or(usize::MAX);
108 if out.try_reserve(reserve.min(cap)).is_err() {
109 return Err(Error::config(ErrorKind::AllocationFailed));
110 }
111 let p = decoder.finish_vec(data, &mut out)?;
112 if p.consumed != data.len() {
113 return Err(Error::new(ErrorKind::TrailingData, p.consumed as u64));
114 }
115 Ok(out)
116}
117
118/// The fields of a gzip header.
119///
120/// Decoders fill it only when asked ([`Decoder::with_keep_header`]); the
121/// optional fields are bounded by [`Limits::max_header`].
122///
123/// # Examples
124///
125/// ```
126/// use compress_lib::{Level, deflate::Flush, gzip::{self, GzipHeader}};
127///
128/// let header = GzipHeader::new().with_name(b"report.csv").with_mtime(1_700_000_000);
129/// let mut enc = gzip::Encoder::new(Level::DEFAULT).with_header(header);
130/// let mut packed = Vec::new();
131/// enc.compress_vec(b"a,b\n1,2\n", &mut packed, Flush::Finish)?;
132///
133/// let mut dec = gzip::Decoder::new().with_keep_header(true);
134/// let mut out = Vec::new();
135/// dec.finish_vec(&packed, &mut out)?;
136/// assert_eq!(dec.header().and_then(|h| h.name()), Some(&b"report.csv"[..]));
137/// # Ok::<(), compress_lib::Error>(())
138/// ```
139#[derive(Clone, Debug, Default, PartialEq, Eq)]
140#[non_exhaustive]
141pub struct GzipHeader {
142 mtime: u32,
143 os: u8,
144 extra_flags: u8,
145 text: bool,
146 name: Option<Vec<u8>>,
147 comment: Option<Vec<u8>>,
148 extra: Option<Vec<u8>>,
149}
150
151impl GzipHeader {
152 /// No name, comment, or extra field; time stamp 0; OS "unknown".
153 ///
154 /// # Examples
155 ///
156 /// ```
157 /// assert_eq!(compress_lib::gzip::GzipHeader::new().os(), 255);
158 /// ```
159 #[must_use]
160 pub fn new() -> Self {
161 Self {
162 os: OS_UNKNOWN,
163 ..Self::default()
164 }
165 }
166
167 /// Sets the file name (written without its terminating zero; it must
168 /// not contain one).
169 ///
170 /// # Examples
171 ///
172 /// ```
173 /// let h = compress_lib::gzip::GzipHeader::new().with_name(b"a.txt");
174 /// assert_eq!(h.name(), Some(&b"a.txt"[..]));
175 /// ```
176 #[must_use]
177 pub fn with_name(mut self, name: &[u8]) -> Self {
178 self.name = Some(name.iter().copied().take_while(|&b| b != 0).collect());
179 self
180 }
181
182 /// Sets the comment (it must not contain a zero byte).
183 ///
184 /// # Examples
185 ///
186 /// ```
187 /// let h = compress_lib::gzip::GzipHeader::new().with_comment(b"nightly export");
188 /// assert_eq!(h.comment(), Some(&b"nightly export"[..]));
189 /// ```
190 #[must_use]
191 pub fn with_comment(mut self, comment: &[u8]) -> Self {
192 self.comment = Some(comment.iter().copied().take_while(|&b| b != 0).collect());
193 self
194 }
195
196 /// Sets the extra field (at most 65,535 bytes; longer is cut).
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// let h = compress_lib::gzip::GzipHeader::new().with_extra(b"AB\x02\x00hi");
202 /// assert_eq!(h.extra().map(<[u8]>::len), Some(6));
203 /// ```
204 #[must_use]
205 pub fn with_extra(mut self, extra: &[u8]) -> Self {
206 self.extra = Some(extra[..extra.len().min(0xFFFF)].to_vec());
207 self
208 }
209
210 /// Sets the modification time (Unix seconds; 0 means none).
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// assert_eq!(compress_lib::gzip::GzipHeader::new().with_mtime(7).mtime(), 7);
216 /// ```
217 #[must_use]
218 pub fn with_mtime(mut self, mtime: u32) -> Self {
219 self.mtime = mtime;
220 self
221 }
222
223 /// Sets the operating system byte (RFC 1952 section 2.3.1).
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// assert_eq!(compress_lib::gzip::GzipHeader::new().with_os(3).os(), 3);
229 /// ```
230 #[must_use]
231 pub fn with_os(mut self, os: u8) -> Self {
232 self.os = os;
233 self
234 }
235
236 /// Marks the data as probably text (FTEXT).
237 ///
238 /// # Examples
239 ///
240 /// ```
241 /// assert!(compress_lib::gzip::GzipHeader::new().with_text(true).text());
242 /// ```
243 #[must_use]
244 pub fn with_text(mut self, text: bool) -> Self {
245 self.text = text;
246 self
247 }
248
249 /// The file name, if any.
250 ///
251 /// # Examples
252 ///
253 /// ```
254 /// assert_eq!(compress_lib::gzip::GzipHeader::new().name(), None);
255 /// ```
256 #[must_use]
257 pub fn name(&self) -> Option<&[u8]> {
258 self.name.as_deref()
259 }
260
261 /// The comment, if any.
262 ///
263 /// # Examples
264 ///
265 /// ```
266 /// assert_eq!(compress_lib::gzip::GzipHeader::new().comment(), None);
267 /// ```
268 #[must_use]
269 pub fn comment(&self) -> Option<&[u8]> {
270 self.comment.as_deref()
271 }
272
273 /// The extra field, if any.
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// assert_eq!(compress_lib::gzip::GzipHeader::new().extra(), None);
279 /// ```
280 #[must_use]
281 pub fn extra(&self) -> Option<&[u8]> {
282 self.extra.as_deref()
283 }
284
285 /// The modification time.
286 ///
287 /// # Examples
288 ///
289 /// ```
290 /// assert_eq!(compress_lib::gzip::GzipHeader::new().mtime(), 0);
291 /// ```
292 #[must_use]
293 pub fn mtime(&self) -> u32 {
294 self.mtime
295 }
296
297 /// The operating system byte.
298 ///
299 /// # Examples
300 ///
301 /// ```
302 /// assert_eq!(compress_lib::gzip::GzipHeader::new().os(), 255);
303 /// ```
304 #[must_use]
305 pub fn os(&self) -> u8 {
306 self.os
307 }
308
309 /// The extra flags byte (2: best compression, 4: fastest).
310 ///
311 /// # Examples
312 ///
313 /// ```
314 /// assert_eq!(compress_lib::gzip::GzipHeader::new().extra_flags(), 0);
315 /// ```
316 #[must_use]
317 pub fn extra_flags(&self) -> u8 {
318 self.extra_flags
319 }
320
321 /// Whether FTEXT is set.
322 ///
323 /// # Examples
324 ///
325 /// ```
326 /// assert!(!compress_lib::gzip::GzipHeader::new().text());
327 /// ```
328 #[must_use]
329 pub fn text(&self) -> bool {
330 self.text
331 }
332
333 /// The encoded header (with `extra_flags` from the level).
334 fn encode(&self, xfl: u8) -> Vec<u8> {
335 let mut flg = 0;
336 if self.text {
337 flg |= FTEXT;
338 }
339 if self.extra.is_some() {
340 flg |= FEXTRA;
341 }
342 if self.name.is_some() {
343 flg |= FNAME;
344 }
345 if self.comment.is_some() {
346 flg |= FCOMMENT;
347 }
348 let mut h = Vec::with_capacity(10);
349 h.extend_from_slice(&[ID1, ID2, 8, flg]);
350 h.extend_from_slice(&self.mtime.to_le_bytes());
351 h.extend_from_slice(&[xfl, self.os]);
352 if let Some(extra) = &self.extra {
353 h.extend_from_slice(&(extra.len() as u16).to_le_bytes());
354 h.extend_from_slice(extra);
355 }
356 for field in [&self.name, &self.comment].into_iter().flatten() {
357 h.extend_from_slice(field);
358 h.push(0);
359 }
360 h
361 }
362}
363
364#[derive(Clone, Copy, Debug, PartialEq, Eq)]
365enum State {
366 /// Fixed ten-byte header: `index` bytes read.
367 Fixed,
368 ExtraLength,
369 Extra,
370 Name,
371 Comment,
372 HeaderCrc,
373 Body,
374 Trailer,
375 /// A member ended; another may start.
376 MemberEnd,
377 Done,
378}
379
380/// A streaming gzip decoder.
381///
382/// Multi-member streams (RFC 1952 section 2.2) are decoded as one by
383/// default, up to [`Limits::max_members`]; the output cap applies to all
384/// members together. With more input possible after a member, `decompress`
385/// returns `NeedsInput`; `finish` decides that the stream ended.
386///
387/// # Examples
388///
389/// ```
390/// use compress_lib::{deflate::Status, gzip};
391///
392/// let packed = gzip::compress(b"streamed");
393/// let mut dec = gzip::Decoder::new();
394/// let mut out = [0u8; 32];
395/// let p = dec.finish(&packed, &mut out)?;
396/// assert_eq!(p.status, Status::Done);
397/// assert_eq!(&out[..p.produced], b"streamed");
398/// # Ok::<(), compress_lib::Error>(())
399/// ```
400#[derive(Debug)]
401pub struct Decoder {
402 inflater: Inflater,
403 limits: Limits,
404 state: State,
405 multi: bool,
406 allow_trailing: bool,
407 keep_header: bool,
408 header: Option<GzipHeader>,
409 /// Header bytes and fields in progress.
410 fixed: [u8; 10],
411 index: usize,
412 extra_left: usize,
413 header_crc: Crc32,
414 header_bytes: usize,
415 field: Vec<u8>,
416 crc: Crc32,
417 member_len: u32,
418 trailer: [u8; 8],
419 members: u32,
420 out_before: u64,
421 consumed_total: u64,
422 failed: Option<Error>,
423}
424
425impl Default for Decoder {
426 fn default() -> Self {
427 Self::new()
428 }
429}
430
431impl Decoder {
432 /// A decoder with window bits 15 and the default limits, multi-member,
433 /// trailing data refused, header fields not kept.
434 ///
435 /// # Examples
436 ///
437 /// ```
438 /// assert!(!compress_lib::gzip::Decoder::new().is_done());
439 /// ```
440 #[must_use]
441 pub fn new() -> Self {
442 Self::from_inflater(Inflater::new(), Limits::new())
443 }
444
445 pub(crate) fn one_shot(limits: Limits) -> Self {
446 Self::from_inflater(Inflater::without_history(limits), limits)
447 }
448
449 fn from_inflater(inflater: Inflater, limits: Limits) -> Self {
450 Self {
451 inflater,
452 limits,
453 state: State::Fixed,
454 multi: true,
455 allow_trailing: false,
456 keep_header: false,
457 header: None,
458 fixed: [0; 10],
459 index: 0,
460 extra_left: 0,
461 header_crc: Crc32::new(),
462 header_bytes: 0,
463 field: Vec::new(),
464 crc: Crc32::new(),
465 member_len: 0,
466 trailer: [0; 8],
467 members: 0,
468 out_before: 0,
469 consumed_total: 0,
470 failed: None,
471 }
472 }
473
474 /// Sets the limits: the output cap (across members), the ratio cap, the
475 /// header field cap, and the member cap.
476 ///
477 /// # Examples
478 ///
479 /// ```
480 /// use compress_lib::{Limits, gzip};
481 ///
482 /// let dec = gzip::Decoder::new().with_limits(Limits::new().with_max_members(1));
483 /// # let _ = dec;
484 /// ```
485 #[must_use]
486 pub fn with_limits(mut self, limits: Limits) -> Self {
487 self.inflater = self.inflater.with_limits(limits);
488 self.limits = limits;
489 self
490 }
491
492 /// Decodes one member only; `Done` at its end, and what follows is left
493 /// to the caller.
494 ///
495 /// # Examples
496 ///
497 /// ```
498 /// use compress_lib::{deflate::Status, gzip};
499 ///
500 /// let mut two = gzip::compress(b"first");
501 /// let first_len = two.len();
502 /// two.extend_from_slice(&gzip::compress(b"second"));
503 /// let mut dec = gzip::Decoder::new().with_single_member();
504 /// let mut out = Vec::new();
505 /// let p = dec.decompress_vec(&two, &mut out)?;
506 /// assert_eq!((p.status, p.consumed), (Status::Done, first_len));
507 /// # Ok::<(), compress_lib::Error>(())
508 /// ```
509 #[must_use]
510 pub fn with_single_member(mut self) -> Self {
511 self.multi = false;
512 self
513 }
514
515 /// Allows bytes that are not a gzip member after the last member (some
516 /// tools pad files with zeros); `consumed` stops before them.
517 ///
518 /// # Examples
519 ///
520 /// ```
521 /// use compress_lib::gzip;
522 ///
523 /// let mut padded = gzip::compress(b"data");
524 /// padded.extend_from_slice(&[0; 8]);
525 /// let mut dec = gzip::Decoder::new().with_trailing_data(true);
526 /// let mut out = Vec::new();
527 /// dec.finish_vec(&padded, &mut out)?;
528 /// assert_eq!(out, b"data");
529 /// # Ok::<(), compress_lib::Error>(())
530 /// ```
531 #[must_use]
532 pub fn with_trailing_data(mut self, allow: bool) -> Self {
533 self.allow_trailing = allow;
534 self
535 }
536
537 /// Keeps the header fields (name, comment, extra) for [`header`]
538 /// (bounded by [`Limits::max_header`]); off by default, so no memory is
539 /// spent on them.
540 ///
541 /// [`header`]: Decoder::header
542 ///
543 /// # Examples
544 ///
545 /// ```
546 /// let dec = compress_lib::gzip::Decoder::new().with_keep_header(true);
547 /// assert!(dec.header().is_none());
548 /// ```
549 #[must_use]
550 pub fn with_keep_header(mut self, keep: bool) -> Self {
551 self.keep_header = keep;
552 self
553 }
554
555 /// The first member's header, once read, when headers are kept.
556 ///
557 /// # Examples
558 ///
559 /// ```
560 /// use compress_lib::gzip;
561 ///
562 /// let mut dec = gzip::Decoder::new().with_keep_header(true);
563 /// dec.finish_vec(&gzip::compress(b"x"), &mut Vec::new())?;
564 /// assert_eq!(dec.header().map(|h| h.os()), Some(255));
565 /// # Ok::<(), compress_lib::Error>(())
566 /// ```
567 #[must_use]
568 pub fn header(&self) -> Option<&GzipHeader> {
569 self.header.as_ref()
570 }
571
572 /// `true` once the stream ended.
573 ///
574 /// # Examples
575 ///
576 /// ```
577 /// use compress_lib::gzip;
578 ///
579 /// let mut dec = gzip::Decoder::new();
580 /// dec.finish_vec(&gzip::compress(b""), &mut Vec::new())?;
581 /// assert!(dec.is_done());
582 /// # Ok::<(), compress_lib::Error>(())
583 /// ```
584 #[must_use]
585 pub fn is_done(&self) -> bool {
586 self.state == State::Done
587 }
588
589 /// Members completed so far.
590 ///
591 /// # Examples
592 ///
593 /// ```
594 /// use compress_lib::gzip;
595 ///
596 /// let mut two = gzip::compress(b"a");
597 /// two.extend_from_slice(&gzip::compress(b"b"));
598 /// let mut dec = gzip::Decoder::new();
599 /// dec.finish_vec(&two, &mut Vec::new())?;
600 /// assert_eq!(dec.members(), 2);
601 /// # Ok::<(), compress_lib::Error>(())
602 /// ```
603 #[must_use]
604 pub fn members(&self) -> u32 {
605 self.members
606 }
607
608 /// Compressed bytes consumed.
609 ///
610 /// # Examples
611 ///
612 /// ```
613 /// use compress_lib::gzip;
614 ///
615 /// let packed = gzip::compress(b"x");
616 /// let mut dec = gzip::Decoder::new();
617 /// dec.finish_vec(&packed, &mut Vec::new())?;
618 /// assert_eq!(dec.total_in(), packed.len() as u64);
619 /// # Ok::<(), compress_lib::Error>(())
620 /// ```
621 #[must_use]
622 pub fn total_in(&self) -> u64 {
623 self.consumed_total
624 }
625
626 /// Decompressed bytes produced, all members.
627 ///
628 /// # Examples
629 ///
630 /// ```
631 /// use compress_lib::gzip;
632 ///
633 /// let mut dec = gzip::Decoder::new();
634 /// dec.finish_vec(&gzip::compress(b"four"), &mut Vec::new())?;
635 /// assert_eq!(dec.total_out(), 4);
636 /// # Ok::<(), compress_lib::Error>(())
637 /// ```
638 #[must_use]
639 pub fn total_out(&self) -> u64 {
640 self.out_before + self.inflater.total_out()
641 }
642
643 /// Heap bytes held.
644 ///
645 /// # Examples
646 ///
647 /// ```
648 /// assert!(compress_lib::gzip::Decoder::new().memory_in_use() > 32 * 1024);
649 /// ```
650 #[must_use]
651 pub fn memory_in_use(&self) -> usize {
652 self.inflater.memory_in_use() + self.field.capacity()
653 }
654
655 /// Starts over for a new stream, keeping allocations.
656 ///
657 /// # Examples
658 ///
659 /// ```
660 /// let mut dec = compress_lib::gzip::Decoder::new();
661 /// dec.reset();
662 /// ```
663 pub fn reset(&mut self) {
664 self.inflater.reset();
665 self.inflater.set_max_output(self.limits.max_output());
666 self.state = State::Fixed;
667 self.index = 0;
668 self.header = None;
669 self.field.clear();
670 self.crc = Crc32::new();
671 self.header_crc = Crc32::new();
672 self.header_bytes = 0;
673 self.members = 0;
674 self.out_before = 0;
675 self.consumed_total = 0;
676 self.failed = None;
677 }
678
679 /// Decompresses as much of `input` into `output` as fits; more input may
680 /// follow (and after a member, perhaps another member).
681 ///
682 /// # Errors
683 ///
684 /// Decoding errors, the header and trailer checks, and the limits.
685 ///
686 /// # Examples
687 ///
688 /// ```
689 /// use compress_lib::{deflate::Status, gzip};
690 ///
691 /// let packed = gzip::compress(b"split");
692 /// let mut dec = gzip::Decoder::new();
693 /// let mut out = [0u8; 16];
694 /// let a = dec.decompress(&packed[..5], &mut out)?;
695 /// assert_eq!(a.status, Status::NeedsInput);
696 /// let b = dec.finish(&packed[5..], &mut out[a.produced..])?;
697 /// assert_eq!(b.status, Status::Done);
698 /// # Ok::<(), compress_lib::Error>(())
699 /// ```
700 pub fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<Progress, Error> {
701 self.run(input, Sink::Slice(output), false)
702 }
703
704 /// As [`decompress`](Decoder::decompress), with `input` the last of the
705 /// stream.
706 ///
707 /// # Errors
708 ///
709 /// As `decompress`, plus `UnexpectedEnd`.
710 ///
711 /// # Examples
712 ///
713 /// ```
714 /// use compress_lib::{ErrorKind, gzip};
715 ///
716 /// let packed = gzip::compress(b"data");
717 /// let err = gzip::Decoder::new().finish(&packed[..packed.len() - 1], &mut [0u8; 8]).unwrap_err();
718 /// assert_eq!(err.kind(), ErrorKind::UnexpectedEnd);
719 /// ```
720 pub fn finish(&mut self, input: &[u8], output: &mut [u8]) -> Result<Progress, Error> {
721 self.run(input, Sink::Slice(output), true)
722 }
723
724 /// Decompresses `input`, appending to `out`.
725 ///
726 /// # Errors
727 ///
728 /// As [`decompress`](Decoder::decompress), plus `AllocationFailed`.
729 ///
730 /// # Examples
731 ///
732 /// ```
733 /// use compress_lib::gzip;
734 ///
735 /// let mut out = Vec::new();
736 /// gzip::Decoder::new().decompress_vec(&gzip::compress(b"vec"), &mut out)?;
737 /// assert_eq!(out, b"vec");
738 /// # Ok::<(), compress_lib::Error>(())
739 /// ```
740 pub fn decompress_vec(&mut self, input: &[u8], out: &mut Vec<u8>) -> Result<Progress, Error> {
741 self.run(input, Sink::Vec(out), false)
742 }
743
744 /// As [`decompress_vec`](Decoder::decompress_vec), with `input` the last
745 /// of the stream.
746 ///
747 /// # Errors
748 ///
749 /// As `decompress_vec`, plus `UnexpectedEnd`.
750 ///
751 /// # Examples
752 ///
753 /// ```
754 /// use compress_lib::gzip;
755 ///
756 /// let mut out = Vec::new();
757 /// gzip::Decoder::new().finish_vec(&gzip::compress(b"vec"), &mut out)?;
758 /// assert_eq!(out, b"vec");
759 /// # Ok::<(), compress_lib::Error>(())
760 /// ```
761 pub fn finish_vec(&mut self, input: &[u8], out: &mut Vec<u8>) -> Result<Progress, Error> {
762 self.run(input, Sink::Vec(out), true)
763 }
764
765 fn fail(&mut self, kind: ErrorKind, at: usize) -> Error {
766 let e = Error::new(kind, self.consumed_total + at as u64);
767 self.failed = Some(e);
768 e
769 }
770
771 /// Counts one byte of an optional header field against the cap.
772 fn header_byte(&mut self, b: u8) -> Result<(), ErrorKind> {
773 self.header_crc.update(&[b]);
774 self.header_bytes += 1;
775 if self.header_bytes > self.limits.max_header() {
776 return Err(ErrorKind::HeaderTooLarge);
777 }
778 if self.keep_header && self.members == 0 {
779 if self.field.try_reserve(1).is_err() {
780 return Err(ErrorKind::AllocationFailed);
781 }
782 self.field.push(b);
783 }
784 Ok(())
785 }
786
787 fn keep_field(&mut self, which: State) {
788 if !(self.keep_header && self.members == 0) {
789 return;
790 }
791 let value = core::mem::take(&mut self.field);
792 if let Some(h) = &mut self.header {
793 match which {
794 State::Extra => h.extra = Some(value),
795 State::Name => h.name = Some(value),
796 _ => h.comment = Some(value),
797 }
798 }
799 }
800
801 /// The header state after `from`, by the flags.
802 fn next_header_state(&self, from: State) -> State {
803 let flg = self.fixed[3];
804 let order = [
805 (State::ExtraLength, FEXTRA),
806 (State::Name, FNAME),
807 (State::Comment, FCOMMENT),
808 (State::HeaderCrc, FHCRC),
809 ];
810 let start = match from {
811 State::Fixed => 0,
812 State::Extra | State::ExtraLength => 1,
813 State::Name => 2,
814 State::Comment => 3,
815 _ => 4,
816 };
817 for &(state, bit) in &order[start..] {
818 if flg & bit != 0 {
819 return state;
820 }
821 }
822 State::Body
823 }
824
825 fn run(&mut self, input: &[u8], mut sink: Sink<'_>, last: bool) -> Result<Progress, Error> {
826 if let Some(e) = self.failed {
827 return Err(e);
828 }
829 let mut ip = 0;
830 let mut produced = 0;
831 let status = loop {
832 match self.state {
833 State::Fixed => {
834 while self.index < 10 && ip < input.len() {
835 self.fixed[self.index] = input[ip];
836 self.index += 1;
837 ip += 1;
838 // Reject a wrong magic number at once (also for the
839 // trailing-data check after a member).
840 if self.index == 2 && self.fixed[..2] != [ID1, ID2] {
841 return Err(self.fail(ErrorKind::InvalidHeader, ip));
842 }
843 }
844 if self.index < 10 {
845 break Status::NeedsInput;
846 }
847 let f = self.fixed;
848 if f[2] != 8 || f[3] & 0xE0 != 0 {
849 return Err(self.fail(ErrorKind::InvalidHeader, ip));
850 }
851 self.header_crc = Crc32::new();
852 self.header_crc.update(&f);
853 self.header_bytes = 0;
854 if self.keep_header && self.members == 0 {
855 self.header = Some(GzipHeader {
856 mtime: u32::from_le_bytes([f[4], f[5], f[6], f[7]]),
857 extra_flags: f[8],
858 os: f[9],
859 text: f[3] & FTEXT != 0,
860 name: None,
861 comment: None,
862 extra: None,
863 });
864 }
865 self.index = 0;
866 self.state = self.next_header_state(State::Fixed);
867 }
868 State::ExtraLength => {
869 while self.index < 2 && ip < input.len() {
870 self.trailer[self.index] = input[ip];
871 self.index += 1;
872 ip += 1;
873 }
874 if self.index < 2 {
875 break Status::NeedsInput;
876 }
877 let xlen = [self.trailer[0], self.trailer[1]];
878 self.header_crc.update(&xlen);
879 self.extra_left = usize::from(u16::from_le_bytes(xlen));
880 self.index = 0;
881 self.state = State::Extra;
882 }
883 State::Extra => {
884 while self.extra_left > 0 && ip < input.len() {
885 let b = input[ip];
886 ip += 1;
887 self.extra_left -= 1;
888 if let Err(kind) = self.header_byte(b) {
889 return Err(self.fail(kind, ip));
890 }
891 }
892 if self.extra_left > 0 {
893 break Status::NeedsInput;
894 }
895 self.keep_field(State::Extra);
896 self.state = self.next_header_state(State::Extra);
897 }
898 State::Name | State::Comment => {
899 let which = self.state;
900 let mut ended = false;
901 while ip < input.len() {
902 let b = input[ip];
903 ip += 1;
904 if b == 0 {
905 self.header_crc.update(&[0]);
906 ended = true;
907 break;
908 }
909 if let Err(kind) = self.header_byte(b) {
910 return Err(self.fail(kind, ip));
911 }
912 }
913 if !ended {
914 break Status::NeedsInput;
915 }
916 self.keep_field(which);
917 self.state = self.next_header_state(which);
918 }
919 State::HeaderCrc => {
920 while self.index < 2 && ip < input.len() {
921 self.trailer[self.index] = input[ip];
922 self.index += 1;
923 ip += 1;
924 }
925 if self.index < 2 {
926 break Status::NeedsInput;
927 }
928 self.index = 0;
929 let want = u16::from_le_bytes([self.trailer[0], self.trailer[1]]);
930 if want != (self.header_crc.finish() & 0xFFFF) as u16 {
931 return Err(self.fail(ErrorKind::ChecksumMismatch, ip));
932 }
933 self.state = State::Body;
934 }
935 State::Body => {
936 let r = match &mut sink {
937 Sink::Slice(out) => self
938 .inflater
939 .decompress(&input[ip..], &mut out[produced..])
940 .inspect(|p| {
941 self.crc.update(&out[produced..produced + p.produced]);
942 }),
943 Sink::Vec(out) => {
944 let at = out.len();
945 self.inflater
946 .decompress_vec(&input[ip..], out)
947 .inspect(|_| {
948 self.crc.update(&out[at..]);
949 })
950 }
951 };
952 let p = match r {
953 Ok(p) => p,
954 Err(e) => {
955 self.failed = Some(e);
956 return Err(e);
957 }
958 };
959 ip += p.consumed;
960 produced += p.produced;
961 self.member_len = self.member_len.wrapping_add(p.produced as u32);
962 match p.status {
963 Status::Done => {
964 self.index = 0;
965 self.state = State::Trailer;
966 }
967 Status::NeedsOutput => break Status::NeedsOutput,
968 _ => break Status::NeedsInput,
969 }
970 }
971 State::Trailer => {
972 while self.index < 8 && ip < input.len() {
973 self.trailer[self.index] = input[ip];
974 self.index += 1;
975 ip += 1;
976 }
977 if self.index < 8 {
978 break Status::NeedsInput;
979 }
980 let t = self.trailer;
981 if u32::from_le_bytes([t[0], t[1], t[2], t[3]]) != self.crc.finish() {
982 return Err(self.fail(ErrorKind::ChecksumMismatch, ip));
983 }
984 if u32::from_le_bytes([t[4], t[5], t[6], t[7]]) != self.member_len {
985 return Err(self.fail(ErrorKind::LengthMismatch, ip));
986 }
987 self.members += 1;
988 self.state = if self.multi {
989 State::MemberEnd
990 } else {
991 State::Done
992 };
993 }
994 State::MemberEnd => {
995 if ip == input.len() {
996 if last {
997 self.state = State::Done;
998 break Status::Done;
999 }
1000 break Status::NeedsInput;
1001 }
1002 if input[ip] != ID1 || (ip + 1 < input.len() && input[ip + 1] != ID2) {
1003 if self.allow_trailing {
1004 self.state = State::Done;
1005 break Status::Done;
1006 }
1007 return Err(self.fail(ErrorKind::TrailingData, ip));
1008 }
1009 if self.members >= self.limits.max_members() {
1010 return Err(self.fail(ErrorKind::TooManyMembers, ip));
1011 }
1012 // A new member: a new DEFLATE stream (no history across
1013 // members), with the output cap shared by all.
1014 self.out_before += self.inflater.total_out();
1015 self.inflater.reset();
1016 self.inflater
1017 .set_max_output(self.limits.max_output().saturating_sub(self.out_before));
1018 self.crc = Crc32::new();
1019 self.member_len = 0;
1020 self.index = 0;
1021 self.state = State::Fixed;
1022 }
1023 State::Done => break Status::Done,
1024 }
1025 };
1026 self.consumed_total += ip as u64;
1027 if status == Status::NeedsInput && last {
1028 // An empty stream, or one cut inside a member.
1029 return Err(self.fail(ErrorKind::UnexpectedEnd, 0));
1030 }
1031 Ok(Progress::new(ip, produced, status))
1032 }
1033}
1034
1035/// A streaming gzip encoder (one member).
1036///
1037/// # Examples
1038///
1039/// ```
1040/// use compress_lib::{Level, deflate::Flush, gzip};
1041///
1042/// let mut enc = gzip::Encoder::new(Level::DEFAULT);
1043/// let mut packed = Vec::new();
1044/// enc.compress_vec(b"part one, ", &mut packed, Flush::None)?;
1045/// enc.compress_vec(b"part two", &mut packed, Flush::Finish)?;
1046/// assert_eq!(gzip::decompress(&packed)?, b"part one, part two");
1047/// # Ok::<(), compress_lib::Error>(())
1048/// ```
1049#[derive(Debug)]
1050pub struct Encoder {
1051 deflater: Deflater,
1052 header: GzipHeader,
1053 crc: Crc32,
1054 pending: Vec<u8>,
1055 pending_pos: usize,
1056 header_written: bool,
1057 trailer_written: bool,
1058}
1059
1060impl Default for Encoder {
1061 fn default() -> Self {
1062 Self::new(Level::DEFAULT)
1063 }
1064}
1065
1066impl Encoder {
1067 /// An encoder at `level` with the plain header of [`GzipHeader::new`].
1068 ///
1069 /// # Examples
1070 ///
1071 /// ```
1072 /// let enc = compress_lib::gzip::Encoder::new(compress_lib::Level::BEST);
1073 /// # let _ = enc;
1074 /// ```
1075 #[must_use]
1076 pub fn new(level: Level) -> Self {
1077 Self {
1078 deflater: Deflater::new(level),
1079 header: GzipHeader::new(),
1080 crc: Crc32::new(),
1081 pending: Vec::new(),
1082 pending_pos: 0,
1083 header_written: false,
1084 trailer_written: false,
1085 }
1086 }
1087
1088 /// Writes `header` instead of the plain one.
1089 ///
1090 /// # Examples
1091 ///
1092 /// ```
1093 /// use compress_lib::{Level, gzip::{Encoder, GzipHeader}};
1094 ///
1095 /// let enc = Encoder::new(Level::DEFAULT).with_header(GzipHeader::new().with_name(b"a.txt"));
1096 /// # let _ = enc;
1097 /// ```
1098 #[must_use]
1099 pub fn with_header(mut self, header: GzipHeader) -> Self {
1100 self.header = header;
1101 self
1102 }
1103
1104 /// Sets the window to `2^bits` bytes, 8 to 15.
1105 ///
1106 /// # Errors
1107 ///
1108 /// [`ErrorKind::InvalidWindowBits`] outside 8 to 15.
1109 ///
1110 /// # Examples
1111 ///
1112 /// ```
1113 /// let enc = compress_lib::gzip::Encoder::default().with_window_bits(12)?;
1114 /// # let _ = enc;
1115 /// # Ok::<(), compress_lib::Error>(())
1116 /// ```
1117 pub fn with_window_bits(mut self, bits: u8) -> Result<Self, Error> {
1118 self.deflater = self.deflater.with_window_bits(bits)?;
1119 Ok(self)
1120 }
1121
1122 /// Starts a new member, keeping allocations and the header.
1123 ///
1124 /// # Examples
1125 ///
1126 /// ```
1127 /// let mut enc = compress_lib::gzip::Encoder::default();
1128 /// enc.reset();
1129 /// ```
1130 pub fn reset(&mut self) {
1131 self.deflater.reset();
1132 self.crc = Crc32::new();
1133 self.pending.clear();
1134 self.pending_pos = 0;
1135 self.header_written = false;
1136 self.trailer_written = false;
1137 }
1138
1139 /// Uncompressed bytes taken.
1140 ///
1141 /// # Examples
1142 ///
1143 /// ```
1144 /// use compress_lib::{deflate::Flush, gzip};
1145 ///
1146 /// let mut enc = gzip::Encoder::default();
1147 /// enc.compress_vec(b"abc", &mut Vec::new(), Flush::Finish)?;
1148 /// assert_eq!(enc.total_in(), 3);
1149 /// # Ok::<(), compress_lib::Error>(())
1150 /// ```
1151 #[must_use]
1152 pub fn total_in(&self) -> u64 {
1153 self.deflater.total_in()
1154 }
1155
1156 /// Heap bytes held.
1157 ///
1158 /// # Examples
1159 ///
1160 /// ```
1161 /// assert!(compress_lib::gzip::Encoder::default().memory_in_use() > 0);
1162 /// ```
1163 #[must_use]
1164 pub fn memory_in_use(&self) -> usize {
1165 self.deflater.memory_in_use() + self.pending.capacity()
1166 }
1167
1168 fn drain(&mut self, output: &mut [u8], produced: &mut usize) -> usize {
1169 let n = (self.pending.len() - self.pending_pos).min(output.len() - *produced);
1170 output[*produced..*produced + n]
1171 .copy_from_slice(&self.pending[self.pending_pos..self.pending_pos + n]);
1172 self.pending_pos += n;
1173 *produced += n;
1174 self.pending.len() - self.pending_pos
1175 }
1176
1177 /// As [`Deflater::compress`], with the header written first and the
1178 /// CRC-32 and length after `Finish`.
1179 ///
1180 /// # Errors
1181 ///
1182 /// As `Deflater::compress`.
1183 ///
1184 /// # Examples
1185 ///
1186 /// ```
1187 /// use compress_lib::{deflate::{Flush, Status}, gzip};
1188 ///
1189 /// let mut enc = gzip::Encoder::default();
1190 /// let mut out = [0u8; 64];
1191 /// let p = enc.compress(b"abc", &mut out, Flush::Finish)?;
1192 /// assert_eq!(p.status, Status::Done);
1193 /// assert_eq!(gzip::decompress(&out[..p.produced])?, b"abc");
1194 /// # Ok::<(), compress_lib::Error>(())
1195 /// ```
1196 pub fn compress(
1197 &mut self,
1198 input: &[u8],
1199 output: &mut [u8],
1200 flush: Flush,
1201 ) -> Result<Progress, Error> {
1202 let mut produced = 0;
1203 if !self.header_written {
1204 let xfl = match self.deflater.level().get() {
1205 9 => 2,
1206 1 => 4,
1207 _ => 0,
1208 };
1209 self.pending = self.header.encode(xfl);
1210 self.pending_pos = 0;
1211 self.header_written = true;
1212 }
1213 if self.drain(output, &mut produced) > 0 {
1214 return Ok(Progress::new(0, produced, Status::NeedsOutput));
1215 }
1216 if self.trailer_written {
1217 if !input.is_empty() {
1218 return Err(Error::config(ErrorKind::InvalidState));
1219 }
1220 return Ok(Progress::new(0, produced, Status::Done));
1221 }
1222 let p = self
1223 .deflater
1224 .compress(input, &mut output[produced..], flush)?;
1225 self.crc.update(&input[..p.consumed]);
1226 produced += p.produced;
1227 if p.status == Status::Done && flush == Flush::Finish {
1228 self.pending.clear();
1229 self.pending
1230 .extend_from_slice(&self.crc.finish().to_le_bytes());
1231 self.pending
1232 .extend_from_slice(&(self.crc.len() as u32).to_le_bytes());
1233 self.pending_pos = 0;
1234 self.trailer_written = true;
1235 let left = self.drain(output, &mut produced);
1236 let status = if left == 0 {
1237 Status::Done
1238 } else {
1239 Status::NeedsOutput
1240 };
1241 return Ok(Progress::new(p.consumed, produced, status));
1242 }
1243 Ok(Progress::new(p.consumed, produced, p.status))
1244 }
1245
1246 /// As [`compress`](Encoder::compress), appending to `out` until the
1247 /// flush point is written.
1248 ///
1249 /// # Errors
1250 ///
1251 /// As `compress`, plus `AllocationFailed`.
1252 ///
1253 /// # Examples
1254 ///
1255 /// ```
1256 /// use compress_lib::{deflate::Flush, gzip};
1257 ///
1258 /// let mut out = Vec::new();
1259 /// gzip::Encoder::default().compress_vec(b"abc", &mut out, Flush::Finish)?;
1260 /// assert_eq!(gzip::decompress(&out)?, b"abc");
1261 /// # Ok::<(), compress_lib::Error>(())
1262 /// ```
1263 pub fn compress_vec(
1264 &mut self,
1265 input: &[u8],
1266 out: &mut Vec<u8>,
1267 flush: Flush,
1268 ) -> Result<Progress, Error> {
1269 let start = out.len();
1270 let mut consumed = 0;
1271 loop {
1272 let have = out.len();
1273 let room = (input.len() - consumed) / 2 + 1024;
1274 if out.capacity() - have < room && out.try_reserve(room).is_err() {
1275 return Err(Error::config(ErrorKind::AllocationFailed));
1276 }
1277 let spare = out.capacity() - have;
1278 out.resize(have + spare, 0);
1279 match self.compress(&input[consumed..], &mut out[have..], flush) {
1280 Ok(p) => {
1281 out.truncate(have + p.produced);
1282 consumed += p.consumed;
1283 if p.status != Status::NeedsOutput {
1284 return Ok(Progress::new(consumed, out.len() - start, p.status));
1285 }
1286 }
1287 Err(e) => {
1288 out.truncate(have);
1289 return Err(e);
1290 }
1291 }
1292 }
1293 }
1294}