roxify 1.16.12 → 1.16.14

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/dist/cli.js CHANGED
@@ -21,7 +21,7 @@ async function loadJsEngine() {
21
21
  };
22
22
  }
23
23
  // Keep in sync with package.json#version.
24
- const VERSION = '1.16.12';
24
+ const VERSION = '1.16.14';
25
25
  function getDirectorySize(dirPath) {
26
26
  let totalSize = 0;
27
27
  try {
@@ -67,20 +67,18 @@ async function readLargeFile(filePath) {
67
67
  }
68
68
  function showHelp() {
69
69
  console.log(`
70
- ROX CLI — Encode/decode binary in PNG or WAV
70
+ ROX CLI — Encode/decode binary in PNG
71
71
 
72
72
  Usage:
73
73
  npx rox <command> [options]
74
74
 
75
75
  Commands:
76
76
  encode <input>... [output] Encode one or more files/directories
77
- decode <input> [output] Decode PNG/WAV to original file
77
+ decode <input> [output] Decode PNG to original file
78
78
  list <input> List files in a Rox archive
79
79
  havepassphrase <input> Check whether the archive requires a passphrase
80
80
 
81
81
  Options:
82
- --image Use PNG container (default)
83
- --sound Use WAV audio container (smaller overhead, faster)
84
82
  -p, --passphrase <pass> Use passphrase (AES-256-GCM)
85
83
  -m, --mode <mode> Mode: screenshot (default)
86
84
  -e, --encrypt <type> auto|aes|xor|none
@@ -101,17 +99,10 @@ Lossy-Resilient Encoding:
101
99
  --ecc-level <level> ECC redundancy: low|medium|quartile|high (default: medium)
102
100
  --block-size <n> Robust image block size: 2-8 pixels (default: 4)
103
101
 
104
- When --lossy-resilient is active, data is encoded with Reed-Solomon ECC
105
- and rendered as a QR-code-style grid (image) or MFSK tones (audio).
106
- Use --sound or --image to choose the container format.
107
-
108
102
  Examples:
109
103
  npx rox encode secret.pdf Encode to PNG
110
- npx rox encode secret.pdf --sound Encode to WAV
111
104
  npx rox encode secret.pdf --lossy-resilient Lossy-resilient PNG
112
- npx rox encode secret.pdf --lossy-resilient --sound --ecc-level high
113
105
  npx rox decode secret.pdf.png Decode back
114
- npx rox decode secret.pdf.wav Decode WAV back
115
106
 
116
107
  Run "npx rox help" for this message.
117
108
  `);
@@ -173,21 +164,18 @@ function parseArgs(args) {
173
164
  parsed.blockSize = bs;
174
165
  i += 2;
175
166
  }
176
- else if (key === 'sound') {
177
- parsed.container = 'sound';
178
- i++;
179
- }
180
- else if (key === 'image') {
181
- parsed.container = 'image';
182
- i++;
183
- }
184
167
  else if (key === 'debug-dir') {
185
168
  parsed.debugDir = args[i + 1];
186
169
  i += 2;
187
170
  }
188
171
  else if (key === 'files') {
189
- parsed.files = args[i + 1].split(',');
190
- i += 2;
172
+ if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
173
+ parsed.files = args[i + 1].split(',');
174
+ i += 2;
175
+ }
176
+ else {
177
+ i++;
178
+ }
191
179
  }
192
180
  else if (key === 'dict') {
193
181
  parsed.dict = args[i + 1];
@@ -276,14 +264,13 @@ async function encodeCommand(args) {
276
264
  safeCwd = '/';
277
265
  }
278
266
  const resolvedInputs = inputPaths.map((p) => resolve(safeCwd, p));
279
- const containerMode = parsed.container || 'image'; // default: image (PNG)
280
- const containerExt = containerMode === 'sound' ? '.wav' : '.png';
281
- let outputName = inputPaths.length === 1 ? basename(firstInput) : 'archive';
267
+ const outputNameBase = inputPaths.length === 1 ? basename(firstInput) : 'archive';
268
+ let outputName = outputNameBase;
282
269
  if (inputPaths.length === 1 && !statSync(resolvedInputs[0]).isDirectory()) {
283
- outputName = outputName.replace(/(\.[^.]+)?$/, containerExt);
270
+ outputName = outputNameBase.replace(/(\.[^.]+)?$/, '.png');
284
271
  }
285
272
  else {
286
- outputName += containerExt;
273
+ outputName = outputNameBase + '.png';
287
274
  }
288
275
  let resolvedOutput;
289
276
  try {
@@ -312,7 +299,7 @@ async function encodeCommand(args) {
312
299
  }
313
300
  }
314
301
  catch (e) { }
315
- if (isRustBinaryAvailable() && !parsed.forceTs && containerMode !== 'sound') {
302
+ if (isRustBinaryAvailable() && !parsed.forceTs) {
316
303
  try {
317
304
  console.log(`Encoding to ${resolvedOutput} (Using native Rust encoder)\n`);
318
305
  const startTime = Date.now();
@@ -410,7 +397,6 @@ async function encodeCommand(args) {
410
397
  skipOptimization: false,
411
398
  compressionLevel: 6,
412
399
  outputFormat: 'auto',
413
- container: containerMode,
414
400
  });
415
401
  if (parsed.verbose)
416
402
  options.verbose = true;
@@ -427,7 +413,7 @@ async function encodeCommand(args) {
427
413
  if (parsed.blockSize)
428
414
  options.robustBlockSize = parsed.blockSize;
429
415
  }
430
- console.log(`Encoding to ${resolvedOutput} (Mode: ${mode}, Container: ${containerMode === 'sound' ? 'WAV' : 'PNG'})\n`);
416
+ console.log(`Encoding to ${resolvedOutput}\n`);
431
417
  let inputData;
432
418
  let inputSizeVal = 0;
433
419
  let displayName;
@@ -763,6 +749,7 @@ async function main() {
763
749
  await encodeCommand(commandArgs);
764
750
  break;
765
751
  case 'decode':
752
+ case 'decompress':
766
753
  await decodeCommand(commandArgs);
767
754
  break;
768
755
  case 'list':
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from './utils/audio.js';
2
1
  export * from './utils/constants.js';
3
2
  export * from './utils/crc.js';
4
3
  export * from './utils/decoder.js';
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- export * from './utils/audio.js';
2
1
  export * from './utils/constants.js';
3
2
  export * from './utils/crc.js';
4
3
  export * from './utils/decoder.js';
@@ -43,28 +43,14 @@ export async function encodeBinaryToPng(input, opts = {}) {
43
43
  const fileListJson = opts.includeFileList && opts.fileList
44
44
  ? normalizeNativeFileList(opts.fileList)
45
45
  : undefined;
46
- // --- PNG container via native Rust encoder ---
47
- if (opts.container === 'sound') {
48
- if (opts.passphrase) {
49
- const encryptType = opts.encrypt && opts.encrypt !== 'auto' ? opts.encrypt : 'aes';
50
- const result = native.nativeEncodeWavWithEncryptionNameAndFilelist(inputBuf, compressionLevel, opts.passphrase, encryptType, fileName, fileListJson);
51
- return Buffer.from(result);
52
- }
53
- else {
54
- const result = native.nativeEncodeWavWithNameAndFilelist(inputBuf, compressionLevel, fileName, fileListJson);
55
- return Buffer.from(result);
56
- }
46
+ if (opts.passphrase) {
47
+ const encryptType = opts.encrypt && opts.encrypt !== 'auto' ? opts.encrypt : 'aes';
48
+ const result = native.nativeEncodePngWithEncryptionNameAndFilelist(inputBuf, compressionLevel, opts.passphrase, encryptType, fileName, fileListJson);
49
+ return Buffer.from(result);
57
50
  }
58
51
  else {
59
- if (opts.passphrase) {
60
- const encryptType = opts.encrypt && opts.encrypt !== 'auto' ? opts.encrypt : 'aes';
61
- const result = native.nativeEncodePngWithEncryptionNameAndFilelist(inputBuf, compressionLevel, opts.passphrase, encryptType, fileName, fileListJson);
62
- return Buffer.from(result);
63
- }
64
- else {
65
- const result = native.nativeEncodePngWithNameAndFilelist(inputBuf, compressionLevel, fileName, fileListJson);
66
- return Buffer.from(result);
67
- }
52
+ const result = native.nativeEncodePngWithNameAndFilelist(inputBuf, compressionLevel, fileName, fileListJson);
53
+ return Buffer.from(result);
68
54
  }
69
55
  }
70
56
  function normalizeNativeFileList(fileList) {
@@ -13,8 +13,6 @@ export interface EncodeOptions {
13
13
  _skipAuto?: boolean;
14
14
  output?: 'auto' | 'png' | 'rox';
15
15
  outputFormat?: 'png' | 'webp';
16
- /** Container format: 'image' (PNG, default) or 'sound' (WAV) */
17
- container?: 'image' | 'sound';
18
16
  /**
19
17
  * Enable lossy-resilient encoding. When true, the output survives lossy
20
18
  * compression (MP3/AAC for audio, JPEG/WebP for image) using QR-code-like
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roxify",
3
- "version": "1.16.12",
3
+ "version": "1.16.14",
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",
@@ -1,23 +0,0 @@
1
- /**
2
- * WAV container for binary data.
3
- *
4
- * Encodes raw bytes as 8-bit unsigned PCM mono samples (44100 Hz).
5
- * Header is exactly 44 bytes. Total container overhead: 44 bytes (constant).
6
- *
7
- * Compared to PNG (stored deflate): PNG overhead grows with data size
8
- * (zlib framing, filter bytes, chunk CRCs). WAV overhead is constant.
9
- */
10
- /**
11
- * Pack raw bytes into a WAV file (8-bit PCM, mono, 44100 Hz).
12
- * The bytes are stored directly as unsigned PCM samples.
13
- */
14
- export declare function bytesToWav(data: Buffer): Buffer;
15
- /**
16
- * Extract raw bytes from a WAV file.
17
- * Returns the PCM data (the original bytes).
18
- */
19
- export declare function wavToBytes(wav: Buffer): Buffer;
20
- /**
21
- * Check if a buffer starts with a RIFF/WAVE header.
22
- */
23
- export declare function isWav(buf: Buffer): boolean;
@@ -1,98 +0,0 @@
1
- /**
2
- * WAV container for binary data.
3
- *
4
- * Encodes raw bytes as 8-bit unsigned PCM mono samples (44100 Hz).
5
- * Header is exactly 44 bytes. Total container overhead: 44 bytes (constant).
6
- *
7
- * Compared to PNG (stored deflate): PNG overhead grows with data size
8
- * (zlib framing, filter bytes, chunk CRCs). WAV overhead is constant.
9
- */
10
- const WAV_HEADER_SIZE = 44;
11
- const SAMPLE_RATE = 44100;
12
- const BITS_PER_SAMPLE = 8;
13
- const NUM_CHANNELS = 1;
14
- /**
15
- * Pack raw bytes into a WAV file (8-bit PCM, mono, 44100 Hz).
16
- * The bytes are stored directly as unsigned PCM samples.
17
- */
18
- export function bytesToWav(data) {
19
- const dataSize = data.length;
20
- const fileSize = WAV_HEADER_SIZE - 8 + dataSize;
21
- const byteRate = SAMPLE_RATE * NUM_CHANNELS * (BITS_PER_SAMPLE / 8);
22
- const blockAlign = NUM_CHANNELS * (BITS_PER_SAMPLE / 8);
23
- const wav = Buffer.alloc(WAV_HEADER_SIZE + dataSize);
24
- let offset = 0;
25
- // RIFF header
26
- wav.write('RIFF', offset, 'ascii');
27
- offset += 4;
28
- wav.writeUInt32LE(fileSize, offset);
29
- offset += 4;
30
- wav.write('WAVE', offset, 'ascii');
31
- offset += 4;
32
- // fmt sub-chunk
33
- wav.write('fmt ', offset, 'ascii');
34
- offset += 4;
35
- wav.writeUInt32LE(16, offset);
36
- offset += 4; // sub-chunk size (PCM = 16)
37
- wav.writeUInt16LE(1, offset);
38
- offset += 2; // audio format (1 = PCM)
39
- wav.writeUInt16LE(NUM_CHANNELS, offset);
40
- offset += 2;
41
- wav.writeUInt32LE(SAMPLE_RATE, offset);
42
- offset += 4;
43
- wav.writeUInt32LE(byteRate, offset);
44
- offset += 4;
45
- wav.writeUInt16LE(blockAlign, offset);
46
- offset += 2;
47
- wav.writeUInt16LE(BITS_PER_SAMPLE, offset);
48
- offset += 2;
49
- // data sub-chunk
50
- wav.write('data', offset, 'ascii');
51
- offset += 4;
52
- wav.writeUInt32LE(dataSize, offset);
53
- offset += 4;
54
- data.copy(wav, offset);
55
- return wav;
56
- }
57
- /**
58
- * Extract raw bytes from a WAV file.
59
- * Returns the PCM data (the original bytes).
60
- */
61
- export function wavToBytes(wav) {
62
- if (wav.length < WAV_HEADER_SIZE) {
63
- throw new Error('WAV data too short');
64
- }
65
- if (wav.toString('ascii', 0, 4) !== 'RIFF') {
66
- throw new Error('Not a RIFF file');
67
- }
68
- if (wav.toString('ascii', 8, 12) !== 'WAVE') {
69
- throw new Error('Not a WAVE file');
70
- }
71
- // Find the "data" sub-chunk
72
- let offset = 12;
73
- while (offset + 8 <= wav.length) {
74
- const chunkId = wav.toString('ascii', offset, offset + 4);
75
- const chunkSize = wav.readUInt32LE(offset + 4);
76
- if (chunkId === 'data') {
77
- const dataStart = offset + 8;
78
- const dataEnd = dataStart + chunkSize;
79
- if (dataEnd > wav.length) {
80
- return wav.subarray(dataStart);
81
- }
82
- return wav.subarray(dataStart, dataEnd);
83
- }
84
- offset += 8 + chunkSize;
85
- if (chunkSize % 2 !== 0)
86
- offset += 1; // RIFF word alignment
87
- }
88
- throw new Error('data chunk not found in WAV');
89
- }
90
- /**
91
- * Check if a buffer starts with a RIFF/WAVE header.
92
- */
93
- export function isWav(buf) {
94
- return (buf.length >= 12 &&
95
- buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && // RIFF
96
- buf[8] === 0x57 && buf[9] === 0x41 && buf[10] === 0x56 && buf[11] === 0x45 // WAVE
97
- );
98
- }