xz-compat 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.
Files changed (145) hide show
  1. package/LICENSE +42 -0
  2. package/README.md +248 -0
  3. package/dist/cjs/compat.d.cts +1 -0
  4. package/dist/cjs/compat.d.ts +1 -0
  5. package/dist/cjs/compat.js +23 -0
  6. package/dist/cjs/compat.js.map +1 -0
  7. package/dist/cjs/filters/bcj/Bcj.d.cts +16 -0
  8. package/dist/cjs/filters/bcj/Bcj.d.ts +16 -0
  9. package/dist/cjs/filters/bcj/Bcj.js +192 -0
  10. package/dist/cjs/filters/bcj/Bcj.js.map +1 -0
  11. package/dist/cjs/filters/bcj/BcjArm.d.cts +16 -0
  12. package/dist/cjs/filters/bcj/BcjArm.d.ts +16 -0
  13. package/dist/cjs/filters/bcj/BcjArm.js +122 -0
  14. package/dist/cjs/filters/bcj/BcjArm.js.map +1 -0
  15. package/dist/cjs/filters/bcj/BcjArm64.d.cts +21 -0
  16. package/dist/cjs/filters/bcj/BcjArm64.d.ts +21 -0
  17. package/dist/cjs/filters/bcj/BcjArm64.js +65 -0
  18. package/dist/cjs/filters/bcj/BcjArm64.js.map +1 -0
  19. package/dist/cjs/filters/bcj/BcjArmt.d.cts +19 -0
  20. package/dist/cjs/filters/bcj/BcjArmt.d.ts +19 -0
  21. package/dist/cjs/filters/bcj/BcjArmt.js +76 -0
  22. package/dist/cjs/filters/bcj/BcjArmt.js.map +1 -0
  23. package/dist/cjs/filters/bcj/BcjIa64.d.cts +15 -0
  24. package/dist/cjs/filters/bcj/BcjIa64.d.ts +15 -0
  25. package/dist/cjs/filters/bcj/BcjIa64.js +141 -0
  26. package/dist/cjs/filters/bcj/BcjIa64.js.map +1 -0
  27. package/dist/cjs/filters/bcj/BcjPpc.d.cts +20 -0
  28. package/dist/cjs/filters/bcj/BcjPpc.d.ts +20 -0
  29. package/dist/cjs/filters/bcj/BcjPpc.js +64 -0
  30. package/dist/cjs/filters/bcj/BcjPpc.js.map +1 -0
  31. package/dist/cjs/filters/bcj/BcjSparc.d.cts +19 -0
  32. package/dist/cjs/filters/bcj/BcjSparc.d.ts +19 -0
  33. package/dist/cjs/filters/bcj/BcjSparc.js +69 -0
  34. package/dist/cjs/filters/bcj/BcjSparc.js.map +1 -0
  35. package/dist/cjs/filters/delta/Delta.d.cts +16 -0
  36. package/dist/cjs/filters/delta/Delta.d.ts +16 -0
  37. package/dist/cjs/filters/delta/Delta.js +74 -0
  38. package/dist/cjs/filters/delta/Delta.js.map +1 -0
  39. package/dist/cjs/filters/index.d.cts +8 -0
  40. package/dist/cjs/filters/index.d.ts +8 -0
  41. package/dist/cjs/filters/index.js +27 -0
  42. package/dist/cjs/filters/index.js.map +1 -0
  43. package/dist/cjs/index.d.cts +4 -0
  44. package/dist/cjs/index.d.ts +4 -0
  45. package/dist/cjs/index.js +58 -0
  46. package/dist/cjs/index.js.map +1 -0
  47. package/dist/cjs/lzma/Lzma2ChunkParser.d.cts +73 -0
  48. package/dist/cjs/lzma/Lzma2ChunkParser.d.ts +73 -0
  49. package/dist/cjs/lzma/Lzma2ChunkParser.js +148 -0
  50. package/dist/cjs/lzma/Lzma2ChunkParser.js.map +1 -0
  51. package/dist/cjs/lzma/index.d.cts +31 -0
  52. package/dist/cjs/lzma/index.d.ts +31 -0
  53. package/dist/cjs/lzma/index.js +83 -0
  54. package/dist/cjs/lzma/index.js.map +1 -0
  55. package/dist/cjs/lzma/stream/transforms.d.cts +46 -0
  56. package/dist/cjs/lzma/stream/transforms.d.ts +46 -0
  57. package/dist/cjs/lzma/stream/transforms.js +193 -0
  58. package/dist/cjs/lzma/stream/transforms.js.map +1 -0
  59. package/dist/cjs/lzma/sync/Lzma2Decoder.d.cts +63 -0
  60. package/dist/cjs/lzma/sync/Lzma2Decoder.d.ts +63 -0
  61. package/dist/cjs/lzma/sync/Lzma2Decoder.js +231 -0
  62. package/dist/cjs/lzma/sync/Lzma2Decoder.js.map +1 -0
  63. package/dist/cjs/lzma/sync/LzmaDecoder.d.cts +97 -0
  64. package/dist/cjs/lzma/sync/LzmaDecoder.d.ts +97 -0
  65. package/dist/cjs/lzma/sync/LzmaDecoder.js +582 -0
  66. package/dist/cjs/lzma/sync/LzmaDecoder.js.map +1 -0
  67. package/dist/cjs/lzma/sync/RangeDecoder.d.cts +69 -0
  68. package/dist/cjs/lzma/sync/RangeDecoder.d.ts +69 -0
  69. package/dist/cjs/lzma/sync/RangeDecoder.js +162 -0
  70. package/dist/cjs/lzma/sync/RangeDecoder.js.map +1 -0
  71. package/dist/cjs/lzma/types.d.cts +117 -0
  72. package/dist/cjs/lzma/types.d.ts +117 -0
  73. package/dist/cjs/lzma/types.js +264 -0
  74. package/dist/cjs/lzma/types.js.map +1 -0
  75. package/dist/cjs/package.json +1 -0
  76. package/dist/cjs/utils/createBufferingDecoder.d.cts +10 -0
  77. package/dist/cjs/utils/createBufferingDecoder.d.ts +10 -0
  78. package/dist/cjs/utils/createBufferingDecoder.js +41 -0
  79. package/dist/cjs/utils/createBufferingDecoder.js.map +1 -0
  80. package/dist/cjs/xz/Decoder.d.cts +21 -0
  81. package/dist/cjs/xz/Decoder.d.ts +21 -0
  82. package/dist/cjs/xz/Decoder.js +325 -0
  83. package/dist/cjs/xz/Decoder.js.map +1 -0
  84. package/dist/esm/compat.d.ts +1 -0
  85. package/dist/esm/compat.js +7 -0
  86. package/dist/esm/compat.js.map +1 -0
  87. package/dist/esm/filters/bcj/Bcj.d.ts +16 -0
  88. package/dist/esm/filters/bcj/Bcj.js +184 -0
  89. package/dist/esm/filters/bcj/Bcj.js.map +1 -0
  90. package/dist/esm/filters/bcj/BcjArm.d.ts +16 -0
  91. package/dist/esm/filters/bcj/BcjArm.js +114 -0
  92. package/dist/esm/filters/bcj/BcjArm.js.map +1 -0
  93. package/dist/esm/filters/bcj/BcjArm64.d.ts +21 -0
  94. package/dist/esm/filters/bcj/BcjArm64.js +57 -0
  95. package/dist/esm/filters/bcj/BcjArm64.js.map +1 -0
  96. package/dist/esm/filters/bcj/BcjArmt.d.ts +19 -0
  97. package/dist/esm/filters/bcj/BcjArmt.js +66 -0
  98. package/dist/esm/filters/bcj/BcjArmt.js.map +1 -0
  99. package/dist/esm/filters/bcj/BcjIa64.d.ts +15 -0
  100. package/dist/esm/filters/bcj/BcjIa64.js +127 -0
  101. package/dist/esm/filters/bcj/BcjIa64.js.map +1 -0
  102. package/dist/esm/filters/bcj/BcjPpc.d.ts +20 -0
  103. package/dist/esm/filters/bcj/BcjPpc.js +55 -0
  104. package/dist/esm/filters/bcj/BcjPpc.js.map +1 -0
  105. package/dist/esm/filters/bcj/BcjSparc.d.ts +19 -0
  106. package/dist/esm/filters/bcj/BcjSparc.js +59 -0
  107. package/dist/esm/filters/bcj/BcjSparc.js.map +1 -0
  108. package/dist/esm/filters/delta/Delta.d.ts +16 -0
  109. package/dist/esm/filters/delta/Delta.js +66 -0
  110. package/dist/esm/filters/delta/Delta.js.map +1 -0
  111. package/dist/esm/filters/index.d.ts +8 -0
  112. package/dist/esm/filters/index.js +9 -0
  113. package/dist/esm/filters/index.js.map +1 -0
  114. package/dist/esm/index.d.ts +4 -0
  115. package/dist/esm/index.js +5 -0
  116. package/dist/esm/index.js.map +1 -0
  117. package/dist/esm/lzma/Lzma2ChunkParser.d.ts +73 -0
  118. package/dist/esm/lzma/Lzma2ChunkParser.js +137 -0
  119. package/dist/esm/lzma/Lzma2ChunkParser.js.map +1 -0
  120. package/dist/esm/lzma/index.d.ts +31 -0
  121. package/dist/esm/lzma/index.js +44 -0
  122. package/dist/esm/lzma/index.js.map +1 -0
  123. package/dist/esm/lzma/stream/transforms.d.ts +46 -0
  124. package/dist/esm/lzma/stream/transforms.js +190 -0
  125. package/dist/esm/lzma/stream/transforms.js.map +1 -0
  126. package/dist/esm/lzma/sync/Lzma2Decoder.d.ts +63 -0
  127. package/dist/esm/lzma/sync/Lzma2Decoder.js +211 -0
  128. package/dist/esm/lzma/sync/Lzma2Decoder.js.map +1 -0
  129. package/dist/esm/lzma/sync/LzmaDecoder.d.ts +97 -0
  130. package/dist/esm/lzma/sync/LzmaDecoder.js +545 -0
  131. package/dist/esm/lzma/sync/LzmaDecoder.js.map +1 -0
  132. package/dist/esm/lzma/sync/RangeDecoder.d.ts +69 -0
  133. package/dist/esm/lzma/sync/RangeDecoder.js +132 -0
  134. package/dist/esm/lzma/sync/RangeDecoder.js.map +1 -0
  135. package/dist/esm/lzma/types.d.ts +117 -0
  136. package/dist/esm/lzma/types.js +154 -0
  137. package/dist/esm/lzma/types.js.map +1 -0
  138. package/dist/esm/package.json +1 -0
  139. package/dist/esm/utils/createBufferingDecoder.d.ts +10 -0
  140. package/dist/esm/utils/createBufferingDecoder.js +30 -0
  141. package/dist/esm/utils/createBufferingDecoder.js.map +1 -0
  142. package/dist/esm/xz/Decoder.d.ts +21 -0
  143. package/dist/esm/xz/Decoder.js +313 -0
  144. package/dist/esm/xz/Decoder.js.map +1 -0
  145. package/package.json +75 -0
