brotlic/
decode.rs

1//! Module that contains the brotli decoder instances
2//!
3//! Contains decompression abstractions over [`Read`] and [`Write`] and a
4//! dedicated low-level encoder.
5//!
6//! [`Read`]: https://doc.rust-lang.org/stable/std/io/trait.Read.html
7//! [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
8
9use std::error::Error;
10use std::ffi::CStr;
11use std::io::{BufRead, Read, Write};
12use std::{fmt, io, ptr, slice};
13
14use brotlic_sys::*;
15
16use crate::{IntoInnerError, SetParameterError};
17
18/// A reference to a brotli decoder.
19///
20/// This decoder contains internal state of the decoding process. This low-level
21/// wrapper intended to be used for people who are familiar with the C API. For
22/// higher level abstractions, see [`DecompressorReader`] and
23/// [`DecompressorWriter`].
24pub struct BrotliDecoder {
25    state: *mut BrotliDecoderState,
26}
27
28unsafe impl Send for BrotliDecoder {}
29unsafe impl Sync for BrotliDecoder {}
30
31impl BrotliDecoder {
32    /// Constructs a new brotli decoder instance.
33    ///
34    /// # Panics
35    ///
36    /// Panics if the decoder fails to be allocated or initialized
37    #[doc(alias = "BrotliDecoderCreateInstance")]
38    pub fn new() -> Self {
39        let instance = unsafe { BrotliDecoderCreateInstance(None, None, ptr::null_mut()) };
40
41        if !instance.is_null() {
42            BrotliDecoder { state: instance }
43        } else {
44            panic!("BrotliDecoderCreateInstance returned NULL: failed to allocate or initialize");
45        }
46    }
47
48    /// Checks if the decoder instance reached its final state.
49    #[doc(alias = "BrotliDecoderIsFinished")]
50    pub fn is_finished(&self) -> bool {
51        unsafe { BrotliDecoderIsFinished(self.state) != 0 }
52    }
53
54    /// Decompresses the input stream to the output stream.
55    ///
56    /// This is a low-level API, for higher level abstractions see
57    /// [`DecompressorReader`] or [`DecompressorWriter`]. Returns the number of
58    /// bytes that were read, written and some additional information. Bytes are
59    /// read from `input`, the number of bytes read is returned in the
60    /// `bytes_read` field of the result. The `input` is never overconsumed, so
61    /// it could be passed to the next consumer after decoding is complete.
62    /// Bytes are written to `output`, the number of bytes written is returned
63    /// in the `bytes_written` field of the result. The `info` field of the
64    /// result communicates the state of the decoding process.
65    ///
66    /// if `info` is [`DecoderInfo::NeedsMoreInput`], more input is required to
67    /// continue decoding. Likewise, if `info` is
68    /// [`DecoderInfo::NeedsMoreOutput`], more output is required to continue
69    /// the decoding conversion. [`DecoderInfo::Finished`] indicates that the
70    /// decoding has finished.
71    #[doc(alias = "BrotliDecoderDecompressStream")]
72    pub fn decompress(
73        &mut self,
74        input: &[u8],
75        output: &mut [u8],
76    ) -> Result<DecodeResult, DecodeError> {
77        let mut input_ptr = input.as_ptr();
78        let mut input_len = input.len();
79        let mut output_ptr = output.as_mut_ptr();
80        let mut output_len = output.len();
81
82        let result = unsafe {
83            BrotliDecoderDecompressStream(
84                self.state,
85                &mut input_len,
86                &mut input_ptr,
87                &mut output_len,
88                &mut output_ptr,
89                ptr::null_mut(),
90            )
91        };
92
93        let bytes_read = input.len() - input_len;
94        let bytes_written = output.len() - output_len;
95
96        #[allow(non_upper_case_globals)]
97        let info = match result {
98            BrotliDecoderResult_BROTLI_DECODER_RESULT_ERROR => return Err(self.last_error()),
99            BrotliDecoderResult_BROTLI_DECODER_RESULT_SUCCESS => DecoderInfo::Finished,
100            BrotliDecoderResult_BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT => {
101                DecoderInfo::NeedsMoreInput
102            }
103            BrotliDecoderResult_BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT => {
104                DecoderInfo::NeedsMoreOutput
105            }
106            _ => panic!("BrotliDecoderDecompressStream returned an unknown error code"),
107        };
108
109        Ok(DecodeResult {
110            bytes_read,
111            bytes_written,
112            info,
113        })
114    }
115
116    /// Convenience function to call method [`Self::decompress`] with only
117    /// input.
118    pub fn give_input(&mut self, input: &[u8]) -> Result<(usize, DecoderInfo), DecodeError> {
119        let res = self.decompress(input, &mut [])?;
120
121        Ok((res.bytes_read, res.info))
122    }
123
124    /// Checks if the decoder has more output.
125    #[doc(alias = "BrotliDecoderHasMoreOutput")]
126    pub fn has_output(&self) -> bool {
127        unsafe { BrotliDecoderHasMoreOutput(self.state) != 0 }
128    }
129
130    /// Checks if the decoder has more output and if so, returns a slice to its
131    /// internal output buffer. Each byte returned from the slice is considered
132    /// "consumed" and must be used as it will not be returned again. Encoder
133    /// output is not guaranteed to be contagious, which means that this
134    /// function can return `Some(&[u8])` multiple times. Only when the method
135    /// returns `None` is when there is no more output available by the decoder.
136    ///
137    /// # Safety
138    ///
139    /// For every consecutive call of this function, the previous slice becomes
140    /// invalidated.
141    #[doc(alias = "BrotliDecoderTakeOutput")]
142    pub unsafe fn take_output(&mut self) -> Option<&[u8]> {
143        if self.has_output() {
144            let mut len: usize = 0;
145            let output = BrotliDecoderTakeOutput(self.state, &mut len as _);
146
147            Some(slice::from_raw_parts(output, len))
148        } else {
149            None
150        }
151    }
152
153    /// Returns the version of the C brotli decoder library.
154    #[doc(alias = "BrotliDecoderVersion")]
155    pub fn version() -> u32 {
156        unsafe { BrotliDecoderVersion() }
157    }
158
159    fn set_param(
160        &mut self,
161        param: BrotliDecoderParameter,
162        value: u32,
163    ) -> Result<(), SetParameterError> {
164        let r = unsafe { BrotliDecoderSetParameter(self.state, param, value) };
165
166        if r != 0 {
167            Ok(())
168        } else {
169            Err(SetParameterError::Generic)
170        }
171    }
172
173    fn last_error(&self) -> DecodeError {
174        let ec = unsafe { BrotliDecoderGetErrorCode(self.state) };
175
176        #[allow(non_upper_case_globals)]
177        match ec {
178            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE => {
179                DecodeError::FormatExuberantNibble
180            }
181            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_RESERVED => {
182                DecodeError::FormatReserved
183            }
184            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE => {
185                DecodeError::FormatExuberantMetaNibble
186            }
187            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET => {
188                DecodeError::FormatSimpleHuffmanAlphabet
189            }
190            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME => {
191                DecodeError::FormatSimpleHuffmanSame
192            }
193            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_CL_SPACE => {
194                DecodeError::FormatClSpace
195            }
196            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE => {
197                DecodeError::FormatHuffmanSpace
198            }
199            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT => {
200                DecodeError::FormatContextMapRepeat
201            }
202            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1 => {
203                DecodeError::FormatBlockLength1
204            }
205            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2 => {
206                DecodeError::FormatBlockLength2
207            }
208            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_TRANSFORM => {
209                DecodeError::FormatTransform
210            }
211            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_DICTIONARY => {
212                DecodeError::FormatDictionary
213            }
214            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS => {
215                DecodeError::FormatWindowBits
216            }
217            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_PADDING_1 => {
218                DecodeError::FormatPadding1
219            }
220            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_PADDING_2 => {
221                DecodeError::FormatPadding2
222            }
223            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_DISTANCE => {
224                DecodeError::FormatDistance
225            }
226            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY => {
227                DecodeError::CompoundDictionary
228            }
229            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET => {
230                DecodeError::DictionaryNotSet
231            }
232            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_INVALID_ARGUMENTS => {
233                DecodeError::InvalidArguments
234            }
235            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES => {
236                DecodeError::AllocContextModes
237            }
238            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS => {
239                DecodeError::AllocTreeGroups
240            }
241            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP => {
242                DecodeError::AllocContextMap
243            }
244            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1 => {
245                DecodeError::AllocRingBuffer1
246            }
247            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2 => {
248                DecodeError::AllocRingBuffer2
249            }
250            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES => {
251                DecodeError::AllocBlockTypeTrees
252            }
253            BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_UNREACHABLE => DecodeError::Unreachable,
254            _ => DecodeError::UnknownError,
255        }
256    }
257}
258
259impl fmt::Debug for BrotliDecoder {
260    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261        f.debug_struct("BrotliDecoder")
262            .field("state", &self.state)
263            .finish_non_exhaustive()
264    }
265}
266
267impl Default for BrotliDecoder {
268    fn default() -> Self {
269        BrotliDecoder::new()
270    }
271}
272
273impl Drop for BrotliDecoder {
274    fn drop(&mut self) {
275        unsafe {
276            BrotliDecoderDestroyInstance(self.state);
277        }
278    }
279}
280
281/// Decompression options to be used for a [`BrotliDecoder`].
282///
283/// # Examples
284///
285/// Building an decoder that supports large window sizes:
286/// ```
287/// use brotlic::BrotliDecoderOptions;
288///
289/// let encoder = BrotliDecoderOptions::new().large_window_size(true).build();
290/// ```
291#[derive(Debug, Clone)]
292pub struct BrotliDecoderOptions {
293    disable_ring_buffer_reallocation: Option<bool>,
294    large_window_size: Option<bool>,
295}
296
297impl BrotliDecoderOptions {
298    /// Creates a new blank set decoder options.
299    ///
300    /// initially no modifications are applied to the decoder and everything is
301    /// set to its default values.
302    pub fn new() -> Self {
303        BrotliDecoderOptions {
304            disable_ring_buffer_reallocation: None,
305            large_window_size: None,
306        }
307    }
308
309    /// Disable "canny" ring buffer allocation strategy.
310    ///
311    /// Ring buffer is allocated according to window size, despite the real size
312    /// of the content.
313    pub fn disable_ring_buffer_reallocation(
314        &mut self,
315        disable_ring_buffer_reallocation: bool,
316    ) -> &mut Self {
317        self.disable_ring_buffer_reallocation = Some(disable_ring_buffer_reallocation);
318        self
319    }
320
321    /// Flag that determines if this decoder supports non standard large window
322    /// sizes. By default, this is turned off and window sizes are limited by
323    /// RFC7932 (Brotli proper). To support large window sizes outside of the
324    /// specification, this flag must be enabled. For more information see
325    /// [`LargeWindowSize`].
326    ///
327    /// [`LargeWindowSize`]: crate::LargeWindowSize
328    pub fn large_window_size(&mut self, large_window_size: bool) -> &mut Self {
329        self.large_window_size = Some(large_window_size);
330        self
331    }
332
333    /// Creates a brotli decoder using the specified settings.
334    ///
335    /// # Errors
336    ///
337    /// If any of the preconditions of the parameters are violated, an error is
338    /// returned.
339    #[doc(alias = "BrotliDecoderSetParameter")]
340    pub fn build(&self) -> Result<BrotliDecoder, SetParameterError> {
341        let mut decoder = BrotliDecoder::new();
342
343        self.configure(&mut decoder)?;
344
345        Ok(decoder)
346    }
347
348    fn configure(&self, decoder: &mut BrotliDecoder) -> Result<(), SetParameterError> {
349        if let Some(disable_ring_buffer_reallocation) = self.disable_ring_buffer_reallocation {
350            let key = BrotliDecoderParameter_BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION;
351            let value = disable_ring_buffer_reallocation as u32;
352
353            decoder.set_param(key, value)?;
354        }
355
356        if let Some(large_window_size) = self.large_window_size {
357            let key = BrotliDecoderParameter_BROTLI_DECODER_PARAM_LARGE_WINDOW;
358            let value = large_window_size as u32;
359
360            decoder.set_param(key, value)?;
361        }
362
363        Ok(())
364    }
365}
366
367impl Default for BrotliDecoderOptions {
368    fn default() -> Self {
369        BrotliDecoderOptions::new()
370    }
371}
372
373/// A struct used by [`BrotliDecoder::decompress`].
374#[derive(Debug, Copy, Clone, Eq, PartialEq)]
375pub struct DecodeResult {
376    /// The number of bytes read from `input`.
377    pub bytes_read: usize,
378    /// The number of bytes written to `output`.
379    pub bytes_written: usize,
380    /// Information the decoder gave on whether its finished or needs more input
381    /// or output.
382    pub info: DecoderInfo,
383}
384
385/// Additional information provided by the decoder on how decompression should
386/// proceed.
387#[derive(Debug, Copy, Clone, Eq, PartialEq)]
388pub enum DecoderInfo {
389    /// The decoder has finished decompressing all input data.
390    Finished,
391    /// The decoder needs more input to proceed decompression.
392    NeedsMoreInput,
393    /// The decoder needs more output to proceed decompression.
394    NeedsMoreOutput,
395}
396
397/// An error returned by [`BrotliDecoder::decompress`].
398#[derive(Debug, Copy, Clone, Eq, PartialEq)]
399#[non_exhaustive]
400#[allow(missing_docs)]
401pub enum DecodeError {
402    UnknownError = 0,
403    FormatExuberantNibble =
404        BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE as isize,
405    FormatReserved = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_RESERVED as isize,
406    FormatExuberantMetaNibble =
407        BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE as isize,
408    FormatSimpleHuffmanAlphabet =
409        BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET as isize,
410    FormatSimpleHuffmanSame =
411        BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME as isize,
412    FormatClSpace = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_CL_SPACE as isize,
413    FormatHuffmanSpace = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE as isize,
414    FormatContextMapRepeat =
415        BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT as isize,
416    FormatBlockLength1 = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1 as isize,
417    FormatBlockLength2 = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2 as isize,
418    FormatTransform = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_TRANSFORM as isize,
419    FormatDictionary = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_DICTIONARY as isize,
420    FormatWindowBits = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS as isize,
421    FormatPadding1 = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_PADDING_1 as isize,
422    FormatPadding2 = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_PADDING_2 as isize,
423    FormatDistance = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_FORMAT_DISTANCE as isize,
424    CompoundDictionary = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY as isize,
425    DictionaryNotSet = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET as isize,
426    InvalidArguments = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_INVALID_ARGUMENTS as isize,
427    AllocContextModes = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES as isize,
428    AllocTreeGroups = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS as isize,
429    AllocContextMap = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP as isize,
430    AllocRingBuffer1 = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1 as isize,
431    AllocRingBuffer2 = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2 as isize,
432    AllocBlockTypeTrees =
433        BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES as isize,
434    Unreachable = BrotliDecoderErrorCode_BROTLI_DECODER_ERROR_UNREACHABLE as isize,
435}
436
437impl Error for DecodeError {}
438
439impl fmt::Display for DecodeError {
440    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441        if *self == DecodeError::UnknownError {
442            write!(f, "decode error: unknown error")
443        } else {
444            let str = unsafe {
445                let error_code = *self as BrotliDecoderErrorCode;
446                let error_string = BrotliDecoderErrorString(error_code);
447                let c_str = CStr::from_ptr(error_string);
448                c_str
449                    .to_str()
450                    .expect("invalid utf-8 returned from BrotliDecoderErrorString")
451            };
452
453            write!(f, "brotli decoder error: {}", str)
454        }
455    }
456}
457
458impl From<DecodeError> for io::Error {
459    fn from(err: DecodeError) -> Self {
460        io::Error::new(io::ErrorKind::Other, err)
461    }
462}
463
464/// Wraps a reader and decompresses its output.
465///
466/// # Examples
467///
468/// Suppose the file `test.brotli` contains brotli compressed data. Let's try to
469/// decompress it:
470///
471/// ```no_run
472/// use std::fs::File;
473/// use std::io::Read;
474///
475/// use brotlic::DecompressorWriter;
476///
477/// let mut input = File::open("test.brotli")?; // test.brotli is brotli compressed
478/// let mut output = String::new();
479///
480/// input.read_to_string(&mut output)?;
481///
482/// println!("Decompressed text: {}", output);
483///
484/// # Ok::<(), std::io::Error>(())
485/// ```
486#[derive(Debug)]
487pub struct DecompressorReader<R: BufRead> {
488    inner: R,
489    decoder: BrotliDecoder,
490}
491
492impl<R: BufRead> DecompressorReader<R> {
493    /// Creates a new `DecompressorReader<R>` with a newly created decoder.
494    ///
495    /// # Panics
496    ///
497    /// Panics if the decoder fails to be allocated or initialized
498    pub fn new(inner: R) -> Self {
499        DecompressorReader {
500            inner,
501            decoder: BrotliDecoder::new(),
502        }
503    }
504
505    /// Creates a new `DecompressorReader<R>` with a specified decoder.
506    ///
507    /// # Examples
508    ///
509    /// ```
510    /// use std::io::Read;
511    ///
512    /// use brotlic::{BrotliDecoderOptions, DecompressorReader};
513    ///
514    /// let decoder = BrotliDecoderOptions::new()
515    ///     .disable_ring_buffer_reallocation(true)
516    ///     .build()?;
517    ///
518    /// let source = [11, 2, 128, 104, 101, 108, 108, 111, 3]; // decompresses to "hello"
519    /// let mut decompressor = DecompressorReader::with_decoder(decoder, source.as_slice());
520    /// # Ok::<(), brotlic::SetParameterError>(())
521    /// ```
522    pub fn with_decoder(decoder: BrotliDecoder, inner: R) -> Self {
523        DecompressorReader { inner, decoder }
524    }
525
526    /// Gets a reference to the underlying reader
527    pub fn get_ref(&self) -> &R {
528        &self.inner
529    }
530
531    /// Gets a mutable reference to the underlying reader.
532    ///
533    /// It is inadvisable to directly read from the underlying reader.
534    pub fn get_mut(&mut self) -> &mut R {
535        &mut self.inner
536    }
537
538    /// Unwraps this `DecompressorReader<R>`, returning the underlying reader.
539    ///
540    /// # Errors
541    ///
542    /// An [`Err`] will be returned if the decompression stream has not been
543    /// finished.
544    pub fn into_inner(self) -> Result<R, IntoInnerError<DecompressorReader<R>>> {
545        if self.decoder.is_finished() {
546            Ok(self.inner)
547        } else {
548            Err(IntoInnerError::new(
549                self,
550                io::ErrorKind::UnexpectedEof.into(),
551            ))
552        }
553    }
554
555    /// Disassembles this `DecompressorReader<R>`, returning the underlying
556    /// reader and decoder.
557    ///
558    /// `into_parts` makes no attempt to validate that the decompression stream
559    /// finished and cannot fail.
560    pub fn into_parts(self) -> (R, BrotliDecoder) {
561        (self.inner, self.decoder)
562    }
563}
564
565impl<R: BufRead> Read for DecompressorReader<R> {
566    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
567        loop {
568            let input = self.inner.fill_buf()?;
569            let eof = input.is_empty();
570            let DecodeResult {
571                bytes_read,
572                bytes_written,
573                info,
574            } = self.decoder.decompress(input, buf)?;
575            self.inner.consume(bytes_read);
576
577            match info {
578                _ if bytes_written > 0 => return Ok(bytes_written),
579                DecoderInfo::Finished => return Ok(0),
580                DecoderInfo::NeedsMoreInput if eof => {
581                    return Err(io::ErrorKind::UnexpectedEof.into());
582                }
583                DecoderInfo::NeedsMoreInput => continue,
584                DecoderInfo::NeedsMoreOutput if buf.is_empty() => return Ok(0),
585                DecoderInfo::NeedsMoreOutput => panic!(
586                    "decoder needs output despite not giving any while having the chance to do so"
587                ),
588            };
589        }
590    }
591}
592
593/// Wraps a writer and decompresses its output.
594///
595/// `DecompressorWriter<R>` wraps a writer and adds brotli decompression to the
596/// output.
597///
598/// # Examples
599///
600/// Let's decompress the `test.brotli` file shown in [`CompressorWriter`]:
601///
602/// ```no_run
603/// use std::fs::File;
604/// use std::io;
605///
606/// use brotlic::DecompressorWriter;
607///
608/// let mut input = File::open("test.brotli")?; // test.brotli is brotli compressed
609/// let mut output = File::create("test_reconstructed.txt")?;
610/// let mut decompressed_output = DecompressorWriter::new(output);
611///
612/// io::copy(&mut input, &mut decompressed_output)?;
613///
614/// # Ok::<(), io::Error>(())
615/// ```
616///
617/// [`CompressorWriter`]: crate::encode::CompressorWriter
618#[derive(Debug)]
619pub struct DecompressorWriter<W: Write> {
620    inner: W,
621    decoder: BrotliDecoder,
622    panicked: bool,
623}
624
625impl<W: Write> DecompressorWriter<W> {
626    /// Creates a new `DecompressorWriter<W>` with a newly created decoder.
627    ///
628    /// # Panics
629    ///
630    /// Panics if the decoder fails to be allocated or initialized
631    pub fn new(inner: W) -> DecompressorWriter<W> {
632        DecompressorWriter {
633            inner,
634            decoder: BrotliDecoder::new(),
635            panicked: false,
636        }
637    }
638
639    /// Creates a new `DecompressorWriter<W>` with a specified decoder.
640    ///
641    /// # Examples
642    ///
643    /// ```
644    /// use std::io::Write;
645    ///
646    /// use brotlic::{BrotliDecoderOptions, DecompressorReader, DecompressorWriter};
647    ///
648    /// let decoder = BrotliDecoderOptions::new()
649    ///     .large_window_size(true)
650    ///     .build()?;
651    ///
652    /// let mut writer = DecompressorWriter::with_decoder(decoder, Vec::new());
653    /// # Ok::<(), brotlic::SetParameterError>(())
654    /// ```
655    pub fn with_decoder(decoder: BrotliDecoder, inner: W) -> Self {
656        DecompressorWriter {
657            inner,
658            decoder,
659            panicked: false,
660        }
661    }
662
663    /// Gets a reference to the underlying writer
664    pub fn get_ref(&self) -> &W {
665        &self.inner
666    }
667
668    /// Gets a mutable reference to the underlying writer.
669    ///
670    /// It is inadvisable to directly write to the underlying writer.
671    pub fn get_mut(&mut self) -> &mut W {
672        &mut self.inner
673    }
674
675    /// Unwraps this `DecompressorWriter<W>`, returning the underlying writer.
676    ///
677    /// If the decompression stream is validated before finishing and will
678    /// return an [`Err`] otherwise. The `DecompressorWriter<W>` will not
679    /// overcome its input, if an adjacent second compression stream follows it
680    /// can be read by another `DecompressorWriter<W>` without length-prefixing.
681    ///
682    /// # Errors
683    ///
684    /// An [`Err`] will be returned if the decompression stream has not been
685    /// finished.
686    pub fn into_inner(self) -> Result<W, IntoInnerError<DecompressorWriter<W>>> {
687        if self.decoder.is_finished() {
688            Ok(self.into_parts().0)
689        } else {
690            Err(IntoInnerError::new(
691                self,
692                io::ErrorKind::UnexpectedEof.into(),
693            ))
694        }
695    }
696
697    /// Disassembles this `DecompressorWriter<W>`, returning the underlying
698    /// writer and decoder.
699    ///
700    /// If the underlying writer panicked, it is not known what portion of the
701    /// data was written. In this case, we return `WriterPanicked` to get the
702    /// encoder back.
703    ///
704    /// `into_parts` makes no attempt to validate that the decompression stream
705    /// finished and cannot fail.
706    pub fn into_parts(self) -> (W, Result<BrotliDecoder, WriterPanicked>) {
707        let inner = self.inner;
708        let decoder = self.decoder;
709
710        let decoder = if !self.panicked {
711            Ok(decoder)
712        } else {
713            Err(WriterPanicked { decoder })
714        };
715
716        (inner, decoder)
717    }
718
719    fn flush_decoder_output(&mut self) -> io::Result<()> {
720        while let Some(output) = unsafe { self.decoder.take_output() } {
721            self.panicked = true;
722            let r = self.inner.write_all(output);
723            self.panicked = false;
724            r?;
725        }
726
727        Ok(())
728    }
729}
730
731impl<W: Write> Write for DecompressorWriter<W> {
732    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
733        let (bytes_read, _decoder_result) = self.decoder.give_input(buf)?;
734        self.flush_decoder_output()?;
735
736        Ok(bytes_read)
737    }
738
739    fn flush(&mut self) -> io::Result<()> {
740        self.inner.flush()
741    }
742}
743
744/// Error returned from [`DecompressorWriter::into_inner`], when the underlying
745/// writer has previously panicked. Contains the decoder that was used for
746/// decompression.
747#[derive(Debug)]
748pub struct WriterPanicked {
749    decoder: BrotliDecoder,
750}
751
752impl WriterPanicked {
753    /// Returns the decoder that was used for decompression. It is unknown what
754    /// data was fed to the decoder, so simply using it to finish it is not a
755    /// good idea.
756    pub fn into_inner(self) -> BrotliDecoder {
757        self.decoder
758    }
759}
760
761impl Error for WriterPanicked {}
762
763impl fmt::Display for WriterPanicked {
764    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
765        f.write_str(
766            "DecompressorWriter inner writer panicked, what data remains unwritten is not known",
767        )
768    }
769}