Initial Commit

This commit is contained in:
Manan006
2024-01-31 17:57:16 +05:30
commit 734726fc12
687 changed files with 189411 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
*/
export default class CopyRectDecoder {
decodeRect(x, y, width, height, sock, display, depth, frame_id) {
if (sock.rQwait("COPYRECT", 4)) {
return false;
}
let deltaX = sock.rQshift16();
let deltaY = sock.rQshift16();
if ((width === 0) || (height === 0)) {
return true;
}
display.copyImage(deltaX, deltaY, x, y, width, height, frame_id);
return true;
}
}
+191
View File
@@ -0,0 +1,191 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
*/
import * as Log from '../util/logging.js';
export default class HextileDecoder {
constructor() {
this._tiles = 0;
this._lastsubencoding = 0;
this._tileBuffer = new Uint8Array(16 * 16 * 4);
}
decodeRect(x, y, width, height, sock, display, depth, frame_id) {
if (this._tiles === 0) {
this._tilesX = Math.ceil(width / 16);
this._tilesY = Math.ceil(height / 16);
this._totalTiles = this._tilesX * this._tilesY;
this._tiles = this._totalTiles;
}
while (this._tiles > 0) {
let bytes = 1;
if (sock.rQwait("HEXTILE", bytes)) {
return false;
}
let rQ = sock.rQ;
let rQi = sock.rQi;
let subencoding = rQ[rQi]; // Peek
if (subencoding > 30) { // Raw
throw new Error("Illegal hextile subencoding (subencoding: " +
subencoding + ")");
}
const currTile = this._totalTiles - this._tiles;
const tileX = currTile % this._tilesX;
const tileY = Math.floor(currTile / this._tilesX);
const tx = x + tileX * 16;
const ty = y + tileY * 16;
const tw = Math.min(16, (x + width) - tx);
const th = Math.min(16, (y + height) - ty);
// Figure out how much we are expecting
if (subencoding & 0x01) { // Raw
bytes += tw * th * 4;
} else {
if (subencoding & 0x02) { // Background
bytes += 4;
}
if (subencoding & 0x04) { // Foreground
bytes += 4;
}
if (subencoding & 0x08) { // AnySubrects
bytes++; // Since we aren't shifting it off
if (sock.rQwait("HEXTILE", bytes)) {
return false;
}
let subrects = rQ[rQi + bytes - 1]; // Peek
if (subencoding & 0x10) { // SubrectsColoured
bytes += subrects * (4 + 2);
} else {
bytes += subrects * 2;
}
}
}
if (sock.rQwait("HEXTILE", bytes)) {
return false;
}
// We know the encoding and have a whole tile
rQi++;
if (subencoding === 0) {
if (this._lastsubencoding & 0x01) {
// Weird: ignore blanks are RAW
Log.Debug(" Ignoring blank after RAW");
} else {
display.fillRect(tx, ty, tw, th, this._background, frame_id);
}
} else if (subencoding & 0x01) { // Raw
let pixels = tw * th;
// Max sure the image is fully opaque
for (let i = 0;i < pixels;i++) {
rQ[rQi + i * 4 + 3] = 255;
}
display.blitImage(tx, ty, tw, th, rQ, rQi, frame_id);
rQi += bytes - 1;
} else {
if (subencoding & 0x02) { // Background
this._background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
rQi += 4;
}
if (subencoding & 0x04) { // Foreground
this._foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
rQi += 4;
}
this._startTile(tx, ty, tw, th, this._background);
if (subencoding & 0x08) { // AnySubrects
let subrects = rQ[rQi];
rQi++;
for (let s = 0; s < subrects; s++) {
let color;
if (subencoding & 0x10) { // SubrectsColoured
color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
rQi += 4;
} else {
color = this._foreground;
}
const xy = rQ[rQi];
rQi++;
const sx = (xy >> 4);
const sy = (xy & 0x0f);
const wh = rQ[rQi];
rQi++;
const sw = (wh >> 4) + 1;
const sh = (wh & 0x0f) + 1;
this._subTile(sx, sy, sw, sh, color);
}
}
this._finishTile(display, frame_id);
}
sock.rQi = rQi;
this._lastsubencoding = subencoding;
this._tiles--;
}
return true;
}
// start updating a tile
_startTile(x, y, width, height, color) {
this._tileX = x;
this._tileY = y;
this._tileW = width;
this._tileH = height;
const red = color[0];
const green = color[1];
const blue = color[2];
const data = this._tileBuffer;
for (let i = 0; i < width * height * 4; i += 4) {
data[i] = red;
data[i + 1] = green;
data[i + 2] = blue;
data[i + 3] = 255;
}
}
// update sub-rectangle of the current tile
_subTile(x, y, w, h, color) {
const red = color[0];
const green = color[1];
const blue = color[2];
const xend = x + w;
const yend = y + h;
const data = this._tileBuffer;
const width = this._tileW;
for (let j = y; j < yend; j++) {
for (let i = x; i < xend; i++) {
const p = (i + (j * width)) * 4;
data[p] = red;
data[p + 1] = green;
data[p + 2] = blue;
data[p + 3] = 255;
}
}
}
// draw the current tile to the screen
_finishTile(display, frame_id) {
display.blitImage(this._tileX, this._tileY,
this._tileW, this._tileH,
this._tileBuffer, 0, frame_id);
}
}
+345
View File
@@ -0,0 +1,345 @@
let wasm;
const heap = new Array(32).fill(undefined);
heap.push(undefined, null, true, false);
function getObject(idx) {
return heap[idx];
}
let heap_next = heap.length;
function dropObject(idx) {
if (idx < 36) return;
heap[idx] = heap_next;
heap_next = idx;
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
const cachedTextDecoder = new TextDecoder('utf-8', {
ignoreBOM: true,
fatal: true
});
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory0;
}
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
let cachegetInt32Memory0 = null;
function getInt32Memory0() {
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachegetInt32Memory0;
}
function getArrayU8FromWasm0(ptr, len) {
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
}
let WASM_VECTOR_LEN = 0;
function passArray8ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 1);
getUint8Memory0().set(arg, ptr / 1);
WASM_VECTOR_LEN = arg.length;
return ptr;
}
/**
* @param {Uint8Array} bytes
* @returns {ImageData}
*/
function decode_qoi(bytes) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
wasm.decode_qoi(retptr, ptr0, len0);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
const cachedTextEncoder = new TextEncoder('utf-8');
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' ?
function(arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
} :
function(arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
});
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length);
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len);
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3);
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
let cachegetUint8ClampedMemory0 = null;
function getUint8ClampedMemory0() {
if (cachegetUint8ClampedMemory0 === null || cachegetUint8ClampedMemory0.buffer !== wasm.memory.buffer) {
cachegetUint8ClampedMemory0 = new Uint8ClampedArray(wasm.memory.buffer);
}
return cachegetUint8ClampedMemory0;
}
function getClampedArrayU8FromWasm0(ptr, len) {
return getUint8ClampedMemory0().subarray(ptr / 1, ptr / 1 + len);
}
function handleError(f, args) {
try {
return f.apply(this, args);
} catch (e) {
wasm.__wbindgen_exn_store(addHeapObject(e));
}
}
/**
*/
class QoiImage {
static __wrap(ptr) {
const obj = Object.create(QoiImage.prototype);
obj.ptr = ptr;
return obj;
}
__destroy_into_raw() {
const ptr = this.ptr;
this.ptr = 0;
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_qoiimage_free(ptr);
}
/**
*/
constructor() {
const ret = wasm.qoiimage_new();
return QoiImage.__wrap(ret);
}
/**
* @returns {number}
*/
get_width() {
const ret = wasm.qoiimage_get_width(this.ptr);
return ret >>> 0;
}
/**
* @returns {number}
*/
get_height() {
const ret = wasm.qoiimage_get_height(this.ptr);
return ret >>> 0;
}
/**
* @returns {number}
*/
get_channels() {
const ret = wasm.qoiimage_get_channels(this.ptr);
return ret;
}
/**
* @returns {Uint8Array}
*/
get_bytes() {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.qoiimage_get_bytes(retptr, this.ptr);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var v0 = getArrayU8FromWasm0(r0, r1).slice();
wasm.__wbindgen_free(r0, r1 * 1);
return v0;
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return {
instance,
module
};
} else {
return instance;
}
}
}
async function init(input) {
if (typeof input === 'undefined') {
input = path + 'core/decoders/qoi/qoi_viewer_bg.wasm';
}
const imports = {};
imports.wbg = {};
imports.wbg.__wbg_new_693216e109162396 = function() {
const ret = new Error();
return addHeapObject(ret);
};
imports.wbg.__wbg_stack_0ddaca5d1abfb52f = function(arg0, arg1) {
const ret = getObject(arg1).stack;
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_error_09919627ac0992f5 = function(arg0, arg1) {
try {
console.error(getStringFromWasm0(arg0, arg1));
} finally {
wasm.__wbindgen_free(arg0, arg1);
}
};
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
imports.wbg.__wbg_newwithu8clampedarrayandsh_87d2f0a48030f922 = function() {
return handleError(function(arg0, arg1, arg2, arg3) {
const ret = new ImageData(getClampedArrayU8FromWasm0(arg0, arg1), arg2 >>> 0, arg3 >>> 0);
return addHeapObject(ret);
}, arguments)
};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
input = fetch(input);
}
const {
instance,
module
} = await load(await input, imports);
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
return wasm;
}
var arr;
var path;
async function run() {
self.addEventListener('message', async function(evt) {
if (evt.data.path) {
path = evt.data.path;
await init();
//Send message that worker is ready
self.postMessage({
result: 1
})
} else {
try {
let length = evt.data.length;
let data = new Uint8Array(evt.data.sab.slice(0, length));
let resultData = decode_qoi(data);
if (!arr) {
arr = new Uint8Array(evt.data.sabR);
}
let lengthR = resultData.data.length;
arr.set(resultData.data);
let img = {
colorSpace: resultData.colorSpace,
width: resultData.width,
height: resultData.height
};
self.postMessage({
result: 0,
img: img,
length: lengthR,
width: evt.data.width,
height: evt.data.height,
x: evt.data.x,
y: evt.data.y,
frame_id: evt.data.frame_id
});
} catch (err) {
self.postMessage({
result: 2,
error: err
});
}
}
}, false);
}
run();
Binary file not shown.
+66
View File
@@ -0,0 +1,66 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
*/
export default class RawDecoder {
constructor() {
this._lines = 0;
}
decodeRect(x, y, width, height, sock, display, depth, frame_id) {
if ((width === 0) || (height === 0)) {
return true;
}
if (this._lines === 0) {
this._lines = height;
}
const pixelSize = depth == 8 ? 1 : 4;
const bytesPerLine = width * pixelSize;
if (sock.rQwait("RAW", bytesPerLine)) {
return false;
}
const curY = y + (height - this._lines);
const currHeight = Math.min(this._lines,
Math.floor(sock.rQlen / bytesPerLine));
const pixels = width * currHeight;
let data = sock.rQ;
let index = sock.rQi;
// Convert data if needed
if (depth == 8) {
const newdata = new Uint8Array(pixels * 4);
for (let i = 0; i < pixels; i++) {
newdata[i * 4 + 0] = ((data[index + i] >> 0) & 0x3) * 255 / 3;
newdata[i * 4 + 1] = ((data[index + i] >> 2) & 0x3) * 255 / 3;
newdata[i * 4 + 2] = ((data[index + i] >> 4) & 0x3) * 255 / 3;
newdata[i * 4 + 3] = 255;
}
data = newdata;
index = 0;
}
// Max sure the image is fully opaque
for (let i = 0; i < pixels; i++) {
data[i * 4 + 3] = 255;
}
display.blitImage(x, curY, width, currHeight, data, index, frame_id);
sock.rQskipBytes(currHeight * bytesPerLine);
this._lines -= currHeight;
if (this._lines > 0) {
return false;
}
return true;
}
}
+44
View File
@@ -0,0 +1,44 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
*/
export default class RREDecoder {
constructor() {
this._subrects = 0;
}
decodeRect(x, y, width, height, sock, display, depth, frame_id) {
if (this._subrects === 0) {
if (sock.rQwait("RRE", 4 + 4)) {
return false;
}
this._subrects = sock.rQshift32();
let color = sock.rQshiftBytes(4); // Background
display.fillRect(x, y, width, height, color);
}
while (this._subrects > 0) {
if (sock.rQwait("RRE", 4 + 8)) {
return false;
}
let color = sock.rQshiftBytes(4);
let sx = sock.rQshift16();
let sy = sock.rQshift16();
let swidth = sock.rQshift16();
let sheight = sock.rQshift16();
display.fillRect(x + sx, y + sy, swidth, sheight, color, frame_id);
this._subrects--;
}
return true;
}
}
+540
View File
@@ -0,0 +1,540 @@
/*
* KasmVNC: HTML5 VNC client
* Copyright (C) 2020 Kasm Technologies
* Copyright (C) 2019 The noVNC Authors
* (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
*/
import * as Log from '../util/logging.js';
import Inflator from "../inflator.js";
export default class TightDecoder {
constructor(display) {
this._ctl = null;
this._filter = null;
this._numColors = 0;
this._palette = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel)
this._len = 0;
this._enableQOI = false;
this._displayGlobal = display;
this._zlibs = [];
for (let i = 0; i < 4; i++) {
this._zlibs[i] = new Inflator();
}
this._itzlib = new Inflator();
}
// ===== PROPERTIES =====
get enableQOI() { return this._enableQOI; }
set enableQOI(enabled) {
if(this._enableQOI === enabled) {
return;
}
if (enabled) {
this._enableQOI = this._enableQOIWorkers();
} else {
this._enableQOI = false;
this._disableQOIWorkers();
}
}
// ===== Public Methods =====
decodeRect(x, y, width, height, sock, display, depth, frame_id) {
if (this._ctl === null) {
if (sock.rQwait("TIGHT compression-control", 1)) {
return false;
}
this._ctl = sock.rQshift8();
// Reset streams if the server requests it
for (let i = 0; i < 4; i++) {
if ((this._ctl >> i) & 1) {
this._zlibs[i].reset();
Log.Info("Reset zlib stream " + i);
}
}
// Figure out filter
this._ctl = this._ctl >> 4;
}
let ret;
if (this._ctl === 0x08) {
ret = this._fillRect(x, y, width, height,
sock, display, depth, frame_id);
} else if (this._ctl === 0x09) {
ret = this._jpegRect(x, y, width, height,
sock, display, depth, frame_id);
} else if (this._ctl === 0x0A) {
ret = this._pngRect(x, y, width, height,
sock, display, depth, frame_id);
} else if ((this._ctl & 0x08) == 0) {
ret = this._basicRect(this._ctl, x, y, width, height,
sock, display, depth, frame_id);
} else if (this._ctl === 0x0B) {
ret = this._webpRect(x, y, width, height,
sock, display, depth, frame_id);
} else if (this._ctl === 0x0C) {
ret = this._qoiRect(x, y, width, height,
sock, display, depth, frame_id);
} else if (this._ctl === 0x0D) {
ret = this._itRect(x, y, width, height,
sock, display, depth, frame_id);
} else {
throw new Error("Illegal tight compression received (ctl: " +
this._ctl + ")");
}
if (ret) {
this._ctl = null;
}
return ret;
}
// ===== Private Methods =====
_fillRect(x, y, width, height, sock, display, depth, frame_id) {
if (sock.rQwait("TIGHT", 3)) {
return false;
}
const rQi = sock.rQi;
const rQ = sock.rQ;
display.fillRect(x, y, width, height,
[rQ[rQi], rQ[rQi + 1], rQ[rQi + 2]], frame_id, false);
sock.rQskipBytes(3);
return true;
}
_jpegRect(x, y, width, height, sock, display, depth, frame_id) {
let data = this._readData(sock);
if (data === null) {
return false;
}
display.imageRect(x, y, width, height, "image/jpeg", data, frame_id);
return true;
}
_webpRect(x, y, width, height, sock, display, depth, frame_id) {
let data = this._readData(sock);
if (data === null) {
return false;
}
display.imageRect(x, y, width, height, "image/webp", data, frame_id);
return true;
}
_processRectQ() {
while (this._availableWorkers.length > 0 && this._qoiRects.length > 0) {
let i = this._availableWorkers.pop();
let worker = this._workers[i];
let rect = this._qoiRects.shift();
this._arrs[i].set(rect.data);
worker.postMessage({
length: rect.data.length,
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
depth: rect.depth,
sab: this._sabs[i],
sabR: this._sabsR[i],
frame_id: rect.frame_id
});
}
}
_qoiRect(x, y, width, height, sock, display, depth, frame_id) {
let data = this._readData(sock);
if (data === null) {
return false;
}
if (this._enableQOI) {
let dataClone = new Uint8Array(data);
let item = {x: x,y: y,width: width,height: height,data: dataClone,depth: depth, frame_id: frame_id};
if (this._qoiRects.length < 1000) {
this._qoiRects.push(item);
this._processRectQ();
} else {
Log.Warn("QOI queue exceeded limit.");
this._qoiRects.splice(0, 500);
}
}
return true;
}
// intensity tinted
_itRect(x, y, width, height, sock, display, depth, frame_id) {
let data = this._readData(sock);
if (data === null) {
return false;
}
const r = data[0];
const g = data[1];
const b = data[2];
const a = data[3];
const uncompressedSize = width * height / 2 + 1;
this._itzlib.reset();
this._itzlib.setInput(data.slice(4));
data = this._itzlib.inflate(uncompressedSize);
this._itzlib.setInput(null);
// unpack
let rgba = new Uint8Array(width * height * 4 + 4);
for (let i = 0, d = 0; i < uncompressedSize; i++, d += 8) {
let p = data[i];
rgba[d + 0] = r;
rgba[d + 1] = g;
rgba[d + 2] = b;
rgba[d + 3] = a * ((p & 15) << 4) / 255;
rgba[d + 4] = r;
rgba[d + 5] = g;
rgba[d + 6] = b;
rgba[d + 7] = a * (p & 240) / 255;
}
let img = new ImageData(new Uint8ClampedArray(rgba.buffer, 0, width * height * 4), width, height);
display.transparentRect(x, y, width, height, img, frame_id);
return true;
}
_pngRect(x, y, width, height, sock, display, depth, frame_id) {
throw new Error("PNG received in standard Tight rect");
}
_basicRect(ctl, x, y, width, height, sock, display, depth, frame_id) {
if (this._filter === null) {
if (ctl & 0x4) {
if (sock.rQwait("TIGHT", 1)) {
return false;
}
this._filter = sock.rQshift8();
} else {
// Implicit CopyFilter
this._filter = 0;
}
}
let streamId = ctl & 0x3;
let ret;
switch (this._filter) {
case 0: // CopyFilter
ret = this._copyFilter(streamId, x, y, width, height,
sock, display, depth, frame_id);
break;
case 1: // PaletteFilter
ret = this._paletteFilter(streamId, x, y, width, height,
sock, display, depth, frame_id);
break;
case 2: // GradientFilter
ret = this._gradientFilter(streamId, x, y, width, height,
sock, display, depth, frame_id);
break;
default:
throw new Error("Illegal tight filter received (ctl: " +
this._filter + ")");
}
if (ret) {
this._filter = null;
}
return ret;
}
_copyFilter(streamId, x, y, width, height, sock, display, depth, frame_id) {
const uncompressedSize = width * height * 3;
let data;
if (uncompressedSize === 0) {
return true;
}
if (uncompressedSize < 12) {
if (sock.rQwait("TIGHT", uncompressedSize)) {
return false;
}
data = sock.rQshiftBytes(uncompressedSize);
} else {
data = this._readData(sock);
if (data === null) {
return false;
}
this._zlibs[streamId].setInput(data);
data = this._zlibs[streamId].inflate(uncompressedSize);
this._zlibs[streamId].setInput(null);
}
let rgbx = new Uint8Array(width * height * 4);
for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) {
rgbx[i] = data[j];
rgbx[i + 1] = data[j + 1];
rgbx[i + 2] = data[j + 2];
rgbx[i + 3] = 255; // Alpha
}
display.blitImage(x, y, width, height, rgbx, 0, frame_id, false);
return true;
}
_paletteFilter(streamId, x, y, width, height, sock, display, depth, frame_id) {
if (this._numColors === 0) {
if (sock.rQwait("TIGHT palette", 1)) {
return false;
}
const numColors = sock.rQpeek8() + 1;
const paletteSize = numColors * 3;
if (sock.rQwait("TIGHT palette", 1 + paletteSize)) {
return false;
}
this._numColors = numColors;
sock.rQskipBytes(1);
sock.rQshiftTo(this._palette, paletteSize);
}
const bpp = (this._numColors <= 2) ? 1 : 8;
const rowSize = Math.floor((width * bpp + 7) / 8);
const uncompressedSize = rowSize * height;
let data;
if (uncompressedSize === 0) {
return true;
}
if (uncompressedSize < 12) {
if (sock.rQwait("TIGHT", uncompressedSize)) {
return false;
}
data = sock.rQshiftBytes(uncompressedSize);
} else {
data = this._readData(sock);
if (data === null) {
return false;
}
this._zlibs[streamId].setInput(data);
data = this._zlibs[streamId].inflate(uncompressedSize);
this._zlibs[streamId].setInput(null);
}
// Convert indexed (palette based) image data to RGB
if (this._numColors == 2) {
this._monoRect(x, y, width, height, data, this._palette, display, frame_id);
} else {
this._paletteRect(x, y, width, height, data, this._palette, display, frame_id);
}
this._numColors = 0;
return true;
}
_monoRect(x, y, width, height, data, palette, display, frame_id) {
// Convert indexed (palette based) image data to RGB
// TODO: reduce number of calculations inside loop
const dest = this._getScratchBuffer(width * height * 4);
const w = Math.floor((width + 7) / 8);
const w1 = Math.floor(width / 8);
for (let y = 0; y < height; y++) {
let dp, sp, x;
for (x = 0; x < w1; x++) {
for (let b = 7; b >= 0; b--) {
dp = (y * width + x * 8 + 7 - b) * 4;
sp = (data[y * w + x] >> b & 1) * 3;
dest[dp] = palette[sp];
dest[dp + 1] = palette[sp + 1];
dest[dp + 2] = palette[sp + 2];
dest[dp + 3] = 255;
}
}
for (let b = 7; b >= 8 - width % 8; b--) {
dp = (y * width + x * 8 + 7 - b) * 4;
sp = (data[y * w + x] >> b & 1) * 3;
dest[dp] = palette[sp];
dest[dp + 1] = palette[sp + 1];
dest[dp + 2] = palette[sp + 2];
dest[dp + 3] = 255;
}
}
display.blitImage(x, y, width, height, dest, 0, frame_id, false);
}
_paletteRect(x, y, width, height, data, palette, display, frame_id) {
// Convert indexed (palette based) image data to RGB
const dest = this._getScratchBuffer(width * height * 4);
const total = width * height * 4;
for (let i = 0, j = 0; i < total; i += 4, j++) {
const sp = data[j] * 3;
dest[i] = palette[sp];
dest[i + 1] = palette[sp + 1];
dest[i + 2] = palette[sp + 2];
dest[i + 3] = 255;
}
display.blitImage(x, y, width, height, dest, 0, frame_id, false);
}
_gradientFilter(streamId, x, y, width, height, sock, display, depth, frame_id) {
throw new Error("Gradient filter not implemented");
}
_readData(sock) {
if (this._len === 0) {
if (sock.rQwait("TIGHT", 3)) {
return null;
}
let byte;
byte = sock.rQshift8();
this._len = byte & 0x7f;
if (byte & 0x80) {
byte = sock.rQshift8();
this._len |= (byte & 0x7f) << 7;
if (byte & 0x80) {
byte = sock.rQshift8();
this._len |= byte << 14;
}
}
}
if (sock.rQwait("TIGHT", this._len)) {
return null;
}
let data = sock.rQshiftBytes(this._len);
this._len = 0;
return data;
}
_getScratchBuffer(size) {
if (!this._scratchBuffer || (this._scratchBuffer.length < size)) {
this._scratchBuffer = new Uint8Array(size);
}
return this._scratchBuffer;
}
async _disableQOIWorkers() {
if (this._workers) {
this._enableQOI = false;
this._availableWorkers = null;
this._sabs = null;
this._sabsR = null;
this._arrs = null;
this._arrsR = null;
this._qoiRects = null;
this._rectQlooping = null;
for await (let i of Array.from(Array(this._threads).keys())) {
this._workers[i].terminate();
delete this._workers[i];
}
this._workers = null;
}
}
_enableQOIWorkers() {
const supportsSharedArrayBuffers = typeof SharedArrayBuffer !== "undefined";
if (!supportsSharedArrayBuffers) {
Log.Warn("Enabling QOI Failed, client not compatible.");
return false;
}
let fullPath = window.location.pathname;
let path = fullPath.substring(0, fullPath.lastIndexOf('/')+1);
if ((window.navigator.hardwareConcurrency) && (window.navigator.hardwareConcurrency >= 4)) {
this._threads = 16;
} else {
this._threads = 8;
}
this._workers = [];
this._availableWorkers = [];
this._sabs = [];
this._sabsR = [];
this._arrs = [];
this._arrsR = [];
this._qoiRects = [];
this._rectQlooping = false;
for (let i = 0; i < this._threads; i++) {
this._workers.push(new Worker("core/decoders/qoi/decoder.js"));
this._sabs.push(new SharedArrayBuffer(300000));
this._sabsR.push(new SharedArrayBuffer(400000));
this._arrs.push(new Uint8Array(this._sabs[i]));
this._arrsR.push(new Uint8ClampedArray(this._sabsR[i]));
this._workers[i].onmessage = (evt) => {
this._availableWorkers.push(i);
switch(evt.data.result) {
case 0:
let data = new Uint8ClampedArray(evt.data.length);
data.set(this._arrsR[i].slice(0, evt.data.length));
let img = new ImageData(data, evt.data.img.width, evt.data.img.height, {colorSpace: evt.data.img.colorSpace});
this._displayGlobal.blitQoi(
evt.data.x,
evt.data.y,
evt.data.width,
evt.data.height,
img,
0,
evt.data.frame_id,
false
);
this._processRectQ();
break;
case 1:
Log.Info("QOI Worker is now available.");
break;
case 2:
Log.Info("Error on worker: " + evt.error);
break;
}
};
}
for (let i = 0; i < this._threads; i++) {
this._workers[i].postMessage({path:path});
}
return true;
}
}
+27
View File
@@ -0,0 +1,27 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
*/
import TightDecoder from './tight.js';
export default class TightPNGDecoder extends TightDecoder {
_pngRect(x, y, width, height, sock, display, depth, frame_id) {
let data = this._readData(sock);
if (data === null) {
return false;
}
display.imageRect(x, y, width, height, "image/png", data, frame_id);
return true;
}
_basicRect(ctl, x, y, width, height, sock, display, depth) {
throw new Error("BasicCompression received in TightPNG rect");
}
}
+283
View File
@@ -0,0 +1,283 @@
/*
* KasmVNC: HTML5 VNC client
* Copyright (C) 2020 Kasm Technologies
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
*/
import * as Log from '../util/logging.js';
import Inflator from "../inflator.js";
export default class UDPDecoder {
constructor() {
this._filter = null;
this._palette = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel)
this._directDraw = false; //Draw directly to the canvas without ordering
this._zlibs = [];
for (let i = 0; i < 4; i++) {
this._zlibs[i] = new Inflator();
}
}
decodeRect(x, y, width, height, data, display, depth, frame_id) {
let ctl = data[12];
ctl = ctl >> 4;
let ret;
if (ctl === 0x08) {
ret = this._fillRect(x, y, width, height, data, display, depth, frame_id);
} else if (ctl === 0x09) {
ret = this._jpegRect(x, y, width, height, data, display, depth, frame_id);
} else if (ctl === 0x0A) {
ret = this._pngRect(x, y, width, height, data, display, depth, frame_id);
} else if ((ctl & 0x08) == 0) {
ret = this._basicRect(ctl, x, y, width, height, data, display, depth, frame_id);
} else if (ctl === 0x0B) {
ret = this._webpRect(x, y, width, height, data, display, depth, frame_id);
} else {
throw new Error("Illegal udp compression received (ctl: " +
ctl + ")");
}
return ret;
}
_fillRect(x, y, width, height, data, display, depth, frame_id) {
display.fillRect(x, y, width, height,
[data[13], data[14], data[15]], frame_id, this._directDraw);
return true;
}
_jpegRect(x, y, width, height, data, display, depth, frame_id) {
let img = this._readData(data);
if (img === null) {
return false;
}
display.imageRect(x, y, width, height, "image/jpeg", img, frame_id, this._directDraw);
return true;
}
_webpRect(x, y, width, height, data, display, depth, frame_id) {
let img = this._readData(data);
if (img === null) {
return false;
}
display.imageRect(x, y, width, height, "image/webp", img, frame_id, this._directDraw);
return true;
}
_pngRect(x, y, width, height, data, display, depth, frame_id) {
//throw new Error("PNG received in UDP rect");
Log.Error("PNG received in UDP rect");
}
_basicRect(ctl, x, y, width, height, data, display, depth, frame_id) {
let zlibs_flags = data[12];
// Reset streams if the server requests it
for (let i = 0; i < 4; i++) {
if ((zlibs_flags >> i) & 1) {
this._zlibs[i].reset();
//Log.Debug("Reset zlib stream " + i);
}
}
let filter = data[13];
let data_index = 14;
let streamId = ctl & 0x3;
if (!(ctl & 0x4)) {
// Implicit CopyFilter
filter = 0;
data_index = 13;
}
let ret;
switch (filter) {
case 0: // CopyFilter
ret = this._copyFilter(streamId, x, y, width, height,
data, display, depth, frame_id, data_index);
break;
case 1: // PaletteFilter
ret = this._paletteFilter(streamId, x, y, width, height,
data, display, depth, frame_id);
break;
case 2: // GradientFilter
ret = this._gradientFilter(streamId, x, y, width, height,
data, display, depth, frame_id);
break;
default:
throw new Error("Illegal tight filter received (ctl: " +
this._filter + ")");
}
return ret;
}
_copyFilter(streamId, x, y, width, height, data, display, depth, frame_id, data_index=14) {
const uncompressedSize = width * height * 3;
if (uncompressedSize === 0) {
return true;
}
if (uncompressedSize < 12) {
data = data.slice(data_index, data_index + uncompressedSize);
} else {
data = this._readData(data, data_index);
if (data === null) {
return false;
}
this._zlibs[streamId].setInput(data);
data = this._zlibs[streamId].inflate(uncompressedSize);
this._zlibs[streamId].setInput(null);
}
let rgbx = new Uint8Array(width * height * 4);
for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) {
rgbx[i] = data[j];
rgbx[i + 1] = data[j + 1];
rgbx[i + 2] = data[j + 2];
rgbx[i + 3] = 255; // Alpha
}
display.blitImage(x, y, width, height, rgbx, 0, frame_id, this._directDraw);
return true;
}
_paletteFilter(streamId, x, y, width, height, data, display, depth, frame_id) {
const numColors = data[14] + 1;
const paletteSize = numColors * 3;
let palette = data.slice(15, 15 + paletteSize);
const bpp = (numColors <= 2) ? 1 : 8;
const rowSize = Math.floor((width * bpp + 7) / 8);
const uncompressedSize = rowSize * height;
let data_i = 15 + paletteSize;
if (uncompressedSize === 0) {
return true;
}
if (uncompressedSize < 12) {
data = data.slice(data_i, data_i + uncompressedSize);
} else {
data = this._readData(data, data_i);
if (data === null) {
return false;
}
this._zlibs[streamId].setInput(data);
data = this._zlibs[streamId].inflate(uncompressedSize);
this._zlibs[streamId].setInput(null);
}
// Convert indexed (palette based) image data to RGB
if (numColors == 2) {
this._monoRect(x, y, width, height, data, palette, display, frame_id);
} else {
this._paletteRect(x, y, width, height, data, palette, display, frame_id);
}
return true;
}
_monoRect(x, y, width, height, data, palette, display, frame_id) {
// Convert indexed (palette based) image data to RGB
// TODO: reduce number of calculations inside loop
const dest = this._getScratchBuffer(width * height * 4);
const w = Math.floor((width + 7) / 8);
const w1 = Math.floor(width / 8);
for (let y = 0; y < height; y++) {
let dp, sp, x;
for (x = 0; x < w1; x++) {
for (let b = 7; b >= 0; b--) {
dp = (y * width + x * 8 + 7 - b) * 4;
sp = (data[y * w + x] >> b & 1) * 3;
dest[dp] = palette[sp];
dest[dp + 1] = palette[sp + 1];
dest[dp + 2] = palette[sp + 2];
dest[dp + 3] = 255;
}
}
for (let b = 7; b >= 8 - width % 8; b--) {
dp = (y * width + x * 8 + 7 - b) * 4;
sp = (data[y * w + x] >> b & 1) * 3;
dest[dp] = palette[sp];
dest[dp + 1] = palette[sp + 1];
dest[dp + 2] = palette[sp + 2];
dest[dp + 3] = 255;
}
}
display.blitImage(x, y, width, height, dest, 0, frame_id, this._directDraw);
}
_paletteRect(x, y, width, height, data, palette, display, frame_id) {
// Convert indexed (palette based) image data to RGB
const dest = this._getScratchBuffer(width * height * 4);
const total = width * height * 4;
for (let i = 0, j = 0; i < total; i += 4, j++) {
const sp = data[j] * 3;
dest[i] = palette[sp];
dest[i + 1] = palette[sp + 1];
dest[i + 2] = palette[sp + 2];
dest[i + 3] = 255;
}
display.blitImage(x, y, width, height, dest, 0, frame_id, this._directDraw);
}
_gradientFilter(streamId, x, y, width, height, data, display, depth, frame_id) {
throw new Error("Gradient filter not implemented");
}
_readData(data, len_index = 13) {
if (data.length < len_index + 2) {
Log.Error("UDP Decoder, readData, invalid data len")
return null;
}
let i = len_index;
let byte = data[i++];
let len = byte & 0x7f;
// lenth field is variably sized 1 to 3 bytes long
if (byte & 0x80) {
byte = data[i++]
len |= (byte & 0x7f) << 7;
if (byte & 0x80) {
byte = data[i++];
len |= byte << 14;
}
}
//TODO: get rid of me
if (data.length !== len + i) {
console.log('Rect of size ' + len + ' with data size ' + data.length + ' index of ' + i);
}
return data.slice(i);
}
_getScratchBuffer(size) {
if (!this._scratchBuffer || (this._scratchBuffer.length < size)) {
this._scratchBuffer = new Uint8Array(size);
}
return this._scratchBuffer;
}
}