lzma1 0.0.6 → 0.1.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/LICENSE CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright [yyyy] [name of copyright owner]
189
+ Copyright 2025 Filip Seman
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
package/lib/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright Filip Seman
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export { compress, compressString, decompress, decompressString, LZMA } from "./lzma.js";
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright Filip Seman
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export { compress, compressString, decompress, decompressString, LZMA } from "./lzma.js";
@@ -1,3 +1,19 @@
1
+ /**
2
+ * Converts a number to a signed 8-bit integer using DataView.
3
+ *
4
+ * Previously, this was done with bitwise operations (value << 24 >> 24), but
5
+ * that approach was obscure and hard to understand. Using DataView improves
6
+ * readability and ensures correct 8-bit conversion.
7
+ */
8
+ export declare function toSigned8bit(value: number): number;
9
+ /**
10
+ * Converts a number to a signed 16-bit integer using DataView.
11
+ *
12
+ * Previously, this was done with bitwise operations (value << 16 >> 16), but
13
+ * that approach was obscure and hard to understand. Using DataView improves
14
+ * readability and ensures correct 16-bit conversion.
15
+ */
16
+ export declare function toSigned16bit(value: number): number;
1
17
  export declare class LZMA {
2
18
  #private;
3
19
  readonly CompressionModes: {
@@ -58,22 +74,39 @@ export declare class LZMA {
58
74
  ReverseGetPrice(Models: number[], startIndex: number, NumBitLevels: number, symbol: number): number;
59
75
  InitBitModels(probs: number[]): void;
60
76
  GetPrice(Prob: number, symbol: number): number;
61
- encode(inputString: string | Uint8Array): number[] | Uint8Array;
62
- compress(data: string | Uint8Array | ArrayBuffer, mode?: keyof typeof this.CompressionModes): Int8Array;
63
- decompress(bytearray: Uint8Array | ArrayBuffer): Int8Array | string;
77
+ encodeString(inputString: string): number[];
78
+ compress(data: Uint8Array | ArrayBuffer, mode?: keyof typeof this.CompressionModes): number[];
79
+ compressString(data: string, mode?: keyof typeof this.CompressionModes): number[];
80
+ decompress(bytearray: Uint8Array | ArrayBuffer): number[];
81
+ decompressString(bytearray: Uint8Array | ArrayBuffer): string;
64
82
  }
65
83
  /**
66
84
  * Compresses data using LZMA algorithm
67
85
  *
68
- * @param data Data to compress - can be string, Uint8Array or ArrayBuffer
86
+ * @param data Data to compress - can be Uint8Array or ArrayBuffer
87
+ * @param mode Compression mode (1-9), defaults to 5
88
+ * @returns Compressed data as a byte array
89
+ */
90
+ export declare function compress(data: Uint8Array | ArrayBuffer, mode?: keyof LZMA["CompressionModes"]): Uint8Array;
91
+ /**
92
+ * Compresses data using LZMA algorithm
93
+ *
94
+ * @param data String to compress
69
95
  * @param mode Compression mode (1-9), defaults to 5
70
- * @returns Compressed data as Int8Array
96
+ * @returns Compressed data as byte array
97
+ */
98
+ export declare function compressString(data: string, mode?: keyof LZMA["CompressionModes"]): Uint8Array;
99
+ /**
100
+ * Decompresses LZMA compressed data
101
+ *
102
+ * @param data Compressed data as Uint8Array or ArrayBuffer
103
+ * @returns Decompressed data
71
104
  */
72
- export declare function compress(data: string | Uint8Array | ArrayBuffer, mode?: keyof LZMA["CompressionModes"]): Int8Array;
105
+ export declare function decompress(data: Uint8Array | ArrayBuffer): Uint8Array;
73
106
  /**
74
107
  * Decompresses LZMA compressed data
75
108
  *
76
109
  * @param data Compressed data as Uint8Array or ArrayBuffer
77
- * @returns Decompressed data as string if input was string, or Int8Array if input was binary
110
+ * @returns Decompressed data as string
78
111
  */
79
- export declare function decompress(data: Uint8Array | ArrayBuffer): string | Int8Array;
112
+ export declare function decompressString(data: Uint8Array | ArrayBuffer): string;
@@ -45,6 +45,32 @@ const CRC32_TABLE = [
45
45
  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
46
46
  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
47
47
  ];
48
+ /**
49
+ * Converts a number to a signed 8-bit integer using DataView.
50
+ *
51
+ * Previously, this was done with bitwise operations (value << 24 >> 24), but
52
+ * that approach was obscure and hard to understand. Using DataView improves
53
+ * readability and ensures correct 8-bit conversion.
54
+ */
55
+ export function toSigned8bit(value) {
56
+ const buffer = new ArrayBuffer(1);
57
+ const view = new DataView(buffer);
58
+ view.setInt8(0, value);
59
+ return view.getInt8(0);
60
+ }
61
+ /**
62
+ * Converts a number to a signed 16-bit integer using DataView.
63
+ *
64
+ * Previously, this was done with bitwise operations (value << 16 >> 16), but
65
+ * that approach was obscure and hard to understand. Using DataView improves
66
+ * readability and ensures correct 16-bit conversion.
67
+ */
68
+ export function toSigned16bit(value) {
69
+ const buffer = new ArrayBuffer(2);
70
+ const view = new DataView(buffer);
71
+ view.setInt16(0, value);
72
+ return view.getInt16(0);
73
+ }
48
74
  export class LZMA {
49
75
  #MAX_UINT32 = 0x100000000; // 2^32
50
76
  #_MAX_UINT32 = 0xFFFFFFFF; // 2^32 - 1
@@ -350,7 +376,7 @@ export class LZMA {
350
376
  return data;
351
377
  }
352
378
  #write(buffer, b) {
353
- buffer.buf[buffer.count++] = b & 0xFF;
379
+ buffer.buf[buffer.count++] = toSigned8bit(b);
354
380
  }
355
381
  #write_0(buffer, buf, off, len) {
356
382
  this.#arraycopy(buf, off, buffer.buf, buffer.count, len);
@@ -442,7 +468,7 @@ export class LZMA {
442
468
  if (r == -1) {
443
469
  throw new Error("truncated input");
444
470
  }
445
- properties[i] = r & 0xFF;
471
+ properties[i] = toSigned8bit(r);
446
472
  }
447
473
  if (!this.#SetDecoderProperties(properties)) {
448
474
  throw new Error("corrupted input");
@@ -1231,7 +1257,7 @@ export class LZMA {
1231
1257
  do {
1232
1258
  symbol = symbol << 1 | this.#decodeBit(decoder.m_Decoders, symbol);
1233
1259
  } while (symbol < 0x100);
1234
- return symbol & 0xFF;
1260
+ return toSigned8bit(symbol);
1235
1261
  }
1236
1262
  #DecodeWithMatchByte(encoder, matchByte) {
1237
1263
  let bit, matchBit, symbol = 1;
@@ -1247,7 +1273,7 @@ export class LZMA {
1247
1273
  break;
1248
1274
  }
1249
1275
  } while (symbol < 0x100);
1250
- return symbol & 0xFF;
1276
+ return toSigned8bit(symbol);
1251
1277
  }
1252
1278
  #createLiteralDecoderEncoder2() {
1253
1279
  const literalDecoder = {
@@ -2341,7 +2367,7 @@ export class LZMA {
2341
2367
  let bit, m = 1, price = 0;
2342
2368
  for (let i = NumBitLevels; i != 0; i -= 1) {
2343
2369
  bit = symbol & 1;
2344
- symbol >>> 1;
2370
+ symbol >>>= 1;
2345
2371
  price += this.#probPrices[((Models[startIndex + m] - bit ^ -bit) & 0x7FF) >>> 2];
2346
2372
  m = m << 1 | bit;
2347
2373
  }
@@ -2353,7 +2379,7 @@ export class LZMA {
2353
2379
  newBound = (rangeDecoder.Range >>> 11) * prob;
2354
2380
  if ((rangeDecoder.Code ^ this.#MIN_INT32) < (newBound ^ this.#MIN_INT32)) {
2355
2381
  rangeDecoder.Range = newBound;
2356
- probs[index] = prob + (0x800 - prob >>> 5) << 0x10 >> 0x10;
2382
+ probs[index] = toSigned16bit(prob + (0x800 - prob >>> 5));
2357
2383
  if (!(rangeDecoder.Range & this.#bitMaskForRange)) {
2358
2384
  rangeDecoder.Code = rangeDecoder.Code << 0x08 | this.#read(rangeDecoder.Stream);
2359
2385
  rangeDecoder.Range <<= 0x08;
@@ -2363,7 +2389,7 @@ export class LZMA {
2363
2389
  else {
2364
2390
  rangeDecoder.Range -= newBound;
2365
2391
  rangeDecoder.Code -= newBound;
2366
- probs[index] = prob - (prob >>> 5) << 0x10 >> 0x10;
2392
+ probs[index] = toSigned16bit(prob - (prob >>> 5));
2367
2393
  if (!(rangeDecoder.Range & this.#bitMaskForRange)) {
2368
2394
  rangeDecoder.Code = rangeDecoder.Code << 0x08 | this.#read(rangeDecoder.Stream);
2369
2395
  rangeDecoder.Range <<= 0x08;
@@ -2405,12 +2431,12 @@ export class LZMA {
2405
2431
  newBound = (rangeEncoder.Range >>> 11) * prob;
2406
2432
  if (!symbol) {
2407
2433
  rangeEncoder.Range = newBound;
2408
- probs[index] = prob + (0x800 - prob >>> 5) << 0x10 >> 0x10;
2434
+ probs[index] = toSigned16bit(prob + (0x800 - prob >>> 5));
2409
2435
  }
2410
2436
  else {
2411
2437
  rangeEncoder.Low = this.#add(rangeEncoder.Low, this.#and(this.#fromInt(newBound), [this.#_MAX_UINT32, 0]));
2412
2438
  rangeEncoder.Range -= newBound;
2413
- probs[index] = prob - (prob >>> 5) << 0x10 >> 0x10;
2439
+ probs[index] = toSigned16bit(prob - (prob >>> 5));
2414
2440
  }
2415
2441
  if (!(rangeEncoder.Range & this.#bitMaskForRange)) {
2416
2442
  rangeEncoder.Range <<= 0x08;
@@ -2444,7 +2470,7 @@ export class LZMA {
2444
2470
  #ShiftLow() {
2445
2471
  const rangeEncoder = this.#compressor.chunker.encoder._rangeEncoder;
2446
2472
  const LowHi = this.#lowBits_0(this.#shru(rangeEncoder.Low, 0x20));
2447
- if (LowHi != 0 || this.#compare(rangeEncoder.Low, [0xFF000000, 0]) < 0) {
2473
+ if (LowHi !== 0 || this.#compare(rangeEncoder.Low, [0xFF000000, 0]) < 0) {
2448
2474
  rangeEncoder._position = this.#add(rangeEncoder._position, this.#fromInt(rangeEncoder._cacheSize));
2449
2475
  let temp = rangeEncoder._cache;
2450
2476
  do {
@@ -2459,7 +2485,7 @@ export class LZMA {
2459
2485
  GetPrice(Prob, symbol) {
2460
2486
  return this.#probPrices[((Prob - symbol ^ -symbol) & 0x7FF) >>> 2];
2461
2487
  }
2462
- #decode(utf) {
2488
+ #decodeString(utf) {
2463
2489
  let j = 0, x, y, z, l = utf.length, buf = [], charCodes = [];
2464
2490
  for (let i = 0; i < l; ++i, ++j) {
2465
2491
  x = utf[i] & 0xFF;
@@ -2521,15 +2547,9 @@ export class LZMA {
2521
2547
  }
2522
2548
  return buf.join("");
2523
2549
  }
2524
- encode(inputString) {
2550
+ encodeString(inputString) {
2525
2551
  let ch, chars = [], elen = 0, l = inputString.length;
2526
- // Be able to handle binary arrays and buffers.
2527
- if (typeof inputString === "object") {
2528
- return inputString;
2529
- }
2530
- else {
2531
- this.#getChars(inputString, 0, l, chars, 0);
2532
- }
2552
+ this.#getChars(inputString, 0, l, chars, 0);
2533
2553
  // Add extra spaces in the array to break up the unicode symbols.
2534
2554
  for (let i = 0; i < l; ++i) {
2535
2555
  ch = chars[i];
@@ -2548,58 +2568,87 @@ export class LZMA {
2548
2568
  for (let i = 0; i < l; ++i) {
2549
2569
  ch = chars[i];
2550
2570
  if (ch >= 1 && ch <= 0x7F) {
2551
- data[elen++] = ch & 0xFF;
2571
+ data[elen++] = toSigned8bit(ch);
2552
2572
  }
2553
- else if (!ch || ch >= 0x80 && ch <= 0x7FF) {
2554
- data[elen++] = (0xC0 | ch >> 6 & 0x1F) & 0xFF;
2555
- data[elen++] = (0x80 | ch & 0x3F) & 0xFF;
2573
+ else if (!ch || (ch >= 0x80 && ch <= 0x7FF)) {
2574
+ data[elen++] = toSigned8bit(0xC0 | (ch >> 6 & 0x1F));
2575
+ data[elen++] = toSigned8bit(0x80 | (ch & 0x3F));
2556
2576
  }
2557
2577
  else {
2558
- data[elen++] = (0xE0 | ch >> 0x0C & 0x0F) & 0xFF;
2559
- data[elen++] = (0x80 | ch >> 6 & 0x3F) & 0xFF;
2560
- data[elen++] = (0x80 | ch & 0x3F) & 0xFF;
2578
+ data[elen++] = toSigned8bit(0xE0 | (ch >> 0x0C) & 0x0F);
2579
+ data[elen++] = toSigned8bit(0x80 | ((ch >> 6) & 0x3F));
2580
+ data[elen++] = toSigned8bit(0x80 | (ch & 0x3F));
2561
2581
  }
2562
2582
  }
2563
2583
  return data;
2564
2584
  }
2565
2585
  compress(data, mode = 5) {
2566
- const encodedData = this.encode(data);
2567
2586
  const compressionMode = this.CompressionModes[mode];
2568
- this.#byteArrayCompressor(encodedData, compressionMode);
2587
+ this.#byteArrayCompressor(data, compressionMode);
2569
2588
  while (this.#processChunkEncode())
2570
2589
  ;
2571
2590
  const compressedByteArray = this.#toByteArray(this.#compressor.output);
2572
- return new Int8Array(compressedByteArray);
2591
+ return compressedByteArray;
2592
+ }
2593
+ compressString(data, mode = 5) {
2594
+ const encodedData = this.encodeString(data);
2595
+ return compress(encodedData, mode);
2573
2596
  }
2574
2597
  decompress(bytearray) {
2575
2598
  this.#byteArrayDecompressor(bytearray);
2576
2599
  while (this.#processChunkDecode())
2577
2600
  ;
2578
2601
  const decodedByteArray = this.#toByteArray(this.#decompressor.output);
2579
- const decoded = this.#decode(decodedByteArray);
2580
- return decoded instanceof Array
2581
- ? new Int8Array(decoded)
2582
- : decoded;
2602
+ return decodedByteArray;
2603
+ }
2604
+ decompressString(bytearray) {
2605
+ this.#byteArrayDecompressor(bytearray);
2606
+ while (this.#processChunkDecode())
2607
+ ;
2608
+ const decodedByteArray = this.#toByteArray(this.#decompressor.output);
2609
+ const decoded = this.#decodeString(decodedByteArray);
2610
+ return decoded;
2583
2611
  }
2584
2612
  }
2585
2613
  /**
2586
2614
  * Compresses data using LZMA algorithm
2587
2615
  *
2588
- * @param data Data to compress - can be string, Uint8Array or ArrayBuffer
2616
+ * @param data Data to compress - can be Uint8Array or ArrayBuffer
2589
2617
  * @param mode Compression mode (1-9), defaults to 5
2590
- * @returns Compressed data as Int8Array
2618
+ * @returns Compressed data as a byte array
2591
2619
  */
2592
2620
  export function compress(data, mode = 5) {
2593
2621
  const lzma = new LZMA();
2594
- return lzma.compress(data, mode);
2622
+ return new Uint8Array(lzma.compress(data, mode));
2623
+ }
2624
+ /**
2625
+ * Compresses data using LZMA algorithm
2626
+ *
2627
+ * @param data String to compress
2628
+ * @param mode Compression mode (1-9), defaults to 5
2629
+ * @returns Compressed data as byte array
2630
+ */
2631
+ export function compressString(data, mode = 5) {
2632
+ const lzma = new LZMA();
2633
+ return lzma.compressString(data, mode);
2595
2634
  }
2596
2635
  /**
2597
2636
  * Decompresses LZMA compressed data
2598
2637
  *
2599
2638
  * @param data Compressed data as Uint8Array or ArrayBuffer
2600
- * @returns Decompressed data as string if input was string, or Int8Array if input was binary
2639
+ * @returns Decompressed data
2601
2640
  */
2602
2641
  export function decompress(data) {
2603
2642
  const lzma = new LZMA();
2604
- return lzma.decompress(data);
2643
+ return new Uint8Array(lzma.decompress(data));
2644
+ }
2645
+ /**
2646
+ * Decompresses LZMA compressed data
2647
+ *
2648
+ * @param data Compressed data as Uint8Array or ArrayBuffer
2649
+ * @returns Decompressed data as string
2650
+ */
2651
+ export function decompressString(data) {
2652
+ const lzma = new LZMA();
2653
+ return lzma.decompressString(data);
2605
2654
  }
package/package.json CHANGED
@@ -1,21 +1,16 @@
1
1
  {
2
2
  "name": "lzma1",
3
3
  "type": "module",
4
- "version": "0.0.6",
4
+ "version": "0.1.0",
5
5
  "license": "Apache-2.0",
6
- "authors": [
7
- "Filip Seman <filip.seman@pm.me>",
8
- "Nathan Rugg <nmrugg@gmail.com> - Original library"
9
- ],
6
+ "author": "Filip Seman <filip.seman@pm.me>",
10
7
  "description": "A JavaScript implementation of the Lempel-Ziv-Markov (LZMA) chain compression algorithm",
11
8
  "funding": "https://github.com/sponsors/xseman",
12
9
  "homepage": "https://github.com/xseman/lzma1#readme",
13
10
  "keywords": [
14
11
  "lzma",
15
12
  "lzma1",
16
- "lzma alone",
17
- "compression",
18
- "decompression"
13
+ "lzma alone"
19
14
  ],
20
15
  "repository": {
21
16
  "type": "git",
@@ -27,23 +22,23 @@
27
22
  "fmt": "dprint fmt",
28
23
  "fmt:check": "dprint check",
29
24
  "typecheck": "tsc --noEmit",
30
- "test": "TS_NODE_TRANSPILE_ONLY=true node --test --experimental-test-coverage --test-coverage-exclude=*.test.ts --loader=ts-node/esm --no-warnings *.test.ts",
31
- "test:watch": "TS_NODE_TRANSPILE_ONLY=true node --test --watch --loader=ts-node/esm --no-warnings *.test.ts"
25
+ "test": "bun test --coverage lzma.test.ts",
26
+ "test:watch": "bun test --watch lzma.test.ts"
32
27
  },
33
28
  "devDependencies": {
34
29
  "@types/node": "^22.13.0",
35
30
  "dprint": "~0.49.0",
36
- "ts-node": "~10.9.0",
37
31
  "typescript": "^5.8.0"
38
32
  },
39
33
  "exports": {
34
+ "./package.json": "./package.json",
40
35
  ".": {
41
- "import": "./dist/index.js",
42
- "types": "./dist/index.d.ts"
36
+ "import": "./lib/index.js",
37
+ "types": "./lib/index.d.ts"
43
38
  }
44
39
  },
45
40
  "files": [
46
- "dist",
47
- "!dist/*test*"
41
+ "lib",
42
+ "!lib/*test*"
48
43
  ]
49
44
  }
package/dist/index.d.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright Filip Seman
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- export { compress, decompress } from "./lzma.js";
package/dist/index.js DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright Filip Seman
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- export { compress, decompress } from "./lzma.js";