1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
use super::{decodebuffer::DecodebufferError, scratch::DecoderScratch};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ExecuteSequencesError {
#[error(transparent)]
DecodebufferError(#[from] DecodebufferError),
#[error("Sequence wants to copy up to byte {wanted}. Bytes in literalsbuffer: {have}")]
NotEnoughBytesForSequence { wanted: usize, have: usize },
#[error("Illegal offset: 0 found")]
ZeroOffset,
}
pub fn execute_sequences(scratch: &mut DecoderScratch) -> Result<(), ExecuteSequencesError> {
let mut literals_copy_counter = 0;
let old_buffer_size = scratch.buffer.len();
let mut seq_sum = 0;
for idx in 0..scratch.sequences.len() {
let seq = scratch.sequences[idx];
if crate::VERBOSE {}
//println!("{}: {}", idx, seq);
if seq.ll > 0 {
let high = literals_copy_counter + seq.ll as usize;
if high > scratch.literals_buffer.len() {
return Err(ExecuteSequencesError::NotEnoughBytesForSequence {
wanted: high,
have: scratch.literals_buffer.len(),
});
}
let literals = &scratch.literals_buffer[literals_copy_counter..high];
literals_copy_counter += seq.ll as usize;
scratch.buffer.push(literals);
}
let actual_offset = do_offset_history(seq.of, seq.ll, &mut scratch.offset_hist);
if actual_offset == 0 {
return Err(ExecuteSequencesError::ZeroOffset);
}
if seq.ml > 0 {
scratch
.buffer
.repeat(actual_offset as usize, seq.ml as usize)?;
}
seq_sum += seq.ml;
seq_sum += seq.ll;
}
if literals_copy_counter < scratch.literals_buffer.len() {
let rest_literals = &scratch.literals_buffer[literals_copy_counter..];
scratch.buffer.push(rest_literals);
seq_sum += rest_literals.len() as u32;
}
let diff = scratch.buffer.len() - old_buffer_size;
assert!(
seq_sum as usize == diff,
"Seq_sum: {} is different from the difference in buffersize: {}",
seq_sum,
diff
);
Ok(())
}
fn do_offset_history(offset_value: u32, lit_len: u32, scratch: &mut [u32; 3]) -> u32 {
let actual_offset = if lit_len > 0 {
match offset_value {
1..=3 => scratch[offset_value as usize - 1],
_ => {
//new offset
offset_value - 3
}
}
} else {
match offset_value {
1..=2 => scratch[offset_value as usize],
3 => scratch[0] - 1,
_ => {
//new offset
offset_value - 3
}
}
};
//update history
if lit_len > 0 {
match offset_value {
1 => {
//nothing
}
2 => {
scratch[1] = scratch[0];
scratch[0] = actual_offset;
}
_ => {
scratch[2] = scratch[1];
scratch[1] = scratch[0];
scratch[0] = actual_offset;
}
}
} else {
match offset_value {
1 => {
scratch[1] = scratch[0];
scratch[0] = actual_offset;
}
2 => {
scratch[2] = scratch[1];
scratch[1] = scratch[0];
scratch[0] = actual_offset;
}
_ => {
scratch[2] = scratch[1];
scratch[1] = scratch[0];
scratch[0] = actual_offset;
}
}
}
actual_offset
}
|