compression_codecs/lz4/
decoder.rs1use 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 mut input_size = input.unwritten().len();
65
66 let result = unsafe {
69 let out_buf = output.unwritten_mut();
70
71 let mut output_size = out_buf.len();
72
73 let result = check_error(LZ4F_decompress(
74 self.ctx.get_mut().ctx,
75 out_buf.as_mut_ptr() as *mut _,
76 &mut output_size,
77 input.unwritten().as_ptr(),
78 &mut input_size,
79 core::ptr::null(),
80 ));
81 output.assume_init_and_advance(output_size);
82
83 result
84 };
85 input.advance(input_size);
86
87 let finished = result? == 0;
88 if finished {
89 self.stream_ended = true;
90 }
91 Ok(finished)
92 }
93
94 fn flush(&mut self, output: &mut WriteBuffer<'_>) -> Result<bool> {
95 self.decode(&mut PartialBuffer::new(&[][..]), output)?;
96
97 loop {
98 let old_len = output.written_len();
99 self.decode(&mut PartialBuffer::new(&[][..]), output)?;
100 if output.written_len() == old_len {
101 break;
102 }
103 }
104
105 Ok(!output.has_no_spare_space())
106 }
107
108 fn finish(&mut self, output: &mut WriteBuffer<'_>) -> Result<bool> {
109 self.flush(output)?;
110
111 if self.stream_ended {
112 Ok(true)
113 } else {
114 Err(std::io::Error::new(
115 std::io::ErrorKind::UnexpectedEof,
116 "lz4 stream did not finish",
117 ))
118 }
119 }
120}