@amritk/nish-x86_64-linux 0.27.2 → 0.28.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/INSTALL.md +13 -8
- package/bin/nish +0 -0
- package/docs/AI.md +19 -2
- package/package.json +1 -1
- package/runtime/core.d.ts +47 -0
- package/runtime/core.mjs +67 -0
- package/runtime/nish.d.ts +49 -0
- package/runtime/nish.h +50 -5
- package/runtime/nish.mjs +6 -0
- package/runtime/runtime-checksum.c +270 -0
- package/runtime/runtime-parallel.c +21 -0
- package/runtime/runtime-sandbox.c +470 -0
- package/runtime/runtime-sha256.c +239 -0
- package/scripts/build.sh +44 -23
- package/std/README.md +15 -10
- package/std/compress/checksum.ts +88 -75
- package/std/compress/deflate.ts +224 -0
- package/std/compress/gzip.ts +52 -0
- package/std/crypto/bcrypt.ts +816 -280
- package/std/json-equal.ts +335 -0
- package/std/json-format.ts +1070 -0
- package/std/json-number.ts +428 -0
- package/std/json-pointer.ts +245 -0
- package/std/json-value.ts +510 -17
- package/std/net/http-compress.ts +259 -16
- package/std/net/http1-client.ts +104 -19
- package/std/net/http1-server.ts +61 -12
- package/std/net/postgres.ts +405 -0
- package/std/net/websocket.ts +295 -14
- package/std/regex.ts +613 -52
- package/std/term-io.ts +35 -8
- package/std/yaml-json.ts +841 -0
package/std/compress/checksum.ts
CHANGED
|
@@ -160,85 +160,98 @@ export class Crc32 {
|
|
|
160
160
|
if (toI32(t.length) !== CRC32_TABLE_SIZE || toI32(bt.length) !== CRC32_TABLE_SIZE) {
|
|
161
161
|
panic("Crc32.update: the table is not its size")
|
|
162
162
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
c = crc32Step(t, c ^ c1, checksumLoad64(buf, p1))
|
|
225
|
-
c = crc32Step(t, c ^ c2, checksumLoad64(buf, p2))
|
|
226
|
-
c = crc32Step(t, c ^ c3, checksumLoad64(buf, p3))
|
|
227
|
-
c = crc32Step(t, c ^ c4, checksumLoad64(buf, p4))
|
|
228
|
-
p += CRC32_BLOCK
|
|
229
|
-
}
|
|
163
|
+
return crc32Walk(t, bt, crc, buf, off, len)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* `Crc32.update`'s loop: the CRC-32 of the bytes `crc` was the CRC of,
|
|
169
|
+
* followed by `buf[off .. off + len)`, a window its one caller has checked,
|
|
170
|
+
* as it has checked both tables' length. Natively the compiler puts the call
|
|
171
|
+
* behind a branch on `nish_crc32_hw` and hands the same window to the
|
|
172
|
+
* runtime's `nish_crc32_update`, which runs it on PCLMULQDQ or the ARMv8
|
|
173
|
+
* CRC32 instructions (`src/kernels.ts`); a machine without them, a process
|
|
174
|
+
* run with `NISH_CRC32=soft`, a wasm32 build and Node run this.
|
|
175
|
+
*/
|
|
176
|
+
const crc32Walk = (t: u32[], bt: u32[], crc: u32, buf: u8[], off: i32, len: i32): u32 => {
|
|
177
|
+
let c: u32 = ~crc
|
|
178
|
+
let p: i32 = off
|
|
179
|
+
const end: i32 = off + len
|
|
180
|
+
if (len >= CRC32_BRAID_MIN) {
|
|
181
|
+
// Braided (Kadatch and Jenkins, "Everything we know about CRC but
|
|
182
|
+
// afraid to forget", 2010): five chains, each over every fifth 8-byte
|
|
183
|
+
// word, so a step's table reads overlap the other four's instead of
|
|
184
|
+
// waiting on its own last. A braid's table also steps it over the
|
|
185
|
+
// other braids' 32 bytes, so before each block every register sits at
|
|
186
|
+
// its own word's place. The last block is taken one word at a time
|
|
187
|
+
// with the plain table, each braid's register joining as its word
|
|
188
|
+
// comes, which adds them into one.
|
|
189
|
+
const blocks: i32 = len / CRC32_BLOCK
|
|
190
|
+
const lastBlock: i32 = off + (blocks - 1) * CRC32_BLOCK
|
|
191
|
+
let c1: u32 = 0
|
|
192
|
+
let c2: u32 = 0
|
|
193
|
+
let c3: u32 = 0
|
|
194
|
+
let c4: u32 = 0
|
|
195
|
+
// Each word's position is a local the loop condition bounds, which
|
|
196
|
+
// is what lets it enter the loader's range without a check.
|
|
197
|
+
let p1: i32 = p + 8
|
|
198
|
+
let p2: i32 = p + 16
|
|
199
|
+
let p3: i32 = p + 24
|
|
200
|
+
let p4: i32 = p + 32
|
|
201
|
+
while (
|
|
202
|
+
p < lastBlock &&
|
|
203
|
+
p >= 0 &&
|
|
204
|
+
p1 >= 0 &&
|
|
205
|
+
p2 >= 0 &&
|
|
206
|
+
p3 >= 0 &&
|
|
207
|
+
p4 >= 0 &&
|
|
208
|
+
p4 <= 2147483639 &&
|
|
209
|
+
p3 <= 2147483639 &&
|
|
210
|
+
p2 <= 2147483639 &&
|
|
211
|
+
p1 <= 2147483639 &&
|
|
212
|
+
p <= 2147483639
|
|
213
|
+
) {
|
|
214
|
+
c = crc32Step(bt, c, checksumLoad64(buf, p))
|
|
215
|
+
c1 = crc32Step(bt, c1, checksumLoad64(buf, p1))
|
|
216
|
+
c2 = crc32Step(bt, c2, checksumLoad64(buf, p2))
|
|
217
|
+
c3 = crc32Step(bt, c3, checksumLoad64(buf, p3))
|
|
218
|
+
c4 = crc32Step(bt, c4, checksumLoad64(buf, p4))
|
|
219
|
+
p += CRC32_BLOCK
|
|
220
|
+
p1 += CRC32_BLOCK
|
|
221
|
+
p2 += CRC32_BLOCK
|
|
222
|
+
p3 += CRC32_BLOCK
|
|
223
|
+
p4 += CRC32_BLOCK
|
|
230
224
|
}
|
|
231
|
-
|
|
232
|
-
|
|
225
|
+
if (
|
|
226
|
+
p >= 0 &&
|
|
227
|
+
p1 >= 0 &&
|
|
228
|
+
p2 >= 0 &&
|
|
229
|
+
p3 >= 0 &&
|
|
230
|
+
p4 >= 0 &&
|
|
231
|
+
p4 <= 2147483639 &&
|
|
232
|
+
p3 <= 2147483639 &&
|
|
233
|
+
p2 <= 2147483639 &&
|
|
234
|
+
p1 <= 2147483639 &&
|
|
235
|
+
p <= 2147483639
|
|
236
|
+
) {
|
|
233
237
|
c = crc32Step(t, c, checksumLoad64(buf, p))
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
c =
|
|
238
|
-
p +=
|
|
238
|
+
c = crc32Step(t, c ^ c1, checksumLoad64(buf, p1))
|
|
239
|
+
c = crc32Step(t, c ^ c2, checksumLoad64(buf, p2))
|
|
240
|
+
c = crc32Step(t, c ^ c3, checksumLoad64(buf, p3))
|
|
241
|
+
c = crc32Step(t, c ^ c4, checksumLoad64(buf, p4))
|
|
242
|
+
p += CRC32_BLOCK
|
|
239
243
|
}
|
|
240
|
-
return ~c
|
|
241
244
|
}
|
|
245
|
+
const whole: i32 = end - (len & 7)
|
|
246
|
+
while (p < whole && p >= 0 && p <= 2147483639) {
|
|
247
|
+
c = crc32Step(t, c, checksumLoad64(buf, p))
|
|
248
|
+
p += 8
|
|
249
|
+
}
|
|
250
|
+
while (p < end) {
|
|
251
|
+
c = uncheckedGet(t, toI32((c ^ toU32(uncheckedGet(buf, p))) & 255)) ^ (c >>> 8)
|
|
252
|
+
p += 1
|
|
253
|
+
}
|
|
254
|
+
return ~c
|
|
242
255
|
}
|
|
243
256
|
|
|
244
257
|
/**
|
package/std/compress/deflate.ts
CHANGED
|
@@ -128,6 +128,12 @@ const DEFLATE_STORED_MAX: i32 = 65535
|
|
|
128
128
|
/** Huffman's multiplier for the hash (Knuth's 2^32 / phi). */
|
|
129
129
|
const DEFLATE_HASH_MUL: i64 = 2654435761
|
|
130
130
|
|
|
131
|
+
/** `FixedDeflater`'s farthest match back: its inputs are short. */
|
|
132
|
+
const FIXED_WINDOW: i32 = 16384
|
|
133
|
+
|
|
134
|
+
/** `FixedDeflater`'s largest hash table, 2^14 entries; a call clears only as much as its input needs. */
|
|
135
|
+
const FIXED_HASH_BITS: i32 = 14
|
|
136
|
+
|
|
131
137
|
/** Decoder table entry kinds, in bits 8 to 10 of an entry. */
|
|
132
138
|
const INF_LITERAL: i32 = 0
|
|
133
139
|
const INF_LENGTH: i32 = 1
|
|
@@ -1653,6 +1659,224 @@ export class Deflater {
|
|
|
1653
1659
|
}
|
|
1654
1660
|
}
|
|
1655
1661
|
|
|
1662
|
+
/**
|
|
1663
|
+
* The most bytes `FixedDeflater.compress` writes for `n` bytes of input: nine
|
|
1664
|
+
* bits a byte, the block's header and end code, and the eight bytes of slack
|
|
1665
|
+
* its word-wide bit writer stores past the last whole byte. A negative `n`
|
|
1666
|
+
* answers the bound of 0.
|
|
1667
|
+
*/
|
|
1668
|
+
export const fixedDeflateBound = (n: i32): i32 => {
|
|
1669
|
+
if (n < 0) {
|
|
1670
|
+
return 16
|
|
1671
|
+
}
|
|
1672
|
+
return n + (n >> 3) + 16
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
/**
|
|
1676
|
+
* A one-block DEFLATE compressor in the fixed Huffman code (BTYPE=01, §3.2.6)
|
|
1677
|
+
* for short inputs such as an HTTP response body: one hash probe per position,
|
|
1678
|
+
* matches at most `FIXED_WINDOW` back, no code to build or send. It carries
|
|
1679
|
+
* nothing from one call to the next: the hash table, sized to the input, is
|
|
1680
|
+
* cleared at the start of every call, so the output is a function of the
|
|
1681
|
+
* input alone. About 70 KB of tables; reuse one per thread.
|
|
1682
|
+
*/
|
|
1683
|
+
export class FixedDeflater {
|
|
1684
|
+
/** `head[h]`: one past the last position, from the input's start, whose four bytes hash to `h`; 0 for none. */
|
|
1685
|
+
readonly head: i32[]
|
|
1686
|
+
/** Per byte: its fixed code, bit-reversed, below bit 16, and the code's length above. */
|
|
1687
|
+
readonly literal: i32[]
|
|
1688
|
+
/** Per length - 3: the length symbol's code and then its extra bits, below bit 16, and how many bits above. */
|
|
1689
|
+
readonly length: i32[]
|
|
1690
|
+
/** Distance to distance symbol, as `Deflater.distSymbol` maps it. */
|
|
1691
|
+
readonly distSymbol: i32[]
|
|
1692
|
+
/** Per distance symbol: its five-bit code, bit-reversed; its base distance; its extra bits. */
|
|
1693
|
+
readonly distCode: i32[]
|
|
1694
|
+
readonly distBase: i32[]
|
|
1695
|
+
readonly distExtra: i32[]
|
|
1696
|
+
|
|
1697
|
+
/** The tables, once. */
|
|
1698
|
+
constructor() {
|
|
1699
|
+
this.head = new Array<i32>(1 << FIXED_HASH_BITS)
|
|
1700
|
+
this.literal = new Array<i32>(256)
|
|
1701
|
+
this.length = new Array<i32>(256)
|
|
1702
|
+
this.distSymbol = new Array<i32>(512)
|
|
1703
|
+
this.distCode = new Array<i32>(30)
|
|
1704
|
+
this.distBase = new Array<i32>(30)
|
|
1705
|
+
this.distExtra = new Array<i32>(30)
|
|
1706
|
+
const lens: i32[] = new Array<i32>(288)
|
|
1707
|
+
const codes: i32[] = new Array<i32>(288)
|
|
1708
|
+
const count: i32[] = new Array<i32>(16)
|
|
1709
|
+
const next: i32[] = new Array<i32>(16)
|
|
1710
|
+
for (let s: i32 = 0; s < 288; s += 1) {
|
|
1711
|
+
lens[s] = deflateFixedLitLength(s)
|
|
1712
|
+
}
|
|
1713
|
+
deflateCanonical(lens, 288, codes, count, next)
|
|
1714
|
+
for (let b: i32 = 0; b < 256; b += 1) {
|
|
1715
|
+
this.literal[b] = codes[b] | (lens[b] << 16)
|
|
1716
|
+
}
|
|
1717
|
+
for (let s: i32 = 0; s < 29; s += 1) {
|
|
1718
|
+
const base: i32 = deflateLengthBase(s)
|
|
1719
|
+
const extra: i32 = deflateLengthExtra(s)
|
|
1720
|
+
// Symbol 27 stops short of 258, which has symbol 28 to itself.
|
|
1721
|
+
const top: i32 = s === 28 ? 259 : deflateLengthBase(s + 1)
|
|
1722
|
+
for (let l: i32 = base; l < top && l >= 3 && l <= 258; l += 1) {
|
|
1723
|
+
const n: i32 = lens[257 + s]
|
|
1724
|
+
this.length[l - 3] = codes[257 + s] | ((l - base) << n) | ((n + extra) << 16)
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
for (let d: i32 = 0; d < 30; d += 1) {
|
|
1728
|
+
this.distCode[d] = deflateReverse(d, 5)
|
|
1729
|
+
this.distBase[d] = deflateDistBase(d)
|
|
1730
|
+
this.distExtra[d] = deflateDistExtra(d)
|
|
1731
|
+
}
|
|
1732
|
+
// Distances 1 to 256 directly; above, by (distance - 1) >> 7 from 256 on.
|
|
1733
|
+
for (let d: i32 = 0; d < 30; d += 1) {
|
|
1734
|
+
const lo: i32 = this.distBase[d]
|
|
1735
|
+
const hi: i32 = d === 29 ? 32769 : this.distBase[d + 1]
|
|
1736
|
+
for (let dist: i32 = lo; dist < hi; dist += 1) {
|
|
1737
|
+
if (dist <= 256) {
|
|
1738
|
+
this.distSymbol[dist - 1] = d
|
|
1739
|
+
} else {
|
|
1740
|
+
const at: i32 = ((dist - 1) >> 7) + 256
|
|
1741
|
+
if (at < 512) {
|
|
1742
|
+
this.distSymbol[at] = d
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
/**
|
|
1750
|
+
* Compresses `src[off .. off + len)` as one final fixed-Huffman block into
|
|
1751
|
+
* `out[at .. at + room)`, and answers where it ends, or `DEFLATE_NO_ROOM` as
|
|
1752
|
+
* soon as it would need more than `room` bytes: a caller that only wants
|
|
1753
|
+
* the output when it is smaller passes the most it will take, and an input
|
|
1754
|
+
* that does not compress is abandoned part way. `fixedDeflateBound(len)`
|
|
1755
|
+
* always fits. A window outside its array panics. Allocates nothing.
|
|
1756
|
+
*/
|
|
1757
|
+
compress(src: u8[], off: i32, len: i32, out: u8[], at: i32, room: i32): i32 {
|
|
1758
|
+
deflateWindow("FixedDeflater.compress", src, off, len)
|
|
1759
|
+
deflateWindow("FixedDeflater.compress", out, at, room)
|
|
1760
|
+
const head: i32[] = this.head
|
|
1761
|
+
const literal: i32[] = this.literal
|
|
1762
|
+
const length: i32[] = this.length
|
|
1763
|
+
const dsym: i32[] = this.distSymbol
|
|
1764
|
+
const dcode: i32[] = this.distCode
|
|
1765
|
+
const dbase: i32[] = this.distBase
|
|
1766
|
+
const dextra: i32[] = this.distExtra
|
|
1767
|
+
if (
|
|
1768
|
+
toI32(head.length) !== 1 << FIXED_HASH_BITS ||
|
|
1769
|
+
toI32(literal.length) !== 256 ||
|
|
1770
|
+
toI32(length.length) !== 256 ||
|
|
1771
|
+
toI32(dsym.length) !== 512 ||
|
|
1772
|
+
toI32(dcode.length) !== 30 ||
|
|
1773
|
+
toI32(dbase.length) !== 30 ||
|
|
1774
|
+
toI32(dextra.length) !== 30
|
|
1775
|
+
) {
|
|
1776
|
+
panic("FixedDeflater.compress: a table is not its size")
|
|
1777
|
+
}
|
|
1778
|
+
// A table about the input's size: clearing it is most of a short call's
|
|
1779
|
+
// fixed cost, and a larger one finds no more matches.
|
|
1780
|
+
let bits: i32 = 8
|
|
1781
|
+
while (bits < FIXED_HASH_BITS && 1 << bits < len) {
|
|
1782
|
+
bits += 1
|
|
1783
|
+
}
|
|
1784
|
+
head.fill(0, 0, 1 << bits)
|
|
1785
|
+
const shift: u32 = toU32(32 - bits)
|
|
1786
|
+
const end: i32 = off + len
|
|
1787
|
+
// Matches start where eight bytes can be read; the last few are literals.
|
|
1788
|
+
const last: i32 = end - 8
|
|
1789
|
+
// A flush writes four bytes of the final output, so one that would pass
|
|
1790
|
+
// the room's end means the whole cannot fit.
|
|
1791
|
+
const oe: i32 = at + room - 4
|
|
1792
|
+
// BFINAL = 1, BTYPE = 01.
|
|
1793
|
+
let bb: u64 = toU64(3)
|
|
1794
|
+
let bc: i32 = 3
|
|
1795
|
+
let o: i32 = at
|
|
1796
|
+
let p: i32 = off
|
|
1797
|
+
while (p < end) {
|
|
1798
|
+
let matched: i32 = 0
|
|
1799
|
+
let dist: i32 = 0
|
|
1800
|
+
if (p >= 0 && p <= last && p <= 2147483639) {
|
|
1801
|
+
const pi: integer<0, 2147483639> = p
|
|
1802
|
+
const w: u64 = deflateLoad64(src, pi)
|
|
1803
|
+
const h: i32 = toI32((toU32(w) * toU32(DEFLATE_HASH_MUL)) >>> shift)
|
|
1804
|
+
const c: i32 = uncheckedGet(head, h) - 1 + off
|
|
1805
|
+
uncheckedSet(head, h, p - off + 1)
|
|
1806
|
+
dist = p - c
|
|
1807
|
+
if (c >= off && c >= 0 && c <= 2147483639 && dist <= FIXED_WINDOW) {
|
|
1808
|
+
const ci: integer<0, 2147483639> = c
|
|
1809
|
+
const x: u64 = deflateLoad64(src, ci) ^ w
|
|
1810
|
+
if (toU32(x) === toU32(0)) {
|
|
1811
|
+
const max: i32 = end - p < DEFLATE_MAX_MATCH ? end - p : DEFLATE_MAX_MATCH
|
|
1812
|
+
matched =
|
|
1813
|
+
x !== toU64(0)
|
|
1814
|
+
? deflateCtz64(x) >> 3
|
|
1815
|
+
: toI32(8) + deflateMatchLength(src, c + 8, p + 8, max - 8)
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
if (matched === 0) {
|
|
1820
|
+
const lc: i32 = uncheckedGet(literal, toI32(uncheckedGet(src, p)))
|
|
1821
|
+
bb = bb | (toU64(toU32(lc & 0xffff)) << toU64(bc))
|
|
1822
|
+
bc += lc >> 16
|
|
1823
|
+
p += 1
|
|
1824
|
+
} else {
|
|
1825
|
+
const lc: i32 = uncheckedGet(length, matched - 3)
|
|
1826
|
+
bb = bb | (toU64(toU32(lc & 0xffff)) << toU64(bc))
|
|
1827
|
+
bc += lc >> 16
|
|
1828
|
+
if (bc >= 32) {
|
|
1829
|
+
if (o > oe) {
|
|
1830
|
+
return DEFLATE_NO_ROOM
|
|
1831
|
+
}
|
|
1832
|
+
uncheckedSet(out, o, toU8(bb))
|
|
1833
|
+
uncheckedSet(out, o + 1, toU8(bb >> toU64(8)))
|
|
1834
|
+
uncheckedSet(out, o + 2, toU8(bb >> toU64(16)))
|
|
1835
|
+
uncheckedSet(out, o + 3, toU8(bb >> toU64(24)))
|
|
1836
|
+
bb = bb >> toU64(32)
|
|
1837
|
+
bc -= 32
|
|
1838
|
+
o += 4
|
|
1839
|
+
}
|
|
1840
|
+
const d: i32 =
|
|
1841
|
+
dist <= 256 ? uncheckedGet(dsym, dist - 1) : uncheckedGet(dsym, ((dist - 1) >> 7) + 256)
|
|
1842
|
+
bb = bb | (toU64(toU32(uncheckedGet(dcode, d) | ((dist - uncheckedGet(dbase, d)) << 5))) << toU64(bc))
|
|
1843
|
+
bc += 5 + uncheckedGet(dextra, d)
|
|
1844
|
+
// One position near the match's end goes into the table, for the
|
|
1845
|
+
// next repeat of what follows it; the rest are skipped.
|
|
1846
|
+
const q: i32 = p + matched - 2
|
|
1847
|
+
if (q >= 0 && q <= last && q <= 2147483639) {
|
|
1848
|
+
const qi: integer<0, 2147483639> = q
|
|
1849
|
+
const hq: i32 = toI32((deflateLoad32(src, qi) * toU32(DEFLATE_HASH_MUL)) >>> shift)
|
|
1850
|
+
uncheckedSet(head, hq, q - off + 1)
|
|
1851
|
+
}
|
|
1852
|
+
p += matched
|
|
1853
|
+
}
|
|
1854
|
+
if (bc >= 32) {
|
|
1855
|
+
if (o > oe) {
|
|
1856
|
+
return DEFLATE_NO_ROOM
|
|
1857
|
+
}
|
|
1858
|
+
uncheckedSet(out, o, toU8(bb))
|
|
1859
|
+
uncheckedSet(out, o + 1, toU8(bb >> toU64(8)))
|
|
1860
|
+
uncheckedSet(out, o + 2, toU8(bb >> toU64(16)))
|
|
1861
|
+
uncheckedSet(out, o + 3, toU8(bb >> toU64(24)))
|
|
1862
|
+
bb = bb >> toU64(32)
|
|
1863
|
+
bc -= 32
|
|
1864
|
+
o += 4
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
// The end-of-block code, 256: seven zero bits.
|
|
1868
|
+
bc += 7
|
|
1869
|
+
const bytes: i32 = (bc + 7) >> 3
|
|
1870
|
+
if (o > at + room - bytes) {
|
|
1871
|
+
return DEFLATE_NO_ROOM
|
|
1872
|
+
}
|
|
1873
|
+
for (let i: i32 = 0; i < bytes; i += 1) {
|
|
1874
|
+
uncheckedSet(out, o + i, toU8(bb >> toU64(8 * i)))
|
|
1875
|
+
}
|
|
1876
|
+
return o + bytes
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1656
1880
|
/**
|
|
1657
1881
|
* One Huffman decoding table: the entries for every `bits`-bit prefix, and
|
|
1658
1882
|
* for the codes longer than that, the count per length and the symbols in
|
package/std/compress/gzip.ts
CHANGED
|
@@ -40,11 +40,13 @@ import {
|
|
|
40
40
|
DEFLATE_ERR_TRUNCATED,
|
|
41
41
|
DEFLATE_NO_ROOM,
|
|
42
42
|
Deflater,
|
|
43
|
+
FixedDeflater,
|
|
43
44
|
INFLATE_DONE,
|
|
44
45
|
INFLATE_NEED_INPUT,
|
|
45
46
|
INFLATE_NEED_OUTPUT,
|
|
46
47
|
Inflater,
|
|
47
48
|
deflateBound,
|
|
49
|
+
fixedDeflateBound,
|
|
48
50
|
} from "nish/compress/deflate"
|
|
49
51
|
import { copyBytes } from "nish/bytes"
|
|
50
52
|
|
|
@@ -203,6 +205,56 @@ export class GzipCompressor {
|
|
|
203
205
|
}
|
|
204
206
|
}
|
|
205
207
|
|
|
208
|
+
/** The most bytes `GzipFixedCompressor.compress` writes for `n` bytes of input. */
|
|
209
|
+
export const gzipFixedBound = (n: i32): i32 => fixedDeflateBound(n) + GZIP_HEADER_SIZE + GZIP_TRAILER_SIZE
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* A gzip compressor for short inputs: a `FixedDeflater` (one fixed-Huffman
|
|
213
|
+
* block, 16 KB window) and the CRC-32 tables, allocated once. Each call
|
|
214
|
+
* depends on its input alone. Not shared between threads.
|
|
215
|
+
*/
|
|
216
|
+
export class GzipFixedCompressor {
|
|
217
|
+
readonly deflater: FixedDeflater
|
|
218
|
+
readonly crc: Crc32
|
|
219
|
+
|
|
220
|
+
/** Builds the tables. */
|
|
221
|
+
constructor() {
|
|
222
|
+
this.deflater = new FixedDeflater()
|
|
223
|
+
this.crc = new Crc32()
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Compresses `src[off .. off + len)` into `out[at .. at + room)` as one gzip
|
|
228
|
+
* member, and answers where it ends, or `DEFLATE_NO_ROOM` (-1) as soon as
|
|
229
|
+
* it would need more than `room` bytes, so a caller passing the most it
|
|
230
|
+
* will take stops early on an input that does not shrink.
|
|
231
|
+
* `gzipFixedBound(len)` always fits. A window outside its array panics.
|
|
232
|
+
* Allocates nothing.
|
|
233
|
+
*/
|
|
234
|
+
compress(src: u8[], off: i32, len: i32, out: u8[], at: i32, room: i32): i32 {
|
|
235
|
+
gzipWindow("GzipFixedCompressor.compress", src, off, len)
|
|
236
|
+
gzipWindow("GzipFixedCompressor.compress", out, at, room)
|
|
237
|
+
if (room < GZIP_HEADER_SIZE + GZIP_TRAILER_SIZE) {
|
|
238
|
+
return DEFLATE_NO_ROOM
|
|
239
|
+
}
|
|
240
|
+
gzipWriteHeader(out, at, 1)
|
|
241
|
+
const end: i32 = this.deflater.compress(
|
|
242
|
+
src,
|
|
243
|
+
off,
|
|
244
|
+
len,
|
|
245
|
+
out,
|
|
246
|
+
at + GZIP_HEADER_SIZE,
|
|
247
|
+
room - GZIP_HEADER_SIZE - GZIP_TRAILER_SIZE
|
|
248
|
+
)
|
|
249
|
+
if (end < 0) {
|
|
250
|
+
return DEFLATE_NO_ROOM
|
|
251
|
+
}
|
|
252
|
+
gzipPut32(out, end, this.crc.update(toU32(0), src, off, len))
|
|
253
|
+
gzipPut32(out, end + 4, toU32(len))
|
|
254
|
+
return end + GZIP_TRAILER_SIZE
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
206
258
|
/**
|
|
207
259
|
* A gzip decompressor: an `Inflater` and the CRC-32 tables, allocated once.
|
|
208
260
|
* Not shared between threads.
|