teeworlds 2.0.2 → 2.0.5
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/lib/client.js +212 -228
- package/lib/client.ts +19 -26
- package/lib/huffman.js +236 -0
- package/lib/huffman.ts +342 -0
- package/package.json +1 -1
- package/lib/huffman.py +0 -224
package/lib/client.ts
CHANGED
|
@@ -7,7 +7,9 @@ import { spawn } from 'child_process';
|
|
|
7
7
|
import MsgUnpacker from './MsgUnpacker';
|
|
8
8
|
import MsgPacker from './MsgPacker';
|
|
9
9
|
import { Snapshot } from './snapshot';
|
|
10
|
+
import Huffman from "./huffman";
|
|
10
11
|
|
|
12
|
+
const huff = new Huffman();
|
|
11
13
|
const SnapUnpacker = new Snapshot();
|
|
12
14
|
|
|
13
15
|
enum NETMSGTYPE {
|
|
@@ -83,24 +85,6 @@ interface chunk {
|
|
|
83
85
|
function toHexStream(buff: Buffer): string {
|
|
84
86
|
return buff.toJSON().data.map(a => ('0' + (a & 0xff).toString(16)).slice(-2)).join("");
|
|
85
87
|
}
|
|
86
|
-
async function decompress(buff: Buffer): Promise<Buffer> {
|
|
87
|
-
return new Promise((resolve) => {
|
|
88
|
-
// get hex stream
|
|
89
|
-
var hexStream = toHexStream(buff)
|
|
90
|
-
var ls = spawn('python', [__dirname + '\\huffman.py', hexStream, "-decompress"])
|
|
91
|
-
ls.stdout.on('data', (data) => {
|
|
92
|
-
resolve(Buffer.from(eval(data.toString()))); // convert stdout array to actual array, then convert the array to Buffer & return it
|
|
93
|
-
});
|
|
94
|
-
setTimeout(() => {
|
|
95
|
-
ls.stdin.end();
|
|
96
|
-
ls.stdout.destroy();
|
|
97
|
-
ls.stderr.destroy();
|
|
98
|
-
|
|
99
|
-
resolve(Buffer.from([]));
|
|
100
|
-
}, 750)
|
|
101
|
-
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
88
|
interface _packet {
|
|
105
89
|
twprotocol: { flags: number, ack: number, chunkAmount: number, size: number },
|
|
106
90
|
chunks: chunk[]
|
|
@@ -156,7 +140,7 @@ declare interface Client {
|
|
|
156
140
|
receivedSnaps: number; /* wait for 2 ss before seeing self as connected */
|
|
157
141
|
lastMsg: string;
|
|
158
142
|
_port: number;
|
|
159
|
-
socket: net.Socket;
|
|
143
|
+
socket: net.Socket | undefined;
|
|
160
144
|
TKEN: Buffer;
|
|
161
145
|
time: number;
|
|
162
146
|
|
|
@@ -207,7 +191,7 @@ class Client extends EventEmitter {
|
|
|
207
191
|
return unpacked;
|
|
208
192
|
packet = packet.slice(3)
|
|
209
193
|
if (unpacked.twprotocol.flags & 128) {
|
|
210
|
-
packet =
|
|
194
|
+
packet = huff.decompress(packet)
|
|
211
195
|
if (packet.length == 1 && packet[0] == -1)
|
|
212
196
|
return unpacked
|
|
213
197
|
}
|
|
@@ -242,12 +226,14 @@ class Client extends EventEmitter {
|
|
|
242
226
|
}
|
|
243
227
|
SendControlMsg(msg: number, ExtraMsg: string = "") {
|
|
244
228
|
return new Promise((resolve, reject) => {
|
|
229
|
+
if (this.socket) {
|
|
230
|
+
var latestBuf = Buffer.from([0x10 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, 0x00, msg])
|
|
231
|
+
latestBuf = Buffer.concat([latestBuf, Buffer.from(ExtraMsg), this.TKEN]) // move header (latestBuf), optional extraMsg & TKEN into 1 buffer
|
|
232
|
+
this.socket.send(latestBuf, 0, latestBuf.length, this.port, this.host, (err, bytes) => {
|
|
233
|
+
resolve(bytes)
|
|
234
|
+
})
|
|
245
235
|
|
|
246
|
-
|
|
247
|
-
latestBuf = Buffer.concat([latestBuf, Buffer.from(ExtraMsg), this.TKEN]) // move header (latestBuf), optional extraMsg & TKEN into 1 buffer
|
|
248
|
-
this.socket.send(latestBuf, 0, latestBuf.length, this.port, this.host, (err, bytes) => {
|
|
249
|
-
resolve(bytes)
|
|
250
|
-
})
|
|
236
|
+
}
|
|
251
237
|
setTimeout(() => { resolve("failed, rip") }, 2000)
|
|
252
238
|
/* after 2 seconds it was probably not able to send,
|
|
253
239
|
so when sending a quit message the user doesnt
|
|
@@ -258,6 +244,8 @@ class Client extends EventEmitter {
|
|
|
258
244
|
SendMsgEx(Msg: MsgPacker, Flags: number) {
|
|
259
245
|
if (this.State == -1)
|
|
260
246
|
throw new Error("Client is not connected");
|
|
247
|
+
if (!this.socket)
|
|
248
|
+
return;
|
|
261
249
|
var header = []
|
|
262
250
|
header[0] = ((Flags & 3) << 6) | ((Msg.size >> 4) & 0x3f);
|
|
263
251
|
header[1] = (Msg.size & 0xf);
|
|
@@ -274,6 +262,8 @@ class Client extends EventEmitter {
|
|
|
274
262
|
SendMsgExWithChunks(Msgs: MsgPacker[], Flags: number) {
|
|
275
263
|
if (this.State == -1)
|
|
276
264
|
throw new Error("Client is not connected");
|
|
265
|
+
if (!this.socket)
|
|
266
|
+
return;
|
|
277
267
|
var header: any[][] = [];
|
|
278
268
|
|
|
279
269
|
Msgs.forEach((Msg: MsgPacker, index) => {
|
|
@@ -304,6 +294,7 @@ class Client extends EventEmitter {
|
|
|
304
294
|
clearInterval(connectInterval)
|
|
305
295
|
}, 500)
|
|
306
296
|
this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
|
|
297
|
+
if (this.socket)
|
|
307
298
|
this.socket.on("message", async (a) => {
|
|
308
299
|
var unpacked: _packet = await this.Unpack(a)
|
|
309
300
|
if (unpacked.twprotocol.flags != 128 && unpacked.twprotocol.ack) {
|
|
@@ -479,7 +470,9 @@ class Client extends EventEmitter {
|
|
|
479
470
|
return new Promise((resolve) => {
|
|
480
471
|
this.SendControlMsg(4).then(() => {
|
|
481
472
|
resolve(true);
|
|
482
|
-
this.socket
|
|
473
|
+
if (this.socket)
|
|
474
|
+
this.socket.close();
|
|
475
|
+
this.socket = undefined
|
|
483
476
|
this.State = -1;
|
|
484
477
|
})
|
|
485
478
|
})
|
package/lib/huffman.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// from Ryozuki, found on ddnet discord ( 11.10.2018 )
|
|
3
|
+
// from typing import List
|
|
4
|
+
// from sys import argv
|
|
5
|
+
var FREQ_TABLE = [
|
|
6
|
+
1 << 30, 4545, 2657, 431, 1950, 919, 444, 482, 2244, 617, 838, 542, 715, 1814, 304, 240, 754, 212, 647, 186,
|
|
7
|
+
283, 131, 146, 166, 543, 164, 167, 136, 179, 859, 363, 113, 157, 154, 204, 108, 137, 180, 202, 176,
|
|
8
|
+
872, 404, 168, 134, 151, 111, 113, 109, 120, 126, 129, 100, 41, 20, 16, 22, 18, 18, 17, 19,
|
|
9
|
+
16, 37, 13, 21, 362, 166, 99, 78, 95, 88, 81, 70, 83, 284, 91, 187, 77, 68, 52, 68,
|
|
10
|
+
59, 66, 61, 638, 71, 157, 50, 46, 69, 43, 11, 24, 13, 19, 10, 12, 12, 20, 14, 9,
|
|
11
|
+
20, 20, 10, 10, 15, 15, 12, 12, 7, 19, 15, 14, 13, 18, 35, 19, 17, 14, 8, 5,
|
|
12
|
+
15, 17, 9, 15, 14, 18, 8, 10, 2173, 134, 157, 68, 188, 60, 170, 60, 194, 62, 175, 71,
|
|
13
|
+
148, 67, 167, 78, 211, 67, 156, 69, 1674, 90, 174, 53, 147, 89, 181, 51, 174, 63, 163, 80,
|
|
14
|
+
167, 94, 128, 122, 223, 153, 218, 77, 200, 110, 190, 73, 174, 69, 145, 66, 277, 143, 141, 60,
|
|
15
|
+
136, 53, 180, 57, 142, 57, 158, 61, 166, 112, 152, 92, 26, 22, 21, 28, 20, 26, 30, 21,
|
|
16
|
+
32, 27, 20, 17, 23, 21, 30, 22, 22, 21, 27, 25, 17, 27, 23, 18, 39, 26, 15, 21,
|
|
17
|
+
12, 18, 18, 27, 20, 18, 15, 19, 11, 17, 33, 12, 18, 15, 19, 18, 16, 26, 17, 18,
|
|
18
|
+
9, 10, 25, 22, 22, 17, 20, 16, 6, 16, 15, 20, 14, 18, 24, 335, 1517
|
|
19
|
+
], HUFFMAN_EOF_SYMBOL = 256, HUFFMAN_MAX_SYMBOLS = HUFFMAN_EOF_SYMBOL + 1, HUFFMAN_MAX_NODES = HUFFMAN_MAX_SYMBOLS * 2 - 1, HUFFMAN_LUTBITS = 10, HUFFMAN_LUTSIZE = 1 << HUFFMAN_LUTBITS, HUFFMAN_LUTMASK = HUFFMAN_LUTSIZE - 1;
|
|
20
|
+
// class HuffmanConstructNode {
|
|
21
|
+
// node_id: number;
|
|
22
|
+
// frequency: number;
|
|
23
|
+
// constructor(node_id: number, frequency: number) {
|
|
24
|
+
// this.node_id = node_id;
|
|
25
|
+
// this.frequency = frequency;
|
|
26
|
+
// }
|
|
27
|
+
// }
|
|
28
|
+
// class HuffmanConstructNode:
|
|
29
|
+
// def __init__(self):
|
|
30
|
+
// self.node_id: int = None
|
|
31
|
+
// self.frequency: int = None
|
|
32
|
+
var Huffman = /** @class */ (function () {
|
|
33
|
+
function Huffman(frequencies) {
|
|
34
|
+
if (frequencies === void 0) { frequencies = FREQ_TABLE; }
|
|
35
|
+
// this.frequencies = frequencies;
|
|
36
|
+
this.nodes = new Array(HUFFMAN_MAX_NODES);
|
|
37
|
+
for (var i = 0; i < HUFFMAN_MAX_NODES; i++) {
|
|
38
|
+
this.nodes[i] = {};
|
|
39
|
+
}
|
|
40
|
+
this.decode_lut = new Array(HUFFMAN_LUTSIZE);
|
|
41
|
+
this.num_nodes = 0;
|
|
42
|
+
this.start_node_index = 0;
|
|
43
|
+
this.construct_tree(frequencies);
|
|
44
|
+
var xx = 0;
|
|
45
|
+
for (var i = 0; i < HUFFMAN_LUTSIZE; i++) {
|
|
46
|
+
var bits = i;
|
|
47
|
+
var broke = false;
|
|
48
|
+
var index = this.start_node_index;
|
|
49
|
+
for (var x = 0; x < HUFFMAN_LUTBITS; x++) {
|
|
50
|
+
if (bits & 1)
|
|
51
|
+
index = this.nodes[index].right;
|
|
52
|
+
else
|
|
53
|
+
index = this.nodes[index].left;
|
|
54
|
+
bits >>= 1;
|
|
55
|
+
if (this.nodes[index].numbits) {
|
|
56
|
+
this.decode_lut[i] = index;
|
|
57
|
+
broke = true;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!broke) {
|
|
62
|
+
this.decode_lut[i] = index;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
Huffman.prototype.set_bits_r = function (node_index, bits, depth) {
|
|
67
|
+
if (this.nodes[node_index].right != 0xffff)
|
|
68
|
+
this.set_bits_r(this.nodes[node_index].right, bits | (1 << depth), depth + 1);
|
|
69
|
+
if (this.nodes[node_index].left != 0xffff)
|
|
70
|
+
this.set_bits_r(this.nodes[node_index].left, bits, depth + 1);
|
|
71
|
+
if (this.nodes[node_index].numbits) {
|
|
72
|
+
this.nodes[node_index].bits = bits;
|
|
73
|
+
this.nodes[node_index].numbits = depth;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
Huffman.prototype.bubble_sort = function (index_list, node_list, size) {
|
|
77
|
+
var changed = true;
|
|
78
|
+
while (changed) {
|
|
79
|
+
changed = false;
|
|
80
|
+
for (var i = 0; i < size - 1; i++) {
|
|
81
|
+
if (node_list[index_list[i]].frequency < node_list[index_list[i + 1]].frequency) {
|
|
82
|
+
var temp = index_list[i];
|
|
83
|
+
index_list[i] = index_list[i + 1];
|
|
84
|
+
index_list[i + 1] = temp;
|
|
85
|
+
changed = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
size--;
|
|
89
|
+
}
|
|
90
|
+
return index_list;
|
|
91
|
+
};
|
|
92
|
+
Huffman.prototype.construct_tree = function (frequencies) {
|
|
93
|
+
if (frequencies === void 0) { frequencies = FREQ_TABLE; }
|
|
94
|
+
var nodes_left_storage = new Array(HUFFMAN_MAX_SYMBOLS);
|
|
95
|
+
for (var i = 0; i < HUFFMAN_MAX_SYMBOLS; i++) {
|
|
96
|
+
nodes_left_storage[i] = {};
|
|
97
|
+
}
|
|
98
|
+
var nodes_left = new Array(HUFFMAN_MAX_SYMBOLS);
|
|
99
|
+
var num_nodes_left = HUFFMAN_MAX_SYMBOLS;
|
|
100
|
+
for (var i = 0; i < HUFFMAN_MAX_SYMBOLS; i++) {
|
|
101
|
+
this.nodes[i].numbits = 0xFFFFFFFF;
|
|
102
|
+
this.nodes[i].symbol = i;
|
|
103
|
+
this.nodes[i].left = 0xFFFF;
|
|
104
|
+
this.nodes[i].right = 0xFFFF;
|
|
105
|
+
if (i == HUFFMAN_EOF_SYMBOL) {
|
|
106
|
+
nodes_left_storage[i].frequency = 1;
|
|
107
|
+
}
|
|
108
|
+
else
|
|
109
|
+
nodes_left_storage[i].frequency = frequencies[i];
|
|
110
|
+
nodes_left_storage[i].node_id = i;
|
|
111
|
+
nodes_left[i] = i;
|
|
112
|
+
}
|
|
113
|
+
this.num_nodes = HUFFMAN_MAX_SYMBOLS;
|
|
114
|
+
while (num_nodes_left > 1) {
|
|
115
|
+
nodes_left = this.bubble_sort(nodes_left, nodes_left_storage, num_nodes_left);
|
|
116
|
+
this.nodes[this.num_nodes].numbits = 0;
|
|
117
|
+
this.nodes[this.num_nodes].left = nodes_left_storage[nodes_left[num_nodes_left - 1]].node_id;
|
|
118
|
+
this.nodes[this.num_nodes].right = nodes_left_storage[nodes_left[num_nodes_left - 2]].node_id;
|
|
119
|
+
nodes_left_storage[nodes_left[num_nodes_left - 2]].node_id = this.num_nodes;
|
|
120
|
+
nodes_left_storage[nodes_left[num_nodes_left - 2]].frequency = nodes_left_storage[nodes_left[num_nodes_left - 1]].frequency
|
|
121
|
+
+ nodes_left_storage[nodes_left[num_nodes_left - 2]].frequency;
|
|
122
|
+
this.num_nodes++;
|
|
123
|
+
num_nodes_left--;
|
|
124
|
+
}
|
|
125
|
+
this.start_node_index = this.num_nodes - 1;
|
|
126
|
+
this.set_bits_r(this.start_node_index, 0, 0);
|
|
127
|
+
};
|
|
128
|
+
Huffman.prototype.compress = function (inp_buffer, start_index, size) {
|
|
129
|
+
if (start_index === void 0) { start_index = 0; }
|
|
130
|
+
if (size === void 0) { size = 0; }
|
|
131
|
+
var output = [];
|
|
132
|
+
var bits = 0;
|
|
133
|
+
var bitcount = 0;
|
|
134
|
+
if (size == 0)
|
|
135
|
+
size = inp_buffer.byteLength;
|
|
136
|
+
inp_buffer = inp_buffer.slice(start_index, start_index + size);
|
|
137
|
+
for (var i = 0; i < size; i++) {
|
|
138
|
+
var x = inp_buffer[i];
|
|
139
|
+
bits |= this.nodes[x].bits << bitcount;
|
|
140
|
+
bitcount += this.nodes[x].numbits;
|
|
141
|
+
while (bitcount >= 8) {
|
|
142
|
+
output.push(bits & 0xff);
|
|
143
|
+
bits >>= 8;
|
|
144
|
+
bitcount -= 8;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
bits |= this.nodes[HUFFMAN_EOF_SYMBOL].bits << bitcount;
|
|
148
|
+
bitcount += this.nodes[HUFFMAN_EOF_SYMBOL].numbits;
|
|
149
|
+
while (bitcount >= 8) {
|
|
150
|
+
output.push(bits & 0xff);
|
|
151
|
+
bits >>= 8;
|
|
152
|
+
bitcount -= 8;
|
|
153
|
+
}
|
|
154
|
+
output.push(bits);
|
|
155
|
+
return Buffer.from(output);
|
|
156
|
+
/* output = bytearray()
|
|
157
|
+
bits = 0
|
|
158
|
+
bitcount = 0
|
|
159
|
+
|
|
160
|
+
if size is None:
|
|
161
|
+
size = len(inp_buffer)
|
|
162
|
+
|
|
163
|
+
for x in inp_buffer[start_index:size:]:
|
|
164
|
+
bits |= self.nodes[x].bits << bitcount
|
|
165
|
+
bitcount += self.nodes[x].numbits
|
|
166
|
+
|
|
167
|
+
while bitcount >= 8:
|
|
168
|
+
output.append(bits & 0xff)
|
|
169
|
+
bits >>= 8
|
|
170
|
+
bitcount -= 8
|
|
171
|
+
|
|
172
|
+
bits |= self.nodes[HUFFMAN_EOF_SYMBOL].bits << bitcount
|
|
173
|
+
bitcount += self.nodes[HUFFMAN_EOF_SYMBOL].numbits
|
|
174
|
+
|
|
175
|
+
while bitcount >= 8:
|
|
176
|
+
output.append(bits & 0xff)
|
|
177
|
+
bits >>= 8
|
|
178
|
+
bitcount -= 8
|
|
179
|
+
|
|
180
|
+
# write out last bits
|
|
181
|
+
output.append(bits)
|
|
182
|
+
return output
|
|
183
|
+
*/
|
|
184
|
+
};
|
|
185
|
+
Huffman.prototype.decompress = function (inp_buffer, size) {
|
|
186
|
+
if (size === void 0) { size = 0; }
|
|
187
|
+
var bits = 0;
|
|
188
|
+
var bitcount = 0;
|
|
189
|
+
var eof = this.nodes[HUFFMAN_EOF_SYMBOL];
|
|
190
|
+
var output = [];
|
|
191
|
+
if (size == 0)
|
|
192
|
+
size = inp_buffer.byteLength;
|
|
193
|
+
inp_buffer = inp_buffer.slice(0, size);
|
|
194
|
+
var src_index = 0;
|
|
195
|
+
while (true) {
|
|
196
|
+
var node_i = -1;
|
|
197
|
+
if (bitcount >= HUFFMAN_LUTBITS)
|
|
198
|
+
node_i = this.decode_lut[bits & HUFFMAN_LUTMASK];
|
|
199
|
+
while (bitcount < 24 && src_index != size) {
|
|
200
|
+
bits |= inp_buffer[src_index] << bitcount;
|
|
201
|
+
bitcount += 8;
|
|
202
|
+
src_index++;
|
|
203
|
+
}
|
|
204
|
+
if (node_i == -1)
|
|
205
|
+
node_i = this.decode_lut[bits & HUFFMAN_LUTMASK];
|
|
206
|
+
// console.log(node_i, bits & HUFFMAN_LUTMASK, this.decode_lut)
|
|
207
|
+
if (this.nodes[node_i].numbits) {
|
|
208
|
+
bits >>= this.nodes[node_i].numbits;
|
|
209
|
+
bitcount -= this.nodes[node_i].numbits;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
bits >>= HUFFMAN_LUTBITS;
|
|
213
|
+
bitcount -= HUFFMAN_LUTBITS;
|
|
214
|
+
while (true) {
|
|
215
|
+
if (bits & 1) {
|
|
216
|
+
node_i = this.nodes[node_i].right;
|
|
217
|
+
}
|
|
218
|
+
else
|
|
219
|
+
node_i = this.nodes[node_i].left;
|
|
220
|
+
bitcount -= 1;
|
|
221
|
+
bits >>= 1;
|
|
222
|
+
if (this.nodes[node_i].numbits)
|
|
223
|
+
break;
|
|
224
|
+
if (bitcount == 0)
|
|
225
|
+
throw new Error("No more bits, decoding error");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (this.nodes[node_i] == eof)
|
|
229
|
+
break;
|
|
230
|
+
output.push(this.nodes[node_i].symbol);
|
|
231
|
+
}
|
|
232
|
+
return Buffer.from(output);
|
|
233
|
+
};
|
|
234
|
+
return Huffman;
|
|
235
|
+
}());
|
|
236
|
+
module.exports = Huffman;
|
package/lib/huffman.ts
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// from Ryozuki, found on ddnet discord ( 11.10.2018 )
|
|
2
|
+
// from typing import List
|
|
3
|
+
// from sys import argv
|
|
4
|
+
let FREQ_TABLE = [
|
|
5
|
+
1 << 30, 4545, 2657, 431, 1950, 919, 444, 482, 2244, 617, 838, 542, 715, 1814, 304, 240, 754, 212, 647, 186,
|
|
6
|
+
283, 131, 146, 166, 543, 164, 167, 136, 179, 859, 363, 113, 157, 154, 204, 108, 137, 180, 202, 176,
|
|
7
|
+
872, 404, 168, 134, 151, 111, 113, 109, 120, 126, 129, 100, 41, 20, 16, 22, 18, 18, 17, 19,
|
|
8
|
+
16, 37, 13, 21, 362, 166, 99, 78, 95, 88, 81, 70, 83, 284, 91, 187, 77, 68, 52, 68,
|
|
9
|
+
59, 66, 61, 638, 71, 157, 50, 46, 69, 43, 11, 24, 13, 19, 10, 12, 12, 20, 14, 9,
|
|
10
|
+
20, 20, 10, 10, 15, 15, 12, 12, 7, 19, 15, 14, 13, 18, 35, 19, 17, 14, 8, 5,
|
|
11
|
+
15, 17, 9, 15, 14, 18, 8, 10, 2173, 134, 157, 68, 188, 60, 170, 60, 194, 62, 175, 71,
|
|
12
|
+
148, 67, 167, 78, 211, 67, 156, 69, 1674, 90, 174, 53, 147, 89, 181, 51, 174, 63, 163, 80,
|
|
13
|
+
167, 94, 128, 122, 223, 153, 218, 77, 200, 110, 190, 73, 174, 69, 145, 66, 277, 143, 141, 60,
|
|
14
|
+
136, 53, 180, 57, 142, 57, 158, 61, 166, 112, 152, 92, 26, 22, 21, 28, 20, 26, 30, 21,
|
|
15
|
+
32, 27, 20, 17, 23, 21, 30, 22, 22, 21, 27, 25, 17, 27, 23, 18, 39, 26, 15, 21,
|
|
16
|
+
12, 18, 18, 27, 20, 18, 15, 19, 11, 17, 33, 12, 18, 15, 19, 18, 16, 26, 17, 18,
|
|
17
|
+
9, 10, 25, 22, 22, 17, 20, 16, 6, 16, 15, 20, 14, 18, 24, 335, 1517],
|
|
18
|
+
|
|
19
|
+
HUFFMAN_EOF_SYMBOL = 256,
|
|
20
|
+
HUFFMAN_MAX_SYMBOLS = HUFFMAN_EOF_SYMBOL + 1,
|
|
21
|
+
HUFFMAN_MAX_NODES = HUFFMAN_MAX_SYMBOLS * 2 - 1,
|
|
22
|
+
HUFFMAN_LUTBITS = 10,
|
|
23
|
+
HUFFMAN_LUTSIZE = 1 << HUFFMAN_LUTBITS,
|
|
24
|
+
HUFFMAN_LUTMASK = HUFFMAN_LUTSIZE - 1;
|
|
25
|
+
|
|
26
|
+
interface HuffmanNode {
|
|
27
|
+
bits: number;
|
|
28
|
+
numbits: number;
|
|
29
|
+
left: number;
|
|
30
|
+
right: number;
|
|
31
|
+
symbol: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// class HuffmanNode {
|
|
35
|
+
// bits: number;
|
|
36
|
+
// numbits: number;
|
|
37
|
+
// left: number;
|
|
38
|
+
// right: number;
|
|
39
|
+
// symbol: number;
|
|
40
|
+
// constructor(/*bits: number, numbits: number, left: number, right: number, symbol: number*/) {
|
|
41
|
+
// this.bits = -1;
|
|
42
|
+
// this.numbits = -1;
|
|
43
|
+
// this.left = -1;
|
|
44
|
+
// this.right = -1;
|
|
45
|
+
// this.symbol = -1;
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
// equal(node: HuffmanNode) {
|
|
49
|
+
// return this.bits == node.bits && this.numbits == node.numbits && this.left == node.left && this.right == node.right && this.symbol == node.symbol;
|
|
50
|
+
// }
|
|
51
|
+
|
|
52
|
+
// }
|
|
53
|
+
|
|
54
|
+
interface HuffmanConstructNode {
|
|
55
|
+
node_id: number;
|
|
56
|
+
frequency: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// class HuffmanConstructNode {
|
|
60
|
+
// node_id: number;
|
|
61
|
+
// frequency: number;
|
|
62
|
+
// constructor(node_id: number, frequency: number) {
|
|
63
|
+
// this.node_id = node_id;
|
|
64
|
+
// this.frequency = frequency;
|
|
65
|
+
// }
|
|
66
|
+
// }
|
|
67
|
+
// class HuffmanConstructNode:
|
|
68
|
+
// def __init__(self):
|
|
69
|
+
// self.node_id: int = None
|
|
70
|
+
// self.frequency: int = None
|
|
71
|
+
|
|
72
|
+
class Huffman {
|
|
73
|
+
nodes: HuffmanNode[];
|
|
74
|
+
decode_lut: number[];
|
|
75
|
+
num_nodes: number;
|
|
76
|
+
start_node_index: number;
|
|
77
|
+
|
|
78
|
+
constructor(frequencies = FREQ_TABLE) {
|
|
79
|
+
// this.frequencies = frequencies;
|
|
80
|
+
this.nodes = new Array<HuffmanNode>(HUFFMAN_MAX_NODES);
|
|
81
|
+
for (let i = 0; i < HUFFMAN_MAX_NODES; i++) {
|
|
82
|
+
this.nodes[i] = {} as HuffmanNode;
|
|
83
|
+
}
|
|
84
|
+
this.decode_lut = new Array<number>(HUFFMAN_LUTSIZE);
|
|
85
|
+
this.num_nodes = 0;
|
|
86
|
+
this.start_node_index = 0;
|
|
87
|
+
|
|
88
|
+
this.construct_tree(frequencies);
|
|
89
|
+
|
|
90
|
+
let xx = 0;
|
|
91
|
+
|
|
92
|
+
for (let i = 0; i < HUFFMAN_LUTSIZE; i++) {
|
|
93
|
+
let bits = i;
|
|
94
|
+
let broke = false;
|
|
95
|
+
let index = this.start_node_index;
|
|
96
|
+
for (let x = 0; x < HUFFMAN_LUTBITS; x++) {
|
|
97
|
+
if (bits & 1)
|
|
98
|
+
index = this.nodes[index].right;
|
|
99
|
+
else
|
|
100
|
+
index = this.nodes[index].left;
|
|
101
|
+
bits >>= 1;
|
|
102
|
+
if (this.nodes[index].numbits) {
|
|
103
|
+
this.decode_lut[i] = index;
|
|
104
|
+
broke = true;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!broke) {
|
|
109
|
+
this.decode_lut[i] = index;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
set_bits_r(node_index: number, bits: number, depth: number) {
|
|
114
|
+
if (this.nodes[node_index].right != 0xffff)
|
|
115
|
+
this.set_bits_r(this.nodes[node_index].right, bits | (1 << depth), depth + 1)
|
|
116
|
+
if (this.nodes[node_index].left != 0xffff)
|
|
117
|
+
this.set_bits_r(this.nodes[node_index].left, bits, depth + 1)
|
|
118
|
+
if (this.nodes[node_index].numbits) {
|
|
119
|
+
this.nodes[node_index].bits = bits;
|
|
120
|
+
this.nodes[node_index].numbits = depth;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
bubble_sort(index_list: number[], node_list: HuffmanConstructNode[], size: number) {
|
|
125
|
+
let changed = true;
|
|
126
|
+
while (changed) {
|
|
127
|
+
changed = false;
|
|
128
|
+
for (let i = 0; i < size-1; i++) {
|
|
129
|
+
if (node_list[index_list[i]].frequency < node_list[index_list[i + 1]].frequency) {
|
|
130
|
+
let temp = index_list[i];
|
|
131
|
+
index_list[i] = index_list[i + 1];
|
|
132
|
+
index_list[i + 1] = temp;
|
|
133
|
+
changed = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
size--;
|
|
137
|
+
}
|
|
138
|
+
return index_list;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
construct_tree(frequencies = FREQ_TABLE) {
|
|
142
|
+
let nodes_left_storage: HuffmanConstructNode[] = new Array<HuffmanConstructNode>(HUFFMAN_MAX_SYMBOLS);
|
|
143
|
+
for (let i = 0; i < HUFFMAN_MAX_SYMBOLS; i++) {
|
|
144
|
+
nodes_left_storage[i] = {} as HuffmanConstructNode;
|
|
145
|
+
}
|
|
146
|
+
let nodes_left: number[] = new Array<number>(HUFFMAN_MAX_SYMBOLS);
|
|
147
|
+
let num_nodes_left = HUFFMAN_MAX_SYMBOLS;
|
|
148
|
+
|
|
149
|
+
for (let i = 0; i < HUFFMAN_MAX_SYMBOLS; i++) {
|
|
150
|
+
this.nodes[i].numbits = 0xFFFFFFFF;
|
|
151
|
+
this.nodes[i].symbol = i;
|
|
152
|
+
this.nodes[i].left = 0xFFFF;
|
|
153
|
+
this.nodes[i].right = 0xFFFF;
|
|
154
|
+
|
|
155
|
+
if (i == HUFFMAN_EOF_SYMBOL) {
|
|
156
|
+
nodes_left_storage[i].frequency = 1;
|
|
157
|
+
} else
|
|
158
|
+
nodes_left_storage[i].frequency = frequencies[i];
|
|
159
|
+
nodes_left_storage[i].node_id = i;
|
|
160
|
+
nodes_left[i] = i;
|
|
161
|
+
}
|
|
162
|
+
this.num_nodes = HUFFMAN_MAX_SYMBOLS;
|
|
163
|
+
|
|
164
|
+
while (num_nodes_left > 1) {
|
|
165
|
+
nodes_left = this.bubble_sort(nodes_left, nodes_left_storage, num_nodes_left);
|
|
166
|
+
|
|
167
|
+
this.nodes[this.num_nodes].numbits = 0;
|
|
168
|
+
this.nodes[this.num_nodes].left = nodes_left_storage[nodes_left[num_nodes_left - 1]].node_id
|
|
169
|
+
this.nodes[this.num_nodes].right = nodes_left_storage[nodes_left[num_nodes_left - 2]].node_id
|
|
170
|
+
|
|
171
|
+
nodes_left_storage[nodes_left[num_nodes_left - 2]].node_id = this.num_nodes;
|
|
172
|
+
nodes_left_storage[nodes_left[num_nodes_left - 2]].frequency = nodes_left_storage[nodes_left[num_nodes_left - 1]].frequency
|
|
173
|
+
+ nodes_left_storage[nodes_left[num_nodes_left - 2]].frequency
|
|
174
|
+
this.num_nodes++;
|
|
175
|
+
num_nodes_left--;
|
|
176
|
+
}
|
|
177
|
+
this.start_node_index = this.num_nodes-1;
|
|
178
|
+
this.set_bits_r(this.start_node_index, 0, 0);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
compress(inp_buffer: Buffer, start_index = 0, size: number = 0): Buffer {
|
|
182
|
+
let output = [];
|
|
183
|
+
let bits = 0;
|
|
184
|
+
let bitcount = 0;
|
|
185
|
+
|
|
186
|
+
if (size == 0)
|
|
187
|
+
size = inp_buffer.byteLength;
|
|
188
|
+
inp_buffer = inp_buffer.slice(start_index, start_index + size);
|
|
189
|
+
for (let i = 0; i < size; i++) {
|
|
190
|
+
let x = inp_buffer[i];
|
|
191
|
+
bits |= this.nodes[x].bits << bitcount;
|
|
192
|
+
bitcount += this.nodes[x].numbits;
|
|
193
|
+
|
|
194
|
+
while (bitcount >= 8) {
|
|
195
|
+
output.push(bits & 0xff);
|
|
196
|
+
bits >>= 8;
|
|
197
|
+
bitcount -= 8;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
bits |= this.nodes[HUFFMAN_EOF_SYMBOL].bits << bitcount;
|
|
201
|
+
bitcount += this.nodes[HUFFMAN_EOF_SYMBOL].numbits;
|
|
202
|
+
|
|
203
|
+
while (bitcount >= 8) {
|
|
204
|
+
output.push(bits & 0xff);
|
|
205
|
+
bits >>= 8;
|
|
206
|
+
bitcount -= 8;
|
|
207
|
+
}
|
|
208
|
+
output.push(bits);
|
|
209
|
+
return Buffer.from(output);
|
|
210
|
+
|
|
211
|
+
/* output = bytearray()
|
|
212
|
+
bits = 0
|
|
213
|
+
bitcount = 0
|
|
214
|
+
|
|
215
|
+
if size is None:
|
|
216
|
+
size = len(inp_buffer)
|
|
217
|
+
|
|
218
|
+
for x in inp_buffer[start_index:size:]:
|
|
219
|
+
bits |= self.nodes[x].bits << bitcount
|
|
220
|
+
bitcount += self.nodes[x].numbits
|
|
221
|
+
|
|
222
|
+
while bitcount >= 8:
|
|
223
|
+
output.append(bits & 0xff)
|
|
224
|
+
bits >>= 8
|
|
225
|
+
bitcount -= 8
|
|
226
|
+
|
|
227
|
+
bits |= self.nodes[HUFFMAN_EOF_SYMBOL].bits << bitcount
|
|
228
|
+
bitcount += self.nodes[HUFFMAN_EOF_SYMBOL].numbits
|
|
229
|
+
|
|
230
|
+
while bitcount >= 8:
|
|
231
|
+
output.append(bits & 0xff)
|
|
232
|
+
bits >>= 8
|
|
233
|
+
bitcount -= 8
|
|
234
|
+
|
|
235
|
+
# write out last bits
|
|
236
|
+
output.append(bits)
|
|
237
|
+
return output
|
|
238
|
+
*/
|
|
239
|
+
}
|
|
240
|
+
decompress(inp_buffer: Buffer, size = 0): Buffer {
|
|
241
|
+
|
|
242
|
+
let bits = 0;
|
|
243
|
+
let bitcount = 0;
|
|
244
|
+
let eof = this.nodes[HUFFMAN_EOF_SYMBOL];
|
|
245
|
+
let output = [];
|
|
246
|
+
|
|
247
|
+
if (size == 0)
|
|
248
|
+
size = inp_buffer.byteLength;
|
|
249
|
+
inp_buffer = inp_buffer.slice(0, size);
|
|
250
|
+
let src_index = 0;
|
|
251
|
+
while (true) {
|
|
252
|
+
let node_i = -1;
|
|
253
|
+
if (bitcount >= HUFFMAN_LUTBITS)
|
|
254
|
+
node_i = this.decode_lut[bits & HUFFMAN_LUTMASK];
|
|
255
|
+
while (bitcount < 24 && src_index != size) {
|
|
256
|
+
bits |= inp_buffer[src_index] << bitcount;
|
|
257
|
+
bitcount += 8;
|
|
258
|
+
src_index++;
|
|
259
|
+
}
|
|
260
|
+
if (node_i == -1)
|
|
261
|
+
node_i = this.decode_lut[bits & HUFFMAN_LUTMASK];
|
|
262
|
+
// console.log(node_i, bits & HUFFMAN_LUTMASK, this.decode_lut)
|
|
263
|
+
if (this.nodes[node_i].numbits) {
|
|
264
|
+
bits >>= this.nodes[node_i].numbits;
|
|
265
|
+
bitcount -= this.nodes[node_i].numbits;
|
|
266
|
+
} else {
|
|
267
|
+
bits >>= HUFFMAN_LUTBITS;
|
|
268
|
+
bitcount -= HUFFMAN_LUTBITS;
|
|
269
|
+
|
|
270
|
+
while (true) {
|
|
271
|
+
if (bits & 1) {
|
|
272
|
+
node_i = this.nodes[node_i].right;
|
|
273
|
+
} else
|
|
274
|
+
node_i = this.nodes[node_i].left;
|
|
275
|
+
bitcount -= 1;
|
|
276
|
+
bits >>= 1;
|
|
277
|
+
|
|
278
|
+
if (this.nodes[node_i].numbits)
|
|
279
|
+
break;
|
|
280
|
+
if (bitcount == 0)
|
|
281
|
+
throw new Error("No more bits, decoding error")
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
}
|
|
285
|
+
if (this.nodes[node_i] == eof)
|
|
286
|
+
break;
|
|
287
|
+
output.push(this.nodes[node_i].symbol);
|
|
288
|
+
}
|
|
289
|
+
return Buffer.from(output);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/*bits = 0
|
|
293
|
+
bitcount = 0
|
|
294
|
+
eof = self.nodes[HUFFMAN_EOF_SYMBOL]
|
|
295
|
+
output = bytearray()
|
|
296
|
+
|
|
297
|
+
if size is None:
|
|
298
|
+
size = len(inp_buffer)
|
|
299
|
+
|
|
300
|
+
src_index = 0
|
|
301
|
+
while True:
|
|
302
|
+
node_i = None
|
|
303
|
+
if bitcount >= HUFFMAN_LUTBITS:
|
|
304
|
+
node_i = self.decode_lut[bits & HUFFMAN_LUTMASK]
|
|
305
|
+
|
|
306
|
+
while bitcount < 24 and src_index != size:
|
|
307
|
+
bits |= inp_buffer[src_index] << bitcount
|
|
308
|
+
src_index += 1
|
|
309
|
+
bitcount += 8
|
|
310
|
+
|
|
311
|
+
if node_i is None:
|
|
312
|
+
node_i = self.decode_lut[bits & HUFFMAN_LUTMASK]
|
|
313
|
+
if self.nodes[node_i].numbits:
|
|
314
|
+
bits >>= self.nodes[node_i].numbits
|
|
315
|
+
bitcount -= self.nodes[node_i].numbits
|
|
316
|
+
else:
|
|
317
|
+
bits >>= HUFFMAN_LUTBITS
|
|
318
|
+
bitcount -= HUFFMAN_LUTBITS
|
|
319
|
+
|
|
320
|
+
while True:
|
|
321
|
+
if bits & 1:
|
|
322
|
+
node_i = self.nodes[node_i].right
|
|
323
|
+
else:
|
|
324
|
+
node_i = self.nodes[node_i].left
|
|
325
|
+
|
|
326
|
+
bitcount -= 1
|
|
327
|
+
bits >>= 1
|
|
328
|
+
|
|
329
|
+
if self.nodes[node_i].numbits:
|
|
330
|
+
break
|
|
331
|
+
|
|
332
|
+
if bitcount === 0:
|
|
333
|
+
raise ValueError("No more bits, decoding error")
|
|
334
|
+
|
|
335
|
+
if self.nodes[node_i] === eof:
|
|
336
|
+
break
|
|
337
|
+
output.append(self.nodes[node_i].symbol)
|
|
338
|
+
|
|
339
|
+
return output */
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export = Huffman;
|