JavaScript 65.5%
Python 17.8%
CSS 13%
HTML 3.7%
1/*2 * noVNC: HTML5 VNC client3 * Copyright (C) 2021 The noVNC authors4 * Licensed under MPL 2.0 (see LICENSE.txt)5 *6 * See README.md for usage and integration instructions.7 *8 */910import Inflate from "../inflator.js";1112const ZRLE_TILE_WIDTH = 64;13const ZRLE_TILE_HEIGHT = 64;1415export default class ZRLEDecoder {16 constructor() {17 this._length = 0;18 this._inflator = new Inflate();1920 this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);21 this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);22 }2324 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 }3435 const data = sock.rQshiftBytes(this._length, false);3637 this._inflator.setInput(data);3839 for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) {40 let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty);4142 for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) {43 let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx);4445 const tileSize = tw * th;46 const subencoding = this._inflator.inflate(1)[0];47 if (subencoding === 0) {48 // raw data49 const data = this._readPixels(tileSize);50 display.blitImage(tx, ty, tw, th, data, 0, false);51 } else if (subencoding === 1) {52 // solid53 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 }7273 _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 }8283 _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 Alpha91 }92 return data;93 }9495 _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;100101 let offset = 0;102 let encoded = this._inflator.inflate(1)[0];103104 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;112113 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 }126127 _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 }143144 _decodeRLEPaletteTile(paletteSize, tileSize) {145 const data = this._tileBuffer;146147 // palette148 const palette = this._readPixels(paletteSize);149150 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 }164165 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 }175176 _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}186