roxify 1.10.1 → 1.11.1
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 +1 -1
- package/dist/roxify_native +0 -0
- package/dist/roxify_native.exe +0 -0
- package/libroxify_native-x86_64-unknown-linux-gnu.node +0 -0
- package/native/archive.rs +61 -17
- package/native/context_mixing.rs +15 -18
- package/native/core.rs +97 -12
- package/native/crypto.rs +1 -1
- package/native/encoder.rs +110 -58
- package/native/hybrid.rs +133 -30
- package/native/lib.rs +1 -0
- package/native/main.rs +55 -29
- package/native/rans_byte.rs +117 -21
- package/native/streaming.rs +214 -0
- package/package.json +1 -1
- 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
|
@@ -7,6 +7,13 @@ use crate::context_mixing::analyze_entropy;
|
|
|
7
7
|
|
|
8
8
|
const BLOCK_SIZE: usize = 1024 * 1024;
|
|
9
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;
|
|
16
|
+
|
|
10
17
|
#[derive(Clone, Debug)]
|
|
11
18
|
pub struct CompressionStats {
|
|
12
19
|
pub original_size: u64,
|
|
@@ -29,19 +36,24 @@ impl HybridCompressor {
|
|
|
29
36
|
|
|
30
37
|
pub fn compress(&self, data: &[u8]) -> Result<(Vec<u8>, CompressionStats)> {
|
|
31
38
|
let original_size = data.len() as u64;
|
|
32
|
-
let entropy = analyze_entropy(data);
|
|
33
39
|
|
|
34
40
|
let blocks: Vec<&[u8]> = data.chunks(self.block_size).collect();
|
|
35
41
|
let blocks_count = blocks.len();
|
|
36
42
|
|
|
37
43
|
let compressed_blocks: Vec<Vec<u8>> = blocks
|
|
38
|
-
.
|
|
44
|
+
.par_iter()
|
|
39
45
|
.map(|block| compress_block(block))
|
|
40
46
|
.collect::<Result<Vec<_>, _>>()?;
|
|
41
47
|
|
|
48
|
+
let entropy = if data.len() > 4096 {
|
|
49
|
+
analyze_entropy(&data[..4096.min(data.len())])
|
|
50
|
+
} else {
|
|
51
|
+
analyze_entropy(data)
|
|
52
|
+
};
|
|
53
|
+
|
|
42
54
|
let total_compressed: usize = compressed_blocks.iter().map(|b| b.len() + 4).sum();
|
|
43
55
|
let mut result = Vec::with_capacity(16 + total_compressed);
|
|
44
|
-
result.extend_from_slice(b"
|
|
56
|
+
result.extend_from_slice(b"RBW2");
|
|
45
57
|
result.extend_from_slice(&(blocks_count as u32).to_le_bytes());
|
|
46
58
|
result.extend_from_slice(&original_size.to_le_bytes());
|
|
47
59
|
|
|
@@ -67,7 +79,9 @@ impl HybridCompressor {
|
|
|
67
79
|
return Err(anyhow::anyhow!("Invalid compressed data"));
|
|
68
80
|
}
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
let magic = &data[0..4];
|
|
83
|
+
let v2 = magic == b"RBW2";
|
|
84
|
+
if magic != b"RBW1" && !v2 {
|
|
71
85
|
return Err(anyhow::anyhow!("Invalid magic"));
|
|
72
86
|
}
|
|
73
87
|
|
|
@@ -78,7 +92,7 @@ impl HybridCompressor {
|
|
|
78
92
|
]) as usize;
|
|
79
93
|
|
|
80
94
|
let mut pos = 16;
|
|
81
|
-
let mut
|
|
95
|
+
let mut block_slices: Vec<&[u8]> = Vec::with_capacity(blocks_count);
|
|
82
96
|
|
|
83
97
|
for _ in 0..blocks_count {
|
|
84
98
|
if pos + 4 > data.len() {
|
|
@@ -91,15 +105,18 @@ impl HybridCompressor {
|
|
|
91
105
|
if pos + block_size > data.len() {
|
|
92
106
|
return Err(anyhow::anyhow!("Truncated block data"));
|
|
93
107
|
}
|
|
94
|
-
|
|
108
|
+
block_slices.push(&data[pos..pos + block_size]);
|
|
95
109
|
pos += block_size;
|
|
96
110
|
}
|
|
97
111
|
|
|
98
|
-
let decompressed_blocks: Vec<Vec<u8>> =
|
|
99
|
-
.
|
|
100
|
-
.map(|
|
|
101
|
-
|
|
102
|
-
|
|
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
|
+
}
|
|
103
120
|
})
|
|
104
121
|
.collect::<Result<Vec<_>, _>>()?;
|
|
105
122
|
|
|
@@ -121,31 +138,121 @@ impl HybridCompressor {
|
|
|
121
138
|
|
|
122
139
|
fn compress_block(block: &[u8]) -> Result<Vec<u8>> {
|
|
123
140
|
if block.is_empty() {
|
|
124
|
-
return Ok(
|
|
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);
|
|
125
166
|
}
|
|
126
167
|
|
|
127
168
|
let bwt = bwt_encode(block)?;
|
|
128
169
|
let mtf_data = mtf_encode(&bwt.transformed);
|
|
129
170
|
let rle_data = rle0_encode(&mtf_data);
|
|
130
|
-
|
|
131
171
|
let stats = SymbolStats::from_data(&rle_data);
|
|
132
172
|
let encoded = rans_encode_block(&rle_data, &stats);
|
|
133
|
-
|
|
134
173
|
let stats_bytes = stats.serialize();
|
|
135
|
-
let rle_len = rle_data.len() as u32;
|
|
136
|
-
let orig_len = block.len() as u32;
|
|
137
174
|
|
|
138
|
-
let
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
result.extend_from_slice(&encoded);
|
|
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();
|
|
144
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);
|
|
145
211
|
Ok(result)
|
|
146
212
|
}
|
|
147
213
|
|
|
148
|
-
fn
|
|
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>> {
|
|
149
256
|
if block.len() < 12 {
|
|
150
257
|
return Err(anyhow::anyhow!("Block too small"));
|
|
151
258
|
}
|
|
@@ -163,22 +270,18 @@ fn decompress_block(block: &[u8]) -> Result<Vec<u8>> {
|
|
|
163
270
|
let original = bwt_decode(&bwt_data, primary_index)?;
|
|
164
271
|
|
|
165
272
|
if original.len() != orig_len {
|
|
166
|
-
return Err(anyhow::anyhow!(
|
|
167
|
-
"Size mismatch: expected {}, got {}",
|
|
168
|
-
orig_len,
|
|
169
|
-
original.len()
|
|
170
|
-
));
|
|
273
|
+
return Err(anyhow::anyhow!("Size mismatch"));
|
|
171
274
|
}
|
|
172
275
|
|
|
173
276
|
Ok(original)
|
|
174
277
|
}
|
|
175
278
|
|
|
176
279
|
pub fn compress_high_performance(data: &[u8]) -> Result<(Vec<u8>, CompressionStats)> {
|
|
177
|
-
let compressor = HybridCompressor::new(false,
|
|
280
|
+
let compressor = HybridCompressor::new(false, 0);
|
|
178
281
|
compressor.compress(data)
|
|
179
282
|
}
|
|
180
283
|
|
|
181
284
|
pub fn decompress_high_performance(data: &[u8]) -> Result<Vec<u8>> {
|
|
182
|
-
let compressor = HybridCompressor::new(false,
|
|
285
|
+
let compressor = HybridCompressor::new(false, 0);
|
|
183
286
|
compressor.decompress(data)
|
|
184
287
|
}
|
package/native/lib.rs
CHANGED
package/native/main.rs
CHANGED
|
@@ -14,6 +14,7 @@ mod png_utils;
|
|
|
14
14
|
mod audio;
|
|
15
15
|
mod reconstitution;
|
|
16
16
|
mod archive;
|
|
17
|
+
mod streaming;
|
|
17
18
|
|
|
18
19
|
use crate::encoder::ImageFormat;
|
|
19
20
|
use std::path::PathBuf;
|
|
@@ -104,15 +105,28 @@ enum Commands {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
fn read_all(path: &PathBuf) -> anyhow::Result<Vec<u8>> {
|
|
107
|
-
let
|
|
108
|
-
let
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
let metadata = std::fs::metadata(path)?;
|
|
109
|
+
let size = metadata.len() as usize;
|
|
110
|
+
|
|
111
|
+
if size > 256 * 1024 * 1024 {
|
|
112
|
+
let file = File::open(path)?;
|
|
113
|
+
let mmap = unsafe { memmap2::Mmap::map(&file)? };
|
|
114
|
+
Ok(mmap.to_vec())
|
|
115
|
+
} else {
|
|
116
|
+
let mut f = File::open(path)?;
|
|
117
|
+
let mut buf = Vec::with_capacity(size);
|
|
118
|
+
f.read_to_end(&mut buf)?;
|
|
119
|
+
Ok(buf)
|
|
120
|
+
}
|
|
111
121
|
}
|
|
112
122
|
|
|
113
123
|
fn write_all(path: &PathBuf, data: &[u8]) -> anyhow::Result<()> {
|
|
114
|
-
let
|
|
115
|
-
|
|
124
|
+
let f = File::create(path)?;
|
|
125
|
+
let buf_size = if data.len() > 64 * 1024 * 1024 { 16 * 1024 * 1024 }
|
|
126
|
+
else { (8 * 1024 * 1024).min(data.len().max(8192)) };
|
|
127
|
+
let mut writer = std::io::BufWriter::with_capacity(buf_size, f);
|
|
128
|
+
writer.write_all(data)?;
|
|
129
|
+
writer.flush()?;
|
|
116
130
|
Ok(())
|
|
117
131
|
}
|
|
118
132
|
|
|
@@ -144,14 +158,12 @@ fn main() -> anyhow::Result<()> {
|
|
|
144
158
|
Commands::Encode { input, output, level, passphrase, encrypt, name, dict } => {
|
|
145
159
|
let is_dir = input.is_dir();
|
|
146
160
|
let (payload, file_list_json) = if is_dir {
|
|
147
|
-
let
|
|
161
|
+
let result = archive::tar_pack_directory_with_list(&input)
|
|
148
162
|
.map_err(|e| anyhow::anyhow!(e))?;
|
|
149
|
-
let
|
|
150
|
-
.map_err(|e| anyhow::anyhow!(e))?;
|
|
151
|
-
let json_list: Vec<serde_json::Value> = list.iter()
|
|
163
|
+
let json_list: Vec<serde_json::Value> = result.file_list.iter()
|
|
152
164
|
.map(|(name, size)| serde_json::json!({"name": name, "size": size}))
|
|
153
165
|
.collect();
|
|
154
|
-
(
|
|
166
|
+
(result.data, Some(serde_json::to_string(&json_list)?))
|
|
155
167
|
} else {
|
|
156
168
|
let pack_result = packer::pack_path_with_metadata(&input)?;
|
|
157
169
|
(pack_result.data, pack_result.file_list_json)
|
|
@@ -165,31 +177,45 @@ fn main() -> anyhow::Result<()> {
|
|
|
165
177
|
None => None,
|
|
166
178
|
};
|
|
167
179
|
|
|
168
|
-
let
|
|
169
|
-
|
|
180
|
+
let use_streaming = payload.len() > 64 * 1024 * 1024;
|
|
181
|
+
|
|
182
|
+
if use_streaming {
|
|
183
|
+
streaming::encode_to_png_file(
|
|
170
184
|
&payload,
|
|
185
|
+
&output,
|
|
171
186
|
level,
|
|
172
|
-
|
|
187
|
+
passphrase.as_deref(),
|
|
173
188
|
Some(&encrypt),
|
|
174
|
-
ImageFormat::Png,
|
|
175
189
|
file_name,
|
|
176
190
|
file_list_json.as_deref(),
|
|
177
191
|
dict_bytes.as_deref(),
|
|
178
|
-
)
|
|
192
|
+
)?;
|
|
179
193
|
} else {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
194
|
+
let png = if let Some(ref pass) = passphrase {
|
|
195
|
+
encoder::encode_to_png_with_encryption_name_and_format_and_filelist(
|
|
196
|
+
&payload,
|
|
197
|
+
level,
|
|
198
|
+
Some(pass),
|
|
199
|
+
Some(&encrypt),
|
|
200
|
+
ImageFormat::Png,
|
|
201
|
+
file_name,
|
|
202
|
+
file_list_json.as_deref(),
|
|
203
|
+
dict_bytes.as_deref(),
|
|
204
|
+
)?
|
|
205
|
+
} else {
|
|
206
|
+
encoder::encode_to_png_with_encryption_name_and_format_and_filelist(
|
|
207
|
+
&payload,
|
|
208
|
+
level,
|
|
209
|
+
None,
|
|
210
|
+
None,
|
|
211
|
+
ImageFormat::Png,
|
|
212
|
+
file_name,
|
|
213
|
+
file_list_json.as_deref(),
|
|
214
|
+
dict_bytes.as_deref(),
|
|
215
|
+
)?
|
|
216
|
+
};
|
|
217
|
+
write_all(&output, &png)?;
|
|
218
|
+
}
|
|
193
219
|
|
|
194
220
|
if file_list_json.is_some() {
|
|
195
221
|
if is_dir {
|
package/native/rans_byte.rs
CHANGED
|
@@ -106,10 +106,10 @@ impl SymbolStats {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
#[inline(always)]
|
|
109
110
|
fn rans_enc_put(state: &mut u32, buf: &mut Vec<u8>, start: u32, freq: u32) {
|
|
110
|
-
let x = *state;
|
|
111
111
|
let x_max = ((RANS_BYTE_L >> PROB_BITS) << 8) * freq;
|
|
112
|
-
let mut x =
|
|
112
|
+
let mut x = *state;
|
|
113
113
|
while x >= x_max {
|
|
114
114
|
buf.push((x & 0xFF) as u8);
|
|
115
115
|
x >>= 8;
|
|
@@ -117,7 +117,22 @@ fn rans_enc_put(state: &mut u32, buf: &mut Vec<u8>, start: u32, freq: u32) {
|
|
|
117
117
|
*state = ((x / freq) << PROB_BITS) + (x % freq) + start;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
#[inline(always)]
|
|
121
|
+
fn rans_dec_renorm(state: &mut u32, data: &[u8], pos: &mut usize) {
|
|
122
|
+
while *state < RANS_BYTE_L && *pos < data.len() {
|
|
123
|
+
*state = (*state << 8) | (data[*pos] as u32);
|
|
124
|
+
*pos += 1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fn write_state(out: &mut Vec<u8>, state: u32) {
|
|
129
|
+
out.push((state >> 24) as u8);
|
|
130
|
+
out.push(((state >> 16) & 0xFF) as u8);
|
|
131
|
+
out.push(((state >> 8) & 0xFF) as u8);
|
|
132
|
+
out.push((state & 0xFF) as u8);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fn read_state(data: &[u8], pos: &mut usize) -> u32 {
|
|
121
136
|
let s = (data[*pos] as u32) << 24
|
|
122
137
|
| (data[*pos + 1] as u32) << 16
|
|
123
138
|
| (data[*pos + 2] as u32) << 8
|
|
@@ -126,18 +141,48 @@ fn rans_dec_init(data: &[u8], pos: &mut usize) -> u32 {
|
|
|
126
141
|
s
|
|
127
142
|
}
|
|
128
143
|
|
|
129
|
-
fn rans_dec_renorm(state: &mut u32, data: &[u8], pos: &mut usize) {
|
|
130
|
-
while *state < RANS_BYTE_L && *pos < data.len() {
|
|
131
|
-
*state = (*state << 8) | (data[*pos] as u32);
|
|
132
|
-
*pos += 1;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
144
|
pub fn rans_encode_block(data: &[u8], stats: &SymbolStats) -> Vec<u8> {
|
|
137
145
|
if data.is_empty() {
|
|
138
146
|
return Vec::new();
|
|
139
147
|
}
|
|
140
148
|
|
|
149
|
+
if data.len() < 8 {
|
|
150
|
+
return rans_encode_single(data, stats);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let mut s0: u32 = RANS_BYTE_L;
|
|
154
|
+
let mut s1: u32 = RANS_BYTE_L;
|
|
155
|
+
let mut rev_bytes: Vec<u8> = Vec::with_capacity(data.len() + 32);
|
|
156
|
+
|
|
157
|
+
let len = data.len();
|
|
158
|
+
let even_start = if len % 2 == 0 { len } else { len - 1 };
|
|
159
|
+
|
|
160
|
+
if len % 2 != 0 {
|
|
161
|
+
let sym = data[len - 1] as usize;
|
|
162
|
+
rans_enc_put(&mut s1, &mut rev_bytes, stats.cum_freqs[sym], stats.freqs[sym]);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let mut i = even_start;
|
|
166
|
+
while i >= 2 {
|
|
167
|
+
i -= 2;
|
|
168
|
+
let sym1 = data[i + 1] as usize;
|
|
169
|
+
rans_enc_put(&mut s1, &mut rev_bytes, stats.cum_freqs[sym1], stats.freqs[sym1]);
|
|
170
|
+
let sym0 = data[i] as usize;
|
|
171
|
+
rans_enc_put(&mut s0, &mut rev_bytes, stats.cum_freqs[sym0], stats.freqs[sym0]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let mut output = Vec::with_capacity(9 + rev_bytes.len());
|
|
175
|
+
output.push(1);
|
|
176
|
+
write_state(&mut output, s0);
|
|
177
|
+
write_state(&mut output, s1);
|
|
178
|
+
|
|
179
|
+
for &b in rev_bytes.iter().rev() {
|
|
180
|
+
output.push(b);
|
|
181
|
+
}
|
|
182
|
+
output
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
fn rans_encode_single(data: &[u8], stats: &SymbolStats) -> Vec<u8> {
|
|
141
186
|
let mut state: u32 = RANS_BYTE_L;
|
|
142
187
|
let mut rev_bytes: Vec<u8> = Vec::with_capacity(data.len() + 16);
|
|
143
188
|
|
|
@@ -146,11 +191,9 @@ pub fn rans_encode_block(data: &[u8], stats: &SymbolStats) -> Vec<u8> {
|
|
|
146
191
|
rans_enc_put(&mut state, &mut rev_bytes, stats.cum_freqs[s], stats.freqs[s]);
|
|
147
192
|
}
|
|
148
193
|
|
|
149
|
-
let mut output = Vec::with_capacity(
|
|
150
|
-
output.push(
|
|
151
|
-
|
|
152
|
-
output.push(((state >> 8) & 0xFF) as u8);
|
|
153
|
-
output.push((state & 0xFF) as u8);
|
|
194
|
+
let mut output = Vec::with_capacity(5 + rev_bytes.len());
|
|
195
|
+
output.push(0);
|
|
196
|
+
write_state(&mut output, state);
|
|
154
197
|
|
|
155
198
|
for &b in rev_bytes.iter().rev() {
|
|
156
199
|
output.push(b);
|
|
@@ -159,19 +202,30 @@ pub fn rans_encode_block(data: &[u8], stats: &SymbolStats) -> Vec<u8> {
|
|
|
159
202
|
}
|
|
160
203
|
|
|
161
204
|
pub fn rans_decode_block(encoded: &[u8], stats: &SymbolStats, output_len: usize) -> Result<Vec<u8>> {
|
|
162
|
-
if encoded.
|
|
205
|
+
if encoded.is_empty() {
|
|
163
206
|
return Err(anyhow::anyhow!("Data too short"));
|
|
164
207
|
}
|
|
165
208
|
|
|
166
|
-
let mut cum2sym =
|
|
209
|
+
let mut cum2sym = [0u8; PROB_SCALE as usize];
|
|
167
210
|
for s in 0..256usize {
|
|
168
|
-
|
|
169
|
-
|
|
211
|
+
let start = stats.cum_freqs[s] as usize;
|
|
212
|
+
let end = stats.cum_freqs[s + 1] as usize;
|
|
213
|
+
if end > start {
|
|
214
|
+
cum2sym[start..end].fill(s as u8);
|
|
170
215
|
}
|
|
171
216
|
}
|
|
172
217
|
|
|
173
|
-
let
|
|
174
|
-
let mut
|
|
218
|
+
let mode = encoded[0];
|
|
219
|
+
let mut pos = 1usize;
|
|
220
|
+
|
|
221
|
+
if mode == 1 && output_len >= 8 {
|
|
222
|
+
return rans_decode_interleaved(encoded, &cum2sym, stats, output_len, &mut pos);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if pos + 4 > encoded.len() {
|
|
226
|
+
return Err(anyhow::anyhow!("Data too short"));
|
|
227
|
+
}
|
|
228
|
+
let mut state = read_state(encoded, &mut pos);
|
|
175
229
|
let mut output = Vec::with_capacity(output_len);
|
|
176
230
|
|
|
177
231
|
for _ in 0..output_len {
|
|
@@ -188,3 +242,45 @@ pub fn rans_decode_block(encoded: &[u8], stats: &SymbolStats, output_len: usize)
|
|
|
188
242
|
|
|
189
243
|
Ok(output)
|
|
190
244
|
}
|
|
245
|
+
|
|
246
|
+
fn rans_decode_interleaved(
|
|
247
|
+
encoded: &[u8],
|
|
248
|
+
cum2sym: &[u8; PROB_SCALE as usize],
|
|
249
|
+
stats: &SymbolStats,
|
|
250
|
+
output_len: usize,
|
|
251
|
+
pos: &mut usize,
|
|
252
|
+
) -> Result<Vec<u8>> {
|
|
253
|
+
if *pos + 8 > encoded.len() {
|
|
254
|
+
return Err(anyhow::anyhow!("Data too short for interleaved"));
|
|
255
|
+
}
|
|
256
|
+
let mut s0 = read_state(encoded, pos);
|
|
257
|
+
let mut s1 = read_state(encoded, pos);
|
|
258
|
+
let mut output = Vec::with_capacity(output_len);
|
|
259
|
+
|
|
260
|
+
let pairs = output_len / 2;
|
|
261
|
+
for _ in 0..pairs {
|
|
262
|
+
let slot0 = s0 & (PROB_SCALE - 1);
|
|
263
|
+
let sym0 = cum2sym[slot0 as usize];
|
|
264
|
+
output.push(sym0);
|
|
265
|
+
let freq0 = stats.freqs[sym0 as usize];
|
|
266
|
+
let start0 = stats.cum_freqs[sym0 as usize];
|
|
267
|
+
s0 = freq0 * (s0 >> PROB_BITS) + slot0 - start0;
|
|
268
|
+
rans_dec_renorm(&mut s0, encoded, pos);
|
|
269
|
+
|
|
270
|
+
let slot1 = s1 & (PROB_SCALE - 1);
|
|
271
|
+
let sym1 = cum2sym[slot1 as usize];
|
|
272
|
+
output.push(sym1);
|
|
273
|
+
let freq1 = stats.freqs[sym1 as usize];
|
|
274
|
+
let start1 = stats.cum_freqs[sym1 as usize];
|
|
275
|
+
s1 = freq1 * (s1 >> PROB_BITS) + slot1 - start1;
|
|
276
|
+
rans_dec_renorm(&mut s1, encoded, pos);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if output_len % 2 != 0 {
|
|
280
|
+
let slot = s1 & (PROB_SCALE - 1);
|
|
281
|
+
let sym = cum2sym[slot as usize];
|
|
282
|
+
output.push(sym);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
Ok(output)
|
|
286
|
+
}
|