Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
N
noVNC
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
rasky
noVNC
Commits
35d7574b
Commit
35d7574b
authored
Mar 11, 2012
by
Joel Martin
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit '
d38db74a
'
Conflicts: README.md
parents
0c4f4b59
d38db74a
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
980 additions
and
11 deletions
+980
-11
README.md
README.md
+1
-0
display.js
include/display.js
+30
-1
jsunzip.js
include/jsunzip.js
+668
-0
rfb.js
include/rfb.js
+278
-10
vnc.js
include/vnc.js
+3
-0
No files found.
README.md
View file @
35d7574b
...
...
@@ -26,6 +26,7 @@ their products including: [Ganeti Web Manager](http://code.osuosl.org/projects/g
*
Easy site integration and theming (3 example themes included)
*
Licensed under the
[
LGPLv3
](
http://www.gnu.org/licenses/lgpl.html
)
*
Support for tight encoding (contributed by Mercuri.ca)
### Screenshots
...
...
include/display.js
View file @
35d7574b
...
...
@@ -20,7 +20,7 @@ var that = {}, // Public API methods
c_forceCanvas
=
false
,
// Predefine function variables (jslint)
imageDataGet
,
bgrxImageData
,
cmapImageData
,
imageDataGet
,
rgbImageData
,
bgrxImageData
,
cmapImageData
,
setFillColor
,
rescale
,
// The full frame buffer (logical canvas) size
...
...
@@ -497,6 +497,26 @@ that.finishTile = function() {
// else: No-op, if not prefer_js then already done by setSubTile
};
rgbImageData
=
function
(
x
,
y
,
width
,
height
,
arr
,
offset
)
{
var
img
,
i
,
j
,
data
,
v
=
viewport
;
/*
if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
(x - v.x + width < 0) || (y - v.y + height < 0)) {
// Skipping because outside of viewport
return;
}
*/
img
=
c_ctx
.
createImageData
(
width
,
height
);
data
=
img
.
data
;
for
(
i
=
0
,
j
=
offset
;
i
<
(
width
*
height
*
4
);
i
=
i
+
4
,
j
=
j
+
3
)
{
data
[
i
]
=
arr
[
j
];
data
[
i
+
1
]
=
arr
[
j
+
1
];
data
[
i
+
2
]
=
arr
[
j
+
2
];
data
[
i
+
3
]
=
255
;
// Set Alpha
}
c_ctx
.
putImageData
(
img
,
x
-
v
.
x
,
y
-
v
.
y
);
};
bgrxImageData
=
function
(
x
,
y
,
width
,
height
,
arr
,
offset
)
{
var
img
,
i
,
j
,
data
,
v
=
viewport
;
/*
...
...
@@ -540,6 +560,15 @@ that.blitImage = function(x, y, width, height, arr, offset) {
}
};
that
.
blitRgbImage
=
function
(
x
,
y
,
width
,
height
,
arr
,
offset
)
{
if
(
conf
.
true_color
)
{
rgbImageData
(
x
,
y
,
width
,
height
,
arr
,
offset
);
}
else
{
// prolly wrong...
cmapImageData
(
x
,
y
,
width
,
height
,
arr
,
offset
);
}
};
that
.
blitStringImage
=
function
(
str
,
x
,
y
)
{
var
img
=
new
Image
();
img
.
onload
=
function
()
{
...
...
include/jsunzip.js
0 → 100755
View file @
35d7574b
/*
* JSUnzip
*
* Copyright (c) 2011 by Erik Moller
* All Rights Reserved
*
* This software is provided 'as-is', without any express
* or implied warranty. In no event will the authors be
* held liable for any damages arising from the use of
* this software.
*
* Permission is granted to anyone to use this software
* for any purpose, including commercial applications,
* and to alter it and redistribute it freely, subject to
* the following restrictions:
*
* 1. The origin of this software must not be
* misrepresented; you must not claim that you
* wrote the original software. If you use this
* software in a product, an acknowledgment in
* the product documentation would be appreciated
* but is not required.
*
* 2. Altered source versions must be plainly marked
* as such, and must not be misrepresented as
* being the original software.
*
* 3. This notice may not be removed or altered from
* any source distribution.
*/
var
tinf
;
function
JSUnzip
()
{
this
.
getInt
=
function
(
offset
,
size
)
{
switch
(
size
)
{
case
4
:
return
(
this
.
data
.
charCodeAt
(
offset
+
3
)
&
0xff
)
<<
24
|
(
this
.
data
.
charCodeAt
(
offset
+
2
)
&
0xff
)
<<
16
|
(
this
.
data
.
charCodeAt
(
offset
+
1
)
&
0xff
)
<<
8
|
(
this
.
data
.
charCodeAt
(
offset
+
0
)
&
0xff
);
break
;
case
2
:
return
(
this
.
data
.
charCodeAt
(
offset
+
1
)
&
0xff
)
<<
8
|
(
this
.
data
.
charCodeAt
(
offset
+
0
)
&
0xff
);
break
;
default
:
return
this
.
data
.
charCodeAt
(
offset
)
&
0xff
;
break
;
}
};
this
.
getDOSDate
=
function
(
dosdate
,
dostime
)
{
var
day
=
dosdate
&
0x1f
;
var
month
=
((
dosdate
>>
5
)
&
0xf
)
-
1
;
var
year
=
1980
+
((
dosdate
>>
9
)
&
0x7f
)
var
second
=
(
dostime
&
0x1f
)
*
2
;
var
minute
=
(
dostime
>>
5
)
&
0x3f
;
hour
=
(
dostime
>>
11
)
&
0x1f
;
return
new
Date
(
year
,
month
,
day
,
hour
,
minute
,
second
);
}
this
.
open
=
function
(
data
)
{
this
.
data
=
data
;
this
.
files
=
[];
if
(
this
.
data
.
length
<
22
)
return
{
'status'
:
false
,
'error'
:
'Invalid data'
};
var
endOfCentralDirectory
=
this
.
data
.
length
-
22
;
while
(
endOfCentralDirectory
>=
0
&&
this
.
getInt
(
endOfCentralDirectory
,
4
)
!=
0x06054b50
)
--
endOfCentralDirectory
;
if
(
endOfCentralDirectory
<
0
)
return
{
'status'
:
false
,
'error'
:
'Invalid data'
};
if
(
this
.
getInt
(
endOfCentralDirectory
+
4
,
2
)
!=
0
||
this
.
getInt
(
endOfCentralDirectory
+
6
,
2
)
!=
0
)
return
{
'status'
:
false
,
'error'
:
'No multidisk support'
};
var
entriesInThisDisk
=
this
.
getInt
(
endOfCentralDirectory
+
8
,
2
);
var
centralDirectoryOffset
=
this
.
getInt
(
endOfCentralDirectory
+
16
,
4
);
var
globalCommentLength
=
this
.
getInt
(
endOfCentralDirectory
+
20
,
2
);
this
.
comment
=
this
.
data
.
slice
(
endOfCentralDirectory
+
22
,
endOfCentralDirectory
+
22
+
globalCommentLength
);
var
fileOffset
=
centralDirectoryOffset
;
for
(
var
i
=
0
;
i
<
entriesInThisDisk
;
++
i
)
{
if
(
this
.
getInt
(
fileOffset
+
0
,
4
)
!=
0x02014b50
)
return
{
'status'
:
false
,
'error'
:
'Invalid data'
};
if
(
this
.
getInt
(
fileOffset
+
6
,
2
)
>
20
)
return
{
'status'
:
false
,
'error'
:
'Unsupported version'
};
if
(
this
.
getInt
(
fileOffset
+
8
,
2
)
&
1
)
return
{
'status'
:
false
,
'error'
:
'Encryption not implemented'
};
var
compressionMethod
=
this
.
getInt
(
fileOffset
+
10
,
2
);
if
(
compressionMethod
!=
0
&&
compressionMethod
!=
8
)
return
{
'status'
:
false
,
'error'
:
'Unsupported compression method'
};
var
lastModFileTime
=
this
.
getInt
(
fileOffset
+
12
,
2
);
var
lastModFileDate
=
this
.
getInt
(
fileOffset
+
14
,
2
);
var
lastModifiedDate
=
this
.
getDOSDate
(
lastModFileDate
,
lastModFileTime
);
var
crc
=
this
.
getInt
(
fileOffset
+
16
,
4
);
// TODO: crc
var
compressedSize
=
this
.
getInt
(
fileOffset
+
20
,
4
);
var
uncompressedSize
=
this
.
getInt
(
fileOffset
+
24
,
4
);
var
fileNameLength
=
this
.
getInt
(
fileOffset
+
28
,
2
);
var
extraFieldLength
=
this
.
getInt
(
fileOffset
+
30
,
2
);
var
fileCommentLength
=
this
.
getInt
(
fileOffset
+
32
,
2
);
var
relativeOffsetOfLocalHeader
=
this
.
getInt
(
fileOffset
+
42
,
4
);
var
fileName
=
this
.
data
.
slice
(
fileOffset
+
46
,
fileOffset
+
46
+
fileNameLength
);
var
fileComment
=
this
.
data
.
slice
(
fileOffset
+
46
+
fileNameLength
+
extraFieldLength
,
fileOffset
+
46
+
fileNameLength
+
extraFieldLength
+
fileCommentLength
);
if
(
this
.
getInt
(
relativeOffsetOfLocalHeader
+
0
,
4
)
!=
0x04034b50
)
return
{
'status'
:
false
,
'error'
:
'Invalid data'
};
var
localFileNameLength
=
this
.
getInt
(
relativeOffsetOfLocalHeader
+
26
,
2
);
var
localExtraFieldLength
=
this
.
getInt
(
relativeOffsetOfLocalHeader
+
28
,
2
);
var
localFileContent
=
relativeOffsetOfLocalHeader
+
30
+
localFileNameLength
+
localExtraFieldLength
;
this
.
files
[
fileName
]
=
{
'fileComment'
:
fileComment
,
'compressionMethod'
:
compressionMethod
,
'compressedSize'
:
compressedSize
,
'uncompressedSize'
:
uncompressedSize
,
'localFileContent'
:
localFileContent
,
'lastModifiedDate'
:
lastModifiedDate
};
fileOffset
+=
46
+
fileNameLength
+
extraFieldLength
+
fileCommentLength
;
}
return
{
'status'
:
true
}
};
this
.
read
=
function
(
fileName
)
{
var
fileInfo
=
this
.
files
[
fileName
];
if
(
fileInfo
)
{
if
(
fileInfo
.
compressionMethod
==
8
)
{
if
(
!
tinf
)
{
tinf
=
new
TINF
();
tinf
.
init
();
}
var
result
=
tinf
.
uncompress
(
this
.
data
,
fileInfo
.
localFileContent
);
if
(
result
.
status
==
tinf
.
OK
)
return
{
'status'
:
true
,
'data'
:
result
.
data
};
else
return
{
'status'
:
false
,
'error'
:
result
.
error
};
}
else
{
return
{
'status'
:
true
,
'data'
:
this
.
data
.
slice
(
fileInfo
.
localFileContent
,
fileInfo
.
localFileContent
+
fileInfo
.
uncompressedSize
)
};
}
}
return
{
'status'
:
false
,
'error'
:
"File '"
+
fileName
+
"' doesn't exist in zip"
};
};
};
/*
* tinflate - tiny inflate
*
* Copyright (c) 2003 by Joergen Ibsen / Jibz
* All Rights Reserved
*
* http://www.ibsensoftware.com/
*
* This software is provided 'as-is', without any express
* or implied warranty. In no event will the authors be
* held liable for any damages arising from the use of
* this software.
*
* Permission is granted to anyone to use this software
* for any purpose, including commercial applications,
* and to alter it and redistribute it freely, subject to
* the following restrictions:
*
* 1. The origin of this software must not be
* misrepresented; you must not claim that you
* wrote the original software. If you use this
* software in a product, an acknowledgment in
* the product documentation would be appreciated
* but is not required.
*
* 2. Altered source versions must be plainly marked
* as such, and must not be misrepresented as
* being the original software.
*
* 3. This notice may not be removed or altered from
* any source distribution.
*/
/*
* tinflate javascript port by Erik Moller in May 2011.
* emoller@opera.com
*
* read_bits() patched by mike@imidio.com to allow
* reading more then 8 bits (needed in some zlib streams)
*/
"use strict"
;
function
TINF
()
{
this
.
OK
=
0
;
this
.
DATA_ERROR
=
(
-
3
);
this
.
WINDOW_SIZE
=
32768
;
/* ------------------------------ *
* -- internal data structures -- *
* ------------------------------ */
this
.
TREE
=
function
()
{
this
.
table
=
new
Array
(
16
);
/* table of code length counts */
this
.
trans
=
new
Array
(
288
);
/* code -> symbol translation table */
};
this
.
DATA
=
function
(
that
)
{
this
.
source
=
''
;
this
.
sourceIndex
=
0
;
this
.
tag
=
0
;
this
.
bitcount
=
0
;
this
.
dest
=
[];
this
.
history
=
[];
this
.
ltree
=
new
that
.
TREE
();
/* dynamic length/symbol tree */
this
.
dtree
=
new
that
.
TREE
();
/* dynamic distance tree */
};
/* --------------------------------------------------- *
* -- uninitialized global data (static structures) -- *
* --------------------------------------------------- */
this
.
sltree
=
new
this
.
TREE
();
/* fixed length/symbol tree */
this
.
sdtree
=
new
this
.
TREE
();
/* fixed distance tree */
/* extra bits and base tables for length codes */
this
.
length_bits
=
new
Array
(
30
);
this
.
length_base
=
new
Array
(
30
);
/* extra bits and base tables for distance codes */
this
.
dist_bits
=
new
Array
(
30
);
this
.
dist_base
=
new
Array
(
30
);
/* special ordering of code length codes */
this
.
clcidx
=
[
16
,
17
,
18
,
0
,
8
,
7
,
9
,
6
,
10
,
5
,
11
,
4
,
12
,
3
,
13
,
2
,
14
,
1
,
15
];
/* ----------------------- *
* -- utility functions -- *
* ----------------------- */
/* build extra bits and base tables */
this
.
build_bits_base
=
function
(
bits
,
base
,
delta
,
first
)
{
var
i
,
sum
;
/* build bits table */
for
(
i
=
0
;
i
<
delta
;
++
i
)
bits
[
i
]
=
0
;
for
(
i
=
0
;
i
<
30
-
delta
;
++
i
)
bits
[
i
+
delta
]
=
Math
.
floor
(
i
/
delta
);
/* build base table */
for
(
sum
=
first
,
i
=
0
;
i
<
30
;
++
i
)
{
base
[
i
]
=
sum
;
sum
+=
1
<<
bits
[
i
];
}
}
/* build the fixed huffman trees */
this
.
build_fixed_trees
=
function
(
lt
,
dt
)
{
var
i
;
/* build fixed length tree */
for
(
i
=
0
;
i
<
7
;
++
i
)
lt
.
table
[
i
]
=
0
;
lt
.
table
[
7
]
=
24
;
lt
.
table
[
8
]
=
152
;
lt
.
table
[
9
]
=
112
;
for
(
i
=
0
;
i
<
24
;
++
i
)
lt
.
trans
[
i
]
=
256
+
i
;
for
(
i
=
0
;
i
<
144
;
++
i
)
lt
.
trans
[
24
+
i
]
=
i
;
for
(
i
=
0
;
i
<
8
;
++
i
)
lt
.
trans
[
24
+
144
+
i
]
=
280
+
i
;
for
(
i
=
0
;
i
<
112
;
++
i
)
lt
.
trans
[
24
+
144
+
8
+
i
]
=
144
+
i
;
/* build fixed distance tree */
for
(
i
=
0
;
i
<
5
;
++
i
)
dt
.
table
[
i
]
=
0
;
dt
.
table
[
5
]
=
32
;
for
(
i
=
0
;
i
<
32
;
++
i
)
dt
.
trans
[
i
]
=
i
;
}
/* given an array of code lengths, build a tree */
this
.
build_tree
=
function
(
t
,
lengths
,
loffset
,
num
)
{
var
offs
=
new
Array
(
16
);
var
i
,
sum
;
/* clear code length count table */
for
(
i
=
0
;
i
<
16
;
++
i
)
t
.
table
[
i
]
=
0
;
/* scan symbol lengths, and sum code length counts */
for
(
i
=
0
;
i
<
num
;
++
i
)
t
.
table
[
lengths
[
loffset
+
i
]]
++
;
t
.
table
[
0
]
=
0
;
/* compute offset table for distribution sort */
for
(
sum
=
0
,
i
=
0
;
i
<
16
;
++
i
)
{
offs
[
i
]
=
sum
;
sum
+=
t
.
table
[
i
];
}
/* create code->symbol translation table (symbols sorted by code) */
for
(
i
=
0
;
i
<
num
;
++
i
)
{
if
(
lengths
[
loffset
+
i
])
t
.
trans
[
offs
[
lengths
[
loffset
+
i
]]
++
]
=
i
;
}
}
/* ---------------------- *
* -- decode functions -- *
* ---------------------- */
/* get one bit from source stream */
this
.
getbit
=
function
(
d
)
{
var
bit
;
/* check if tag is empty */
if
(
!
d
.
bitcount
--
)
{
/* load next tag */
d
.
tag
=
d
.
source
[
d
.
sourceIndex
++
]
&
0xff
;
d
.
bitcount
=
7
;
}
/* shift bit out of tag */
bit
=
d
.
tag
&
0x01
;
d
.
tag
>>=
1
;
return
bit
;
}
/* read a num bit value from a stream and add base */
this
.
read_bits
=
function
(
d
,
num
,
base
)
{
if
(
!
num
)
return
base
;
var
val
=
0
;
while
(
d
.
bitcount
<
24
)
{
d
.
tag
=
d
.
tag
|
(
d
.
source
[
d
.
sourceIndex
++
]
&
0xff
)
<<
d
.
bitcount
;
d
.
bitcount
+=
8
;
}
val
=
d
.
tag
&
(
0xffff
>>
(
16
-
num
));
d
.
tag
>>=
num
;
d
.
bitcount
-=
num
;
return
val
+
base
;
}
/* given a data stream and a tree, decode a symbol */
this
.
decode_symbol
=
function
(
d
,
t
)
{
while
(
d
.
bitcount
<
16
)
{
d
.
tag
=
d
.
tag
|
(
d
.
source
[
d
.
sourceIndex
++
]
&
0xff
)
<<
d
.
bitcount
;
d
.
bitcount
+=
8
;
}
var
sum
=
0
,
cur
=
0
,
len
=
0
;
do
{
cur
=
2
*
cur
+
((
d
.
tag
&
(
1
<<
len
))
>>
len
);
++
len
;
sum
+=
t
.
table
[
len
];
cur
-=
t
.
table
[
len
];
}
while
(
cur
>=
0
);
d
.
tag
>>=
len
;
d
.
bitcount
-=
len
;
return
t
.
trans
[
sum
+
cur
];
}
/* given a data stream, decode dynamic trees from it */
this
.
decode_trees
=
function
(
d
,
lt
,
dt
)
{
var
code_tree
=
new
this
.
TREE
();
var
lengths
=
new
Array
(
288
+
32
);
var
hlit
,
hdist
,
hclen
;
var
i
,
num
,
length
;
/* get 5 bits HLIT (257-286) */
hlit
=
this
.
read_bits
(
d
,
5
,
257
);
/* get 5 bits HDIST (1-32) */
hdist
=
this
.
read_bits
(
d
,
5
,
1
);
/* get 4 bits HCLEN (4-19) */
hclen
=
this
.
read_bits
(
d
,
4
,
4
);
for
(
i
=
0
;
i
<
19
;
++
i
)
lengths
[
i
]
=
0
;
/* read code lengths for code length alphabet */
for
(
i
=
0
;
i
<
hclen
;
++
i
)
{
/* get 3 bits code length (0-7) */
var
clen
=
this
.
read_bits
(
d
,
3
,
0
);
lengths
[
this
.
clcidx
[
i
]]
=
clen
;
}
/* build code length tree */
this
.
build_tree
(
code_tree
,
lengths
,
0
,
19
);
/* decode code lengths for the dynamic trees */
for
(
num
=
0
;
num
<
hlit
+
hdist
;
)
{
var
sym
=
this
.
decode_symbol
(
d
,
code_tree
);
switch
(
sym
)
{
case
16
:
/* copy previous code length 3-6 times (read 2 bits) */
{
var
prev
=
lengths
[
num
-
1
];
for
(
length
=
this
.
read_bits
(
d
,
2
,
3
);
length
;
--
length
)
{
lengths
[
num
++
]
=
prev
;
}
}
break
;
case
17
:
/* repeat code length 0 for 3-10 times (read 3 bits) */
for
(
length
=
this
.
read_bits
(
d
,
3
,
3
);
length
;
--
length
)
{
lengths
[
num
++
]
=
0
;
}
break
;
case
18
:
/* repeat code length 0 for 11-138 times (read 7 bits) */
for
(
length
=
this
.
read_bits
(
d
,
7
,
11
);
length
;
--
length
)
{
lengths
[
num
++
]
=
0
;
}
break
;
default
:
/* values 0-15 represent the actual code lengths */
lengths
[
num
++
]
=
sym
;
break
;
}
}
/* build dynamic trees */
this
.
build_tree
(
lt
,
lengths
,
0
,
hlit
);
this
.
build_tree
(
dt
,
lengths
,
hlit
,
hdist
);
}
/* ----------------------------- *
* -- block inflate functions -- *
* ----------------------------- */
/* given a stream and two trees, inflate a block of data */
this
.
inflate_block_data
=
function
(
d
,
lt
,
dt
)
{
// js optimization.
var
ddest
=
d
.
dest
;
var
ddestlength
=
ddest
.
length
;
while
(
1
)
{
var
sym
=
this
.
decode_symbol
(
d
,
lt
);
/* check for end of block */
if
(
sym
==
256
)
{
return
this
.
OK
;
}
if
(
sym
<
256
)
{
ddest
[
ddestlength
++
]
=
sym
;
// ? String.fromCharCode(sym);
d
.
history
.
push
(
sym
);
}
else
{
var
length
,
dist
,
offs
;
var
i
;
sym
-=
257
;
/* possibly get more bits from length code */
length
=
this
.
read_bits
(
d
,
this
.
length_bits
[
sym
],
this
.
length_base
[
sym
]);
dist
=
this
.
decode_symbol
(
d
,
dt
);
/* possibly get more bits from distance code */
offs
=
d
.
history
.
length
-
this
.
read_bits
(
d
,
this
.
dist_bits
[
dist
],
this
.
dist_base
[
dist
]);
if
(
offs
<
0
)
throw
(
"Invalid zlib offset "
+
offs
);
/* copy match */
for
(
i
=
offs
;
i
<
offs
+
length
;
++
i
)
{
//ddest[ddestlength++] = ddest[i];
ddest
[
ddestlength
++
]
=
d
.
history
[
i
];
d
.
history
.
push
(
d
.
history
[
i
]);
}
}
}
}
/* inflate an uncompressed block of data */
this
.
inflate_uncompressed_block
=
function
(
d
)
{
var
length
,
invlength
;
var
i
;
if
(
d
.
bitcount
>
7
)
{
var
overflow
=
Math
.
floor
(
d
.
bitcount
/
8
);
d
.
sourceIndex
-=
overflow
;
d
.
bitcount
=
0
;
d
.
tag
=
0
;
}
/* get length */
length
=
d
.
source
[
d
.
sourceIndex
+
1
];
length
=
256
*
length
+
d
.
source
[
d
.
sourceIndex
];
/* get one's complement of length */
invlength
=
d
.
source
[
d
.
sourceIndex
+
3
];
invlength
=
256
*
invlength
+
d
.
source
[
d
.
sourceIndex
+
2
];
/* check length */
if
(
length
!=
(
~
invlength
&
0x0000ffff
))
return
this
.
DATA_ERROR
;
d
.
sourceIndex
+=
4
;
/* copy block */
for
(
i
=
length
;
i
;
--
i
)
{
d
.
history
.
push
(
d
.
source
[
d
.
sourceIndex
]);
d
.
dest
[
d
.
dest
.
length
]
=
d
.
source
[
d
.
sourceIndex
++
];
}
/* make sure we start next block on a byte boundary */
d
.
bitcount
=
0
;
return
this
.
OK
;
}
/* inflate a block of data compressed with fixed huffman trees */
this
.
inflate_fixed_block
=
function
(
d
)
{
/* decode block using fixed trees */
return
this
.
inflate_block_data
(
d
,
this
.
sltree
,
this
.
sdtree
);
}
/* inflate a block of data compressed with dynamic huffman trees */
this
.
inflate_dynamic_block
=
function
(
d
)
{
/* decode trees from stream */
this
.
decode_trees
(
d
,
d
.
ltree
,
d
.
dtree
);
/* decode block using decoded trees */
return
this
.
inflate_block_data
(
d
,
d
.
ltree
,
d
.
dtree
);
}
/* ---------------------- *
* -- public functions -- *
* ---------------------- */
/* initialize global (static) data */
this
.
init
=
function
()
{
/* build fixed huffman trees */
this
.
build_fixed_trees
(
this
.
sltree
,
this
.
sdtree
);
/* build extra bits and base tables */
this
.
build_bits_base
(
this
.
length_bits
,
this
.
length_base
,
4
,
3
);
this
.
build_bits_base
(
this
.
dist_bits
,
this
.
dist_base
,
2
,
1
);
/* fix a special case */
this
.
length_bits
[
28
]
=
0
;
this
.
length_base
[
28
]
=
258
;
this
.
reset
();
}
this
.
reset
=
function
()
{
this
.
d
=
new
this
.
DATA
(
this
);
delete
this
.
header
;
}
/* inflate stream from source to dest */
this
.
uncompress
=
function
(
source
,
offset
)
{
var
d
=
this
.
d
;
var
bfinal
;
/* initialise data */
d
.
source
=
source
;
d
.
sourceIndex
=
offset
;
d
.
bitcount
=
0
;
d
.
dest
=
[];
// Skip zlib header at start of stream
if
(
typeof
this
.
header
==
'undefined'
)
{
this
.
header
=
this
.
read_bits
(
d
,
16
,
0
);
/* byte 0: 0x78, 7 = 32k window size, 8 = deflate */
/* byte 1: check bits for header and other flags */
}
var
blocks
=
0
;
do
{
var
btype
;
var
res
;
/* read final block flag */
bfinal
=
this
.
getbit
(
d
);
/* read block type (2 bits) */
btype
=
this
.
read_bits
(
d
,
2
,
0
);
/* decompress block */
switch
(
btype
)
{
case
0
:
/* decompress uncompressed block */
res
=
this
.
inflate_uncompressed_block
(
d
);
break
;
case
1
:
/* decompress block with fixed huffman trees */
res
=
this
.
inflate_fixed_block
(
d
);
break
;
case
2
:
/* decompress block with dynamic huffman trees */
res
=
this
.
inflate_dynamic_block
(
d
);
break
;
default
:
return
{
'status'
:
this
.
DATA_ERROR
};
}
if
(
res
!=
this
.
OK
)
return
{
'status'
:
this
.
DATA_ERROR
};
blocks
++
;
}
while
(
!
bfinal
&&
d
.
sourceIndex
<
d
.
source
.
length
);
d
.
history
=
d
.
history
.
slice
(
-
this
.
WINDOW_SIZE
);
return
{
'status'
:
this
.
OK
,
'data'
:
d
.
dest
};
}
};
include/rfb.js
View file @
35d7574b
...
...
@@ -4,6 +4,9 @@
* Licensed under LGPL-3 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
* TIGHT decoder portion:
* (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
*/
/*jslint white: false, browser: true, bitwise: false, plusplus: false */
...
...
@@ -46,6 +49,7 @@ var that = {}, // Public API methods
// In preference order
encodings
=
[
[
'COPYRECT'
,
0x01
],
[
'TIGHT'
,
0x07
],
[
'TIGHT_PNG'
,
-
260
],
[
'HEXTILE'
,
0x05
],
[
'RRE'
,
0x02
],
...
...
@@ -54,10 +58,12 @@ var that = {}, // Public API methods
[
'Cursor'
,
-
239
],
// Psuedo-encoding settings
[
'JPEG_quality_lo'
,
-
32
],
//['JPEG_quality_lo', -32 ],
[
'JPEG_quality_med'
,
-
26
],
//['JPEG_quality_hi', -23 ],
[
'compress_lo'
,
-
255
]
//['compress_hi', -247 ]
//['compress_lo', -255 ],
[
'compress_hi'
,
-
247
],
[
'last_rect'
,
-
224
]
],
encHandlers
=
{},
...
...
@@ -87,7 +93,9 @@ var that = {}, // Public API methods
encoding
:
0
,
subencoding
:
-
1
,
background
:
null
,
imgQ
:
[]
// TIGHT_PNG image queue
imgQ
:
[],
// TIGHT_PNG image queue
zlibs
:
[],
// TIGHT zlib streams
palette
:
null
},
fb_Bpp
=
4
,
...
...
@@ -270,14 +278,18 @@ function constructor() {
function
connect
()
{
Util
.
Debug
(
">> RFB.connect"
);
var
uri
=
""
;
if
(
conf
.
encrypt
)
{
uri
=
"
wss://"
;
var
uri
;
if
(
typeof
UsingSocketIO
!==
"undefined"
)
{
uri
=
"
http://"
+
rfb_host
+
":"
+
rfb_port
+
"/"
+
rfb_path
;
}
else
{
uri
=
"ws://"
;
if
(
conf
.
encrypt
)
{
uri
=
"wss://"
;
}
else
{
uri
=
"ws://"
;
}
uri
+=
rfb_host
+
":"
+
rfb_port
+
"/"
+
rfb_path
;
}
uri
+=
rfb_host
+
":"
+
rfb_port
+
"/"
+
rfb_path
;
Util
.
Info
(
"connecting to "
+
uri
);
ws
.
open
(
uri
);
...
...
@@ -296,6 +308,7 @@ init_vars = function() {
FBU
.
lines
=
0
;
// RAW
FBU
.
tiles
=
0
;
// HEXTILE
FBU
.
imgQ
=
[];
// TIGHT_PNG image queue
FBU
.
zlibs
=
[];
// TIGHT zlib encoders
mouse_buttonMask
=
0
;
mouse_arr
=
[];
...
...
@@ -303,6 +316,12 @@ init_vars = function() {
for
(
i
=
0
;
i
<
encodings
.
length
;
i
+=
1
)
{
encStats
[
encodings
[
i
][
1
]][
0
]
=
0
;
}
for
(
i
=
0
;
i
<
4
;
i
++
)
{
//FBU.zlibs[i] = new InflateStream();
FBU
.
zlibs
[
i
]
=
new
TINF
();
FBU
.
zlibs
[
i
].
init
();
}
};
// Print statistics
...
...
@@ -976,6 +995,11 @@ framebufferUpdate = function() {
'encoding'
:
FBU
.
encoding
,
'encodingName'
:
encNames
[
FBU
.
encoding
]});
if
(
encNames
[
FBU
.
encoding
]
==
'last_rect'
)
{
FBU
.
rects
=
0
;
break
;
}
if
(
encNames
[
FBU
.
encoding
])
{
// Debug:
/*
...
...
@@ -1257,6 +1281,248 @@ encHandlers.HEXTILE = function display_hextile() {
};
encHandlers
.
TIGHT
=
function
display_tight
()
{
Util
.
Debug
(
">> display_tight"
);
if
(
fb_depth
==
1
)
{
fail
(
"Tight protocol handler only implements true color mode"
);
}
var
ctl
,
cmode
,
clength
,
getCLength
,
color
,
img
,
data
;
var
filterId
=
-
1
,
resetStreams
=
0
,
streamId
=
-
1
;
var
rQ
=
ws
.
get_rQ
(),
rQi
=
ws
.
get_rQi
();
FBU
.
bytes
=
1
;
// compression-control byte
if
(
ws
.
rQwait
(
"TIGHT compression-control"
,
FBU
.
bytes
))
{
return
false
;
}
// Get 'compact length' header and data size
getCLength
=
function
(
arr
)
{
var
header
=
1
,
data
=
0
;
data
+=
arr
[
0
]
&
0x7f
;
if
(
arr
[
0
]
&
0x80
)
{
header
+=
1
;
data
+=
(
arr
[
1
]
&
0x7f
)
<<
7
;
if
(
arr
[
1
]
&
0x80
)
{
header
+=
1
;
data
+=
arr
[
2
]
<<
14
;
}
}
return
[
header
,
data
];
};
var
checksum
=
function
(
data
)
{
var
sum
=
0
,
i
;
for
(
i
=
0
;
i
<
data
.
length
;
i
++
)
{
sum
+=
data
[
i
];
if
(
sum
>
65536
)
sum
-=
65536
;
}
return
sum
;
}
var
decompress
=
function
(
data
)
{
for
(
var
i
=
0
;
i
<
4
;
i
++
)
{
if
((
resetStreams
>>
i
)
&
1
)
{
FBU
.
zlibs
[
i
].
reset
();
Util
.
Info
(
"Reset zlib stream "
+
i
);
}
}
var
uncompressed
=
FBU
.
zlibs
[
streamId
].
uncompress
(
data
,
0
);
if
(
uncompressed
.
status
!==
0
)
Util
.
Error
(
"Invalid data in zlib stream"
);
//Util.Warn("Decompressed " + data.length + " to " + uncompressed.data.length + " checksums " +
// checksum(data) + ":" + checksum(uncompressed.data));
return
uncompressed
.
data
;
}
var
handlePalette
=
function
()
{
var
numColors
=
rQ
[
rQi
+
2
]
+
1
;
var
paletteSize
=
numColors
*
fb_depth
;
FBU
.
bytes
+=
paletteSize
;
if
(
ws
.
rQwait
(
"TIGHT palette "
+
cmode
,
FBU
.
bytes
))
{
return
false
;
}
var
bpp
=
(
numColors
<=
2
)
?
1
:
8
;
var
rowSize
=
Math
.
floor
((
FBU
.
width
*
bpp
+
7
)
/
8
);
var
raw
=
false
;
if
(
rowSize
*
FBU
.
height
<
12
)
{
raw
=
true
;
clength
=
[
0
,
rowSize
*
FBU
.
height
];
}
else
clength
=
getCLength
(
ws
.
rQslice
(
3
+
paletteSize
,
3
+
paletteSize
+
3
));
FBU
.
bytes
+=
clength
[
0
]
+
clength
[
1
];
if
(
ws
.
rQwait
(
"TIGHT "
+
cmode
,
FBU
.
bytes
))
{
return
false
;
}
// Shift ctl, filter id, num colors, palette entries, and clength off
ws
.
rQshiftBytes
(
3
);
FBU
.
palette
=
ws
.
rQshiftBytes
(
paletteSize
);
ws
.
rQshiftBytes
(
clength
[
0
]);
if
(
raw
)
data
=
ws
.
rQshiftBytes
(
clength
[
1
]);
else
data
=
decompress
(
ws
.
rQshiftBytes
(
clength
[
1
]));
// Convert indexed (palette based) image data to RGB
// TODO: reduce number of calculations inside loop
var
dest
=
[];
var
x
,
y
,
b
;
if
(
numColors
==
2
)
{
var
w
=
Math
.
floor
((
FBU
.
width
+
7
)
/
8
);
var
w1
=
Math
.
floor
(
FBU
.
width
/
8
);
for
(
y
=
0
;
y
<
FBU
.
height
;
y
++
)
{
for
(
x
=
0
;
x
<
w1
;
x
++
)
{
for
(
b
=
7
;
b
>=
0
;
b
--
)
{
var
dp
=
(
y
*
FBU
.
width
+
x
*
8
+
7
-
b
)
*
3
;
var
sp
=
(
data
[
y
*
w
+
x
]
>>
b
&
1
)
*
3
;
dest
[
dp
]
=
FBU
.
palette
[
sp
];
dest
[
dp
+
1
]
=
FBU
.
palette
[
sp
+
1
];
dest
[
dp
+
2
]
=
FBU
.
palette
[
sp
+
2
];
}
}
for
(
b
=
7
;
b
>=
8
-
FBU
.
width
%
8
;
b
--
)
{
var
dp
=
(
y
*
FBU
.
width
+
x
*
8
+
7
-
b
)
*
3
;
var
sp
=
(
data
[
y
*
w
+
x
]
>>
b
&
1
)
*
3
;
dest
[
dp
]
=
FBU
.
palette
[
sp
];
dest
[
dp
+
1
]
=
FBU
.
palette
[
sp
+
1
];
dest
[
dp
+
2
]
=
FBU
.
palette
[
sp
+
2
];
}
}
}
else
{
for
(
y
=
0
;
y
<
FBU
.
height
;
y
++
)
{
for
(
x
=
0
;
x
<
FBU
.
width
;
x
++
)
{
var
dp
=
(
y
*
FBU
.
width
+
x
)
*
3
;
var
sp
=
data
[
y
*
FBU
.
width
+
x
]
*
3
;
dest
[
dp
]
=
FBU
.
palette
[
sp
];
dest
[
dp
+
1
]
=
FBU
.
palette
[
sp
+
1
];
dest
[
dp
+
2
]
=
FBU
.
palette
[
sp
+
2
];
}
}
}
FBU
.
imgQ
.
push
({
'type'
:
'rgb'
,
'img'
:
{
'complete'
:
true
,
'data'
:
dest
},
'x'
:
FBU
.
x
,
'y'
:
FBU
.
y
,
'width'
:
FBU
.
width
,
'height'
:
FBU
.
height
});
return
true
;
}
var
handleCopy
=
function
()
{
var
raw
=
false
;
var
uncompressedSize
=
FBU
.
width
*
FBU
.
height
*
fb_depth
;
if
(
uncompressedSize
<
12
)
{
raw
=
true
;
clength
=
[
0
,
uncompressedSize
];
}
else
clength
=
getCLength
(
ws
.
rQslice
(
1
,
4
));
FBU
.
bytes
=
1
+
clength
[
0
]
+
clength
[
1
];
if
(
ws
.
rQwait
(
"TIGHT "
+
cmode
,
FBU
.
bytes
))
{
return
false
;
}
// Shift ctl, clength off
ws
.
rQshiftBytes
(
1
+
clength
[
0
]);
if
(
raw
)
data
=
ws
.
rQshiftBytes
(
clength
[
1
]);
else
data
=
decompress
(
ws
.
rQshiftBytes
(
clength
[
1
]));
FBU
.
imgQ
.
push
({
'type'
:
'rgb'
,
'img'
:
{
'complete'
:
true
,
'data'
:
data
},
'x'
:
FBU
.
x
,
'y'
:
FBU
.
y
,
'width'
:
FBU
.
width
,
'height'
:
FBU
.
height
});
return
true
;
}
ctl
=
ws
.
rQpeek8
();
// Keep tight reset bits
resetStreams
=
ctl
&
0xF
;
// Figure out filter
ctl
=
ctl
>>
4
;
streamId
=
ctl
&
0x3
;
if
(
ctl
==
0x08
)
cmode
=
"fill"
;
else
if
(
ctl
==
0x09
)
cmode
=
"jpeg"
;
else
if
(
ctl
&
0x04
)
cmode
=
"filter"
;
else
if
(
ctl
<
0x04
)
cmode
=
"copy"
;
else
throw
(
"Illegal tight compression received, ctl: "
+
ctl
);
switch
(
cmode
)
{
// fill uses fb_depth because TPIXELs drop the padding byte
case
"fill"
:
FBU
.
bytes
+=
fb_depth
;
break
;
// TPIXEL
case
"jpeg"
:
FBU
.
bytes
+=
3
;
break
;
// max clength
case
"filter"
:
FBU
.
bytes
+=
2
;
break
;
// filter id + num colors if palette
case
"copy"
:
break
;
}
if
(
ws
.
rQwait
(
"TIGHT "
+
cmode
,
FBU
.
bytes
))
{
return
false
;
}
//Util.Debug(" ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
//Util.Debug(" cmode: " + cmode);
// Determine FBU.bytes
switch
(
cmode
)
{
case
"fill"
:
ws
.
rQshift8
();
// shift off ctl
color
=
ws
.
rQshiftBytes
(
fb_depth
);
FBU
.
imgQ
.
push
({
'type'
:
'fill'
,
'img'
:
{
'complete'
:
true
},
'x'
:
FBU
.
x
,
'y'
:
FBU
.
y
,
'width'
:
FBU
.
width
,
'height'
:
FBU
.
height
,
'color'
:
[
color
[
2
],
color
[
1
],
color
[
0
]]
});
break
;
case
"jpeg"
:
clength
=
getCLength
(
ws
.
rQslice
(
1
,
4
));
FBU
.
bytes
=
1
+
clength
[
0
]
+
clength
[
1
];
// ctl + clength size + jpeg-data
if
(
ws
.
rQwait
(
"TIGHT "
+
cmode
,
FBU
.
bytes
))
{
return
false
;
}
// We have everything, render it
//Util.Debug(" png, ws.rQlen(): " + ws.rQlen() + ", clength[0]: " + clength[0] + ", clength[1]: " + clength[1]);
ws
.
rQshiftBytes
(
1
+
clength
[
0
]);
// shift off ctl + compact length
img
=
new
Image
();
//img.onload = scan_tight_imgQ;
FBU
.
imgQ
.
push
({
'type'
:
'img'
,
'img'
:
img
,
'x'
:
FBU
.
x
,
'y'
:
FBU
.
y
});
img
.
src
=
"data:image/"
+
cmode
+
extract_data_uri
(
ws
.
rQshiftBytes
(
clength
[
1
]));
img
=
null
;
break
;
case
"filter"
:
filterId
=
rQ
[
rQi
+
1
];
if
(
filterId
==
1
)
{
if
(
!
handlePalette
())
{
return
false
;
}
}
else
{
// Filter 0, Copy could be valid here, but servers don't send it as an explicit filter
// Filter 2, Gradient is valid but not used if jpeg is enabled
throw
(
"Unsupported tight subencoding received, filter: "
+
filterId
);
}
break
;
case
"copy"
:
if
(
!
handleCopy
())
{
return
false
;
}
break
;
}
FBU
.
bytes
=
0
;
FBU
.
rects
-=
1
;
//Util.Debug(" ending ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
//Util.Debug("<< display_tight_png");
return
true
;
};
encHandlers
.
TIGHT_PNG
=
function
display_tight_png
()
{
//Util.Debug(">> display_tight_png");
var
ctl
,
cmode
,
clength
,
getCLength
,
color
,
img
;
...
...
@@ -1360,6 +1626,8 @@ scan_tight_imgQ = function() {
data
=
imgQ
.
shift
();
if
(
data
.
type
===
'fill'
)
{
display
.
fillRect
(
data
.
x
,
data
.
y
,
data
.
width
,
data
.
height
,
data
.
color
);
}
else
if
(
data
.
type
===
'rgb'
)
{
display
.
blitRgbImage
(
data
.
x
,
data
.
y
,
data
.
width
,
data
.
height
,
data
.
img
.
data
,
0
);
}
else
{
ctx
.
drawImage
(
data
.
img
,
data
.
x
,
data
.
y
);
}
...
...
include/vnc.js
View file @
35d7574b
...
...
@@ -32,10 +32,13 @@ function get_INCLUDE_URI() {
extra
+=
start
+
"webutil.js"
+
end
;
extra
+=
start
+
"base64.js"
+
end
;
extra
+=
start
+
"websock.js"
+
end
;
// extra += start + "socketio.js" + end;
extra
+=
start
+
"des.js"
+
end
;
extra
+=
start
+
"input.js"
+
end
;
extra
+=
start
+
"display.js"
+
end
;
extra
+=
start
+
"blowfish.js"
+
end
;
extra
+=
start
+
"rfb.js"
+
end
;
extra
+=
start
+
"jsunzip.js"
+
end
;
document
.
write
(
extra
);
}());
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment