sproutboat 0.27.0 → 0.29.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/CHANGELOG.md +44 -0
- package/SURFACE.md +4 -4
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/package.json +8 -8
- package/src/build.ts +12 -2
- package/src/compile.ts +23 -1
- package/src/main.ts +13 -2
- package/src/native-restore-sources.ts +48 -0
- package/src/native-restore.ts +155 -0
- package/src/surface.ts +3 -3
- package/vendor/ltx-restore/LICENSE +202 -0
- package/vendor/ltx-restore/NOTICE +32 -0
- package/vendor/ltx-restore/crc64-native.ts.txt +7 -0
- package/vendor/ltx-restore/errors.ts.txt +74 -0
- package/vendor/ltx-restore/file-io.ts.txt +54 -0
- package/vendor/ltx-restore/ltx/byte-reader.ts.txt +46 -0
- package/vendor/ltx-restore/ltx/bytes.ts.txt +87 -0
- package/vendor/ltx-restore/ltx/checksum.ts.txt +46 -0
- package/vendor/ltx-restore/ltx/constants.ts.txt +71 -0
- package/vendor/ltx-restore/ltx/crc64.ts.txt +73 -0
- package/vendor/ltx-restore/ltx/decoder.ts.txt +285 -0
- package/vendor/ltx-restore/ltx/header.ts.txt +126 -0
- package/vendor/ltx-restore/ltx/lz4.ts.txt +260 -0
- package/vendor/ltx-restore/ltx/page-index.ts.txt +140 -0
- package/vendor/ltx-restore/ltx/page.ts.txt +80 -0
- package/vendor/ltx-restore/ltx/sink.ts.txt +33 -0
- package/vendor/ltx-restore/ltx/trailer.ts.txt +58 -0
- package/vendor/ltx-restore/ltx/types.ts.txt +152 -0
- package/vendor/ltx-restore/lz4js/README.md +39 -0
- package/vendor/ltx-restore/lz4js/lz4.js.txt +560 -0
- package/vendor/ltx-restore/lz4js/package.json +36 -0
- package/vendor/ltx-restore/lz4js/util.js.txt +54 -0
- package/vendor/ltx-restore/lz4js/xxh32.js.txt +102 -0
- package/vendor/ltx-restore/program.ts.txt +3 -0
- package/vendor/ltx-restore/restore-native.ts.txt +120 -0
- package/vendor/ltx-restore/restore.ts.txt +96 -0
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
// lz4.js - An implementation of Lz4 in plain JavaScript.
|
|
2
|
+
//
|
|
3
|
+
// TODO:
|
|
4
|
+
// - Unify header parsing/writing.
|
|
5
|
+
// - Support options (block size, checksums)
|
|
6
|
+
// - Support streams
|
|
7
|
+
// - Better error handling (handle bad offset, etc.)
|
|
8
|
+
// - HC support (better search algorithm)
|
|
9
|
+
// - Tests/benchmarking
|
|
10
|
+
|
|
11
|
+
var xxhash = require('./xxh32.js');
|
|
12
|
+
var util = require('./util.js');
|
|
13
|
+
|
|
14
|
+
// Constants
|
|
15
|
+
// --
|
|
16
|
+
|
|
17
|
+
// Compression format parameters/constants.
|
|
18
|
+
var minMatch = 4;
|
|
19
|
+
var minLength = 13;
|
|
20
|
+
var searchLimit = 5;
|
|
21
|
+
var skipTrigger = 6;
|
|
22
|
+
var hashSize = 1 << 16;
|
|
23
|
+
|
|
24
|
+
// Token constants.
|
|
25
|
+
var mlBits = 4;
|
|
26
|
+
var mlMask = (1 << mlBits) - 1;
|
|
27
|
+
var runBits = 4;
|
|
28
|
+
var runMask = (1 << runBits) - 1;
|
|
29
|
+
|
|
30
|
+
// Shared buffers
|
|
31
|
+
var blockBuf = makeBuffer(5 << 20);
|
|
32
|
+
var hashTable = makeHashTable();
|
|
33
|
+
|
|
34
|
+
// Frame constants.
|
|
35
|
+
var magicNum = 0x184D2204;
|
|
36
|
+
|
|
37
|
+
// Frame descriptor flags.
|
|
38
|
+
var fdContentChksum = 0x4;
|
|
39
|
+
var fdContentSize = 0x8;
|
|
40
|
+
var fdBlockChksum = 0x10;
|
|
41
|
+
// var fdBlockIndep = 0x20;
|
|
42
|
+
var fdVersion = 0x40;
|
|
43
|
+
var fdVersionMask = 0xC0;
|
|
44
|
+
|
|
45
|
+
// Block sizes.
|
|
46
|
+
var bsUncompressed = 0x80000000;
|
|
47
|
+
var bsDefault = 7;
|
|
48
|
+
var bsShift = 4;
|
|
49
|
+
var bsMask = 7;
|
|
50
|
+
var bsMap = {
|
|
51
|
+
4: 0x10000,
|
|
52
|
+
5: 0x40000,
|
|
53
|
+
6: 0x100000,
|
|
54
|
+
7: 0x400000
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Utility functions/primitives
|
|
58
|
+
// --
|
|
59
|
+
|
|
60
|
+
// Makes our hashtable. On older browsers, may return a plain array.
|
|
61
|
+
function makeHashTable () {
|
|
62
|
+
try {
|
|
63
|
+
return new Uint32Array(hashSize);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
var hashTable = new Array(hashSize);
|
|
66
|
+
|
|
67
|
+
for (var i = 0; i < hashSize; i++) {
|
|
68
|
+
hashTable[i] = 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return hashTable;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Clear hashtable.
|
|
76
|
+
function clearHashTable (table) {
|
|
77
|
+
for (var i = 0; i < hashSize; i++) {
|
|
78
|
+
hashTable[i] = 0;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Makes a byte buffer. On older browsers, may return a plain array.
|
|
83
|
+
function makeBuffer (size) {
|
|
84
|
+
try {
|
|
85
|
+
return new Uint8Array(size);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
var buf = new Array(size);
|
|
88
|
+
|
|
89
|
+
for (var i = 0; i < size; i++) {
|
|
90
|
+
buf[i] = 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return buf;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function sliceArray (array, start, end) {
|
|
98
|
+
if (typeof array.buffer !== undefined) {
|
|
99
|
+
if (Uint8Array.prototype.slice) {
|
|
100
|
+
return array.slice(start, end);
|
|
101
|
+
} else {
|
|
102
|
+
// Uint8Array#slice polyfill.
|
|
103
|
+
var len = array.length;
|
|
104
|
+
|
|
105
|
+
// Calculate start.
|
|
106
|
+
start = start | 0;
|
|
107
|
+
start = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len);
|
|
108
|
+
|
|
109
|
+
// Calculate end.
|
|
110
|
+
end = (end === undefined) ? len : end | 0;
|
|
111
|
+
end = (end < 0) ? Math.max(len + end, 0) : Math.min(end, len);
|
|
112
|
+
|
|
113
|
+
// Copy into new array.
|
|
114
|
+
var arraySlice = new Uint8Array(end - start);
|
|
115
|
+
for (var i = start, n = 0; i < end;) {
|
|
116
|
+
arraySlice[n++] = array[i++];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return arraySlice;
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
// Assume normal array.
|
|
123
|
+
return array.slice(start, end);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Implementation
|
|
128
|
+
// --
|
|
129
|
+
|
|
130
|
+
// Calculates an upper bound for lz4 compression.
|
|
131
|
+
exports.compressBound = function compressBound (n) {
|
|
132
|
+
return (n + (n / 255) + 16) | 0;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Calculates an upper bound for lz4 decompression, by reading the data.
|
|
136
|
+
exports.decompressBound = function decompressBound (src) {
|
|
137
|
+
var sIndex = 0;
|
|
138
|
+
|
|
139
|
+
// Read magic number
|
|
140
|
+
if (util.readU32(src, sIndex) !== magicNum) {
|
|
141
|
+
throw new Error('invalid magic number');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
sIndex += 4;
|
|
145
|
+
|
|
146
|
+
// Read descriptor
|
|
147
|
+
var descriptor = src[sIndex++];
|
|
148
|
+
|
|
149
|
+
// Check version
|
|
150
|
+
if ((descriptor & fdVersionMask) !== fdVersion) {
|
|
151
|
+
throw new Error('incompatible descriptor version ' + (descriptor & fdVersionMask));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Read flags
|
|
155
|
+
var useBlockSum = (descriptor & fdBlockChksum) !== 0;
|
|
156
|
+
var useContentSize = (descriptor & fdContentSize) !== 0;
|
|
157
|
+
|
|
158
|
+
// Read block size
|
|
159
|
+
var bsIdx = (src[sIndex++] >> bsShift) & bsMask;
|
|
160
|
+
|
|
161
|
+
if (bsMap[bsIdx] === undefined) {
|
|
162
|
+
throw new Error('invalid block size ' + bsIdx);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
var maxBlockSize = bsMap[bsIdx];
|
|
166
|
+
|
|
167
|
+
// Get content size
|
|
168
|
+
if (useContentSize) {
|
|
169
|
+
return util.readU64(src, sIndex);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Checksum
|
|
173
|
+
sIndex++;
|
|
174
|
+
|
|
175
|
+
// Read blocks.
|
|
176
|
+
var maxSize = 0;
|
|
177
|
+
while (true) {
|
|
178
|
+
var blockSize = util.readU32(src, sIndex);
|
|
179
|
+
sIndex += 4;
|
|
180
|
+
|
|
181
|
+
if (blockSize & bsUncompressed) {
|
|
182
|
+
blockSize &= ~bsUncompressed;
|
|
183
|
+
maxSize += blockSize;
|
|
184
|
+
} else {
|
|
185
|
+
maxSize += maxBlockSize;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (blockSize === 0) {
|
|
189
|
+
return maxSize;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (useBlockSum) {
|
|
193
|
+
sIndex += 4;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
sIndex += blockSize;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Creates a buffer of a given byte-size, falling back to plain arrays.
|
|
201
|
+
exports.makeBuffer = makeBuffer;
|
|
202
|
+
|
|
203
|
+
// Decompresses a block of Lz4.
|
|
204
|
+
exports.decompressBlock = function decompressBlock (src, dst, sIndex, sLength, dIndex) {
|
|
205
|
+
var mLength, mOffset, sEnd, n, i;
|
|
206
|
+
|
|
207
|
+
// Setup initial state.
|
|
208
|
+
sEnd = sIndex + sLength;
|
|
209
|
+
|
|
210
|
+
// Consume entire input block.
|
|
211
|
+
while (sIndex < sEnd) {
|
|
212
|
+
var token = src[sIndex++];
|
|
213
|
+
|
|
214
|
+
// Copy literals.
|
|
215
|
+
var literalCount = (token >> 4);
|
|
216
|
+
if (literalCount > 0) {
|
|
217
|
+
// Parse length.
|
|
218
|
+
if (literalCount === 0xf) {
|
|
219
|
+
while (true) {
|
|
220
|
+
literalCount += src[sIndex];
|
|
221
|
+
if (src[sIndex++] !== 0xff) {
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Copy literals
|
|
228
|
+
for (n = sIndex + literalCount; sIndex < n;) {
|
|
229
|
+
dst[dIndex++] = src[sIndex++];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (sIndex >= sEnd) {
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Copy match.
|
|
238
|
+
mLength = (token & 0xf);
|
|
239
|
+
|
|
240
|
+
// Parse offset.
|
|
241
|
+
mOffset = src[sIndex++] | (src[sIndex++] << 8);
|
|
242
|
+
|
|
243
|
+
// Parse length.
|
|
244
|
+
if (mLength === 0xf) {
|
|
245
|
+
while (true) {
|
|
246
|
+
mLength += src[sIndex];
|
|
247
|
+
if (src[sIndex++] !== 0xff) {
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
mLength += minMatch;
|
|
254
|
+
|
|
255
|
+
// Copy match.
|
|
256
|
+
for (i = dIndex - mOffset, n = i + mLength; i < n;) {
|
|
257
|
+
dst[dIndex++] = dst[i++] | 0;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return dIndex;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// Compresses a block with Lz4.
|
|
265
|
+
exports.compressBlock = function compressBlock (src, dst, sIndex, sLength, hashTable) {
|
|
266
|
+
var mIndex, mAnchor, mLength, mOffset, mStep;
|
|
267
|
+
var literalCount, dIndex, sEnd, n;
|
|
268
|
+
|
|
269
|
+
// Setup initial state.
|
|
270
|
+
dIndex = 0;
|
|
271
|
+
sEnd = sLength + sIndex;
|
|
272
|
+
mAnchor = sIndex;
|
|
273
|
+
|
|
274
|
+
// Process only if block is large enough.
|
|
275
|
+
if (sLength >= minLength) {
|
|
276
|
+
var searchMatchCount = (1 << skipTrigger) + 3;
|
|
277
|
+
|
|
278
|
+
// Consume until last n literals (Lz4 spec limitation.)
|
|
279
|
+
while (sIndex + minMatch < sEnd - searchLimit) {
|
|
280
|
+
var seq = util.readU32(src, sIndex);
|
|
281
|
+
var hash = util.hashU32(seq) >>> 0;
|
|
282
|
+
|
|
283
|
+
// Crush hash to 16 bits.
|
|
284
|
+
hash = ((hash >> 16) ^ hash) >>> 0 & 0xffff;
|
|
285
|
+
|
|
286
|
+
// Look for a match in the hashtable. NOTE: remove one; see below.
|
|
287
|
+
mIndex = hashTable[hash] - 1;
|
|
288
|
+
|
|
289
|
+
// Put pos in hash table. NOTE: add one so that zero = invalid.
|
|
290
|
+
hashTable[hash] = sIndex + 1;
|
|
291
|
+
|
|
292
|
+
// Determine if there is a match (within range.)
|
|
293
|
+
if (mIndex < 0 || ((sIndex - mIndex) >>> 16) > 0 || util.readU32(src, mIndex) !== seq) {
|
|
294
|
+
mStep = searchMatchCount++ >> skipTrigger;
|
|
295
|
+
sIndex += mStep;
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
searchMatchCount = (1 << skipTrigger) + 3;
|
|
300
|
+
|
|
301
|
+
// Calculate literal count and offset.
|
|
302
|
+
literalCount = sIndex - mAnchor;
|
|
303
|
+
mOffset = sIndex - mIndex;
|
|
304
|
+
|
|
305
|
+
// We've already matched one word, so get that out of the way.
|
|
306
|
+
sIndex += minMatch;
|
|
307
|
+
mIndex += minMatch;
|
|
308
|
+
|
|
309
|
+
// Determine match length.
|
|
310
|
+
// N.B.: mLength does not include minMatch, Lz4 adds it back
|
|
311
|
+
// in decoding.
|
|
312
|
+
mLength = sIndex;
|
|
313
|
+
while (sIndex < sEnd - searchLimit && src[sIndex] === src[mIndex]) {
|
|
314
|
+
sIndex++;
|
|
315
|
+
mIndex++;
|
|
316
|
+
}
|
|
317
|
+
mLength = sIndex - mLength;
|
|
318
|
+
|
|
319
|
+
// Write token + literal count.
|
|
320
|
+
var token = mLength < mlMask ? mLength : mlMask;
|
|
321
|
+
if (literalCount >= runMask) {
|
|
322
|
+
dst[dIndex++] = (runMask << mlBits) + token;
|
|
323
|
+
for (n = literalCount - runMask; n >= 0xff; n -= 0xff) {
|
|
324
|
+
dst[dIndex++] = 0xff;
|
|
325
|
+
}
|
|
326
|
+
dst[dIndex++] = n;
|
|
327
|
+
} else {
|
|
328
|
+
dst[dIndex++] = (literalCount << mlBits) + token;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Write literals.
|
|
332
|
+
for (var i = 0; i < literalCount; i++) {
|
|
333
|
+
dst[dIndex++] = src[mAnchor + i];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Write offset.
|
|
337
|
+
dst[dIndex++] = mOffset;
|
|
338
|
+
dst[dIndex++] = (mOffset >> 8);
|
|
339
|
+
|
|
340
|
+
// Write match length.
|
|
341
|
+
if (mLength >= mlMask) {
|
|
342
|
+
for (n = mLength - mlMask; n >= 0xff; n -= 0xff) {
|
|
343
|
+
dst[dIndex++] = 0xff;
|
|
344
|
+
}
|
|
345
|
+
dst[dIndex++] = n;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Move the anchor.
|
|
349
|
+
mAnchor = sIndex;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Nothing was encoded.
|
|
354
|
+
if (mAnchor === 0) {
|
|
355
|
+
return 0;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Write remaining literals.
|
|
359
|
+
// Write literal token+count.
|
|
360
|
+
literalCount = sEnd - mAnchor;
|
|
361
|
+
if (literalCount >= runMask) {
|
|
362
|
+
dst[dIndex++] = (runMask << mlBits);
|
|
363
|
+
for (n = literalCount - runMask; n >= 0xff; n -= 0xff) {
|
|
364
|
+
dst[dIndex++] = 0xff;
|
|
365
|
+
}
|
|
366
|
+
dst[dIndex++] = n;
|
|
367
|
+
} else {
|
|
368
|
+
dst[dIndex++] = (literalCount << mlBits);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Write literals.
|
|
372
|
+
sIndex = mAnchor;
|
|
373
|
+
while (sIndex < sEnd) {
|
|
374
|
+
dst[dIndex++] = src[sIndex++];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return dIndex;
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// Decompresses a frame of Lz4 data.
|
|
381
|
+
exports.decompressFrame = function decompressFrame (src, dst) {
|
|
382
|
+
var useBlockSum, useContentSum, useContentSize, descriptor;
|
|
383
|
+
var sIndex = 0;
|
|
384
|
+
var dIndex = 0;
|
|
385
|
+
|
|
386
|
+
// Read magic number
|
|
387
|
+
if (util.readU32(src, sIndex) !== magicNum) {
|
|
388
|
+
throw new Error('invalid magic number');
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
sIndex += 4;
|
|
392
|
+
|
|
393
|
+
// Read descriptor
|
|
394
|
+
descriptor = src[sIndex++];
|
|
395
|
+
|
|
396
|
+
// Check version
|
|
397
|
+
if ((descriptor & fdVersionMask) !== fdVersion) {
|
|
398
|
+
throw new Error('incompatible descriptor version');
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Read flags
|
|
402
|
+
useBlockSum = (descriptor & fdBlockChksum) !== 0;
|
|
403
|
+
useContentSum = (descriptor & fdContentChksum) !== 0;
|
|
404
|
+
useContentSize = (descriptor & fdContentSize) !== 0;
|
|
405
|
+
|
|
406
|
+
// Read block size
|
|
407
|
+
var bsIdx = (src[sIndex++] >> bsShift) & bsMask;
|
|
408
|
+
|
|
409
|
+
if (bsMap[bsIdx] === undefined) {
|
|
410
|
+
throw new Error('invalid block size');
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (useContentSize) {
|
|
414
|
+
// TODO: read content size
|
|
415
|
+
sIndex += 8;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
sIndex++;
|
|
419
|
+
|
|
420
|
+
// Read blocks.
|
|
421
|
+
while (true) {
|
|
422
|
+
var compSize;
|
|
423
|
+
|
|
424
|
+
compSize = util.readU32(src, sIndex);
|
|
425
|
+
sIndex += 4;
|
|
426
|
+
|
|
427
|
+
if (compSize === 0) {
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (useBlockSum) {
|
|
432
|
+
// TODO: read block checksum
|
|
433
|
+
sIndex += 4;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Check if block is compressed
|
|
437
|
+
if ((compSize & bsUncompressed) !== 0) {
|
|
438
|
+
// Mask off the 'uncompressed' bit
|
|
439
|
+
compSize &= ~bsUncompressed;
|
|
440
|
+
|
|
441
|
+
// Copy uncompressed data into destination buffer.
|
|
442
|
+
for (var j = 0; j < compSize; j++) {
|
|
443
|
+
dst[dIndex++] = src[sIndex++];
|
|
444
|
+
}
|
|
445
|
+
} else {
|
|
446
|
+
// Decompress into blockBuf
|
|
447
|
+
dIndex = exports.decompressBlock(src, dst, sIndex, compSize, dIndex);
|
|
448
|
+
sIndex += compSize;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (useContentSum) {
|
|
453
|
+
// TODO: read content checksum
|
|
454
|
+
sIndex += 4;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return dIndex;
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// Compresses data to an Lz4 frame.
|
|
461
|
+
exports.compressFrame = function compressFrame (src, dst) {
|
|
462
|
+
var dIndex = 0;
|
|
463
|
+
|
|
464
|
+
// Write magic number.
|
|
465
|
+
util.writeU32(dst, dIndex, magicNum);
|
|
466
|
+
dIndex += 4;
|
|
467
|
+
|
|
468
|
+
// Descriptor flags.
|
|
469
|
+
dst[dIndex++] = fdVersion;
|
|
470
|
+
dst[dIndex++] = bsDefault << bsShift;
|
|
471
|
+
|
|
472
|
+
// Descriptor checksum.
|
|
473
|
+
dst[dIndex] = xxhash.hash(0, dst, 4, dIndex - 4) >> 8;
|
|
474
|
+
dIndex++;
|
|
475
|
+
|
|
476
|
+
// Write blocks.
|
|
477
|
+
var maxBlockSize = bsMap[bsDefault];
|
|
478
|
+
var remaining = src.length;
|
|
479
|
+
var sIndex = 0;
|
|
480
|
+
|
|
481
|
+
// Clear the hashtable.
|
|
482
|
+
clearHashTable(hashTable);
|
|
483
|
+
|
|
484
|
+
// Split input into blocks and write.
|
|
485
|
+
while (remaining > 0) {
|
|
486
|
+
var compSize = 0;
|
|
487
|
+
var blockSize = remaining > maxBlockSize ? maxBlockSize : remaining;
|
|
488
|
+
|
|
489
|
+
compSize = exports.compressBlock(src, blockBuf, sIndex, blockSize, hashTable);
|
|
490
|
+
|
|
491
|
+
if (compSize > blockSize || compSize === 0) {
|
|
492
|
+
// Output uncompressed.
|
|
493
|
+
util.writeU32(dst, dIndex, 0x80000000 | blockSize);
|
|
494
|
+
dIndex += 4;
|
|
495
|
+
|
|
496
|
+
for (var z = sIndex + blockSize; sIndex < z;) {
|
|
497
|
+
dst[dIndex++] = src[sIndex++];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
remaining -= blockSize;
|
|
501
|
+
} else {
|
|
502
|
+
// Output compressed.
|
|
503
|
+
util.writeU32(dst, dIndex, compSize);
|
|
504
|
+
dIndex += 4;
|
|
505
|
+
|
|
506
|
+
for (var j = 0; j < compSize;) {
|
|
507
|
+
dst[dIndex++] = blockBuf[j++];
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
sIndex += blockSize;
|
|
511
|
+
remaining -= blockSize;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Write blank end block.
|
|
516
|
+
util.writeU32(dst, dIndex, 0);
|
|
517
|
+
dIndex += 4;
|
|
518
|
+
|
|
519
|
+
return dIndex;
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
// Decompresses a buffer containing an Lz4 frame. maxSize is optional; if not
|
|
523
|
+
// provided, a maximum size will be determined by examining the data. The
|
|
524
|
+
// buffer returned will always be perfectly-sized.
|
|
525
|
+
exports.decompress = function decompress (src, maxSize) {
|
|
526
|
+
var dst, size;
|
|
527
|
+
|
|
528
|
+
if (maxSize === undefined) {
|
|
529
|
+
maxSize = exports.decompressBound(src);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
dst = exports.makeBuffer(maxSize);
|
|
533
|
+
size = exports.decompressFrame(src, dst);
|
|
534
|
+
|
|
535
|
+
if (size !== maxSize) {
|
|
536
|
+
dst = sliceArray(dst, 0, size);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return dst;
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
// Compresses a buffer to an Lz4 frame. maxSize is optional; if not provided,
|
|
543
|
+
// a buffer will be created based on the theoretical worst output size for a
|
|
544
|
+
// given input size. The buffer returned will always be perfectly-sized.
|
|
545
|
+
exports.compress = function compress (src, maxSize) {
|
|
546
|
+
var dst, size;
|
|
547
|
+
|
|
548
|
+
if (maxSize === undefined) {
|
|
549
|
+
maxSize = exports.compressBound(src.length);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
dst = exports.makeBuffer(maxSize);
|
|
553
|
+
size = exports.compressFrame(src, dst);
|
|
554
|
+
|
|
555
|
+
if (size !== maxSize) {
|
|
556
|
+
dst = sliceArray(dst, 0, size);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return dst;
|
|
560
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lz4js",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "An Lz4 implementation for the browser.",
|
|
5
|
+
"main": "lz4.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "mocha -R spec test/cases"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+ssh://git@github.com/Benzinga/lz4js.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"lz4",
|
|
15
|
+
"compression",
|
|
16
|
+
"decompression",
|
|
17
|
+
"browser",
|
|
18
|
+
"commonjs"
|
|
19
|
+
],
|
|
20
|
+
"author": "John Chadwick",
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/Benzinga/lz4js/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/Benzinga/lz4js#readme",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"chai": "^3.5.0",
|
|
28
|
+
"eslint": "^3.0.1",
|
|
29
|
+
"eslint-config-semistandard": "^6.0.2",
|
|
30
|
+
"eslint-config-standard": "^5.3.5",
|
|
31
|
+
"eslint-plugin-promise": "^2.0.0",
|
|
32
|
+
"eslint-plugin-react": "^5.2.2",
|
|
33
|
+
"eslint-plugin-standard": "^2.0.0",
|
|
34
|
+
"mocha": "^2.5.3"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Simple hash function, from: http://burtleburtle.net/bob/hash/integer.html.
|
|
2
|
+
// Chosen because it doesn't use multiply and achieves full avalanche.
|
|
3
|
+
exports.hashU32 = function hashU32 (a) {
|
|
4
|
+
a = a | 0;
|
|
5
|
+
a = a + 2127912214 + (a << 12) | 0;
|
|
6
|
+
a = a ^ -949894596 ^ a >>> 19;
|
|
7
|
+
a = a + 374761393 + (a << 5) | 0;
|
|
8
|
+
a = a + -744332180 ^ a << 9;
|
|
9
|
+
a = a + -42973499 + (a << 3) | 0;
|
|
10
|
+
return a ^ -1252372727 ^ a >>> 16 | 0;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Reads a 64-bit little-endian integer from an array.
|
|
14
|
+
exports.readU64 = function readU64 (b, n) {
|
|
15
|
+
var x = 0;
|
|
16
|
+
x |= b[n++] << 0;
|
|
17
|
+
x |= b[n++] << 8;
|
|
18
|
+
x |= b[n++] << 16;
|
|
19
|
+
x |= b[n++] << 24;
|
|
20
|
+
x |= b[n++] << 32;
|
|
21
|
+
x |= b[n++] << 40;
|
|
22
|
+
x |= b[n++] << 48;
|
|
23
|
+
x |= b[n++] << 56;
|
|
24
|
+
return x;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Reads a 32-bit little-endian integer from an array.
|
|
28
|
+
exports.readU32 = function readU32 (b, n) {
|
|
29
|
+
var x = 0;
|
|
30
|
+
x |= b[n++] << 0;
|
|
31
|
+
x |= b[n++] << 8;
|
|
32
|
+
x |= b[n++] << 16;
|
|
33
|
+
x |= b[n++] << 24;
|
|
34
|
+
return x;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Writes a 32-bit little-endian integer from an array.
|
|
38
|
+
exports.writeU32 = function writeU32 (b, n, x) {
|
|
39
|
+
b[n++] = (x >> 0) & 0xff;
|
|
40
|
+
b[n++] = (x >> 8) & 0xff;
|
|
41
|
+
b[n++] = (x >> 16) & 0xff;
|
|
42
|
+
b[n++] = (x >> 24) & 0xff;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Multiplies two numbers using 32-bit integer multiplication.
|
|
46
|
+
// Algorithm from Emscripten.
|
|
47
|
+
exports.imul = function imul (a, b) {
|
|
48
|
+
var ah = a >>> 16;
|
|
49
|
+
var al = a & 65535;
|
|
50
|
+
var bh = b >>> 16;
|
|
51
|
+
var bl = b & 65535;
|
|
52
|
+
|
|
53
|
+
return al * bl + (ah * bl + al * bh << 16) | 0;
|
|
54
|
+
};
|