@xterm/addon-unicode-graphemes 0.4.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/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@xterm/addon-unicode-graphemes",
3
+ "version": "0.4.0",
4
+ "author": {
5
+ "name": "The xterm.js authors",
6
+ "url": "https://xtermjs.org/"
7
+ },
8
+ "main": "lib/addon-unicode-graphemes.js",
9
+ "module": "lib/addon-unicode-graphemes.mjs",
10
+ "types": "typings/addon-unicode-graphemes.d.ts",
11
+ "repository": "https://github.com/xtermjs/xterm.js/tree/master/addons/addon-unicode-graphemes",
12
+ "license": "MIT",
13
+ "keywords": [
14
+ "terminal",
15
+ "xterm",
16
+ "xterm.js"
17
+ ],
18
+ "scripts": {
19
+ "build": "../../node_modules/.bin/tsc -p .",
20
+ "prepackage": "npm run build",
21
+ "package": "../../node_modules/.bin/webpack",
22
+ "prepublishOnly": "npm run package",
23
+ "start": "node ../../demo/start",
24
+ "benchmark": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json out-benchmark/benchmark/*benchmark.js",
25
+ "benchmark-baseline": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js",
26
+ "benchmark-eval": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js"
27
+ },
28
+ "commit": "f447274f430fd22513f6adbf9862d19524471c04"
29
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Copyright (c) 2023 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { IUnicodeVersionProvider } from '@xterm/xterm';
7
+ import { UnicodeCharProperties, UnicodeCharWidth } from 'common/services/Services';
8
+ import { UnicodeService } from 'common/services/UnicodeService';
9
+ import * as UC from './third-party/UnicodeProperties';
10
+
11
+ export class UnicodeGraphemeProvider implements IUnicodeVersionProvider {
12
+ public readonly version;
13
+ public ambiguousCharsAreWide: boolean = false;
14
+ public readonly handleGraphemes: boolean;
15
+
16
+ constructor(handleGraphemes: boolean = true) {
17
+ this.version = handleGraphemes ? '15-graphemes' : '15';
18
+ this.handleGraphemes = handleGraphemes;
19
+ }
20
+
21
+ private static readonly _plainNarrowProperties: UnicodeCharProperties
22
+ = UnicodeService.createPropertyValue(UC.GRAPHEME_BREAK_Other, 1, false);
23
+
24
+ public charProperties(codepoint: number, preceding: UnicodeCharProperties): UnicodeCharProperties {
25
+ // Optimize the simple ASCII case, under the condition that
26
+ // UnicodeService.extractCharKind(preceding) === GRAPHEME_BREAK_Other
27
+ // (which also covers the case that preceding === 0).
28
+ if ((codepoint >= 32 && codepoint < 127) && (preceding >> 3) === 0) {
29
+ return UnicodeGraphemeProvider._plainNarrowProperties;
30
+ }
31
+
32
+ let charInfo = UC.getInfo(codepoint);
33
+ let w = UC.infoToWidthInfo(charInfo);
34
+ let shouldJoin = false;
35
+ if (w >= 2) {
36
+ // Treat emoji_presentation_selector as WIDE.
37
+ w = w === 3 || this.ambiguousCharsAreWide || codepoint === 0xfe0f ? 2 : 1;
38
+ } else {
39
+ w = 1;
40
+ }
41
+ if (preceding !== 0) {
42
+ const oldWidth = UnicodeService.extractWidth(preceding);
43
+ if (this.handleGraphemes) {
44
+ charInfo = UC.shouldJoin(UnicodeService.extractCharKind(preceding), charInfo);
45
+ } else {
46
+ charInfo = w === 0 ? 1 : 0;
47
+ }
48
+ shouldJoin = charInfo > 0;
49
+ if (shouldJoin) {
50
+ if (oldWidth > w) {
51
+ w = oldWidth;
52
+ } else if (charInfo === 32) { // UC.GRAPHEME_BREAK_SAW_Regional_Pair)
53
+ w = 2;
54
+ }
55
+ }
56
+ }
57
+ return UnicodeService.createPropertyValue(charInfo, w, shouldJoin);
58
+ }
59
+
60
+ public wcwidth(codepoint: number): UnicodeCharWidth {
61
+ const charInfo = UC.getInfo(codepoint);
62
+ const w = UC.infoToWidthInfo(charInfo);
63
+ const kind = (charInfo & UC.GRAPHEME_BREAK_MASK) >> UC.GRAPHEME_BREAK_SHIFT;
64
+ if (kind === UC.GRAPHEME_BREAK_Extend || kind === UC.GRAPHEME_BREAK_Prepend) {
65
+ return 0;
66
+ }
67
+ if (w >= 2 && (w === 3 || this.ambiguousCharsAreWide)) {
68
+ return 2;
69
+ }
70
+ return 1;
71
+ }
72
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Copyright (c) 2023 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ *
5
+ * UnicodeVersionProvider for V15 with grapeme cluster handleing.
6
+ */
7
+
8
+ import type { Terminal, ITerminalAddon, IUnicodeHandling } from '@xterm/xterm';
9
+ import type { UnicodeGraphemesAddon as IUnicodeGraphemesApi } from '@xterm/addon-unicode-graphemes';
10
+ import { UnicodeGraphemeProvider } from './UnicodeGraphemeProvider';
11
+
12
+ export class UnicodeGraphemesAddon implements ITerminalAddon , IUnicodeGraphemesApi {
13
+ private _provider15Graphemes?: UnicodeGraphemeProvider;
14
+ private _provider15?: UnicodeGraphemeProvider;
15
+ private _unicode?: IUnicodeHandling;
16
+ private _oldVersion: string = '';
17
+
18
+ public activate(terminal: Terminal): void {
19
+ if (! this._provider15) {
20
+ this._provider15 = new UnicodeGraphemeProvider(false);
21
+ }
22
+ if (! this._provider15Graphemes) {
23
+ this._provider15Graphemes = new UnicodeGraphemeProvider(true);
24
+ }
25
+ const unicode = terminal.unicode;
26
+ this._unicode = unicode;
27
+ unicode.register(this._provider15);
28
+ unicode.register(this._provider15Graphemes);
29
+ this._oldVersion = unicode.activeVersion;
30
+ unicode.activeVersion = '15-graphemes';
31
+ }
32
+
33
+ public dispose(): void {
34
+ if (this._unicode) {
35
+ this._unicode.activeVersion = this._oldVersion;
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,147 @@
1
+ import UnicodeTrie from './unicode-trie';
2
+ const trieRaw = "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";
3
+
4
+ declare const Buffer: any;
5
+ function _dec(s: string): Uint8Array {
6
+ if (typeof Buffer !== 'undefined') return Buffer.from(s, 'base64');
7
+ const bs = atob(s);
8
+ const r = new Uint8Array(bs.length);
9
+ for (let i = 0; i < r.length; ++i) r[i] = bs.charCodeAt(i);
10
+ return r;
11
+ }
12
+
13
+ const trieData = new UnicodeTrie(_dec(trieRaw));
14
+ export const GRAPHEME_BREAK_MASK = 0xF;
15
+ export const GRAPHEME_BREAK_SHIFT = 0;
16
+ export const CHARWIDTH_MASK = 0x30;
17
+ export const CHARWIDTH_SHIFT = 4;
18
+
19
+ // Values for the GRAPHEME_BREAK property
20
+ export const GRAPHEME_BREAK_Other = 0; // includes CR, LF, Control
21
+ export const GRAPHEME_BREAK_Prepend = 1;
22
+ export const GRAPHEME_BREAK_Extend = 2;
23
+ export const GRAPHEME_BREAK_Regional_Indicator = 3;
24
+ export const GRAPHEME_BREAK_SpacingMark = 4;
25
+ export const GRAPHEME_BREAK_Hangul_L = 5;
26
+ export const GRAPHEME_BREAK_Hangul_V = 6;
27
+ export const GRAPHEME_BREAK_Hangul_T = 7;
28
+ export const GRAPHEME_BREAK_Hangul_LV = 8;
29
+ export const GRAPHEME_BREAK_Hangul_LVT = 9;
30
+ export const GRAPHEME_BREAK_ZWJ = 10;
31
+ export const GRAPHEME_BREAK_ExtPic = 11;
32
+
33
+ // Only used as return value from shouldJoin/shouldJoinBackwards.
34
+ // (Must be positive; distinct from other values;
35
+ // and become GRAPHEME_BREAK_Other when masked with GRAPHEME_BREAK_MASK.)
36
+ const GRAPHEME_BREAK_SAW_Regional_Pair = 32;
37
+
38
+ export const CHARWIDTH_NORMAL = 0;
39
+ export const CHARWIDTH_FORCE_1COLUMN = 1;
40
+ export const CHARWIDTH_EA_AMBIGUOUS = 2;
41
+ export const CHARWIDTH_WIDE = 3;
42
+
43
+ // In the following 'info' is an encoded value from trie.get(codePoint)
44
+
45
+ // In the following 'info' is an encoded value from trie.get(codePoint)
46
+
47
+ export function infoToWidthInfo(info: number): number {
48
+ return (info & CHARWIDTH_MASK) >> CHARWIDTH_SHIFT;
49
+ }
50
+
51
+ export function infoToWidth(info: number, ambiguousIsWide = false): 0 | 1 |2 {
52
+ const v = infoToWidthInfo(info);
53
+ return v < CHARWIDTH_EA_AMBIGUOUS ? 1
54
+ : v >= CHARWIDTH_WIDE || ambiguousIsWide ? 2 : 1;
55
+ }
56
+
57
+ export function strWidth(str: string, preferWide: boolean): number {
58
+ let width = 0;
59
+ for (let i = 0; i < str.length;) {
60
+ const codePoint = str.codePointAt(i) as number;
61
+ width += infoToWidth(getInfo(codePoint), preferWide);
62
+ i += (codePoint <= 0xffff) ? 1 : 2;
63
+ }
64
+ return width;
65
+ }
66
+
67
+ export function columnToIndexInContext(str: string, startIndex: number, column: number, preferWide: boolean): number {
68
+ let rv = 0;
69
+ for (let i = startIndex; ;) {
70
+ if (i >= str.length)
71
+ return i;
72
+ const codePoint = str.codePointAt(i) as number;
73
+ const w = infoToWidth(getInfo(codePoint), preferWide);
74
+ rv += w;
75
+ if (rv > column)
76
+ return i;
77
+ i += (codePoint <= 0xffff) ? 1 : 2;
78
+ }
79
+ }
80
+
81
+
82
+ // Test if should break between beforeState and afterCode.
83
+ // Return <= 0 if should break; > 0 if should join.
84
+ // 'beforeState' is the return value from the previous possible break;
85
+ // the value 0 is start of string.
86
+ // 'afterCode' is the GRAPHEME_BREAK_Xxx value for the following codepoint.
87
+ export function shouldJoin(beforeState: number, afterInfo: number): number {
88
+ let beforeCode = (beforeState & GRAPHEME_BREAK_MASK) >> GRAPHEME_BREAK_SHIFT;
89
+ let afterCode = (afterInfo & GRAPHEME_BREAK_MASK) >> GRAPHEME_BREAK_SHIFT;
90
+ if (_shouldJoin(beforeCode, afterCode)) {
91
+ if (afterCode === GRAPHEME_BREAK_Regional_Indicator)
92
+ return GRAPHEME_BREAK_SAW_Regional_Pair;
93
+ else
94
+ return afterCode + 16;
95
+ } else
96
+ return afterCode - 16;
97
+ }
98
+
99
+ export function shouldJoinBackwards(beforeInfo: number, afterState: number): number {
100
+ let afterCode = (afterState & GRAPHEME_BREAK_MASK) >> GRAPHEME_BREAK_SHIFT;
101
+ let beforeCode = (beforeInfo & GRAPHEME_BREAK_MASK) >> GRAPHEME_BREAK_SHIFT;
102
+ if (_shouldJoin(beforeCode, afterCode)) {
103
+ if (beforeCode === GRAPHEME_BREAK_Regional_Indicator)
104
+ return GRAPHEME_BREAK_SAW_Regional_Pair;
105
+ else
106
+ return beforeCode + 16;
107
+ } else
108
+ return beforeCode - 16;
109
+ }
110
+
111
+ /** Doesn't handle an odd number of RI characters. */
112
+ function _shouldJoin(beforeCode: number, afterCode: number): boolean {
113
+ if (beforeCode >= GRAPHEME_BREAK_Hangul_L
114
+ && beforeCode <= GRAPHEME_BREAK_Hangul_LVT) {
115
+ if (beforeCode == GRAPHEME_BREAK_Hangul_L // GB6
116
+ && (afterCode == GRAPHEME_BREAK_Hangul_L
117
+ || afterCode == GRAPHEME_BREAK_Hangul_V
118
+ || afterCode == GRAPHEME_BREAK_Hangul_LV
119
+ || afterCode == GRAPHEME_BREAK_Hangul_LVT))
120
+ return true;
121
+ if ((beforeCode == GRAPHEME_BREAK_Hangul_LV // GB7
122
+ || beforeCode == GRAPHEME_BREAK_Hangul_V)
123
+ && (afterCode == GRAPHEME_BREAK_Hangul_V
124
+ || afterCode == GRAPHEME_BREAK_Hangul_T))
125
+ return true;
126
+ if ((beforeCode == GRAPHEME_BREAK_Hangul_LVT // GB8
127
+ || beforeCode == GRAPHEME_BREAK_Hangul_T)
128
+ && afterCode == GRAPHEME_BREAK_Hangul_T)
129
+ return true;
130
+ }
131
+ if (afterCode == GRAPHEME_BREAK_Extend // GB9
132
+ || afterCode == GRAPHEME_BREAK_ZWJ
133
+ || beforeCode == GRAPHEME_BREAK_Prepend // GB9a
134
+ || afterCode == GRAPHEME_BREAK_SpacingMark) // GB9b
135
+ return true;
136
+ if (beforeCode == GRAPHEME_BREAK_ZWJ // GB11
137
+ && afterCode == GRAPHEME_BREAK_ExtPic)
138
+ return true;
139
+ if (afterCode == GRAPHEME_BREAK_Regional_Indicator // GB12, GB13
140
+ && beforeCode == GRAPHEME_BREAK_Regional_Indicator)
141
+ return true;
142
+ return false;
143
+ }
144
+
145
+ export function getInfo(codePoint: number): number {
146
+ return trieData.get(codePoint);
147
+ }
@@ -0,0 +1,380 @@
1
+ var TINF_OK = 0;
2
+ var TINF_DATA_ERROR = -3;
3
+
4
+ class Tree {
5
+ table = new Uint16Array(16); /* table of code length counts */
6
+ trans = new Uint16Array(288); /* code -> symbol translation table */
7
+ };
8
+
9
+ class Data {
10
+ tag: number = 0;
11
+ bitcount: number = 0;
12
+ destLen: number = 0;
13
+ ltree: Tree;
14
+ dtree: Tree;
15
+ source: Uint8Array;
16
+ dest: Uint8Array;
17
+ sourceIndex: number = 0;
18
+
19
+ constructor(source: Uint8Array, dest: Uint8Array) {
20
+ this.source = source;
21
+ this.dest = dest;
22
+ this.ltree = new Tree(); /* dynamic length/symbol tree */
23
+ this.dtree = new Tree(); /* dynamic distance tree */
24
+ }
25
+ }
26
+
27
+ /* --------------------------------------------------- *
28
+ * -- uninitialized global data (static structures) -- *
29
+ * --------------------------------------------------- */
30
+
31
+ var sltree = new Tree();
32
+ var sdtree = new Tree();
33
+
34
+ /* extra bits and base tables for length codes */
35
+ var length_bits = new Uint8Array(30);
36
+ var length_base = new Uint16Array(30);
37
+
38
+ /* extra bits and base tables for distance codes */
39
+ var dist_bits = new Uint8Array(30);
40
+ var dist_base = new Uint16Array(30);
41
+
42
+ /* special ordering of code length codes */
43
+ var clcidx = new Uint8Array([
44
+ 16, 17, 18, 0, 8, 7, 9, 6,
45
+ 10, 5, 11, 4, 12, 3, 13, 2,
46
+ 14, 1, 15
47
+ ]);
48
+
49
+ /* used by tinf_decode_trees, avoids allocations every call */
50
+ const code_tree = new Tree();
51
+ const lengths = new Uint8Array(288 + 32);
52
+
53
+ /* ----------------------- *
54
+ * -- utility functions -- *
55
+ * ----------------------- */
56
+
57
+ /* build extra bits and base tables */
58
+ function tinf_build_bits_base(bits: Uint8Array, base: Uint16Array, delta: number, first: number): void {
59
+ var i, sum;
60
+
61
+ /* build bits table */
62
+ for (i = 0; i < delta; ++i) bits[i] = 0;
63
+ for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta | 0;
64
+
65
+ /* build base table */
66
+ for (sum = first, i = 0; i < 30; ++i) {
67
+ base[i] = sum;
68
+ sum += 1 << bits[i];
69
+ }
70
+ }
71
+
72
+ /* build the fixed huffman trees */
73
+ function tinf_build_fixed_trees(lt: Tree, dt: Tree): void {
74
+ var i;
75
+
76
+ /* build fixed length tree */
77
+ for (i = 0; i < 7; ++i) lt.table[i] = 0;
78
+
79
+ lt.table[7] = 24;
80
+ lt.table[8] = 152;
81
+ lt.table[9] = 112;
82
+
83
+ for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i;
84
+ for (i = 0; i < 144; ++i) lt.trans[24 + i] = i;
85
+ for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i;
86
+ for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i;
87
+
88
+ /* build fixed distance tree */
89
+ for (i = 0; i < 5; ++i) dt.table[i] = 0;
90
+
91
+ dt.table[5] = 32;
92
+
93
+ for (i = 0; i < 32; ++i) dt.trans[i] = i;
94
+ }
95
+
96
+ /* given an array of code lengths, build a tree */
97
+ var offs = new Uint16Array(16);
98
+
99
+ function tinf_build_tree(t: Tree, lengths: Uint8Array, off: number, num: number): void {
100
+ var i, sum;
101
+
102
+ /* clear code length count table */
103
+ for (i = 0; i < 16; ++i) t.table[i] = 0;
104
+
105
+ /* scan symbol lengths, and sum code length counts */
106
+ for (i = 0; i < num; ++i) t.table[lengths[off + i]]++;
107
+
108
+ t.table[0] = 0;
109
+
110
+ /* compute offset table for distribution sort */
111
+ for (sum = 0, i = 0; i < 16; ++i) {
112
+ offs[i] = sum;
113
+ sum += t.table[i];
114
+ }
115
+
116
+ /* create code->symbol translation table (symbols sorted by code) */
117
+ for (i = 0; i < num; ++i) {
118
+ if (lengths[off + i]) t.trans[offs[lengths[off + i]]++] = i;
119
+ }
120
+ }
121
+
122
+ /* ---------------------- *
123
+ * -- decode functions -- *
124
+ * ---------------------- */
125
+
126
+ /* get one bit from source stream */
127
+ function tinf_getbit(d: Data): number {
128
+ /* check if tag is empty */
129
+ if (!d.bitcount--) {
130
+ /* load next tag */
131
+ d.tag = d.source[d.sourceIndex++];
132
+ d.bitcount = 7;
133
+ }
134
+
135
+ /* shift bit out of tag */
136
+ var bit = d.tag & 1;
137
+ d.tag >>>= 1;
138
+
139
+ return bit;
140
+ }
141
+
142
+ /* read a num bit value from a stream and add base */
143
+ function tinf_read_bits(d: Data, num: number, base: number): number {
144
+ if (!num)
145
+ return base;
146
+
147
+ while (d.bitcount < 24) {
148
+ d.tag |= d.source[d.sourceIndex++] << d.bitcount;
149
+ d.bitcount += 8;
150
+ }
151
+
152
+ var val = d.tag & (0xffff >>> (16 - num));
153
+ d.tag >>>= num;
154
+ d.bitcount -= num;
155
+ return val + base;
156
+ }
157
+
158
+ /* given a data stream and a tree, decode a symbol */
159
+ function tinf_decode_symbol(d: Data, t: Tree): number {
160
+ while (d.bitcount < 24) {
161
+ d.tag |= d.source[d.sourceIndex++] << d.bitcount;
162
+ d.bitcount += 8;
163
+ }
164
+
165
+ var sum = 0, cur = 0, len = 0;
166
+ var tag = d.tag;
167
+
168
+ /* get more bits while code value is above sum */
169
+ do {
170
+ cur = 2 * cur + (tag & 1);
171
+ tag >>>= 1;
172
+ ++len;
173
+
174
+ sum += t.table[len];
175
+ cur -= t.table[len];
176
+ } while (cur >= 0);
177
+
178
+ d.tag = tag;
179
+ d.bitcount -= len;
180
+
181
+ return t.trans[sum + cur];
182
+ }
183
+
184
+ /* given a data stream, decode dynamic trees from it */
185
+ function tinf_decode_trees(d: Data, lt: Tree, dt: Tree): void {
186
+ var hlit, hdist, hclen;
187
+ var i, num, length;
188
+
189
+ /* get 5 bits HLIT (257-286) */
190
+ hlit = tinf_read_bits(d, 5, 257);
191
+
192
+ /* get 5 bits HDIST (1-32) */
193
+ hdist = tinf_read_bits(d, 5, 1);
194
+
195
+ /* get 4 bits HCLEN (4-19) */
196
+ hclen = tinf_read_bits(d, 4, 4);
197
+
198
+ for (i = 0; i < 19; ++i) lengths[i] = 0;
199
+
200
+ /* read code lengths for code length alphabet */
201
+ for (i = 0; i < hclen; ++i) {
202
+ /* get 3 bits code length (0-7) */
203
+ var clen = tinf_read_bits(d, 3, 0);
204
+ lengths[clcidx[i]] = clen;
205
+ }
206
+
207
+ /* build code length tree */
208
+ tinf_build_tree(code_tree, lengths, 0, 19);
209
+
210
+ /* decode code lengths for the dynamic trees */
211
+ for (num = 0; num < hlit + hdist;) {
212
+ var sym = tinf_decode_symbol(d, code_tree);
213
+
214
+ switch (sym) {
215
+ case 16:
216
+ /* copy previous code length 3-6 times (read 2 bits) */
217
+ var prev = lengths[num - 1];
218
+ for (length = tinf_read_bits(d, 2, 3); length; --length) {
219
+ lengths[num++] = prev;
220
+ }
221
+ break;
222
+ case 17:
223
+ /* repeat code length 0 for 3-10 times (read 3 bits) */
224
+ for (length = tinf_read_bits(d, 3, 3); length; --length) {
225
+ lengths[num++] = 0;
226
+ }
227
+ break;
228
+ case 18:
229
+ /* repeat code length 0 for 11-138 times (read 7 bits) */
230
+ for (length = tinf_read_bits(d, 7, 11); length; --length) {
231
+ lengths[num++] = 0;
232
+ }
233
+ break;
234
+ default:
235
+ /* values 0-15 represent the actual code lengths */
236
+ lengths[num++] = sym;
237
+ break;
238
+ }
239
+ }
240
+
241
+ /* build dynamic trees */
242
+ tinf_build_tree(lt, lengths, 0, hlit);
243
+ tinf_build_tree(dt, lengths, hlit, hdist);
244
+ }
245
+
246
+ /* ----------------------------- *
247
+ * -- block inflate functions -- *
248
+ * ----------------------------- */
249
+
250
+ /* given a stream and two trees, inflate a block of data */
251
+ function tinf_inflate_block_data(d: Data, lt: Tree, dt: Tree): number {
252
+ for (;;) {
253
+ var sym = tinf_decode_symbol(d, lt);
254
+
255
+ /* check for end of block */
256
+ if (sym === 256) {
257
+ return TINF_OK;
258
+ }
259
+
260
+ if (sym < 256) {
261
+ d.dest[d.destLen++] = sym;
262
+ } else {
263
+ var length, dist, offs;
264
+ var i;
265
+
266
+ sym -= 257;
267
+
268
+ /* possibly get more bits from length code */
269
+ length = tinf_read_bits(d, length_bits[sym], length_base[sym]);
270
+
271
+ dist = tinf_decode_symbol(d, dt);
272
+
273
+ /* possibly get more bits from distance code */
274
+ offs = d.destLen - tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
275
+
276
+ /* copy match */
277
+ for (i = offs; i < offs + length; ++i) {
278
+ d.dest[d.destLen++] = d.dest[i];
279
+ }
280
+ }
281
+ }
282
+ }
283
+
284
+ /* inflate an uncompressed block of data */
285
+ function tinf_inflate_uncompressed_block(d: Data) {
286
+ var length, invlength;
287
+ var i;
288
+
289
+ /* unread from bitbuffer */
290
+ while (d.bitcount > 8) {
291
+ d.sourceIndex--;
292
+ d.bitcount -= 8;
293
+ }
294
+
295
+ /* get length */
296
+ length = d.source[d.sourceIndex + 1];
297
+ length = 256 * length + d.source[d.sourceIndex];
298
+
299
+ /* get one's complement of length */
300
+ invlength = d.source[d.sourceIndex + 3];
301
+ invlength = 256 * invlength + d.source[d.sourceIndex + 2];
302
+
303
+ /* check length */
304
+ if (length !== (~invlength & 0x0000ffff))
305
+ return TINF_DATA_ERROR;
306
+
307
+ d.sourceIndex += 4;
308
+
309
+ /* copy block */
310
+ for (i = length; i; --i)
311
+ d.dest[d.destLen++] = d.source[d.sourceIndex++];
312
+
313
+ /* make sure we start next block on a byte boundary */
314
+ d.bitcount = 0;
315
+
316
+ return TINF_OK;
317
+ }
318
+
319
+ /* inflate stream from source to dest */
320
+ function tinf_uncompress(source: Uint8Array, dest: Uint8Array) {
321
+ var d = new Data(source, dest);
322
+ var bfinal, btype, res;
323
+
324
+ do {
325
+ /* read final block flag */
326
+ bfinal = tinf_getbit(d);
327
+
328
+ /* read block type (2 bits) */
329
+ btype = tinf_read_bits(d, 2, 0);
330
+
331
+ /* decompress block */
332
+ switch (btype) {
333
+ case 0:
334
+ /* decompress uncompressed block */
335
+ res = tinf_inflate_uncompressed_block(d);
336
+ break;
337
+ case 1:
338
+ /* decompress block with fixed huffman trees */
339
+ res = tinf_inflate_block_data(d, sltree, sdtree);
340
+ break;
341
+ case 2:
342
+ /* decompress block with dynamic huffman trees */
343
+ tinf_decode_trees(d, d.ltree, d.dtree);
344
+ res = tinf_inflate_block_data(d, d.ltree, d.dtree);
345
+ break;
346
+ default:
347
+ res = TINF_DATA_ERROR;
348
+ }
349
+
350
+ if (res !== TINF_OK)
351
+ throw new Error('Data error');
352
+
353
+ } while (!bfinal);
354
+
355
+ if (d.destLen < d.dest.length) {
356
+ if (typeof d.dest.slice === 'function')
357
+ return d.dest.slice(0, d.destLen);
358
+ else
359
+ return d.dest.subarray(0, d.destLen);
360
+ }
361
+
362
+ return d.dest;
363
+ }
364
+
365
+ /* -------------------- *
366
+ * -- initialization -- *
367
+ * -------------------- */
368
+
369
+ /* build fixed huffman trees */
370
+ tinf_build_fixed_trees(sltree, sdtree);
371
+
372
+ /* build extra bits and base tables */
373
+ tinf_build_bits_base(length_bits, length_base, 4, 3);
374
+ tinf_build_bits_base(dist_bits, dist_base, 2, 1);
375
+
376
+ /* fix a special case */
377
+ length_bits[28] = 0;
378
+ length_base[28] = 258;
379
+
380
+ export default tinf_uncompress