susi-qemu 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/bin/susi +9 -4
  3. data/lib/disk.rb +7 -5
  4. data/lib/novnc/core/base64.js +104 -0
  5. data/lib/novnc/core/crypto/aes.js +178 -0
  6. data/lib/novnc/core/crypto/bigint.js +34 -0
  7. data/lib/novnc/core/crypto/crypto.js +90 -0
  8. data/lib/novnc/core/crypto/des.js +330 -0
  9. data/lib/novnc/core/crypto/dh.js +55 -0
  10. data/lib/novnc/core/crypto/md5.js +82 -0
  11. data/lib/novnc/core/crypto/rsa.js +132 -0
  12. data/lib/novnc/core/decoders/copyrect.js +27 -0
  13. data/lib/novnc/core/decoders/h264.js +321 -0
  14. data/lib/novnc/core/decoders/hextile.js +181 -0
  15. data/lib/novnc/core/decoders/jpeg.js +146 -0
  16. data/lib/novnc/core/decoders/raw.js +59 -0
  17. data/lib/novnc/core/decoders/rre.js +44 -0
  18. data/lib/novnc/core/decoders/tight.js +393 -0
  19. data/lib/novnc/core/decoders/tightpng.js +27 -0
  20. data/lib/novnc/core/decoders/zlib.js +51 -0
  21. data/lib/novnc/core/decoders/zrle.js +185 -0
  22. data/lib/novnc/core/deflator.js +84 -0
  23. data/lib/novnc/core/display.js +575 -0
  24. data/lib/novnc/core/encodings.js +53 -0
  25. data/lib/novnc/core/inflator.js +65 -0
  26. data/lib/novnc/core/input/domkeytable.js +311 -0
  27. data/lib/novnc/core/input/fixedkeys.js +129 -0
  28. data/lib/novnc/core/input/gesturehandler.js +567 -0
  29. data/lib/novnc/core/input/keyboard.js +294 -0
  30. data/lib/novnc/core/input/keysym.js +616 -0
  31. data/lib/novnc/core/input/keysymdef.js +688 -0
  32. data/lib/novnc/core/input/util.js +191 -0
  33. data/lib/novnc/core/input/vkeys.js +116 -0
  34. data/lib/novnc/core/input/xtscancodes.js +173 -0
  35. data/lib/novnc/core/ra2.js +312 -0
  36. data/lib/novnc/core/rfb.js +3257 -0
  37. data/lib/novnc/core/util/browser.js +172 -0
  38. data/lib/novnc/core/util/cursor.js +249 -0
  39. data/lib/novnc/core/util/element.js +32 -0
  40. data/lib/novnc/core/util/events.js +138 -0
  41. data/lib/novnc/core/util/eventtarget.js +35 -0
  42. data/lib/novnc/core/util/int.js +15 -0
  43. data/lib/novnc/core/util/logging.js +56 -0
  44. data/lib/novnc/core/util/strings.js +28 -0
  45. data/lib/novnc/core/websock.js +365 -0
  46. data/lib/novnc/screen.html +21 -0
  47. data/lib/novnc/vendor/pako/lib/utils/common.js +45 -0
  48. data/lib/novnc/vendor/pako/lib/zlib/adler32.js +27 -0
  49. data/lib/novnc/vendor/pako/lib/zlib/constants.js +47 -0
  50. data/lib/novnc/vendor/pako/lib/zlib/crc32.js +36 -0
  51. data/lib/novnc/vendor/pako/lib/zlib/deflate.js +1846 -0
  52. data/lib/novnc/vendor/pako/lib/zlib/gzheader.js +35 -0
  53. data/lib/novnc/vendor/pako/lib/zlib/inffast.js +324 -0
  54. data/lib/novnc/vendor/pako/lib/zlib/inflate.js +1527 -0
  55. data/lib/novnc/vendor/pako/lib/zlib/inftrees.js +322 -0
  56. data/lib/novnc/vendor/pako/lib/zlib/messages.js +11 -0
  57. data/lib/novnc/vendor/pako/lib/zlib/trees.js +1195 -0
  58. data/lib/novnc/vendor/pako/lib/zlib/zstream.js +24 -0
  59. data/lib/output.rb +11 -0
  60. data/lib/qmp.rb +6 -0
  61. data/lib/ssh.rb +3 -1
  62. data/lib/susi.rb +7 -6
  63. data/lib/version.rb +1 -1
  64. data/lib/vm.rb +36 -13
  65. data/lib/vnc.rb +34 -30
  66. metadata +57 -1
