-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecode-ranges.js
79 lines (72 loc) · 1.59 KB
/
decode-ranges.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
* This file ships to end users.
* See scripts/encode-ranges.js for encode utilities
*/
const base64enc =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
const base64dec = Object.freeze(Object.fromEntries(
Array.from(base64enc, (c, i) => [c, i])
));
class UnicodeRange {
constructor(begin, end) {
this.begin = begin;
this.end = end;
this.length = end - begin;
}
*keys() {
const { begin, end } = this;
for (let i = begin; i < end; ++i) {
yield i;
}
}
*values() {
const { begin, end } = this;
for (let i = begin; i < end; ++i) {
yield String.fromCodePoint(i);
}
}
}
/**
* Base64 decode variable-length deltas (5/10/15/21-bit).
*/
function decodeDeltas(input) {
const output = [];
for (let i = 0; i < input.length; ) {
let x = base64dec[input[i++]];
switch (x & 56) {
case 32:
case 40:
x = (x & 15) << 6;
x |= base64dec[input[i++]];
break;
case 48:
x = (x & 7) << 12;
x |= base64dec[input[i++]] << 6;
x |= base64dec[input[i++]];
break;
case 56:
x = (x & 7) << 18;
x |= base64dec[input[i++]] << 12;
x |= base64dec[input[i++]] << 6;
x |= base64dec[input[i++]];
break;
}
output.push(x);
}
return output;
}
/**
* RLE + base64 decode code point ranges.
*/
function decodeRanges(input) {
const deltas = decodeDeltas(input);
const ranges = [];
for (let end = -1, i = 1; i < deltas.length; i += 2) {
const begin = end + 1 + deltas[i - 1];
const length = 1 + deltas[i];
end = begin + length;
ranges.push(new UnicodeRange(begin, end));
}
return ranges;
}
module.exports = decodeRanges;