roxify 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +14 -2
- package/README.md +15 -0
- package/dist/cli.js +8 -1
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.js +1 -0
- package/dist/utils/decoder.js +40 -3
- package/dist/utils/encoder.js +24 -11
- package/dist/utils/inspection.d.ts +0 -28
- package/dist/utils/inspection.js +124 -406
- package/dist/utils/native.js +1 -9
- package/dist/utils/rust-cli-wrapper.js +41 -38
- package/dist/utils/types.d.ts +1 -1
- package/libroxify_native-x86_64-unknown-linux-gnu.node +0 -0
- package/native/bench_hybrid.rs +145 -0
- package/native/bwt.rs +25 -69
- package/native/context_mixing.rs +15 -18
- package/native/hybrid.rs +196 -71
- package/native/lib.rs +6 -3
- package/native/mtf.rs +106 -0
- package/native/rans_byte.rs +286 -0
- package/native/test_small_bwt.rs +31 -0
- package/native/test_stages.rs +70 -0
- package/package.json +1 -1
- package/dist/rox-macos-universal +0 -0
- package/dist/roxify_native +0 -0
- package/dist/roxify_native-macos-arm64 +0 -0
- package/dist/roxify_native-macos-x64 +0 -0
- package/dist/roxify_native.exe +0 -0
- package/roxify_native-aarch64-apple-darwin.node +0 -0
- package/roxify_native-aarch64-pc-windows-msvc.node +0 -0
- package/roxify_native-aarch64-unknown-linux-gnu.node +0 -0
- package/roxify_native-i686-pc-windows-msvc.node +0 -0
- package/roxify_native-i686-unknown-linux-gnu.node +0 -0
- package/roxify_native-x86_64-apple-darwin.node +0 -0
- package/roxify_native-x86_64-pc-windows-gnu.node +0 -0
- package/roxify_native-x86_64-pc-windows-msvc.node +0 -0
- package/roxify_native-x86_64-unknown-linux-gnu.node +0 -0
package/native/hybrid.rs
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
use anyhow::Result;
|
|
2
2
|
use rayon::prelude::*;
|
|
3
|
-
use crate::bwt::bwt_encode;
|
|
3
|
+
use crate::bwt::{bwt_encode, bwt_decode};
|
|
4
|
+
use crate::mtf::{mtf_encode, mtf_decode, rle0_encode, rle0_decode};
|
|
5
|
+
use crate::rans_byte::{SymbolStats, rans_encode_block, rans_decode_block};
|
|
4
6
|
use crate::context_mixing::analyze_entropy;
|
|
5
|
-
use crate::rans::{build_symbols_from_frequencies, RansEncoder};
|
|
6
|
-
use crate::pool::BufferPool;
|
|
7
|
-
use std::sync::Arc;
|
|
8
7
|
|
|
9
|
-
const BLOCK_SIZE: usize =
|
|
8
|
+
const BLOCK_SIZE: usize = 256 * 1024;
|
|
9
|
+
|
|
10
|
+
const BLOCK_FLAG_BWT: u8 = 0;
|
|
11
|
+
const BLOCK_FLAG_ZSTD: u8 = 1;
|
|
12
|
+
const BLOCK_FLAG_STORE: u8 = 2;
|
|
13
|
+
|
|
14
|
+
const ENTROPY_THRESHOLD_STORE: f32 = 7.95;
|
|
15
|
+
const ENTROPY_THRESHOLD_ZSTD: f32 = 7.5;
|
|
10
16
|
|
|
11
17
|
#[derive(Clone, Debug)]
|
|
12
18
|
pub struct CompressionStats {
|
|
@@ -18,34 +24,38 @@ pub struct CompressionStats {
|
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
pub struct HybridCompressor {
|
|
21
|
-
pool: Arc<BufferPool>,
|
|
22
|
-
enable_gpu: bool,
|
|
23
27
|
block_size: usize,
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
impl HybridCompressor {
|
|
27
|
-
pub fn new(
|
|
31
|
+
pub fn new(_enable_gpu: bool, _pool_size: usize) -> Self {
|
|
28
32
|
HybridCompressor {
|
|
29
|
-
pool: Arc::new(BufferPool::new(pool_size, BLOCK_SIZE)),
|
|
30
|
-
enable_gpu,
|
|
31
33
|
block_size: BLOCK_SIZE,
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
pub fn compress(&self, data: &[u8]) -> Result<(Vec<u8>, CompressionStats)> {
|
|
36
38
|
let original_size = data.len() as u64;
|
|
37
|
-
let entropy = analyze_entropy(data);
|
|
38
39
|
|
|
39
40
|
let blocks: Vec<&[u8]> = data.chunks(self.block_size).collect();
|
|
40
41
|
let blocks_count = blocks.len();
|
|
41
42
|
|
|
42
43
|
let compressed_blocks: Vec<Vec<u8>> = blocks
|
|
43
|
-
.
|
|
44
|
-
.map(|block|
|
|
44
|
+
.par_iter()
|
|
45
|
+
.map(|block| compress_block(block))
|
|
45
46
|
.collect::<Result<Vec<_>, _>>()?;
|
|
46
47
|
|
|
47
|
-
let
|
|
48
|
+
let entropy = if data.len() > 4096 {
|
|
49
|
+
analyze_entropy(&data[..4096.min(data.len())])
|
|
50
|
+
} else {
|
|
51
|
+
analyze_entropy(data)
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
let total_compressed: usize = compressed_blocks.iter().map(|b| b.len() + 4).sum();
|
|
55
|
+
let mut result = Vec::with_capacity(16 + total_compressed);
|
|
56
|
+
result.extend_from_slice(b"RBW2");
|
|
48
57
|
result.extend_from_slice(&(blocks_count as u32).to_le_bytes());
|
|
58
|
+
result.extend_from_slice(&original_size.to_le_bytes());
|
|
49
59
|
|
|
50
60
|
for block in &compressed_blocks {
|
|
51
61
|
result.extend_from_slice(&(block.len() as u32).to_le_bytes());
|
|
@@ -64,83 +74,58 @@ impl HybridCompressor {
|
|
|
64
74
|
}))
|
|
65
75
|
}
|
|
66
76
|
|
|
67
|
-
fn
|
|
68
|
-
if
|
|
69
|
-
return
|
|
77
|
+
pub fn decompress(&self, data: &[u8]) -> Result<Vec<u8>> {
|
|
78
|
+
if data.len() < 16 {
|
|
79
|
+
return Err(anyhow::anyhow!("Invalid compressed data"));
|
|
70
80
|
}
|
|
71
81
|
|
|
72
|
-
let
|
|
73
|
-
let
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
for &byte in bwt_data {
|
|
77
|
-
freqs[byte as usize] += 1;
|
|
82
|
+
let magic = &data[0..4];
|
|
83
|
+
let v2 = magic == b"RBW2";
|
|
84
|
+
if magic != b"RBW1" && !v2 {
|
|
85
|
+
return Err(anyhow::anyhow!("Invalid magic"));
|
|
78
86
|
}
|
|
79
87
|
|
|
80
|
-
let
|
|
81
|
-
let
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
let bit = (byte >> bit_idx) & 1 == 1;
|
|
86
|
-
let symbol_idx = if bit { 1 } else { 0 };
|
|
87
|
-
let _ = encoder.encode(symbol_idx);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
88
|
+
let blocks_count = u32::from_le_bytes([data[4], data[5], data[6], data[7]]) as usize;
|
|
89
|
+
let original_size = u64::from_le_bytes([
|
|
90
|
+
data[8], data[9], data[10], data[11],
|
|
91
|
+
data[12], data[13], data[14], data[15],
|
|
92
|
+
]) as usize;
|
|
90
93
|
|
|
91
|
-
let
|
|
92
|
-
let mut
|
|
93
|
-
result.extend_from_slice(&bwt.primary_index.to_le_bytes());
|
|
94
|
-
result.extend_from_slice(&encoded);
|
|
95
|
-
|
|
96
|
-
Ok(result)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
pub fn decompress(&self, data: &[u8]) -> Result<Vec<u8>> {
|
|
100
|
-
if data.len() < 4 {
|
|
101
|
-
return Err(anyhow::anyhow!("Invalid compressed data"));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let blocks_count = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
|
|
105
|
-
let mut pos = 4;
|
|
106
|
-
let mut result = Vec::new();
|
|
94
|
+
let mut pos = 16;
|
|
95
|
+
let mut block_slices: Vec<&[u8]> = Vec::with_capacity(blocks_count);
|
|
107
96
|
|
|
108
97
|
for _ in 0..blocks_count {
|
|
109
98
|
if pos + 4 > data.len() {
|
|
110
99
|
return Err(anyhow::anyhow!("Truncated block header"));
|
|
111
100
|
}
|
|
112
|
-
|
|
113
101
|
let block_size = u32::from_le_bytes([
|
|
114
|
-
data[pos],
|
|
115
|
-
data[pos + 1],
|
|
116
|
-
data[pos + 2],
|
|
117
|
-
data[pos + 3],
|
|
102
|
+
data[pos], data[pos + 1], data[pos + 2], data[pos + 3],
|
|
118
103
|
]) as usize;
|
|
119
104
|
pos += 4;
|
|
120
|
-
|
|
121
105
|
if pos + block_size > data.len() {
|
|
122
106
|
return Err(anyhow::anyhow!("Truncated block data"));
|
|
123
107
|
}
|
|
124
|
-
|
|
125
|
-
let block_data = &data[pos..pos + block_size];
|
|
108
|
+
block_slices.push(&data[pos..pos + block_size]);
|
|
126
109
|
pos += block_size;
|
|
127
|
-
|
|
128
|
-
let decompressed = self.decompress_block(block_data)?;
|
|
129
|
-
result.extend_from_slice(&decompressed);
|
|
130
110
|
}
|
|
131
111
|
|
|
132
|
-
|
|
133
|
-
|
|
112
|
+
let decompressed_blocks: Vec<Vec<u8>> = block_slices
|
|
113
|
+
.par_iter()
|
|
114
|
+
.map(|block_data| {
|
|
115
|
+
if v2 {
|
|
116
|
+
decompress_block_v2(block_data)
|
|
117
|
+
} else {
|
|
118
|
+
decompress_block_v1(block_data)
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
.collect::<Result<Vec<_>, _>>()?;
|
|
134
122
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
123
|
+
let mut result = Vec::with_capacity(original_size);
|
|
124
|
+
for block in decompressed_blocks {
|
|
125
|
+
result.extend_from_slice(&block);
|
|
138
126
|
}
|
|
139
127
|
|
|
140
|
-
|
|
141
|
-
let _encoded_data = &block[4..];
|
|
142
|
-
|
|
143
|
-
Ok(Vec::new())
|
|
128
|
+
Ok(result)
|
|
144
129
|
}
|
|
145
130
|
|
|
146
131
|
pub fn estimate_gain(&self, data: &[u8]) -> f64 {
|
|
@@ -151,12 +136,152 @@ impl HybridCompressor {
|
|
|
151
136
|
}
|
|
152
137
|
}
|
|
153
138
|
|
|
139
|
+
fn compress_block(block: &[u8]) -> Result<Vec<u8>> {
|
|
140
|
+
if block.is_empty() {
|
|
141
|
+
return Ok(vec![BLOCK_FLAG_STORE]);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let entropy = analyze_entropy(block);
|
|
145
|
+
|
|
146
|
+
if entropy >= ENTROPY_THRESHOLD_STORE {
|
|
147
|
+
let mut result = Vec::with_capacity(1 + block.len());
|
|
148
|
+
result.push(BLOCK_FLAG_STORE);
|
|
149
|
+
result.extend_from_slice(block);
|
|
150
|
+
return Ok(result);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if entropy >= ENTROPY_THRESHOLD_ZSTD {
|
|
154
|
+
let compressed = zstd::encode_all(block, 1)?;
|
|
155
|
+
if compressed.len() < block.len() {
|
|
156
|
+
let mut result = Vec::with_capacity(1 + 4 + compressed.len());
|
|
157
|
+
result.push(BLOCK_FLAG_ZSTD);
|
|
158
|
+
result.extend_from_slice(&(block.len() as u32).to_le_bytes());
|
|
159
|
+
result.extend_from_slice(&compressed);
|
|
160
|
+
return Ok(result);
|
|
161
|
+
}
|
|
162
|
+
let mut result = Vec::with_capacity(1 + block.len());
|
|
163
|
+
result.push(BLOCK_FLAG_STORE);
|
|
164
|
+
result.extend_from_slice(block);
|
|
165
|
+
return Ok(result);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let bwt = bwt_encode(block)?;
|
|
169
|
+
let mtf_data = mtf_encode(&bwt.transformed);
|
|
170
|
+
let rle_data = rle0_encode(&mtf_data);
|
|
171
|
+
let stats = SymbolStats::from_data(&rle_data);
|
|
172
|
+
let encoded = rans_encode_block(&rle_data, &stats);
|
|
173
|
+
let stats_bytes = stats.serialize();
|
|
174
|
+
|
|
175
|
+
let bwt_total = 1 + 4 + 4 + 4 + stats_bytes.len() + encoded.len();
|
|
176
|
+
|
|
177
|
+
if bwt_total < block.len() {
|
|
178
|
+
let zstd_compressed = zstd::encode_all(block, 3)?;
|
|
179
|
+
let zstd_total = 1 + 4 + zstd_compressed.len();
|
|
180
|
+
|
|
181
|
+
if zstd_total < bwt_total {
|
|
182
|
+
let mut result = Vec::with_capacity(zstd_total);
|
|
183
|
+
result.push(BLOCK_FLAG_ZSTD);
|
|
184
|
+
result.extend_from_slice(&(block.len() as u32).to_le_bytes());
|
|
185
|
+
result.extend_from_slice(&zstd_compressed);
|
|
186
|
+
return Ok(result);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
let mut result = Vec::with_capacity(bwt_total);
|
|
190
|
+
result.push(BLOCK_FLAG_BWT);
|
|
191
|
+
result.extend_from_slice(&bwt.primary_index.to_le_bytes());
|
|
192
|
+
result.extend_from_slice(&(block.len() as u32).to_le_bytes());
|
|
193
|
+
result.extend_from_slice(&(rle_data.len() as u32).to_le_bytes());
|
|
194
|
+
result.extend_from_slice(&stats_bytes);
|
|
195
|
+
result.extend_from_slice(&encoded);
|
|
196
|
+
return Ok(result);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
let zstd_compressed = zstd::encode_all(block, 3)?;
|
|
200
|
+
if 1 + 4 + zstd_compressed.len() < block.len() {
|
|
201
|
+
let mut result = Vec::with_capacity(1 + 4 + zstd_compressed.len());
|
|
202
|
+
result.push(BLOCK_FLAG_ZSTD);
|
|
203
|
+
result.extend_from_slice(&(block.len() as u32).to_le_bytes());
|
|
204
|
+
result.extend_from_slice(&zstd_compressed);
|
|
205
|
+
return Ok(result);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let mut result = Vec::with_capacity(1 + block.len());
|
|
209
|
+
result.push(BLOCK_FLAG_STORE);
|
|
210
|
+
result.extend_from_slice(block);
|
|
211
|
+
Ok(result)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
fn decompress_block_v2(block: &[u8]) -> Result<Vec<u8>> {
|
|
215
|
+
if block.is_empty() {
|
|
216
|
+
return Err(anyhow::anyhow!("Empty block"));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
match block[0] {
|
|
220
|
+
BLOCK_FLAG_STORE => Ok(block[1..].to_vec()),
|
|
221
|
+
BLOCK_FLAG_ZSTD => {
|
|
222
|
+
if block.len() < 5 {
|
|
223
|
+
return Err(anyhow::anyhow!("Truncated zstd block"));
|
|
224
|
+
}
|
|
225
|
+
let orig_len = u32::from_le_bytes([block[1], block[2], block[3], block[4]]) as usize;
|
|
226
|
+
let mut decoded = zstd::decode_all(&block[5..])?;
|
|
227
|
+
decoded.truncate(orig_len);
|
|
228
|
+
Ok(decoded)
|
|
229
|
+
}
|
|
230
|
+
BLOCK_FLAG_BWT => {
|
|
231
|
+
if block.len() < 13 {
|
|
232
|
+
return Err(anyhow::anyhow!("Truncated BWT block"));
|
|
233
|
+
}
|
|
234
|
+
let primary_index = u32::from_le_bytes([block[1], block[2], block[3], block[4]]);
|
|
235
|
+
let orig_len = u32::from_le_bytes([block[5], block[6], block[7], block[8]]) as usize;
|
|
236
|
+
let rle_len = u32::from_le_bytes([block[9], block[10], block[11], block[12]]) as usize;
|
|
237
|
+
|
|
238
|
+
let (stats, stats_size) = SymbolStats::deserialize(&block[13..])?;
|
|
239
|
+
let encoded = &block[13 + stats_size..];
|
|
240
|
+
|
|
241
|
+
let rle_data = rans_decode_block(encoded, &stats, rle_len)?;
|
|
242
|
+
let mtf_data = rle0_decode(&rle_data);
|
|
243
|
+
let bwt_data = mtf_decode(&mtf_data);
|
|
244
|
+
let original = bwt_decode(&bwt_data, primary_index)?;
|
|
245
|
+
|
|
246
|
+
if original.len() != orig_len {
|
|
247
|
+
return Err(anyhow::anyhow!("Size mismatch"));
|
|
248
|
+
}
|
|
249
|
+
Ok(original)
|
|
250
|
+
}
|
|
251
|
+
_ => Err(anyhow::anyhow!("Unknown block type: {}", block[0])),
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
fn decompress_block_v1(block: &[u8]) -> Result<Vec<u8>> {
|
|
256
|
+
if block.len() < 12 {
|
|
257
|
+
return Err(anyhow::anyhow!("Block too small"));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let primary_index = u32::from_le_bytes([block[0], block[1], block[2], block[3]]);
|
|
261
|
+
let orig_len = u32::from_le_bytes([block[4], block[5], block[6], block[7]]) as usize;
|
|
262
|
+
let rle_len = u32::from_le_bytes([block[8], block[9], block[10], block[11]]) as usize;
|
|
263
|
+
|
|
264
|
+
let (stats, stats_size) = SymbolStats::deserialize(&block[12..])?;
|
|
265
|
+
let encoded = &block[12 + stats_size..];
|
|
266
|
+
|
|
267
|
+
let rle_data = rans_decode_block(encoded, &stats, rle_len)?;
|
|
268
|
+
let mtf_data = rle0_decode(&rle_data);
|
|
269
|
+
let bwt_data = mtf_decode(&mtf_data);
|
|
270
|
+
let original = bwt_decode(&bwt_data, primary_index)?;
|
|
271
|
+
|
|
272
|
+
if original.len() != orig_len {
|
|
273
|
+
return Err(anyhow::anyhow!("Size mismatch"));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
Ok(original)
|
|
277
|
+
}
|
|
278
|
+
|
|
154
279
|
pub fn compress_high_performance(data: &[u8]) -> Result<(Vec<u8>, CompressionStats)> {
|
|
155
|
-
let compressor = HybridCompressor::new(
|
|
280
|
+
let compressor = HybridCompressor::new(false, 0);
|
|
156
281
|
compressor.compress(data)
|
|
157
282
|
}
|
|
158
283
|
|
|
159
284
|
pub fn decompress_high_performance(data: &[u8]) -> Result<Vec<u8>> {
|
|
160
|
-
let compressor = HybridCompressor::new(
|
|
285
|
+
let compressor = HybridCompressor::new(false, 0);
|
|
161
286
|
compressor.decompress(data)
|
|
162
287
|
}
|
package/native/lib.rs
CHANGED
|
@@ -9,7 +9,9 @@ mod core;
|
|
|
9
9
|
#[cfg(feature = "gpu")]
|
|
10
10
|
mod gpu;
|
|
11
11
|
mod rans;
|
|
12
|
+
mod rans_byte;
|
|
12
13
|
mod bwt;
|
|
14
|
+
mod mtf;
|
|
13
15
|
mod context_mixing;
|
|
14
16
|
mod pool;
|
|
15
17
|
mod hybrid;
|
|
@@ -150,17 +152,18 @@ pub fn entropy_estimate(buffer: Buffer) -> f32 {
|
|
|
150
152
|
|
|
151
153
|
#[cfg(not(test))]
|
|
152
154
|
#[napi]
|
|
153
|
-
pub fn hybrid_compress(buffer: Buffer) -> Result<
|
|
155
|
+
pub fn hybrid_compress(buffer: Buffer) -> Result<Buffer> {
|
|
154
156
|
match hybrid::compress_high_performance(&buffer) {
|
|
155
|
-
Ok((compressed, _stats)) => Ok(compressed),
|
|
157
|
+
Ok((compressed, _stats)) => Ok(Buffer::from(compressed)),
|
|
156
158
|
Err(e) => Err(Error::from_reason(e.to_string())),
|
|
157
159
|
}
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
#[cfg(not(test))]
|
|
161
163
|
#[napi]
|
|
162
|
-
pub fn hybrid_decompress(buffer: Buffer) -> Result<
|
|
164
|
+
pub fn hybrid_decompress(buffer: Buffer) -> Result<Buffer> {
|
|
163
165
|
hybrid::decompress_high_performance(&buffer)
|
|
166
|
+
.map(Buffer::from)
|
|
164
167
|
.map_err(|e| Error::from_reason(e.to_string()))
|
|
165
168
|
}
|
|
166
169
|
|
package/native/mtf.rs
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
pub fn mtf_encode(data: &[u8]) -> Vec<u8> {
|
|
2
|
+
let mut table = [0u8; 256];
|
|
3
|
+
for i in 0..256 {
|
|
4
|
+
table[i] = i as u8;
|
|
5
|
+
}
|
|
6
|
+
let mut output = Vec::with_capacity(data.len());
|
|
7
|
+
|
|
8
|
+
for &byte in data {
|
|
9
|
+
let pos = unsafe { table.iter().position(|&b| b == byte).unwrap_unchecked() };
|
|
10
|
+
output.push(pos as u8);
|
|
11
|
+
if pos > 0 {
|
|
12
|
+
let val = table[pos];
|
|
13
|
+
table.copy_within(0..pos, 1);
|
|
14
|
+
table[0] = val;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
output
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub fn mtf_decode(data: &[u8]) -> Vec<u8> {
|
|
22
|
+
let mut table = [0u8; 256];
|
|
23
|
+
for i in 0..256 {
|
|
24
|
+
table[i] = i as u8;
|
|
25
|
+
}
|
|
26
|
+
let mut output = Vec::with_capacity(data.len());
|
|
27
|
+
|
|
28
|
+
for &idx in data {
|
|
29
|
+
let pos = idx as usize;
|
|
30
|
+
let byte = table[pos];
|
|
31
|
+
output.push(byte);
|
|
32
|
+
if pos > 0 {
|
|
33
|
+
let val = table[pos];
|
|
34
|
+
table.copy_within(0..pos, 1);
|
|
35
|
+
table[0] = val;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
output
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
pub fn rle0_encode(data: &[u8]) -> Vec<u8> {
|
|
43
|
+
let mut output = Vec::with_capacity(data.len());
|
|
44
|
+
let mut i = 0;
|
|
45
|
+
|
|
46
|
+
while i < data.len() {
|
|
47
|
+
if data[i] == 0 {
|
|
48
|
+
let mut run = 0u32;
|
|
49
|
+
while i < data.len() && data[i] == 0 {
|
|
50
|
+
run += 1;
|
|
51
|
+
i += 1;
|
|
52
|
+
}
|
|
53
|
+
output.push(0);
|
|
54
|
+
if run <= 127 {
|
|
55
|
+
output.push(run as u8);
|
|
56
|
+
} else if run <= 16383 {
|
|
57
|
+
output.push(0x80 | ((run >> 8) as u8));
|
|
58
|
+
output.push((run & 0xFF) as u8);
|
|
59
|
+
} else {
|
|
60
|
+
output.push(0xC0 | ((run >> 16) as u8));
|
|
61
|
+
output.push(((run >> 8) & 0xFF) as u8);
|
|
62
|
+
output.push((run & 0xFF) as u8);
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
output.push(data[i]);
|
|
66
|
+
i += 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
output
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
pub fn rle0_decode(data: &[u8]) -> Vec<u8> {
|
|
74
|
+
let mut output = Vec::with_capacity(data.len() * 2);
|
|
75
|
+
let mut i = 0;
|
|
76
|
+
|
|
77
|
+
while i < data.len() {
|
|
78
|
+
if data[i] == 0 {
|
|
79
|
+
i += 1;
|
|
80
|
+
if i >= data.len() {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
let run;
|
|
84
|
+
if data[i] & 0xC0 == 0xC0 {
|
|
85
|
+
let hi = (data[i] & 0x3F) as u32;
|
|
86
|
+
run = (hi << 16) | ((data[i + 1] as u32) << 8) | (data[i + 2] as u32);
|
|
87
|
+
i += 3;
|
|
88
|
+
} else if data[i] & 0x80 != 0 {
|
|
89
|
+
let hi = (data[i] & 0x7F) as u32;
|
|
90
|
+
run = (hi << 8) | (data[i + 1] as u32);
|
|
91
|
+
i += 2;
|
|
92
|
+
} else {
|
|
93
|
+
run = data[i] as u32;
|
|
94
|
+
i += 1;
|
|
95
|
+
}
|
|
96
|
+
for _ in 0..run {
|
|
97
|
+
output.push(0);
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
output.push(data[i]);
|
|
101
|
+
i += 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
output
|
|
106
|
+
}
|