roxify 1.13.2 → 1.13.3

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.
@@ -42,21 +42,14 @@ pub fn encode_dir_to_png_encrypted_with_progress(
42
42
  encrypt_type: Option<&str>,
43
43
  progress: Option<ProgressCallback>,
44
44
  ) -> anyhow::Result<()> {
45
- let tmp_zst = output_path.with_extension("tmp.zst");
46
-
47
- let file_list = compress_dir_to_zst(dir_path, &tmp_zst, compression_level, &progress)?;
48
-
49
- if let Some(ref cb) = progress {
50
- cb(90, 100, "writing_png");
51
- }
45
+ let (zst_buf, file_list) = compress_dir_to_zst_mem(dir_path, compression_level, &progress)?;
52
46
 
53
47
  let file_list_json = serde_json::to_string(&file_list)?;
54
48
 
55
- let result = write_png_from_zst(
56
- &tmp_zst, output_path, name, Some(&file_list_json),
57
- passphrase, encrypt_type,
49
+ let result = write_png_from_zst_mem(
50
+ zst_buf, output_path, name, Some(&file_list_json),
51
+ passphrase, encrypt_type, &progress,
58
52
  );
59
- let _ = std::fs::remove_file(&tmp_zst);
60
53
 
61
54
  if let Some(ref cb) = progress {
62
55
  cb(100, 100, "done");
@@ -65,12 +58,11 @@ pub fn encode_dir_to_png_encrypted_with_progress(
65
58
  result
66
59
  }
67
60
 
68
- fn compress_dir_to_zst(
61
+ fn compress_dir_to_zst_mem(
69
62
  dir_path: &Path,
70
- zst_path: &Path,
71
63
  compression_level: i32,
72
64
  progress: &Option<ProgressCallback>,
73
- ) -> anyhow::Result<Vec<serde_json::Value>> {
65
+ ) -> anyhow::Result<(Vec<u8>, Vec<serde_json::Value>)> {
74
66
  let base = dir_path;
75
67
 
76
68
  let entries: Vec<_> = WalkDir::new(dir_path)
@@ -80,13 +72,13 @@ fn compress_dir_to_zst(
80
72
  .filter(|e| e.file_type().is_file())
81
73
  .collect();
82
74
 
83
- let total_files = entries.len() as u64;
84
-
85
- let zst_file = File::create(zst_path)?;
86
- let buf_writer = BufWriter::with_capacity(16 * 1024 * 1024, zst_file);
75
+ let total_bytes: u64 = entries.iter()
76
+ .filter_map(|e| std::fs::metadata(e.path()).ok())
77
+ .map(|m| m.len())
78
+ .sum();
87
79
 
88
80
  let actual_level = compression_level.min(3);
89
- let mut encoder = zstd::stream::Encoder::new(buf_writer, actual_level)
81
+ let mut encoder = zstd::stream::Encoder::new(Vec::with_capacity(16 * 1024 * 1024), actual_level)
90
82
  .map_err(|e| anyhow::anyhow!("zstd init: {}", e))?;
91
83
 
92
84
  let threads = num_cpus::get() as u32;
@@ -99,9 +91,11 @@ fn compress_dir_to_zst(
99
91
  encoder.write_all(MAGIC)?;
100
92
 
101
93
  let mut file_list = Vec::new();
94
+ let mut bytes_processed: u64 = 0;
95
+ let mut last_pct: u64 = 0;
102
96
  {
103
97
  let mut tar_builder = Builder::new(&mut encoder);
104
- for (idx, entry) in entries.iter().enumerate() {
98
+ for entry in entries.iter() {
105
99
  let full = entry.path();
106
100
  let rel = full.strip_prefix(base).unwrap_or(full);
107
101
  let rel_str = rel.to_string_lossy().replace('\\', "/");
@@ -131,28 +125,37 @@ fn compress_dir_to_zst(
131
125
 
132
126
  file_list.push(serde_json::json!({"name": rel_str, "size": size}));
133
127
 
128
+ bytes_processed += size;
134
129
  if let Some(ref cb) = progress {
135
- let pct = ((idx as u64 + 1) * 85 / total_files.max(1)).min(85);
136
- cb(pct, 100, "compressing");
130
+ let pct = if total_bytes > 0 {
131
+ (bytes_processed * 89 / total_bytes).min(89)
132
+ } else {
133
+ 89
134
+ };
135
+ if pct > last_pct {
136
+ last_pct = pct;
137
+ cb(pct, 100, "compressing");
138
+ }
137
139
  }
138
140
  }
139
141
  tar_builder.finish().map_err(|e| anyhow::anyhow!("tar finish: {}", e))?;
140
142
  }
141
143
 
142
- encoder.finish().map_err(|e| anyhow::anyhow!("zstd finish: {}", e))?;
144
+ let zst_buf = encoder.finish().map_err(|e| anyhow::anyhow!("zstd finish: {}", e))?;
143
145
 
144
- Ok(file_list)
146
+ Ok((zst_buf, file_list))
145
147
  }
146
148
 
147
- fn write_png_from_zst(
148
- zst_path: &Path,
149
+ fn write_png_from_zst_mem(
150
+ zst_buf: Vec<u8>,
149
151
  output_path: &Path,
150
152
  name: Option<&str>,
151
153
  file_list: Option<&str>,
152
154
  passphrase: Option<&str>,
153
155
  _encrypt_type: Option<&str>,
156
+ progress: &Option<ProgressCallback>,
154
157
  ) -> anyhow::Result<()> {
155
- let zst_size = std::fs::metadata(zst_path)?.len() as usize;
158
+ let zst_size = zst_buf.len();
156
159
 
157
160
  let mut encryptor = match passphrase {
158
161
  Some(pass) if !pass.is_empty() => Some(crate::crypto::StreamingEncryptor::new(pass)?),
@@ -239,8 +242,7 @@ fn write_png_from_zst(
239
242
  ihdr[9] = 2;
240
243
  write_chunk_hdr(&mut w, b"IHDR", &ihdr)?;
241
244
 
242
- let mut zst_file = File::open(zst_path)?;
243
- let mut zst_reader = std::io::BufReader::with_capacity(16 * 1024 * 1024, &mut zst_file);
245
+ let mut zst_reader = std::io::Cursor::new(zst_buf);
244
246
 
245
247
  write_idat_streaming(
246
248
  &mut w,
@@ -255,6 +257,7 @@ fn write_png_from_zst(
255
257
  marker_end_pos,
256
258
  idat_len,
257
259
  total_data_bytes,
260
+ progress,
258
261
  )?;
259
262
 
260
263
  if let Some(fl) = file_list {
@@ -291,6 +294,7 @@ fn write_idat_streaming<W: Write, R: Read>(
291
294
  marker_end_pos: usize,
292
295
  idat_len: usize,
293
296
  total_data_bytes: usize,
297
+ progress: &Option<ProgressCallback>,
294
298
  ) -> anyhow::Result<()> {
295
299
  w.write_all(&(idat_len as u32).to_be_bytes())?;
296
300
  w.write_all(b"IDAT")?;
@@ -323,14 +327,15 @@ fn write_idat_streaming<W: Write, R: Read>(
323
327
  let mut fl_pos: usize = 0;
324
328
  let mut zero_remaining = padding_after;
325
329
 
326
- let mut adler_a: u32 = 1;
327
- let mut adler_b: u32 = 0;
330
+ let mut adler = simd_adler32::Adler32::new();
328
331
 
329
332
  let buf_size = 1024 * 1024;
330
333
  let mut transfer_buf = vec![0u8; buf_size];
331
334
  let zero_buf = vec![0u8; buf_size];
332
335
 
333
- for _row in 0..height {
336
+ let mut last_png_pct: u64 = 89;
337
+
338
+ for row_idx in 0..height {
334
339
  if deflate_block_remaining == 0 {
335
340
  let remaining_scanlines = scanlines_total - scanline_pos;
336
341
  let block_size = remaining_scanlines.min(65535);
@@ -350,8 +355,7 @@ fn write_idat_streaming<W: Write, R: Read>(
350
355
  let filter_byte = [0u8];
351
356
  w.write_all(&filter_byte)?;
352
357
  crc.update(&filter_byte);
353
- adler_a = (adler_a + 0) % 65521;
354
- adler_b = (adler_b + adler_a) % 65521;
358
+ adler.write(&filter_byte);
355
359
  scanline_pos += 1;
356
360
  deflate_block_remaining -= 1;
357
361
 
@@ -388,10 +392,7 @@ fn write_idat_streaming<W: Write, R: Read>(
388
392
  let slice = &marker_end_bytes[me_offset..me_offset + take];
389
393
  w.write_all(slice)?;
390
394
  crc.update(slice);
391
- for &b in slice {
392
- adler_a = (adler_a + b as u32) % 65521;
393
- adler_b = (adler_b + adler_a) % 65521;
394
- }
395
+ adler.write(slice);
395
396
  flat_pos += take;
396
397
  chunk_written += take;
397
398
  scanline_pos += take;
@@ -406,10 +407,7 @@ fn write_idat_streaming<W: Write, R: Read>(
406
407
  let slice = &header_bytes[header_pos..header_pos + take];
407
408
  w.write_all(slice)?;
408
409
  crc.update(slice);
409
- for &b in slice {
410
- adler_a = (adler_a + b as u32) % 65521;
411
- adler_b = (adler_b + adler_a) % 65521;
412
- }
410
+ adler.write(slice);
413
411
  header_pos += take;
414
412
  flat_pos += take;
415
413
  chunk_written += take;
@@ -426,10 +424,7 @@ fn write_idat_streaming<W: Write, R: Read>(
426
424
  }
427
425
  w.write_all(&transfer_buf[..got])?;
428
426
  crc.update(&transfer_buf[..got]);
429
- for &b in &transfer_buf[..got] {
430
- adler_a = (adler_a + b as u32) % 65521;
431
- adler_b = (adler_b + adler_a) % 65521;
432
- }
427
+ adler.write(&transfer_buf[..got]);
433
428
  zst_remaining -= got;
434
429
  flat_pos += got;
435
430
  chunk_written += got;
@@ -448,10 +443,7 @@ fn write_idat_streaming<W: Write, R: Read>(
448
443
  let slice = &hmac_bytes[hmac_pos..hmac_pos + take];
449
444
  w.write_all(slice)?;
450
445
  crc.update(slice);
451
- for &b in slice {
452
- adler_a = (adler_a + b as u32) % 65521;
453
- adler_b = (adler_b + adler_a) % 65521;
454
- }
446
+ adler.write(slice);
455
447
  hmac_pos += take;
456
448
  flat_pos += take;
457
449
  chunk_written += take;
@@ -470,10 +462,7 @@ fn write_idat_streaming<W: Write, R: Read>(
470
462
  let slice = &fl_chunk_data[fl_pos..fl_pos + take];
471
463
  w.write_all(slice)?;
472
464
  crc.update(slice);
473
- for &b in slice {
474
- adler_a = (adler_a + b as u32) % 65521;
475
- adler_b = (adler_b + adler_a) % 65521;
476
- }
465
+ adler.write(slice);
477
466
  fl_pos += take;
478
467
  flat_pos += take;
479
468
  chunk_written += take;
@@ -490,9 +479,7 @@ fn write_idat_streaming<W: Write, R: Read>(
490
479
  if take == 0 { break; }
491
480
  w.write_all(&zero_buf[..take])?;
492
481
  crc.update(&zero_buf[..take]);
493
- for _ in 0..take {
494
- adler_b = (adler_b + adler_a) % 65521;
495
- }
482
+ adler.write(&zero_buf[..take]);
496
483
  zero_remaining -= take;
497
484
  flat_pos += take;
498
485
  chunk_written += take;
@@ -502,10 +489,18 @@ fn write_idat_streaming<W: Write, R: Read>(
502
489
  }
503
490
  }
504
491
  }
492
+
493
+ if let Some(ref cb) = progress {
494
+ let pct = 90 + ((row_idx as u64 + 1) * 9 / height as u64).min(9);
495
+ if pct > last_png_pct {
496
+ last_png_pct = pct;
497
+ cb(pct, 100, "writing_png");
498
+ }
499
+ }
505
500
  }
506
501
 
507
- let adler = (adler_b << 16) | adler_a;
508
- let adler_bytes = adler.to_be_bytes();
502
+ let adler_val = adler.finish();
503
+ let adler_bytes = adler_val.to_be_bytes();
509
504
  w.write_all(&adler_bytes)?;
510
505
  crc.update(&adler_bytes);
511
506
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roxify",
3
- "version": "1.13.2",
3
+ "version": "1.13.3",
4
4
  "type": "module",
5
5
  "description": "Ultra-lightweight PNG steganography with native Rust acceleration. Encode binary data into PNG images with zstd compression.",
6
6
  "main": "dist/index.js",