mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-29 15:17:16 +08:00
Optimize encode code
This commit is contained in:
@@ -24,21 +24,3 @@ impl<T: Copy> VecExt<T> for Vec<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SliceExt<T> {
|
|
||||||
fn rfind(&self, pattern: &[T]) -> Option<usize>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PartialEq> SliceExt<T> for [T] {
|
|
||||||
fn rfind(&self, pattern: &[T]) -> Option<usize> {
|
|
||||||
if pattern.is_empty() || self.len() < pattern.len() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
for i in (0..=self.len() - pattern.len()).rev() {
|
|
||||||
if &self[i..i + pattern.len()] == pattern {
|
|
||||||
return Some(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -350,34 +350,72 @@ impl<'a, T: Write + Seek> DscEncoder<'a, T> {
|
|||||||
// LZSS compression
|
// LZSS compression
|
||||||
let mut ops = vec![];
|
let mut ops = vec![];
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
|
|
||||||
|
const MIN_LEN: usize = 2;
|
||||||
|
const MAX_LEN: usize = 257;
|
||||||
|
const WINDOW_SIZE: usize = 4097;
|
||||||
|
|
||||||
|
let mut head: Vec<i32> = vec![-1; 1 << 16];
|
||||||
|
let mut prev: Vec<i32> = vec![-1; data.len()];
|
||||||
|
|
||||||
while pos < data.len() {
|
while pos < data.len() {
|
||||||
|
let max_len = (data.len() - pos).min(MAX_LEN);
|
||||||
let mut best_len = 0;
|
let mut best_len = 0;
|
||||||
let mut best_offset = 0;
|
let mut best_offset = 0;
|
||||||
let max_len = (data.len() - pos).min(257);
|
|
||||||
|
|
||||||
if max_len >= 2 {
|
if max_len >= MIN_LEN {
|
||||||
let search_start = if pos > 4097 { pos - 4097 } else { 0 };
|
let limit = pos.saturating_sub(WINDOW_SIZE);
|
||||||
let lookbehind = &data[search_start..pos];
|
let key = (data[pos] as u16) << 8 | data[pos + 1] as u16;
|
||||||
for len in (2..=max_len).rev() {
|
let mut match_pos_i32 = head[key as usize];
|
||||||
if let Some(found_idx) = lookbehind.rfind(&data[pos..pos + len]) {
|
|
||||||
let offset = lookbehind.len() - found_idx;
|
while match_pos_i32 != -1 {
|
||||||
if offset >= 2 {
|
let match_pos = match_pos_i32 as usize;
|
||||||
best_len = len;
|
if match_pos < limit {
|
||||||
best_offset = offset;
|
break;
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
if data.get(match_pos + best_len) == data.get(pos + best_len) {
|
||||||
|
let mut current_len = 0;
|
||||||
|
for i in 0..max_len {
|
||||||
|
if data.get(pos + i) != data.get(match_pos + i) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current_len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if current_len > best_len {
|
||||||
|
best_len = current_len;
|
||||||
|
best_offset = pos - match_pos;
|
||||||
|
if best_len >= max_len {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
match_pos_i32 = prev[match_pos];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if best_len >= 2 {
|
if best_len >= MIN_LEN && best_offset >= 2 {
|
||||||
ops.push(LzssOp::Match {
|
ops.push(LzssOp::Match {
|
||||||
len: best_len as u16,
|
len: best_len as u16,
|
||||||
offset: best_offset as u16,
|
offset: best_offset as u16,
|
||||||
});
|
});
|
||||||
|
for i in 0..best_len {
|
||||||
|
if pos + i + 1 < data.len() {
|
||||||
|
let key = (data[pos + i] as u16) << 8 | data[pos + i + 1] as u16;
|
||||||
|
let current_pos = pos + i;
|
||||||
|
prev[current_pos] = head[key as usize];
|
||||||
|
head[key as usize] = current_pos as i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
pos += best_len;
|
pos += best_len;
|
||||||
} else {
|
} else {
|
||||||
ops.push(LzssOp::Literal(data[pos]));
|
ops.push(LzssOp::Literal(data[pos]));
|
||||||
|
if pos + 1 < data.len() {
|
||||||
|
let key = (data[pos] as u16) << 8 | data[pos + 1] as u16;
|
||||||
|
prev[pos] = head[key as usize];
|
||||||
|
head[key as usize] = pos as i32;
|
||||||
|
}
|
||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user