@@ -0,0 +1,325 @@
1
+ /**
2
+ * XZ Decompression Module
3
+ *
4
+ * XZ is a container format that wraps LZMA2 compressed data.
5
+ * This module provides both synchronous and streaming XZ decoders.
6
+ *
7
+ * Pure JavaScript implementation, works on Node.js 0.8+
8
+ */ "use strict";
9
+ Object.defineProperty(exports, "__esModule", {
10
+ value: true
11
+ });
12
+ function _export(target, all) {
13
+ for(var name in all)Object.defineProperty(target, name, {
14
+ enumerable: true,
15
+ get: Object.getOwnPropertyDescriptor(all, name).get
16
+ });
17
+ }
18
+ _export(exports, {
19
+ get createXZDecoder () {
20
+ return createXZDecoder;
21
+ },
22
+ get decodeXZ () {
23
+ return decodeXZ;
24
+ }
25
+ });
26
+ var _extractbaseiterator = require("extract-base-iterator");
27
+ var _Bcjts = require("../filters/bcj/Bcj.js");
28
+ var _BcjArmts = require("../filters/bcj/BcjArm.js");
29
+ var _BcjArm64ts = require("../filters/bcj/BcjArm64.js");
30
+ var _BcjArmtts = require("../filters/bcj/BcjArmt.js");
31
+ var _BcjIa64ts = require("../filters/bcj/BcjIa64.js");
32
+ var _BcjPpcts = require("../filters/bcj/BcjPpc.js");
33
+ var _BcjSparcts = require("../filters/bcj/BcjSparc.js");
34
+ var _Deltats = require("../filters/delta/Delta.js");
35
+ var _indexts = require("../lzma/index.js");
36
+ // XZ magic bytes
37
+ var XZ_MAGIC = [
38
+ 0xfd,
39
+ 0x37,
40
+ 0x7a,
41
+ 0x58,
42
+ 0x5a,
43
+ 0x00
44
+ ];
45
+ var XZ_FOOTER_MAGIC = [
46
+ 0x59,
47
+ 0x5a
48
+ ]; // "YZ"
49
+ // Filter IDs (from XZ specification)
50
+ var FILTER_DELTA = 0x03;
51
+ var FILTER_BCJ_X86 = 0x04;
52
+ var FILTER_BCJ_PPC = 0x05;
53
+ var FILTER_BCJ_IA64 = 0x06;
54
+ var FILTER_BCJ_ARM = 0x07;
55
+ var FILTER_BCJ_ARMT = 0x08;
56
+ var FILTER_BCJ_SPARC = 0x09;
57
+ var FILTER_BCJ_ARM64 = 0x0a;
58
+ var FILTER_LZMA2 = 0x21;
59
+ /**
60
+ * Simple buffer comparison
61
+ */ function bufferEquals(buf, offset, expected) {
62
+ if (offset + expected.length > buf.length) {
63
+ return false;
64
+ }
65
+ for(var i = 0; i < expected.length; i++){
66
+ if (buf[offset + i] !== expected[i]) {
67
+ return false;
68
+ }
69
+ }
70
+ return true;
71
+ }
72
+ /**
73
+ * Decode variable-length integer (XZ multibyte encoding)
74
+ * Returns number, but limits to 32-bit to work on Node 0.8+
75
+ */ function decodeMultibyte(buf, offset) {
76
+ var value = 0;
77
+ var i = 0;
78
+ var byte;
79
+ do {
80
+ if (offset + i >= buf.length) {
81
+ throw new Error('Truncated multibyte integer');
82
+ }
83
+ byte = buf[offset + i];
84
+ value |= (byte & 0x7f) << i * 7;
85
+ i++;
86
+ if (i > 4) {
87
+ // Reduced to prevent overflow on Node 0.8
88
+ throw new Error('Multibyte integer too large');
89
+ }
90
+ }while (byte & 0x80);
91
+ return {
92
+ value: value,
93
+ bytesRead: i
94
+ };
95
+ }
96
+ /**
97
+ * Apply a preprocessing filter (BCJ/Delta) to decompressed data
98
+ */ function applyFilter(data, filter) {
99
+ switch(filter.id){
100
+ case FILTER_BCJ_X86:
101
+ return (0, _Bcjts.decodeBcj)(data, filter.props);
102
+ case FILTER_BCJ_ARM:
103
+ return (0, _BcjArmts.decodeBcjArm)(data, filter.props);
104
+ case FILTER_BCJ_ARM64:
105
+ return (0, _BcjArm64ts.decodeBcjArm64)(data, filter.props);
106
+ case FILTER_BCJ_ARMT:
107
+ return (0, _BcjArmtts.decodeBcjArmt)(data, filter.props);
108
+ case FILTER_BCJ_PPC:
109
+ return (0, _BcjPpcts.decodeBcjPpc)(data, filter.props);
110
+ case FILTER_BCJ_SPARC:
111
+ return (0, _BcjSparcts.decodeBcjSparc)(data, filter.props);
112
+ case FILTER_BCJ_IA64:
113
+ return (0, _BcjIa64ts.decodeBcjIa64)(data, filter.props);
114
+ case FILTER_DELTA:
115
+ return (0, _Deltats.decodeDelta)(data, filter.props);
116
+ default:
117
+ throw new Error("Unsupported filter: 0x".concat(filter.id.toString(16)));
118
+ }
119
+ }
120
+ /**
121
+ * Parse XZ Block Header to extract filters and LZMA2 properties
122
+ */ function parseBlockHeader(input, offset, _checkSize) {
123
+ // Block header size
124
+ var blockHeaderSizeRaw = input[offset];
125
+ if (blockHeaderSizeRaw === 0) {
126
+ throw new Error('Invalid block header size (index indicator found instead of block)');
127
+ }
128
+ var blockHeaderSize = (blockHeaderSizeRaw + 1) * 4;
129
+ // Parse block header
130
+ var blockHeaderStart = offset;
131
+ offset++; // skip size byte
132
+ var blockFlags = input[offset++];
133
+ var numFilters = (blockFlags & 0x03) + 1;
134
+ var hasCompressedSize = (blockFlags & 0x40) !== 0;
135
+ var hasUncompressedSize = (blockFlags & 0x80) !== 0;
136
+ // Skip optional sizes
137
+ if (hasCompressedSize) {
138
+ var result = decodeMultibyte(input, offset);
139
+ offset += result.bytesRead;
140
+ }
141
+ if (hasUncompressedSize) {
142
+ var result1 = decodeMultibyte(input, offset);
143
+ offset += result1.bytesRead;
144
+ }
145
+ // Parse all filters
146
+ var filters = [];
147
+ var lzma2Props = null;
148
+ for(var i = 0; i < numFilters; i++){
149
+ var filterIdResult = decodeMultibyte(input, offset);
150
+ var filterId = filterIdResult.value;
151
+ offset += filterIdResult.bytesRead;
152
+ var propsSizeResult = decodeMultibyte(input, offset);
153
+ offset += propsSizeResult.bytesRead;
154
+ var filterProps = input.slice(offset, offset + propsSizeResult.value);
155
+ offset += propsSizeResult.value;
156
+ if (filterId === FILTER_LZMA2) {
157
+ // LZMA2 must be the last filter
158
+ lzma2Props = filterProps;
159
+ } else if (filterId === FILTER_DELTA || filterId >= FILTER_BCJ_X86 && filterId <= FILTER_BCJ_ARM64) {
160
+ // Preprocessing filter - store for later application
161
+ filters.push({
162
+ id: filterId,
163
+ props: filterProps
164
+ });
165
+ } else {
166
+ throw new Error("Unsupported filter: 0x".concat(filterId.toString(16)));
167
+ }
168
+ }
169
+ if (!lzma2Props) {
170
+ throw new Error('No LZMA2 filter found in XZ block');
171
+ }
172
+ // Skip to end of block header (must be aligned to 4 bytes)
173
+ var blockDataStart = blockHeaderStart + blockHeaderSize;
174
+ return {
175
+ filters: filters,
176
+ lzma2Props: lzma2Props,
177
+ headerSize: blockHeaderSize,
178
+ dataStart: blockDataStart,
179
+ dataEnd: input.length,
180
+ nextOffset: blockDataStart
181
+ };
182
+ }
183
+ /**
184
+ * Parse XZ Index to get block positions
185
+ *
186
+ * XZ Index stores "Unpadded Size" for each block which equals:
187
+ * Block Header Size + Compressed Data Size + Check Size
188
+ * (does NOT include padding to 4-byte boundary)
189
+ */ function parseIndex(input, indexStart, checkSize) {
190
+ var offset = indexStart;
191
+ // Index indicator (0x00)
192
+ if (input[offset] !== 0x00) {
193
+ throw new Error('Invalid index indicator');
194
+ }
195
+ offset++;
196
+ // Number of records
197
+ var countResult = decodeMultibyte(input, offset);
198
+ var recordCount = countResult.value;
199
+ offset += countResult.bytesRead;
200
+ var records = [];
201
+ // Parse each record
202
+ for(var i = 0; i < recordCount; i++){
203
+ // Unpadded Size (header + compressed data + check)
204
+ var unpaddedResult = decodeMultibyte(input, offset);
205
+ offset += unpaddedResult.bytesRead;
206
+ // Uncompressed size
207
+ var uncompressedResult = decodeMultibyte(input, offset);
208
+ offset += uncompressedResult.bytesRead;
209
+ records.push({
210
+ compressedPos: 0,
211
+ unpaddedSize: unpaddedResult.value,
212
+ compressedDataSize: 0,
213
+ uncompressedSize: uncompressedResult.value
214
+ });
215
+ }
216
+ // Calculate actual positions by walking through blocks
217
+ var currentPos = 12; // After stream header
218
+ for(var i1 = 0; i1 < records.length; i1++){
219
+ var record = records[i1];
220
+ // Record where this block's header starts
221
+ record.compressedPos = currentPos;
222
+ // Get block header size from the actual data
223
+ var headerSizeRaw = input[currentPos];
224
+ var headerSize = (headerSizeRaw + 1) * 4;
225
+ // Calculate compressed data size from unpadded size
226
+ // unpaddedSize = headerSize + compressedDataSize + checkSize
227
+ record.compressedDataSize = record.unpaddedSize - headerSize - checkSize;
228
+ // Move to next block: unpaddedSize + padding to 4-byte boundary
229
+ var paddedSize = Math.ceil(record.unpaddedSize / 4) * 4;
230
+ currentPos += paddedSize;
231
+ }
232
+ return records;
233
+ }
234
+ function decodeXZ(input) {
235
+ var _loop = function(i) {
236
+ var record = blockRecords[i];
237
+ var recordStart = record.compressedPos;
238
+ // Parse block header
239
+ var blockInfo = parseBlockHeader(input, recordStart, checkSize);
240
+ // Extract compressed data for this block
241
+ var dataStart = recordStart + blockInfo.headerSize;
242
+ // compressedDataSize is calculated from the Index's Unpadded Size minus header and check
243
+ var dataEnd = dataStart + record.compressedDataSize;
244
+ // Note: XZ blocks have padding AFTER the check field to align to 4 bytes,
245
+ // but the compressedSize from index is exact - no need to strip padding.
246
+ // LZMA2 data includes a 0x00 end marker which must NOT be stripped.
247
+ var compressedData = input.slice(dataStart, dataEnd);
248
+ // Decompress this block with LZMA2
249
+ var blockChunks = [];
250
+ (0, _indexts.decodeLzma2)(compressedData, blockInfo.lzma2Props, record.uncompressedSize, {
251
+ write: function(chunk) {
252
+ blockChunks.push(chunk);
253
+ }
254
+ });
255
+ // Concatenate LZMA2 output
256
+ var blockOutput = Buffer.concat(blockChunks);
257
+ // Apply preprocessing filters in reverse order (BCJ/Delta applied after LZMA2)
258
+ // Filters are stored in order they were applied during compression,
259
+ // so we need to reverse for decompression
260
+ for(var j = blockInfo.filters.length - 1; j >= 0; j--){
261
+ blockOutput = applyFilter(blockOutput, blockInfo.filters[j]);
262
+ }
263
+ outputChunks.push(blockOutput);
264
+ _totalOutputSize += blockOutput.length;
265
+ };
266
+ var _checkSizes_checkType;
267
+ // Verify XZ magic
268
+ if (input.length < 12 || !bufferEquals(input, 0, XZ_MAGIC)) {
269
+ throw new Error('Invalid XZ magic bytes');
270
+ }
271
+ // Stream flags at offset 6-7
272
+ var checkType = input[7] & 0x0f;
273
+ // Check sizes based on check type
274
+ var checkSizes = {
275
+ 0: 0,
276
+ 1: 4,
277
+ 4: 8,
278
+ 10: 32
279
+ };
280
+ var checkSize = (_checkSizes_checkType = checkSizes[checkType]) !== null && _checkSizes_checkType !== void 0 ? _checkSizes_checkType : 0;
281
+ // Find footer by skipping stream padding (null bytes at end before footer)
282
+ // Stream padding must be multiple of 4 bytes
283
+ var footerEnd = input.length;
284
+ while(footerEnd > 12 && input[footerEnd - 1] === 0x00){
285
+ footerEnd--;
286
+ }
287
+ // Align to 4-byte boundary (stream padding rules)
288
+ while(footerEnd % 4 !== 0 && footerEnd > 12){
289
+ footerEnd++;
290
+ }
291
+ // Verify footer magic (at footerEnd - 2)
292
+ if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {
293
+ throw new Error('Invalid XZ footer magic');
294
+ }
295
+ // Get backward size (tells us where index starts) - at footerEnd - 8
296
+ var backwardSize = (input.readUInt32LE(footerEnd - 8) + 1) * 4;
297
+ var indexStart = footerEnd - 12 - backwardSize;
298
+ // Parse Index to get block information
299
+ var blockRecords = parseIndex(input, indexStart, checkSize);
300
+ // Decompress each block
301
+ var outputChunks = [];
302
+ var _totalOutputSize = 0;
303
+ for(var i = 0; i < blockRecords.length; i++)_loop(i);
304
+ return Buffer.concat(outputChunks);
305
+ }
306
+ function createXZDecoder() {
307
+ var chunks = [];
308
+ return new _extractbaseiterator.Transform({
309
+ transform: function transform(chunk, _encoding, callback) {
310
+ chunks.push(chunk);
311
+ callback();
312
+ },
313
+ flush: function flush(callback) {
314
+ try {
315
+ var input = Buffer.concat(chunks);
316
+ var output = decodeXZ(input);
317
+ this.push(output);
318
+ callback();
319
+ } catch (err) {
320
+ callback(err);
321
+ }
322
+ }
323
+ });
324
+ }
325
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/xz/Decoder.ts"],"sourcesContent":["/**\n * XZ Decompression Module\n *\n * XZ is a container format that wraps LZMA2 compressed data.\n * This module provides both synchronous and streaming XZ decoders.\n *\n * Pure JavaScript implementation, works on Node.js 0.8+\n */\n\nimport { Transform } from 'extract-base-iterator';\nimport type { Transform as TransformType } from 'stream';\nimport { decodeBcj } from '../filters/bcj/Bcj.ts';\nimport { decodeBcjArm } from '../filters/bcj/BcjArm.ts';\nimport { decodeBcjArm64 } from '../filters/bcj/BcjArm64.ts';\nimport { decodeBcjArmt } from '../filters/bcj/BcjArmt.ts';\nimport { decodeBcjIa64 } from '../filters/bcj/BcjIa64.ts';\nimport { decodeBcjPpc } from '../filters/bcj/BcjPpc.ts';\nimport { decodeBcjSparc } from '../filters/bcj/BcjSparc.ts';\nimport { decodeDelta } from '../filters/delta/Delta.ts';\nimport { decodeLzma2 } from '../lzma/index.ts';\n\n// XZ magic bytes\nconst XZ_MAGIC = [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00];\nconst XZ_FOOTER_MAGIC = [0x59, 0x5a]; // \"YZ\"\n\n// Filter IDs (from XZ specification)\nconst FILTER_DELTA = 0x03;\nconst FILTER_BCJ_X86 = 0x04;\nconst FILTER_BCJ_PPC = 0x05;\nconst FILTER_BCJ_IA64 = 0x06;\nconst FILTER_BCJ_ARM = 0x07;\nconst FILTER_BCJ_ARMT = 0x08;\nconst FILTER_BCJ_SPARC = 0x09;\nconst FILTER_BCJ_ARM64 = 0x0a;\nconst FILTER_LZMA2 = 0x21;\n\n// Filter info for parsing\ninterface FilterInfo {\n id: number;\n props: Buffer;\n}\n\n/**\n * Simple buffer comparison\n */\nfunction bufferEquals(buf: Buffer, offset: number, expected: number[]): boolean {\n if (offset + expected.length > buf.length) {\n return false;\n }\n for (let i = 0; i < expected.length; i++) {\n if (buf[offset + i] !== expected[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Decode variable-length integer (XZ multibyte encoding)\n * Returns number, but limits to 32-bit to work on Node 0.8+\n */\nfunction decodeMultibyte(buf: Buffer, offset: number): { value: number; bytesRead: number } {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= buf.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = buf[offset + i];\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n // Reduced to prevent overflow on Node 0.8\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n}\n\n/**\n * Apply a preprocessing filter (BCJ/Delta) to decompressed data\n */\nfunction applyFilter(data: Buffer, filter: FilterInfo): Buffer {\n switch (filter.id) {\n case FILTER_BCJ_X86:\n return decodeBcj(data, filter.props);\n case FILTER_BCJ_ARM:\n return decodeBcjArm(data, filter.props);\n case FILTER_BCJ_ARM64:\n return decodeBcjArm64(data, filter.props);\n case FILTER_BCJ_ARMT:\n return decodeBcjArmt(data, filter.props);\n case FILTER_BCJ_PPC:\n return decodeBcjPpc(data, filter.props);\n case FILTER_BCJ_SPARC:\n return decodeBcjSparc(data, filter.props);\n case FILTER_BCJ_IA64:\n return decodeBcjIa64(data, filter.props);\n case FILTER_DELTA:\n return decodeDelta(data, filter.props);\n default:\n throw new Error(`Unsupported filter: 0x${filter.id.toString(16)}`);\n }\n}\n\n/**\n * Parse XZ Block Header to extract filters and LZMA2 properties\n */\nfunction parseBlockHeader(\n input: Buffer,\n offset: number,\n _checkSize: number\n): {\n filters: FilterInfo[];\n lzma2Props: Buffer;\n headerSize: number;\n dataStart: number;\n dataEnd: number;\n nextOffset: number;\n} {\n // Block header size\n const blockHeaderSizeRaw = input[offset];\n if (blockHeaderSizeRaw === 0) {\n throw new Error('Invalid block header size (index indicator found instead of block)');\n }\n const blockHeaderSize = (blockHeaderSizeRaw + 1) * 4;\n\n // Parse block header\n const blockHeaderStart = offset;\n offset++; // skip size byte\n\n const blockFlags = input[offset++];\n const numFilters = (blockFlags & 0x03) + 1;\n const hasCompressedSize = (blockFlags & 0x40) !== 0;\n const hasUncompressedSize = (blockFlags & 0x80) !== 0;\n\n // Skip optional sizes\n if (hasCompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n if (hasUncompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n // Parse all filters\n const filters: FilterInfo[] = [];\n let lzma2Props: Buffer | null = null;\n\n for (let i = 0; i < numFilters; i++) {\n const filterIdResult = decodeMultibyte(input, offset);\n const filterId = filterIdResult.value;\n offset += filterIdResult.bytesRead;\n\n const propsSizeResult = decodeMultibyte(input, offset);\n offset += propsSizeResult.bytesRead;\n\n const filterProps = input.slice(offset, offset + propsSizeResult.value);\n offset += propsSizeResult.value;\n\n if (filterId === FILTER_LZMA2) {\n // LZMA2 must be the last filter\n lzma2Props = filterProps;\n } else if (filterId === FILTER_DELTA || (filterId >= FILTER_BCJ_X86 && filterId <= FILTER_BCJ_ARM64)) {\n // Preprocessing filter - store for later application\n filters.push({ id: filterId, props: filterProps });\n } else {\n throw new Error(`Unsupported filter: 0x${filterId.toString(16)}`);\n }\n }\n\n if (!lzma2Props) {\n throw new Error('No LZMA2 filter found in XZ block');\n }\n\n // Skip to end of block header (must be aligned to 4 bytes)\n const blockDataStart = blockHeaderStart + blockHeaderSize;\n\n return {\n filters,\n lzma2Props,\n headerSize: blockHeaderSize,\n dataStart: blockDataStart,\n dataEnd: input.length,\n nextOffset: blockDataStart,\n };\n}\n\n/**\n * Parse XZ Index to get block positions\n *\n * XZ Index stores \"Unpadded Size\" for each block which equals:\n * Block Header Size + Compressed Data Size + Check Size\n * (does NOT include padding to 4-byte boundary)\n */\nfunction parseIndex(\n input: Buffer,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (input[offset] !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyte(input, offset);\n const recordCount = countResult.value;\n offset += countResult.bytesRead;\n\n const records: Array<{\n compressedPos: number;\n unpaddedSize: number;\n compressedDataSize: number;\n uncompressedSize: number;\n }> = [];\n\n // Parse each record\n for (let i = 0; i < recordCount; i++) {\n // Unpadded Size (header + compressed data + check)\n const unpaddedResult = decodeMultibyte(input, offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyte(input, offset);\n offset += uncompressedResult.bytesRead;\n\n records.push({\n compressedPos: 0, // will be calculated\n unpaddedSize: unpaddedResult.value,\n compressedDataSize: 0, // will be calculated\n uncompressedSize: uncompressedResult.value,\n });\n }\n\n // Calculate actual positions by walking through blocks\n let currentPos = 12; // After stream header\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n // Record where this block's header starts\n record.compressedPos = currentPos;\n\n // Get block header size from the actual data\n const headerSizeRaw = input[currentPos];\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n // unpaddedSize = headerSize + compressedDataSize + checkSize\n record.compressedDataSize = record.unpaddedSize - headerSize - checkSize;\n\n // Move to next block: unpaddedSize + padding to 4-byte boundary\n const paddedSize = Math.ceil(record.unpaddedSize / 4) * 4;\n currentPos += paddedSize;\n }\n\n return records;\n}\n\n/**\n * Decompress XZ data synchronously\n * Properly handles multi-block XZ files and stream padding\n * @param input - XZ compressed data\n * @returns Decompressed data\n */\nexport function decodeXZ(input: Buffer): Buffer {\n // Verify XZ magic\n if (input.length < 12 || !bufferEquals(input, 0, XZ_MAGIC)) {\n throw new Error('Invalid XZ magic bytes');\n }\n\n // Stream flags at offset 6-7\n const checkType = input[7] & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n // Stream padding must be multiple of 4 bytes\n let footerEnd = input.length;\n while (footerEnd > 12 && input[footerEnd - 1] === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary (stream padding rules)\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {\n throw new Error('Invalid XZ footer magic');\n }\n\n // Get backward size (tells us where index starts) - at footerEnd - 8\n const backwardSize = (input.readUInt32LE(footerEnd - 8) + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Decompress each block\n const outputChunks: Buffer[] = [];\n let _totalOutputSize = 0;\n\n for (let i = 0; i < blockRecords.length; i++) {\n const record = blockRecords[i];\n const recordStart = record.compressedPos;\n\n // Parse block header\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + blockInfo.headerSize;\n // compressedDataSize is calculated from the Index's Unpadded Size minus header and check\n const dataEnd = dataStart + record.compressedDataSize;\n\n // Note: XZ blocks have padding AFTER the check field to align to 4 bytes,\n // but the compressedSize from index is exact - no need to strip padding.\n // LZMA2 data includes a 0x00 end marker which must NOT be stripped.\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block with LZMA2\n const blockChunks: Buffer[] = [];\n decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize, {\n write: (chunk: Buffer) => {\n blockChunks.push(chunk);\n },\n });\n\n // Concatenate LZMA2 output\n let blockOutput = Buffer.concat(blockChunks) as Buffer;\n\n // Apply preprocessing filters in reverse order (BCJ/Delta applied after LZMA2)\n // Filters are stored in order they were applied during compression,\n // so we need to reverse for decompression\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n outputChunks.push(blockOutput);\n _totalOutputSize += blockOutput.length;\n }\n\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n */\nexport function createXZDecoder(): TransformType {\n const chunks: Buffer[] = [];\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n chunks.push(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n try {\n const input = Buffer.concat(chunks);\n const output = decodeXZ(input);\n this.push(output);\n callback();\n } catch (err) {\n callback(err as Error);\n }\n },\n });\n}\n"],"names":["createXZDecoder","decodeXZ","XZ_MAGIC","XZ_FOOTER_MAGIC","FILTER_DELTA","FILTER_BCJ_X86","FILTER_BCJ_PPC","FILTER_BCJ_IA64","FILTER_BCJ_ARM","FILTER_BCJ_ARMT","FILTER_BCJ_SPARC","FILTER_BCJ_ARM64","FILTER_LZMA2","bufferEquals","buf","offset","expected","length","i","decodeMultibyte","value","byte","Error","bytesRead","applyFilter","data","filter","id","decodeBcj","props","decodeBcjArm","decodeBcjArm64","decodeBcjArmt","decodeBcjPpc","decodeBcjSparc","decodeBcjIa64","decodeDelta","toString","parseBlockHeader","input","_checkSize","blockHeaderSizeRaw","blockHeaderSize","blockHeaderStart","blockFlags","numFilters","hasCompressedSize","hasUncompressedSize","result","filters","lzma2Props","filterIdResult","filterId","propsSizeResult","filterProps","slice","push","blockDataStart","headerSize","dataStart","dataEnd","nextOffset","parseIndex","indexStart","checkSize","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","blockRecords","recordStart","blockInfo","compressedData","blockChunks","decodeLzma2","write","chunk","blockOutput","Buffer","concat","j","outputChunks","_totalOutputSize","checkSizes","checkType","footerEnd","backwardSize","readUInt32LE","chunks","Transform","transform","_encoding","callback","flush","output","err"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function tmpdir(): string;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Compatibility Layer for Node.js 0.8+
3
+ * Local to this package - contains only needed functions.
4
+ */ import os from 'os';
5
+ export function tmpdir() {
6
+ return typeof os.tmpdir === 'function' ? os.tmpdir() : require('os-shim').tmpdir();
7
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/compat.ts"],"sourcesContent":["/**\n * Compatibility Layer for Node.js 0.8+\n * Local to this package - contains only needed functions.\n */\nimport os from 'os';\n\nexport function tmpdir(): string {\n return typeof os.tmpdir === 'function' ? os.tmpdir() : require('os-shim').tmpdir();\n}\n"],"names":["os","tmpdir","require"],"mappings":"AAAA;;;CAGC,GACD,OAAOA,QAAQ,KAAK;AAEpB,OAAO,SAASC;IACd,OAAO,OAAOD,GAAGC,MAAM,KAAK,aAAaD,GAAGC,MAAM,KAAKC,QAAQ,WAAWD,MAAM;AAClF"}
@@ -0,0 +1,16 @@
1
+ import { Transform } from 'extract-base-iterator';
2
+ /**
3
+ * Decode BCJ (x86) filtered data (synchronous, for buffered use)
4
+ * Reverses the BCJ transformation by converting absolute addresses back to relative
5
+ *
6
+ * @param input - BCJ filtered data
7
+ * @param _properties - Unused for BCJ
8
+ * @param _unpackSize - Unused for BCJ
9
+ * @returns Unfiltered data
10
+ */
11
+ export declare function decodeBcj(input: Buffer, _properties?: Buffer, _unpackSize?: number): Buffer;
12
+ /**
13
+ * Create a streaming BCJ decoder Transform.
14
+ * Processes data chunk by chunk, buffering incomplete instructions.
15
+ */
16
+ export declare function createBcjDecoder(_properties?: Buffer, _unpackSize?: number): InstanceType<typeof Transform>;
@@ -0,0 +1,184 @@
1
+ // BCJ (x86) filter codec - converts x86 CALL/JMP relative addresses
2
+ // This is a simple filter that makes executables more compressible by LZMA
3
+ //
4
+ // BCJ transforms relative addresses in x86 CALL (0xE8) and JMP (0xE9) instructions
5
+ // to absolute addresses, which creates more repetitive patterns for compression.
6
+ //
7
+ // Reference: https://github.com/tukaani-project/xz/blob/master/src/liblzma/simple/x86.c
8
+ //
9
+ // This implementation uses true streaming - processes data chunk by chunk
10
+ // while buffering incomplete instructions across chunk boundaries.
11
+ import { allocBuffer, bufferFrom, Transform } from 'extract-base-iterator';
12
+ // Test if byte is 0x00 or 0xFF (valid MSB for converted addresses)
13
+ function Test86MSByte(b) {
14
+ return b === 0 || b === 0xff;
15
+ }
16
+ // Lookup table for mask to bit number conversion (used in false positive prevention)
17
+ const MASK_TO_BIT_NUMBER = [
18
+ 0,
19
+ 1,
20
+ 2,
21
+ 2,
22
+ 3
23
+ ];
24
+ /**
25
+ * Core x86 BCJ conversion function (matches reference x86_code)
26
+ * Works for both encoding and decoding based on isEncoder flag
27
+ *
28
+ * @param state - Filter state (prevMask and prevPos)
29
+ * @param nowPos - Current position in the overall stream
30
+ * @param isEncoder - true for encoding, false for decoding
31
+ * @param buffer - Buffer to process (modified in place)
32
+ * @param size - Size of buffer
33
+ * @returns Number of bytes processed
34
+ */ function x86Code(state, nowPos, isEncoder, buffer, size) {
35
+ let prevMask = state.prevMask;
36
+ let prevPos = state.prevPos;
37
+ if (size < 5) {
38
+ return 0;
39
+ }
40
+ // Decay prev_pos if too far from current position
41
+ if (nowPos - prevPos > 5) {
42
+ prevPos = nowPos - 5;
43
+ }
44
+ const limit = size - 5;
45
+ let bufferPos = 0;
46
+ while(bufferPos <= limit){
47
+ const opcode = buffer[bufferPos];
48
+ // Check for CALL (0xE8) or JMP (0xE9) opcode
49
+ if (opcode !== 0xe8 && opcode !== 0xe9) {
50
+ bufferPos++;
51
+ continue;
52
+ }
53
+ // Calculate offset from previous position
54
+ const offset = nowPos + bufferPos - prevPos;
55
+ prevPos = nowPos + bufferPos;
56
+ // Update mask based on offset
57
+ if (offset > 5) {
58
+ prevMask = 0;
59
+ } else {
60
+ for(let i = 0; i < offset; i++){
61
+ prevMask &= 0x77;
62
+ prevMask <<= 1;
63
+ }
64
+ }
65
+ // Get the high byte of the address
66
+ let b = buffer[bufferPos + 4];
67
+ // Check if this looks like a valid address to convert
68
+ if (Test86MSByte(b) && prevMask >> 1 <= 4 && prevMask >> 1 !== 3) {
69
+ // Read 32-bit address (big-endian style: high byte first in src)
70
+ let src = b << 24 | buffer[bufferPos + 3] << 16 | buffer[bufferPos + 2] << 8 | buffer[bufferPos + 1];
71
+ // Make src unsigned 32-bit
72
+ src = src >>> 0;
73
+ let dest;
74
+ // Conversion loop with false positive correction
75
+ while(true){
76
+ if (isEncoder) {
77
+ dest = src + (nowPos + bufferPos + 5) >>> 0;
78
+ } else {
79
+ dest = src - (nowPos + bufferPos + 5) >>> 0;
80
+ }
81
+ if (prevMask === 0) {
82
+ break;
83
+ }
84
+ const i = MASK_TO_BIT_NUMBER[prevMask >> 1];
85
+ b = dest >>> 24 - i * 8 & 0xff;
86
+ if (!Test86MSByte(b)) {
87
+ break;
88
+ }
89
+ // XOR correction for false positive prevention
90
+ src = (dest ^ (1 << 32 - i * 8) - 1) >>> 0;
91
+ }
92
+ // Write back the converted address
93
+ // High byte: ~(((dest >> 24) & 1) - 1) produces 0x00 or 0xFF
94
+ buffer[bufferPos + 4] = ~((dest >>> 24 & 1) - 1) & 0xff;
95
+ buffer[bufferPos + 3] = dest >>> 16 & 0xff;
96
+ buffer[bufferPos + 2] = dest >>> 8 & 0xff;
97
+ buffer[bufferPos + 1] = dest & 0xff;
98
+ bufferPos += 5;
99
+ prevMask = 0;
100
+ } else {
101
+ bufferPos++;
102
+ prevMask |= 1;
103
+ if (Test86MSByte(b)) {
104
+ prevMask |= 0x10;
105
+ }
106
+ }
107
+ }
108
+ // Save state
109
+ state.prevMask = prevMask;
110
+ state.prevPos = prevPos;
111
+ return bufferPos;
112
+ }
113
+ /**
114
+ * Decode BCJ (x86) filtered data (synchronous, for buffered use)
115
+ * Reverses the BCJ transformation by converting absolute addresses back to relative
116
+ *
117
+ * @param input - BCJ filtered data
118
+ * @param _properties - Unused for BCJ
119
+ * @param _unpackSize - Unused for BCJ
120
+ * @returns Unfiltered data
121
+ */ export function decodeBcj(input, _properties, _unpackSize) {
122
+ const output = bufferFrom(input); // Copy since we modify in place
123
+ const state = {
124
+ prevMask: 0,
125
+ prevPos: 0xfffffffb
126
+ };
127
+ x86Code(state, 0, false, output, output.length);
128
+ return output;
129
+ }
130
+ /**
131
+ * Create a streaming BCJ decoder Transform.
132
+ * Processes data chunk by chunk, buffering incomplete instructions.
133
+ */ export function createBcjDecoder(_properties, _unpackSize) {
134
+ // State that persists across chunks
135
+ const state = {
136
+ prevMask: 0,
137
+ prevPos: 0xfffffffb
138
+ };
139
+ let globalPos = 0; // Position in the overall stream
140
+ let pending = null; // Bytes pending from previous chunk
141
+ const transform = new Transform({
142
+ transform: (chunk, _encoding, callback)=>{
143
+ // Combine pending bytes with new chunk
144
+ let data;
145
+ if (pending && pending.length > 0) {
146
+ data = Buffer.concat([
147
+ pending,
148
+ chunk
149
+ ]);
150
+ } else {
151
+ data = chunk;
152
+ }
153
+ // We need at least 5 bytes to process an instruction
154
+ if (data.length < 5) {
155
+ pending = data;
156
+ callback(null, allocBuffer(0));
157
+ return;
158
+ }
159
+ // Process the buffer
160
+ const output = bufferFrom(data);
161
+ const processed = x86Code(state, globalPos, false, output, output.length);
162
+ if (processed === 0) {
163
+ // Not enough data to process
164
+ pending = data;
165
+ callback(null, allocBuffer(0));
166
+ return;
167
+ }
168
+ // Output processed bytes, keep unprocessed as pending
169
+ const result = output.slice(0, processed);
170
+ pending = output.slice(processed);
171
+ globalPos += processed;
172
+ callback(null, result);
173
+ },
174
+ flush: function(callback) {
175
+ // Output any remaining pending bytes
176
+ if (pending && pending.length > 0) {
177
+ // Process final bytes - can't convert incomplete instructions
178
+ this.push(pending);
179
+ }
180
+ callback(null);
181
+ }
182
+ });
183
+ return transform;
184
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/filters/bcj/Bcj.ts"],"sourcesContent":["// BCJ (x86) filter codec - converts x86 CALL/JMP relative addresses\n// This is a simple filter that makes executables more compressible by LZMA\n//\n// BCJ transforms relative addresses in x86 CALL (0xE8) and JMP (0xE9) instructions\n// to absolute addresses, which creates more repetitive patterns for compression.\n//\n// Reference: https://github.com/tukaani-project/xz/blob/master/src/liblzma/simple/x86.c\n//\n// This implementation uses true streaming - processes data chunk by chunk\n// while buffering incomplete instructions across chunk boundaries.\n\nimport { allocBuffer, bufferFrom, Transform } from 'extract-base-iterator';\n\n// Test if byte is 0x00 or 0xFF (valid MSB for converted addresses)\nfunction Test86MSByte(b: number): boolean {\n return b === 0 || b === 0xff;\n}\n\n// Lookup table for mask to bit number conversion (used in false positive prevention)\nconst MASK_TO_BIT_NUMBER = [0, 1, 2, 2, 3];\n\n/**\n * BCJ x86 filter state\n */\ninterface BcjX86State {\n prevMask: number;\n prevPos: number;\n}\n\n/**\n * Core x86 BCJ conversion function (matches reference x86_code)\n * Works for both encoding and decoding based on isEncoder flag\n *\n * @param state - Filter state (prevMask and prevPos)\n * @param nowPos - Current position in the overall stream\n * @param isEncoder - true for encoding, false for decoding\n * @param buffer - Buffer to process (modified in place)\n * @param size - Size of buffer\n * @returns Number of bytes processed\n */\nfunction x86Code(state: BcjX86State, nowPos: number, isEncoder: boolean, buffer: Buffer, size: number): number {\n let prevMask = state.prevMask;\n let prevPos = state.prevPos;\n\n if (size < 5) {\n return 0;\n }\n\n // Decay prev_pos if too far from current position\n if (nowPos - prevPos > 5) {\n prevPos = nowPos - 5;\n }\n\n const limit = size - 5;\n let bufferPos = 0;\n\n while (bufferPos <= limit) {\n const opcode = buffer[bufferPos];\n\n // Check for CALL (0xE8) or JMP (0xE9) opcode\n if (opcode !== 0xe8 && opcode !== 0xe9) {\n bufferPos++;\n continue;\n }\n\n // Calculate offset from previous position\n const offset = nowPos + bufferPos - prevPos;\n prevPos = nowPos + bufferPos;\n\n // Update mask based on offset\n if (offset > 5) {\n prevMask = 0;\n } else {\n for (let i = 0; i < offset; i++) {\n prevMask &= 0x77;\n prevMask <<= 1;\n }\n }\n\n // Get the high byte of the address\n let b = buffer[bufferPos + 4];\n\n // Check if this looks like a valid address to convert\n if (Test86MSByte(b) && prevMask >> 1 <= 4 && prevMask >> 1 !== 3) {\n // Read 32-bit address (big-endian style: high byte first in src)\n let src = (b << 24) | (buffer[bufferPos + 3] << 16) | (buffer[bufferPos + 2] << 8) | buffer[bufferPos + 1];\n\n // Make src unsigned 32-bit\n src = src >>> 0;\n\n let dest: number;\n\n // Conversion loop with false positive correction\n while (true) {\n if (isEncoder) {\n dest = (src + (nowPos + bufferPos + 5)) >>> 0;\n } else {\n dest = (src - (nowPos + bufferPos + 5)) >>> 0;\n }\n\n if (prevMask === 0) {\n break;\n }\n\n const i = MASK_TO_BIT_NUMBER[prevMask >> 1];\n b = (dest >>> (24 - i * 8)) & 0xff;\n\n if (!Test86MSByte(b)) {\n break;\n }\n\n // XOR correction for false positive prevention\n src = (dest ^ ((1 << (32 - i * 8)) - 1)) >>> 0;\n }\n\n // Write back the converted address\n // High byte: ~(((dest >> 24) & 1) - 1) produces 0x00 or 0xFF\n buffer[bufferPos + 4] = ~(((dest >>> 24) & 1) - 1) & 0xff;\n buffer[bufferPos + 3] = (dest >>> 16) & 0xff;\n buffer[bufferPos + 2] = (dest >>> 8) & 0xff;\n buffer[bufferPos + 1] = dest & 0xff;\n\n bufferPos += 5;\n prevMask = 0;\n } else {\n bufferPos++;\n prevMask |= 1;\n if (Test86MSByte(b)) {\n prevMask |= 0x10;\n }\n }\n }\n\n // Save state\n state.prevMask = prevMask;\n state.prevPos = prevPos;\n\n return bufferPos;\n}\n\n/**\n * Decode BCJ (x86) filtered data (synchronous, for buffered use)\n * Reverses the BCJ transformation by converting absolute addresses back to relative\n *\n * @param input - BCJ filtered data\n * @param _properties - Unused for BCJ\n * @param _unpackSize - Unused for BCJ\n * @returns Unfiltered data\n */\nexport function decodeBcj(input: Buffer, _properties?: Buffer, _unpackSize?: number): Buffer {\n const output = bufferFrom(input); // Copy since we modify in place\n\n const state: BcjX86State = {\n prevMask: 0,\n prevPos: 0xfffffffb, // (uint32_t)(-5) in C\n };\n\n x86Code(state, 0, false, output, output.length);\n\n return output;\n}\n\n/**\n * Create a streaming BCJ decoder Transform.\n * Processes data chunk by chunk, buffering incomplete instructions.\n */\nexport function createBcjDecoder(_properties?: Buffer, _unpackSize?: number): InstanceType<typeof Transform> {\n // State that persists across chunks\n const state: BcjX86State = {\n prevMask: 0,\n prevPos: 0xfffffffb, // (uint32_t)(-5) in C\n };\n let globalPos = 0; // Position in the overall stream\n let pending: Buffer | null = null; // Bytes pending from previous chunk\n\n const transform = new Transform({\n transform: (chunk: Buffer, _encoding: string, callback: (err?: Error | null, data?: Buffer) => void) => {\n // Combine pending bytes with new chunk\n let data: Buffer;\n if (pending && pending.length > 0) {\n data = Buffer.concat([pending, chunk]);\n } else {\n data = chunk;\n }\n\n // We need at least 5 bytes to process an instruction\n if (data.length < 5) {\n pending = data;\n callback(null, allocBuffer(0));\n return;\n }\n\n // Process the buffer\n const output = bufferFrom(data);\n const processed = x86Code(state, globalPos, false, output, output.length);\n\n if (processed === 0) {\n // Not enough data to process\n pending = data;\n callback(null, allocBuffer(0));\n return;\n }\n\n // Output processed bytes, keep unprocessed as pending\n const result = output.slice(0, processed);\n pending = output.slice(processed);\n globalPos += processed;\n\n callback(null, result);\n },\n flush: function (this: InstanceType<typeof Transform>, callback: (err?: Error | null) => void) {\n // Output any remaining pending bytes\n if (pending && pending.length > 0) {\n // Process final bytes - can't convert incomplete instructions\n this.push(pending);\n }\n callback(null);\n },\n });\n\n return transform;\n}\n"],"names":["allocBuffer","bufferFrom","Transform","Test86MSByte","b","MASK_TO_BIT_NUMBER","x86Code","state","nowPos","isEncoder","buffer","size","prevMask","prevPos","limit","bufferPos","opcode","offset","i","src","dest","decodeBcj","input","_properties","_unpackSize","output","length","createBcjDecoder","globalPos","pending","transform","chunk","_encoding","callback","data","Buffer","concat","processed","result","slice","flush","push"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { Transform } from 'extract-base-iterator';
2
+ /**
3
+ * Decode ARM BCJ filtered data (synchronous, for buffered use)
4
+ * Reverses the BCJ transformation by converting absolute addresses back to relative
5
+ *
6
+ * @param input - ARM BCJ filtered data
7
+ * @param _properties - Unused for ARM BCJ
8
+ * @param _unpackSize - Unused for ARM BCJ
9
+ * @returns Unfiltered data
10
+ */
11
+ export declare function decodeBcjArm(input: Buffer, _properties?: Buffer, _unpackSize?: number): Buffer;
12
+ /**
13
+ * Create a streaming ARM BCJ decoder Transform.
14
+ * Processes data in 4-byte aligned chunks.
15
+ */
16
+ export declare function createBcjArmDecoder(_properties?: Buffer, _unpackSize?: number): InstanceType<typeof Transform>;