compression_codecs/lz4/
decoder.rs

1use crate::DecodeV2;
2use compression_core::{
3    unshared::Unshared,
4    util::{PartialBuffer, WriteBuffer},
5};
6use lz4::liblz4::{
7    check_error, LZ4FDecompressionContext, LZ4F_createDecompressionContext, LZ4F_decompress,
8    LZ4F_freeDecompressionContext, LZ4F_resetDecompressionContext, LZ4F_VERSION,
9};
10use std::io::Result;
11
12#[derive(Debug)]
13struct DecoderContext {
14    ctx: LZ4FDecompressionContext,
15}
16
17#[derive(Debug)]
18pub struct Lz4Decoder {
19    ctx: Unshared<DecoderContext>,
20    stream_ended: bool,
21}
22
23impl DecoderContext {
24    fn new() -> Result<Self> {
25        let mut context = LZ4FDecompressionContext(core::ptr::null_mut());
26        check_error(unsafe { LZ4F_createDecompressionContext(&mut context, LZ4F_VERSION) })?;
27        Ok(Self { ctx: context })
28    }
29}
30
31impl Drop for DecoderContext {
32    fn drop(&mut self) {
33        unsafe { LZ4F_freeDecompressionContext(self.ctx) };
34    }
35}
36
37impl Default for Lz4Decoder {
38    fn default() -> Self {
39        Self {
40            ctx: Unshared::new(DecoderContext::new().unwrap()),
41            stream_ended: false,
42        }
43    }
44}
45
46impl Lz4Decoder {
47    pub fn new() -> Self {
48        Self::default()
49    }
50}
51
52impl DecodeV2 for Lz4Decoder {
53    fn reinit(&mut self) -> Result<()> {
54        unsafe { LZ4F_resetDecompressionContext(self.ctx.get_mut().ctx) };
55        self.stream_ended = false;
56        Ok(())
57    }
58
59    fn decode(
60        &mut self,
61        input: &mut PartialBuffer<&[u8]>,
62        output: &mut WriteBuffer<'_>,
63    ) -> Result<bool> {
64        let out_buf = output.initialize_unwritten();
65
66        let mut output_size = out_buf.len();
67        let mut input_size = input.unwritten().len();
68        let result = unsafe {
69            check_error(LZ4F_decompress(
70                self.ctx.get_mut().ctx,
71                out_buf.as_mut_ptr(),
72                &mut output_size,
73                input.unwritten().as_ptr(),
74                &mut input_size,
75                core::ptr::null(),
76            ))
77        };
78        input.advance(input_size);
79        output.advance(output_size);
80
81        let finished = result? == 0;
82        if finished {
83            self.stream_ended = true;
84        }
85        Ok(finished)
86    }
87
88    fn flush(&mut self, output: &mut WriteBuffer<'_>) -> Result<bool> {
89        self.decode(&mut PartialBuffer::new(&[][..]), output)?;
90
91        loop {
92            let old_len = output.written_len();
93            self.decode(&mut PartialBuffer::new(&[][..]), output)?;
94            if output.written_len() == old_len {
95                break;
96            }
97        }
98
99        Ok(!output.has_no_spare_space())
100    }
101
102    fn finish(&mut self, output: &mut WriteBuffer<'_>) -> Result<bool> {
103        self.flush(output)?;
104
105        if self.stream_ended {
106            Ok(true)
107        } else {
108            Err(std::io::Error::new(
109                std::io::ErrorKind::UnexpectedEof,
110                "lz4 stream did not finish",
111            ))
112        }
113    }
114}