Skip to main content

libflate/
gzip.rs

1//! The encoder and decoder of the GZIP format.
2//!
3//! The GZIP format is defined in [RFC-1952](https://tools.ietf.org/html/rfc1952).
4//!
5//! # Examples
6//! ```
7//! use no_std_io2::io::{Read, Write};
8//! use libflate::gzip::{Encoder, Decoder};
9//!
10//! // Encoding
11//! let mut encoder = Encoder::new(Vec::new()).unwrap();
12//! encoder.write_all(b"Hello World!".as_ref()).unwrap();
13//! let encoded_data = encoder.finish().into_result().unwrap();
14//!
15//! // Decoding
16//! let mut decoder = Decoder::new(&encoded_data[..]).unwrap();
17//! let mut decoded_data = Vec::new();
18//! decoder.read_to_end(&mut decoded_data).unwrap();
19//!
20//! assert_eq!(decoded_data, b"Hello World!");
21//! ```
22use crate::checksum;
23use crate::deflate;
24use crate::finish::{Complete, Finish};
25use crate::lz77;
26use alloc::{ffi::CString, vec::Vec};
27use no_std_io2::io;
28#[cfg(feature = "std")]
29use std::time;
30
31const GZIP_ID: [u8; 2] = [31, 139];
32const COMPRESSION_METHOD_DEFLATE: u8 = 8;
33
34const OS_FAT: u8 = 0;
35const OS_AMIGA: u8 = 1;
36const OS_VMS: u8 = 2;
37const OS_UNIX: u8 = 3;
38const OS_VM_CMS: u8 = 4;
39const OS_ATARI_TOS: u8 = 5;
40const OS_HPFS: u8 = 6;
41const OS_MACINTOSH: u8 = 7;
42const OS_Z_SYSTEM: u8 = 8;
43const OS_CPM: u8 = 9;
44const OS_TOPS20: u8 = 10;
45const OS_NTFS: u8 = 11;
46const OS_QDOS: u8 = 12;
47const OS_ACORN_RISCOS: u8 = 13;
48const OS_UNKNOWN: u8 = 255;
49
50const F_TEXT: u8 = 0b00_0001;
51const F_HCRC: u8 = 0b00_0010;
52const F_EXTRA: u8 = 0b00_0100;
53const F_NAME: u8 = 0b00_1000;
54const F_COMMENT: u8 = 0b01_0000;
55
56/// Compression levels defined by the GZIP format.
57#[derive(Debug, Clone, PartialEq, Eq, Hash)]
58pub enum CompressionLevel {
59    /// Compressor used fastest algorithm.
60    Fastest,
61
62    /// Compressor used maximum compression, slowest algorithm.
63    Slowest,
64
65    /// No information about compression method.
66    Unknown,
67}
68impl CompressionLevel {
69    fn to_u8(&self) -> u8 {
70        match *self {
71            CompressionLevel::Fastest => 4,
72            CompressionLevel::Slowest => 2,
73            CompressionLevel::Unknown => 0,
74        }
75    }
76    fn from_u8(x: u8) -> Self {
77        match x {
78            4 => CompressionLevel::Fastest,
79            2 => CompressionLevel::Slowest,
80            _ => CompressionLevel::Unknown,
81        }
82    }
83}
84impl From<lz77::CompressionLevel> for CompressionLevel {
85    fn from(f: lz77::CompressionLevel) -> Self {
86        match f {
87            lz77::CompressionLevel::Fast => CompressionLevel::Fastest,
88            lz77::CompressionLevel::Best => CompressionLevel::Slowest,
89            _ => CompressionLevel::Unknown,
90        }
91    }
92}
93
94#[derive(Debug, Clone)]
95pub(crate) struct Trailer {
96    crc32: u32,
97    input_size: u32,
98}
99impl Trailer {
100    pub fn crc32(&self) -> u32 {
101        self.crc32
102    }
103    pub fn read_from<R>(mut reader: R) -> io::Result<Self>
104    where
105        R: io::Read,
106    {
107        let mut buf = [0; 4];
108        reader.read_exact(&mut buf)?;
109        let crc32 = u32::from_le_bytes(buf);
110        reader.read_exact(&mut buf)?;
111        let input_size = u32::from_le_bytes(buf);
112        Ok(Trailer { crc32, input_size })
113    }
114    fn write_to<W>(&self, mut writer: W) -> io::Result<()>
115    where
116        W: io::Write,
117    {
118        writer.write_all(&self.crc32.to_le_bytes())?;
119        writer.write_all(&self.input_size.to_le_bytes())?;
120        Ok(())
121    }
122}
123
124/// GZIP header builder.
125#[derive(Debug, Clone)]
126pub struct HeaderBuilder {
127    header: Header,
128}
129impl HeaderBuilder {
130    /// Makes a new builder instance.
131    ///
132    /// # Examples
133    /// ```
134    /// use libflate::gzip::{HeaderBuilder, CompressionLevel, Os};
135    ///
136    /// let header = HeaderBuilder::new().finish();
137    /// assert_eq!(header.compression_level(), CompressionLevel::Unknown);
138    /// assert_eq!(header.os(), Os::Unix);
139    /// assert_eq!(header.is_text(), false);
140    /// assert_eq!(header.is_verified(), false);
141    /// assert_eq!(header.extra_field(), None);
142    /// assert_eq!(header.filename(), None);
143    /// assert_eq!(header.comment(), None);
144    /// ```
145    pub fn new() -> Self {
146        // wasm-unknown-unknown does not implement the time module
147        #[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
148        let modification_time = time::UNIX_EPOCH
149            .elapsed()
150            .map(|d| d.as_secs() as u32)
151            .unwrap_or(0);
152        #[cfg(any(target_arch = "wasm32", not(feature = "std")))]
153        let modification_time = 0;
154
155        let header = Header {
156            modification_time,
157            compression_level: CompressionLevel::Unknown,
158            os: Os::Unix,
159            is_text: false,
160            is_verified: false,
161            extra_field: None,
162            filename: None,
163            comment: None,
164        };
165        HeaderBuilder { header }
166    }
167
168    /// Sets the modification time (UNIX timestamp).
169    ///
170    /// # Examples
171    /// ```
172    /// use libflate::gzip::HeaderBuilder;
173    ///
174    /// let header = HeaderBuilder::new().modification_time(10).finish();
175    /// assert_eq!(header.modification_time(), 10);
176    /// ```
177    pub fn modification_time(&mut self, modification_time: u32) -> &mut Self {
178        self.header.modification_time = modification_time;
179        self
180    }
181
182    /// Sets the OS type.
183    ///
184    /// ```
185    /// use libflate::gzip::{HeaderBuilder, Os};
186    ///
187    /// let header = HeaderBuilder::new().os(Os::Ntfs).finish();
188    /// assert_eq!(header.os(), Os::Ntfs);
189    /// ```
190    pub fn os(&mut self, os: Os) -> &mut Self {
191        self.header.os = os;
192        self
193    }
194
195    /// Indicates the encoding data is a ASCII text.
196    ///
197    /// # Examples
198    /// ```
199    /// use libflate::gzip::HeaderBuilder;
200    ///
201    /// let header = HeaderBuilder::new().text().finish();
202    /// assert_eq!(header.is_text(), true);
203    /// ```
204    pub fn text(&mut self) -> &mut Self {
205        self.header.is_text = true;
206        self
207    }
208
209    /// Specifies toe verify header bytes using CRC-16.
210    ///
211    /// # Examples
212    /// ```
213    /// use libflate::gzip::HeaderBuilder;
214    ///
215    /// let header = HeaderBuilder::new().verify().finish();
216    /// assert_eq!(header.is_verified(), true);
217    /// ```
218    pub fn verify(&mut self) -> &mut Self {
219        self.header.is_verified = true;
220        self
221    }
222
223    /// Sets the extra field.
224    ///
225    /// # Examples
226    /// ```
227    /// use libflate::gzip::{HeaderBuilder, ExtraField, ExtraSubField};
228    ///
229    /// let subfield = ExtraSubField{id: [0, 1], data: vec![2, 3, 4]};
230    /// let extra = ExtraField{subfields: vec![subfield]};
231    /// let header = HeaderBuilder::new().extra_field(extra.clone()).finish();
232    /// assert_eq!(header.extra_field(), Some(&extra));
233    /// ```
234    pub fn extra_field(&mut self, extra: ExtraField) -> &mut Self {
235        self.header.extra_field = Some(extra);
236        self
237    }
238
239    /// Sets the file name.
240    ///
241    /// # Examples
242    /// ```
243    /// #[cfg(not(feature = "std"))]
244    /// extern crate alloc;
245    /// #[cfg(not(feature = "std"))]
246    /// use alloc::ffi::CString;
247    /// #[cfg(feature = "std")]
248    /// use std::ffi::CString;
249    /// use libflate::gzip::HeaderBuilder;
250    ///
251    /// let header = HeaderBuilder::new().filename(CString::new("foo").unwrap()).finish();
252    /// assert_eq!(header.filename(), Some(&CString::new("foo").unwrap()));
253    /// ```
254    pub fn filename(&mut self, filename: CString) -> &mut Self {
255        self.header.filename = Some(filename);
256        self
257    }
258
259    /// Sets the comment.
260    ///
261    /// # Examples
262    /// ```
263    /// #[cfg(not(feature = "std"))]
264    /// extern crate alloc;
265    /// #[cfg(not(feature = "std"))]
266    /// use alloc::ffi::CString;
267    /// #[cfg(feature = "std")]
268    /// use std::ffi::CString;
269    /// use libflate::gzip::HeaderBuilder;
270    ///
271    /// let header = HeaderBuilder::new().comment(CString::new("foo").unwrap()).finish();
272    /// assert_eq!(header.comment(), Some(&CString::new("foo").unwrap()));
273    /// ```
274    pub fn comment(&mut self, comment: CString) -> &mut Self {
275        self.header.comment = Some(comment);
276        self
277    }
278
279    /// Returns the result header.
280    pub fn finish(&self) -> Header {
281        self.header.clone()
282    }
283}
284impl Default for HeaderBuilder {
285    fn default() -> Self {
286        Self::new()
287    }
288}
289
290/// GZIP Header.
291#[derive(Debug, Clone)]
292pub struct Header {
293    modification_time: u32,
294    compression_level: CompressionLevel,
295    os: Os,
296    is_text: bool,
297    is_verified: bool,
298    extra_field: Option<ExtraField>,
299    filename: Option<CString>,
300    comment: Option<CString>,
301}
302impl Header {
303    /// Returns the modification time (UNIX timestamp).
304    pub fn modification_time(&self) -> u32 {
305        self.modification_time
306    }
307
308    /// Returns the compression level.
309    pub fn compression_level(&self) -> CompressionLevel {
310        self.compression_level.clone()
311    }
312
313    /// Returns the OS type.
314    pub fn os(&self) -> Os {
315        self.os.clone()
316    }
317
318    /// Returns `true` if the stream is probably ASCII text, `false` otherwise.
319    pub fn is_text(&self) -> bool {
320        self.is_text
321    }
322
323    /// Returns `true` if the header bytes is verified by CRC-16, `false` otherwise.
324    pub fn is_verified(&self) -> bool {
325        self.is_verified
326    }
327
328    /// Returns the extra field.
329    pub fn extra_field(&self) -> Option<&ExtraField> {
330        self.extra_field.as_ref()
331    }
332
333    /// Returns the file name.
334    pub fn filename(&self) -> Option<&CString> {
335        self.filename.as_ref()
336    }
337
338    /// Returns the comment.
339    pub fn comment(&self) -> Option<&CString> {
340        self.comment.as_ref()
341    }
342
343    fn flags(&self) -> u8 {
344        [
345            (F_TEXT, self.is_text),
346            (F_HCRC, self.is_verified),
347            (F_EXTRA, self.extra_field.is_some()),
348            (F_NAME, self.filename.is_some()),
349            (F_COMMENT, self.comment.is_some()),
350        ]
351        .iter()
352        .filter(|e| e.1)
353        .map(|e| e.0)
354        .sum()
355    }
356    fn crc16(&self) -> u16 {
357        let mut crc = checksum::Crc32::new();
358        let mut buf = Vec::new();
359        Header {
360            is_verified: false,
361            ..self.clone()
362        }
363        .write_to(&mut buf)
364        .unwrap();
365        crc.update(&buf);
366        crc.value() as u16
367    }
368    fn write_to<W>(&self, mut writer: W) -> io::Result<()>
369    where
370        W: io::Write,
371    {
372        writer.write_all(&GZIP_ID)?;
373        writer.write_all(&[COMPRESSION_METHOD_DEFLATE, self.flags()])?;
374        writer.write_all(&self.modification_time.to_le_bytes())?;
375        writer.write_all(&[self.compression_level.to_u8(), self.os.to_u8()])?;
376        if let Some(ref x) = self.extra_field {
377            x.write_to(&mut writer)?;
378        }
379        if let Some(ref x) = self.filename {
380            writer.write_all(x.as_bytes_with_nul())?;
381        }
382        if let Some(ref x) = self.comment {
383            writer.write_all(x.as_bytes_with_nul())?;
384        }
385        if self.is_verified {
386            writer.write_all(&self.crc16().to_le_bytes())?;
387        }
388        Ok(())
389    }
390    pub(crate) fn read_from<R>(mut reader: R) -> io::Result<Self>
391    where
392        R: io::Read,
393    {
394        let mut this = HeaderBuilder::new().finish();
395        let mut buf = [0; 2 + 1 + 1 + 4 + 1 + 1];
396        reader.read_exact(&mut buf)?;
397        let id = &buf[0..2];
398        if id != GZIP_ID {
399            return Err(invalid_data_error!(
400                "Unexpected GZIP ID: value={:?}, \
401                 expected={:?}",
402                id,
403                GZIP_ID
404            ));
405        }
406        let compression_method = buf[2];
407        if compression_method != COMPRESSION_METHOD_DEFLATE {
408            return Err(invalid_data_error!(
409                "Compression methods other than DEFLATE(8) are \
410                 unsupported: method={}",
411                compression_method
412            ));
413        }
414        let flags = buf[3];
415        this.modification_time = u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]);
416        this.compression_level = CompressionLevel::from_u8(buf[8]);
417        this.os = Os::from_u8(buf[9]);
418        if flags & F_EXTRA != 0 {
419            this.extra_field = Some(ExtraField::read_from(&mut reader)?);
420        }
421        if flags & F_NAME != 0 {
422            this.filename = Some(read_cstring(&mut reader)?);
423        }
424        if flags & F_COMMENT != 0 {
425            this.comment = Some(read_cstring(&mut reader)?);
426        }
427        // Checksum verification is skipped during fuzzing
428        // so that random data from fuzzer can reach actually interesting code.
429        // Compilation flag 'fuzzing' is automatically set by all 3 Rust fuzzers.
430        if flags & F_HCRC != 0 && cfg!(not(fuzzing)) {
431            let mut buf = [0; 2];
432            reader.read_exact(&mut buf)?;
433            let crc = u16::from_le_bytes(buf);
434            let expected = this.crc16();
435            if crc != expected {
436                return Err(invalid_data_error!(
437                    "CRC16 of GZIP header mismatched: value={}, \
438                     expected={}",
439                    crc,
440                    expected
441                ));
442            }
443            this.is_verified = true;
444        }
445        Ok(this)
446    }
447}
448
449fn read_cstring<R>(mut reader: R) -> io::Result<CString>
450where
451    R: io::Read,
452{
453    let mut buf = Vec::new();
454    loop {
455        let mut cbuf = [0; 1];
456        reader.read_exact(&mut cbuf)?;
457        if cbuf[0] == 0 {
458            return Ok(CString::new(buf).unwrap());
459        }
460        buf.push(cbuf[0]);
461    }
462}
463
464/// Extra field of a GZIP header.
465#[derive(Debug, Clone, PartialEq, Eq, Hash)]
466pub struct ExtraField {
467    /// Data of the extra field.
468    pub subfields: Vec<ExtraSubField>,
469}
470impl ExtraField {
471    fn read_from<R>(mut reader: R) -> io::Result<Self>
472    where
473        R: io::Read,
474    {
475        let mut subfields = Vec::new();
476        let mut buf = [0; 2];
477        reader.read_exact(&mut buf)?;
478        let data_size = u16::from_le_bytes(buf) as usize;
479        let mut reader = reader.take(data_size as u64);
480        while reader.limit() > 0 {
481            subfields.push(ExtraSubField::read_from(&mut reader)?);
482        }
483        Ok(ExtraField { subfields })
484    }
485    fn write_to<W>(&self, mut writer: W) -> io::Result<()>
486    where
487        W: io::Write,
488    {
489        let len = self.subfields.iter().map(|f| f.write_len()).sum::<usize>();
490        if len > 0xFFFF {
491            return Err(invalid_data_error!("extra field too long: {}", len));
492        }
493        writer.write_all(&(len as u16).to_le_bytes())?;
494        for f in &self.subfields {
495            f.write_to(&mut writer)?;
496        }
497        Ok(())
498    }
499}
500
501/// A sub field in the extra field of a GZIP header.
502#[derive(Debug, Clone, PartialEq, Eq, Hash)]
503pub struct ExtraSubField {
504    /// ID of the field.
505    pub id: [u8; 2],
506
507    /// Data of the field.
508    pub data: Vec<u8>,
509}
510impl ExtraSubField {
511    fn read_from<R>(mut reader: R) -> io::Result<Self>
512    where
513        R: io::Read,
514    {
515        let mut field = ExtraSubField {
516            id: [0; 2],
517            data: Vec::new(),
518        };
519
520        reader.read_exact(&mut field.id)?;
521        let mut buf = [0; 2];
522        reader.read_exact(&mut buf)?;
523        let data_size = u16::from_le_bytes(buf) as usize;
524        field.data.resize(data_size, 0);
525        reader.read_exact(&mut field.data)?;
526
527        Ok(field)
528    }
529    fn write_to<W>(&self, mut writer: W) -> io::Result<()>
530    where
531        W: io::Write,
532    {
533        writer.write_all(&self.id)?;
534        writer.write_all(&(self.data.len() as u16).to_le_bytes())?;
535        writer.write_all(&self.data)?;
536        Ok(())
537    }
538    fn write_len(&self) -> usize {
539        4 + self.data.len()
540    }
541}
542
543/// OS type.
544#[derive(Debug, Clone, PartialEq, Eq, Hash)]
545pub enum Os {
546    /// FAT filesystem (MS-DOS, OS/2, NT/Win32)
547    Fat,
548
549    /// Amiga
550    Amiga,
551
552    /// VMS (or OpenVMS)
553    Vms,
554
555    /// Unix
556    Unix,
557
558    /// VM/CMS
559    VmCms,
560
561    /// Atari TOS
562    AtariTos,
563
564    /// HPFS filesystem (OS/2, NT)
565    Hpfs,
566
567    /// Macintosh
568    Macintosh,
569
570    /// Z-System
571    ZSystem,
572
573    /// CP/M
574    CpM,
575
576    /// TOPS-20
577    Tops20,
578
579    /// NTFS filesystem (NT)
580    Ntfs,
581
582    /// QDOS
583    Qdos,
584
585    /// Acorn RISCOS
586    AcornRiscos,
587
588    /// Unknown
589    Unknown,
590
591    /// Undefined value in RFC-1952
592    Undefined(u8),
593}
594impl Os {
595    fn to_u8(&self) -> u8 {
596        match *self {
597            Os::Fat => OS_FAT,
598            Os::Amiga => OS_AMIGA,
599            Os::Vms => OS_VMS,
600            Os::Unix => OS_UNIX,
601            Os::VmCms => OS_VM_CMS,
602            Os::AtariTos => OS_ATARI_TOS,
603            Os::Hpfs => OS_HPFS,
604            Os::Macintosh => OS_MACINTOSH,
605            Os::ZSystem => OS_Z_SYSTEM,
606            Os::CpM => OS_CPM,
607            Os::Tops20 => OS_TOPS20,
608            Os::Ntfs => OS_NTFS,
609            Os::Qdos => OS_QDOS,
610            Os::AcornRiscos => OS_ACORN_RISCOS,
611            Os::Unknown => OS_UNKNOWN,
612            Os::Undefined(os) => os,
613        }
614    }
615    fn from_u8(x: u8) -> Self {
616        match x {
617            OS_FAT => Os::Fat,
618            OS_AMIGA => Os::Amiga,
619            OS_VMS => Os::Vms,
620            OS_UNIX => Os::Unix,
621            OS_VM_CMS => Os::VmCms,
622            OS_ATARI_TOS => Os::AtariTos,
623            OS_HPFS => Os::Hpfs,
624            OS_MACINTOSH => Os::Macintosh,
625            OS_Z_SYSTEM => Os::ZSystem,
626            OS_CPM => Os::CpM,
627            OS_TOPS20 => Os::Tops20,
628            OS_NTFS => Os::Ntfs,
629            OS_QDOS => Os::Qdos,
630            OS_ACORN_RISCOS => Os::AcornRiscos,
631            OS_UNKNOWN => Os::Unknown,
632            os => Os::Undefined(os),
633        }
634    }
635}
636
637/// Options for a GZIP encoder.
638#[derive(Debug)]
639pub struct EncodeOptions<E>
640where
641    E: lz77::Lz77Encode,
642{
643    header: Header,
644    options: deflate::EncodeOptions<E>,
645}
646impl Default for EncodeOptions<lz77::DefaultLz77Encoder> {
647    fn default() -> Self {
648        EncodeOptions {
649            header: HeaderBuilder::new().finish(),
650            options: Default::default(),
651        }
652    }
653}
654impl EncodeOptions<lz77::DefaultLz77Encoder> {
655    /// Makes a default instance.
656    ///
657    /// # Examples
658    /// ```
659    /// use libflate::gzip::{Encoder, EncodeOptions};
660    ///
661    /// let options = EncodeOptions::new();
662    /// let encoder = Encoder::with_options(Vec::new(), options).unwrap();
663    /// ```
664    pub fn new() -> Self {
665        Self::default()
666    }
667}
668impl<E> EncodeOptions<E>
669where
670    E: lz77::Lz77Encode,
671{
672    /// Specifies the LZ77 encoder used to compress input data.
673    ///
674    /// # Example
675    /// ```
676    /// use libflate::lz77::DefaultLz77Encoder;
677    /// use libflate::gzip::{Encoder, EncodeOptions};
678    ///
679    /// let options = EncodeOptions::with_lz77(DefaultLz77Encoder::new());
680    /// let encoder = Encoder::with_options(Vec::new(), options).unwrap();
681    /// ```
682    pub fn with_lz77(lz77: E) -> Self {
683        let mut header = HeaderBuilder::new().finish();
684        header.compression_level = From::from(lz77.compression_level());
685        EncodeOptions {
686            header,
687            options: deflate::EncodeOptions::with_lz77(lz77),
688        }
689    }
690
691    /// Disables LZ77 compression.
692    ///
693    /// # Example
694    /// ```
695    /// use libflate::lz77::DefaultLz77Encoder;
696    /// use libflate::gzip::{Encoder, EncodeOptions};
697    ///
698    /// let options = EncodeOptions::new().no_compression();
699    /// let encoder = Encoder::with_options(Vec::new(), options).unwrap();
700    /// ```
701    pub fn no_compression(mut self) -> Self {
702        self.options = self.options.no_compression();
703        self.header.compression_level = CompressionLevel::Unknown;
704        self
705    }
706
707    /// Sets the GZIP header which will be written to the output stream.
708    ///
709    /// # Example
710    /// ```
711    /// use libflate::gzip::{Encoder, EncodeOptions, HeaderBuilder};
712    ///
713    /// let header = HeaderBuilder::new().text().modification_time(100).finish();
714    /// let options = EncodeOptions::new().header(header);
715    /// let encoder = Encoder::with_options(Vec::new(), options).unwrap();
716    /// ```
717    pub fn header(mut self, header: Header) -> Self {
718        self.header = header;
719        self
720    }
721
722    /// Specifies the hint of the size of a DEFLATE block.
723    ///
724    /// The default value is `deflate::DEFAULT_BLOCK_SIZE`.
725    ///
726    /// # Example
727    /// ```
728    /// use libflate::gzip::{Encoder, EncodeOptions};
729    ///
730    /// let options = EncodeOptions::new().block_size(512 * 1024);
731    /// let encoder = Encoder::with_options(Vec::new(), options).unwrap();
732    /// ```
733    pub fn block_size(mut self, size: usize) -> Self {
734        self.options = self.options.block_size(size);
735        self
736    }
737
738    /// Specifies to compress with fixed huffman codes.
739    ///
740    /// # Example
741    /// ```
742    /// use libflate::gzip::{Encoder, EncodeOptions};
743    ///
744    /// let options = EncodeOptions::new().fixed_huffman_codes();
745    /// let encoder = Encoder::with_options(Vec::new(), options).unwrap();
746    /// ```
747    pub fn fixed_huffman_codes(mut self) -> Self {
748        self.options = self.options.fixed_huffman_codes();
749        self
750    }
751}
752
753/// GZIP encoder.
754pub struct Encoder<W, E = lz77::DefaultLz77Encoder> {
755    header: Header,
756    crc32: checksum::Crc32,
757    input_size: u32,
758    writer: deflate::Encoder<W, E>,
759}
760impl<W> Encoder<W, lz77::DefaultLz77Encoder>
761where
762    W: io::Write,
763{
764    /// Makes a new encoder instance.
765    ///
766    /// Encoded GZIP stream is written to `inner`.
767    ///
768    /// # Examples
769    /// ```
770    /// use no_std_io2::io::Write;
771    /// use libflate::gzip::Encoder;
772    ///
773    /// let mut encoder = Encoder::new(Vec::new()).unwrap();
774    /// encoder.write_all(&b"Hello World!"[..]).unwrap();
775    /// encoder.finish().into_result().unwrap();
776    /// ```
777    pub fn new(inner: W) -> io::Result<Self> {
778        Self::with_options(inner, EncodeOptions::new())
779    }
780}
781impl<W, E> Encoder<W, E>
782where
783    W: io::Write,
784    E: lz77::Lz77Encode,
785{
786    /// Makes a new encoder instance with specified options.
787    ///
788    /// Encoded GZIP stream is written to `inner`.
789    ///
790    /// # Examples
791    /// ```
792    /// use no_std_io2::io::Write;
793    /// use libflate::gzip::{Encoder, EncodeOptions, HeaderBuilder};
794    ///
795    /// let header = HeaderBuilder::new().modification_time(123).finish();
796    /// let options = EncodeOptions::new().no_compression().header(header);
797    /// let mut encoder = Encoder::with_options(Vec::new(), options).unwrap();
798    /// encoder.write_all(&b"Hello World!"[..]).unwrap();
799    ///
800    /// assert_eq!(encoder.finish().into_result().unwrap(),
801    ///            &[31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255, 72, 101, 108, 108,
802    ///              111, 32, 87, 111, 114, 108, 100, 33, 163, 28, 41, 28, 12, 0, 0, 0][..]);
803    /// ```
804    pub fn with_options(mut inner: W, options: EncodeOptions<E>) -> io::Result<Self> {
805        options.header.write_to(&mut inner)?;
806        Ok(Encoder {
807            header: options.header.clone(),
808            crc32: checksum::Crc32::new(),
809            input_size: 0,
810            writer: deflate::Encoder::with_options(inner, options.options),
811        })
812    }
813
814    /// Returns the header of the GZIP stream.
815    ///
816    /// # Examples
817    /// ```
818    /// use libflate::gzip::{Encoder, Os};
819    ///
820    /// let encoder = Encoder::new(Vec::new()).unwrap();
821    /// assert_eq!(encoder.header().os(), Os::Unix);
822    /// ```
823    pub fn header(&self) -> &Header {
824        &self.header
825    }
826
827    /// Writes the GZIP trailer and returns the inner stream.
828    ///
829    /// # Examples
830    /// ```
831    /// use no_std_io2::io::Write;
832    /// use libflate::gzip::Encoder;
833    ///
834    /// let mut encoder = Encoder::new(Vec::new()).unwrap();
835    /// encoder.write_all(&b"Hello World!"[..]).unwrap();
836    ///
837    /// assert!(encoder.finish().as_result().is_ok())
838    /// ```
839    ///
840    /// # Note
841    ///
842    /// If you are not concerned the result of this encoding,
843    /// it may be convenient to use `AutoFinishUnchecked` instead of the explicit invocation of this method.
844    ///
845    /// ```
846    /// use no_std_io2::io::Write;
847    /// use libflate::finish::AutoFinishUnchecked;
848    /// use libflate::gzip::Encoder;
849    ///
850    /// let plain = b"Hello World!";
851    /// let mut buf = Vec::new();
852    /// let mut encoder = AutoFinishUnchecked::new(Encoder::new(&mut buf).unwrap());
853    /// #[cfg(not(feature = "std"))]
854    /// encoder.write_all(plain.as_ref()).unwrap();
855    /// #[cfg(feature = "std")]
856    /// std::io::copy(&mut &plain[..], &mut encoder).unwrap();
857    /// ```
858    pub fn finish(self) -> Finish<W, io::Error> {
859        let trailer = Trailer {
860            crc32: self.crc32.value(),
861            input_size: self.input_size,
862        };
863        let mut inner = finish_try!(self.writer.finish());
864        match trailer.write_to(&mut inner).and_then(|_| inner.flush()) {
865            Ok(_) => Finish::new(inner, None),
866            Err(e) => Finish::new(inner, Some(e)),
867        }
868    }
869
870    /// Returns the immutable reference to the inner stream.
871    pub fn as_inner_ref(&self) -> &W {
872        self.writer.as_inner_ref()
873    }
874
875    /// Returns the mutable reference to the inner stream.
876    pub fn as_inner_mut(&mut self) -> &mut W {
877        self.writer.as_inner_mut()
878    }
879
880    /// Unwraps the `Encoder`, returning the inner stream.
881    pub fn into_inner(self) -> W {
882        self.writer.into_inner()
883    }
884}
885impl<W, E> io::Write for Encoder<W, E>
886where
887    W: io::Write,
888    E: lz77::Lz77Encode,
889{
890    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
891        let written_size = self.writer.write(buf)?;
892        self.crc32.update(&buf[..written_size]);
893        self.input_size = self.input_size.wrapping_add(written_size as u32);
894        Ok(written_size)
895    }
896    fn flush(&mut self) -> io::Result<()> {
897        self.writer.flush()
898    }
899}
900impl<W, E> Complete for Encoder<W, E>
901where
902    W: io::Write,
903    E: lz77::Lz77Encode,
904{
905    fn complete(self) -> io::Result<()> {
906        self.finish().into_result().map(|_| ())
907    }
908}
909
910/// GZIP decoder.
911#[derive(Debug)]
912pub struct Decoder<R> {
913    header: Header,
914    reader: deflate::Decoder<R>,
915    crc32: checksum::Crc32,
916    eos: bool,
917}
918impl<R> Decoder<R>
919where
920    R: io::Read,
921{
922    /// Makes a new decoder instance.
923    ///
924    /// `inner` is to be decoded GZIP stream.
925    ///
926    /// # Examples
927    /// ```
928    /// use no_std_io2::io::Read;
929    /// use libflate::gzip::Decoder;
930    ///
931    /// let encoded_data = [31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255,
932    ///                     72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33,
933    ///                     163, 28, 41, 28, 12, 0, 0, 0];
934    ///
935    /// let mut decoder = Decoder::new(&encoded_data[..]).unwrap();
936    /// let mut buf = Vec::new();
937    /// decoder.read_to_end(&mut buf).unwrap();
938    ///
939    /// assert_eq!(buf, b"Hello World!");
940    /// ```
941    pub fn new(mut inner: R) -> io::Result<Self> {
942        let header = Header::read_from(&mut inner)?;
943        Ok(Self::with_header(inner, header))
944    }
945
946    /// Returns the header of the GZIP stream.
947    ///
948    /// # Examples
949    /// ```
950    /// use libflate::gzip::{Decoder, Os};
951    ///
952    /// let encoded_data = [31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255,
953    ///                     72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33,
954    ///                     163, 28, 41, 28, 12, 0, 0, 0];
955    ///
956    /// let decoder = Decoder::new(&encoded_data[..]).unwrap();
957    /// assert_eq!(decoder.header().os(), Os::Unix);
958    /// ```
959    pub fn header(&self) -> &Header {
960        &self.header
961    }
962
963    /// Returns the immutable reference to the inner stream.
964    pub fn as_inner_ref(&self) -> &R {
965        self.reader.as_inner_ref()
966    }
967
968    /// Returns the mutable reference to the inner stream.
969    pub fn as_inner_mut(&mut self) -> &mut R {
970        self.reader.as_inner_mut()
971    }
972
973    /// Unwraps this `Decoder`, returning the underlying reader.
974    ///
975    /// # Examples
976    /// ```
977    /// use no_std_io2::io::Cursor;
978    /// use libflate::gzip::Decoder;
979    ///
980    /// let encoded_data = [31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255,
981    ///                     72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33,
982    ///                     163, 28, 41, 28, 12, 0, 0, 0];
983    ///
984    /// let decoder = Decoder::new(Cursor::new(&encoded_data[..])).unwrap();
985    /// assert_eq!(decoder.into_inner().into_inner(), &encoded_data[..]);
986    /// ```
987    pub fn into_inner(self) -> R {
988        self.reader.into_inner()
989    }
990
991    /// Returns the data that has been decoded but has not yet been read.
992    ///
993    /// This method is useful to retrieve partial decoded data when the decoding process is failed.
994    pub fn unread_decoded_data(&self) -> &[u8] {
995        self.reader.unread_decoded_data()
996    }
997
998    fn with_header(inner: R, header: Header) -> Self {
999        Decoder {
1000            header,
1001            reader: deflate::Decoder::new(inner),
1002            crc32: checksum::Crc32::new(),
1003            eos: false,
1004        }
1005    }
1006
1007    fn reset(&mut self, header: Header) {
1008        self.header = header;
1009        self.reader.reset();
1010        self.crc32 = checksum::Crc32::new();
1011        self.eos = false;
1012    }
1013}
1014impl<R> io::Read for Decoder<R>
1015where
1016    R: io::Read,
1017{
1018    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1019        if self.eos {
1020            Ok(0)
1021        } else {
1022            let read_size = self.reader.read(buf)?;
1023            self.crc32.update(&buf[..read_size]);
1024            if read_size == 0 {
1025                if buf.is_empty() {
1026                    return Ok(0);
1027                }
1028
1029                self.eos = true;
1030                let trailer = Trailer::read_from(self.reader.as_inner_mut())?;
1031                // checksum verification is skipped during fuzzing
1032                // so that random data from fuzzer can reach actually interesting code
1033                // Compilation flag 'fuzzing' is automatically set by all 3 Rust fuzzers.
1034                if cfg!(not(fuzzing)) && trailer.crc32 != self.crc32.value() {
1035                    Err(invalid_data_error!(
1036                        "CRC32 mismatched: value={}, expected={}",
1037                        self.crc32.value(),
1038                        trailer.crc32
1039                    ))
1040                } else {
1041                    Ok(0)
1042                }
1043            } else {
1044                Ok(read_size)
1045            }
1046        }
1047    }
1048}
1049
1050/// A decoder that decodes all members in a GZIP stream.
1051#[derive(Debug)]
1052pub struct MultiDecoder<R> {
1053    decoder: Decoder<R>,
1054    eos: bool,
1055}
1056impl<R> MultiDecoder<R>
1057where
1058    R: io::Read,
1059{
1060    /// Makes a new decoder instance.
1061    ///
1062    /// `inner` is to be decoded GZIP stream.
1063    ///
1064    /// # Examples
1065    /// ```
1066    /// use no_std_io2::io::Read;
1067    /// use libflate::gzip::MultiDecoder;
1068    ///
1069    /// let mut encoded_data = Vec::new();
1070    ///
1071    /// // Add a member (a GZIP binary that represents "Hello ")
1072    /// encoded_data.extend(&[31, 139, 8, 0, 51, 206, 75, 90, 0, 3, 5, 128, 49, 9, 0, 0, 0, 194, 170, 24,
1073    ///                       199, 34, 126, 3, 251, 127, 163, 131, 71, 192, 252, 45, 234, 6, 0, 0, 0][..]);
1074    ///
1075    /// // Add another member (a GZIP binary that represents "World!")
1076    /// encoded_data.extend(&[31, 139, 8, 0, 227, 207, 75, 90, 0, 3, 5, 128, 49, 9, 0, 0, 0, 194, 178, 152,
1077    ///                       202, 2, 158, 130, 96, 255, 99, 120, 111, 4, 222, 157, 40, 118, 6, 0, 0, 0][..]);
1078    ///
1079    /// let mut decoder = MultiDecoder::new(&encoded_data[..]).unwrap();
1080    /// let mut buf = Vec::new();
1081    /// decoder.read_to_end(&mut buf).unwrap();
1082    ///
1083    /// assert_eq!(buf, b"Hello World!");
1084    /// ```
1085    pub fn new(inner: R) -> io::Result<Self> {
1086        let decoder = Decoder::new(inner)?;
1087        Ok(MultiDecoder {
1088            decoder,
1089            eos: false,
1090        })
1091    }
1092
1093    /// Returns the header of the current member in the GZIP stream.
1094    ///
1095    /// # Examples
1096    /// ```
1097    /// use libflate::gzip::{MultiDecoder, Os};
1098    ///
1099    /// let encoded_data = [31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255,
1100    ///                     72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33,
1101    ///                     163, 28, 41, 28, 12, 0, 0, 0];
1102    ///
1103    /// let decoder = MultiDecoder::new(&encoded_data[..]).unwrap();
1104    /// assert_eq!(decoder.header().os(), Os::Unix);
1105    /// ```
1106    pub fn header(&self) -> &Header {
1107        self.decoder.header()
1108    }
1109
1110    /// Returns the immutable reference to the inner stream.
1111    pub fn as_inner_ref(&self) -> &R {
1112        self.decoder.as_inner_ref()
1113    }
1114
1115    /// Returns the mutable reference to the inner stream.
1116    pub fn as_inner_mut(&mut self) -> &mut R {
1117        self.decoder.as_inner_mut()
1118    }
1119
1120    /// Unwraps this `MultiDecoder`, returning the underlying reader.
1121    ///
1122    /// # Examples
1123    /// ```
1124    /// use no_std_io2::io::Cursor;
1125    /// use libflate::gzip::MultiDecoder;
1126    ///
1127    /// let encoded_data = [31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255,
1128    ///                     72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33,
1129    ///                     163, 28, 41, 28, 12, 0, 0, 0];
1130    ///
1131    /// let decoder = MultiDecoder::new(Cursor::new(&encoded_data[..])).unwrap();
1132    /// assert_eq!(decoder.into_inner().into_inner(), &encoded_data[..]);
1133    /// ```
1134    pub fn into_inner(self) -> R {
1135        self.decoder.into_inner()
1136    }
1137}
1138impl<R> io::Read for MultiDecoder<R>
1139where
1140    R: io::Read,
1141{
1142    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1143        if self.eos {
1144            return Ok(0);
1145        }
1146
1147        let read_size = self.decoder.read(buf)?;
1148        if read_size == 0 {
1149            match Header::read_from(self.as_inner_mut()) {
1150                Err(e) => {
1151                    if e.kind() == io::ErrorKind::UnexpectedEof {
1152                        self.eos = true;
1153                        Ok(0)
1154                    } else {
1155                        Err(e)
1156                    }
1157                }
1158                Ok(header) => {
1159                    self.decoder.reset(header);
1160                    self.read(buf)
1161                }
1162            }
1163        } else {
1164            Ok(read_size)
1165        }
1166    }
1167}
1168
1169#[cfg(test)]
1170mod tests {
1171    use super::*;
1172    use crate::finish::AutoFinish;
1173    use alloc::{vec, vec::Vec};
1174    use no_std_io2::io::{Read, Write};
1175
1176    fn decode(buf: &[u8]) -> io::Result<Vec<u8>> {
1177        let mut decoder = Decoder::new(buf).unwrap();
1178        let mut buf = Vec::with_capacity(buf.len());
1179        decoder.read_to_end(&mut buf)?;
1180        Ok(buf)
1181    }
1182
1183    fn decode_multi(buf: &[u8]) -> io::Result<Vec<u8>> {
1184        let mut decoder = MultiDecoder::new(buf).unwrap();
1185        let mut buf = Vec::with_capacity(buf.len());
1186        decoder.read_to_end(&mut buf).unwrap();
1187        Ok(buf)
1188    }
1189
1190    fn encode(text: &[u8]) -> io::Result<Vec<u8>> {
1191        let mut encoder = Encoder::new(Vec::new()).unwrap();
1192        encoder.write_all(text).unwrap();
1193        encoder.finish().into_result()
1194    }
1195
1196    #[test]
1197    fn encode_works() {
1198        let plain = b"Hello World! Hello GZIP!!";
1199        let mut encoder = Encoder::new(Vec::new()).unwrap();
1200        encoder.write_all(plain.as_ref()).unwrap();
1201        let encoded = encoder.finish().into_result().unwrap();
1202        assert_eq!(decode(&encoded).unwrap(), plain);
1203    }
1204
1205    #[test]
1206    fn encoder_auto_finish_works() {
1207        let plain = b"Hello World! Hello GZIP!!";
1208        let mut buf = Vec::new();
1209        {
1210            let mut encoder = AutoFinish::new(Encoder::new(&mut buf).unwrap());
1211            encoder.write_all(plain.as_ref()).unwrap();
1212        }
1213        assert_eq!(decode(&buf).unwrap(), plain);
1214    }
1215
1216    #[test]
1217    fn multi_decode_works() {
1218        use core::iter;
1219        let text = b"Hello World!";
1220        let encoded: Vec<u8> = iter::repeat(encode(text).unwrap())
1221            .take(2)
1222            .flat_map(|b| b)
1223            .collect();
1224        assert_eq!(decode(&encoded).unwrap(), b"Hello World!");
1225        assert_eq!(decode_multi(&encoded).unwrap(), b"Hello World!Hello World!");
1226    }
1227
1228    #[test]
1229    /// See: https://github.com/sile/libflate/issues/15 and https://github.com/RazrFalcon/usvg/issues/20
1230    fn issue_15_1() {
1231        let data = b"\x1F\x8B\x08\xC1\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x80\x80\x80\x80\x7B\x7B\x7B\x7B\x7B\x7B\x97\x7B\x7B\x7B\x86\x27\xEB\x60\xA7\xA8\x46\x6E\x1F\x33\x51\x5C\x34\xE0\xD2\x2E\xE8\x0C\x19\x1D\x3D\x3C\xFD\x3B\x6A\xFA\x63\xDF\x28\x87\x86\xF2\xA6\xAC\x87\x86\xF2\xA6\xAC\xD5";
1232        assert!(decode(&data[..]).is_err());
1233    }
1234
1235    #[test]
1236    /// See: https://github.com/sile/libflate/issues/15 and https://github.com/RazrFalcon/usvg/issues/21
1237    fn issue_15_2() {
1238        let data = b"\x1F\x8B\x08\xC1\x7B\x7B\x7B\x7B\x7B\xFC\x5D\x2D\xDC\x08\xC1\x7B\x7B\x7B\x7B\x7B\xFC\x5D\x2D\xDC\x08\xC1\x7B\x7F\x7B\x7B\x7B\xFC\x5D\x2D\xDC\x69\x32\x48\x22\x5A\x81\x81\x42\x42\x81\x7E\x81\x81\x81\x81\xF2\x17";
1239        assert!(decode(&data[..]).is_err());
1240    }
1241
1242    #[test]
1243    /// See: https://github.com/sile/libflate/issues/15 and https://github.com/RazrFalcon/usvg/issues/22
1244    fn issue_15_3() {
1245        let data = b"\x1F\x8B\x08\xC1\x91\x28\x71\xDC\xF2\x2D\x34\x35\x31\x35\x34\x30\x70\x6E\x60\x35\x31\x32\x32\x33\x32\x33\x37\x32\x36\x38\xDD\x1C\xE5\x2A\xDD\xDD\xDD\x22\xDD\xDD\xDD\xDC\x88\x13\xC9\x40\x60\xA7";
1246        assert!(decode(&data[..]).is_err());
1247    }
1248
1249    #[test]
1250    /// See: https://github.com/sile/libflate/issues/61
1251    fn issue_61() {
1252        let data = encode(b"Hello World").unwrap();
1253        let mut decoder = Decoder::new(&data[..]).unwrap();
1254        let mut buf = Vec::new();
1255        decoder.read(&mut buf).unwrap();
1256        decoder.read_to_end(&mut buf).unwrap();
1257        assert_eq!(buf, b"Hello World");
1258    }
1259
1260    #[test]
1261    fn extra_field() {
1262        let f = ExtraField {
1263            subfields: vec![ExtraSubField {
1264                id: [0, 0x42],
1265                data: "abc".into(),
1266            }],
1267        };
1268
1269        let mut buf = Vec::new();
1270        f.write_to(&mut buf).unwrap();
1271
1272        assert_eq!(ExtraField::read_from(&buf[..]).unwrap(), f);
1273    }
1274
1275    #[test]
1276    #[cfg(feature = "std")]
1277    fn encode_with_extra_field() {
1278        use std::io;
1279
1280        let mut buf = Vec::new();
1281        let extra_field = ExtraField {
1282            subfields: vec![ExtraSubField {
1283                id: [0, 0x42],
1284                data: "abc".into(),
1285            }],
1286        };
1287        {
1288            // encode
1289            let header = HeaderBuilder::new()
1290                .extra_field(extra_field.clone())
1291                .finish();
1292
1293            let ops = EncodeOptions::new().header(header);
1294            let mut encoder = Encoder::with_options(&mut buf, ops).unwrap();
1295            write!(encoder, "hello world").unwrap();
1296            encoder.finish().as_result().unwrap();
1297        }
1298        {
1299            // decode
1300            let mut decoder = Decoder::new(&buf[..]).unwrap();
1301            io::copy(&mut decoder, &mut io::sink()).unwrap();
1302            assert_eq!(decoder.header().extra_field(), Some(&extra_field));
1303        }
1304    }
1305}