@@ -0,0 +1,44 @@
1
+ /*
2
+ * noVNC: HTML5 VNC client
3
+ * Copyright (C) 2019 The noVNC Authors
4
+ * Licensed under MPL 2.0 (see LICENSE.txt)
5
+ *
6
+ * See README.md for usage and integration instructions.
7
+ *
8
+ */
9
+
10
+ export default class RREDecoder {
11
+ constructor() {
12
+ this._subrects = 0;
13
+ }
14
+
15
+ decodeRect(x, y, width, height, sock, display, depth) {
16
+ if (this._subrects === 0) {
17
+ if (sock.rQwait("RRE", 4 + 4)) {
18
+ return false;
19
+ }
20
+
21
+ this._subrects = sock.rQshift32();
22
+
23
+ let color = sock.rQshiftBytes(4); // Background
24
+ display.fillRect(x, y, width, height, color);
25
+ }
26
+
27
+ while (this._subrects > 0) {
28
+ if (sock.rQwait("RRE", 4 + 8)) {
29
+ return false;
30
+ }
31
+
32
+ let color = sock.rQshiftBytes(4);
33
+ let sx = sock.rQshift16();
34
+ let sy = sock.rQshift16();
35
+ let swidth = sock.rQshift16();
36
+ let sheight = sock.rQshift16();
37
+ display.fillRect(x + sx, y + sy, swidth, sheight, color);
38
+
39
+ this._subrects--;
40
+ }
41
+
42
+ return true;
43
+ }
44
+ }
@@ -0,0 +1,393 @@
1
+ /*
2
+ * noVNC: HTML5 VNC client
3
+ * Copyright (C) 2019 The noVNC Authors
4
+ * (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
5
+ * Licensed under MPL 2.0 (see LICENSE.txt)
6
+ *
7
+ * See README.md for usage and integration instructions.
8
+ *
9
+ */
10
+
11
+ import * as Log from '../util/logging.js';
12
+ import Inflator from "../inflator.js";
13
+
14
+ export default class TightDecoder {
15
+ constructor() {
16
+ this._ctl = null;
17
+ this._filter = null;
18
+ this._numColors = 0;
19
+ this._palette = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel)
20
+ this._len = 0;
21
+
22
+ this._zlibs = [];
23
+ for (let i = 0; i < 4; i++) {
24
+ this._zlibs[i] = new Inflator();
25
+ }
26
+ }
27
+
28
+ decodeRect(x, y, width, height, sock, display, depth) {
29
+ if (this._ctl === null) {
30
+ if (sock.rQwait("TIGHT compression-control", 1)) {
31
+ return false;
32
+ }
33
+
34
+ this._ctl = sock.rQshift8();
35
+
36
+ // Reset streams if the server requests it
37
+ for (let i = 0; i < 4; i++) {
38
+ if ((this._ctl >> i) & 1) {
39
+ this._zlibs[i].reset();
40
+ Log.Info("Reset zlib stream " + i);
41
+ }
42
+ }
43
+
44
+ // Figure out filter
45
+ this._ctl = this._ctl >> 4;
46
+ }
47
+
48
+ let ret;
49
+
50
+ if (this._ctl === 0x08) {
51
+ ret = this._fillRect(x, y, width, height,
52
+ sock, display, depth);
53
+ } else if (this._ctl === 0x09) {
54
+ ret = this._jpegRect(x, y, width, height,
55
+ sock, display, depth);
56
+ } else if (this._ctl === 0x0A) {
57
+ ret = this._pngRect(x, y, width, height,
58
+ sock, display, depth);
59
+ } else if ((this._ctl & 0x08) == 0) {
60
+ ret = this._basicRect(this._ctl, x, y, width, height,
61
+ sock, display, depth);
62
+ } else {
63
+ throw new Error("Illegal tight compression received (ctl: " +
64
+ this._ctl + ")");
65
+ }
66
+
67
+ if (ret) {
68
+ this._ctl = null;
69
+ }
70
+
71
+ return ret;
72
+ }
73
+
74
+ _fillRect(x, y, width, height, sock, display, depth) {
75
+ if (sock.rQwait("TIGHT", 3)) {
76
+ return false;
77
+ }
78
+
79
+ let pixel = sock.rQshiftBytes(3);
80
+ display.fillRect(x, y, width, height, pixel, false);
81
+
82
+ return true;
83
+ }
84
+
85
+ _jpegRect(x, y, width, height, sock, display, depth) {
86
+ let data = this._readData(sock);
87
+ if (data === null) {
88
+ return false;
89
+ }
90
+
91
+ display.imageRect(x, y, width, height, "image/jpeg", data);
92
+
93
+ return true;
94
+ }
95
+
96
+ _pngRect(x, y, width, height, sock, display, depth) {
97
+ throw new Error("PNG received in standard Tight rect");
98
+ }
99
+
100
+ _basicRect(ctl, x, y, width, height, sock, display, depth) {
101
+ if (this._filter === null) {
102
+ if (ctl & 0x4) {
103
+ if (sock.rQwait("TIGHT", 1)) {
104
+ return false;
105
+ }
106
+
107
+ this._filter = sock.rQshift8();
108
+ } else {
109
+ // Implicit CopyFilter
110
+ this._filter = 0;
111
+ }
112
+ }
113
+
114
+ let streamId = ctl & 0x3;
115
+
116
+ let ret;
117
+
118
+ switch (this._filter) {
119
+ case 0: // CopyFilter
120
+ ret = this._copyFilter(streamId, x, y, width, height,
121
+ sock, display, depth);
122
+ break;
123
+ case 1: // PaletteFilter
124
+ ret = this._paletteFilter(streamId, x, y, width, height,
125
+ sock, display, depth);
126
+ break;
127
+ case 2: // GradientFilter
128
+ ret = this._gradientFilter(streamId, x, y, width, height,
129
+ sock, display, depth);
130
+ break;
131
+ default:
132
+ throw new Error("Illegal tight filter received (ctl: " +
133
+ this._filter + ")");
134
+ }
135
+
136
+ if (ret) {
137
+ this._filter = null;
138
+ }
139
+
140
+ return ret;
141
+ }
142
+
143
+ _copyFilter(streamId, x, y, width, height, sock, display, depth) {
144
+ const uncompressedSize = width * height * 3;
145
+ let data;
146
+
147
+ if (uncompressedSize === 0) {
148
+ return true;
149
+ }
150
+
151
+ if (uncompressedSize < 12) {
152
+ if (sock.rQwait("TIGHT", uncompressedSize)) {
153
+ return false;
154
+ }
155
+
156
+ data = sock.rQshiftBytes(uncompressedSize);
157
+ } else {
158
+ data = this._readData(sock);
159
+ if (data === null) {
160
+ return false;
161
+ }
162
+
163
+ this._zlibs[streamId].setInput(data);
164
+ data = this._zlibs[streamId].inflate(uncompressedSize);
165
+ this._zlibs[streamId].setInput(null);
166
+ }
167
+
168
+ let rgbx = new Uint8Array(width * height * 4);
169
+ for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) {
170
+ rgbx[i] = data[j];
171
+ rgbx[i + 1] = data[j + 1];
172
+ rgbx[i + 2] = data[j + 2];
173
+ rgbx[i + 3] = 255; // Alpha
174
+ }
175
+
176
+ display.blitImage(x, y, width, height, rgbx, 0, false);
177
+
178
+ return true;
179
+ }
180
+
181
+ _paletteFilter(streamId, x, y, width, height, sock, display, depth) {
182
+ if (this._numColors === 0) {
183
+ if (sock.rQwait("TIGHT palette", 1)) {
184
+ return false;
185
+ }
186
+
187
+ const numColors = sock.rQpeek8() + 1;
188
+ const paletteSize = numColors * 3;
189
+
190
+ if (sock.rQwait("TIGHT palette", 1 + paletteSize)) {
191
+ return false;
192
+ }
193
+
194
+ this._numColors = numColors;
195
+ sock.rQskipBytes(1);
196
+
197
+ sock.rQshiftTo(this._palette, paletteSize);
198
+ }
199
+
200
+ const bpp = (this._numColors <= 2) ? 1 : 8;
201
+ const rowSize = Math.floor((width * bpp + 7) / 8);
202
+ const uncompressedSize = rowSize * height;
203
+
204
+ let data;
205
+
206
+ if (uncompressedSize === 0) {
207
+ return true;
208
+ }
209
+
210
+ if (uncompressedSize < 12) {
211
+ if (sock.rQwait("TIGHT", uncompressedSize)) {
212
+ return false;
213
+ }
214
+
215
+ data = sock.rQshiftBytes(uncompressedSize);
216
+ } else {
217
+ data = this._readData(sock);
218
+ if (data === null) {
219
+ return false;
220
+ }
221
+
222
+ this._zlibs[streamId].setInput(data);
223
+ data = this._zlibs[streamId].inflate(uncompressedSize);
224
+ this._zlibs[streamId].setInput(null);
225
+ }
226
+
227
+ // Convert indexed (palette based) image data to RGB
228
+ if (this._numColors == 2) {
229
+ this._monoRect(x, y, width, height, data, this._palette, display);
230
+ } else {
231
+ this._paletteRect(x, y, width, height, data, this._palette, display);
232
+ }
233
+
234
+ this._numColors = 0;
235
+
236
+ return true;
237
+ }
238
+
239
+ _monoRect(x, y, width, height, data, palette, display) {
240
+ // Convert indexed (palette based) image data to RGB
241
+ // TODO: reduce number of calculations inside loop
242
+ const dest = this._getScratchBuffer(width * height * 4);
243
+ const w = Math.floor((width + 7) / 8);
244
+ const w1 = Math.floor(width / 8);
245
+
246
+ for (let y = 0; y < height; y++) {
247
+ let dp, sp, x;
248
+ for (x = 0; x < w1; x++) {
249
+ for (let b = 7; b >= 0; b--) {
250
+ dp = (y * width + x * 8 + 7 - b) * 4;
251
+ sp = (data[y * w + x] >> b & 1) * 3;
252
+ dest[dp] = palette[sp];
253
+ dest[dp + 1] = palette[sp + 1];
254
+ dest[dp + 2] = palette[sp + 2];
255
+ dest[dp + 3] = 255;
256
+ }
257
+ }
258
+
259
+ for (let b = 7; b >= 8 - width % 8; b--) {
260
+ dp = (y * width + x * 8 + 7 - b) * 4;
261
+ sp = (data[y * w + x] >> b & 1) * 3;
262
+ dest[dp] = palette[sp];
263
+ dest[dp + 1] = palette[sp + 1];
264
+ dest[dp + 2] = palette[sp + 2];
265
+ dest[dp + 3] = 255;
266
+ }
267
+ }
268
+
269
+ display.blitImage(x, y, width, height, dest, 0, false);
270
+ }
271
+
272
+ _paletteRect(x, y, width, height, data, palette, display) {
273
+ // Convert indexed (palette based) image data to RGB
274
+ const dest = this._getScratchBuffer(width * height * 4);
275
+ const total = width * height * 4;
276
+ for (let i = 0, j = 0; i < total; i += 4, j++) {
277
+ const sp = data[j] * 3;
278
+ dest[i] = palette[sp];
279
+ dest[i + 1] = palette[sp + 1];
280
+ dest[i + 2] = palette[sp + 2];
281
+ dest[i + 3] = 255;
282
+ }
283
+
284
+ display.blitImage(x, y, width, height, dest, 0, false);
285
+ }
286
+
287
+ _gradientFilter(streamId, x, y, width, height, sock, display, depth) {
288
+ // assume the TPIXEL is 3 bytes long
289
+ const uncompressedSize = width * height * 3;
290
+ let data;
291
+
292
+ if (uncompressedSize === 0) {
293
+ return true;
294
+ }
295
+
296
+ if (uncompressedSize < 12) {
297
+ if (sock.rQwait("TIGHT", uncompressedSize)) {
298
+ return false;
299
+ }
300
+
301
+ data = sock.rQshiftBytes(uncompressedSize);
302
+ } else {
303
+ data = this._readData(sock);
304
+ if (data === null) {
305
+ return false;
306
+ }
307
+
308
+ this._zlibs[streamId].setInput(data);
309
+ data = this._zlibs[streamId].inflate(uncompressedSize);
310
+ this._zlibs[streamId].setInput(null);
311
+ }
312
+
313
+ let rgbx = new Uint8Array(4 * width * height);
314
+
315
+ let rgbxIndex = 0, dataIndex = 0;
316
+ let left = new Uint8Array(3);
317
+ for (let x = 0; x < width; x++) {
318
+ for (let c = 0; c < 3; c++) {
319
+ const prediction = left[c];
320
+ const value = data[dataIndex++] + prediction;
321
+ rgbx[rgbxIndex++] = value;
322
+ left[c] = value;
323
+ }
324
+ rgbx[rgbxIndex++] = 255;
325
+ }
326
+
327
+ let upperIndex = 0;
328
+ let upper = new Uint8Array(3),
329
+ upperleft = new Uint8Array(3);
330
+ for (let y = 1; y < height; y++) {
331
+ left.fill(0);
332
+ upperleft.fill(0);
333
+ for (let x = 0; x < width; x++) {
334
+ for (let c = 0; c < 3; c++) {
335
+ upper[c] = rgbx[upperIndex++];
336
+ let prediction = left[c] + upper[c] - upperleft[c];
337
+ if (prediction < 0) {
338
+ prediction = 0;
339
+ } else if (prediction > 255) {
340
+ prediction = 255;
341
+ }
342
+ const value = data[dataIndex++] + prediction;
343
+ rgbx[rgbxIndex++] = value;
344
+ upperleft[c] = upper[c];
345
+ left[c] = value;
346
+ }
347
+ rgbx[rgbxIndex++] = 255;
348
+ upperIndex++;
349
+ }
350
+ }
351
+
352
+ display.blitImage(x, y, width, height, rgbx, 0, false);
353
+
354
+ return true;
355
+ }
356
+
357
+ _readData(sock) {
358
+ if (this._len === 0) {
359
+ if (sock.rQwait("TIGHT", 3)) {
360
+ return null;
361
+ }
362
+
363
+ let byte;
364
+
365
+ byte = sock.rQshift8();
366
+ this._len = byte & 0x7f;
367
+ if (byte & 0x80) {
368
+ byte = sock.rQshift8();
369
+ this._len |= (byte & 0x7f) << 7;
370
+ if (byte & 0x80) {
371
+ byte = sock.rQshift8();
372
+ this._len |= byte << 14;
373
+ }
374
+ }
375
+ }
376
+
377
+ if (sock.rQwait("TIGHT", this._len)) {
378
+ return null;
379
+ }
380
+
381
+ let data = sock.rQshiftBytes(this._len, false);
382
+ this._len = 0;
383
+
384
+ return data;
385
+ }
386
+
387
+ _getScratchBuffer(size) {
388
+ if (!this._scratchBuffer || (this._scratchBuffer.length < size)) {
389
+ this._scratchBuffer = new Uint8Array(size);
390
+ }
391
+ return this._scratchBuffer;
392
+ }
393
+ }
@@ -0,0 +1,27 @@
1
+ /*
2
+ * noVNC: HTML5 VNC client
3
+ * Copyright (C) 2019 The noVNC Authors
4
+ * Licensed under MPL 2.0 (see LICENSE.txt)
5
+ *
6
+ * See README.md for usage and integration instructions.
7
+ *
8
+ */
9
+
10
+ import TightDecoder from './tight.js';
11
+
12
+ export default class TightPNGDecoder extends TightDecoder {
13
+ _pngRect(x, y, width, height, sock, display, depth) {
14
+ let data = this._readData(sock);
15
+ if (data === null) {
16
+ return false;
17
+ }
18
+
19
+ display.imageRect(x, y, width, height, "image/png", data);
20
+
21
+ return true;
22
+ }
23
+
24
+ _basicRect(ctl, x, y, width, height, sock, display, depth) {
25
+ throw new Error("BasicCompression received in TightPNG rect");
26
+ }
27
+ }
@@ -0,0 +1,51 @@
1
+ /*
2
+ * noVNC: HTML5 VNC client
3
+ * Copyright (C) 2024 The noVNC Authors
4
+ * Licensed under MPL 2.0 (see LICENSE.txt)
5
+ *
6
+ * See README.md for usage and integration instructions.
7
+ *
8
+ */
9
+
10
+ import Inflator from "../inflator.js";
11
+
12
+ export default class ZlibDecoder {
13
+ constructor() {
14
+ this._zlib = new Inflator();
15
+ this._length = 0;
16
+ }
17
+
18
+ decodeRect(x, y, width, height, sock, display, depth) {
19
+ if ((width === 0) || (height === 0)) {
20
+ return true;
21
+ }
22
+
23
+ if (this._length === 0) {
24
+ if (sock.rQwait("ZLIB", 4)) {
25
+ return false;
26
+ }
27
+
28
+ this._length = sock.rQshift32();
29
+ }
30
+
31
+ if (sock.rQwait("ZLIB", this._length)) {
32
+ return false;
33
+ }
34
+
35
+ let data = new Uint8Array(sock.rQshiftBytes(this._length, false));
36
+ this._length = 0;
37
+
38
+ this._zlib.setInput(data);
39
+ data = this._zlib.inflate(width * height * 4);
40
+ this._zlib.setInput(null);
41
+
42
+ // Max sure the image is fully opaque
43
+ for (let i = 0; i < width * height; i++) {
44
+ data[i * 4 + 3] = 255;
45
+ }
46
+
47
+ display.blitImage(x, y, width, height, data, 0);
48
+
49
+ return true;
50
+ }
51
+ }
@@ -0,0 +1,185 @@
1
+ /*
2
+ * noVNC: HTML5 VNC client
3
+ * Copyright (C) 2021 The noVNC Authors
4
+ * Licensed under MPL 2.0 (see LICENSE.txt)
5
+ *
6
+ * See README.md for usage and integration instructions.
7
+ *
8
+ */
9
+
10
+ import Inflate from "../inflator.js";
11
+
12
+ const ZRLE_TILE_WIDTH = 64;
13
+ const ZRLE_TILE_HEIGHT = 64;
14
+
15
+ export default class ZRLEDecoder {
16
+ constructor() {
17
+ this._length = 0;
18
+ this._inflator = new Inflate();
19
+
20
+ this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
21
+ this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
22
+ }
23
+
24
+ decodeRect(x, y, width, height, sock, display, depth) {
25
+ if (this._length === 0) {
26
+ if (sock.rQwait("ZLib data length", 4)) {
27
+ return false;
28
+ }
29
+ this._length = sock.rQshift32();
30
+ }
31
+ if (sock.rQwait("Zlib data", this._length)) {
32
+ return false;
33
+ }
34
+
35
+ const data = sock.rQshiftBytes(this._length, false);
36
+
37
+ this._inflator.setInput(data);
38
+
39
+ for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) {
40
+ let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty);
41
+
42
+ for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) {
43
+ let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx);
44
+
45
+ const tileSize = tw * th;
46
+ const subencoding = this._inflator.inflate(1)[0];
47
+ if (subencoding === 0) {
48
+ // raw data
49
+ const data = this._readPixels(tileSize);
50
+ display.blitImage(tx, ty, tw, th, data, 0, false);
51
+ } else if (subencoding === 1) {
52
+ // solid
53
+ const background = this._readPixels(1);
54
+ display.fillRect(tx, ty, tw, th, [background[0], background[1], background[2]]);
55
+ } else if (subencoding >= 2 && subencoding <= 16) {
56
+ const data = this._decodePaletteTile(subencoding, tileSize, tw, th);
57
+ display.blitImage(tx, ty, tw, th, data, 0, false);
58
+ } else if (subencoding === 128) {
59
+ const data = this._decodeRLETile(tileSize);
60
+ display.blitImage(tx, ty, tw, th, data, 0, false);
61
+ } else if (subencoding >= 130 && subencoding <= 255) {
62
+ const data = this._decodeRLEPaletteTile(subencoding - 128, tileSize);
63
+ display.blitImage(tx, ty, tw, th, data, 0, false);
64
+ } else {
65
+ throw new Error('Unknown subencoding: ' + subencoding);
66
+ }
67
+ }
68
+ }
69
+ this._length = 0;
70
+ return true;
71
+ }
72
+
73
+ _getBitsPerPixelInPalette(paletteSize) {
74
+ if (paletteSize <= 2) {
75
+ return 1;
76
+ } else if (paletteSize <= 4) {
77
+ return 2;
78
+ } else if (paletteSize <= 16) {
79
+ return 4;
80
+ }
81
+ }
82
+
83
+ _readPixels(pixels) {
84
+ let data = this._pixelBuffer;
85
+ const buffer = this._inflator.inflate(3*pixels);
86
+ for (let i = 0, j = 0; i < pixels*4; i += 4, j += 3) {
87
+ data[i] = buffer[j];
88
+ data[i + 1] = buffer[j + 1];
89
+ data[i + 2] = buffer[j + 2];
90
+ data[i + 3] = 255; // Add the Alpha
91
+ }
92
+ return data;
93
+ }
94
+
95
+ _decodePaletteTile(paletteSize, tileSize, tilew, tileh) {
96
+ const data = this._tileBuffer;
97
+ const palette = this._readPixels(paletteSize);
98
+ const bitsPerPixel = this._getBitsPerPixelInPalette(paletteSize);
99
+ const mask = (1 << bitsPerPixel) - 1;
100
+
101
+ let offset = 0;
102
+ let encoded = this._inflator.inflate(1)[0];
103
+
104
+ for (let y=0; y<tileh; y++) {
105
+ let shift = 8-bitsPerPixel;
106
+ for (let x=0; x<tilew; x++) {
107
+ if (shift<0) {
108
+ shift=8-bitsPerPixel;
109
+ encoded = this._inflator.inflate(1)[0];
110
+ }
111
+ let indexInPalette = (encoded>>shift) & mask;
112
+
113
+ data[offset] = palette[indexInPalette * 4];
114
+ data[offset + 1] = palette[indexInPalette * 4 + 1];
115
+ data[offset + 2] = palette[indexInPalette * 4 + 2];
116
+ data[offset + 3] = palette[indexInPalette * 4 + 3];
117
+ offset += 4;
118
+ shift-=bitsPerPixel;
119
+ }
120
+ if (shift<8-bitsPerPixel && y<tileh-1) {
121
+ encoded = this._inflator.inflate(1)[0];
122
+ }
123
+ }
124
+ return data;
125
+ }
126
+
127
+ _decodeRLETile(tileSize) {
128
+ const data = this._tileBuffer;
129
+ let i = 0;
130
+ while (i < tileSize) {
131
+ const pixel = this._readPixels(1);
132
+ const length = this._readRLELength();
133
+ for (let j = 0; j < length; j++) {
134
+ data[i * 4] = pixel[0];
135
+ data[i * 4 + 1] = pixel[1];
136
+ data[i * 4 + 2] = pixel[2];
137
+ data[i * 4 + 3] = pixel[3];
138
+ i++;
139
+ }
140
+ }
141
+ return data;
142
+ }
143
+
144
+ _decodeRLEPaletteTile(paletteSize, tileSize) {
145
+ const data = this._tileBuffer;
146
+
147
+ // palette
148
+ const palette = this._readPixels(paletteSize);
149
+
150
+ let offset = 0;
151
+ while (offset < tileSize) {
152
+ let indexInPalette = this._inflator.inflate(1)[0];
153
+ let length = 1;
154
+ if (indexInPalette >= 128) {
155
+ indexInPalette -= 128;
156
+ length = this._readRLELength();
157
+ }
158
+ if (indexInPalette > paletteSize) {
159
+ throw new Error('Too big index in palette: ' + indexInPalette + ', palette size: ' + paletteSize);
160
+ }
161
+ if (offset + length > tileSize) {
162
+ throw new Error('Too big rle length in palette mode: ' + length + ', allowed length is: ' + (tileSize - offset));
163
+ }
164
+
165
+ for (let j = 0; j < length; j++) {
166
+ data[offset * 4] = palette[indexInPalette * 4];
167
+ data[offset * 4 + 1] = palette[indexInPalette * 4 + 1];
168
+ data[offset * 4 + 2] = palette[indexInPalette * 4 + 2];
169
+ data[offset * 4 + 3] = palette[indexInPalette * 4 + 3];
170
+ offset++;
171
+ }
172
+ }
173
+ return data;
174
+ }
175
+
176
+ _readRLELength() {
177
+ let length = 0;
178
+ let current = 0;
179
+ do {
180
+ current = this._inflator.inflate(1)[0];
181
+ length += current;
182
+ } while (current === 255);
183
+ return length + 1;
184
+ }
185
+ }