1 | use super::{decodebuffer::DecodeBufferError, scratch::DecoderScratch}; |
2 | |
3 | #[derive (Debug)] |
4 | #[non_exhaustive ] |
5 | pub enum ExecuteSequencesError { |
6 | DecodebufferError(DecodeBufferError), |
7 | NotEnoughBytesForSequence { wanted: usize, have: usize }, |
8 | ZeroOffset, |
9 | } |
10 | |
11 | impl core::fmt::Display for ExecuteSequencesError { |
12 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
13 | match self { |
14 | ExecuteSequencesError::DecodebufferError(e: &DecodeBufferError) => { |
15 | write!(f, " {:?}" , e) |
16 | } |
17 | ExecuteSequencesError::NotEnoughBytesForSequence { wanted: &usize, have: &usize } => { |
18 | write!( |
19 | f, |
20 | "Sequence wants to copy up to byte {}. Bytes in literalsbuffer: {}" , |
21 | wanted, have |
22 | ) |
23 | } |
24 | ExecuteSequencesError::ZeroOffset => { |
25 | write!(f, "Illegal offset: 0 found" ) |
26 | } |
27 | } |
28 | } |
29 | } |
30 | |
31 | #[cfg (feature = "std" )] |
32 | impl std::error::Error for ExecuteSequencesError { |
33 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
34 | match self { |
35 | ExecuteSequencesError::DecodebufferError(source: &DecodeBufferError) => Some(source), |
36 | _ => None, |
37 | } |
38 | } |
39 | } |
40 | |
41 | impl From<DecodeBufferError> for ExecuteSequencesError { |
42 | fn from(val: DecodeBufferError) -> Self { |
43 | Self::DecodebufferError(val) |
44 | } |
45 | } |
46 | |
47 | /// Take the provided decoder and execute the sequences stored within |
48 | pub fn execute_sequences(scratch: &mut DecoderScratch) -> Result<(), ExecuteSequencesError> { |
49 | let mut literals_copy_counter = 0; |
50 | let old_buffer_size = scratch.buffer.len(); |
51 | let mut seq_sum = 0; |
52 | |
53 | for idx in 0..scratch.sequences.len() { |
54 | let seq = scratch.sequences[idx]; |
55 | |
56 | if seq.ll > 0 { |
57 | let high = literals_copy_counter + seq.ll as usize; |
58 | if high > scratch.literals_buffer.len() { |
59 | return Err(ExecuteSequencesError::NotEnoughBytesForSequence { |
60 | wanted: high, |
61 | have: scratch.literals_buffer.len(), |
62 | }); |
63 | } |
64 | let literals = &scratch.literals_buffer[literals_copy_counter..high]; |
65 | literals_copy_counter += seq.ll as usize; |
66 | |
67 | scratch.buffer.push(literals); |
68 | } |
69 | |
70 | let actual_offset = do_offset_history(seq.of, seq.ll, &mut scratch.offset_hist); |
71 | if actual_offset == 0 { |
72 | return Err(ExecuteSequencesError::ZeroOffset); |
73 | } |
74 | if seq.ml > 0 { |
75 | scratch |
76 | .buffer |
77 | .repeat(actual_offset as usize, seq.ml as usize)?; |
78 | } |
79 | |
80 | seq_sum += seq.ml; |
81 | seq_sum += seq.ll; |
82 | } |
83 | if literals_copy_counter < scratch.literals_buffer.len() { |
84 | let rest_literals = &scratch.literals_buffer[literals_copy_counter..]; |
85 | scratch.buffer.push(rest_literals); |
86 | seq_sum += rest_literals.len() as u32; |
87 | } |
88 | |
89 | let diff = scratch.buffer.len() - old_buffer_size; |
90 | assert!( |
91 | seq_sum as usize == diff, |
92 | "Seq_sum: {} is different from the difference in buffersize: {}" , |
93 | seq_sum, |
94 | diff |
95 | ); |
96 | Ok(()) |
97 | } |
98 | |
99 | /// Update the most recently used offsets to reflect the provided offset value, and return the |
100 | /// "actual" offset needed because offsets are not stored in a raw way, some transformations are needed |
101 | /// before you get a functional number. |
102 | fn do_offset_history(offset_value: u32, lit_len: u32, scratch: &mut [u32; 3]) -> u32 { |
103 | let actual_offset = if lit_len > 0 { |
104 | match offset_value { |
105 | 1..=3 => scratch[offset_value as usize - 1], |
106 | _ => { |
107 | //new offset |
108 | offset_value - 3 |
109 | } |
110 | } |
111 | } else { |
112 | match offset_value { |
113 | 1..=2 => scratch[offset_value as usize], |
114 | 3 => scratch[0] - 1, |
115 | _ => { |
116 | //new offset |
117 | offset_value - 3 |
118 | } |
119 | } |
120 | }; |
121 | |
122 | //update history |
123 | if lit_len > 0 { |
124 | match offset_value { |
125 | 1 => { |
126 | //nothing |
127 | } |
128 | 2 => { |
129 | scratch[1] = scratch[0]; |
130 | scratch[0] = actual_offset; |
131 | } |
132 | _ => { |
133 | scratch[2] = scratch[1]; |
134 | scratch[1] = scratch[0]; |
135 | scratch[0] = actual_offset; |
136 | } |
137 | } |
138 | } else { |
139 | match offset_value { |
140 | 1 => { |
141 | scratch[1] = scratch[0]; |
142 | scratch[0] = actual_offset; |
143 | } |
144 | 2 => { |
145 | scratch[2] = scratch[1]; |
146 | scratch[1] = scratch[0]; |
147 | scratch[0] = actual_offset; |
148 | } |
149 | _ => { |
150 | scratch[2] = scratch[1]; |
151 | scratch[1] = scratch[0]; |
152 | scratch[0] = actual_offset; |
153 | } |
154 | } |
155 | } |
156 | |
157 | actual_offset |
158 | } |
159 | |