lzma1 0.1.2 → 0.3.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/lib/index.js CHANGED
@@ -3,8 +3,8 @@
3
3
  * Copyright Filip Seman
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
- import { LZMA } from "./lzma.js";
7
- export { LZMA } from "./lzma.js";
6
+ import { LZMA, } from "./lzma.js";
7
+ export { CRC32_TABLE } from "./utils.js";
8
8
  /**
9
9
  * Compresses data using LZMA algorithm
10
10
  *
@@ -13,8 +13,12 @@ export { LZMA } from "./lzma.js";
13
13
  * @returns Compressed data as a byte array
14
14
  */
15
15
  export function compress(data, mode = 5) {
16
- const lzma = new LZMA();
17
- return new Uint8Array(lzma.compress(data, mode));
16
+ // Convert ArrayBuffer to Uint8Array if needed
17
+ const input = data instanceof ArrayBuffer
18
+ ? new Uint8Array(data)
19
+ : data;
20
+ const result = new LZMA().compress(input, mode);
21
+ return new Uint8Array(result);
18
22
  }
19
23
  /**
20
24
  * Compresses data using LZMA algorithm
@@ -24,8 +28,8 @@ export function compress(data, mode = 5) {
24
28
  * @returns Compressed data as byte array
25
29
  */
26
30
  export function compressString(data, mode = 5) {
27
- const lzma = new LZMA();
28
- return new Uint8Array(lzma.compressString(data, mode));
31
+ const compressedData = new LZMA().compressString(data, mode);
32
+ return new Uint8Array(compressedData);
29
33
  }
30
34
  /**
31
35
  * Decompresses LZMA compressed data
@@ -34,8 +38,11 @@ export function compressString(data, mode = 5) {
34
38
  * @returns Decompressed data
35
39
  */
36
40
  export function decompress(data) {
37
- const lzma = new LZMA();
38
- return new Uint8Array(lzma.decompress(data));
41
+ const input = data instanceof ArrayBuffer
42
+ ? new Uint8Array(data)
43
+ : data;
44
+ const decompressedData = new LZMA().decompress(input);
45
+ return new Uint8Array(decompressedData);
39
46
  }
40
47
  /**
41
48
  * Decompresses LZMA compressed data
@@ -44,6 +51,5 @@ export function decompress(data) {
44
51
  * @returns Decompressed data as string
45
52
  */
46
53
  export function decompressString(data) {
47
- const lzma = new LZMA();
48
- return lzma.decompressString(data);
54
+ return new LZMA().decompressString(data);
49
55
  }
