| 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 | |