@@ -0,0 +1,171 @@
1
+ import { createBitTree, getBitPrice, initArray, initBitModels, } from "./utils.js";
2
+ /**
3
+ * Length encoder class for LZMA compression
4
+ * Handles encoding of match lengths with price optimization
5
+ */
6
+ export class LenEncoder {
7
+ // Choice probability arrays for length range selection
8
+ choice = initArray(2);
9
+ // Low range coders (for lengths 2-9)
10
+ lowCoder = [];
11
+ // Mid range coders (for lengths 10-17)
12
+ midCoder = [];
13
+ // High range coder (for lengths 18+)
14
+ highCoder = createBitTree(8);
15
+ // Price optimization properties
16
+ tableSize = 0;
17
+ prices = [];
18
+ counters = [];
19
+ constructor() {
20
+ // Initialize low and mid coders for all position states (up to 16)
21
+ for (let posState = 0; posState < 16; ++posState) {
22
+ this.lowCoder[posState] = createBitTree(3);
23
+ this.midCoder[posState] = createBitTree(3);
24
+ }
25
+ }
26
+ /**
27
+ * Initialize the encoder with specified number of position states
28
+ */
29
+ init(numPosStates) {
30
+ // Initialize choice probability models
31
+ initBitModels(this.choice);
32
+ // Initialize low and mid coders for each position state
33
+ for (let posState = 0; posState < numPosStates; ++posState) {
34
+ initBitModels(this.lowCoder[posState].models);
35
+ initBitModels(this.midCoder[posState].models);
36
+ }
37
+ // Initialize high coder
38
+ initBitModels(this.highCoder.models);
39
+ }
40
+ /**
41
+ * Encode a length value using the provided range encoder
42
+ */
43
+ encode(symbol, posState, rangeEncoder) {
44
+ if (symbol < 8) {
45
+ // Length 2-9: use low coder
46
+ rangeEncoder.encodeBit(this.choice, 0, 0);
47
+ rangeEncoder.encodeBitTree(this.lowCoder[posState], symbol);
48
+ }
49
+ else {
50
+ symbol -= 8;
51
+ rangeEncoder.encodeBit(this.choice, 0, 1);
52
+ if (symbol < 8) {
53
+ // Length 10-17: use mid coder
54
+ rangeEncoder.encodeBit(this.choice, 1, 0);
55
+ rangeEncoder.encodeBitTree(this.midCoder[posState], symbol);
56
+ }
57
+ else {
58
+ // Length 18+: use high coder
59
+ rangeEncoder.encodeBit(this.choice, 1, 1);
60
+ rangeEncoder.encodeBitTree(this.highCoder, symbol - 8);
61
+ }
62
+ }
63
+ }
64
+ /**
65
+ * Encode with price table update
66
+ */
67
+ encodeWithUpdate(symbol, posState, rangeEncoder) {
68
+ this.encode(symbol, posState, rangeEncoder);
69
+ if (this.counters && (this.counters[posState] -= 1) == 0) {
70
+ // Reset counter and update prices if needed
71
+ this.counters[posState] = this.tableSize;
72
+ }
73
+ }
74
+ /**
75
+ * Get price for encoding a symbol at the given position state
76
+ */
77
+ getPrice(symbol, posState) {
78
+ return this.prices[posState * 0x110 + symbol];
79
+ }
80
+ /**
81
+ * Initialize as a price table encoder
82
+ */
83
+ initPriceTable() {
84
+ this.prices = [];
85
+ this.counters = [];
86
+ }
87
+ /**
88
+ * Set table size for price optimization
89
+ */
90
+ setTableSize(size) {
91
+ this.tableSize = size;
92
+ }
93
+ /**
94
+ * Set table size and update internal counters
95
+ */
96
+ setTableSizeAndInitCounters(size, numPosStates) {
97
+ this.tableSize = size;
98
+ if (this.counters) {
99
+ for (let posState = 0; posState < numPosStates; ++posState) {
100
+ this.counters[posState] = size;
101
+ }
102
+ }
103
+ }
104
+ /**
105
+ * Get table size
106
+ */
107
+ getTableSize() {
108
+ return this.tableSize;
109
+ }
110
+ /**
111
+ * Update price tables for all position states
112
+ */
113
+ updateTables(numPosStates) {
114
+ if (!this.prices || !this.counters) {
115
+ this.initPriceTable();
116
+ }
117
+ for (let posState = 0; posState < numPosStates; ++posState) {
118
+ this.setPrices(posState, this.tableSize, this.prices, 0);
119
+ if (this.counters) {
120
+ this.counters[posState] = this.tableSize;
121
+ }
122
+ }
123
+ }
124
+ // Private methods for internal state management
125
+ /**
126
+ * Calculate price for bit tree encoder
127
+ */
128
+ getBitTreePrice(encoder, symbol) {
129
+ let bit, bitIndex, m = 1, price = 0;
130
+ for (bitIndex = encoder.numBitLevels; bitIndex != 0;) {
131
+ bitIndex -= 1;
132
+ bit = symbol >>> bitIndex & 1;
133
+ price += this.getBitPrice(encoder.models[m], bit);
134
+ m = (m << 1) + bit;
135
+ }
136
+ return price;
137
+ }
138
+ /**
139
+ * Get price for a single bit
140
+ */
141
+ getBitPrice(prob, symbol) {
142
+ return getBitPrice(prob, symbol);
143
+ }
144
+ /**
145
+ * Set prices for all symbols in a position state range
146
+ */
147
+ setPrices(posState, numSymbols, prices, priceIndex) {
148
+ const a0 = this.getBitPrice(this.choice[0], 0);
149
+ const a1 = this.getBitPrice(this.choice[0], 1);
150
+ const b0 = a1 + this.getBitPrice(this.choice[1], 0);
151
+ const b1 = a1 + this.getBitPrice(this.choice[1], 1);
152
+ let i = 0;
153
+ const st = priceIndex + posState * 0x110;
154
+ // Set prices for low range (lengths 2-9)
155
+ for (i = 0; i < 8; ++i) {
156
+ if (i >= numSymbols)
157
+ return;
158
+ prices[st + i] = a0 + this.getBitTreePrice(this.lowCoder[posState], i);
159
+ }
160
+ // Set prices for mid range (lengths 10-17)
161
+ for (; i < 16; ++i) {
162
+ if (i >= numSymbols)
163
+ return;
164
+ prices[st + i] = b0 + this.getBitTreePrice(this.midCoder[posState], i - 8);
165
+ }
166
+ // Set prices for high range (lengths 18+)
167
+ for (; i < numSymbols; ++i) {
168
+ prices[st + i] = b1 + this.getBitTreePrice(this.highCoder, i - 8 - 8);
169
+ }
170
+ }
171
+ }
@@ -0,0 +1,162 @@
1
+ import { getBitPrice, initArray, } from "./utils.js";
2
+ export class LitSubCoder {
3
+ coders;
4
+ constructor() {
5
+ this.coders = initArray(0x300, 0x400);
6
+ }
7
+ /**
8
+ * Decode normal literal symbol
9
+ */
10
+ decodeNormal(rd) {
11
+ let symbol = 1;
12
+ while (symbol < 0x100) {
13
+ const i = rd.decodeBit(this.coders, symbol);
14
+ symbol = (symbol << 1) | i;
15
+ }
16
+ return symbol & 0xFF;
17
+ }
18
+ /**
19
+ * Decode literal symbol with match byte context
20
+ */
21
+ decodeWithMatchByte(rd, matchByte) {
22
+ let uMatchByte = matchByte;
23
+ let symbol = 1;
24
+ while (symbol < 0x100) {
25
+ const matchBit = (uMatchByte >> 7) & 1;
26
+ uMatchByte <<= 1;
27
+ const bit = rd.decodeBit(this.coders, ((1 + matchBit) << 8) + symbol);
28
+ symbol = (symbol << 1) | bit;
29
+ if (matchBit !== bit) {
30
+ while (symbol < 0x100) {
31
+ const i = rd.decodeBit(this.coders, symbol);
32
+ symbol = (symbol << 1) | i;
33
+ }
34
+ break;
35
+ }
36
+ }
37
+ return symbol & 0xFF;
38
+ }
39
+ /**
40
+ * Encode literal symbol
41
+ */
42
+ encode(re, symbol) {
43
+ let context = 1;
44
+ for (let i = 7; i >= 0; i--) {
45
+ const bit = (symbol >> i) & 1;
46
+ re.encodeBit(this.coders, context, bit);
47
+ context = (context << 1) | bit;
48
+ }
49
+ }
50
+ /**
51
+ * Encode literal symbol with match byte context
52
+ */
53
+ encodeMatched(re, matchByte, symbol) {
54
+ let uMatchByte = matchByte;
55
+ let context = 1;
56
+ let same = true;
57
+ for (let i = 7; i >= 0; i--) {
58
+ const bit = (symbol >> i) & 1;
59
+ let state = context;
60
+ if (same) {
61
+ const matchBit = (uMatchByte >> i) & 1;
62
+ state += (1 + matchBit) << 8;
63
+ same = matchBit === bit;
64
+ }
65
+ re.encodeBit(this.coders, state, bit);
66
+ context = (context << 1) | bit;
67
+ }
68
+ }
69
+ /**
70
+ * Get price for encoding literal symbol
71
+ */
72
+ getPrice(matchMode, matchByte, symbol) {
73
+ let uMatchByte = matchByte;
74
+ let price = 0;
75
+ let context = 1;
76
+ let i = 7;
77
+ if (matchMode) {
78
+ while (i >= 0) {
79
+ const matchBit = (uMatchByte >> i) & 1;
80
+ const bit = (symbol >> i) & 1;
81
+ price += getBitPrice(this.coders[(1 + matchBit) << 8 + context], bit);
82
+ context = (context << 1) | bit;
83
+ if (matchBit !== bit) {
84
+ i--;
85
+ break;
86
+ }
87
+ i--;
88
+ }
89
+ }
90
+ while (i >= 0) {
91
+ const bit = (symbol >> i) & 1;
92
+ price += getBitPrice(this.coders[context], bit);
93
+ context = (context << 1) | bit;
94
+ i--;
95
+ }
96
+ return price;
97
+ }
98
+ /**
99
+ * Reset coder to initial state
100
+ */
101
+ reset() {
102
+ this.coders.fill(1024);
103
+ }
104
+ /**
105
+ * Get decoders array (for compatibility with LiteralDecoderEncoder2)
106
+ */
107
+ get decoders() {
108
+ return this.coders;
109
+ }
110
+ }
111
+ export class LitCoder {
112
+ _coders;
113
+ _numPrevBits;
114
+ _posMask;
115
+ constructor(numPosBits, numPrevBits) {
116
+ const numStates = 1 << (numPrevBits + numPosBits);
117
+ this._coders = [];
118
+ this._numPrevBits = numPrevBits;
119
+ this._posMask = (1 << numPosBits) - 1;
120
+ for (let i = 0; i < numStates; i++) {
121
+ this._coders[i] = new LitSubCoder();
122
+ }
123
+ }
124
+ /**
125
+ * Get sub-coder for position and previous byte
126
+ */
127
+ getSubCoder(pos, prevByte) {
128
+ return this._coders[((pos & this._posMask) << this._numPrevBits)
129
+ + (prevByte >> (8 - this._numPrevBits))];
130
+ }
131
+ /**
132
+ * Reset all sub-coders
133
+ */
134
+ reset() {
135
+ this._coders.forEach((coder) => coder.reset());
136
+ }
137
+ /**
138
+ * Get number of previous bits (for compatibility)
139
+ */
140
+ get numPrevBits() {
141
+ return this._numPrevBits;
142
+ }
143
+ /**
144
+ * Get number of position bits (for compatibility)
145
+ */
146
+ get numPosBits() {
147
+ // Calculate from posMask
148
+ return Math.log2(this._posMask + 1);
149
+ }
150
+ /**
151
+ * Get position mask (for compatibility)
152
+ */
153
+ get posMask() {
154
+ return this._posMask;
155
+ }
156
+ /**
157
+ * Get coders array (for compatibility)
158
+ */
159
+ get coders() {
160
+ return this._coders;
161
+ }
162
+ }
@@ -0,0 +1,88 @@
1
+ export class LzOutWindow {
2
+ buffer = null;
3
+ pos = 0;
4
+ streamPos = 0;
5
+ stream = null;
6
+ windowSize = 0;
7
+ // Private Go-style properties
8
+ w = null;
9
+ buf;
10
+ constructor(writer = null, windowSize = 4096) {
11
+ this.w = writer;
12
+ this.stream = writer;
13
+ this.windowSize = windowSize;
14
+ this.buf = new Uint8Array(windowSize);
15
+ this.buffer = this.buf;
16
+ this.pos = 0;
17
+ this.streamPos = 0;
18
+ }
19
+ /**
20
+ * Copy a block of data from a previous position (LZ77-style)
21
+ */
22
+ copyBlock(distance, length) {
23
+ if (!this.buffer)
24
+ return;
25
+ for (let i = 0; i < length; i++) {
26
+ // Get byte from previous position
27
+ let sourcePos = this.pos - distance - 1;
28
+ if (sourcePos < 0) {
29
+ sourcePos += this.windowSize;
30
+ }
31
+ const byte = this.buffer[sourcePos];
32
+ this.putByte(byte);
33
+ }
34
+ }
35
+ /**
36
+ * Put a single byte into the window
37
+ */
38
+ putByte(byte) {
39
+ if (!this.buffer)
40
+ return;
41
+ this.buffer[this.pos] = byte;
42
+ this.pos++;
43
+ this.streamPos++;
44
+ if (this.pos >= this.windowSize) {
45
+ this.flush();
46
+ }
47
+ }
48
+ /**
49
+ * Get a byte from a relative position
50
+ */
51
+ getByte(relativePos) {
52
+ if (!this.buffer)
53
+ return 0;
54
+ let pos = this.pos + relativePos;
55
+ if (pos < 0) {
56
+ pos += this.windowSize;
57
+ }
58
+ else if (pos >= this.windowSize) {
59
+ pos -= this.windowSize;
60
+ }
61
+ return this.buffer[pos];
62
+ }
63
+ /**
64
+ * Flush buffered data to output writer
65
+ */
66
+ flush() {
67
+ if (this.w && this.buffer && this.pos > 0) {
68
+ this.w.writeBytes(this.buffer, 0, this.pos);
69
+ this.pos = 0;
70
+ }
71
+ }
72
+ /**
73
+ * Check if the window is empty
74
+ */
75
+ isEmpty() {
76
+ return this.streamPos === 0;
77
+ }
78
+ /**
79
+ * Reset the window
80
+ */
81
+ reset() {
82
+ this.pos = 0;
83
+ this.streamPos = 0;
84
+ if (this.buffer) {
85
+ this.buffer.fill(0);
86
+ }
87
+ }
88
+ }