mirror of
https://github.com/Cateners/tiny_computer.git
synced 2026-05-20 16:35:47 +08:00
Update code to v1.0.14 (10)
This commit is contained in:
315
android/extern/libvncserver/src/common/base64.c
vendored
Normal file
315
android/extern/libvncserver/src/common/base64.c
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 1995 by International Business Machines, Inc.
|
||||
*
|
||||
* International Business Machines, Inc. (hereinafter called IBM) grants
|
||||
* permission under its copyrights to use, copy, modify, and distribute this
|
||||
* Software with or without fee, provided that the above copyright notice and
|
||||
* all paragraphs of this notice appear in all copies, and that the name of IBM
|
||||
* not be used in connection with the marketing of any product incorporating
|
||||
* the Software or modifications thereof, without specific, written prior
|
||||
* permission.
|
||||
*
|
||||
* To the extent it has a right to do so, IBM grants an immunity from suit
|
||||
* under its patents, if any, for the use, sale or manufacture of products to
|
||||
* the extent that such products are used for performing Domain Name System
|
||||
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
|
||||
* granted for any product per se or for any other function of any product.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
|
||||
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
|
||||
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <resolv.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char Base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char Pad64 = '=';
|
||||
|
||||
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
|
||||
The following encoding technique is taken from RFC 1521 by Borenstein
|
||||
and Freed. It is reproduced here in a slightly edited form for
|
||||
convenience.
|
||||
|
||||
A 65-character subset of US-ASCII is used, enabling 6 bits to be
|
||||
represented per printable character. (The extra 65th character, "=",
|
||||
is used to signify a special processing function.)
|
||||
|
||||
The encoding process represents 24-bit groups of input bits as output
|
||||
strings of 4 encoded characters. Proceeding from left to right, a
|
||||
24-bit input group is formed by concatenating 3 8-bit input groups.
|
||||
These 24 bits are then treated as 4 concatenated 6-bit groups, each
|
||||
of which is translated into a single digit in the base64 alphabet.
|
||||
|
||||
Each 6-bit group is used as an index into an array of 64 printable
|
||||
characters. The character referenced by the index is placed in the
|
||||
output string.
|
||||
|
||||
Table 1: The Base64 Alphabet
|
||||
|
||||
Value Encoding Value Encoding Value Encoding Value Encoding
|
||||
0 A 17 R 34 i 51 z
|
||||
1 B 18 S 35 j 52 0
|
||||
2 C 19 T 36 k 53 1
|
||||
3 D 20 U 37 l 54 2
|
||||
4 E 21 V 38 m 55 3
|
||||
5 F 22 W 39 n 56 4
|
||||
6 G 23 X 40 o 57 5
|
||||
7 H 24 Y 41 p 58 6
|
||||
8 I 25 Z 42 q 59 7
|
||||
9 J 26 a 43 r 60 8
|
||||
10 K 27 b 44 s 61 9
|
||||
11 L 28 c 45 t 62 +
|
||||
12 M 29 d 46 u 63 /
|
||||
13 N 30 e 47 v
|
||||
14 O 31 f 48 w (pad) =
|
||||
15 P 32 g 49 x
|
||||
16 Q 33 h 50 y
|
||||
|
||||
Special processing is performed if fewer than 24 bits are available
|
||||
at the end of the data being encoded. A full encoding quantum is
|
||||
always completed at the end of a quantity. When fewer than 24 input
|
||||
bits are available in an input group, zero bits are added (on the
|
||||
right) to form an integral number of 6-bit groups. Padding at the
|
||||
end of the data is performed using the '=' character.
|
||||
|
||||
Since all base64 input is an integral number of octets, only the
|
||||
-------------------------------------------------
|
||||
following cases can arise:
|
||||
|
||||
(1) the final quantum of encoding input is an integral
|
||||
multiple of 24 bits; here, the final unit of encoded
|
||||
output will be an integral multiple of 4 characters
|
||||
with no "=" padding,
|
||||
(2) the final quantum of encoding input is exactly 8 bits;
|
||||
here, the final unit of encoded output will be two
|
||||
characters followed by two "=" padding characters, or
|
||||
(3) the final quantum of encoding input is exactly 16 bits;
|
||||
here, the final unit of encoded output will be three
|
||||
characters followed by one "=" padding character.
|
||||
*/
|
||||
|
||||
int
|
||||
__b64_ntop(src, srclength, target, targsize)
|
||||
u_char const *src;
|
||||
size_t srclength;
|
||||
char *target;
|
||||
size_t targsize;
|
||||
{
|
||||
size_t datalength = 0;
|
||||
u_char input[3];
|
||||
u_char output[4];
|
||||
int i;
|
||||
|
||||
while (2 < srclength) {
|
||||
input[0] = *src++;
|
||||
input[1] = *src++;
|
||||
input[2] = *src++;
|
||||
srclength -= 3;
|
||||
|
||||
output[0] = input[0] >> 2;
|
||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||
output[3] = input[2] & 0x3f;
|
||||
|
||||
if (datalength + 4 > targsize)
|
||||
return (-1);
|
||||
target[datalength++] = Base64[output[0]];
|
||||
target[datalength++] = Base64[output[1]];
|
||||
target[datalength++] = Base64[output[2]];
|
||||
target[datalength++] = Base64[output[3]];
|
||||
}
|
||||
|
||||
/* Now we worry about padding. */
|
||||
if (0 != srclength) {
|
||||
/* Get what's left. */
|
||||
input[0] = input[1] = input[2] = '\0';
|
||||
for (i = 0; i < srclength; i++)
|
||||
input[i] = *src++;
|
||||
|
||||
output[0] = input[0] >> 2;
|
||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||
|
||||
if (datalength + 4 > targsize)
|
||||
return (-1);
|
||||
target[datalength++] = Base64[output[0]];
|
||||
target[datalength++] = Base64[output[1]];
|
||||
if (srclength == 1)
|
||||
target[datalength++] = Pad64;
|
||||
else
|
||||
target[datalength++] = Base64[output[2]];
|
||||
target[datalength++] = Pad64;
|
||||
}
|
||||
if (datalength >= targsize)
|
||||
return (-1);
|
||||
target[datalength] = '\0'; /* Returned value doesn't count \0. */
|
||||
return (datalength);
|
||||
}
|
||||
|
||||
/* skips all whitespace anywhere.
|
||||
converts characters, four at a time, starting at (or after)
|
||||
src from base - 64 numbers into three 8 bit bytes in the target area.
|
||||
it returns the number of data bytes stored at the target, or -1 on error.
|
||||
*/
|
||||
|
||||
int
|
||||
__b64_pton(src, target, targsize)
|
||||
char const *src;
|
||||
u_char *target;
|
||||
size_t targsize;
|
||||
{
|
||||
int tarindex, state, ch;
|
||||
u_char nextbyte;
|
||||
char *pos;
|
||||
|
||||
state = 0;
|
||||
tarindex = 0;
|
||||
|
||||
while ((ch = (unsigned char)*src++) != '\0') {
|
||||
if (isspace(ch)) /* Skip whitespace anywhere. */
|
||||
continue;
|
||||
|
||||
if (ch == Pad64)
|
||||
break;
|
||||
|
||||
pos = strchr(Base64, ch);
|
||||
if (pos == 0) /* A non-base64 character. */
|
||||
return (-1);
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (target) {
|
||||
if (tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] = (pos - Base64) << 2;
|
||||
}
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
if (target) {
|
||||
if (tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base64) >> 4;
|
||||
nextbyte = ((pos - Base64) & 0x0f) << 4;
|
||||
if (tarindex + 1 < targsize)
|
||||
target[tarindex+1] = nextbyte;
|
||||
else if (nextbyte)
|
||||
return (-1);
|
||||
}
|
||||
tarindex++;
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
if (target) {
|
||||
if (tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base64) >> 2;
|
||||
nextbyte = ((pos - Base64) & 0x03) << 6;
|
||||
if (tarindex + 1 < targsize)
|
||||
target[tarindex+1] = nextbyte;
|
||||
else if (nextbyte)
|
||||
return (-1);
|
||||
}
|
||||
tarindex++;
|
||||
state = 3;
|
||||
break;
|
||||
case 3:
|
||||
if (target) {
|
||||
if (tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base64);
|
||||
}
|
||||
tarindex++;
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We are done decoding Base-64 chars. Let's see if we ended
|
||||
* on a byte boundary, and/or with erroneous trailing characters.
|
||||
*/
|
||||
|
||||
if (ch == Pad64) { /* We got a pad char. */
|
||||
ch = (unsigned char)*src++; /* Skip it, get next. */
|
||||
switch (state) {
|
||||
case 0: /* Invalid = in first position */
|
||||
case 1: /* Invalid = in second position */
|
||||
return (-1);
|
||||
|
||||
case 2: /* Valid, means one byte of info */
|
||||
/* Skip any number of spaces. */
|
||||
for (; ch != '\0'; ch = (unsigned char)*src++)
|
||||
if (!isspace(ch))
|
||||
break;
|
||||
/* Make sure there is another trailing = sign. */
|
||||
if (ch != Pad64)
|
||||
return (-1);
|
||||
ch = (unsigned char)*src++; /* Skip the = */
|
||||
/* Fall through to "single trailing =" case. */
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case 3: /* Valid, means two bytes of info */
|
||||
/*
|
||||
* We know this char is an =. Is there anything but
|
||||
* whitespace after it?
|
||||
*/
|
||||
for (; ch != '\0'; ch = (unsigned char)*src++)
|
||||
if (!isspace(ch))
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Now make sure for cases 2 and 3 that the "extra"
|
||||
* bits that slopped past the last full byte were
|
||||
* zeros. If we don't check them, they become a
|
||||
* subliminal channel.
|
||||
*/
|
||||
if (target && tarindex < targsize &&
|
||||
target[tarindex] != 0)
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We ended by seeing the end of the string. Make sure we
|
||||
* have no partial bytes lying around.
|
||||
*/
|
||||
if (state != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (tarindex);
|
||||
}
|
||||
10
android/extern/libvncserver/src/common/base64.h
vendored
Normal file
10
android/extern/libvncserver/src/common/base64.h
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef _BASE64_H
|
||||
#define _BASE64_H
|
||||
|
||||
extern int __b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize);
|
||||
extern int __b64_pton(char const *src, u_char *target, size_t targsize);
|
||||
|
||||
#define rfbBase64NtoP __b64_ntop
|
||||
#define rfbBase64PtoN __b64_pton
|
||||
|
||||
#endif /* _BASE64_H */
|
||||
46
android/extern/libvncserver/src/common/crypto.h
vendored
Normal file
46
android/extern/libvncserver/src/common/crypto.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _RFB_CRYPTO_H
|
||||
#define _RFB_CRYPTO_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rfb/rfbconfig.h"
|
||||
|
||||
#define SHA1_HASH_SIZE 20
|
||||
#define MD5_HASH_SIZE 16
|
||||
|
||||
/* Generates an MD5 hash of 'in' and writes it to 'out', which must be 16 bytes in size. */
|
||||
int hash_md5(void *out, const void *in, const size_t in_len);
|
||||
|
||||
/* Generates an SHA1 hash of 'in' and writes it to 'out', which must be 20 bytes in size. */
|
||||
int hash_sha1(void *out, const void *in, const size_t in_len);
|
||||
|
||||
/* Fill 'out' with 'len' random bytes. */
|
||||
void random_bytes(void *out, size_t len);
|
||||
|
||||
/*
|
||||
Takes the 8-byte key in 'key', reverses the bits in each byte of key as required by the RFB protocol,
|
||||
encrypts 'in' with the resulting key using single-key 56-bit DES and writes the result to 'out'.
|
||||
*/
|
||||
int encrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len);
|
||||
|
||||
/*
|
||||
Takes the 8-byte key in 'key', reverses the bits in each byte of key as required by the RFB protocol,
|
||||
decrypts 'in' with the resulting key using single-key 56-bit DES and writes the result to 'out'.
|
||||
*/
|
||||
int decrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len);
|
||||
|
||||
/* Encrypts 'in' with the the 16-byte key in 'key' using AES-128-ECB and writes the result to 'out'. */
|
||||
int encrypt_aes128ecb(void *out, int *out_len, const unsigned char key[16], const void *in, const size_t in_len);
|
||||
|
||||
/*
|
||||
Generates a Diffie-Hellman public-private keypair using the generator value 'gen' and prime modulo
|
||||
'prime', writing the result to 'pub_out' and 'priv_out', which must be 'keylen' in size.
|
||||
*/
|
||||
int dh_generate_keypair(uint8_t *priv_out, uint8_t *pub_out, const uint8_t *gen, const size_t gen_len, const uint8_t *prime, const size_t keylen);
|
||||
|
||||
/*
|
||||
Computes the shared Diffie-Hellman secret using the private key 'priv', the other side's public
|
||||
key 'pub' and the modulo prime 'prime' and writes it to 'shared_out', which must be 'keylen' in size.
|
||||
*/
|
||||
int dh_compute_shared_key(uint8_t *shared_out, const uint8_t *priv, const uint8_t *pub, const uint8_t *prime, const size_t keylen);
|
||||
|
||||
#endif
|
||||
93
android/extern/libvncserver/src/common/crypto_included.c
vendored
Normal file
93
android/extern/libvncserver/src/common/crypto_included.c
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* crypto_included.c - Crypto wrapper (included version)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011 Gernot Tenchio
|
||||
* Copyright (C) 2019 Christian Beier
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "sha.h"
|
||||
#include "d3des.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
int hash_md5(void *out, const void *in, const size_t in_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hash_sha1(void *out, const void *in, const size_t in_len)
|
||||
{
|
||||
SHA1Context sha1;
|
||||
if(SHA1Reset(&sha1) != shaSuccess)
|
||||
return 0;
|
||||
if(SHA1Input(&sha1, in, in_len) != shaSuccess)
|
||||
return 0;
|
||||
if(SHA1Result(&sha1, out) != shaSuccess)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void random_bytes(void *out, size_t len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int encrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len)
|
||||
{
|
||||
int eightbyteblocks = in_len/8;
|
||||
int i;
|
||||
rfbDesKey((unsigned char*)key, EN0);
|
||||
for(i = 0; i < eightbyteblocks; ++i)
|
||||
rfbDes((unsigned char*)in + i*8, (unsigned char*)out + i*8);
|
||||
|
||||
*out_len = in_len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int decrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len)
|
||||
{
|
||||
int eightbyteblocks = in_len/8;
|
||||
int i;
|
||||
rfbDesKey((unsigned char*)key, DE1);
|
||||
for(i = 0; i < eightbyteblocks; ++i)
|
||||
rfbDes((unsigned char*)in + i*8, (unsigned char*)out + i*8);
|
||||
|
||||
*out_len = in_len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int encrypt_aes128ecb(void *out, int *out_len, const unsigned char key[16], const void *in, const size_t in_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dh_generate_keypair(uint8_t *priv_out, uint8_t *pub_out, const uint8_t *gen, const size_t gen_len, const uint8_t *prime, const size_t keylen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dh_compute_shared_key(uint8_t *shared_out, const uint8_t *priv, const uint8_t *pub, const uint8_t *prime, const size_t keylen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
271
android/extern/libvncserver/src/common/crypto_libgcrypt.c
vendored
Normal file
271
android/extern/libvncserver/src/common/crypto_libgcrypt.c
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* crypto_gnutls.c - Crypto wrapper (libgcrypt version)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011 Gernot Tenchio
|
||||
* Copyright (C) 2019 Christian Beier
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gcrypt.h>
|
||||
#include "crypto.h"
|
||||
|
||||
static int mpiToBytes(const gcry_mpi_t value, uint8_t *result, size_t size)
|
||||
{
|
||||
gcry_error_t error;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
error = gcry_mpi_print(GCRYMPI_FMT_USG, result, size, &len, value);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
return 0;
|
||||
for (i=size-1;i>(int)size-1-(int)len;--i)
|
||||
result[i] = result[i-size+len];
|
||||
for (;i>=0;--i)
|
||||
result[i] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned char reverseByte(unsigned char b) {
|
||||
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
int hash_md5(void *out, const void *in, const size_t in_len)
|
||||
{
|
||||
int result = 0;
|
||||
gcry_error_t error;
|
||||
gcry_md_hd_t md5 = NULL;
|
||||
void *digest;
|
||||
|
||||
error = gcry_md_open(&md5, GCRY_MD_MD5, 0);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
gcry_md_write(md5, in, in_len);
|
||||
|
||||
if(!(digest = gcry_md_read(md5, GCRY_MD_MD5)))
|
||||
goto out;
|
||||
|
||||
memcpy(out, digest, gcry_md_get_algo_dlen(GCRY_MD_MD5));
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
gcry_md_close(md5);
|
||||
return result;
|
||||
}
|
||||
|
||||
int hash_sha1(void *out, const void *in, const size_t in_len)
|
||||
{
|
||||
int result = 0;
|
||||
gcry_error_t error;
|
||||
gcry_md_hd_t sha1 = NULL;
|
||||
void *digest;
|
||||
|
||||
error = gcry_md_open(&sha1, GCRY_MD_SHA1, 0);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
gcry_md_write(sha1, in, in_len);
|
||||
|
||||
if(!(digest = gcry_md_read(sha1, GCRY_MD_SHA1)))
|
||||
goto out;
|
||||
|
||||
memcpy(out, digest, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
gcry_md_close(sha1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void random_bytes(void *out, size_t len)
|
||||
{
|
||||
gcry_randomize(out, len, GCRY_STRONG_RANDOM);
|
||||
}
|
||||
|
||||
int encrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len)
|
||||
{
|
||||
int result = 0;
|
||||
gcry_error_t error;
|
||||
gcry_cipher_hd_t des = NULL;
|
||||
unsigned char mungedkey[8];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
mungedkey[i] = reverseByte(key[i]);
|
||||
|
||||
error = gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
error = gcry_cipher_setkey(des, mungedkey, 8);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
error = gcry_cipher_encrypt(des, out, in_len, in, in_len);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
*out_len = in_len;
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
gcry_cipher_close(des);
|
||||
return result;
|
||||
}
|
||||
|
||||
int decrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len)
|
||||
{
|
||||
int result = 0;
|
||||
gcry_error_t error;
|
||||
gcry_cipher_hd_t des = NULL;
|
||||
unsigned char mungedkey[8];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
mungedkey[i] = reverseByte(key[i]);
|
||||
|
||||
error = gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
error = gcry_cipher_setkey(des, mungedkey, 8);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
error = gcry_cipher_decrypt(des, out, in_len, in, in_len);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
*out_len = in_len;
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
gcry_cipher_close(des);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int encrypt_aes128ecb(void *out, int *out_len, const unsigned char key[16], const void *in, const size_t in_len)
|
||||
{
|
||||
int result = 0;
|
||||
gcry_error_t error;
|
||||
gcry_cipher_hd_t aes = NULL;
|
||||
|
||||
error = gcry_cipher_open(&aes, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
error = gcry_cipher_setkey(aes, key, 16);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
error = gcry_cipher_encrypt(aes, out, in_len, in, in_len);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
*out_len = in_len;
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
gcry_cipher_close(aes);
|
||||
return result;
|
||||
}
|
||||
|
||||
int dh_generate_keypair(uint8_t *priv_out, uint8_t *pub_out, const uint8_t *gen, const size_t gen_len, const uint8_t *prime, const size_t keylen)
|
||||
{
|
||||
int result = 0;
|
||||
gcry_error_t error;
|
||||
gcry_mpi_t genmpi = NULL, modmpi = NULL, privmpi = NULL, pubmpi = NULL;
|
||||
|
||||
error = gcry_mpi_scan(&genmpi, GCRYMPI_FMT_USG, gen, gen_len, NULL);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
error = gcry_mpi_scan(&modmpi, GCRYMPI_FMT_USG, prime, keylen, NULL);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
privmpi = gcry_mpi_new(keylen);
|
||||
if (!privmpi)
|
||||
goto out;
|
||||
gcry_mpi_randomize(privmpi, (keylen/8)*8, GCRY_STRONG_RANDOM);
|
||||
|
||||
pubmpi = gcry_mpi_new(keylen);
|
||||
if (!pubmpi)
|
||||
goto out;
|
||||
|
||||
gcry_mpi_powm(pubmpi, genmpi, privmpi, modmpi);
|
||||
|
||||
if (!mpiToBytes(pubmpi, pub_out, keylen))
|
||||
goto out;
|
||||
if (!mpiToBytes(privmpi, priv_out, keylen))
|
||||
goto out;
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
gcry_mpi_release(genmpi);
|
||||
gcry_mpi_release(modmpi);
|
||||
gcry_mpi_release(privmpi);
|
||||
gcry_mpi_release(pubmpi);
|
||||
return result;
|
||||
}
|
||||
|
||||
int dh_compute_shared_key(uint8_t *shared_out, const uint8_t *priv, const uint8_t *pub, const uint8_t *prime, const size_t keylen)
|
||||
{
|
||||
int result = 1;
|
||||
gcry_error_t error;
|
||||
gcry_mpi_t keympi = NULL, modmpi = NULL, privmpi = NULL, pubmpi = NULL;
|
||||
|
||||
error = gcry_mpi_scan(&privmpi, GCRYMPI_FMT_USG, priv, keylen, NULL);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
error = gcry_mpi_scan(&pubmpi, GCRYMPI_FMT_USG, pub, keylen, NULL);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
error = gcry_mpi_scan(&modmpi, GCRYMPI_FMT_USG, prime, keylen, NULL);
|
||||
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
keympi = gcry_mpi_new(keylen);
|
||||
if (!keympi)
|
||||
goto out;
|
||||
|
||||
gcry_mpi_powm(keympi, pubmpi, privmpi, modmpi);
|
||||
|
||||
if (!mpiToBytes(keympi, shared_out, keylen))
|
||||
goto out;
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
gcry_mpi_release(keympi);
|
||||
gcry_mpi_release(modmpi);
|
||||
gcry_mpi_release(privmpi);
|
||||
gcry_mpi_release(pubmpi);
|
||||
|
||||
return result;
|
||||
}
|
||||
246
android/extern/libvncserver/src/common/crypto_openssl.c
vendored
Normal file
246
android/extern/libvncserver/src/common/crypto_openssl.c
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* crypto_openssl.c - Crypto wrapper (openssl version)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011 Gernot Tenchio
|
||||
* Copyright (C) 2019 Christian Beier
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
#include <openssl/provider.h>
|
||||
#endif
|
||||
#include "crypto.h"
|
||||
|
||||
static unsigned char reverseByte(unsigned char b) {
|
||||
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
int hash_md5(void *out, const void *in, const size_t in_len)
|
||||
{
|
||||
MD5_CTX md5;
|
||||
if(!MD5_Init(&md5))
|
||||
return 0;
|
||||
if(!MD5_Update(&md5, in, in_len))
|
||||
return 0;
|
||||
if(!MD5_Final(out, &md5))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hash_sha1(void *out, const void *in, const size_t in_len)
|
||||
{
|
||||
SHA_CTX sha1;
|
||||
if(!SHA1_Init(&sha1))
|
||||
return 0;
|
||||
if(!SHA1_Update(&sha1, in, in_len))
|
||||
return 0;
|
||||
if(!SHA1_Final(out, &sha1))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void random_bytes(void *out, size_t len)
|
||||
{
|
||||
RAND_bytes(out, len);
|
||||
}
|
||||
|
||||
int encrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len)
|
||||
{
|
||||
int result = 0;
|
||||
EVP_CIPHER_CTX *des = NULL;
|
||||
unsigned char mungedkey[8];
|
||||
int i;
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
OSSL_PROVIDER *providerLegacy = NULL;
|
||||
OSSL_PROVIDER *providerDefault = NULL;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
mungedkey[i] = reverseByte(key[i]);
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
/* Load Multiple providers into the default (NULL) library context */
|
||||
if (!(providerLegacy = OSSL_PROVIDER_load(NULL, "legacy")))
|
||||
goto out;
|
||||
if (!(providerDefault = OSSL_PROVIDER_load(NULL, "default")))
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
if(!(des = EVP_CIPHER_CTX_new()))
|
||||
goto out;
|
||||
if(!EVP_EncryptInit_ex(des, EVP_des_ecb(), NULL, mungedkey, NULL))
|
||||
goto out;
|
||||
if(!EVP_EncryptUpdate(des, out, out_len, in, in_len))
|
||||
goto out;
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
if (des)
|
||||
EVP_CIPHER_CTX_free(des);
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
if (providerLegacy)
|
||||
OSSL_PROVIDER_unload(providerLegacy);
|
||||
if (providerDefault)
|
||||
OSSL_PROVIDER_unload(providerDefault);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int decrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len)
|
||||
{
|
||||
int result = 0;
|
||||
EVP_CIPHER_CTX *des;
|
||||
unsigned char mungedkey[8];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
mungedkey[i] = reverseByte(key[i]);
|
||||
|
||||
if(!(des = EVP_CIPHER_CTX_new()))
|
||||
goto out;
|
||||
if(!EVP_DecryptInit_ex(des, EVP_des_ecb(), NULL, mungedkey, NULL))
|
||||
goto out;
|
||||
if(!EVP_DecryptUpdate(des, out, out_len, in, in_len))
|
||||
goto out;
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
EVP_CIPHER_CTX_free(des);
|
||||
return result;
|
||||
}
|
||||
|
||||
int encrypt_aes128ecb(void *out, int *out_len, const unsigned char key[16], const void *in, const size_t in_len)
|
||||
{
|
||||
int result = 0;
|
||||
EVP_CIPHER_CTX *aes;
|
||||
|
||||
if(!(aes = EVP_CIPHER_CTX_new()))
|
||||
goto out;
|
||||
EVP_CIPHER_CTX_set_padding(aes, 0);
|
||||
if(!EVP_EncryptInit_ex(aes, EVP_aes_128_ecb(), NULL, key, NULL))
|
||||
goto out;
|
||||
if(!EVP_EncryptUpdate(aes, out, out_len, in, in_len))
|
||||
goto out;
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
EVP_CIPHER_CTX_free(aes);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void pad_leading_zeros(uint8_t *out, const size_t current_len, const size_t expected_len) {
|
||||
if (current_len >= expected_len || expected_len < 1)
|
||||
return;
|
||||
|
||||
size_t diff = expected_len - current_len;
|
||||
memmove(out + diff, out, current_len);
|
||||
memset(out, 0, diff);
|
||||
}
|
||||
|
||||
int dh_generate_keypair(uint8_t *priv_out, uint8_t *pub_out, const uint8_t *gen, const size_t gen_len, const uint8_t *prime, const size_t keylen)
|
||||
{
|
||||
int result = 0;
|
||||
DH *dh;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L || \
|
||||
(defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x30500000)
|
||||
const BIGNUM *pub_key = NULL;
|
||||
const BIGNUM *priv_key = NULL;
|
||||
#endif
|
||||
|
||||
if(!(dh = DH_new()))
|
||||
goto out;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x30500000)
|
||||
dh->p = BN_bin2bn(prime, keylen, NULL);
|
||||
dh->g = BN_bin2bn(gen, gen_len, NULL);
|
||||
#else
|
||||
if(!DH_set0_pqg(dh, BN_bin2bn(prime, keylen, NULL), NULL, BN_bin2bn(gen, gen_len, NULL)))
|
||||
goto out;
|
||||
#endif
|
||||
if(!DH_generate_key(dh))
|
||||
goto out;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x30500000)
|
||||
if(BN_bn2bin(dh->priv_key, priv_out) == 0)
|
||||
goto out;
|
||||
if(BN_bn2bin(dh->pub_key, pub_out) == 0)
|
||||
goto out;
|
||||
|
||||
pad_leading_zeros(priv_out, BN_num_bytes(dh->priv_key), keylen);
|
||||
pad_leading_zeros(pub_out, BN_num_bytes(dh->pub_key), keylen);
|
||||
#else
|
||||
DH_get0_key(dh, &pub_key, &priv_key);
|
||||
if(BN_bn2binpad(priv_key, priv_out, keylen) == -1)
|
||||
goto out;
|
||||
if(BN_bn2binpad(pub_key, pub_out, keylen) == -1)
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
DH_free(dh);
|
||||
return result;
|
||||
}
|
||||
|
||||
int dh_compute_shared_key(uint8_t *shared_out, const uint8_t *priv, const uint8_t *pub, const uint8_t *prime, const size_t keylen)
|
||||
{
|
||||
int result = 0;
|
||||
DH *dh;
|
||||
|
||||
//Technically gen is not required for calculation of shared key,
|
||||
//but wolfSSL checks for a valid value assigned to dh->g
|
||||
uint8_t dummy_gen[] = {0, 2};
|
||||
|
||||
if(!(dh = DH_new()))
|
||||
goto out;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x30500000)
|
||||
dh->p = BN_bin2bn(prime, keylen, NULL);
|
||||
dh->g = BN_bin2bn(dummy_gen, 2, NULL);
|
||||
dh->priv_key = BN_bin2bn(priv, keylen, NULL);
|
||||
#else
|
||||
if(!DH_set0_pqg(dh, BN_bin2bn(prime, keylen, NULL), NULL, BN_new()))
|
||||
goto out;
|
||||
if(!DH_set0_key(dh, NULL, BN_bin2bn(priv, keylen, NULL)))
|
||||
goto out;
|
||||
#endif
|
||||
int shared_len = DH_compute_key(shared_out, BN_bin2bn(pub, keylen, NULL), dh);
|
||||
if(shared_len == -1)
|
||||
goto out;
|
||||
|
||||
pad_leading_zeros(shared_out, shared_len, keylen);
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
DH_free(dh);
|
||||
return result;
|
||||
}
|
||||
437
android/extern/libvncserver/src/common/d3des.c
vendored
Normal file
437
android/extern/libvncserver/src/common/d3des.c
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* This is D3DES (V5.09) by Richard Outerbridge with the double and
|
||||
* triple-length support removed for use in VNC. Also the bytebit[] array
|
||||
* has been reversed so that the most significant bit in each byte of the
|
||||
* key is ignored, not the least significant.
|
||||
*
|
||||
* These changes are:
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/* D3DES (V5.09) -
|
||||
*
|
||||
* A portable, public domain, version of the Data Encryption Standard.
|
||||
*
|
||||
* Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
|
||||
* Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
|
||||
* code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
|
||||
* Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
|
||||
* for humouring me on.
|
||||
*
|
||||
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
|
||||
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
|
||||
*/
|
||||
|
||||
#include "d3des.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define TLS __thread
|
||||
#elif defined(_MSC_VER)
|
||||
#define TLS __declspec(thread)
|
||||
#else
|
||||
#define TLS
|
||||
#endif
|
||||
|
||||
static void scrunch(unsigned char *, unsigned long *);
|
||||
static void unscrun(unsigned long *, unsigned char *);
|
||||
static void desfunc(unsigned long *, unsigned long *);
|
||||
static void cookey(unsigned long *);
|
||||
|
||||
static TLS unsigned long KnL[32] = { 0L };
|
||||
/*
|
||||
static unsigned long KnR[32] = { 0L };
|
||||
static unsigned long Kn3[32] = { 0L };
|
||||
static unsigned char Df_Key[24] = {
|
||||
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
|
||||
0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
|
||||
0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 };
|
||||
*/
|
||||
|
||||
static const unsigned short bytebit[8] = {
|
||||
01, 02, 04, 010, 020, 040, 0100, 0200 };
|
||||
|
||||
static const unsigned long bigbyte[24] = {
|
||||
0x800000L, 0x400000L, 0x200000L, 0x100000L,
|
||||
0x80000L, 0x40000L, 0x20000L, 0x10000L,
|
||||
0x8000L, 0x4000L, 0x2000L, 0x1000L,
|
||||
0x800L, 0x400L, 0x200L, 0x100L,
|
||||
0x80L, 0x40L, 0x20L, 0x10L,
|
||||
0x8L, 0x4L, 0x2L, 0x1L };
|
||||
|
||||
/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
|
||||
|
||||
static const unsigned char pc1[56] = {
|
||||
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
|
||||
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
|
||||
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
|
||||
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
|
||||
|
||||
static const unsigned char totrot[16] = {
|
||||
1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
|
||||
|
||||
static const unsigned char pc2[48] = {
|
||||
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
|
||||
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
|
||||
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
|
||||
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
|
||||
|
||||
void rfbDesKey(unsigned char *key,
|
||||
int edf)
|
||||
{
|
||||
register int i, j, l, m, n;
|
||||
unsigned char pc1m[56], pcr[56];
|
||||
unsigned long kn[32];
|
||||
|
||||
for ( j = 0; j < 56; j++ ) {
|
||||
l = pc1[j];
|
||||
m = l & 07;
|
||||
pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
|
||||
}
|
||||
for( i = 0; i < 16; i++ ) {
|
||||
if( edf == DE1 ) m = (15 - i) << 1;
|
||||
else m = i << 1;
|
||||
n = m + 1;
|
||||
kn[m] = kn[n] = 0L;
|
||||
for( j = 0; j < 28; j++ ) {
|
||||
l = j + totrot[i];
|
||||
if( l < 28 ) pcr[j] = pc1m[l];
|
||||
else pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
for( j = 28; j < 56; j++ ) {
|
||||
l = j + totrot[i];
|
||||
if( l < 56 ) pcr[j] = pc1m[l];
|
||||
else pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
for( j = 0; j < 24; j++ ) {
|
||||
if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
|
||||
if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
|
||||
}
|
||||
}
|
||||
cookey(kn);
|
||||
return;
|
||||
}
|
||||
|
||||
static void rfbUseKey(register unsigned long *from)
|
||||
{
|
||||
register unsigned long *to, *endp;
|
||||
|
||||
to = KnL, endp = &KnL[32];
|
||||
while( to < endp ) *to++ = *from++;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void cookey(register unsigned long *raw1)
|
||||
{
|
||||
register unsigned long *cook, *raw0;
|
||||
unsigned long dough[32];
|
||||
register int i;
|
||||
|
||||
cook = dough;
|
||||
for( i = 0; i < 16; i++, raw1++ ) {
|
||||
raw0 = raw1++;
|
||||
*cook = (*raw0 & 0x00fc0000L) << 6;
|
||||
*cook |= (*raw0 & 0x00000fc0L) << 10;
|
||||
*cook |= (*raw1 & 0x00fc0000L) >> 10;
|
||||
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
|
||||
*cook = (*raw0 & 0x0003f000L) << 12;
|
||||
*cook |= (*raw0 & 0x0000003fL) << 16;
|
||||
*cook |= (*raw1 & 0x0003f000L) >> 4;
|
||||
*cook++ |= (*raw1 & 0x0000003fL);
|
||||
}
|
||||
rfbUseKey(dough);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void rfbDes(unsigned char *inblock,
|
||||
unsigned char *outblock)
|
||||
{
|
||||
unsigned long work[2];
|
||||
|
||||
scrunch(inblock, work);
|
||||
desfunc(work, KnL);
|
||||
unscrun(work, outblock);
|
||||
return;
|
||||
}
|
||||
|
||||
static void scrunch(register unsigned char *outof,
|
||||
register unsigned long *into)
|
||||
{
|
||||
*into = (*outof++ & 0xffL) << 24;
|
||||
*into |= (*outof++ & 0xffL) << 16;
|
||||
*into |= (*outof++ & 0xffL) << 8;
|
||||
*into++ |= (*outof++ & 0xffL);
|
||||
*into = (*outof++ & 0xffL) << 24;
|
||||
*into |= (*outof++ & 0xffL) << 16;
|
||||
*into |= (*outof++ & 0xffL) << 8;
|
||||
*into |= (*outof & 0xffL);
|
||||
return;
|
||||
}
|
||||
|
||||
static void unscrun(register unsigned long *outof,
|
||||
register unsigned char *into)
|
||||
{
|
||||
*into++ = (unsigned char)((*outof >> 24) & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 16) & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 8) & 0xffL);
|
||||
*into++ = (unsigned char)( *outof++ & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 24) & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 16) & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 8) & 0xffL);
|
||||
*into = (unsigned char)( *outof & 0xffL);
|
||||
return;
|
||||
}
|
||||
|
||||
static const unsigned long SP1[64] = {
|
||||
0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
|
||||
0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
|
||||
0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
|
||||
0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
|
||||
0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
|
||||
0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
|
||||
0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
|
||||
0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
|
||||
0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
|
||||
0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
|
||||
0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
|
||||
0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
|
||||
0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
|
||||
0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
|
||||
0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
|
||||
0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
|
||||
|
||||
static const unsigned long SP2[64] = {
|
||||
0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
|
||||
0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
|
||||
0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
|
||||
0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
|
||||
0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
|
||||
0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
|
||||
0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
|
||||
0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
|
||||
0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
|
||||
0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
|
||||
0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
|
||||
0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
|
||||
0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
|
||||
0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
|
||||
0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
|
||||
0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
|
||||
|
||||
static const unsigned long SP3[64] = {
|
||||
0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
|
||||
0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
|
||||
0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
|
||||
0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
|
||||
0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
|
||||
0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
|
||||
0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
|
||||
0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
|
||||
0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
|
||||
0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
|
||||
0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
|
||||
0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
|
||||
0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
|
||||
0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
|
||||
0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
|
||||
0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
|
||||
|
||||
static const unsigned long SP4[64] = {
|
||||
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
|
||||
0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
|
||||
0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
|
||||
0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
|
||||
0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
|
||||
0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
|
||||
0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
|
||||
0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
|
||||
0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
|
||||
0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
|
||||
0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
|
||||
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
|
||||
0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
|
||||
0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
|
||||
0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
|
||||
0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
|
||||
|
||||
static const unsigned long SP5[64] = {
|
||||
0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
|
||||
0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
|
||||
0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
|
||||
0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
|
||||
0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
|
||||
0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
|
||||
0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
|
||||
0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
|
||||
0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
|
||||
0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
|
||||
0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
|
||||
0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
|
||||
0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
|
||||
0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
|
||||
0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
|
||||
0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
|
||||
|
||||
static const unsigned long SP6[64] = {
|
||||
0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
|
||||
0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
|
||||
0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
|
||||
0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
|
||||
0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
|
||||
0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
|
||||
0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
|
||||
0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
|
||||
0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
|
||||
0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
|
||||
0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
|
||||
0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
|
||||
0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
|
||||
0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
|
||||
0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
|
||||
0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
|
||||
|
||||
static const unsigned long SP7[64] = {
|
||||
0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
|
||||
0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
|
||||
0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
|
||||
0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
|
||||
0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
|
||||
0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
|
||||
0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
|
||||
0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
|
||||
0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
|
||||
0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
|
||||
0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
|
||||
0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
|
||||
0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
|
||||
0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
|
||||
0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
|
||||
0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
|
||||
|
||||
static const unsigned long SP8[64] = {
|
||||
0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
|
||||
0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
|
||||
0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
|
||||
0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
|
||||
0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
|
||||
0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
|
||||
0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
|
||||
0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
|
||||
0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
|
||||
0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
|
||||
0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
|
||||
0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
|
||||
0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
|
||||
0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
|
||||
0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
|
||||
0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
|
||||
|
||||
static void desfunc(register unsigned long *block,
|
||||
register unsigned long *keys)
|
||||
{
|
||||
register unsigned long fval, work, right, leftt;
|
||||
register int round;
|
||||
|
||||
leftt = block[0];
|
||||
right = block[1];
|
||||
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 4);
|
||||
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 16);
|
||||
work = ((right >> 2) ^ leftt) & 0x33333333L;
|
||||
leftt ^= work;
|
||||
right ^= (work << 2);
|
||||
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 8);
|
||||
right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
|
||||
work = (leftt ^ right) & 0xaaaaaaaaL;
|
||||
leftt ^= work;
|
||||
right ^= work;
|
||||
leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
|
||||
|
||||
for( round = 0; round < 8; round++ ) {
|
||||
work = (right << 28) | (right >> 4);
|
||||
work ^= *keys++;
|
||||
fval = SP7[ work & 0x3fL];
|
||||
fval |= SP5[(work >> 8) & 0x3fL];
|
||||
fval |= SP3[(work >> 16) & 0x3fL];
|
||||
fval |= SP1[(work >> 24) & 0x3fL];
|
||||
work = right ^ *keys++;
|
||||
fval |= SP8[ work & 0x3fL];
|
||||
fval |= SP6[(work >> 8) & 0x3fL];
|
||||
fval |= SP4[(work >> 16) & 0x3fL];
|
||||
fval |= SP2[(work >> 24) & 0x3fL];
|
||||
leftt ^= fval;
|
||||
work = (leftt << 28) | (leftt >> 4);
|
||||
work ^= *keys++;
|
||||
fval = SP7[ work & 0x3fL];
|
||||
fval |= SP5[(work >> 8) & 0x3fL];
|
||||
fval |= SP3[(work >> 16) & 0x3fL];
|
||||
fval |= SP1[(work >> 24) & 0x3fL];
|
||||
work = leftt ^ *keys++;
|
||||
fval |= SP8[ work & 0x3fL];
|
||||
fval |= SP6[(work >> 8) & 0x3fL];
|
||||
fval |= SP4[(work >> 16) & 0x3fL];
|
||||
fval |= SP2[(work >> 24) & 0x3fL];
|
||||
right ^= fval;
|
||||
}
|
||||
|
||||
right = (right << 31) | (right >> 1);
|
||||
work = (leftt ^ right) & 0xaaaaaaaaL;
|
||||
leftt ^= work;
|
||||
right ^= work;
|
||||
leftt = (leftt << 31) | (leftt >> 1);
|
||||
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 8);
|
||||
work = ((leftt >> 2) ^ right) & 0x33333333L;
|
||||
right ^= work;
|
||||
leftt ^= (work << 2);
|
||||
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 16);
|
||||
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 4);
|
||||
*block++ = right;
|
||||
*block = leftt;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Validation sets:
|
||||
*
|
||||
* Single-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : c957 4425 6a5e d31d
|
||||
*
|
||||
* Double-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : 7f1d 0a77 826b 8aff
|
||||
*
|
||||
* Double-length key, double-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
|
||||
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
|
||||
* Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
|
||||
*
|
||||
* Triple-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : de0b 7c06 ae5e 0ed5
|
||||
*
|
||||
* Triple-length key, double-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
|
||||
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
|
||||
* Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
|
||||
*
|
||||
* d3des V5.0a rwo 9208.07 18:44 Graven Imagery
|
||||
**********************************************************************/
|
||||
46
android/extern/libvncserver/src/common/d3des.h
vendored
Normal file
46
android/extern/libvncserver/src/common/d3des.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef D3DES_H
|
||||
#define D3DES_H
|
||||
|
||||
/*
|
||||
* This is D3DES (V5.09) by Richard Outerbridge with the double and
|
||||
* triple-length support removed for use in VNC.
|
||||
*
|
||||
* These changes are:
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/* d3des.h -
|
||||
*
|
||||
* Headers and defines for d3des.c
|
||||
* Graven Imagery, 1992.
|
||||
*
|
||||
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
|
||||
* (GEnie : OUTER; CIS : [71755,204])
|
||||
*/
|
||||
|
||||
#define EN0 0 /* MODE == encrypt */
|
||||
#define DE1 1 /* MODE == decrypt */
|
||||
|
||||
extern void rfbDesKey(unsigned char *, int);
|
||||
/* hexkey[8] MODE
|
||||
* Sets the internal key register according to the hexadecimal
|
||||
* key contained in the 8 bytes of hexkey, according to the DES,
|
||||
* for encryption or decryption according to MODE.
|
||||
*/
|
||||
|
||||
|
||||
extern void rfbDes(unsigned char *, unsigned char *);
|
||||
/* from[8] to[8]
|
||||
* Encrypts/Decrypts (according to the key currently loaded in the
|
||||
* internal key register) one block of eight bytes at address 'from'
|
||||
* into the block at address 'to'. They can be the same.
|
||||
*/
|
||||
|
||||
/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
|
||||
********************************************************************/
|
||||
|
||||
#endif
|
||||
444
android/extern/libvncserver/src/common/lzoconf.h
vendored
Normal file
444
android/extern/libvncserver/src/common/lzoconf.h
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
/* lzoconf.h -- configuration of the LZO data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __LZOCONF_H_INCLUDED
|
||||
#define __LZOCONF_H_INCLUDED 1
|
||||
|
||||
#define LZO_VERSION 0x2070
|
||||
#define LZO_VERSION_STRING "2.07"
|
||||
#define LZO_VERSION_DATE "Jun 25 2014"
|
||||
|
||||
/* internal Autoconf configuration file - only used when building LZO */
|
||||
#if defined(LZO_HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// LZO requires a conforming <limits.h>
|
||||
************************************************************************/
|
||||
|
||||
#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
|
||||
# error "invalid CHAR_BIT"
|
||||
#endif
|
||||
#if !defined(UCHAR_MAX) || !defined(USHRT_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
|
||||
# error "check your compiler installation"
|
||||
#endif
|
||||
#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
|
||||
# error "your limits.h macros are broken"
|
||||
#endif
|
||||
|
||||
/* get OS and architecture defines */
|
||||
#ifndef __LZODEFS_H_INCLUDED
|
||||
#include "lzodefs.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// some core defines
|
||||
************************************************************************/
|
||||
|
||||
/* memory checkers */
|
||||
#if !defined(__LZO_CHECKER)
|
||||
# if defined(__BOUNDS_CHECKING_ON)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__CHECKER__)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__INSURE__)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__PURIFY__)
|
||||
# define __LZO_CHECKER 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// integral and pointer types
|
||||
************************************************************************/
|
||||
|
||||
/* lzo_uint must match size_t */
|
||||
#if !defined(LZO_UINT_MAX)
|
||||
# if (LZO_ABI_LLP64)
|
||||
# if (LZO_OS_WIN64)
|
||||
typedef unsigned __int64 lzo_uint;
|
||||
typedef __int64 lzo_int;
|
||||
# else
|
||||
typedef lzo_ullong_t lzo_uint;
|
||||
typedef lzo_llong_t lzo_int;
|
||||
# endif
|
||||
# define LZO_SIZEOF_LZO_UINT 8
|
||||
# define LZO_UINT_MAX 0xffffffffffffffffull
|
||||
# define LZO_INT_MAX 9223372036854775807LL
|
||||
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
|
||||
# elif (LZO_ABI_IP32L64) /* MIPS R5900 */
|
||||
typedef unsigned int lzo_uint;
|
||||
typedef int lzo_int;
|
||||
# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_INT
|
||||
# define LZO_UINT_MAX UINT_MAX
|
||||
# define LZO_INT_MAX INT_MAX
|
||||
# define LZO_INT_MIN INT_MIN
|
||||
# elif (ULONG_MAX >= LZO_0xffffffffL)
|
||||
typedef unsigned long lzo_uint;
|
||||
typedef long lzo_int;
|
||||
# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LONG
|
||||
# define LZO_UINT_MAX ULONG_MAX
|
||||
# define LZO_INT_MAX LONG_MAX
|
||||
# define LZO_INT_MIN LONG_MIN
|
||||
# else
|
||||
# error "lzo_uint"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The larger type of lzo_uint and lzo_uint32_t. */
|
||||
#if (LZO_SIZEOF_LZO_UINT >= 4)
|
||||
# define lzo_xint lzo_uint
|
||||
#else
|
||||
# define lzo_xint lzo_uint32_t
|
||||
#endif
|
||||
|
||||
typedef int lzo_bool;
|
||||
|
||||
/* sanity checks */
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_UINT)
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t))
|
||||
|
||||
#ifndef __LZO_MMODEL
|
||||
#define __LZO_MMODEL /*empty*/
|
||||
#endif
|
||||
|
||||
/* no typedef here because of const-pointer issues */
|
||||
#define lzo_bytep unsigned char __LZO_MMODEL *
|
||||
#define lzo_charp char __LZO_MMODEL *
|
||||
#define lzo_voidp void __LZO_MMODEL *
|
||||
#define lzo_shortp short __LZO_MMODEL *
|
||||
#define lzo_ushortp unsigned short __LZO_MMODEL *
|
||||
#define lzo_intp lzo_int __LZO_MMODEL *
|
||||
#define lzo_uintp lzo_uint __LZO_MMODEL *
|
||||
#define lzo_xintp lzo_xint __LZO_MMODEL *
|
||||
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
|
||||
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
|
||||
|
||||
#define lzo_int8_tp lzo_int8_t __LZO_MMODEL *
|
||||
#define lzo_uint8_tp lzo_uint8_t __LZO_MMODEL *
|
||||
#define lzo_int16_tp lzo_int16_t __LZO_MMODEL *
|
||||
#define lzo_uint16_tp lzo_uint16_t __LZO_MMODEL *
|
||||
#define lzo_int32_tp lzo_int32_t __LZO_MMODEL *
|
||||
#define lzo_uint32_tp lzo_uint32_t __LZO_MMODEL *
|
||||
#if defined(lzo_int64_t)
|
||||
#define lzo_int64_tp lzo_int64_t __LZO_MMODEL *
|
||||
#define lzo_uint64_tp lzo_uint64_t __LZO_MMODEL *
|
||||
#endif
|
||||
|
||||
/* Older LZO versions used to support ancient systems and memory models
|
||||
* like 16-bit MSDOS with __huge pointers and Cray PVP, but these
|
||||
* obsolete configurations are not supported any longer.
|
||||
*/
|
||||
#if defined(__LZO_MMODEL_HUGE)
|
||||
#error "__LZO_MMODEL_HUGE is unsupported"
|
||||
#endif
|
||||
#if (LZO_MM_PVP)
|
||||
#error "LZO_MM_PVP is unsupported"
|
||||
#endif
|
||||
#if (LZO_SIZEOF_INT < 4)
|
||||
#error "LZO_SIZEOF_INT < 4 is unsupported"
|
||||
#endif
|
||||
#if (__LZO_UINTPTR_T_IS_POINTER)
|
||||
#error "__LZO_UINTPTR_T_IS_POINTER is unsupported"
|
||||
#endif
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) >= 4)
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) >= 4)
|
||||
/* Strange configurations where sizeof(lzo_uint) != sizeof(size_t) should
|
||||
* work but have not received much testing lately, so be strict here.
|
||||
*/
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(size_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(ptrdiff_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(lzo_uintptr_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_uintptr_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_uintptr_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long *) == sizeof(lzo_uintptr_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_voidp))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_bytep))
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// function types
|
||||
************************************************************************/
|
||||
|
||||
/* name mangling */
|
||||
#if !defined(__LZO_EXTERN_C)
|
||||
# ifdef __cplusplus
|
||||
# define __LZO_EXTERN_C extern "C"
|
||||
# else
|
||||
# define __LZO_EXTERN_C extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* calling convention */
|
||||
#if !defined(__LZO_CDECL)
|
||||
# define __LZO_CDECL __lzo_cdecl
|
||||
#endif
|
||||
|
||||
/* DLL export information */
|
||||
#if !defined(__LZO_EXPORT1)
|
||||
# define __LZO_EXPORT1 /*empty*/
|
||||
#endif
|
||||
#if !defined(__LZO_EXPORT2)
|
||||
# define __LZO_EXPORT2 /*empty*/
|
||||
#endif
|
||||
|
||||
/* __cdecl calling convention for public C and assembly functions */
|
||||
#if !defined(LZO_PUBLIC)
|
||||
# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
|
||||
#endif
|
||||
#if !defined(LZO_EXTERN)
|
||||
# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
|
||||
#endif
|
||||
#if !defined(LZO_PRIVATE)
|
||||
# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
|
||||
#endif
|
||||
|
||||
/* function types */
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem,
|
||||
const lzo_bytep dict, lzo_uint dict_len );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem,
|
||||
const lzo_bytep dict, lzo_uint dict_len );
|
||||
|
||||
|
||||
/* Callback interface. Currently only the progress indicator ("nprogress")
|
||||
* is used, but this may change in a future release. */
|
||||
|
||||
struct lzo_callback_t;
|
||||
typedef struct lzo_callback_t lzo_callback_t;
|
||||
#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
|
||||
|
||||
/* malloc & free function types */
|
||||
typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
|
||||
(lzo_callback_p self, lzo_uint items, lzo_uint size);
|
||||
typedef void (__LZO_CDECL *lzo_free_func_t)
|
||||
(lzo_callback_p self, lzo_voidp ptr);
|
||||
|
||||
/* a progress indicator callback function */
|
||||
typedef void (__LZO_CDECL *lzo_progress_func_t)
|
||||
(lzo_callback_p, lzo_uint, lzo_uint, int);
|
||||
|
||||
struct lzo_callback_t
|
||||
{
|
||||
/* custom allocators (set to 0 to disable) */
|
||||
lzo_alloc_func_t nalloc; /* [not used right now] */
|
||||
lzo_free_func_t nfree; /* [not used right now] */
|
||||
|
||||
/* a progress indicator callback function (set to 0 to disable) */
|
||||
lzo_progress_func_t nprogress;
|
||||
|
||||
/* INFO: the first parameter "self" of the nalloc/nfree/nprogress
|
||||
* callbacks points back to this struct, so you are free to store
|
||||
* some extra info in the following variables. */
|
||||
lzo_voidp user1;
|
||||
lzo_xint user2;
|
||||
lzo_xint user3;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// error codes and prototypes
|
||||
************************************************************************/
|
||||
|
||||
/* Error codes for the compression/decompression functions. Negative
|
||||
* values are errors, positive values will be used for special but
|
||||
* normal events.
|
||||
*/
|
||||
#define LZO_E_OK 0
|
||||
#define LZO_E_ERROR (-1)
|
||||
#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */
|
||||
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
|
||||
#define LZO_E_INPUT_OVERRUN (-4)
|
||||
#define LZO_E_OUTPUT_OVERRUN (-5)
|
||||
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
|
||||
#define LZO_E_EOF_NOT_FOUND (-7)
|
||||
#define LZO_E_INPUT_NOT_CONSUMED (-8)
|
||||
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
|
||||
#define LZO_E_INVALID_ARGUMENT (-10)
|
||||
#define LZO_E_INVALID_ALIGNMENT (-11) /* pointer argument is not properly aligned */
|
||||
#define LZO_E_OUTPUT_NOT_CONSUMED (-12)
|
||||
#define LZO_E_INTERNAL_ERROR (-99)
|
||||
|
||||
|
||||
#ifndef lzo_sizeof_dict_t
|
||||
# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))
|
||||
#endif
|
||||
|
||||
/* lzo_init() should be the first function you call.
|
||||
* Check the return code !
|
||||
*
|
||||
* lzo_init() is a macro to allow checking that the library and the
|
||||
* compiler's view of various types are consistent.
|
||||
*/
|
||||
#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
|
||||
(int)sizeof(long),(int)sizeof(lzo_uint32_t),(int)sizeof(lzo_uint),\
|
||||
(int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
|
||||
(int)sizeof(lzo_callback_t))
|
||||
LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
|
||||
|
||||
/* version functions (useful for shared libraries) */
|
||||
LZO_EXTERN(unsigned) lzo_version(void);
|
||||
LZO_EXTERN(const char *) lzo_version_string(void);
|
||||
LZO_EXTERN(const char *) lzo_version_date(void);
|
||||
LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
|
||||
LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
|
||||
|
||||
/* string functions */
|
||||
LZO_EXTERN(int)
|
||||
lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memset(lzo_voidp buf, int c, lzo_uint len);
|
||||
|
||||
/* checksum functions */
|
||||
LZO_EXTERN(lzo_uint32_t)
|
||||
lzo_adler32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);
|
||||
LZO_EXTERN(lzo_uint32_t)
|
||||
lzo_crc32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);
|
||||
LZO_EXTERN(const lzo_uint32_tp)
|
||||
lzo_get_crc32_table(void);
|
||||
|
||||
/* misc. */
|
||||
LZO_EXTERN(int) _lzo_config_check(void);
|
||||
typedef union {
|
||||
lzo_voidp a00; lzo_bytep a01; lzo_uint a02; lzo_xint a03; lzo_uintptr_t a04;
|
||||
void *a05; unsigned char *a06; unsigned long a07; size_t a08; ptrdiff_t a09;
|
||||
#if defined(lzo_int64_t)
|
||||
lzo_uint64_t a10;
|
||||
#endif
|
||||
} lzo_align_t;
|
||||
|
||||
/* align a char pointer on a boundary that is a multiple of 'size' */
|
||||
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
|
||||
#define LZO_PTR_ALIGN_UP(p,size) \
|
||||
((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// deprecated macros - only for backward compatibility
|
||||
************************************************************************/
|
||||
|
||||
/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
|
||||
#define lzo_byte unsigned char
|
||||
/* deprecated type names */
|
||||
#define lzo_int32 lzo_int32_t
|
||||
#define lzo_uint32 lzo_uint32_t
|
||||
#define lzo_int32p lzo_int32_t __LZO_MMODEL *
|
||||
#define lzo_uint32p lzo_uint32_t __LZO_MMODEL *
|
||||
#define LZO_INT32_MAX LZO_INT32_C(2147483647)
|
||||
#define LZO_UINT32_MAX LZO_UINT32_C(4294967295)
|
||||
#if defined(lzo_int64_t)
|
||||
#define lzo_int64 lzo_int64_t
|
||||
#define lzo_uint64 lzo_uint64_t
|
||||
#define lzo_int64p lzo_int64_t __LZO_MMODEL *
|
||||
#define lzo_uint64p lzo_uint64_t __LZO_MMODEL *
|
||||
#define LZO_INT64_MAX LZO_INT64_C(9223372036854775807)
|
||||
#define LZO_UINT64_MAX LZO_UINT64_C(18446744073709551615)
|
||||
#endif
|
||||
/* deprecated types */
|
||||
typedef union { lzo_bytep a; lzo_uint b; } __lzo_pu_u;
|
||||
typedef union { lzo_bytep a; lzo_uint32_t b; } __lzo_pu32_u;
|
||||
|
||||
#if defined(LZO_CFG_COMPAT)
|
||||
|
||||
#define __LZOCONF_H 1
|
||||
|
||||
#if defined(LZO_ARCH_I086)
|
||||
# define __LZO_i386 1
|
||||
#elif defined(LZO_ARCH_I386)
|
||||
# define __LZO_i386 1
|
||||
#endif
|
||||
|
||||
#if defined(LZO_OS_DOS16)
|
||||
# define __LZO_DOS 1
|
||||
# define __LZO_DOS16 1
|
||||
#elif defined(LZO_OS_DOS32)
|
||||
# define __LZO_DOS 1
|
||||
#elif defined(LZO_OS_WIN16)
|
||||
# define __LZO_WIN 1
|
||||
# define __LZO_WIN16 1
|
||||
#elif defined(LZO_OS_WIN32)
|
||||
# define __LZO_WIN 1
|
||||
#endif
|
||||
|
||||
#define __LZO_CMODEL /*empty*/
|
||||
#define __LZO_DMODEL /*empty*/
|
||||
#define __LZO_ENTRY __LZO_CDECL
|
||||
#define LZO_EXTERN_CDECL LZO_EXTERN
|
||||
#define LZO_ALIGN LZO_PTR_ALIGN_UP
|
||||
|
||||
#define lzo_compress_asm_t lzo_compress_t
|
||||
#define lzo_decompress_asm_t lzo_decompress_t
|
||||
|
||||
#endif /* LZO_CFG_COMPAT */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
|
||||
/* vim:set ts=4 et: */
|
||||
2998
android/extern/libvncserver/src/common/lzodefs.h
vendored
Normal file
2998
android/extern/libvncserver/src/common/lzodefs.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6037
android/extern/libvncserver/src/common/minilzo.c
vendored
Normal file
6037
android/extern/libvncserver/src/common/minilzo.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
94
android/extern/libvncserver/src/common/minilzo.h
vendored
Normal file
94
android/extern/libvncserver/src/common/minilzo.h
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/* minilzo.h -- mini subset of the LZO real-time data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* the full LZO package can be found at
|
||||
* http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MINILZO_H
|
||||
#define __MINILZO_H 1
|
||||
|
||||
#define MINILZO_VERSION 0x2070
|
||||
|
||||
#ifdef __LZOCONF_H
|
||||
# error "you cannot use both LZO and miniLZO"
|
||||
#endif
|
||||
|
||||
#undef LZO_HAVE_CONFIG_H
|
||||
#include "lzoconf.h"
|
||||
|
||||
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
|
||||
# error "version mismatch in header files"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
|
||||
/* Memory required for the wrkmem parameter.
|
||||
* When the required size is 0, you can also pass a NULL pointer.
|
||||
*/
|
||||
|
||||
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
|
||||
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32_t) (16384L * lzo_sizeof_dict_t))
|
||||
#define LZO1X_MEM_DECOMPRESS (0)
|
||||
|
||||
|
||||
/* compression */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
/* decompression */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem /* NOT USED */ );
|
||||
|
||||
/* safe decompression with overrun testing */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem /* NOT USED */ );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
29
android/extern/libvncserver/src/common/sha-private.h
vendored
Normal file
29
android/extern/libvncserver/src/common/sha-private.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/************************ sha-private.h ************************/
|
||||
/***************** See RFC 6234 for details. *******************/
|
||||
#ifndef _SHA_PRIVATE__H
|
||||
#define _SHA_PRIVATE__H
|
||||
/*
|
||||
* These definitions are defined in FIPS 180-3, section 4.1.
|
||||
* Ch() and Maj() are defined identically in sections 4.1.1,
|
||||
* 4.1.2, and 4.1.3.
|
||||
*
|
||||
* The definitions used in FIPS 180-3 are as follows:
|
||||
*/
|
||||
|
||||
#ifndef USE_MODIFIED_MACROS
|
||||
#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
|
||||
#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#else /* USE_MODIFIED_MACROS */
|
||||
/*
|
||||
* The following definitions are equivalent and potentially faster.
|
||||
*/
|
||||
|
||||
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
|
||||
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
|
||||
|
||||
#endif /* USE_MODIFIED_MACROS */
|
||||
|
||||
#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))
|
||||
|
||||
#endif /* _SHA_PRIVATE__H */
|
||||
|
||||
358
android/extern/libvncserver/src/common/sha.h
vendored
Normal file
358
android/extern/libvncserver/src/common/sha.h
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
/**************************** sha.h ****************************/
|
||||
/***************** See RFC 6234 for details. *******************/
|
||||
/*
|
||||
Copyright (c) 2011 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and
|
||||
the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor
|
||||
the names of specific contributors, may be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _SHA_H_
|
||||
#define _SHA_H_
|
||||
|
||||
/*
|
||||
* Description:
|
||||
* This file implements the Secure Hash Algorithms
|
||||
* as defined in the U.S. National Institute of Standards
|
||||
* and Technology Federal Information Processing Standards
|
||||
* Publication (FIPS PUB) 180-3 published in October 2008
|
||||
* and formerly defined in its predecessors, FIPS PUB 180-1
|
||||
* and FIP PUB 180-2.
|
||||
*
|
||||
* A combined document showing all algorithms is available at
|
||||
* http://csrc.nist.gov/publications/fips/
|
||||
* fips180-3/fips180-3_final.pdf
|
||||
*
|
||||
* The five hashes are defined in these sizes:
|
||||
* SHA-1 20 byte / 160 bit
|
||||
* SHA-224 28 byte / 224 bit
|
||||
* SHA-256 32 byte / 256 bit
|
||||
* SHA-384 48 byte / 384 bit
|
||||
* SHA-512 64 byte / 512 bit
|
||||
*
|
||||
* Compilation Note:
|
||||
* These files may be compiled with two options:
|
||||
* USE_32BIT_ONLY - use 32-bit arithmetic only, for systems
|
||||
* without 64-bit integers
|
||||
*
|
||||
* USE_MODIFIED_MACROS - use alternate form of the SHA_Ch()
|
||||
* and SHA_Maj() macros that are equivalent
|
||||
* and potentially faster on many systems
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
/*
|
||||
* If you do not have the ISO standard stdint.h header file, then you
|
||||
* must typedef the following:
|
||||
* name meaning
|
||||
* uint64_t unsigned 64-bit integer
|
||||
* uint32_t unsigned 32-bit integer
|
||||
* uint8_t unsigned 8-bit integer (i.e., unsigned char)
|
||||
* int_least16_t integer of >= 16 bits
|
||||
*
|
||||
* See stdint-example.h
|
||||
*/
|
||||
|
||||
#ifndef _SHA_enum_
|
||||
#define _SHA_enum_
|
||||
/*
|
||||
* All SHA functions return one of these values.
|
||||
*/
|
||||
enum {
|
||||
shaSuccess = 0,
|
||||
shaNull, /* Null pointer parameter */
|
||||
shaInputTooLong, /* input data too long */
|
||||
shaStateError, /* called Input after FinalBits or Result */
|
||||
shaBadParam /* passed a bad parameter */
|
||||
};
|
||||
#endif /* _SHA_enum_ */
|
||||
|
||||
/*
|
||||
* These constants hold size information for each of the SHA
|
||||
* hashing operations
|
||||
*/
|
||||
enum {
|
||||
SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64,
|
||||
SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128,
|
||||
SHA512_Message_Block_Size = 128,
|
||||
USHA_Max_Message_Block_Size = SHA512_Message_Block_Size,
|
||||
|
||||
SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32,
|
||||
SHA384HashSize = 48, SHA512HashSize = 64,
|
||||
USHAMaxHashSize = SHA512HashSize,
|
||||
|
||||
SHA1HashSizeBits = 160, SHA224HashSizeBits = 224,
|
||||
SHA256HashSizeBits = 256, SHA384HashSizeBits = 384,
|
||||
SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits
|
||||
};
|
||||
|
||||
/*
|
||||
* These constants are used in the USHA (Unified SHA) functions.
|
||||
*/
|
||||
typedef enum SHAversion {
|
||||
SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
} SHAversion;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-1
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA1Context {
|
||||
uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
|
||||
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 512-bit message blocks */
|
||||
uint8_t Message_Block[SHA1_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA1Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-256
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA256Context {
|
||||
uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */
|
||||
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 512-bit message blocks */
|
||||
uint8_t Message_Block[SHA256_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA256Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-512
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA512Context {
|
||||
#ifdef USE_32BIT_ONLY
|
||||
uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */
|
||||
uint32_t Length[4]; /* Message length in bits */
|
||||
#else /* !USE_32BIT_ONLY */
|
||||
uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */
|
||||
uint64_t Length_High, Length_Low; /* Message length in bits */
|
||||
#endif /* USE_32BIT_ONLY */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 1024-bit message blocks */
|
||||
uint8_t Message_Block[SHA512_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed?*/
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA512Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-224
|
||||
* hashing operation. It uses the SHA-256 structure for computation.
|
||||
*/
|
||||
typedef struct SHA256Context SHA224Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-384
|
||||
* hashing operation. It uses the SHA-512 structure for computation.
|
||||
*/
|
||||
typedef struct SHA512Context SHA384Context;
|
||||
|
||||
/*
|
||||
* This structure holds context information for all SHA
|
||||
* hashing operations.
|
||||
*/
|
||||
typedef struct USHAContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
union {
|
||||
SHA1Context sha1Context;
|
||||
SHA224Context sha224Context; SHA256Context sha256Context;
|
||||
SHA384Context sha384Context; SHA512Context sha512Context;
|
||||
} ctx;
|
||||
|
||||
} USHAContext;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the HMAC
|
||||
* keyed-hashing operation.
|
||||
*/
|
||||
typedef struct HMACContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
int hashSize; /* hash size of SHA being used */
|
||||
int blockSize; /* block size of SHA being used */
|
||||
USHAContext shaContext; /* SHA context */
|
||||
unsigned char k_opad[USHA_Max_Message_Block_Size];
|
||||
/* outer padding - key XORd with opad */
|
||||
int Computed; /* Is the MAC computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
|
||||
} HMACContext;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the HKDF
|
||||
* extract-and-expand Key Derivation Functions.
|
||||
*/
|
||||
typedef struct HKDFContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
HMACContext hmacContext;
|
||||
int hashSize; /* hash size of SHA being used */
|
||||
unsigned char prk[USHAMaxHashSize];
|
||||
/* pseudo-random key - output of hkdfInput */
|
||||
int Computed; /* Is the key material computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} HKDFContext;
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
|
||||
/* SHA-1 */
|
||||
extern int SHA1Reset(SHA1Context *);
|
||||
extern int SHA1Input(SHA1Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA1FinalBits(SHA1Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA1Result(SHA1Context *,
|
||||
uint8_t Message_Digest[SHA1HashSize]);
|
||||
|
||||
/* SHA-224 */
|
||||
extern int SHA224Reset(SHA224Context *);
|
||||
extern int SHA224Input(SHA224Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA224FinalBits(SHA224Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA224Result(SHA224Context *,
|
||||
uint8_t Message_Digest[SHA224HashSize]);
|
||||
|
||||
/* SHA-256 */
|
||||
extern int SHA256Reset(SHA256Context *);
|
||||
extern int SHA256Input(SHA256Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA256FinalBits(SHA256Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA256Result(SHA256Context *,
|
||||
uint8_t Message_Digest[SHA256HashSize]);
|
||||
|
||||
/* SHA-384 */
|
||||
extern int SHA384Reset(SHA384Context *);
|
||||
extern int SHA384Input(SHA384Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA384FinalBits(SHA384Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA384Result(SHA384Context *,
|
||||
uint8_t Message_Digest[SHA384HashSize]);
|
||||
|
||||
/* SHA-512 */
|
||||
extern int SHA512Reset(SHA512Context *);
|
||||
extern int SHA512Input(SHA512Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA512FinalBits(SHA512Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA512Result(SHA512Context *,
|
||||
uint8_t Message_Digest[SHA512HashSize]);
|
||||
|
||||
/* Unified SHA functions, chosen by whichSha */
|
||||
extern int USHAReset(USHAContext *context, SHAversion whichSha);
|
||||
extern int USHAInput(USHAContext *context,
|
||||
const uint8_t *bytes, unsigned int bytecount);
|
||||
extern int USHAFinalBits(USHAContext *context,
|
||||
uint8_t bits, unsigned int bit_count);
|
||||
extern int USHAResult(USHAContext *context,
|
||||
uint8_t Message_Digest[USHAMaxHashSize]);
|
||||
extern int USHABlockSize(enum SHAversion whichSha);
|
||||
extern int USHAHashSize(enum SHAversion whichSha);
|
||||
extern int USHAHashSizeBits(enum SHAversion whichSha);
|
||||
extern const char *USHAHashName(enum SHAversion whichSha);
|
||||
|
||||
/*
|
||||
* HMAC Keyed-Hashing for Message Authentication, RFC 2104,
|
||||
* for all SHAs.
|
||||
* This interface allows a fixed-length text input to be used.
|
||||
*/
|
||||
extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */
|
||||
const unsigned char *text, /* pointer to data stream */
|
||||
int text_len, /* length of data stream */
|
||||
const unsigned char *key, /* pointer to authentication key */
|
||||
int key_len, /* length of authentication key */
|
||||
uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
|
||||
|
||||
/*
|
||||
* HMAC Keyed-Hashing for Message Authentication, RFC 2104,
|
||||
* for all SHAs.
|
||||
* This interface allows any length of text input to be used.
|
||||
*/
|
||||
extern int hmacReset(HMACContext *context, enum SHAversion whichSha,
|
||||
const unsigned char *key, int key_len);
|
||||
extern int hmacInput(HMACContext *context, const unsigned char *text,
|
||||
int text_len);
|
||||
extern int hmacFinalBits(HMACContext *context, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int hmacResult(HMACContext *context,
|
||||
uint8_t digest[USHAMaxHashSize]);
|
||||
|
||||
/*
|
||||
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
|
||||
* RFC 5869, for all SHAs.
|
||||
*/
|
||||
extern int hkdf(SHAversion whichSha, const unsigned char *salt,
|
||||
int salt_len, const unsigned char *ikm, int ikm_len,
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[ ], int okm_len);
|
||||
extern int hkdfExtract(SHAversion whichSha, const unsigned char *salt,
|
||||
int salt_len, const unsigned char *ikm,
|
||||
int ikm_len, uint8_t prk[USHAMaxHashSize]);
|
||||
extern int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
|
||||
int prk_len, const unsigned char *info,
|
||||
int info_len, uint8_t okm[ ], int okm_len);
|
||||
|
||||
/*
|
||||
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
|
||||
* RFC 5869, for all SHAs.
|
||||
* This interface allows any length of text input to be used.
|
||||
*/
|
||||
extern int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
|
||||
const unsigned char *salt, int salt_len);
|
||||
extern int hkdfInput(HKDFContext *context, const unsigned char *ikm,
|
||||
int ikm_len);
|
||||
extern int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
|
||||
unsigned int ikm_bit_count);
|
||||
extern int hkdfResult(HKDFContext *context,
|
||||
uint8_t prk[USHAMaxHashSize],
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[USHAMaxHashSize], int okm_len);
|
||||
#endif /* _SHA_H_ */
|
||||
|
||||
414
android/extern/libvncserver/src/common/sha1.c
vendored
Normal file
414
android/extern/libvncserver/src/common/sha1.c
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
/**************************** sha1.c ***************************/
|
||||
/***************** See RFC 6234 for details. *******************/
|
||||
/* Copyright (c) 2011 IETF Trust and the persons identified as */
|
||||
/* authors of the code. All rights reserved. */
|
||||
/* See sha.h for terms of use and redistribution. */
|
||||
|
||||
/*
|
||||
* Description:
|
||||
* This file implements the Secure Hash Algorithm SHA-1
|
||||
* as defined in the U.S. National Institute of Standards
|
||||
* and Technology Federal Information Processing Standards
|
||||
* Publication (FIPS PUB) 180-3 published in October 2008
|
||||
* and formerly defined in its predecessors, FIPS PUB 180-1
|
||||
* and FIP PUB 180-2.
|
||||
*
|
||||
* A combined document showing all algorithms is available at
|
||||
* http://csrc.nist.gov/publications/fips/
|
||||
* fips180-3/fips180-3_final.pdf
|
||||
*
|
||||
* The SHA-1 algorithm produces a 160-bit message digest for a
|
||||
* given data stream that can serve as a means of providing a
|
||||
* "fingerprint" for a message.
|
||||
*
|
||||
* Portability Issues:
|
||||
* SHA-1 is defined in terms of 32-bit "words". This code
|
||||
* uses <stdint.h> (included via "sha.h") to define 32- and
|
||||
* 8-bit unsigned integer types. If your C compiler does
|
||||
* not support 32-bit unsigned integers, this code is not
|
||||
* appropriate.
|
||||
*
|
||||
* Caveats:
|
||||
* SHA-1 is designed to work with messages less than 2^64 bits
|
||||
* long. This implementation uses SHA1Input() to hash the bits
|
||||
* that are a multiple of the size of an 8-bit octet, and then
|
||||
* optionally uses SHA1FinalBits() to hash the final few bits of
|
||||
* the input.
|
||||
*/
|
||||
|
||||
#include "sha.h"
|
||||
#include "sha-private.h"
|
||||
|
||||
/*
|
||||
* Define the SHA1 circular left shift macro
|
||||
*/
|
||||
#define SHA1_ROTL(bits,word) \
|
||||
(((word) << (bits)) | ((word) >> (32-(bits))))
|
||||
|
||||
/*
|
||||
* Add "length" to the length.
|
||||
* Set Corrupted when overflow has occurred.
|
||||
*/
|
||||
static uint32_t addTemp;
|
||||
#define SHA1AddLength(context, length) \
|
||||
(addTemp = (context)->Length_Low, \
|
||||
(context)->Corrupted = \
|
||||
(((context)->Length_Low += (length)) < addTemp) && \
|
||||
(++(context)->Length_High == 0) ? shaInputTooLong \
|
||||
: (context)->Corrupted )
|
||||
|
||||
/* Local Function Prototypes */
|
||||
static void SHA1ProcessMessageBlock(SHA1Context *context);
|
||||
static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte);
|
||||
static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte);
|
||||
|
||||
/*
|
||||
* SHA1Reset
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the SHA1Context in preparation
|
||||
* for computing a new SHA1 message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to reset.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Reset(SHA1Context *context)
|
||||
{
|
||||
if (!context) return shaNull;
|
||||
|
||||
context->Length_High = context->Length_Low = 0;
|
||||
context->Message_Block_Index = 0;
|
||||
|
||||
/* Initial Hash Values: FIPS 180-3 section 5.3.1 */
|
||||
context->Intermediate_Hash[0] = 0x67452301;
|
||||
context->Intermediate_Hash[1] = 0xEFCDAB89;
|
||||
context->Intermediate_Hash[2] = 0x98BADCFE;
|
||||
context->Intermediate_Hash[3] = 0x10325476;
|
||||
context->Intermediate_Hash[4] = 0xC3D2E1F0;
|
||||
|
||||
context->Computed = 0;
|
||||
context->Corrupted = shaSuccess;
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion
|
||||
* of the message.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update.
|
||||
* message_array[ ]: [in]
|
||||
* An array of octets representing the next portion of
|
||||
* the message.
|
||||
* length: [in]
|
||||
* The length of the message in message_array.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Input(SHA1Context *context,
|
||||
const uint8_t *message_array, unsigned length)
|
||||
{
|
||||
if (!context) return shaNull;
|
||||
if (!length) return shaSuccess;
|
||||
if (!message_array) return shaNull;
|
||||
if (context->Computed) return context->Corrupted = shaStateError;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
|
||||
while (length--) {
|
||||
context->Message_Block[context->Message_Block_Index++] =
|
||||
*message_array;
|
||||
|
||||
if ((SHA1AddLength(context, 8) == shaSuccess) &&
|
||||
(context->Message_Block_Index == SHA1_Message_Block_Size))
|
||||
SHA1ProcessMessageBlock(context);
|
||||
|
||||
message_array++;
|
||||
}
|
||||
|
||||
return context->Corrupted;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1FinalBits
|
||||
*
|
||||
* Description:
|
||||
* This function will add in any final bits of the message.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update.
|
||||
* message_bits: [in]
|
||||
* The final bits of the message, in the upper portion of the
|
||||
* byte. (Use 0b###00000 instead of 0b00000### to input the
|
||||
* three bits ###.)
|
||||
* length: [in]
|
||||
* The number of bits in message_bits, between 1 and 7.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
int SHA1FinalBits(SHA1Context *context, uint8_t message_bits,
|
||||
unsigned int length)
|
||||
{
|
||||
static uint8_t masks[8] = {
|
||||
/* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
|
||||
/* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
|
||||
/* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
|
||||
/* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE
|
||||
};
|
||||
|
||||
static uint8_t markbit[8] = {
|
||||
/* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
|
||||
/* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
|
||||
/* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
|
||||
/* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01
|
||||
};
|
||||
|
||||
if (!context) return shaNull;
|
||||
if (!length) return shaSuccess;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
if (context->Computed) return context->Corrupted = shaStateError;
|
||||
if (length >= 8) return context->Corrupted = shaBadParam;
|
||||
|
||||
SHA1AddLength(context, length);
|
||||
SHA1Finalize(context,
|
||||
(uint8_t) ((message_bits & masks[length]) | markbit[length]));
|
||||
|
||||
return context->Corrupted;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Result
|
||||
*
|
||||
* Description:
|
||||
* This function will return the 160-bit message digest
|
||||
* into the Message_Digest array provided by the caller.
|
||||
* NOTE:
|
||||
* The first octet of hash is stored in the element with index 0,
|
||||
* the last octet of hash in the element with index 19.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to use to calculate the SHA-1 hash.
|
||||
* Message_Digest[ ]: [out]
|
||||
* Where the digest is returned.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Result(SHA1Context *context,
|
||||
uint8_t Message_Digest[SHA1HashSize])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!context) return shaNull;
|
||||
if (!Message_Digest) return shaNull;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
|
||||
if (!context->Computed)
|
||||
SHA1Finalize(context, 0x80);
|
||||
|
||||
for (i = 0; i < SHA1HashSize; ++i)
|
||||
Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i>>2]
|
||||
>> (8 * ( 3 - ( i & 0x03 ) )));
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1ProcessMessageBlock
|
||||
*
|
||||
* Description:
|
||||
* This helper function will process the next 512 bits of the
|
||||
* message stored in the Message_Block array.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
* Many of the variable names in this code, especially the
|
||||
* single character names, were used because those were the
|
||||
* names used in the Secure Hash Standard.
|
||||
*/
|
||||
static void SHA1ProcessMessageBlock(SHA1Context *context)
|
||||
{
|
||||
/* Constants defined in FIPS 180-3, section 4.2.1 */
|
||||
const uint32_t K[4] = {
|
||||
0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
|
||||
};
|
||||
|
||||
int t; /* Loop counter */
|
||||
uint32_t temp; /* Temporary word value */
|
||||
uint32_t W[80]; /* Word sequence */
|
||||
uint32_t A, B, C, D, E; /* Word buffers */
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for (t = 0; t < 16; t++) {
|
||||
W[t] = ((uint32_t)context->Message_Block[t * 4]) << 24;
|
||||
W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16;
|
||||
W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8;
|
||||
W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]);
|
||||
}
|
||||
|
||||
for (t = 16; t < 80; t++)
|
||||
W[t] = SHA1_ROTL(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
|
||||
A = context->Intermediate_Hash[0];
|
||||
B = context->Intermediate_Hash[1];
|
||||
C = context->Intermediate_Hash[2];
|
||||
D = context->Intermediate_Hash[3];
|
||||
E = context->Intermediate_Hash[4];
|
||||
|
||||
for (t = 0; t < 20; t++) {
|
||||
temp = SHA1_ROTL(5,A) + SHA_Ch(B, C, D) + E + W[t] + K[0];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1_ROTL(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 20; t < 40; t++) {
|
||||
temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[1];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1_ROTL(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 40; t < 60; t++) {
|
||||
temp = SHA1_ROTL(5,A) + SHA_Maj(B, C, D) + E + W[t] + K[2];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1_ROTL(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 60; t < 80; t++) {
|
||||
temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[3];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1_ROTL(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
context->Intermediate_Hash[0] += A;
|
||||
context->Intermediate_Hash[1] += B;
|
||||
context->Intermediate_Hash[2] += C;
|
||||
context->Intermediate_Hash[3] += D;
|
||||
context->Intermediate_Hash[4] += E;
|
||||
context->Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Finalize
|
||||
*
|
||||
* Description:
|
||||
* This helper function finishes off the digest calculations.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update.
|
||||
* Pad_Byte: [in]
|
||||
* The last byte to add to the message block before the 0-padding
|
||||
* and length. This will contain the last bits of the message
|
||||
* followed by another single bit. If the message was an
|
||||
* exact multiple of 8-bits long, Pad_Byte will be 0x80.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte)
|
||||
{
|
||||
int i;
|
||||
SHA1PadMessage(context, Pad_Byte);
|
||||
/* message may be sensitive, clear it out */
|
||||
for (i = 0; i < SHA1_Message_Block_Size; ++i)
|
||||
context->Message_Block[i] = 0;
|
||||
context->Length_High = 0; /* and clear length */
|
||||
context->Length_Low = 0;
|
||||
context->Computed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1PadMessage
|
||||
*
|
||||
* Description:
|
||||
* According to the standard, the message must be padded to the next
|
||||
* even multiple of 512 bits. The first padding bit must be a '1'.
|
||||
* The last 64 bits represent the length of the original message.
|
||||
* All bits in between should be 0. This helper function will pad
|
||||
* the message according to those rules by filling the Message_Block
|
||||
* array accordingly. When it returns, it can be assumed that the
|
||||
* message digest has been computed.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to pad.
|
||||
* Pad_Byte: [in]
|
||||
* The last byte to add to the message block before the 0-padding
|
||||
* and length. This will contain the last bits of the message
|
||||
* followed by another single bit. If the message was an
|
||||
* exact multiple of 8-bits long, Pad_Byte will be 0x80.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*/
|
||||
static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte)
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second
|
||||
* block.
|
||||
*/
|
||||
if (context->Message_Block_Index >= (SHA1_Message_Block_Size - 8)) {
|
||||
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
|
||||
while (context->Message_Block_Index < SHA1_Message_Block_Size)
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
|
||||
SHA1ProcessMessageBlock(context);
|
||||
} else
|
||||
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
|
||||
|
||||
while (context->Message_Block_Index < (SHA1_Message_Block_Size - 8))
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
context->Message_Block[56] = (uint8_t) (context->Length_High >> 24);
|
||||
context->Message_Block[57] = (uint8_t) (context->Length_High >> 16);
|
||||
context->Message_Block[58] = (uint8_t) (context->Length_High >> 8);
|
||||
context->Message_Block[59] = (uint8_t) (context->Length_High);
|
||||
context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24);
|
||||
context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16);
|
||||
context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8);
|
||||
context->Message_Block[63] = (uint8_t) (context->Length_Low);
|
||||
|
||||
SHA1ProcessMessageBlock(context);
|
||||
}
|
||||
|
||||
85
android/extern/libvncserver/src/common/sockets.c
vendored
Normal file
85
android/extern/libvncserver/src/common/sockets.c
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* common/sockets.c - Common internal socket functions used by both
|
||||
* libvncclient and libvncserver.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Christian Beier
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sockets.h"
|
||||
|
||||
|
||||
rfbBool sock_set_nonblocking(rfbSocket sock, rfbBool non_blocking, void (*log)(const char *format, ...))
|
||||
{
|
||||
#ifdef WIN32
|
||||
unsigned long block = non_blocking ? 0 : 1;
|
||||
if(ioctlsocket(sock, FIONBIO, &block) == SOCKET_ERROR) {
|
||||
errno=WSAGetLastError();
|
||||
#else
|
||||
int flags = fcntl(sock, F_GETFL);
|
||||
int new_flags;
|
||||
if(non_blocking)
|
||||
new_flags = flags | O_NONBLOCK;
|
||||
else
|
||||
new_flags = flags & ~O_NONBLOCK;
|
||||
if(flags < 0 || fcntl(sock, F_SETFL, new_flags) < 0) {
|
||||
#endif
|
||||
log("Setting socket to %sblocking mode failed: %s\n", non_blocking ? "non-" : "", strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
rfbBool sock_wait_for_connected(int socket, unsigned int timeout_seconds)
|
||||
{
|
||||
fd_set writefds;
|
||||
fd_set exceptfds;
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec=timeout_seconds;
|
||||
timeout.tv_usec=0;
|
||||
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(socket, &writefds);
|
||||
FD_ZERO(&exceptfds);
|
||||
FD_SET(socket, &exceptfds);
|
||||
if (select(socket+1, NULL, &writefds, &exceptfds, &timeout)==1) {
|
||||
#ifdef WIN32
|
||||
if (FD_ISSET(socket, &exceptfds))
|
||||
return FALSE;
|
||||
#else
|
||||
int so_error;
|
||||
socklen_t len = sizeof so_error;
|
||||
getsockopt(socket, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
if (so_error!=0)
|
||||
return FALSE;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
86
android/extern/libvncserver/src/common/sockets.h
vendored
Normal file
86
android/extern/libvncserver/src/common/sockets.h
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* LibVNCServer/LibVNCClient common platform socket defines, includes
|
||||
* and internal socket helper functions.
|
||||
*
|
||||
* Copyright (C) 2022 Christian Beier <dontmind@freeshell.org>
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifndef _RFB_COMMON_SOCKETS_H
|
||||
#define _RFB_COMMON_SOCKETS_H
|
||||
|
||||
#ifdef WIN32
|
||||
/*
|
||||
Windows sockets
|
||||
*/
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#undef EWOULDBLOCK
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
|
||||
#undef ETIMEDOUT
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
|
||||
#undef EINTR
|
||||
#define EINTR WSAEINTR
|
||||
|
||||
#undef EINVAL
|
||||
#define EINVAL WSAEINVAL
|
||||
|
||||
/* MinGW has those, but MSVC not */
|
||||
#ifdef _MSC_VER
|
||||
#define SHUT_RD SD_RECEIVE
|
||||
#define SHUT_WR SD_SEND
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#endif
|
||||
|
||||
#define read(sock,buf,len) recv(sock,buf,len,0)
|
||||
#define write(sock,buf,len) send(sock,buf,len,0)
|
||||
|
||||
#else
|
||||
/*
|
||||
Unix sockets
|
||||
*/
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Common internal socket functions
|
||||
*/
|
||||
#include "rfb/rfbproto.h"
|
||||
|
||||
/*
|
||||
Set (non)blocking mode for a socket.
|
||||
Returns TRUE on succcess, FALSE on failure.
|
||||
*/
|
||||
rfbBool sock_set_nonblocking(rfbSocket sock, rfbBool non_blocking, void (*log)(const char *format, ...));
|
||||
|
||||
|
||||
/*
|
||||
Wait for a socket to become connected.
|
||||
Returns TRUE if socket connected in time, FALSE if otherwise.
|
||||
*/
|
||||
rfbBool sock_wait_for_connected(int socket, unsigned int timeout_seconds);
|
||||
|
||||
|
||||
#endif /* _RFB_COMMON_SOCKETS_H */
|
||||
858
android/extern/libvncserver/src/common/turbojpeg.c
vendored
Normal file
858
android/extern/libvncserver/src/common/turbojpeg.c
vendored
Normal file
@@ -0,0 +1,858 @@
|
||||
/*
|
||||
* Copyright (C)2009-2012 D. R. Commander. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the libjpeg-turbo Project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* TurboJPEG/OSS: this implements the TurboJPEG API using libjpeg-turbo */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef JCS_EXTENSIONS
|
||||
#define JPEG_INTERNAL_OPTIONS
|
||||
#endif
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
#include <setjmp.h>
|
||||
#include "./turbojpeg.h"
|
||||
|
||||
#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
|
||||
|
||||
#define CSTATE_START 100
|
||||
#define DSTATE_START 200
|
||||
#define MEMZERO(ptr, size) memset(ptr, 0, size)
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
|
||||
/* Error handling (based on example in example.c) */
|
||||
|
||||
static char errStr[JMSG_LENGTH_MAX]="No error";
|
||||
|
||||
struct my_error_mgr
|
||||
{
|
||||
struct jpeg_error_mgr pub;
|
||||
jmp_buf setjmp_buffer;
|
||||
};
|
||||
typedef struct my_error_mgr *my_error_ptr;
|
||||
|
||||
static void my_error_exit(j_common_ptr cinfo)
|
||||
{
|
||||
my_error_ptr myerr=(my_error_ptr)cinfo->err;
|
||||
(*cinfo->err->output_message)(cinfo);
|
||||
longjmp(myerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
/* Based on output_message() in jerror.c */
|
||||
|
||||
static void my_output_message(j_common_ptr cinfo)
|
||||
{
|
||||
(*cinfo->err->format_message)(cinfo, errStr);
|
||||
}
|
||||
|
||||
|
||||
/* Global structures, macros, etc. */
|
||||
|
||||
enum {COMPRESS=1, DECOMPRESS=2};
|
||||
|
||||
typedef struct _tjinstance
|
||||
{
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_decompress_struct dinfo;
|
||||
struct jpeg_destination_mgr jdst;
|
||||
struct jpeg_source_mgr jsrc;
|
||||
struct my_error_mgr jerr;
|
||||
int init;
|
||||
} tjinstance;
|
||||
|
||||
static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
|
||||
|
||||
#define NUMSF 4
|
||||
static const tjscalingfactor sf[NUMSF]={
|
||||
{1, 1},
|
||||
{1, 2},
|
||||
{1, 4},
|
||||
{1, 8}
|
||||
};
|
||||
|
||||
#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
|
||||
retval=-1; goto bailout;}
|
||||
#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
|
||||
j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
|
||||
(void) cinfo; (void) dinfo; /* silence warnings */ \
|
||||
if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
|
||||
return -1;} \
|
||||
cinfo=&this->cinfo; dinfo=&this->dinfo;
|
||||
|
||||
static int getPixelFormat(int pixelSize, int flags)
|
||||
{
|
||||
if(pixelSize==1) return TJPF_GRAY;
|
||||
if(pixelSize==3)
|
||||
{
|
||||
if(flags&TJ_BGR) return TJPF_BGR;
|
||||
else return TJPF_RGB;
|
||||
}
|
||||
if(pixelSize==4)
|
||||
{
|
||||
if(flags&TJ_ALPHAFIRST)
|
||||
{
|
||||
if(flags&TJ_BGR) return TJPF_XBGR;
|
||||
else return TJPF_XRGB;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(flags&TJ_BGR) return TJPF_BGRX;
|
||||
else return TJPF_RGBX;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int setCompDefaults(struct jpeg_compress_struct *cinfo,
|
||||
int pixelFormat, int subsamp, int jpegQual)
|
||||
{
|
||||
int retval=0;
|
||||
|
||||
switch(pixelFormat)
|
||||
{
|
||||
case TJPF_GRAY:
|
||||
cinfo->in_color_space=JCS_GRAYSCALE; break;
|
||||
#if JCS_EXTENSIONS==1
|
||||
case TJPF_RGB:
|
||||
cinfo->in_color_space=JCS_EXT_RGB; break;
|
||||
case TJPF_BGR:
|
||||
cinfo->in_color_space=JCS_EXT_BGR; break;
|
||||
case TJPF_RGBX:
|
||||
case TJPF_RGBA:
|
||||
cinfo->in_color_space=JCS_EXT_RGBX; break;
|
||||
case TJPF_BGRX:
|
||||
case TJPF_BGRA:
|
||||
cinfo->in_color_space=JCS_EXT_BGRX; break;
|
||||
case TJPF_XRGB:
|
||||
case TJPF_ARGB:
|
||||
cinfo->in_color_space=JCS_EXT_XRGB; break;
|
||||
case TJPF_XBGR:
|
||||
case TJPF_ABGR:
|
||||
cinfo->in_color_space=JCS_EXT_XBGR; break;
|
||||
#else
|
||||
case TJPF_RGB:
|
||||
case TJPF_BGR:
|
||||
case TJPF_RGBX:
|
||||
case TJPF_BGRX:
|
||||
case TJPF_XRGB:
|
||||
case TJPF_XBGR:
|
||||
case TJPF_RGBA:
|
||||
case TJPF_BGRA:
|
||||
case TJPF_ARGB:
|
||||
case TJPF_ABGR:
|
||||
cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cinfo->input_components=tjPixelSize[pixelFormat];
|
||||
jpeg_set_defaults(cinfo);
|
||||
if(jpegQual>=0)
|
||||
{
|
||||
jpeg_set_quality(cinfo, jpegQual, TRUE);
|
||||
if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW;
|
||||
else cinfo->dct_method=JDCT_FASTEST;
|
||||
}
|
||||
if(subsamp==TJSAMP_GRAY)
|
||||
jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
|
||||
else
|
||||
jpeg_set_colorspace(cinfo, JCS_YCbCr);
|
||||
|
||||
cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
|
||||
cinfo->comp_info[1].h_samp_factor=1;
|
||||
cinfo->comp_info[2].h_samp_factor=1;
|
||||
cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
|
||||
cinfo->comp_info[1].v_samp_factor=1;
|
||||
cinfo->comp_info[2].v_samp_factor=1;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
|
||||
int pixelFormat)
|
||||
{
|
||||
int retval=0;
|
||||
|
||||
switch(pixelFormat)
|
||||
{
|
||||
case TJPF_GRAY:
|
||||
dinfo->out_color_space=JCS_GRAYSCALE; break;
|
||||
#if JCS_EXTENSIONS==1
|
||||
case TJPF_RGB:
|
||||
dinfo->out_color_space=JCS_EXT_RGB; break;
|
||||
case TJPF_BGR:
|
||||
dinfo->out_color_space=JCS_EXT_BGR; break;
|
||||
case TJPF_RGBX:
|
||||
dinfo->out_color_space=JCS_EXT_RGBX; break;
|
||||
case TJPF_BGRX:
|
||||
dinfo->out_color_space=JCS_EXT_BGRX; break;
|
||||
case TJPF_XRGB:
|
||||
dinfo->out_color_space=JCS_EXT_XRGB; break;
|
||||
case TJPF_XBGR:
|
||||
dinfo->out_color_space=JCS_EXT_XBGR; break;
|
||||
#if JCS_ALPHA_EXTENSIONS==1
|
||||
case TJPF_RGBA:
|
||||
dinfo->out_color_space=JCS_EXT_RGBA; break;
|
||||
case TJPF_BGRA:
|
||||
dinfo->out_color_space=JCS_EXT_BGRA; break;
|
||||
case TJPF_ARGB:
|
||||
dinfo->out_color_space=JCS_EXT_ARGB; break;
|
||||
case TJPF_ABGR:
|
||||
dinfo->out_color_space=JCS_EXT_ABGR; break;
|
||||
#endif
|
||||
#else
|
||||
case TJPF_RGB:
|
||||
case TJPF_BGR:
|
||||
case TJPF_RGBX:
|
||||
case TJPF_BGRX:
|
||||
case TJPF_XRGB:
|
||||
case TJPF_XBGR:
|
||||
case TJPF_RGBA:
|
||||
case TJPF_BGRA:
|
||||
case TJPF_ARGB:
|
||||
case TJPF_ABGR:
|
||||
dinfo->out_color_space=JCS_RGB; break;
|
||||
#endif
|
||||
default:
|
||||
_throw("Unsupported pixel format");
|
||||
}
|
||||
|
||||
bailout:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int getSubsamp(j_decompress_ptr dinfo)
|
||||
{
|
||||
int retval=-1, i, k;
|
||||
for(i=0; i<NUMSUBOPT; i++)
|
||||
{
|
||||
if(dinfo->num_components==pixelsize[i])
|
||||
{
|
||||
if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
|
||||
&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
|
||||
{
|
||||
int match=0;
|
||||
for(k=1; k<dinfo->num_components; k++)
|
||||
{
|
||||
if(dinfo->comp_info[k].h_samp_factor==1
|
||||
&& dinfo->comp_info[k].v_samp_factor==1)
|
||||
match++;
|
||||
}
|
||||
if(match==dinfo->num_components-1)
|
||||
{
|
||||
retval=i; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
#ifndef JCS_EXTENSIONS
|
||||
|
||||
/* Conversion functions to emulate the colorspace extensions. This allows the
|
||||
TurboJPEG wrapper to be used with libjpeg */
|
||||
|
||||
#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
|
||||
int rowPad=pitch-width*PS; \
|
||||
while(height--) \
|
||||
{ \
|
||||
unsigned char *endOfRow=src+width*PS; \
|
||||
while(src<endOfRow) \
|
||||
{ \
|
||||
dst[RGB_RED]=src[ROFFSET]; \
|
||||
dst[RGB_GREEN]=src[GOFFSET]; \
|
||||
dst[RGB_BLUE]=src[BOFFSET]; \
|
||||
dst+=RGB_PIXELSIZE; src+=PS; \
|
||||
} \
|
||||
src+=rowPad; \
|
||||
} \
|
||||
}
|
||||
|
||||
static unsigned char *toRGB(unsigned char *src, int width, int pitch,
|
||||
int height, int pixelFormat, unsigned char *dst)
|
||||
{
|
||||
unsigned char *retval=src;
|
||||
switch(pixelFormat)
|
||||
{
|
||||
case TJPF_RGB:
|
||||
#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
|
||||
retval=dst; TORGB(3, 0, 1, 2);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_BGR:
|
||||
#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
|
||||
retval=dst; TORGB(3, 2, 1, 0);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_RGBX:
|
||||
case TJPF_RGBA:
|
||||
#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
|
||||
retval=dst; TORGB(4, 0, 1, 2);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_BGRX:
|
||||
case TJPF_BGRA:
|
||||
#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
|
||||
retval=dst; TORGB(4, 2, 1, 0);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_XRGB:
|
||||
case TJPF_ARGB:
|
||||
#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
|
||||
retval=dst; TORGB(4, 1, 2, 3);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_XBGR:
|
||||
case TJPF_ABGR:
|
||||
#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
|
||||
retval=dst; TORGB(4, 3, 2, 1);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
|
||||
int rowPad=pitch-width*PS; \
|
||||
while(height--) \
|
||||
{ \
|
||||
unsigned char *endOfRow=dst+width*PS; \
|
||||
while(dst<endOfRow) \
|
||||
{ \
|
||||
dst[ROFFSET]=src[RGB_RED]; \
|
||||
dst[GOFFSET]=src[RGB_GREEN]; \
|
||||
dst[BOFFSET]=src[RGB_BLUE]; \
|
||||
SETALPHA \
|
||||
dst+=PS; src+=RGB_PIXELSIZE; \
|
||||
} \
|
||||
dst+=rowPad; \
|
||||
} \
|
||||
}
|
||||
|
||||
static void fromRGB(unsigned char *src, unsigned char *dst, int width,
|
||||
int pitch, int height, int pixelFormat)
|
||||
{
|
||||
switch(pixelFormat)
|
||||
{
|
||||
case TJPF_RGB:
|
||||
#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
|
||||
FROMRGB(3, 0, 1, 2,);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_BGR:
|
||||
#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
|
||||
FROMRGB(3, 2, 1, 0,);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_RGBX:
|
||||
#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
|
||||
FROMRGB(4, 0, 1, 2,);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_RGBA:
|
||||
#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
|
||||
FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_BGRX:
|
||||
#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
|
||||
FROMRGB(4, 2, 1, 0,);
|
||||
#endif
|
||||
break;
|
||||
case TJPF_BGRA:
|
||||
#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
|
||||
FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
|
||||
#endif
|
||||
break;
|
||||
case TJPF_XRGB:
|
||||
#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
|
||||
FROMRGB(4, 1, 2, 3,); return;
|
||||
#endif
|
||||
break;
|
||||
case TJPF_ARGB:
|
||||
#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
|
||||
FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
|
||||
#endif
|
||||
break;
|
||||
case TJPF_XBGR:
|
||||
#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
|
||||
FROMRGB(4, 3, 2, 1,); return;
|
||||
#endif
|
||||
break;
|
||||
case TJPF_ABGR:
|
||||
#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
|
||||
FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* General API functions */
|
||||
|
||||
DLLEXPORT char* DLLCALL tjGetErrorStr(void)
|
||||
{
|
||||
return errStr;
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
|
||||
{
|
||||
getinstance(handle);
|
||||
if(setjmp(this->jerr.setjmp_buffer)) return -1;
|
||||
if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
|
||||
if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
|
||||
free(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Compressor */
|
||||
|
||||
static boolean empty_output_buffer(j_compress_ptr cinfo)
|
||||
{
|
||||
ERREXIT(cinfo, JERR_BUFFER_SIZE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void dst_noop(j_compress_ptr cinfo)
|
||||
{
|
||||
}
|
||||
|
||||
static tjhandle _tjInitCompress(tjinstance *this)
|
||||
{
|
||||
/* This is also straight out of example.c */
|
||||
this->cinfo.err=jpeg_std_error(&this->jerr.pub);
|
||||
this->jerr.pub.error_exit=my_error_exit;
|
||||
this->jerr.pub.output_message=my_output_message;
|
||||
|
||||
if(setjmp(this->jerr.setjmp_buffer))
|
||||
{
|
||||
/* If we get here, the JPEG code has signaled an error. */
|
||||
if(this) free(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jpeg_create_compress(&this->cinfo);
|
||||
this->cinfo.dest=&this->jdst;
|
||||
this->jdst.init_destination=dst_noop;
|
||||
this->jdst.empty_output_buffer=empty_output_buffer;
|
||||
this->jdst.term_destination=dst_noop;
|
||||
|
||||
this->init|=COMPRESS;
|
||||
return (tjhandle)this;
|
||||
}
|
||||
|
||||
DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
|
||||
{
|
||||
tjinstance *this=NULL;
|
||||
if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
|
||||
{
|
||||
snprintf(errStr, JMSG_LENGTH_MAX,
|
||||
"tjInitCompress(): Memory allocation failure");
|
||||
return NULL;
|
||||
}
|
||||
MEMZERO(this, sizeof(tjinstance));
|
||||
return _tjInitCompress(this);
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
|
||||
int jpegSubsamp)
|
||||
{
|
||||
unsigned long retval=0; int mcuw, mcuh, chromasf;
|
||||
if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
|
||||
_throw("tjBufSize(): Invalid argument");
|
||||
|
||||
/*
|
||||
* This allows for rare corner cases in which a JPEG image can actually be
|
||||
* larger than the uncompressed input (we wouldn't mention it if it hadn't
|
||||
* happened before.)
|
||||
*/
|
||||
mcuw=tjMCUWidth[jpegSubsamp];
|
||||
mcuh=tjMCUHeight[jpegSubsamp];
|
||||
chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
|
||||
retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
|
||||
|
||||
bailout:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
|
||||
{
|
||||
unsigned long retval=0;
|
||||
if(width<1 || height<1)
|
||||
_throw("TJBUFSIZE(): Invalid argument");
|
||||
|
||||
/*
|
||||
* This allows for rare corner cases in which a JPEG image can actually be
|
||||
* larger than the uncompressed input (we wouldn't mention it if it hadn't
|
||||
* happened before.)
|
||||
*/
|
||||
retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
|
||||
|
||||
bailout:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
|
||||
int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
|
||||
unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
|
||||
{
|
||||
int i, retval=0; JSAMPROW *row_pointer=NULL;
|
||||
#ifndef JCS_EXTENSIONS
|
||||
unsigned char *rgbBuf=NULL;
|
||||
#endif
|
||||
|
||||
getinstance(handle)
|
||||
if((this->init&COMPRESS)==0)
|
||||
_throw("tjCompress2(): Instance has not been initialized for compression");
|
||||
|
||||
if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
|
||||
|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
|
||||
|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
|
||||
_throw("tjCompress2(): Invalid argument");
|
||||
|
||||
if(setjmp(this->jerr.setjmp_buffer))
|
||||
{
|
||||
/* If we get here, the JPEG code has signaled an error. */
|
||||
retval=-1;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
|
||||
|
||||
#ifndef JCS_EXTENSIONS
|
||||
if(pixelFormat!=TJPF_GRAY)
|
||||
{
|
||||
rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
|
||||
if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
|
||||
srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
|
||||
pitch=width*RGB_PIXELSIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
cinfo->image_width=width;
|
||||
cinfo->image_height=height;
|
||||
|
||||
if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
|
||||
else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
|
||||
else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
|
||||
|
||||
if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
|
||||
return -1;
|
||||
|
||||
this->jdst.next_output_byte=*jpegBuf;
|
||||
this->jdst.free_in_buffer=tjBufSize(width, height, jpegSubsamp);
|
||||
|
||||
jpeg_start_compress(cinfo, TRUE);
|
||||
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
|
||||
_throw("tjCompress2(): Memory allocation failure");
|
||||
for(i=0; i<height; i++)
|
||||
{
|
||||
if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
|
||||
else row_pointer[i]=&srcBuf[i*pitch];
|
||||
}
|
||||
while(cinfo->next_scanline<cinfo->image_height)
|
||||
{
|
||||
jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
|
||||
cinfo->image_height-cinfo->next_scanline);
|
||||
}
|
||||
jpeg_finish_compress(cinfo);
|
||||
*jpegSize=tjBufSize(width, height, jpegSubsamp)
|
||||
-(unsigned long)(this->jdst.free_in_buffer);
|
||||
|
||||
bailout:
|
||||
if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
|
||||
#ifndef JCS_EXTENSIONS
|
||||
if(rgbBuf) free(rgbBuf);
|
||||
#endif
|
||||
if(row_pointer) free(row_pointer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
|
||||
int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
|
||||
unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
|
||||
{
|
||||
int retval=0; unsigned long size = 0;
|
||||
retval=tjCompress2(handle, srcBuf, width, pitch, height,
|
||||
getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
|
||||
flags);
|
||||
*jpegSize=size;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* Decompressor */
|
||||
|
||||
static boolean fill_input_buffer(j_decompress_ptr dinfo)
|
||||
{
|
||||
ERREXIT(dinfo, JERR_BUFFER_SIZE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void skip_input_data(j_decompress_ptr dinfo, long num_bytes)
|
||||
{
|
||||
dinfo->src->next_input_byte += (size_t) num_bytes;
|
||||
dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
|
||||
}
|
||||
|
||||
static void src_noop(j_decompress_ptr dinfo)
|
||||
{
|
||||
}
|
||||
|
||||
static tjhandle _tjInitDecompress(tjinstance *this)
|
||||
{
|
||||
/* This is also straight out of example.c */
|
||||
this->dinfo.err=jpeg_std_error(&this->jerr.pub);
|
||||
this->jerr.pub.error_exit=my_error_exit;
|
||||
this->jerr.pub.output_message=my_output_message;
|
||||
|
||||
if(setjmp(this->jerr.setjmp_buffer))
|
||||
{
|
||||
/* If we get here, the JPEG code has signaled an error. */
|
||||
if(this) free(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jpeg_create_decompress(&this->dinfo);
|
||||
this->dinfo.src=&this->jsrc;
|
||||
this->jsrc.init_source=src_noop;
|
||||
this->jsrc.fill_input_buffer=fill_input_buffer;
|
||||
this->jsrc.skip_input_data=skip_input_data;
|
||||
this->jsrc.resync_to_restart=jpeg_resync_to_restart;
|
||||
this->jsrc.term_source=src_noop;
|
||||
|
||||
this->init|=DECOMPRESS;
|
||||
return (tjhandle)this;
|
||||
}
|
||||
|
||||
DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
|
||||
{
|
||||
tjinstance *this;
|
||||
if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
|
||||
{
|
||||
snprintf(errStr, JMSG_LENGTH_MAX,
|
||||
"tjInitDecompress(): Memory allocation failure");
|
||||
return NULL;
|
||||
}
|
||||
MEMZERO(this, sizeof(tjinstance));
|
||||
return _tjInitDecompress(this);
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
|
||||
unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
|
||||
int *jpegSubsamp)
|
||||
{
|
||||
int retval=0;
|
||||
|
||||
getinstance(handle);
|
||||
if((this->init&DECOMPRESS)==0)
|
||||
_throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
|
||||
|
||||
if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
|
||||
|| jpegSubsamp==NULL)
|
||||
_throw("tjDecompressHeader2(): Invalid argument");
|
||||
|
||||
if(setjmp(this->jerr.setjmp_buffer))
|
||||
{
|
||||
/* If we get here, the JPEG code has signaled an error. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
this->jsrc.bytes_in_buffer=jpegSize;
|
||||
this->jsrc.next_input_byte=jpegBuf;
|
||||
jpeg_read_header(dinfo, TRUE);
|
||||
|
||||
*width=dinfo->image_width;
|
||||
*height=dinfo->image_height;
|
||||
*jpegSubsamp=getSubsamp(dinfo);
|
||||
|
||||
jpeg_abort_decompress(dinfo);
|
||||
|
||||
if(*jpegSubsamp<0)
|
||||
_throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
|
||||
if(*width<1 || *height<1)
|
||||
_throw("tjDecompressHeader2(): Invalid data returned in header");
|
||||
|
||||
bailout:
|
||||
return retval;
|
||||
}
|
||||
|
||||
DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
|
||||
unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
|
||||
{
|
||||
int jpegSubsamp;
|
||||
return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
|
||||
&jpegSubsamp);
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
|
||||
{
|
||||
if(numscalingfactors==NULL)
|
||||
{
|
||||
snprintf(errStr, JMSG_LENGTH_MAX,
|
||||
"tjGetScalingFactors(): Invalid argument");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*numscalingfactors=NUMSF;
|
||||
return (tjscalingfactor *)sf;
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
|
||||
unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
|
||||
int height, int pixelFormat, int flags)
|
||||
{
|
||||
int i, retval=0; JSAMPROW *row_pointer=NULL;
|
||||
int jpegwidth, jpegheight, scaledw, scaledh;
|
||||
#ifndef JCS_EXTENSIONS
|
||||
unsigned char *rgbBuf=NULL;
|
||||
unsigned char *_dstBuf=NULL; int _pitch=0;
|
||||
#endif
|
||||
|
||||
getinstance(handle);
|
||||
if((this->init&DECOMPRESS)==0)
|
||||
_throw("tjDecompress2(): Instance has not been initialized for decompression");
|
||||
|
||||
if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
|
||||
|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
|
||||
_throw("tjDecompress2(): Invalid argument");
|
||||
|
||||
if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
|
||||
else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
|
||||
else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
|
||||
|
||||
if(setjmp(this->jerr.setjmp_buffer))
|
||||
{
|
||||
/* If we get here, the JPEG code has signaled an error. */
|
||||
retval=-1;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
this->jsrc.bytes_in_buffer=jpegSize;
|
||||
this->jsrc.next_input_byte=jpegBuf;
|
||||
jpeg_read_header(dinfo, TRUE);
|
||||
if(setDecompDefaults(dinfo, pixelFormat)==-1)
|
||||
{
|
||||
retval=-1; goto bailout;
|
||||
}
|
||||
|
||||
if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
|
||||
|
||||
jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
|
||||
if(width==0) width=jpegwidth;
|
||||
if(height==0) height=jpegheight;
|
||||
for(i=0; i<NUMSF; i++)
|
||||
{
|
||||
scaledw=TJSCALED(jpegwidth, sf[i]);
|
||||
scaledh=TJSCALED(jpegheight, sf[i]);
|
||||
if(scaledw<=width && scaledh<=height)
|
||||
break;
|
||||
}
|
||||
if(scaledw>width || scaledh>height)
|
||||
_throw("tjDecompress2(): Could not scale down to desired image dimensions");
|
||||
#ifndef JCS_EXTENSIONS
|
||||
width=scaledw; height=scaledh;
|
||||
#endif
|
||||
dinfo->scale_num=sf[i].num;
|
||||
dinfo->scale_denom=sf[i].denom;
|
||||
|
||||
jpeg_start_decompress(dinfo);
|
||||
if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
|
||||
|
||||
#ifndef JCS_EXTENSIONS
|
||||
if(pixelFormat!=TJPF_GRAY &&
|
||||
(RGB_RED!=tjRedOffset[pixelFormat] ||
|
||||
RGB_GREEN!=tjGreenOffset[pixelFormat] ||
|
||||
RGB_BLUE!=tjBlueOffset[pixelFormat] ||
|
||||
RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
|
||||
{
|
||||
rgbBuf=(unsigned char *)malloc(width*height*3);
|
||||
if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
|
||||
_pitch=pitch; pitch=width*3;
|
||||
_dstBuf=dstBuf; dstBuf=rgbBuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
|
||||
*dinfo->output_height))==NULL)
|
||||
_throw("tjDecompress2(): Memory allocation failure");
|
||||
for(i=0; i<(int)dinfo->output_height; i++)
|
||||
{
|
||||
if(flags&TJFLAG_BOTTOMUP)
|
||||
row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
|
||||
else row_pointer[i]=&dstBuf[i*pitch];
|
||||
}
|
||||
while(dinfo->output_scanline<dinfo->output_height)
|
||||
{
|
||||
jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
|
||||
dinfo->output_height-dinfo->output_scanline);
|
||||
}
|
||||
jpeg_finish_decompress(dinfo);
|
||||
|
||||
#ifndef JCS_EXTENSIONS
|
||||
fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
|
||||
#endif
|
||||
|
||||
bailout:
|
||||
if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
|
||||
#ifndef JCS_EXTENSIONS
|
||||
if(rgbBuf) free(rgbBuf);
|
||||
#endif
|
||||
if(row_pointer) free(row_pointer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
|
||||
unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
|
||||
int height, int pixelSize, int flags)
|
||||
{
|
||||
return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
|
||||
height, getPixelFormat(pixelSize, flags), flags);
|
||||
}
|
||||
534
android/extern/libvncserver/src/common/turbojpeg.h
vendored
Normal file
534
android/extern/libvncserver/src/common/turbojpeg.h
vendored
Normal file
@@ -0,0 +1,534 @@
|
||||
|
||||
/*
|
||||
* Copyright (C)2009-2012 D. R. Commander. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the libjpeg-turbo Project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __TURBOJPEG_H__
|
||||
#define __TURBOJPEG_H__
|
||||
|
||||
#if defined(_WIN32) && defined(DLLDEFINE)
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define DLLEXPORT
|
||||
#endif
|
||||
#define DLLCALL
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup TurboJPEG Lite
|
||||
* TurboJPEG API. This API provides an interface for generating and decoding
|
||||
* JPEG images in memory.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The number of chrominance subsampling options
|
||||
*/
|
||||
#define TJ_NUMSAMP 5
|
||||
|
||||
/**
|
||||
* Chrominance subsampling options.
|
||||
* When an image is converted from the RGB to the YCbCr colorspace as part of
|
||||
* the JPEG compression process, some of the Cb and Cr (chrominance) components
|
||||
* can be discarded or averaged together to produce a smaller image with little
|
||||
* perceptible loss of image clarity (the human eye is more sensitive to small
|
||||
* changes in brightness than small changes in color.) This is called
|
||||
* "chrominance subsampling".
|
||||
*/
|
||||
enum TJSAMP
|
||||
{
|
||||
/**
|
||||
* 4:4:4 chrominance subsampling (no chrominance subsampling). The JPEG or
|
||||
* YUV image will contain one chrominance component for every pixel in the
|
||||
* source image.
|
||||
*/
|
||||
TJSAMP_444=0,
|
||||
/**
|
||||
* 4:2:2 chrominance subsampling. The JPEG or YUV image will contain one
|
||||
* chrominance component for every 2x1 block of pixels in the source image.
|
||||
*/
|
||||
TJSAMP_422,
|
||||
/**
|
||||
* 4:2:0 chrominance subsampling. The JPEG or YUV image will contain one
|
||||
* chrominance component for every 2x2 block of pixels in the source image.
|
||||
*/
|
||||
TJSAMP_420,
|
||||
/**
|
||||
* Grayscale. The JPEG or YUV image will contain no chrominance components.
|
||||
*/
|
||||
TJSAMP_GRAY,
|
||||
/**
|
||||
* 4:4:0 chrominance subsampling. The JPEG or YUV image will contain one
|
||||
* chrominance component for every 1x2 block of pixels in the source image.
|
||||
*/
|
||||
TJSAMP_440
|
||||
};
|
||||
|
||||
/**
|
||||
* MCU block width (in pixels) for a given level of chrominance subsampling.
|
||||
* MCU block sizes:
|
||||
* - 8x8 for no subsampling or grayscale
|
||||
* - 16x8 for 4:2:2
|
||||
* - 8x16 for 4:4:0
|
||||
* - 16x16 for 4:2:0
|
||||
*/
|
||||
static const int tjMCUWidth[TJ_NUMSAMP] = {8, 16, 16, 8, 8};
|
||||
|
||||
/**
|
||||
* MCU block height (in pixels) for a given level of chrominance subsampling.
|
||||
* MCU block sizes:
|
||||
* - 8x8 for no subsampling or grayscale
|
||||
* - 16x8 for 4:2:2
|
||||
* - 8x16 for 4:4:0
|
||||
* - 16x16 for 4:2:0
|
||||
*/
|
||||
static const int tjMCUHeight[TJ_NUMSAMP] = {8, 8, 16, 8, 16};
|
||||
|
||||
|
||||
/**
|
||||
* The number of pixel formats
|
||||
*/
|
||||
#define TJ_NUMPF 11
|
||||
|
||||
/**
|
||||
* Pixel formats
|
||||
*/
|
||||
enum TJPF
|
||||
{
|
||||
/**
|
||||
* RGB pixel format. The red, green, and blue components in the image are
|
||||
* stored in 3-byte pixels in the order R, G, B from lowest to highest byte
|
||||
* address within each pixel.
|
||||
*/
|
||||
TJPF_RGB=0,
|
||||
/**
|
||||
* BGR pixel format. The red, green, and blue components in the image are
|
||||
* stored in 3-byte pixels in the order B, G, R from lowest to highest byte
|
||||
* address within each pixel.
|
||||
*/
|
||||
TJPF_BGR,
|
||||
/**
|
||||
* RGBX pixel format. The red, green, and blue components in the image are
|
||||
* stored in 4-byte pixels in the order R, G, B from lowest to highest byte
|
||||
* address within each pixel. The X component is ignored when compressing
|
||||
* and undefined when decompressing.
|
||||
*/
|
||||
TJPF_RGBX,
|
||||
/**
|
||||
* BGRX pixel format. The red, green, and blue components in the image are
|
||||
* stored in 4-byte pixels in the order B, G, R from lowest to highest byte
|
||||
* address within each pixel. The X component is ignored when compressing
|
||||
* and undefined when decompressing.
|
||||
*/
|
||||
TJPF_BGRX,
|
||||
/**
|
||||
* XBGR pixel format. The red, green, and blue components in the image are
|
||||
* stored in 4-byte pixels in the order R, G, B from highest to lowest byte
|
||||
* address within each pixel. The X component is ignored when compressing
|
||||
* and undefined when decompressing.
|
||||
*/
|
||||
TJPF_XBGR,
|
||||
/**
|
||||
* XRGB pixel format. The red, green, and blue components in the image are
|
||||
* stored in 4-byte pixels in the order B, G, R from highest to lowest byte
|
||||
* address within each pixel. The X component is ignored when compressing
|
||||
* and undefined when decompressing.
|
||||
*/
|
||||
TJPF_XRGB,
|
||||
/**
|
||||
* Grayscale pixel format. Each 1-byte pixel represents a luminance
|
||||
* (brightness) level from 0 to 255.
|
||||
*/
|
||||
TJPF_GRAY,
|
||||
/**
|
||||
* RGBA pixel format. This is the same as @ref TJPF_RGBX, except that when
|
||||
* decompressing, the X component is guaranteed to be 0xFF, which can be
|
||||
* interpreted as an opaque alpha channel.
|
||||
*/
|
||||
TJPF_RGBA,
|
||||
/**
|
||||
* BGRA pixel format. This is the same as @ref TJPF_BGRX, except that when
|
||||
* decompressing, the X component is guaranteed to be 0xFF, which can be
|
||||
* interpreted as an opaque alpha channel.
|
||||
*/
|
||||
TJPF_BGRA,
|
||||
/**
|
||||
* ABGR pixel format. This is the same as @ref TJPF_XBGR, except that when
|
||||
* decompressing, the X component is guaranteed to be 0xFF, which can be
|
||||
* interpreted as an opaque alpha channel.
|
||||
*/
|
||||
TJPF_ABGR,
|
||||
/**
|
||||
* ARGB pixel format. This is the same as @ref TJPF_XRGB, except that when
|
||||
* decompressing, the X component is guaranteed to be 0xFF, which can be
|
||||
* interpreted as an opaque alpha channel.
|
||||
*/
|
||||
TJPF_ARGB
|
||||
};
|
||||
|
||||
/**
|
||||
* Red offset (in bytes) for a given pixel format. This specifies the number
|
||||
* of bytes that the red component is offset from the start of the pixel. For
|
||||
* instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>,
|
||||
* then the red component will be <tt>pixel[tjRedOffset[TJ_BGRX]]</tt>.
|
||||
*/
|
||||
static const int tjRedOffset[TJ_NUMPF] = {0, 2, 0, 2, 3, 1, 0, 0, 2, 3, 1};
|
||||
/**
|
||||
* Green offset (in bytes) for a given pixel format. This specifies the number
|
||||
* of bytes that the green component is offset from the start of the pixel.
|
||||
* For instance, if a pixel of format TJ_BGRX is stored in
|
||||
* <tt>char pixel[]</tt>, then the green component will be
|
||||
* <tt>pixel[tjGreenOffset[TJ_BGRX]]</tt>.
|
||||
*/
|
||||
static const int tjGreenOffset[TJ_NUMPF] = {1, 1, 1, 1, 2, 2, 0, 1, 1, 2, 2};
|
||||
/**
|
||||
* Blue offset (in bytes) for a given pixel format. This specifies the number
|
||||
* of bytes that the Blue component is offset from the start of the pixel. For
|
||||
* instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>,
|
||||
* then the blue component will be <tt>pixel[tjBlueOffset[TJ_BGRX]]</tt>.
|
||||
*/
|
||||
static const int tjBlueOffset[TJ_NUMPF] = {2, 0, 2, 0, 1, 3, 0, 2, 0, 1, 3};
|
||||
|
||||
/**
|
||||
* Pixel size (in bytes) for a given pixel format.
|
||||
*/
|
||||
static const int tjPixelSize[TJ_NUMPF] = {3, 3, 4, 4, 4, 4, 1, 4, 4, 4, 4};
|
||||
|
||||
|
||||
/**
|
||||
* The uncompressed source/destination image is stored in bottom-up (Windows,
|
||||
* OpenGL) order, not top-down (X11) order.
|
||||
*/
|
||||
#define TJFLAG_BOTTOMUP 2
|
||||
/**
|
||||
* Turn off CPU auto-detection and force TurboJPEG to use MMX code (IPP and
|
||||
* 32-bit libjpeg-turbo versions only.)
|
||||
*/
|
||||
#define TJFLAG_FORCEMMX 8
|
||||
/**
|
||||
* Turn off CPU auto-detection and force TurboJPEG to use SSE code (32-bit IPP
|
||||
* and 32-bit libjpeg-turbo versions only)
|
||||
*/
|
||||
#define TJFLAG_FORCESSE 16
|
||||
/**
|
||||
* Turn off CPU auto-detection and force TurboJPEG to use SSE2 code (32-bit IPP
|
||||
* and 32-bit libjpeg-turbo versions only)
|
||||
*/
|
||||
#define TJFLAG_FORCESSE2 32
|
||||
/**
|
||||
* Turn off CPU auto-detection and force TurboJPEG to use SSE3 code (64-bit IPP
|
||||
* version only)
|
||||
*/
|
||||
#define TJFLAG_FORCESSE3 128
|
||||
/**
|
||||
* Use fast, inaccurate chrominance upsampling routines in the JPEG
|
||||
* decompressor (libjpeg and libjpeg-turbo versions only)
|
||||
*/
|
||||
#define TJFLAG_FASTUPSAMPLE 256
|
||||
|
||||
|
||||
/**
|
||||
* Scaling factor
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* Numerator
|
||||
*/
|
||||
int num;
|
||||
/**
|
||||
* Denominator
|
||||
*/
|
||||
int denom;
|
||||
} tjscalingfactor;
|
||||
|
||||
|
||||
/**
|
||||
* TurboJPEG instance handle
|
||||
*/
|
||||
typedef void* tjhandle;
|
||||
|
||||
|
||||
/**
|
||||
* Pad the given width to the nearest 32-bit boundary
|
||||
*/
|
||||
#define TJPAD(width) (((width)+3)&(~3))
|
||||
|
||||
/**
|
||||
* Compute the scaled value of <tt>dimension</tt> using the given scaling
|
||||
* factor. This macro performs the integer equivalent of <tt>ceil(dimension *
|
||||
* scalingFactor)</tt>.
|
||||
*/
|
||||
#define TJSCALED(dimension, scalingFactor) ((dimension * scalingFactor.num \
|
||||
+ scalingFactor.denom - 1) / scalingFactor.denom)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Create a TurboJPEG compressor instance.
|
||||
*
|
||||
* @return a handle to the newly-created instance, or NULL if an error
|
||||
* occurred (see #tjGetErrorStr().)
|
||||
*/
|
||||
DLLEXPORT tjhandle DLLCALL tjInitCompress(void);
|
||||
|
||||
|
||||
/**
|
||||
* Compress an RGB or grayscale image into a JPEG image.
|
||||
*
|
||||
* @param handle a handle to a TurboJPEG compressor or transformer instance
|
||||
* @param srcBuf pointer to an image buffer containing RGB or grayscale pixels
|
||||
* to be compressed
|
||||
* @param width width (in pixels) of the source image
|
||||
* @param pitch bytes per line of the source image. Normally, this should be
|
||||
* <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded,
|
||||
* or <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of
|
||||
* the image is padded to the nearest 32-bit boundary, as is the case
|
||||
* for Windows bitmaps. You can also be clever and use this parameter
|
||||
* to skip lines, etc. Setting this parameter to 0 is the equivalent of
|
||||
* setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
|
||||
* @param height height (in pixels) of the source image
|
||||
* @param pixelFormat pixel format of the source image (see @ref TJPF
|
||||
* "Pixel formats".)
|
||||
* @param jpegBuf address of a pointer to an image buffer that will receive the
|
||||
* JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer
|
||||
* to accommodate the size of the JPEG image. Thus, you can choose to:
|
||||
* -# pre-allocate the JPEG buffer with an arbitrary size using
|
||||
* #tjAlloc() and let TurboJPEG grow the buffer as needed,
|
||||
* -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the
|
||||
* buffer for you, or
|
||||
* -# pre-allocate the buffer to a "worst case" size determined by
|
||||
* calling #tjBufSize(). This should ensure that the buffer never has
|
||||
* to be re-allocated (setting #TJFLAG_NOREALLOC guarantees this.)
|
||||
* .
|
||||
* If you choose option 1, <tt>*jpegSize</tt> should be set to the
|
||||
* size of your pre-allocated buffer. In any case, unless you have
|
||||
* set #TJFLAG_NOREALLOC, you should always check <tt>*jpegBuf</tt> upon
|
||||
* return from this function, as it may have changed.
|
||||
* @param jpegSize pointer to an unsigned long variable that holds the size of
|
||||
* the JPEG image buffer. If <tt>*jpegBuf</tt> points to a
|
||||
* pre-allocated buffer, then <tt>*jpegSize</tt> should be set to the
|
||||
* size of the buffer. Upon return, <tt>*jpegSize</tt> will contain the
|
||||
* size of the JPEG image (in bytes.)
|
||||
* @param jpegSubsamp the level of chrominance subsampling to be used when
|
||||
* generating the JPEG image (see @ref TJSAMP
|
||||
* "Chrominance subsampling options".)
|
||||
* @param jpegQual the image quality of the generated JPEG image (1 = worst,
|
||||
100 = best)
|
||||
* @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
|
||||
* "flags".
|
||||
*
|
||||
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
|
||||
*/
|
||||
DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
|
||||
int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
|
||||
unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* The maximum size of the buffer (in bytes) required to hold a JPEG image with
|
||||
* the given parameters. The number of bytes returned by this function is
|
||||
* larger than the size of the uncompressed source image. The reason for this
|
||||
* is that the JPEG format uses 16-bit coefficients, and it is thus possible
|
||||
* for a very high-quality JPEG image with very high frequency content to
|
||||
* expand rather than compress when converted to the JPEG format. Such images
|
||||
* represent a very rare corner case, but since there is no way to predict the
|
||||
* size of a JPEG image prior to compression, the corner case has to be
|
||||
* handled.
|
||||
*
|
||||
* @param width width of the image (in pixels)
|
||||
* @param height height of the image (in pixels)
|
||||
* @param jpegSubsamp the level of chrominance subsampling to be used when
|
||||
* generating the JPEG image (see @ref TJSAMP
|
||||
* "Chrominance subsampling options".)
|
||||
*
|
||||
* @return the maximum size of the buffer (in bytes) required to hold the
|
||||
* image, or -1 if the arguments are out of bounds.
|
||||
*/
|
||||
DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
|
||||
int jpegSubsamp);
|
||||
|
||||
|
||||
/**
|
||||
* Create a TurboJPEG decompressor instance.
|
||||
*
|
||||
* @return a handle to the newly-created instance, or NULL if an error
|
||||
* occurred (see #tjGetErrorStr().)
|
||||
*/
|
||||
DLLEXPORT tjhandle DLLCALL tjInitDecompress(void);
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve information about a JPEG image without decompressing it.
|
||||
*
|
||||
* @param handle a handle to a TurboJPEG decompressor or transformer instance
|
||||
* @param jpegBuf pointer to a buffer containing a JPEG image
|
||||
* @param jpegSize size of the JPEG image (in bytes)
|
||||
* @param width pointer to an integer variable that will receive the width (in
|
||||
* pixels) of the JPEG image
|
||||
* @param height pointer to an integer variable that will receive the height
|
||||
* (in pixels) of the JPEG image
|
||||
* @param jpegSubsamp pointer to an integer variable that will receive the
|
||||
* level of chrominance subsampling used when compressing the JPEG image
|
||||
* (see @ref TJSAMP "Chrominance subsampling options".)
|
||||
*
|
||||
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
|
||||
*/
|
||||
DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
|
||||
unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
|
||||
int *jpegSubsamp);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of fractional scaling factors that the JPEG decompressor in
|
||||
* this implementation of TurboJPEG supports.
|
||||
*
|
||||
* @param numscalingfactors pointer to an integer variable that will receive
|
||||
* the number of elements in the list
|
||||
*
|
||||
* @return a pointer to a list of fractional scaling factors, or NULL if an
|
||||
* error is encountered (see #tjGetErrorStr().)
|
||||
*/
|
||||
DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors);
|
||||
|
||||
|
||||
/**
|
||||
* Decompress a JPEG image to an RGB or grayscale image.
|
||||
*
|
||||
* @param handle a handle to a TurboJPEG decompressor or transformer instance
|
||||
* @param jpegBuf pointer to a buffer containing the JPEG image to decompress
|
||||
* @param jpegSize size of the JPEG image (in bytes)
|
||||
* @param dstBuf pointer to an image buffer that will receive the decompressed
|
||||
* image. This buffer should normally be <tt>pitch * scaledHeight</tt>
|
||||
* bytes in size, where <tt>scaledHeight</tt> can be determined by
|
||||
* calling #TJSCALED() with the JPEG image height and one of the scaling
|
||||
* factors returned by #tjGetScalingFactors(). The dstBuf pointer may
|
||||
* also be used to decompress into a specific region of a larger buffer.
|
||||
* @param width desired width (in pixels) of the destination image. If this is
|
||||
* smaller than the width of the JPEG image being decompressed, then
|
||||
* TurboJPEG will use scaling in the JPEG decompressor to generate the
|
||||
* largest possible image that will fit within the desired width. If
|
||||
* width is set to 0, then only the height will be considered when
|
||||
* determining the scaled image size.
|
||||
* @param pitch bytes per line of the destination image. Normally, this is
|
||||
* <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt> if the decompressed
|
||||
* image is unpadded, else <tt>#TJPAD(scaledWidth *
|
||||
* #tjPixelSize[pixelFormat])</tt> if each line of the decompressed
|
||||
* image is padded to the nearest 32-bit boundary, as is the case for
|
||||
* Windows bitmaps. (NOTE: <tt>scaledWidth</tt> can be determined by
|
||||
* calling #TJSCALED() with the JPEG image width and one of the scaling
|
||||
* factors returned by #tjGetScalingFactors().) You can also be clever
|
||||
* and use the pitch parameter to skip lines, etc. Setting this
|
||||
* parameter to 0 is the equivalent of setting it to <tt>scaledWidth
|
||||
* * #tjPixelSize[pixelFormat]</tt>.
|
||||
* @param height desired height (in pixels) of the destination image. If this
|
||||
* is smaller than the height of the JPEG image being decompressed, then
|
||||
* TurboJPEG will use scaling in the JPEG decompressor to generate the
|
||||
* largest possible image that will fit within the desired height. If
|
||||
* height is set to 0, then only the width will be considered when
|
||||
* determining the scaled image size.
|
||||
* @param pixelFormat pixel format of the destination image (see @ref
|
||||
* TJPF "Pixel formats".)
|
||||
* @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
|
||||
* "flags".
|
||||
*
|
||||
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
|
||||
*/
|
||||
DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
|
||||
unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
|
||||
int width, int pitch, int height, int pixelFormat, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a TurboJPEG compressor, decompressor, or transformer instance.
|
||||
*
|
||||
* @param handle a handle to a TurboJPEG compressor, decompressor or
|
||||
* transformer instance
|
||||
*
|
||||
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
|
||||
*/
|
||||
DLLEXPORT int DLLCALL tjDestroy(tjhandle handle);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a descriptive error message explaining why the last command failed.
|
||||
*
|
||||
* @return a descriptive error message explaining why the last command failed.
|
||||
*/
|
||||
DLLEXPORT char* DLLCALL tjGetErrorStr(void);
|
||||
|
||||
|
||||
/* Backward compatibility functions and macros (nothing to see here) */
|
||||
#define NUMSUBOPT TJ_NUMSAMP
|
||||
#define TJ_444 TJSAMP_444
|
||||
#define TJ_422 TJSAMP_422
|
||||
#define TJ_420 TJSAMP_420
|
||||
#define TJ_411 TJSAMP_420
|
||||
#define TJ_GRAYSCALE TJSAMP_GRAY
|
||||
|
||||
#define TJ_BGR 1
|
||||
#define TJ_BOTTOMUP TJFLAG_BOTTOMUP
|
||||
#define TJ_FORCEMMX TJFLAG_FORCEMMX
|
||||
#define TJ_FORCESSE TJFLAG_FORCESSE
|
||||
#define TJ_FORCESSE2 TJFLAG_FORCESSE2
|
||||
#define TJ_ALPHAFIRST 64
|
||||
#define TJ_FORCESSE3 TJFLAG_FORCESSE3
|
||||
#define TJ_FASTUPSAMPLE TJFLAG_FASTUPSAMPLE
|
||||
|
||||
DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height);
|
||||
|
||||
DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
|
||||
int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
|
||||
unsigned long *compressedSize, int jpegSubsamp, int jpegQual, int flags);
|
||||
|
||||
DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
|
||||
unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height);
|
||||
|
||||
DLLEXPORT int DLLCALL tjDecompress(tjhandle handle,
|
||||
unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
|
||||
int width, int pitch, int height, int pixelSize, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
215
android/extern/libvncserver/src/common/vncauth.c
vendored
Normal file
215
android/extern/libvncserver/src/common/vncauth.c
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* vncauth.c - Functions for VNC password management and authentication.
|
||||
*/
|
||||
|
||||
#include <rfb/rfbproto.h>
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#define _POSIX_SOURCE
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef LIBVNCSERVER_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "crypto.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#define srandom srand
|
||||
#define random rand
|
||||
#include <process.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* libvncclient does not need this */
|
||||
#ifndef rfbEncryptBytes
|
||||
|
||||
/*
|
||||
* We use a fixed key to store passwords, since we assume that our local
|
||||
* file system is secure but nonetheless don't want to store passwords
|
||||
* as plaintext.
|
||||
*/
|
||||
|
||||
static unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7};
|
||||
|
||||
|
||||
/*
|
||||
* Encrypt a password and store it in a file. Returns 0 if successful,
|
||||
* 1 if the file could not be written.
|
||||
*/
|
||||
|
||||
int
|
||||
rfbEncryptAndStorePasswd(char *passwd, char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned int i;
|
||||
unsigned char encryptedPasswd[8];
|
||||
int out_len;
|
||||
|
||||
if ((fp = fopen(fname,"w")) == NULL) return 1;
|
||||
|
||||
/* windows security sux */
|
||||
#ifndef WIN32
|
||||
fchmod(fileno(fp), S_IRUSR|S_IWUSR);
|
||||
#endif
|
||||
|
||||
/* pad password with nulls */
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i < strlen(passwd)) {
|
||||
encryptedPasswd[i] = passwd[i];
|
||||
} else {
|
||||
encryptedPasswd[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do encryption in-place - this way we overwrite our copy of the plaintext
|
||||
password */
|
||||
encrypt_rfbdes(encryptedPasswd, &out_len, fixedkey, encryptedPasswd, sizeof(encryptedPasswd));
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
putc(encryptedPasswd[i], fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decrypt a password from a file. Returns a pointer to a newly allocated
|
||||
* string containing the password or a null pointer if the password could
|
||||
* not be retrieved for some reason.
|
||||
*/
|
||||
|
||||
char *
|
||||
rfbDecryptPasswdFromFile(char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
int i, ch;
|
||||
unsigned char *passwd = (unsigned char *)malloc(9);
|
||||
int out_len;
|
||||
|
||||
if (!passwd || (fp = fopen(fname,"r")) == NULL) {
|
||||
free(passwd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
ch = getc(fp);
|
||||
if (ch == EOF) {
|
||||
fclose(fp);
|
||||
free(passwd);
|
||||
return NULL;
|
||||
}
|
||||
passwd[i] = ch;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if(!decrypt_rfbdes(passwd, &out_len, fixedkey, passwd, 8))
|
||||
return NULL;
|
||||
|
||||
passwd[8] = 0;
|
||||
|
||||
return (char *)passwd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate CHALLENGESIZE random bytes for use in challenge-response
|
||||
* authentication.
|
||||
*/
|
||||
|
||||
void
|
||||
rfbRandomBytes(unsigned char *bytes)
|
||||
{
|
||||
int i;
|
||||
static rfbBool s_srandom_called = FALSE;
|
||||
|
||||
if (!s_srandom_called) {
|
||||
srandom((unsigned int)time(NULL) ^ (unsigned int)getpid());
|
||||
s_srandom_called = TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < CHALLENGESIZE; i++) {
|
||||
bytes[i] = (unsigned char)(random() & 255);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Encrypt CHALLENGESIZE bytes in memory using a password.
|
||||
*/
|
||||
|
||||
void
|
||||
rfbEncryptBytes(unsigned char *bytes, char *passwd)
|
||||
{
|
||||
unsigned char key[8];
|
||||
unsigned int i;
|
||||
int out_len;
|
||||
|
||||
/* key is simply password padded with nulls */
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i < strlen(passwd)) {
|
||||
key[i] = passwd[i];
|
||||
} else {
|
||||
key[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
encrypt_rfbdes(bytes, &out_len, key, bytes, CHALLENGESIZE);
|
||||
}
|
||||
|
||||
void
|
||||
rfbEncryptBytes2(unsigned char *where, const int length, unsigned char *key) {
|
||||
int i, j, out_len;
|
||||
for (i = 0; i< 8; i++)
|
||||
where[i] ^= key[i];
|
||||
encrypt_rfbdes(where, &out_len, key, where, 8);
|
||||
for (i = 8; i < length; i += 8) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
where[i + j] ^= where[i + j - 8];
|
||||
}
|
||||
encrypt_rfbdes(where + i, &out_len, key, where + i, 8);
|
||||
}
|
||||
}
|
||||
828
android/extern/libvncserver/src/common/zywrletemplate.c
vendored
Normal file
828
android/extern/libvncserver/src/common/zywrletemplate.c
vendored
Normal file
@@ -0,0 +1,828 @@
|
||||
|
||||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE. *
|
||||
* *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE. *
|
||||
* PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006 *
|
||||
* BY Hitachi Systems & Services, Ltd. *
|
||||
* (Noriaki Yamazaki, Research & Development Center) * *
|
||||
* *
|
||||
********************************************************************
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Hitachi Systems & Services, Ltd. nor
|
||||
the names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
********************************************************************/
|
||||
|
||||
/* Change Log:
|
||||
V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline
|
||||
(Thanks Johannes Schindelin, author of LibVNC
|
||||
Server/Client)
|
||||
V0.01 : 2007/02/06 : Initial release
|
||||
*/
|
||||
|
||||
/* #define ZYWRLE_ENCODE */
|
||||
/* #define ZYWRLE_DECODE */
|
||||
#define ZYWRLE_QUANTIZE
|
||||
|
||||
/*
|
||||
[References]
|
||||
PLHarr:
|
||||
Senecal, J. G., P. Lindstrom, M. A. Duchaineau, and K. I. Joy, "An Improved N-Bit to N-Bit Reversible Haar-Like Transform," Pacific Graphics 2004, October 2004, pp. 371-380.
|
||||
EZW:
|
||||
Shapiro, JM: Embedded Image Coding Using Zerotrees of Wavelet Coefficients, IEEE Trans. Signal. Process., Vol.41, pp.3445-3462 (1993).
|
||||
*/
|
||||
|
||||
|
||||
/* Template Macro stuffs. */
|
||||
#undef ZYWRLE_ANALYZE
|
||||
#undef ZYWRLE_SYNTHESIZE
|
||||
#define ZYWRLE_ANALYZE __RFB_CONCAT3E(zywrleAnalyze,BPP,END_FIX)
|
||||
#define ZYWRLE_SYNTHESIZE __RFB_CONCAT3E(zywrleSynthesize,BPP,END_FIX)
|
||||
|
||||
#define ZYWRLE_RGBYUV __RFB_CONCAT3E(zywrleRGBYUV,BPP,END_FIX)
|
||||
#define ZYWRLE_YUVRGB __RFB_CONCAT3E(zywrleYUVRGB,BPP,END_FIX)
|
||||
#define ZYWRLE_YMASK __RFB_CONCAT2E(ZYWRLE_YMASK,BPP)
|
||||
#define ZYWRLE_UVMASK __RFB_CONCAT2E(ZYWRLE_UVMASK,BPP)
|
||||
#define ZYWRLE_LOAD_PIXEL __RFB_CONCAT2E(ZYWRLE_LOAD_PIXEL,BPP)
|
||||
#define ZYWRLE_SAVE_PIXEL __RFB_CONCAT2E(ZYWRLE_SAVE_PIXEL,BPP)
|
||||
|
||||
/* Packing/Unpacking pixel stuffs.
|
||||
Endian conversion stuffs. */
|
||||
#undef S_0
|
||||
#undef S_1
|
||||
#undef L_0
|
||||
#undef L_1
|
||||
#undef L_2
|
||||
#if ZYWRLE_ENDIAN == ENDIAN_BIG
|
||||
# define S_0 1
|
||||
# define S_1 0
|
||||
# define L_0 3
|
||||
# define L_1 2
|
||||
# define L_2 1
|
||||
#else
|
||||
# define S_0 0
|
||||
# define S_1 1
|
||||
# define L_0 0
|
||||
# define L_1 1
|
||||
# define L_2 2
|
||||
#endif
|
||||
|
||||
/* Load/Save pixel stuffs. */
|
||||
#define ZYWRLE_YMASK15 0xFFFFFFF8
|
||||
#define ZYWRLE_UVMASK15 0xFFFFFFF8
|
||||
#define ZYWRLE_LOAD_PIXEL15(pSrc,R,G,B) { \
|
||||
R = (((unsigned char*)pSrc)[S_1]<< 1)& 0xF8; \
|
||||
G = ((((unsigned char*)pSrc)[S_1]<< 6)|(((unsigned char*)pSrc)[S_0]>> 2))& 0xF8; \
|
||||
B = (((unsigned char*)pSrc)[S_0]<< 3)& 0xF8; \
|
||||
}
|
||||
#define ZYWRLE_SAVE_PIXEL15(pDst,R,G,B) { \
|
||||
R &= 0xF8; \
|
||||
G &= 0xF8; \
|
||||
B &= 0xF8; \
|
||||
((unsigned char*)pDst)[S_1] = (unsigned char)( (R>>1)|(G>>6) ); \
|
||||
((unsigned char*)pDst)[S_0] = (unsigned char)(((B>>3)|(G<<2))& 0xFF); \
|
||||
}
|
||||
#define ZYWRLE_YMASK16 0xFFFFFFFC
|
||||
#define ZYWRLE_UVMASK16 0xFFFFFFF8
|
||||
#define ZYWRLE_LOAD_PIXEL16(pSrc,R,G,B) { \
|
||||
R = ((unsigned char*)pSrc)[S_1] & 0xF8; \
|
||||
G = ((((unsigned char*)pSrc)[S_1]<< 5)|(((unsigned char*)pSrc)[S_0]>> 3))& 0xFC; \
|
||||
B = (((unsigned char*)pSrc)[S_0]<< 3)& 0xF8; \
|
||||
}
|
||||
#define ZYWRLE_SAVE_PIXEL16(pDst,R,G,B) { \
|
||||
R &= 0xF8; \
|
||||
G &= 0xFC; \
|
||||
B &= 0xF8; \
|
||||
((unsigned char*)pDst)[S_1] = (unsigned char)( R |(G>>5) ); \
|
||||
((unsigned char*)pDst)[S_0] = (unsigned char)(((B>>3)|(G<<3))& 0xFF); \
|
||||
}
|
||||
#define ZYWRLE_YMASK32 0xFFFFFFFF
|
||||
#define ZYWRLE_UVMASK32 0xFFFFFFFF
|
||||
#define ZYWRLE_LOAD_PIXEL32(pSrc,R,G,B) { \
|
||||
R = ((unsigned char*)pSrc)[L_2]; \
|
||||
G = ((unsigned char*)pSrc)[L_1]; \
|
||||
B = ((unsigned char*)pSrc)[L_0]; \
|
||||
}
|
||||
#define ZYWRLE_SAVE_PIXEL32(pDst,R,G,B) { \
|
||||
((unsigned char*)pDst)[L_2] = (unsigned char)R; \
|
||||
((unsigned char*)pDst)[L_1] = (unsigned char)G; \
|
||||
((unsigned char*)pDst)[L_0] = (unsigned char)B; \
|
||||
}
|
||||
|
||||
#ifndef ZYWRLE_ONCE
|
||||
#define ZYWRLE_ONCE
|
||||
|
||||
#ifdef WIN32
|
||||
#define InlineX __inline
|
||||
#else
|
||||
# ifndef __STRICT_ANSI__
|
||||
# define InlineX inline
|
||||
# else
|
||||
# define InlineX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef ZYWRLE_ENCODE
|
||||
/* Tables for Coefficients filtering. */
|
||||
# ifndef ZYWRLE_QUANTIZE
|
||||
/* Type A:lower bit omitting of EZW style. */
|
||||
const static unsigned int zywrleParam[3][3]={
|
||||
{0x0000F000,0x00000000,0x00000000},
|
||||
{0x0000C000,0x00F0F0F0,0x00000000},
|
||||
{0x0000C000,0x00C0C0C0,0x00F0F0F0},
|
||||
/* {0x0000FF00,0x00000000,0x00000000},
|
||||
{0x0000FF00,0x00FFFFFF,0x00000000},
|
||||
{0x0000FF00,0x00FFFFFF,0x00FFFFFF}, */
|
||||
};
|
||||
# else
|
||||
/* Type B:Non liner quantization filter. */
|
||||
static const signed char zywrleConv[4][256]={
|
||||
{ /* bi=5, bo=5 r=0.0:PSNR=24.849 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
{ /* bi=5, bo=5 r=2.0:PSNR=74.031 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32,
|
||||
48, 48, 48, 48, 48, 48, 48, 48,
|
||||
48, 48, 48, 56, 56, 56, 56, 56,
|
||||
56, 56, 56, 56, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 72, 72, 72, 72,
|
||||
72, 72, 72, 72, 80, 80, 80, 80,
|
||||
80, 80, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 96, 96,
|
||||
96, 96, 96, 104, 104, 104, 104, 104,
|
||||
104, 104, 104, 104, 104, 112, 112, 112,
|
||||
112, 112, 112, 112, 112, 112, 120, 120,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
0, -120, -120, -120, -120, -120, -120, -120,
|
||||
-120, -120, -120, -112, -112, -112, -112, -112,
|
||||
-112, -112, -112, -112, -104, -104, -104, -104,
|
||||
-104, -104, -104, -104, -104, -104, -96, -96,
|
||||
-96, -96, -96, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -80,
|
||||
-80, -80, -80, -80, -80, -72, -72, -72,
|
||||
-72, -72, -72, -72, -72, -64, -64, -64,
|
||||
-64, -64, -64, -64, -64, -56, -56, -56,
|
||||
-56, -56, -56, -56, -56, -56, -48, -48,
|
||||
-48, -48, -48, -48, -48, -48, -48, -48,
|
||||
-48, -32, -32, -32, -32, -32, -32, -32,
|
||||
-32, -32, -32, -32, -32, -32, -32, -32,
|
||||
-32, -32, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
{ /* bi=5, bo=4 r=2.0:PSNR=64.441 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
48, 48, 48, 48, 48, 48, 48, 48,
|
||||
48, 48, 48, 48, 48, 48, 48, 48,
|
||||
48, 48, 48, 48, 48, 48, 48, 48,
|
||||
64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64,
|
||||
80, 80, 80, 80, 80, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
104, 104, 104, 104, 104, 104, 104, 104,
|
||||
104, 104, 104, 112, 112, 112, 112, 112,
|
||||
112, 112, 112, 112, 120, 120, 120, 120,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
0, -120, -120, -120, -120, -120, -120, -120,
|
||||
-120, -120, -120, -120, -120, -112, -112, -112,
|
||||
-112, -112, -112, -112, -112, -112, -104, -104,
|
||||
-104, -104, -104, -104, -104, -104, -104, -104,
|
||||
-104, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -80, -80, -80, -80,
|
||||
-80, -80, -80, -80, -80, -80, -80, -80,
|
||||
-80, -64, -64, -64, -64, -64, -64, -64,
|
||||
-64, -64, -64, -64, -64, -64, -64, -64,
|
||||
-64, -48, -48, -48, -48, -48, -48, -48,
|
||||
-48, -48, -48, -48, -48, -48, -48, -48,
|
||||
-48, -48, -48, -48, -48, -48, -48, -48,
|
||||
-48, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
{ /* bi=5, bo=2 r=2.0:PSNR=43.175 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
0, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
}
|
||||
};
|
||||
const static signed char* zywrleParam[3][3][3]={
|
||||
{{zywrleConv[0],zywrleConv[2],zywrleConv[0]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]}},
|
||||
{{zywrleConv[0],zywrleConv[3],zywrleConv[0]},{zywrleConv[1],zywrleConv[1],zywrleConv[1]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]}},
|
||||
{{zywrleConv[0],zywrleConv[3],zywrleConv[0]},{zywrleConv[2],zywrleConv[2],zywrleConv[2]},{zywrleConv[1],zywrleConv[1],zywrleConv[1]}},
|
||||
};
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static InlineX void Harr(signed char* pX0, signed char* pX1)
|
||||
{
|
||||
/* Piecewise-Linear Harr(PLHarr) */
|
||||
int X0 = (int)*pX0, X1 = (int)*pX1;
|
||||
int orgX0 = X0, orgX1 = X1;
|
||||
if ((X0 ^ X1) & 0x80) {
|
||||
/* differ sign */
|
||||
X1 += X0;
|
||||
if (((X1^orgX1)&0x80)==0) {
|
||||
/* |X1| > |X0| */
|
||||
X0 -= X1; /* H = -B */
|
||||
}
|
||||
} else {
|
||||
/* same sign */
|
||||
X0 -= X1;
|
||||
if (((X0 ^ orgX0) & 0x80) == 0) {
|
||||
/* |X0| > |X1| */
|
||||
X1 += X0; /* L = A */
|
||||
}
|
||||
}
|
||||
*pX0 = (signed char)X1;
|
||||
*pX1 = (signed char)X0;
|
||||
}
|
||||
/*
|
||||
1D-Wavelet transform.
|
||||
|
||||
In coefficients array, the famous 'pyramid' decomposition is well used.
|
||||
|
||||
1D Model:
|
||||
|L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0
|
||||
|L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1
|
||||
|
||||
But this method needs line buffer because H/L is different position from X0/X1.
|
||||
So, I used 'interleave' decomposition instead of it.
|
||||
|
||||
1D Model:
|
||||
|L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0
|
||||
|L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1
|
||||
|
||||
In this method, H/L and X0/X1 is always same position.
|
||||
This lead us to more speed and less memory.
|
||||
Of cause, the result of both method is quite same
|
||||
because its only difference is that coefficient position.
|
||||
*/
|
||||
static InlineX void WaveletLevel(int* data, int size, int l, int SkipPixel)
|
||||
{
|
||||
int s, ofs;
|
||||
signed char* pX0;
|
||||
signed char* end;
|
||||
|
||||
pX0 = (signed char*)data;
|
||||
s = (8<<l)*SkipPixel;
|
||||
end = pX0+(size>>(l+1))*s;
|
||||
s -= 2;
|
||||
ofs = (4<<l)*SkipPixel;
|
||||
while (pX0 < end) {
|
||||
Harr(pX0, pX0+ofs);
|
||||
pX0++;
|
||||
Harr(pX0, pX0+ofs);
|
||||
pX0++;
|
||||
Harr(pX0, pX0+ofs);
|
||||
pX0 += s;
|
||||
}
|
||||
}
|
||||
#define InvWaveletLevel(d,s,l,pix) WaveletLevel(d,s,l,pix)
|
||||
|
||||
#ifdef ZYWRLE_ENCODE
|
||||
# ifndef ZYWRLE_QUANTIZE
|
||||
/* Type A:lower bit omitting of EZW style. */
|
||||
static InlineX void FilterWaveletSquare(int* pBuf, int width, int height, int level, int l)
|
||||
{
|
||||
int r, s;
|
||||
int x, y;
|
||||
int* pH;
|
||||
const unsigned int* pM;
|
||||
|
||||
pM = &(zywrleParam[level-1][l]);
|
||||
s = 2<<l;
|
||||
for (r = 1; r < 4; r++) {
|
||||
pH = pBuf;
|
||||
if (r & 0x01)
|
||||
pH += s>>1;
|
||||
if (r & 0x02)
|
||||
pH += (s>>1)*width;
|
||||
for (y = 0; y < height / s; y++) {
|
||||
for (x = 0; x < width / s; x++) {
|
||||
/*
|
||||
these are same following code.
|
||||
pH[x] = pH[x] / (~pM[x]+1) * (~pM[x]+1);
|
||||
( round pH[x] with pM[x] bit )
|
||||
'&' operator isn't 'round' but is 'floor'.
|
||||
So, we must offset when pH[x] is negative.
|
||||
*/
|
||||
if (((signed char*)pH)[0] & 0x80)
|
||||
((signed char*)pH)[0] += ~((signed char*)pM)[0];
|
||||
if (((signed char*)pH)[1] & 0x80)
|
||||
((signed char*)pH)[1] += ~((signed char*)pM)[1];
|
||||
if (((signed char*)pH)[2] & 0x80)
|
||||
((signed char*)pH)[2] += ~((signed char*)pM)[2];
|
||||
*pH &= *pM;
|
||||
pH += s;
|
||||
}
|
||||
pH += (s-1)*width;
|
||||
}
|
||||
}
|
||||
}
|
||||
# else
|
||||
/*
|
||||
Type B:Non liner quantization filter.
|
||||
|
||||
Coefficients have Gaussian curve and smaller value which is
|
||||
large part of coefficients isn't more important than larger value.
|
||||
So, I use filter of Non liner quantize/dequantize table.
|
||||
In general, Non liner quantize formula is explained as following.
|
||||
|
||||
y=f(x) = sign(x)*round( ((abs(x)/(2^7))^ r )* 2^(bo-1) )*2^(8-bo)
|
||||
x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi)
|
||||
( r:power coefficient bi:effective MSB in input bo:effective MSB in output )
|
||||
|
||||
r < 1.0 : Smaller value is more important than larger value.
|
||||
r > 1.0 : Larger value is more important than smaller value.
|
||||
r = 1.0 : Liner quantization which is same with EZW style.
|
||||
|
||||
r = 0.75 is famous non liner quantization used in MP3 audio codec.
|
||||
In contrast to audio data, larger value is important in wavelet coefficients.
|
||||
So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ).
|
||||
|
||||
As compared with EZW style liner quantization, this filter tended to be
|
||||
more sharp edge and be more compression rate but be more blocking noise and be less quality.
|
||||
Especially, the surface of graphic objects has distinguishable noise in middle quality mode.
|
||||
|
||||
We need only quantized-dequantized(filtered) value rather than quantized value itself
|
||||
because all values are packed or palette-lized in later ZRLE section.
|
||||
This lead us not to need to modify client decoder when we change
|
||||
the filtering procedure in future.
|
||||
Client only decodes coefficients given by encoder.
|
||||
*/
|
||||
static InlineX void FilterWaveletSquare(int* pBuf, int width, int height, int level, int l)
|
||||
{
|
||||
int r, s;
|
||||
int x, y;
|
||||
int* pH;
|
||||
const signed char** pM;
|
||||
|
||||
pM = zywrleParam[level-1][l];
|
||||
s = 2<<l;
|
||||
for (r = 1; r < 4; r++) {
|
||||
pH = pBuf;
|
||||
if (r & 0x01)
|
||||
pH += s>>1;
|
||||
if (r & 0x02)
|
||||
pH += (s>>1)*width;
|
||||
for (y = 0; y < height / s; y++) {
|
||||
for (x = 0; x < width / s; x++) {
|
||||
((signed char*)pH)[0] = pM[0][((unsigned char*)pH)[0]];
|
||||
((signed char*)pH)[1] = pM[1][((unsigned char*)pH)[1]];
|
||||
((signed char*)pH)[2] = pM[2][((unsigned char*)pH)[2]];
|
||||
pH += s;
|
||||
}
|
||||
pH += (s-1)*width;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
static InlineX void Wavelet(int* pBuf, int width, int height, int level)
|
||||
{
|
||||
int l, s;
|
||||
int* pTop;
|
||||
int* pEnd;
|
||||
|
||||
for (l = 0; l < level; l++) {
|
||||
pTop = pBuf;
|
||||
pEnd = pBuf+height*width;
|
||||
s = width<<l;
|
||||
while (pTop < pEnd) {
|
||||
WaveletLevel(pTop, width, l, 1);
|
||||
pTop += s;
|
||||
}
|
||||
pTop = pBuf;
|
||||
pEnd = pBuf+width;
|
||||
s = 1<<l;
|
||||
while (pTop < pEnd) {
|
||||
WaveletLevel(pTop, height,l, width);
|
||||
pTop += s;
|
||||
}
|
||||
FilterWaveletSquare(pBuf, width, height, level, l);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef ZYWRLE_DECODE
|
||||
static InlineX void InvWavelet(int* pBuf, int width, int height, int level)
|
||||
{
|
||||
int l, s;
|
||||
int* pTop;
|
||||
int* pEnd;
|
||||
|
||||
for (l = level - 1; l >= 0; l--) {
|
||||
pTop = pBuf;
|
||||
pEnd = pBuf+width;
|
||||
s = 1<<l;
|
||||
while (pTop < pEnd) {
|
||||
InvWaveletLevel(pTop, height,l, width);
|
||||
pTop += s;
|
||||
}
|
||||
pTop = pBuf;
|
||||
pEnd = pBuf+height*width;
|
||||
s = width<<l;
|
||||
while (pTop < pEnd) {
|
||||
InvWaveletLevel(pTop, width, l, 1);
|
||||
pTop += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Load/Save coefficients stuffs.
|
||||
Coefficients manages as 24 bits little-endian pixel. */
|
||||
#define ZYWRLE_LOAD_COEFF(pSrc,R,G,B) { \
|
||||
R = ((signed char*)pSrc)[2]; \
|
||||
G = ((signed char*)pSrc)[1]; \
|
||||
B = ((signed char*)pSrc)[0]; \
|
||||
}
|
||||
#define ZYWRLE_SAVE_COEFF(pDst,R,G,B) { \
|
||||
((signed char*)pDst)[2] = (signed char)R; \
|
||||
((signed char*)pDst)[1] = (signed char)G; \
|
||||
((signed char*)pDst)[0] = (signed char)B; \
|
||||
}
|
||||
|
||||
/*
|
||||
RGB <=> YUV conversion stuffs.
|
||||
YUV coversion is explained as following formula in strict meaning:
|
||||
Y = 0.299R + 0.587G + 0.114B ( 0<=Y<=255)
|
||||
U = -0.169R - 0.331G + 0.500B (-128<=U<=127)
|
||||
V = 0.500R - 0.419G - 0.081B (-128<=V<=127)
|
||||
|
||||
I use simple conversion RCT(reversible color transform) which is described
|
||||
in JPEG-2000 specification.
|
||||
Y = (R + 2G + B)/4 ( 0<=Y<=255)
|
||||
U = B-G (-256<=U<=255)
|
||||
V = R-G (-256<=V<=255)
|
||||
*/
|
||||
#define ROUND(x) (((x)<0)?0:(((x)>255)?255:(x)))
|
||||
/* RCT is N-bit RGB to N-bit Y and N+1-bit UV.
|
||||
For make Same N-bit, UV is lossy.
|
||||
More exact PLHarr, we reduce to odd range(-127<=x<=127). */
|
||||
#define ZYWRLE_RGBYUV1(R,G,B,Y,U,V,ymask,uvmask) { \
|
||||
Y = (R+(G<<1)+B)>>2; \
|
||||
U = B-G; \
|
||||
V = R-G; \
|
||||
Y -= 128; \
|
||||
U >>= 1; \
|
||||
V >>= 1; \
|
||||
Y &= ymask; \
|
||||
U &= uvmask; \
|
||||
V &= uvmask; \
|
||||
if (Y == -128) \
|
||||
Y += (0xFFFFFFFF-ymask+1); \
|
||||
if (U == -128) \
|
||||
U += (0xFFFFFFFF-uvmask+1); \
|
||||
if (V == -128) \
|
||||
V += (0xFFFFFFFF-uvmask+1); \
|
||||
}
|
||||
#define ZYWRLE_YUVRGB1(R,G,B,Y,U,V) { \
|
||||
Y += 128; \
|
||||
U <<= 1; \
|
||||
V <<= 1; \
|
||||
G = Y-((U+V)>>2); \
|
||||
B = U+G; \
|
||||
R = V+G; \
|
||||
G = ROUND(G); \
|
||||
B = ROUND(B); \
|
||||
R = ROUND(R); \
|
||||
}
|
||||
|
||||
/*
|
||||
coefficient packing/unpacking stuffs.
|
||||
Wavelet transform makes 4 sub coefficient image from 1 original image.
|
||||
|
||||
model with pyramid decomposition:
|
||||
+------+------+
|
||||
| | |
|
||||
| L | Hx |
|
||||
| | |
|
||||
+------+------+
|
||||
| | |
|
||||
| H | Hxy |
|
||||
| | |
|
||||
+------+------+
|
||||
|
||||
So, we must transfer each sub images individually in strict meaning.
|
||||
But at least ZRLE meaning, following one decompositon image is same as
|
||||
avobe individual sub image. I use this format.
|
||||
(Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L)
|
||||
for simplified procedure for any wavelet level.)
|
||||
|
||||
+------+------+
|
||||
| L |
|
||||
+------+------+
|
||||
| Hx |
|
||||
+------+------+
|
||||
| Hy |
|
||||
+------+------+
|
||||
| Hxy |
|
||||
+------+------+
|
||||
*/
|
||||
#define INC_PTR(data) \
|
||||
data++; \
|
||||
if( data-pData >= (w+uw) ){ \
|
||||
data += scanline-(w+uw); \
|
||||
pData = data; \
|
||||
}
|
||||
|
||||
#define ZYWRLE_TRANSFER_COEFF(pBuf,data,r,w,h,scanline,level,TRANS) \
|
||||
pH = pBuf; \
|
||||
s = 2<<level; \
|
||||
if (r & 0x01) \
|
||||
pH += s>>1; \
|
||||
if (r & 0x02) \
|
||||
pH += (s>>1)*w; \
|
||||
pEnd = pH+h*w; \
|
||||
while (pH < pEnd) { \
|
||||
pLine = pH+w; \
|
||||
while (pH < pLine) { \
|
||||
TRANS \
|
||||
INC_PTR(data) \
|
||||
pH += s; \
|
||||
} \
|
||||
pH += (s-1)*w; \
|
||||
}
|
||||
|
||||
#define ZYWRLE_PACK_COEFF(pBuf,data,r,width,height,scanline,level) \
|
||||
ZYWRLE_TRANSFER_COEFF(pBuf,data,r,width,height,scanline,level,ZYWRLE_LOAD_COEFF(pH,R,G,B);ZYWRLE_SAVE_PIXEL(data,R,G,B);)
|
||||
|
||||
#define ZYWRLE_UNPACK_COEFF(pBuf,data,r,width,height,scanline,level) \
|
||||
ZYWRLE_TRANSFER_COEFF(pBuf,data,r,width,height,scanline,level,ZYWRLE_LOAD_PIXEL(data,R,G,B);ZYWRLE_SAVE_COEFF(pH,R,G,B);)
|
||||
|
||||
#define ZYWRLE_SAVE_UNALIGN(data,TRANS) \
|
||||
pTop = pBuf+w*h; \
|
||||
pEnd = pBuf + (w+uw)*(h+uh); \
|
||||
while (pTop < pEnd) { \
|
||||
TRANS \
|
||||
INC_PTR(data) \
|
||||
pTop++; \
|
||||
}
|
||||
|
||||
#define ZYWRLE_LOAD_UNALIGN(data,TRANS) \
|
||||
pTop = pBuf+w*h; \
|
||||
if (uw) { \
|
||||
pData= data + w; \
|
||||
pEnd = (int*)(pData+ h*scanline); \
|
||||
while (pData < (PIXEL_T*)pEnd) { \
|
||||
pLine = (int*)(pData + uw); \
|
||||
while (pData < (PIXEL_T*)pLine) { \
|
||||
TRANS \
|
||||
pData++; \
|
||||
pTop++; \
|
||||
} \
|
||||
pData += scanline-uw; \
|
||||
} \
|
||||
} \
|
||||
if (uh) { \
|
||||
pData= data + h*scanline; \
|
||||
pEnd = (int*)(pData+ uh*scanline); \
|
||||
while (pData < (PIXEL_T*)pEnd) { \
|
||||
pLine = (int*)(pData + w); \
|
||||
while (pData < (PIXEL_T*)pLine) { \
|
||||
TRANS \
|
||||
pData++; \
|
||||
pTop++; \
|
||||
} \
|
||||
pData += scanline-w; \
|
||||
} \
|
||||
} \
|
||||
if (uw && uh) { \
|
||||
pData= data + w+ h*scanline; \
|
||||
pEnd = (int*)(pData+ uh*scanline); \
|
||||
while (pData < (PIXEL_T*)pEnd) { \
|
||||
pLine = (int*)(pData + uw); \
|
||||
while (pData < (PIXEL_T*)pLine) { \
|
||||
TRANS \
|
||||
pData++; \
|
||||
pTop++; \
|
||||
} \
|
||||
pData += scanline-uw; \
|
||||
} \
|
||||
}
|
||||
|
||||
static InlineX void zywrleCalcSize(int* pW, int* pH, int level)
|
||||
{
|
||||
*pW &= ~((1<<level)-1);
|
||||
*pH &= ~((1<<level)-1);
|
||||
}
|
||||
|
||||
#endif /* ZYWRLE_ONCE */
|
||||
|
||||
#ifndef CPIXEL
|
||||
#ifdef ZYWRLE_ENCODE
|
||||
static InlineX void ZYWRLE_RGBYUV(int* pBuf, PIXEL_T* data, int width, int height, int scanline)
|
||||
{
|
||||
int R, G, B;
|
||||
int Y, U, V;
|
||||
int* pLine;
|
||||
int* pEnd;
|
||||
pEnd = pBuf+height*width;
|
||||
while (pBuf < pEnd) {
|
||||
pLine = pBuf+width;
|
||||
while (pBuf < pLine) {
|
||||
ZYWRLE_LOAD_PIXEL(data,R,G,B);
|
||||
ZYWRLE_RGBYUV1(R,G,B,Y,U,V,ZYWRLE_YMASK,ZYWRLE_UVMASK);
|
||||
ZYWRLE_SAVE_COEFF(pBuf,V,Y,U);
|
||||
pBuf++;
|
||||
data++;
|
||||
}
|
||||
data += scanline-width;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef ZYWRLE_DECODE
|
||||
static InlineX void ZYWRLE_YUVRGB(int* pBuf, PIXEL_T* data, int width, int height, int scanline) {
|
||||
int R, G, B;
|
||||
int Y, U, V;
|
||||
int* pLine;
|
||||
int* pEnd;
|
||||
pEnd = pBuf+height*width;
|
||||
while (pBuf < pEnd) {
|
||||
pLine = pBuf+width;
|
||||
while (pBuf < pLine) {
|
||||
ZYWRLE_LOAD_COEFF(pBuf,V,Y,U);
|
||||
ZYWRLE_YUVRGB1(R,G,B,Y,U,V);
|
||||
ZYWRLE_SAVE_PIXEL(data,R,G,B);
|
||||
pBuf++;
|
||||
data++;
|
||||
}
|
||||
data += scanline-width;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ZYWRLE_ENCODE
|
||||
PIXEL_T* ZYWRLE_ANALYZE(PIXEL_T* dst, PIXEL_T* src, int w, int h, int scanline, int level, int* pBuf) {
|
||||
int l;
|
||||
int uw = w;
|
||||
int uh = h;
|
||||
int* pTop;
|
||||
int* pEnd;
|
||||
int* pLine;
|
||||
PIXEL_T* pData;
|
||||
int R, G, B;
|
||||
int s;
|
||||
int* pH;
|
||||
|
||||
zywrleCalcSize(&w, &h, level);
|
||||
if (w == 0 || h == 0)
|
||||
return NULL;
|
||||
uw -= w;
|
||||
uh -= h;
|
||||
|
||||
pData = dst;
|
||||
ZYWRLE_LOAD_UNALIGN(src,*(PIXEL_T*)pTop=*pData;)
|
||||
ZYWRLE_RGBYUV(pBuf, src, w, h, scanline);
|
||||
Wavelet(pBuf, w, h, level);
|
||||
for (l = 0; l < level; l++) {
|
||||
ZYWRLE_PACK_COEFF(pBuf, dst, 3, w, h, scanline, l);
|
||||
ZYWRLE_PACK_COEFF(pBuf, dst, 2, w, h, scanline, l);
|
||||
ZYWRLE_PACK_COEFF(pBuf, dst, 1, w, h, scanline, l);
|
||||
if (l == level - 1) {
|
||||
ZYWRLE_PACK_COEFF(pBuf, dst, 0, w, h, scanline, l);
|
||||
}
|
||||
}
|
||||
ZYWRLE_SAVE_UNALIGN(dst,*dst=*(PIXEL_T*)pTop;)
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
#ifdef ZYWRLE_DECODE
|
||||
PIXEL_T* ZYWRLE_SYNTHESIZE(PIXEL_T* dst, PIXEL_T* src, int w, int h, int scanline, int level, int* pBuf)
|
||||
{
|
||||
int l;
|
||||
int uw = w;
|
||||
int uh = h;
|
||||
int* pTop;
|
||||
int* pEnd;
|
||||
int* pLine;
|
||||
PIXEL_T* pData;
|
||||
int R, G, B;
|
||||
int s;
|
||||
int* pH;
|
||||
|
||||
zywrleCalcSize(&w, &h, level);
|
||||
if (w == 0 || h == 0)
|
||||
return NULL;
|
||||
uw -= w;
|
||||
uh -= h;
|
||||
|
||||
pData = src;
|
||||
for (l = 0; l < level; l++) {
|
||||
ZYWRLE_UNPACK_COEFF(pBuf, src, 3, w, h, scanline, l);
|
||||
ZYWRLE_UNPACK_COEFF(pBuf, src, 2, w, h, scanline, l);
|
||||
ZYWRLE_UNPACK_COEFF(pBuf, src, 1, w, h, scanline, l);
|
||||
if (l == level - 1) {
|
||||
ZYWRLE_UNPACK_COEFF(pBuf, src, 0, w, h, scanline, l);
|
||||
}
|
||||
}
|
||||
ZYWRLE_SAVE_UNALIGN(src,*(PIXEL_T*)pTop=*src;)
|
||||
InvWavelet(pBuf, w, h, level);
|
||||
ZYWRLE_YUVRGB(pBuf, dst, w, h, scanline);
|
||||
ZYWRLE_LOAD_UNALIGN(dst,*pData=*(PIXEL_T*)pTop;)
|
||||
return src;
|
||||
}
|
||||
#endif
|
||||
#endif /* CPIXEL */
|
||||
|
||||
#undef ZYWRLE_RGBYUV
|
||||
#undef ZYWRLE_YUVRGB
|
||||
#undef ZYWRLE_LOAD_PIXEL
|
||||
#undef ZYWRLE_SAVE_PIXEL
|
||||
70
android/extern/libvncserver/src/libvncclient/corre.c
vendored
Normal file
70
android/extern/libvncserver/src/libvncclient/corre.c
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* corre.c - handle CoRRE encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles a CoRRE
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP)
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
|
||||
static rfbBool
|
||||
HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbRREHeader hdr;
|
||||
int i;
|
||||
CARDBPP pix;
|
||||
uint8_t *ptr;
|
||||
int x, y, w, h;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader))
|
||||
return FALSE;
|
||||
|
||||
hdr.nSubrects = rfbClientSwap32IfLE(hdr.nSubrects);
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||
return FALSE;
|
||||
|
||||
client->GotFillRect(client, rx, ry, rw, rh, pix);
|
||||
|
||||
if (hdr.nSubrects > RFB_BUFFER_SIZE / (4 + (BPP / 8)) || !ReadFromRFBServer(client, client->buffer, hdr.nSubrects * (4 + (BPP / 8))))
|
||||
return FALSE;
|
||||
|
||||
ptr = (uint8_t *)client->buffer;
|
||||
|
||||
for (i = 0; i < hdr.nSubrects; i++) {
|
||||
pix = *(CARDBPP *)ptr;
|
||||
ptr += BPP/8;
|
||||
x = *ptr++;
|
||||
y = *ptr++;
|
||||
w = *ptr++;
|
||||
h = *ptr++;
|
||||
|
||||
client->GotFillRect(client, rx+x, ry+y, w, h, pix);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
||||
181
android/extern/libvncserver/src/libvncclient/cursor.c
vendored
Normal file
181
android/extern/libvncserver/src/libvncclient/cursor.c
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* cursor.c - code to support cursor shape updates (XCursor and
|
||||
* RichCursor preudo-encodings).
|
||||
*/
|
||||
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
|
||||
#define OPER_SAVE 0
|
||||
#define OPER_RESTORE 1
|
||||
|
||||
#define MAX_CURSOR_SIZE 1024
|
||||
|
||||
#define RGB24_TO_PIXEL(bpp,r,g,b) \
|
||||
((((uint##bpp##_t)(r) & 0xFF) * client->format.redMax + 127) / 255 \
|
||||
<< client->format.redShift | \
|
||||
(((uint##bpp##_t)(g) & 0xFF) * client->format.greenMax + 127) / 255 \
|
||||
<< client->format.greenShift | \
|
||||
(((uint##bpp##_t)(b) & 0xFF) * client->format.blueMax + 127) / 255 \
|
||||
<< client->format.blueShift)
|
||||
|
||||
|
||||
rfbBool HandleCursorShape(rfbClient* client,int xhot, int yhot, int width, int height, uint32_t enc)
|
||||
{
|
||||
int bytesPerPixel;
|
||||
size_t bytesPerRow, bytesMaskData;
|
||||
rfbXCursorColors rgb;
|
||||
uint32_t colors[2];
|
||||
char *buf;
|
||||
uint8_t *ptr;
|
||||
int x, y, b;
|
||||
|
||||
bytesPerPixel = client->format.bitsPerPixel / 8;
|
||||
bytesPerRow = (width + 7) / 8;
|
||||
bytesMaskData = bytesPerRow * height;
|
||||
|
||||
if (width * height == 0)
|
||||
return TRUE;
|
||||
|
||||
if (width >= MAX_CURSOR_SIZE || height >= MAX_CURSOR_SIZE)
|
||||
return FALSE;
|
||||
|
||||
/* Allocate memory for pixel data and temporary mask data. */
|
||||
if(client->rcSource)
|
||||
free(client->rcSource);
|
||||
|
||||
client->rcSource = malloc((size_t)width * height * bytesPerPixel);
|
||||
if (client->rcSource == NULL)
|
||||
return FALSE;
|
||||
|
||||
buf = malloc(bytesMaskData);
|
||||
if (buf == NULL) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Read and decode cursor pixel data, depending on the encoding type. */
|
||||
|
||||
if (enc == rfbEncodingXCursor) {
|
||||
/* Read and convert background and foreground colors. */
|
||||
if (!ReadFromRFBServer(client, (char *)&rgb, sz_rfbXCursorColors)) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue);
|
||||
colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue);
|
||||
|
||||
/* Read 1bpp pixel data into a temporary buffer. */
|
||||
if (!ReadFromRFBServer(client, buf, bytesMaskData)) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Convert 1bpp data to byte-wide color indices. */
|
||||
ptr = client->rcSource;
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width / 8; x++) {
|
||||
for (b = 7; b >= 0; b--) {
|
||||
*ptr = buf[y * bytesPerRow + x] >> b & 1;
|
||||
ptr += bytesPerPixel;
|
||||
}
|
||||
}
|
||||
for (b = 7; b > 7 - width % 8; b--) {
|
||||
*ptr = buf[y * bytesPerRow + x] >> b & 1;
|
||||
ptr += bytesPerPixel;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert indices into the actual pixel values. */
|
||||
switch (bytesPerPixel) {
|
||||
case 1:
|
||||
for (x = 0; x < width * height; x++)
|
||||
client->rcSource[x] = (uint8_t)colors[client->rcSource[x]];
|
||||
break;
|
||||
case 2:
|
||||
for (x = 0; x < width * height; x++)
|
||||
((uint16_t *)client->rcSource)[x] = (uint16_t)colors[client->rcSource[x * 2]];
|
||||
break;
|
||||
case 4:
|
||||
for (x = 0; x < width * height; x++)
|
||||
((uint32_t *)client->rcSource)[x] = colors[client->rcSource[x * 4]];
|
||||
break;
|
||||
}
|
||||
|
||||
} else { /* enc == rfbEncodingRichCursor */
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)client->rcSource, width * height * bytesPerPixel)) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Read and decode mask data. */
|
||||
|
||||
if (!ReadFromRFBServer(client, buf, bytesMaskData)) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(client->rcMask)
|
||||
free(client->rcMask);
|
||||
|
||||
client->rcMask = malloc((size_t)width * height);
|
||||
if (client->rcMask == NULL) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ptr = client->rcMask;
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width / 8; x++) {
|
||||
for (b = 7; b >= 0; b--) {
|
||||
*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
|
||||
}
|
||||
}
|
||||
for (b = 7; b > 7 - width % 8; b--) {
|
||||
*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (client->GotCursorShape != NULL) {
|
||||
client->GotCursorShape(client, xhot, yhot, width, height, bytesPerPixel);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
127
android/extern/libvncserver/src/libvncclient/hextile.c
vendored
Normal file
127
android/extern/libvncserver/src/libvncclient/hextile.c
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* hextile.c - handle hextile encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles a hextile
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleHextileBPP CONCAT2E(HandleHextile,BPP)
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
|
||||
static rfbBool
|
||||
HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
CARDBPP bg = 0, fg;
|
||||
int i;
|
||||
uint8_t *ptr;
|
||||
int x, y, w, h;
|
||||
int sx, sy, sw, sh;
|
||||
uint8_t subencoding;
|
||||
uint8_t nSubrects;
|
||||
|
||||
for (y = ry; y < ry+rh; y += 16) {
|
||||
for (x = rx; x < rx+rw; x += 16) {
|
||||
w = h = 16;
|
||||
if (rx+rw - x < 16)
|
||||
w = rx+rw - x;
|
||||
if (ry+rh - y < 16)
|
||||
h = ry+rh - y;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&subencoding, 1))
|
||||
return FALSE;
|
||||
|
||||
if (subencoding & rfbHextileRaw) {
|
||||
if (!ReadFromRFBServer(client, client->buffer, w * h * (BPP / 8)))
|
||||
return FALSE;
|
||||
|
||||
client->GotBitmap(client, (uint8_t *)client->buffer, x, y, w, h);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subencoding & rfbHextileBackgroundSpecified)
|
||||
if (!ReadFromRFBServer(client, (char *)&bg, sizeof(bg)))
|
||||
return FALSE;
|
||||
|
||||
client->GotFillRect(client, x, y, w, h, bg);
|
||||
|
||||
if (subencoding & rfbHextileForegroundSpecified)
|
||||
if (!ReadFromRFBServer(client, (char *)&fg, sizeof(fg)))
|
||||
return FALSE;
|
||||
|
||||
if (!(subencoding & rfbHextileAnySubrects)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&nSubrects, 1))
|
||||
return FALSE;
|
||||
|
||||
ptr = (uint8_t*)client->buffer;
|
||||
|
||||
if (subencoding & rfbHextileSubrectsColoured) {
|
||||
if (!ReadFromRFBServer(client, client->buffer, nSubrects * (2 + (BPP / 8))))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < nSubrects; i++) {
|
||||
#if BPP==8
|
||||
GET_PIXEL8(fg, ptr);
|
||||
#elif BPP==16
|
||||
GET_PIXEL16(fg, ptr);
|
||||
#elif BPP==32
|
||||
GET_PIXEL32(fg, ptr);
|
||||
#else
|
||||
#error "Invalid BPP"
|
||||
#endif
|
||||
sx = rfbHextileExtractX(*ptr);
|
||||
sy = rfbHextileExtractY(*ptr);
|
||||
ptr++;
|
||||
sw = rfbHextileExtractW(*ptr);
|
||||
sh = rfbHextileExtractH(*ptr);
|
||||
ptr++;
|
||||
|
||||
client->GotFillRect(client, x+sx, y+sy, sw, sh, fg);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!ReadFromRFBServer(client, client->buffer, nSubrects * 2))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < nSubrects; i++) {
|
||||
sx = rfbHextileExtractX(*ptr);
|
||||
sy = rfbHextileExtractY(*ptr);
|
||||
ptr++;
|
||||
sw = rfbHextileExtractW(*ptr);
|
||||
sh = rfbHextileExtractH(*ptr);
|
||||
ptr++;
|
||||
|
||||
client->GotFillRect(client, x+sx, y+sy, sw, sh, fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
||||
14
android/extern/libvncserver/src/libvncclient/libvncclient.pc.cmakein
vendored
Normal file
14
android/extern/libvncserver/src/libvncclient/libvncclient.pc.cmakein
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_PREFIX@/include
|
||||
|
||||
Name: LibVNCClient
|
||||
Description: A library for easy implementation of a VNC client.
|
||||
Version: @LibVNCServer_VERSION@
|
||||
Requires:
|
||||
Requires.private:
|
||||
Libs: -L${libdir} -lvncclient
|
||||
Libs.private: @PRIVATE_LIBS@
|
||||
Cflags: -I${includedir}
|
||||
|
||||
229
android/extern/libvncserver/src/libvncclient/listen.c
vendored
Normal file
229
android/extern/libvncserver/src/libvncclient/listen.c
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org>
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* listen.c - listen for incoming connections
|
||||
*/
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
#if LIBVNCSERVER_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else // #ifdef WIN32
|
||||
#include <sys/wait.h>
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
#if LIBVNCSERVER_HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
/*
|
||||
* listenForIncomingConnections() - listen for incoming connections from
|
||||
* servers, and fork a new process to deal with each connection.
|
||||
*/
|
||||
|
||||
void
|
||||
listenForIncomingConnections(rfbClient* client)
|
||||
{
|
||||
#ifdef WIN32
|
||||
/* FIXME */
|
||||
rfbClientErr("listenForIncomingConnections on MinGW32 NOT IMPLEMENTED\n");
|
||||
return;
|
||||
#else
|
||||
int listenSocket = RFB_INVALID_SOCKET, listen6Socket = RFB_INVALID_SOCKET;
|
||||
fd_set fds;
|
||||
|
||||
client->listenSpecified = TRUE;
|
||||
|
||||
listenSocket = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress);
|
||||
|
||||
if (listenSocket == RFB_INVALID_SOCKET)
|
||||
return;
|
||||
|
||||
rfbClientLog("%s -listen: Listening on port %d\n",
|
||||
client->programName,client->listenPort);
|
||||
rfbClientLog("%s -listen: Command line errors are not reported until "
|
||||
"a connection comes in.\n", client->programName);
|
||||
|
||||
#ifdef LIBVNCSERVER_IPv6 /* only try that if we're IPv6-capable, otherwise we may try to bind to the same port which would make all that listening fail */
|
||||
/* only do IPv6 listen of listen6Port is set */
|
||||
if (client->listen6Port != RFB_INVALID_SOCKET)
|
||||
{
|
||||
listen6Socket = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address);
|
||||
|
||||
if (listen6Socket == RFB_INVALID_SOCKET)
|
||||
return;
|
||||
|
||||
rfbClientLog("%s -listen: Listening on IPV6 port %d\n",
|
||||
client->programName,client->listenPort);
|
||||
rfbClientLog("%s -listen: Command line errors are not reported until "
|
||||
"a connection comes in.\n", client->programName);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (TRUE) {
|
||||
int r;
|
||||
/* reap any zombies */
|
||||
int status, pid;
|
||||
while ((pid= wait4(-1, &status, WNOHANG, (struct rusage *)0))>0);
|
||||
|
||||
/* TODO: callback for discard any events (like X11 events) */
|
||||
|
||||
FD_ZERO(&fds);
|
||||
|
||||
if(listenSocket != RFB_INVALID_SOCKET)
|
||||
FD_SET(listenSocket, &fds);
|
||||
if(listen6Socket != RFB_INVALID_SOCKET)
|
||||
FD_SET(listen6Socket, &fds);
|
||||
|
||||
r = select(rfbMax(listenSocket, listen6Socket)+1, &fds, NULL, NULL, NULL);
|
||||
|
||||
if (r > 0) {
|
||||
if (FD_ISSET(listenSocket, &fds))
|
||||
client->sock = AcceptTcpConnection(client->listenSock);
|
||||
else if (FD_ISSET(listen6Socket, &fds))
|
||||
client->sock = AcceptTcpConnection(client->listen6Sock);
|
||||
|
||||
if (client->sock == RFB_INVALID_SOCKET)
|
||||
return;
|
||||
if (!SetNonBlocking(client->sock))
|
||||
return;
|
||||
|
||||
/* Now fork off a new process to deal with it... */
|
||||
|
||||
switch (fork()) {
|
||||
|
||||
case -1:
|
||||
rfbClientErr("fork\n");
|
||||
return;
|
||||
|
||||
case 0:
|
||||
/* child - return to caller */
|
||||
rfbCloseSocket(listenSocket);
|
||||
rfbCloseSocket(listen6Socket);
|
||||
return;
|
||||
|
||||
default:
|
||||
/* parent - go round and listen again */
|
||||
rfbCloseSocket(client->sock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* listenForIncomingConnectionsNoFork() - listen for incoming connections
|
||||
* from servers, but DON'T fork, instead just wait timeout microseconds.
|
||||
* If timeout is negative, block indefinitely.
|
||||
* Returns 1 on success (there was an incoming connection on the listen socket
|
||||
* and we accepted it successfully), -1 on error, 0 on timeout.
|
||||
*/
|
||||
|
||||
int
|
||||
listenForIncomingConnectionsNoFork(rfbClient* client, int timeout)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval to;
|
||||
int r;
|
||||
|
||||
to.tv_sec= timeout / 1000000;
|
||||
to.tv_usec= timeout % 1000000;
|
||||
|
||||
client->listenSpecified = TRUE;
|
||||
|
||||
if (client->listenSock == RFB_INVALID_SOCKET)
|
||||
{
|
||||
client->listenSock = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress);
|
||||
|
||||
if (client->listenSock == RFB_INVALID_SOCKET)
|
||||
return -1;
|
||||
|
||||
rfbClientLog("%s -listennofork: Listening on port %d\n",
|
||||
client->programName,client->listenPort);
|
||||
rfbClientLog("%s -listennofork: Command line errors are not reported until "
|
||||
"a connection comes in.\n", client->programName);
|
||||
}
|
||||
|
||||
#ifdef LIBVNCSERVER_IPv6 /* only try that if we're IPv6-capable, otherwise we may try to bind to the same port which would make all that listening fail */
|
||||
/* only do IPv6 listen of listen6Port is set */
|
||||
if (client->listen6Port != RFB_INVALID_SOCKET && client->listen6Sock == RFB_INVALID_SOCKET)
|
||||
{
|
||||
client->listen6Sock = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address);
|
||||
|
||||
if (client->listen6Sock == RFB_INVALID_SOCKET)
|
||||
return -1;
|
||||
|
||||
rfbClientLog("%s -listennofork: Listening on IPV6 port %d\n",
|
||||
client->programName,client->listenPort);
|
||||
rfbClientLog("%s -listennofork: Command line errors are not reported until "
|
||||
"a connection comes in.\n", client->programName);
|
||||
}
|
||||
#endif
|
||||
|
||||
FD_ZERO(&fds);
|
||||
|
||||
if(client->listenSock != RFB_INVALID_SOCKET)
|
||||
FD_SET(client->listenSock, &fds);
|
||||
if(client->listen6Sock != RFB_INVALID_SOCKET)
|
||||
FD_SET(client->listen6Sock, &fds);
|
||||
|
||||
if (timeout < 0)
|
||||
r = select(rfbMax(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, NULL);
|
||||
else
|
||||
r = select(rfbMax(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, &to);
|
||||
|
||||
if (r > 0)
|
||||
{
|
||||
if (FD_ISSET(client->listenSock, &fds))
|
||||
client->sock = AcceptTcpConnection(client->listenSock);
|
||||
else if (FD_ISSET(client->listen6Sock, &fds))
|
||||
client->sock = AcceptTcpConnection(client->listen6Sock);
|
||||
|
||||
if (client->sock == RFB_INVALID_SOCKET)
|
||||
return -1;
|
||||
if (!SetNonBlocking(client->sock))
|
||||
return -1;
|
||||
|
||||
if(client->listenSock != RFB_INVALID_SOCKET) {
|
||||
rfbCloseSocket(client->listenSock);
|
||||
client->listenSock = RFB_INVALID_SOCKET;
|
||||
}
|
||||
if(client->listen6Sock != RFB_INVALID_SOCKET) {
|
||||
rfbCloseSocket(client->listen6Sock);
|
||||
client->listen6Sock = RFB_INVALID_SOCKET;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* r is now either 0 (timeout) or -1 (error) */
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
2855
android/extern/libvncserver/src/libvncclient/rfbclient.c
vendored
Normal file
2855
android/extern/libvncserver/src/libvncclient/rfbclient.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
68
android/extern/libvncserver/src/libvncclient/rre.c
vendored
Normal file
68
android/extern/libvncserver/src/libvncclient/rre.c
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* rre.c - handle RRE encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles an RRE
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleRREBPP CONCAT2E(HandleRRE,BPP)
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
|
||||
static rfbBool
|
||||
HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbRREHeader hdr;
|
||||
int i;
|
||||
CARDBPP pix;
|
||||
rfbRectangle subrect;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader))
|
||||
return FALSE;
|
||||
|
||||
hdr.nSubrects = rfbClientSwap32IfLE(hdr.nSubrects);
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||
return FALSE;
|
||||
|
||||
client->GotFillRect(client, rx, ry, rw, rh, pix);
|
||||
|
||||
for (i = 0; i < hdr.nSubrects; i++) {
|
||||
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||
return FALSE;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&subrect, sz_rfbRectangle))
|
||||
return FALSE;
|
||||
|
||||
subrect.x = rfbClientSwap16IfLE(subrect.x);
|
||||
subrect.y = rfbClientSwap16IfLE(subrect.y);
|
||||
subrect.w = rfbClientSwap16IfLE(subrect.w);
|
||||
subrect.h = rfbClientSwap16IfLE(subrect.h);
|
||||
|
||||
client->GotFillRect(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
||||
570
android/extern/libvncserver/src/libvncclient/sasl.c
vendored
Normal file
570
android/extern/libvncserver/src/libvncclient/sasl.c
vendored
Normal file
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
* The software in this file is derived from the vncconnection.c source file
|
||||
* from the GTK VNC Widget with modifications by S. Waterman <simon.waterman@zynstra.com>
|
||||
* for compatibility with libvncserver. The copyright and license
|
||||
* statements below apply only to this source file and to no other parts of the
|
||||
* libvncserver library.
|
||||
*
|
||||
* GTK VNC Widget
|
||||
*
|
||||
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
|
||||
* Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* sasl.c - functions to deal with client side of the SASL protocol.
|
||||
*/
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#define _POSIX_SOURCE
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
#include "sockets.h"
|
||||
|
||||
#include "sasl.h"
|
||||
|
||||
#include "tls.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define snprintf _snprintf /* MSVC went straight to the underscored syntax */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NB, keep in sync with similar method in qemud/remote.c
|
||||
*/
|
||||
static char *vnc_connection_addr_to_string(char *host, int port)
|
||||
{
|
||||
char * buf = (char *)malloc(strlen(host) + 7);
|
||||
if (buf) {
|
||||
sprintf(buf, "%s;%hu", host, (unsigned short)port);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int log_func(void *context,
|
||||
int level,
|
||||
const char *message)
|
||||
{
|
||||
rfbClientLog("SASL: %s\n", message);
|
||||
|
||||
return SASL_OK;
|
||||
}
|
||||
|
||||
static int user_callback_adapt(void *context,
|
||||
int id,
|
||||
const char **result,
|
||||
unsigned *len)
|
||||
{
|
||||
rfbClient* client = (rfbClient *)context;
|
||||
|
||||
if (id != SASL_CB_AUTHNAME) {
|
||||
rfbClientLog("Unrecognized SASL callback ID %d\n", id);
|
||||
return SASL_FAIL;
|
||||
}
|
||||
|
||||
if (!client->GetUser) {
|
||||
rfbClientLog("Client user callback not found\n");
|
||||
return SASL_FAIL;
|
||||
}
|
||||
|
||||
*result = client->GetUser(client);
|
||||
|
||||
if (! *result) return SASL_FAIL;
|
||||
/**len = strlen(*result);*/
|
||||
return SASL_OK;
|
||||
}
|
||||
|
||||
static int password_callback_adapt(sasl_conn_t *conn,
|
||||
void * context,
|
||||
int id,
|
||||
sasl_secret_t **secret)
|
||||
{
|
||||
rfbClient* client = (rfbClient *)context;
|
||||
char * password;
|
||||
|
||||
if (id != SASL_CB_PASS) {
|
||||
rfbClientLog("Unrecognized SASL callback ID %d\n", id);
|
||||
return SASL_FAIL;
|
||||
}
|
||||
|
||||
if (client->saslSecret) { /* If we've already got it just return it. */
|
||||
*secret = client->saslSecret;
|
||||
return SASL_OK;
|
||||
}
|
||||
|
||||
if (!client->GetPassword) {
|
||||
rfbClientLog("Client password callback not found\n");
|
||||
return SASL_FAIL;
|
||||
}
|
||||
|
||||
password = client->GetPassword(client);
|
||||
|
||||
if (! password) return SASL_FAIL;
|
||||
|
||||
sasl_secret_t *lsec = (sasl_secret_t *)malloc(sizeof(sasl_secret_t) + strlen(password));
|
||||
if (!lsec) {
|
||||
rfbClientLog("Could not allocate sasl_secret_t\n");
|
||||
return SASL_FAIL;
|
||||
}
|
||||
|
||||
strcpy((char *)lsec->data, password);
|
||||
lsec->len = strlen(password);
|
||||
if (client->saslSecret)
|
||||
free(client->saslSecret);
|
||||
client->saslSecret = lsec;
|
||||
*secret = lsec;
|
||||
|
||||
/* Clear client password */
|
||||
size_t i;
|
||||
for (i = 0; i < lsec->len; i++) {
|
||||
password[i] = '\0';
|
||||
}
|
||||
free(password);
|
||||
|
||||
return SASL_OK;
|
||||
}
|
||||
|
||||
#define SASL_MAX_MECHLIST_LEN 300
|
||||
#define SASL_MAX_DATA_LEN (1024 * 1024)
|
||||
|
||||
/* Perform the SASL authentication process
|
||||
*/
|
||||
rfbBool
|
||||
HandleSASLAuth(rfbClient *client)
|
||||
{
|
||||
sasl_conn_t *saslconn = NULL;
|
||||
sasl_security_properties_t secprops;
|
||||
const char *clientout;
|
||||
char *serverin = NULL;
|
||||
unsigned int clientoutlen, serverinlen;
|
||||
int err, complete = 0;
|
||||
char *localAddr = NULL, *remoteAddr = NULL;
|
||||
const void *val;
|
||||
sasl_ssf_t ssf;
|
||||
sasl_callback_t saslcb[] = {
|
||||
{SASL_CB_LOG, (void *)log_func, NULL},
|
||||
{SASL_CB_AUTHNAME, client->GetUser ? (void *)user_callback_adapt : NULL, client},
|
||||
{SASL_CB_PASS, client->GetPassword ? (void *)password_callback_adapt : NULL, client},
|
||||
{ .id = 0 },
|
||||
};
|
||||
sasl_interact_t *interact = NULL;
|
||||
uint32_t mechlistlen;
|
||||
char *mechlist;
|
||||
char *wantmech;
|
||||
const char *mechname;
|
||||
|
||||
if (client->saslconn)
|
||||
sasl_dispose(&client->saslconn);
|
||||
|
||||
/* Sets up the SASL library as a whole */
|
||||
err = sasl_client_init(NULL);
|
||||
rfbClientLog("Client initialize SASL authentication %d\n", err);
|
||||
if (err != SASL_OK) {
|
||||
rfbClientLog("failed to initialize SASL library: %d (%s)\n",
|
||||
err, sasl_errstring(err, NULL, NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get local address in form IPADDR:PORT */
|
||||
struct sockaddr_storage localAddress;
|
||||
socklen_t addressLength = sizeof(localAddress);
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
int port;
|
||||
|
||||
if (getsockname(client->sock, (struct sockaddr*)&localAddress, &addressLength)) {
|
||||
rfbClientLog("failed to get local address\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (localAddress.ss_family == AF_INET) {
|
||||
struct sockaddr_in *sa_in = (struct sockaddr_in*)&localAddress;
|
||||
inet_ntop(AF_INET, &(sa_in->sin_addr), buf, INET_ADDRSTRLEN);
|
||||
port = ntohs(sa_in->sin_port);
|
||||
localAddr = vnc_connection_addr_to_string(buf, port);
|
||||
} else if (localAddress.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sa_in = (struct sockaddr_in6*)&localAddress;
|
||||
inet_ntop(AF_INET6, &(sa_in->sin6_addr), buf, INET6_ADDRSTRLEN);
|
||||
port = ntohs(sa_in->sin6_port);
|
||||
localAddr = vnc_connection_addr_to_string(buf, port);
|
||||
} else {
|
||||
rfbClientLog("failed to get local address\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get remote address in form IPADDR:PORT */
|
||||
remoteAddr = vnc_connection_addr_to_string(client->serverHost, client->serverPort);
|
||||
|
||||
rfbClientLog("Client SASL new host:'%s' local:'%s' remote:'%s'\n", client->serverHost, localAddr, remoteAddr);
|
||||
|
||||
/* Setup a handle for being a client */
|
||||
err = sasl_client_new("vnc",
|
||||
client->serverHost,
|
||||
localAddr,
|
||||
remoteAddr,
|
||||
saslcb,
|
||||
SASL_SUCCESS_DATA,
|
||||
&saslconn);
|
||||
free(localAddr);
|
||||
free(remoteAddr);
|
||||
|
||||
if (err != SASL_OK) {
|
||||
rfbClientLog("Failed to create SASL client context: %d (%s)\n",
|
||||
err, sasl_errstring(err, NULL, NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Initialize some connection props we care about */
|
||||
if (client->tlsSession) {
|
||||
if (!(ssf = (sasl_ssf_t)GetTLSCipherBits(client))) {
|
||||
rfbClientLog("%s", "invalid cipher size for TLS session\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rfbClientLog("Setting external SSF %d\n", ssf);
|
||||
err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
|
||||
if (err != SASL_OK) {
|
||||
rfbClientLog("cannot set external SSF %d (%s)\n",
|
||||
err, sasl_errstring(err, NULL, NULL));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
memset (&secprops, 0, sizeof secprops);
|
||||
/* If we've got TLS, we don't care about SSF */
|
||||
secprops.min_ssf = client->tlsSession ? 0 : 56; /* Equiv to DES supported by all Kerberos */
|
||||
secprops.max_ssf = client->tlsSession ? 0 : 100000; /* Very strong ! AES == 256 */
|
||||
secprops.maxbufsize = 100000;
|
||||
/* If we're not TLS, then forbid any anonymous or trivially crackable auth */
|
||||
secprops.security_flags = client->tlsSession ? 0 :
|
||||
SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
|
||||
|
||||
err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
|
||||
if (err != SASL_OK) {
|
||||
rfbClientLog("cannot set security props %d (%s)\n",
|
||||
err, sasl_errstring(err, NULL, NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get the supported mechanisms from the server */
|
||||
if (!ReadFromRFBServer(client, (char *)&mechlistlen, 4)) {
|
||||
rfbClientLog("failed to read mechlistlen\n");
|
||||
goto error;
|
||||
}
|
||||
mechlistlen = rfbClientSwap32IfLE(mechlistlen);
|
||||
rfbClientLog("mechlistlen is %d\n", mechlistlen);
|
||||
if (mechlistlen > SASL_MAX_MECHLIST_LEN) {
|
||||
rfbClientLog("mechlistlen %d too long\n", mechlistlen);
|
||||
goto error;
|
||||
}
|
||||
|
||||
mechlist = malloc(mechlistlen+1);
|
||||
if (!mechlist || !ReadFromRFBServer(client, mechlist, mechlistlen)) {
|
||||
free(mechlist);
|
||||
goto error;
|
||||
}
|
||||
mechlist[mechlistlen] = '\0';
|
||||
|
||||
/* Allow the client to influence the mechanism selected. */
|
||||
if (client->GetSASLMechanism) {
|
||||
wantmech = client->GetSASLMechanism(client, mechlist);
|
||||
|
||||
if (wantmech && *wantmech != 0) {
|
||||
if (strstr(mechlist, wantmech) == NULL) {
|
||||
rfbClientLog("Client requested SASL mechanism %s not supported by server\n",
|
||||
wantmech);
|
||||
free(mechlist);
|
||||
free(wantmech);
|
||||
goto error;
|
||||
} else {
|
||||
free(mechlist);
|
||||
mechlist = wantmech;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rfbClientLog("Client start negotiation mechlist '%s'\n", mechlist);
|
||||
|
||||
/* Start the auth negotiation on the client end first */
|
||||
err = sasl_client_start(saslconn,
|
||||
mechlist,
|
||||
&interact,
|
||||
&clientout,
|
||||
&clientoutlen,
|
||||
&mechname);
|
||||
if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
|
||||
rfbClientLog("Failed to start SASL negotiation: %d (%s)\n",
|
||||
err, sasl_errdetail(saslconn));
|
||||
free(mechlist);
|
||||
mechlist = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Need to gather some credentials from the client */
|
||||
if (err == SASL_INTERACT) {
|
||||
rfbClientLog("User interaction required but not currently supported\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rfbClientLog("Server start negotiation with mech %s. Data %d bytes %p '%s'\n",
|
||||
mechname, clientoutlen, clientout, clientout);
|
||||
|
||||
if (clientoutlen > SASL_MAX_DATA_LEN) {
|
||||
rfbClientLog("SASL negotiation data too long: %d bytes\n",
|
||||
clientoutlen);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send back the chosen mechname */
|
||||
uint32_t mechnamelen = rfbClientSwap32IfLE(strlen(mechname));
|
||||
if (!WriteToRFBServer(client, (char *)&mechnamelen, 4)) goto error;
|
||||
if (!WriteToRFBServer(client, (char *)mechname, strlen(mechname))) goto error;
|
||||
|
||||
/* NB, distinction of NULL vs "" is *critical* in SASL */
|
||||
if (clientout) {
|
||||
uint32_t colsw = rfbClientSwap32IfLE(clientoutlen + 1);
|
||||
if (!WriteToRFBServer(client, (char *)&colsw, 4)) goto error;
|
||||
if (!WriteToRFBServer(client, (char *)clientout, clientoutlen + 1)) goto error;
|
||||
} else {
|
||||
uint32_t temp = 0;
|
||||
if (!WriteToRFBServer(client, (char *)&temp, 4)) goto error;
|
||||
}
|
||||
|
||||
rfbClientLog("%s", "Getting sever start negotiation reply\n");
|
||||
/* Read the 'START' message reply from server */
|
||||
if (!ReadFromRFBServer(client, (char *)&serverinlen, 4)) goto error;
|
||||
serverinlen = rfbClientSwap32IfLE(serverinlen);
|
||||
|
||||
if (serverinlen > SASL_MAX_DATA_LEN) {
|
||||
rfbClientLog("SASL negotiation data too long: %d bytes\n",
|
||||
serverinlen);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* NB, distinction of NULL vs "" is *critical* in SASL */
|
||||
if (serverinlen) {
|
||||
serverin = malloc(serverinlen);
|
||||
if (!serverin || !ReadFromRFBServer(client, serverin, serverinlen)) goto error;
|
||||
serverin[serverinlen-1] = '\0';
|
||||
serverinlen--;
|
||||
} else {
|
||||
serverin = NULL;
|
||||
}
|
||||
if (!ReadFromRFBServer(client, (char *)&complete, 1)) goto error;
|
||||
|
||||
rfbClientLog("Client start result complete: %d. Data %d bytes %p '%s'\n",
|
||||
complete, serverinlen, serverin, serverin);
|
||||
|
||||
/* Loop-the-loop...
|
||||
* Even if the server has completed, the client must *always* do at least one step
|
||||
* in this loop to verify the server isn't lying about something. Mutual auth */
|
||||
for (;;) {
|
||||
err = sasl_client_step(saslconn,
|
||||
serverin,
|
||||
serverinlen,
|
||||
&interact,
|
||||
&clientout,
|
||||
&clientoutlen);
|
||||
if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
|
||||
rfbClientLog("Failed SASL step: %d (%s)\n",
|
||||
err, sasl_errdetail(saslconn));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Need to gather some credentials from the client */
|
||||
if (err == SASL_INTERACT) {
|
||||
rfbClientLog("User interaction required but not currently supported\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (serverin) {
|
||||
free(serverin);
|
||||
serverin = NULL;
|
||||
}
|
||||
|
||||
rfbClientLog("Client step result %d. Data %d bytes %p '%s'\n", err, clientoutlen, clientout, clientout);
|
||||
|
||||
/* Previous server call showed completion & we're now locally complete too */
|
||||
if (complete && err == SASL_OK)
|
||||
break;
|
||||
|
||||
/* Not done, prepare to talk with the server for another iteration */
|
||||
|
||||
/* NB, distinction of NULL vs "" is *critical* in SASL */
|
||||
if (clientout) {
|
||||
uint32_t colsw = rfbClientSwap32IfLE(clientoutlen + 1);
|
||||
if (!WriteToRFBServer(client, (char *)&colsw, 4)) goto error;
|
||||
if (!WriteToRFBServer(client, (char *)clientout, clientoutlen + 1)) goto error;
|
||||
} else {
|
||||
uint32_t temp = 0;
|
||||
if (!WriteToRFBServer(client, (char *)&temp, 4)) goto error;
|
||||
}
|
||||
|
||||
rfbClientLog("Server step with %d bytes %p\n", clientoutlen, clientout);
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&serverinlen, 4)) goto error;
|
||||
serverinlen = rfbClientSwap32IfLE(serverinlen);
|
||||
|
||||
if (serverinlen > SASL_MAX_DATA_LEN) {
|
||||
rfbClientLog("SASL negotiation data too long: %d bytes\n",
|
||||
serverinlen);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* NB, distinction of NULL vs "" is *critical* in SASL */
|
||||
if (serverinlen) {
|
||||
serverin = malloc(serverinlen);
|
||||
if (!serverin || !ReadFromRFBServer(client, serverin, serverinlen)) goto error;
|
||||
serverin[serverinlen-1] = '\0';
|
||||
serverinlen--;
|
||||
} else {
|
||||
serverin = NULL;
|
||||
}
|
||||
if (!ReadFromRFBServer(client, (char *)&complete, 1)) goto error;
|
||||
|
||||
rfbClientLog("Client step result complete: %d. Data %d bytes %p '%s'\n",
|
||||
complete, serverinlen, serverin, serverin);
|
||||
|
||||
/* This server call shows complete, and earlier client step was OK */
|
||||
if (complete && err == SASL_OK) {
|
||||
free(serverin);
|
||||
serverin = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for suitable SSF if non-TLS */
|
||||
if (!client->tlsSession) {
|
||||
err = sasl_getprop(saslconn, SASL_SSF, &val);
|
||||
if (err != SASL_OK) {
|
||||
rfbClientLog("cannot query SASL ssf on connection %d (%s)\n",
|
||||
err, sasl_errstring(err, NULL, NULL));
|
||||
goto error;
|
||||
}
|
||||
ssf = *(const int *)val;
|
||||
rfbClientLog("SASL SSF value %d\n", ssf);
|
||||
if (ssf < 56) { /* 56 == DES level, good for Kerberos */
|
||||
rfbClientLog("negotiation SSF %d was not strong enough\n", ssf);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
rfbClientLog("%s", "SASL authentication complete\n");
|
||||
|
||||
uint32_t result;
|
||||
if (!ReadFromRFBServer(client, (char *)&result, 4)) {
|
||||
rfbClientLog("Failed to read authentication result\n");
|
||||
goto error;
|
||||
}
|
||||
result = rfbClientSwap32IfLE(result);
|
||||
|
||||
if (result != 0) {
|
||||
rfbClientLog("Authentication failure\n");
|
||||
goto error;
|
||||
}
|
||||
rfbClientLog("Authentication successful - switching to SSF\n");
|
||||
|
||||
/* This must come *after* check-auth-result, because the former
|
||||
* is defined to be sent unencrypted, and setting saslconn turns
|
||||
* on the SSF layer encryption processing */
|
||||
client->saslconn = saslconn;
|
||||
|
||||
/* Clear SASL secret from memory if set - it'll be free'd on dispose */
|
||||
if (client->saslSecret) {
|
||||
size_t i;
|
||||
for (i = 0; i < client->saslSecret->len; i++)
|
||||
client->saslSecret->data[i] = '\0';
|
||||
client->saslSecret->len = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (client->saslSecret) {
|
||||
size_t i;
|
||||
for (i = 0; i < client->saslSecret->len; i++)
|
||||
client->saslSecret->data[i] = '\0';
|
||||
client->saslSecret->len = 0;
|
||||
}
|
||||
|
||||
if (saslconn)
|
||||
sasl_dispose(&saslconn);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
ReadFromSASL(rfbClient* client, char *out, unsigned int n)
|
||||
{
|
||||
size_t want;
|
||||
|
||||
if (client->saslDecoded == NULL) {
|
||||
char *encoded;
|
||||
int encodedLen;
|
||||
int err, ret;
|
||||
|
||||
encodedLen = 8192;
|
||||
encoded = (char *)malloc(encodedLen);
|
||||
if (!encoded) {
|
||||
errno = EIO;
|
||||
return -EIO;
|
||||
}
|
||||
ret = read(client->sock, encoded, encodedLen);
|
||||
if (ret < 0) {
|
||||
free(encoded);
|
||||
return ret;
|
||||
}
|
||||
if (ret == 0) {
|
||||
free(encoded);
|
||||
errno = EIO;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = sasl_decode(client->saslconn, encoded, ret,
|
||||
&client->saslDecoded, &client->saslDecodedLength);
|
||||
free(encoded);
|
||||
if (err != SASL_OK) {
|
||||
rfbClientLog("Failed to decode SASL data %s\n",
|
||||
sasl_errstring(err, NULL, NULL));
|
||||
return -EINVAL;
|
||||
}
|
||||
client->saslDecodedOffset = 0;
|
||||
}
|
||||
|
||||
want = client->saslDecodedLength - client->saslDecodedOffset;
|
||||
if (want > n)
|
||||
want = n;
|
||||
|
||||
memcpy(out,
|
||||
client->saslDecoded + client->saslDecodedOffset,
|
||||
want);
|
||||
client->saslDecodedOffset += want;
|
||||
if (client->saslDecodedOffset == client->saslDecodedLength) {
|
||||
client->saslDecodedLength = client->saslDecodedOffset = 0;
|
||||
client->saslDecoded = NULL;
|
||||
}
|
||||
|
||||
if (!want) {
|
||||
errno = EAGAIN;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return want;
|
||||
}
|
||||
39
android/extern/libvncserver/src/libvncclient/sasl.h
vendored
Normal file
39
android/extern/libvncserver/src/libvncclient/sasl.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef RFBSASL_H
|
||||
#define RFBSASL_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 S. Waterman. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
/*
|
||||
* Perform the SASL authentication process
|
||||
*/
|
||||
rfbBool HandleSASLAuth(rfbClient *client);
|
||||
|
||||
/*
|
||||
* Read from SASL when the SASL SSF is in use.
|
||||
*/
|
||||
int ReadFromSASL(rfbClient* client, char *out, unsigned int n);
|
||||
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
#endif /* RFBSASL_H */
|
||||
879
android/extern/libvncserver/src/libvncclient/sockets.c
vendored
Normal file
879
android/extern/libvncserver/src/libvncclient/sockets.c
vendored
Normal file
@@ -0,0 +1,879 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org>
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* sockets.c - functions to deal with sockets.
|
||||
*/
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#ifdef __linux__
|
||||
/* Setting this on other systems hides definitions such as INADDR_LOOPBACK.
|
||||
* The check should be for __GLIBC__ in fact. */
|
||||
# define _POSIX_SOURCE
|
||||
#endif
|
||||
#endif
|
||||
#if LIBVNCSERVER_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
#include "sockets.h"
|
||||
#include "tls.h"
|
||||
#include "sasl.h"
|
||||
|
||||
void PrintInHex(char *buf, int len);
|
||||
|
||||
rfbBool errorMessageOnReadFailure = TRUE;
|
||||
|
||||
/*
|
||||
* ReadFromRFBServer is called whenever we want to read some data from the RFB
|
||||
* server. It is non-trivial for two reasons:
|
||||
*
|
||||
* 1. For efficiency it performs some intelligent buffering, avoiding invoking
|
||||
* the read() system call too often. For small chunks of data, it simply
|
||||
* copies the data out of an internal buffer. For large amounts of data it
|
||||
* reads directly into the buffer provided by the caller.
|
||||
*
|
||||
* 2. Whenever read() would block, it invokes the Xt event dispatching
|
||||
* mechanism to process X events. In fact, this is the only place these
|
||||
* events are processed, as there is no XtAppMainLoop in the program.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
ReadFromRFBServer(rfbClient* client, char *out, unsigned int n)
|
||||
{
|
||||
const int USECS_WAIT_PER_RETRY = 100000;
|
||||
int retries = 0;
|
||||
#undef DEBUG_READ_EXACT
|
||||
#ifdef DEBUG_READ_EXACT
|
||||
char* oout=out;
|
||||
unsigned int nn=n;
|
||||
rfbClientLog("ReadFromRFBServer %d bytes\n",n);
|
||||
#endif
|
||||
|
||||
/* Handle attempts to write to NULL out buffer that might occur
|
||||
when an outside malloc() fails. For instance, memcpy() to NULL
|
||||
results in undefined behaviour and probably memory corruption.*/
|
||||
if(!out)
|
||||
return FALSE;
|
||||
|
||||
if (client->serverPort==-1) {
|
||||
/* vncrec playing */
|
||||
rfbVNCRec* rec = client->vncRec;
|
||||
struct timeval tv;
|
||||
|
||||
if (rec->readTimestamp) {
|
||||
rec->readTimestamp = FALSE;
|
||||
if (!fread(&tv,sizeof(struct timeval),1,rec->file))
|
||||
return FALSE;
|
||||
|
||||
tv.tv_sec = rfbClientSwap32IfLE (tv.tv_sec);
|
||||
tv.tv_usec = rfbClientSwap32IfLE (tv.tv_usec);
|
||||
|
||||
if (rec->tv.tv_sec!=0 && !rec->doNotSleep) {
|
||||
struct timeval diff;
|
||||
diff.tv_sec = tv.tv_sec - rec->tv.tv_sec;
|
||||
diff.tv_usec = tv.tv_usec - rec->tv.tv_usec;
|
||||
if(diff.tv_usec<0) {
|
||||
diff.tv_sec--;
|
||||
diff.tv_usec+=1000000;
|
||||
}
|
||||
#ifndef WIN32
|
||||
sleep (diff.tv_sec);
|
||||
usleep (diff.tv_usec);
|
||||
#else
|
||||
Sleep (diff.tv_sec * 1000 + diff.tv_usec/1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
rec->tv=tv;
|
||||
}
|
||||
|
||||
return (fread(out,1,n,rec->file) != n ? FALSE : TRUE);
|
||||
}
|
||||
|
||||
if (n <= client->buffered) {
|
||||
memcpy(out, client->bufoutptr, n);
|
||||
client->bufoutptr += n;
|
||||
client->buffered -= n;
|
||||
#ifdef DEBUG_READ_EXACT
|
||||
goto hexdump;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
memcpy(out, client->bufoutptr, client->buffered);
|
||||
|
||||
out += client->buffered;
|
||||
n -= client->buffered;
|
||||
|
||||
client->bufoutptr = client->buf;
|
||||
client->buffered = 0;
|
||||
|
||||
if (n <= RFB_BUF_SIZE) {
|
||||
|
||||
while (client->buffered < n) {
|
||||
int i;
|
||||
if (client->tlsSession)
|
||||
i = ReadFromTLS(client, client->buf + client->buffered, RFB_BUF_SIZE - client->buffered);
|
||||
else
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
if (client->saslconn)
|
||||
i = ReadFromSASL(client, client->buf + client->buffered, RFB_BUF_SIZE - client->buffered);
|
||||
else {
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
i = read(client->sock, client->buf + client->buffered, RFB_BUF_SIZE - client->buffered);
|
||||
#ifdef WIN32
|
||||
if (i < 0) errno=WSAGetLastError();
|
||||
#endif
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i <= 0) {
|
||||
if (i < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
if (client->readTimeout > 0 &&
|
||||
++retries > (client->readTimeout * 1000 * 1000 / USECS_WAIT_PER_RETRY))
|
||||
{
|
||||
rfbClientLog("Connection timed out\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* TODO:
|
||||
ProcessXtEvents();
|
||||
*/
|
||||
WaitForMessage(client, USECS_WAIT_PER_RETRY);
|
||||
i = 0;
|
||||
} else {
|
||||
rfbClientErr("read (%d: %s)\n",errno,strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (errorMessageOnReadFailure) {
|
||||
rfbClientLog("VNC server closed connection\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
client->buffered += i;
|
||||
}
|
||||
|
||||
memcpy(out, client->bufoutptr, n);
|
||||
client->bufoutptr += n;
|
||||
client->buffered -= n;
|
||||
|
||||
} else {
|
||||
|
||||
while (n > 0) {
|
||||
int i;
|
||||
if (client->tlsSession)
|
||||
i = ReadFromTLS(client, out, n);
|
||||
else
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
if (client->saslconn)
|
||||
i = ReadFromSASL(client, out, n);
|
||||
else
|
||||
#endif
|
||||
i = read(client->sock, out, n);
|
||||
|
||||
if (i <= 0) {
|
||||
if (i < 0) {
|
||||
#ifdef WIN32
|
||||
errno=WSAGetLastError();
|
||||
#endif
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
if (client->readTimeout > 0 &&
|
||||
++retries > (client->readTimeout * 1000 * 1000 / USECS_WAIT_PER_RETRY))
|
||||
{
|
||||
rfbClientLog("Connection timed out\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* TODO:
|
||||
ProcessXtEvents();
|
||||
*/
|
||||
WaitForMessage(client, USECS_WAIT_PER_RETRY);
|
||||
i = 0;
|
||||
} else {
|
||||
rfbClientErr("read (%s)\n",strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (errorMessageOnReadFailure) {
|
||||
rfbClientLog("VNC server closed connection\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
out += i;
|
||||
n -= i;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_READ_EXACT
|
||||
hexdump:
|
||||
{ unsigned int ii;
|
||||
for(ii=0;ii<nn;ii++)
|
||||
fprintf(stderr,"%02x ",(unsigned char)oout[ii]);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write an exact number of bytes, and don't return until you've sent them.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
WriteToRFBServer(rfbClient* client, const char *buf, unsigned int n)
|
||||
{
|
||||
fd_set fds;
|
||||
int i = 0;
|
||||
int j;
|
||||
const char *obuf = buf;
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
const char *output;
|
||||
unsigned int outputlen;
|
||||
int err;
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
if (client->serverPort==-1)
|
||||
return TRUE; /* vncrec playing */
|
||||
|
||||
if (client->tlsSession) {
|
||||
/* WriteToTLS() will guarantee either everything is written, or error/eof returns */
|
||||
i = WriteToTLS(client, buf, n);
|
||||
if (i <= 0) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
if (client->saslconn) {
|
||||
err = sasl_encode(client->saslconn,
|
||||
buf, n,
|
||||
&output, &outputlen);
|
||||
if (err != SASL_OK) {
|
||||
rfbClientLog("Failed to encode SASL data %s",
|
||||
sasl_errstring(err, NULL, NULL));
|
||||
return FALSE;
|
||||
}
|
||||
obuf = output;
|
||||
n = outputlen;
|
||||
}
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
while (i < n) {
|
||||
j = write(client->sock, obuf + i, (n - i));
|
||||
if (j <= 0) {
|
||||
if (j < 0) {
|
||||
#ifdef WIN32
|
||||
errno=WSAGetLastError();
|
||||
#endif
|
||||
if (errno == EWOULDBLOCK ||
|
||||
#ifdef LIBVNCSERVER_ENOENT_WORKAROUND
|
||||
errno == ENOENT ||
|
||||
#endif
|
||||
errno == EAGAIN) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(client->sock,&fds);
|
||||
|
||||
if (select(client->sock+1, NULL, &fds, NULL, NULL) <= 0) {
|
||||
rfbClientErr("select\n");
|
||||
return FALSE;
|
||||
}
|
||||
j = 0;
|
||||
} else {
|
||||
rfbClientErr("write\n");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
rfbClientLog("write failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
i += j;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
rfbSocket
|
||||
ConnectClientToTcpAddr(unsigned int host, int port)
|
||||
{
|
||||
rfbSocket sock = ConnectClientToTcpAddrWithTimeout(host, port, DEFAULT_CONNECT_TIMEOUT);
|
||||
/* put socket back into blocking mode for compatibility reasons */
|
||||
if (sock != RFB_INVALID_SOCKET) {
|
||||
SetBlocking(sock);
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
rfbSocket
|
||||
ConnectClientToTcpAddrWithTimeout(unsigned int host, int port, unsigned int timeout)
|
||||
{
|
||||
rfbSocket sock;
|
||||
struct sockaddr_in addr;
|
||||
int one = 1;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = host;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock == RFB_INVALID_SOCKET) {
|
||||
#ifdef WIN32
|
||||
errno=WSAGetLastError();
|
||||
#endif
|
||||
rfbClientErr("ConnectToTcpAddr: socket (%s)\n",strerror(errno));
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (!SetNonBlocking(sock))
|
||||
return FALSE;
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
#ifdef WIN32
|
||||
errno=WSAGetLastError();
|
||||
#endif
|
||||
if (!((errno == EWOULDBLOCK || errno == EINPROGRESS) && sock_wait_for_connected(sock, timeout))) {
|
||||
rfbClientErr("ConnectToTcpAddr: connect\n");
|
||||
rfbCloseSocket(sock);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&one, sizeof(one)) < 0) {
|
||||
rfbClientErr("ConnectToTcpAddr: setsockopt\n");
|
||||
rfbCloseSocket(sock);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
rfbSocket
|
||||
ConnectClientToTcpAddr6(const char *hostname, int port)
|
||||
{
|
||||
rfbSocket sock = ConnectClientToTcpAddr6WithTimeout(hostname, port, DEFAULT_CONNECT_TIMEOUT);
|
||||
/* put socket back into blocking mode for compatibility reasons */
|
||||
if (sock != RFB_INVALID_SOCKET) {
|
||||
SetBlocking(sock);
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
rfbSocket
|
||||
ConnectClientToTcpAddr6WithTimeout(const char *hostname, int port, unsigned int timeout)
|
||||
{
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
rfbSocket sock;
|
||||
int n;
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
char port_s[10];
|
||||
int one = 1;
|
||||
|
||||
snprintf(port_s, 10, "%d", port);
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if ((n = getaddrinfo(strcmp(hostname,"") == 0 ? "localhost": hostname, port_s, &hints, &res)))
|
||||
{
|
||||
errno = -(1000 + n); // (ab)using errno for 'getaddrinfo' error reporting
|
||||
rfbClientErr("ConnectClientToTcpAddr6: getaddrinfo (%s)\n", gai_strerror(n));
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
ressave = res;
|
||||
sock = RFB_INVALID_SOCKET;
|
||||
while (res)
|
||||
{
|
||||
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (sock != RFB_INVALID_SOCKET)
|
||||
{
|
||||
if (SetNonBlocking(sock)) {
|
||||
if (connect(sock, res->ai_addr, res->ai_addrlen) == 0) {
|
||||
break;
|
||||
} else {
|
||||
#ifdef WIN32
|
||||
errno=WSAGetLastError();
|
||||
#endif
|
||||
if ((errno == EWOULDBLOCK || errno == EINPROGRESS) && sock_wait_for_connected(sock, timeout))
|
||||
break;
|
||||
rfbCloseSocket(sock);
|
||||
sock = RFB_INVALID_SOCKET;
|
||||
}
|
||||
} else {
|
||||
rfbCloseSocket(sock);
|
||||
sock = RFB_INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
res = res->ai_next;
|
||||
}
|
||||
freeaddrinfo(ressave);
|
||||
|
||||
if (sock == RFB_INVALID_SOCKET)
|
||||
{
|
||||
rfbClientErr("ConnectClientToTcpAddr6: connect\n");
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&one, sizeof(one)) < 0) {
|
||||
rfbClientErr("ConnectToTcpAddr: setsockopt\n");
|
||||
rfbCloseSocket(sock);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
||||
#else
|
||||
|
||||
rfbClientErr("ConnectClientToTcpAddr6: IPv6 disabled\n");
|
||||
return RFB_INVALID_SOCKET;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
rfbSocket
|
||||
ConnectClientToUnixSock(const char *sockFile)
|
||||
{
|
||||
rfbSocket sock = ConnectClientToUnixSockWithTimeout(sockFile, DEFAULT_CONNECT_TIMEOUT);
|
||||
/* put socket back into blocking mode for compatibility reasons */
|
||||
if (sock != RFB_INVALID_SOCKET) {
|
||||
SetBlocking(sock);
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
rfbSocket
|
||||
ConnectClientToUnixSockWithTimeout(const char *sockFile, unsigned int timeout)
|
||||
{
|
||||
#ifdef WIN32
|
||||
rfbClientErr("Windows doesn't support UNIX sockets\n");
|
||||
return RFB_INVALID_SOCKET;
|
||||
#else
|
||||
rfbSocket sock;
|
||||
struct sockaddr_un addr;
|
||||
addr.sun_family = AF_UNIX;
|
||||
if(strlen(sockFile) + 1 > sizeof(addr.sun_path)) {
|
||||
rfbClientErr("ConnectToUnixSock: socket file name too long\n");
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
strcpy(addr.sun_path, sockFile);
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock == RFB_INVALID_SOCKET) {
|
||||
rfbClientErr("ConnectToUnixSock: socket (%s)\n",strerror(errno));
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (!SetNonBlocking(sock))
|
||||
return RFB_INVALID_SOCKET;
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr.sun_family) + strlen(addr.sun_path)) < 0 &&
|
||||
!(errno == EINPROGRESS && sock_wait_for_connected(sock, timeout))) {
|
||||
rfbClientErr("ConnectToUnixSock: connect\n");
|
||||
rfbCloseSocket(sock);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return sock;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* FindFreeTcpPort tries to find unused TCP port in the range
|
||||
* (TUNNEL_PORT_OFFSET, TUNNEL_PORT_OFFSET + 99]. Returns 0 on failure.
|
||||
*/
|
||||
|
||||
int
|
||||
FindFreeTcpPort(void)
|
||||
{
|
||||
rfbSocket sock;
|
||||
int port;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock == RFB_INVALID_SOCKET) {
|
||||
rfbClientErr(": FindFreeTcpPort: socket\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
|
||||
addr.sin_port = htons((unsigned short)port);
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||
rfbCloseSocket(sock);
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
rfbCloseSocket(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ListenAtTcpPort starts listening at the given TCP port.
|
||||
*/
|
||||
|
||||
rfbSocket
|
||||
ListenAtTcpPort(int port)
|
||||
{
|
||||
return ListenAtTcpPortAndAddress(port, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* ListenAtTcpPortAndAddress starts listening at the given TCP port on
|
||||
* the given IP address
|
||||
*/
|
||||
|
||||
rfbSocket
|
||||
ListenAtTcpPortAndAddress(int port, const char *address)
|
||||
{
|
||||
rfbSocket sock = RFB_INVALID_SOCKET;
|
||||
int one = 1;
|
||||
#ifndef LIBVNCSERVER_IPv6
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (address) {
|
||||
addr.sin_addr.s_addr = inet_addr(address);
|
||||
} else {
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock == RFB_INVALID_SOCKET) {
|
||||
rfbClientErr("ListenAtTcpPort: socket\n");
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *)&one, sizeof(one)) < 0) {
|
||||
rfbClientErr("ListenAtTcpPort: setsockopt\n");
|
||||
rfbCloseSocket(sock);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
rfbClientErr("ListenAtTcpPort: bind\n");
|
||||
rfbCloseSocket(sock);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
#else
|
||||
int rv;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
char port_str[8];
|
||||
|
||||
snprintf(port_str, 8, "%d", port);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE; /* fill in wildcard address if address == NULL */
|
||||
|
||||
if ((rv = getaddrinfo(address, port_str, &hints, &servinfo)) != 0) {
|
||||
rfbClientErr("ListenAtTcpPortAndAddress: error in getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* loop through all the results and bind to the first we can */
|
||||
for(p = servinfo; p != NULL; p = p->ai_next) {
|
||||
if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == RFB_INVALID_SOCKET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
/* we have separate IPv4 and IPv6 sockets since some OS's do not support dual binding */
|
||||
if (p->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) {
|
||||
rfbClientErr("ListenAtTcpPortAndAddress: error in setsockopt IPV6_V6ONLY: %s\n", strerror(errno));
|
||||
rfbCloseSocket(sock);
|
||||
freeaddrinfo(servinfo);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
|
||||
rfbClientErr("ListenAtTcpPortAndAddress: error in setsockopt SO_REUSEADDR: %s\n", strerror(errno));
|
||||
rfbCloseSocket(sock);
|
||||
freeaddrinfo(servinfo);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (bind(sock, p->ai_addr, p->ai_addrlen) < 0) {
|
||||
rfbCloseSocket(sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
rfbClientErr("ListenAtTcpPortAndAddress: error in bind: %s\n", strerror(errno));
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* all done with this structure now */
|
||||
freeaddrinfo(servinfo);
|
||||
#endif
|
||||
|
||||
if (listen(sock, 5) < 0) {
|
||||
rfbClientErr("ListenAtTcpPort: listen\n");
|
||||
rfbCloseSocket(sock);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AcceptTcpConnection accepts a TCP connection.
|
||||
*/
|
||||
|
||||
rfbSocket
|
||||
AcceptTcpConnection(rfbSocket listenSock)
|
||||
{
|
||||
rfbSocket sock;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
int one = 1;
|
||||
|
||||
sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
|
||||
if (sock == RFB_INVALID_SOCKET) {
|
||||
rfbClientErr("AcceptTcpConnection: accept\n");
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&one, sizeof(one)) < 0) {
|
||||
rfbClientErr("AcceptTcpConnection: setsockopt\n");
|
||||
rfbCloseSocket(sock);
|
||||
return RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetNonBlocking sets a socket into non-blocking mode.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
SetNonBlocking(rfbSocket sock)
|
||||
{
|
||||
return sock_set_nonblocking(sock, TRUE, rfbClientErr);
|
||||
}
|
||||
|
||||
|
||||
rfbBool SetBlocking(rfbSocket sock)
|
||||
{
|
||||
return sock_set_nonblocking(sock, FALSE, rfbClientErr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetDSCP sets a socket's IP QoS parameters aka Differentiated Services Code Point field
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
SetDSCP(rfbSocket sock, int dscp)
|
||||
{
|
||||
#ifdef WIN32
|
||||
rfbClientErr("Setting of QoS IP DSCP not implemented for Windows\n");
|
||||
return TRUE;
|
||||
#else
|
||||
int level, cmd;
|
||||
struct sockaddr addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
|
||||
if(getsockname(sock, &addr, &addrlen) != 0) {
|
||||
rfbClientErr("Setting socket QoS failed while getting socket address: %s\n",strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch(addr.sa_family)
|
||||
{
|
||||
#if defined LIBVNCSERVER_IPv6 && defined IPV6_TCLASS
|
||||
case AF_INET6:
|
||||
level = IPPROTO_IPV6;
|
||||
cmd = IPV6_TCLASS;
|
||||
break;
|
||||
#endif
|
||||
case AF_INET:
|
||||
level = IPPROTO_IP;
|
||||
cmd = IP_TOS;
|
||||
break;
|
||||
default:
|
||||
rfbClientErr("Setting socket QoS failed: Not bound to IP address");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(setsockopt(sock, level, cmd, (void*)&dscp, sizeof(dscp)) != 0) {
|
||||
rfbClientErr("Setting socket QoS failed: %s\n", strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* StringToIPAddr - convert a host string to an IP address.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
StringToIPAddr(const char *str, unsigned int *addr)
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
|
||||
if (strcmp(str,"") == 0) {
|
||||
*addr = htonl(INADDR_LOOPBACK); /* local */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
*addr = inet_addr(str);
|
||||
|
||||
if (*addr != -1)
|
||||
return TRUE;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (getaddrinfo(str, NULL, &hints, &res) == 0) {
|
||||
*addr = (((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr);
|
||||
freeaddrinfo(res);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if the other end of a socket is on the same machine.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
SameMachine(rfbSocket sock)
|
||||
{
|
||||
struct sockaddr_in peeraddr, myaddr;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_in);
|
||||
|
||||
getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen);
|
||||
getsockname(sock, (struct sockaddr *)&myaddr, &addrlen);
|
||||
|
||||
return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print out the contents of a packet for debugging.
|
||||
*/
|
||||
|
||||
void
|
||||
PrintInHex(char *buf, int len)
|
||||
{
|
||||
int i, j;
|
||||
char c, str[17];
|
||||
|
||||
str[16] = 0;
|
||||
|
||||
rfbClientLog("ReadExact: ");
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if ((i % 16 == 0) && (i != 0)) {
|
||||
rfbClientLog(" ");
|
||||
}
|
||||
c = buf[i];
|
||||
str[i % 16] = (((c > 31) && (c < 127)) ? c : '.');
|
||||
rfbClientLog("%02x ",(unsigned char)c);
|
||||
if ((i % 4) == 3)
|
||||
rfbClientLog(" ");
|
||||
if ((i % 16) == 15)
|
||||
{
|
||||
rfbClientLog("%s\n",str);
|
||||
}
|
||||
}
|
||||
if ((i % 16) != 0)
|
||||
{
|
||||
for (j = i % 16; j < 16; j++)
|
||||
{
|
||||
rfbClientLog(" ");
|
||||
if ((j % 4) == 3) rfbClientLog(" ");
|
||||
}
|
||||
str[i % 16] = 0;
|
||||
rfbClientLog("%s\n",str);
|
||||
}
|
||||
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
int WaitForMessage(rfbClient* client,unsigned int usecs)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
int num;
|
||||
|
||||
if (client->serverPort==-1)
|
||||
/* playing back vncrec file */
|
||||
return 1;
|
||||
|
||||
if (client->buffered > 0)
|
||||
return 1;
|
||||
|
||||
timeout.tv_sec=(usecs/1000000);
|
||||
timeout.tv_usec=(usecs%1000000);
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(client->sock,&fds);
|
||||
|
||||
num=select(client->sock+1, &fds, NULL, NULL, &timeout);
|
||||
if(num<0) {
|
||||
#ifdef WIN32
|
||||
errno=WSAGetLastError();
|
||||
#endif
|
||||
rfbClientLog("Waiting for message failed: %d (%s)\n",errno,strerror(errno));
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
670
android/extern/libvncserver/src/libvncclient/tight.c
vendored
Normal file
670
android/extern/libvncserver/src/libvncclient/tight.c
vendored
Normal file
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright (C) 2017, 2019 D. R. Commander. All Rights Reserved.
|
||||
* Copyright (C) 2004-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2004 Landmark Graphics Corporation. All Rights Reserved.
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
|
||||
|
||||
#include "turbojpeg.h"
|
||||
|
||||
/*
|
||||
* tight.c - handle ``tight'' encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple
|
||||
* times by rfbproto.c, each time with a different definition of the
|
||||
* macro BPP. For each value of BPP, this file defines a function
|
||||
* which handles a tight-encoded rectangle with BPP bits per pixel.
|
||||
*
|
||||
*/
|
||||
|
||||
#define TIGHT_MIN_TO_COMPRESS 12
|
||||
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
#define filterPtrBPP CONCAT2E(filterPtr,BPP)
|
||||
|
||||
#define HandleTightBPP CONCAT2E(HandleTight,BPP)
|
||||
#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
|
||||
#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
|
||||
#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
|
||||
#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
|
||||
#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
|
||||
#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
|
||||
|
||||
#if BPP != 8
|
||||
#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
|
||||
#endif
|
||||
|
||||
#ifndef RGB_TO_PIXEL
|
||||
|
||||
#define RGB_TO_PIXEL(bpp,r,g,b) \
|
||||
(((CARD##bpp)(r) & client->format.redMax) << client->format.redShift | \
|
||||
((CARD##bpp)(g) & client->format.greenMax) << client->format.greenShift | \
|
||||
((CARD##bpp)(b) & client->format.blueMax) << client->format.blueShift)
|
||||
|
||||
#define RGB24_TO_PIXEL(bpp,r,g,b) \
|
||||
((((CARD##bpp)(r) & 0xFF) * client->format.redMax + 127) / 255 \
|
||||
<< client->format.redShift | \
|
||||
(((CARD##bpp)(g) & 0xFF) * client->format.greenMax + 127) / 255 \
|
||||
<< client->format.greenShift | \
|
||||
(((CARD##bpp)(b) & 0xFF) * client->format.blueMax + 127) / 255 \
|
||||
<< client->format.blueShift)
|
||||
|
||||
#define RGB24_TO_PIXEL32(r,g,b) \
|
||||
(((uint32_t)(r) & 0xFF) << client->format.redShift | \
|
||||
((uint32_t)(g) & 0xFF) << client->format.greenShift | \
|
||||
((uint32_t)(b) & 0xFF) << client->format.blueShift)
|
||||
|
||||
#endif
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
typedef void (*filterPtrBPP)(rfbClient* client, int, int, int);
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
static int InitFilterCopyBPP (rfbClient* client, int rw, int rh);
|
||||
static int InitFilterPaletteBPP (rfbClient* client, int rw, int rh);
|
||||
static int InitFilterGradientBPP (rfbClient* client, int rw, int rh);
|
||||
static void FilterCopyBPP (rfbClient* client, int srcx, int srcy, int numRows);
|
||||
static void FilterPaletteBPP (rfbClient* client, int srcx, int srcy, int numRows);
|
||||
static void FilterGradientBPP (rfbClient* client, int srcx, int srcy, int numRows);
|
||||
|
||||
#if BPP != 8
|
||||
static rfbBool DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h);
|
||||
#endif
|
||||
|
||||
/* Definitions */
|
||||
|
||||
static rfbBool
|
||||
HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
CARDBPP fill_colour;
|
||||
uint8_t comp_ctl;
|
||||
uint8_t filter_id;
|
||||
filterPtrBPP filterFn;
|
||||
z_streamp zs;
|
||||
int err, stream_id, compressedLen, bitsPixel;
|
||||
int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
|
||||
rfbBool readUncompressed = FALSE;
|
||||
|
||||
if (client->frameBuffer == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (rx + rw > client->width || ry + rh > client->height) {
|
||||
rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", rx, ry, rw, rh);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&comp_ctl, 1))
|
||||
return FALSE;
|
||||
|
||||
/* Flush zlib streams if we are told by the server to do so. */
|
||||
for (stream_id = 0; stream_id < 4; stream_id++) {
|
||||
if ((comp_ctl & 1) && client->zlibStreamActive[stream_id]) {
|
||||
if (inflateEnd (&client->zlibStream[stream_id]) != Z_OK &&
|
||||
client->zlibStream[stream_id].msg != NULL)
|
||||
rfbClientLog("inflateEnd: %s\n", client->zlibStream[stream_id].msg);
|
||||
client->zlibStreamActive[stream_id] = FALSE;
|
||||
}
|
||||
comp_ctl >>= 1;
|
||||
}
|
||||
|
||||
if ((comp_ctl & rfbTightNoZlib) == rfbTightNoZlib) {
|
||||
comp_ctl &= ~(rfbTightNoZlib);
|
||||
readUncompressed = TRUE;
|
||||
}
|
||||
|
||||
/* Handle solid rectangles. */
|
||||
if (comp_ctl == rfbTightFill) {
|
||||
#if BPP == 32
|
||||
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||
if (!ReadFromRFBServer(client, client->buffer, 3))
|
||||
return FALSE;
|
||||
fill_colour = RGB24_TO_PIXEL32(client->buffer[0], client->buffer[1], client->buffer[2]);
|
||||
} else {
|
||||
if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour)))
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour)))
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
client->GotFillRect(client, rx, ry, rw, rh, fill_colour);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if BPP == 8
|
||||
if (comp_ctl == rfbTightJpeg) {
|
||||
rfbClientLog("Tight encoding: JPEG is not supported in 8 bpp mode.\n");
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
if (comp_ctl == rfbTightJpeg) {
|
||||
return DecompressJpegRectBPP(client, rx, ry, rw, rh);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Quit on unsupported subencoding value. */
|
||||
if (comp_ctl > rfbTightMaxSubencoding) {
|
||||
rfbClientLog("Tight encoding: bad subencoding value received.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here primary compression mode handling begins.
|
||||
* Data was processed with optional filter + zlib compression.
|
||||
*/
|
||||
|
||||
/* First, we should identify a filter to use. */
|
||||
if ((comp_ctl & rfbTightExplicitFilter) != 0) {
|
||||
if (!ReadFromRFBServer(client, (char*)&filter_id, 1))
|
||||
return FALSE;
|
||||
|
||||
switch (filter_id) {
|
||||
case rfbTightFilterCopy:
|
||||
filterFn = FilterCopyBPP;
|
||||
bitsPixel = InitFilterCopyBPP(client, rw, rh);
|
||||
break;
|
||||
case rfbTightFilterPalette:
|
||||
filterFn = FilterPaletteBPP;
|
||||
bitsPixel = InitFilterPaletteBPP(client, rw, rh);
|
||||
break;
|
||||
case rfbTightFilterGradient:
|
||||
filterFn = FilterGradientBPP;
|
||||
bitsPixel = InitFilterGradientBPP(client, rw, rh);
|
||||
break;
|
||||
default:
|
||||
rfbClientLog("Tight encoding: unknown filter code received.\n");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
filterFn = FilterCopyBPP;
|
||||
bitsPixel = InitFilterCopyBPP(client, rw, rh);
|
||||
}
|
||||
if (bitsPixel == 0) {
|
||||
rfbClientLog("Tight encoding: error receiving palette.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Determine if the data should be decompressed or just copied. */
|
||||
rowSize = (rw * bitsPixel + 7) / 8;
|
||||
if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
|
||||
if (!ReadFromRFBServer(client, (char*)client->buffer, rh * rowSize))
|
||||
return FALSE;
|
||||
|
||||
filterFn(client, rx, ry, rh);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Read the length (1..3 bytes) of compressed data following. */
|
||||
compressedLen = (int)ReadCompactLen(client);
|
||||
if (compressedLen <= 0) {
|
||||
rfbClientLog("Incorrect data received from the server.\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (readUncompressed) {
|
||||
if (compressedLen > RFB_BUFFER_SIZE) {
|
||||
rfbClientErr("Received uncompressed byte count exceeds our buffer size.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)client->buffer, compressedLen))
|
||||
return FALSE;
|
||||
|
||||
filterFn(client, rx, ry, rh);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Now let's initialize compression stream if needed. */
|
||||
stream_id = comp_ctl & 0x03;
|
||||
zs = &client->zlibStream[stream_id];
|
||||
if (!client->zlibStreamActive[stream_id]) {
|
||||
zs->zalloc = Z_NULL;
|
||||
zs->zfree = Z_NULL;
|
||||
zs->opaque = Z_NULL;
|
||||
err = inflateInit(zs);
|
||||
if (err != Z_OK) {
|
||||
if (zs->msg != NULL)
|
||||
rfbClientLog("InflateInit error: %s.\n", zs->msg);
|
||||
return FALSE;
|
||||
}
|
||||
client->zlibStreamActive[stream_id] = TRUE;
|
||||
}
|
||||
|
||||
/* Read, decode and draw actual pixel data in a loop. */
|
||||
|
||||
bufferSize = RFB_BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
|
||||
if (rowSize > bufferSize) {
|
||||
/* Should be impossible when RFB_BUFFER_SIZE >= 16384 */
|
||||
rfbClientLog("Internal error: incorrect buffer size.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rowsProcessed = 0;
|
||||
extraBytes = 0;
|
||||
|
||||
while (compressedLen > 0) {
|
||||
if (compressedLen > ZLIB_BUFFER_SIZE)
|
||||
portionLen = ZLIB_BUFFER_SIZE;
|
||||
else
|
||||
portionLen = compressedLen;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)client->zlib_buffer, portionLen))
|
||||
return FALSE;
|
||||
|
||||
compressedLen -= portionLen;
|
||||
|
||||
zs->next_in = (Bytef *)client->zlib_buffer;
|
||||
zs->avail_in = portionLen;
|
||||
|
||||
do {
|
||||
zs->next_out = (Bytef *)&client->buffer[extraBytes];
|
||||
zs->avail_out = bufferSize - extraBytes;
|
||||
|
||||
err = inflate(zs, Z_SYNC_FLUSH);
|
||||
if (err == Z_BUF_ERROR) /* Input exhausted -- no problem. */
|
||||
break;
|
||||
if (err != Z_OK && err != Z_STREAM_END) {
|
||||
if (zs->msg != NULL) {
|
||||
rfbClientLog("Inflate error: %s.\n", zs->msg);
|
||||
} else {
|
||||
rfbClientLog("Inflate error: %d.\n", err);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
numRows = (bufferSize - zs->avail_out) / rowSize;
|
||||
|
||||
filterFn(client, rx, ry+rowsProcessed, numRows);
|
||||
|
||||
extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
|
||||
if (extraBytes > 0)
|
||||
memcpy(client->buffer, &client->buffer[numRows * rowSize], extraBytes);
|
||||
|
||||
rowsProcessed += numRows;
|
||||
}
|
||||
while (zs->avail_out == 0);
|
||||
}
|
||||
|
||||
if (rowsProcessed != rh) {
|
||||
rfbClientLog("Incorrect number of scan lines after decompression.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*
|
||||
* Filter stuff.
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
InitFilterCopyBPP (rfbClient* client, int rw, int rh)
|
||||
{
|
||||
client->rectWidth = rw;
|
||||
|
||||
#if BPP == 32
|
||||
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||
client->cutZeros = TRUE;
|
||||
return 24;
|
||||
} else {
|
||||
client->cutZeros = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return BPP;
|
||||
}
|
||||
|
||||
static void
|
||||
FilterCopyBPP (rfbClient* client, int srcx, int srcy, int numRows)
|
||||
{
|
||||
CARDBPP *dst =
|
||||
(CARDBPP *)&client->frameBuffer[(srcy * client->width + srcx) * BPP / 8];
|
||||
int y;
|
||||
|
||||
#if BPP == 32
|
||||
int x;
|
||||
|
||||
if (client->cutZeros) {
|
||||
for (y = 0; y < numRows; y++) {
|
||||
for (x = 0; x < client->rectWidth; x++) {
|
||||
dst[y*client->width+x] =
|
||||
RGB24_TO_PIXEL32(client->buffer[(y*client->rectWidth+x)*3],
|
||||
client->buffer[(y*client->rectWidth+x)*3+1],
|
||||
client->buffer[(y*client->rectWidth+x)*3+2]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (y = 0; y < numRows; y++)
|
||||
memcpy (&dst[y*client->width],
|
||||
&client->buffer[y * client->rectWidth * (BPP / 8)],
|
||||
client->rectWidth * (BPP / 8));
|
||||
}
|
||||
|
||||
static int
|
||||
InitFilterGradientBPP (rfbClient* client, int rw, int rh)
|
||||
{
|
||||
int bits;
|
||||
|
||||
bits = InitFilterCopyBPP(client, rw, rh);
|
||||
if (client->cutZeros)
|
||||
memset(client->tightPrevRow, 0, rw * 3);
|
||||
else
|
||||
memset(client->tightPrevRow, 0, rw * 3 * sizeof(uint16_t));
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
#if BPP == 32
|
||||
|
||||
static void
|
||||
FilterGradient24 (rfbClient* client, int srcx, int srcy, int numRows)
|
||||
{
|
||||
CARDBPP *dst =
|
||||
(CARDBPP *)&client->frameBuffer[(srcy * client->width + srcx) * BPP / 8];
|
||||
int x, y, c;
|
||||
uint8_t thisRow[2048*3];
|
||||
uint8_t pix[3];
|
||||
int est[3];
|
||||
|
||||
for (y = 0; y < numRows; y++) {
|
||||
|
||||
/* First pixel in a row */
|
||||
for (c = 0; c < 3; c++) {
|
||||
pix[c] = client->tightPrevRow[c] + client->buffer[y*client->rectWidth*3+c];
|
||||
thisRow[c] = pix[c];
|
||||
}
|
||||
dst[y*client->width] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
|
||||
|
||||
/* Remaining pixels of a row */
|
||||
for (x = 1; x < client->rectWidth; x++) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
est[c] = (int)client->tightPrevRow[x*3+c] + (int)pix[c] -
|
||||
(int)client->tightPrevRow[(x-1)*3+c];
|
||||
if (est[c] > 0xFF) {
|
||||
est[c] = 0xFF;
|
||||
} else if (est[c] < 0x00) {
|
||||
est[c] = 0x00;
|
||||
}
|
||||
pix[c] = (uint8_t)est[c] + client->buffer[(y*client->rectWidth+x)*3+c];
|
||||
thisRow[x*3+c] = pix[c];
|
||||
}
|
||||
dst[y*client->width+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
|
||||
}
|
||||
|
||||
memcpy(client->tightPrevRow, thisRow, client->rectWidth * 3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
FilterGradientBPP (rfbClient* client, int srcx, int srcy, int numRows)
|
||||
{
|
||||
CARDBPP *dst =
|
||||
(CARDBPP *)&client->frameBuffer[(srcy * client->width + srcx) * BPP / 8];
|
||||
int x, y, c;
|
||||
CARDBPP *src = (CARDBPP *)client->buffer;
|
||||
uint16_t *thatRow = (uint16_t *)client->tightPrevRow;
|
||||
uint16_t thisRow[2048*3];
|
||||
uint16_t pix[3];
|
||||
uint16_t max[3];
|
||||
int shift[3];
|
||||
int est[3];
|
||||
|
||||
#if BPP == 32
|
||||
if (client->cutZeros) {
|
||||
FilterGradient24(client, srcx, srcy, numRows);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
max[0] = client->format.redMax;
|
||||
max[1] = client->format.greenMax;
|
||||
max[2] = client->format.blueMax;
|
||||
|
||||
shift[0] = client->format.redShift;
|
||||
shift[1] = client->format.greenShift;
|
||||
shift[2] = client->format.blueShift;
|
||||
|
||||
for (y = 0; y < numRows; y++) {
|
||||
|
||||
/* First pixel in a row */
|
||||
for (c = 0; c < 3; c++) {
|
||||
pix[c] = (uint16_t)(((src[y*client->rectWidth] >> shift[c]) + thatRow[c]) & max[c]);
|
||||
thisRow[c] = pix[c];
|
||||
}
|
||||
dst[y*client->width] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
|
||||
|
||||
/* Remaining pixels of a row */
|
||||
for (x = 1; x < client->rectWidth; x++) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
|
||||
if (est[c] > (int)max[c]) {
|
||||
est[c] = (int)max[c];
|
||||
} else if (est[c] < 0) {
|
||||
est[c] = 0;
|
||||
}
|
||||
pix[c] = (uint16_t)(((src[y*client->rectWidth+x] >> shift[c]) + est[c]) & max[c]);
|
||||
thisRow[x*3+c] = pix[c];
|
||||
}
|
||||
dst[y*client->width+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
|
||||
}
|
||||
memcpy(thatRow, thisRow, client->rectWidth * 3 * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
InitFilterPaletteBPP (rfbClient* client, int rw, int rh)
|
||||
{
|
||||
uint8_t numColors;
|
||||
#if BPP == 32
|
||||
int i;
|
||||
CARDBPP *palette = (CARDBPP *)client->tightPalette;
|
||||
#endif
|
||||
|
||||
client->rectWidth = rw;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)&numColors, 1))
|
||||
return 0;
|
||||
|
||||
client->rectColors = (int)numColors;
|
||||
if (++client->rectColors < 2)
|
||||
return 0;
|
||||
|
||||
#if BPP == 32
|
||||
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||
if (!ReadFromRFBServer(client, (char*)&client->tightPalette, client->rectColors * 3))
|
||||
return 0;
|
||||
for (i = client->rectColors - 1; i >= 0; i--) {
|
||||
palette[i] = RGB24_TO_PIXEL32(client->tightPalette[i*3],
|
||||
client->tightPalette[i*3+1],
|
||||
client->tightPalette[i*3+2]);
|
||||
}
|
||||
return (client->rectColors == 2) ? 1 : 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)&client->tightPalette, client->rectColors * (BPP / 8)))
|
||||
return 0;
|
||||
|
||||
return (client->rectColors == 2) ? 1 : 8;
|
||||
}
|
||||
|
||||
static void
|
||||
FilterPaletteBPP (rfbClient* client, int srcx, int srcy, int numRows)
|
||||
{
|
||||
int x, y, b, w;
|
||||
CARDBPP *dst =
|
||||
(CARDBPP *)&client->frameBuffer[(srcy * client->width + srcx) * BPP / 8];
|
||||
uint8_t *src = (uint8_t *)client->buffer;
|
||||
CARDBPP *palette = (CARDBPP *)client->tightPalette;
|
||||
|
||||
if (client->rectColors == 2) {
|
||||
w = (client->rectWidth + 7) / 8;
|
||||
for (y = 0; y < numRows; y++) {
|
||||
for (x = 0; x < client->rectWidth / 8; x++) {
|
||||
for (b = 7; b >= 0; b--)
|
||||
dst[y*client->width+x*8+7-b] = palette[src[y*w+x] >> b & 1];
|
||||
}
|
||||
for (b = 7; b >= 8 - client->rectWidth % 8; b--) {
|
||||
dst[y*client->width+x*8+7-b] = palette[src[y*w+x] >> b & 1];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < numRows; y++)
|
||||
for (x = 0; x < client->rectWidth; x++)
|
||||
dst[y*client->width+x] = palette[(int)src[y*client->rectWidth+x]];
|
||||
}
|
||||
}
|
||||
|
||||
#if BPP != 8
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*
|
||||
* JPEG decompression.
|
||||
*
|
||||
*/
|
||||
|
||||
static rfbBool
|
||||
DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h)
|
||||
{
|
||||
int compressedLen;
|
||||
uint8_t *compressedData, *dst;
|
||||
int pixelSize, pitch, flags = 0;
|
||||
|
||||
compressedLen = (int)ReadCompactLen(client);
|
||||
if (compressedLen <= 0) {
|
||||
rfbClientLog("Incorrect data received from the server.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
compressedData = malloc(compressedLen);
|
||||
if (compressedData == NULL) {
|
||||
rfbClientLog("Memory allocation error.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)compressedData, compressedLen)) {
|
||||
free(compressedData);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(client->GotJpeg != NULL)
|
||||
return client->GotJpeg(client, compressedData, compressedLen, x, y, w, h);
|
||||
|
||||
if (!client->tjhnd) {
|
||||
if ((client->tjhnd = tjInitDecompress()) == NULL) {
|
||||
rfbClientLog("TurboJPEG error: %s\n", tjGetErrorStr());
|
||||
free(compressedData);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#if BPP == 16
|
||||
flags = 0;
|
||||
pixelSize = 3;
|
||||
pitch = w * pixelSize;
|
||||
dst = (uint8_t *)client->buffer;
|
||||
#else
|
||||
if (client->format.bigEndian) flags |= TJ_ALPHAFIRST;
|
||||
if (client->format.redShift == 16 && client->format.blueShift == 0)
|
||||
flags |= TJ_BGR;
|
||||
if (client->format.bigEndian) flags ^= TJ_BGR;
|
||||
pixelSize = BPP / 8;
|
||||
pitch = client->width * pixelSize;
|
||||
dst = &client->frameBuffer[y * pitch + x * pixelSize];
|
||||
#endif
|
||||
|
||||
if (tjDecompress(client->tjhnd, compressedData, (unsigned long)compressedLen,
|
||||
dst, w, pitch, h, pixelSize, flags)==-1) {
|
||||
rfbClientLog("TurboJPEG error: %s\n", tjGetErrorStr());
|
||||
free(compressedData);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
free(compressedData);
|
||||
|
||||
#if BPP == 16
|
||||
pixelSize = BPP / 8;
|
||||
pitch = client->width * pixelSize;
|
||||
dst = &client->frameBuffer[y * pitch + x * pixelSize];
|
||||
{
|
||||
CARDBPP *dst16=(CARDBPP *)dst, *dst2;
|
||||
char *src = client->buffer;
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < h; j++) {
|
||||
for (i = 0, dst2 = dst16; i < w; i++, dst2++, src += 3) {
|
||||
*dst2 = RGB24_TO_PIXEL(BPP, src[0], src[1], src[2]);
|
||||
}
|
||||
dst16 += client->width;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static long
|
||||
ReadCompactLen (rfbClient* client)
|
||||
{
|
||||
long len;
|
||||
uint8_t b;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&b, 1))
|
||||
return -1;
|
||||
len = (int)b & 0x7F;
|
||||
if (b & 0x80) {
|
||||
if (!ReadFromRFBServer(client, (char *)&b, 1))
|
||||
return -1;
|
||||
len |= ((int)b & 0x7F) << 7;
|
||||
if (b & 0x80) {
|
||||
if (!ReadFromRFBServer(client, (char *)&b, 1))
|
||||
return -1;
|
||||
len |= ((int)b & 0xFF) << 14;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef CARDBPP
|
||||
|
||||
/* LIBVNCSERVER_HAVE_LIBZ and LIBVNCSERVER_HAVE_LIBJPEG */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
56
android/extern/libvncserver/src/libvncclient/tls.h
vendored
Normal file
56
android/extern/libvncserver/src/libvncclient/tls.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef TLS_H
|
||||
#define TLS_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009 Vic Lee.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/* Handle Anonymous TLS Authentication (18) with the server.
|
||||
* After authentication, client->tlsSession will be set.
|
||||
*/
|
||||
rfbBool HandleAnonTLSAuth(rfbClient* client);
|
||||
|
||||
/* Handle VeNCrypt Authentication (19) with the server.
|
||||
* The callback function GetX509Credential will be called.
|
||||
* After authentication, client->tlsSession will be set.
|
||||
*/
|
||||
rfbBool HandleVeNCryptAuth(rfbClient* client);
|
||||
|
||||
/* Read desired bytes from TLS session.
|
||||
* It's a wrapper function over gnutls_record_recv() and return values
|
||||
* are same as read(), that is, >0 for actual bytes read, 0 for EOF,
|
||||
* or EAGAIN, EINTR.
|
||||
* This should be a non-blocking call. Blocking is handled in sockets.c.
|
||||
*/
|
||||
int ReadFromTLS(rfbClient* client, char *out, unsigned int n);
|
||||
|
||||
/* Write desired bytes to TLS session.
|
||||
* It's a wrapper function over gnutls_record_send() and it will be
|
||||
* blocking call, until all bytes are written or error returned.
|
||||
*/
|
||||
int WriteToTLS(rfbClient* client, const char *buf, unsigned int n);
|
||||
|
||||
/* Free TLS resources */
|
||||
void FreeTLS(rfbClient* client);
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
/* Get the number of bits in the current cipher */
|
||||
int GetTLSCipherBits(rfbClient* client);
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
#endif /* TLS_H */
|
||||
662
android/extern/libvncserver/src/libvncclient/tls_gnutls.c
vendored
Normal file
662
android/extern/libvncserver/src/libvncclient/tls_gnutls.c
vendored
Normal file
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Vic Lee.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/x509.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
#include <errno.h>
|
||||
#include "tls.h"
|
||||
|
||||
|
||||
static const char *rfbTLSPriority = "NORMAL:+DHE-DSS:+RSA:+DHE-RSA:+SRP";
|
||||
static const char *rfbAnonTLSPriority = "NORMAL:+ANON-ECDH:+ANON-DH";
|
||||
|
||||
#define DH_BITS 1024
|
||||
static gnutls_dh_params_t rfbDHParams;
|
||||
|
||||
static rfbBool rfbTLSInitialized = FALSE;
|
||||
|
||||
static int
|
||||
verify_certificate_callback (gnutls_session_t session)
|
||||
{
|
||||
unsigned int status;
|
||||
const gnutls_datum_t *cert_list;
|
||||
unsigned int cert_list_size;
|
||||
int ret;
|
||||
gnutls_x509_crt_t cert;
|
||||
rfbClient *sptr;
|
||||
char *hostname;
|
||||
|
||||
sptr = (rfbClient *)gnutls_session_get_ptr(session);
|
||||
if (!sptr) {
|
||||
rfbClientLog("Failed to validate certificate - missing client data\n");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
hostname = sptr->serverHost;
|
||||
if (!hostname) {
|
||||
rfbClientLog("No server hostname found for client\n");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
/* This verification function uses the trusted CAs in the credentials
|
||||
* structure. So you must have installed one or more CA certificates.
|
||||
*/
|
||||
ret = gnutls_certificate_verify_peers2 (session, &status);
|
||||
if (ret < 0)
|
||||
{
|
||||
rfbClientLog ("Certificate validation call failed\n");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
if (status & GNUTLS_CERT_INVALID)
|
||||
rfbClientLog("The certificate is not trusted.\n");
|
||||
|
||||
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
|
||||
rfbClientLog("The certificate hasn't got a known issuer.\n");
|
||||
|
||||
if (status & GNUTLS_CERT_REVOKED)
|
||||
rfbClientLog("The certificate has been revoked.\n");
|
||||
|
||||
if (status & GNUTLS_CERT_EXPIRED)
|
||||
rfbClientLog("The certificate has expired\n");
|
||||
|
||||
if (status & GNUTLS_CERT_NOT_ACTIVATED)
|
||||
rfbClientLog("The certificate is not yet activated\n");
|
||||
|
||||
if (status)
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
|
||||
/* Up to here the process is the same for X.509 certificates and
|
||||
* OpenPGP keys. From now on X.509 certificates are assumed. This can
|
||||
* be easily extended to work with openpgp keys as well.
|
||||
*/
|
||||
if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
|
||||
rfbClientLog("The certificate was not X509\n");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
if (gnutls_x509_crt_init (&cert) < 0)
|
||||
{
|
||||
rfbClientLog("Error initialising certificate structure\n");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
|
||||
if (cert_list == NULL)
|
||||
{
|
||||
rfbClientLog("No certificate was found!\n");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
|
||||
{
|
||||
rfbClientLog("Error parsing certificate\n");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
if (!gnutls_x509_crt_check_hostname (cert, hostname))
|
||||
{
|
||||
rfbClientLog("The certificate's owner does not match hostname '%s'\n",
|
||||
hostname);
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
gnutls_x509_crt_deinit (cert);
|
||||
|
||||
/* notify gnutls to continue handshake normally */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
InitializeTLS(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (rfbTLSInitialized) return TRUE;
|
||||
if ((ret = gnutls_global_init()) < 0 ||
|
||||
(ret = gnutls_dh_params_init(&rfbDHParams)) < 0 ||
|
||||
(ret = gnutls_dh_params_generate2(rfbDHParams, DH_BITS)) < 0)
|
||||
{
|
||||
rfbClientLog("Failed to initialized GnuTLS: %s.\n", gnutls_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
rfbClientLog("GnuTLS version %s initialized.\n", gnutls_check_version(NULL));
|
||||
rfbTLSInitialized = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* On Windows, translate WSAGetLastError() to errno values as GNU TLS does it
|
||||
* internally too. This is necessary because send() and recv() on Windows
|
||||
* don't set errno when they fail but GNUTLS expects a proper errno value.
|
||||
*
|
||||
* Use gnutls_transport_set_global_errno() like the GNU TLS documentation
|
||||
* suggests to avoid problems with different errno variables when GNU TLS and
|
||||
* libvncclient are linked to different versions of msvcrt.dll.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
static void WSAtoTLSErrno(gnutls_session_t* session)
|
||||
{
|
||||
switch(WSAGetLastError()) {
|
||||
#if (GNUTLS_VERSION_NUMBER >= 0x029901)
|
||||
case WSAEWOULDBLOCK:
|
||||
gnutls_transport_set_errno(session, EAGAIN);
|
||||
break;
|
||||
case WSAEINTR:
|
||||
gnutls_transport_set_errno(session, EINTR);
|
||||
break;
|
||||
default:
|
||||
gnutls_transport_set_errno(session, EIO);
|
||||
break;
|
||||
#else
|
||||
case WSAEWOULDBLOCK:
|
||||
gnutls_transport_set_global_errno(EAGAIN);
|
||||
break;
|
||||
case WSAEINTR:
|
||||
gnutls_transport_set_global_errno(EINTR);
|
||||
break;
|
||||
default:
|
||||
gnutls_transport_set_global_errno(EIO);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t
|
||||
PushTLS(gnutls_transport_ptr_t transport, const void *data, size_t len)
|
||||
{
|
||||
rfbClient *client = (rfbClient*)transport;
|
||||
int ret;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ret = write(client->sock, data, len);
|
||||
if (ret < 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
WSAtoTLSErrno((gnutls_session_t*)&client->tlsSession);
|
||||
#endif
|
||||
if (errno == EINTR) continue;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
PullTLS(gnutls_transport_ptr_t transport, void *data, size_t len)
|
||||
{
|
||||
rfbClient *client = (rfbClient*)transport;
|
||||
int ret;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ret = read(client->sock, data, len);
|
||||
if (ret < 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
WSAtoTLSErrno((gnutls_session_t*)&client->tlsSession);
|
||||
#endif
|
||||
if (errno == EINTR) continue;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
PullTimeout(gnutls_transport_ptr_t transport, unsigned int timeout)
|
||||
{
|
||||
rfbClient *client = (rfbClient*)transport;
|
||||
int ret;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ret = gnutls_system_recv_timeout((gnutls_transport_ptr_t)(long)client->sock, timeout);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
WSAtoTLSErrno((gnutls_session_t*)&client->tlsSession);
|
||||
#endif
|
||||
if (errno == EINTR) continue;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
InitializeTLSSession(rfbClient* client, rfbBool anonTLS)
|
||||
{
|
||||
int ret;
|
||||
const char *p;
|
||||
|
||||
if (client->tlsSession) return TRUE;
|
||||
|
||||
if ((ret = gnutls_init((gnutls_session_t*)&client->tlsSession, GNUTLS_CLIENT)) < 0)
|
||||
{
|
||||
rfbClientLog("Failed to initialized TLS session: %s.\n", gnutls_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((ret = gnutls_priority_set_direct((gnutls_session_t)client->tlsSession,
|
||||
anonTLS ? rfbAnonTLSPriority : rfbTLSPriority, &p)) < 0)
|
||||
{
|
||||
rfbClientLog("Warning: Failed to set TLS priority: %s (%s).\n", gnutls_strerror(ret), p);
|
||||
}
|
||||
|
||||
gnutls_transport_set_ptr((gnutls_session_t)client->tlsSession, (gnutls_transport_ptr_t)client);
|
||||
gnutls_transport_set_push_function((gnutls_session_t)client->tlsSession, PushTLS);
|
||||
gnutls_transport_set_pull_function((gnutls_session_t)client->tlsSession, PullTLS);
|
||||
|
||||
gnutls_transport_set_pull_timeout_function((gnutls_session_t)client->tlsSession, PullTimeout);
|
||||
gnutls_handshake_set_timeout((gnutls_session_t)client->tlsSession, 15000);
|
||||
|
||||
INIT_MUTEX(client->tlsRwMutex);
|
||||
|
||||
rfbClientLog("TLS session initialized.\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
SetTLSAnonCredential(rfbClient* client)
|
||||
{
|
||||
gnutls_anon_client_credentials_t anonCred;
|
||||
int ret;
|
||||
|
||||
if ((ret = gnutls_anon_allocate_client_credentials(&anonCred)) < 0 ||
|
||||
(ret = gnutls_credentials_set((gnutls_session_t)client->tlsSession, GNUTLS_CRD_ANON, anonCred)) < 0)
|
||||
{
|
||||
FreeTLS(client);
|
||||
rfbClientLog("Failed to create anonymous credentials: %s", gnutls_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
rfbClientLog("TLS anonymous credential created.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
HandshakeTLS(rfbClient* client)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while ((ret = gnutls_handshake((gnutls_session_t)client->tlsSession)) < 0)
|
||||
{
|
||||
if (!gnutls_error_is_fatal(ret))
|
||||
{
|
||||
rfbClientLog("TLS handshake got a temporary error: %s.\n", gnutls_strerror(ret));
|
||||
continue;
|
||||
}
|
||||
rfbClientLog("TLS handshake failed: %s\n", gnutls_strerror(ret));
|
||||
FreeTLS(client);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rfbClientLog("TLS handshake done.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* VeNCrypt sub auth. 1 byte auth count, followed by count * 4 byte integers */
|
||||
static rfbBool
|
||||
ReadVeNCryptSecurityType(rfbClient* client, uint32_t *result)
|
||||
{
|
||||
uint8_t count=0;
|
||||
uint8_t loop=0;
|
||||
uint32_t tAuth[256], t;
|
||||
char buf1[500],buf2[10];
|
||||
uint32_t origAuthScheme, authScheme;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&count, 1)) return FALSE;
|
||||
|
||||
if (count==0)
|
||||
{
|
||||
rfbClientLog("List of security types is ZERO. Giving up.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rfbClientLog("We have %d security types to read\n", count);
|
||||
authScheme=0;
|
||||
/* now, we have a list of available security types to read ( uint8_t[] ) */
|
||||
for (loop=0;loop<count;loop++)
|
||||
{
|
||||
if (!ReadFromRFBServer(client, (char *)&tAuth[loop], 4)) return FALSE;
|
||||
t=rfbClientSwap32IfLE(tAuth[loop]);
|
||||
rfbClientLog("%d) Received security type %d\n", loop, t);
|
||||
if (t==rfbNoAuth ||
|
||||
t==rfbVncAuth ||
|
||||
t==rfbVeNCryptPlain ||
|
||||
t==rfbVeNCryptTLSNone ||
|
||||
t==rfbVeNCryptTLSVNC ||
|
||||
t==rfbVeNCryptTLSPlain ||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
t==rfbVeNCryptTLSSASL ||
|
||||
t==rfbVeNCryptX509SASL ||
|
||||
#endif /*LIBVNCSERVER_HAVE_SASL */
|
||||
t==rfbVeNCryptX509None ||
|
||||
t==rfbVeNCryptX509VNC ||
|
||||
t==rfbVeNCryptX509Plain)
|
||||
{
|
||||
if (
|
||||
authScheme==0 ||
|
||||
authScheme==rfbNoAuth ||
|
||||
authScheme==rfbVncAuth ||
|
||||
authScheme==rfbVeNCryptPlain)
|
||||
{
|
||||
/* for security reasons, the encrypted type has a higher priority */
|
||||
origAuthScheme=tAuth[loop];
|
||||
authScheme=t;
|
||||
}
|
||||
}
|
||||
tAuth[loop]=t;
|
||||
}
|
||||
if (authScheme==0)
|
||||
{
|
||||
memset(buf1, 0, sizeof(buf1));
|
||||
for (loop=0;loop<count;loop++)
|
||||
{
|
||||
if (strlen(buf1)>=sizeof(buf1)-1) break;
|
||||
snprintf(buf2, sizeof(buf2), (loop>0 ? ", %d" : "%d"), (int)tAuth[loop]);
|
||||
strncat(buf1, buf2, sizeof(buf1)-strlen(buf1)-1);
|
||||
}
|
||||
rfbClientLog("Unknown VeNCrypt authentication scheme from VNC server: %s\n",
|
||||
buf1);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rfbClientLog("Selecting security type %d\n", authScheme);
|
||||
/* send back 4 bytes (in original byte order!) indicating which security type to use */
|
||||
if (!WriteToRFBServer(client, (char *)&origAuthScheme, 4)) return FALSE;
|
||||
}
|
||||
*result = authScheme;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeX509Credential(rfbCredential *cred)
|
||||
{
|
||||
if (cred->x509Credential.x509CACertFile) free(cred->x509Credential.x509CACertFile);
|
||||
if (cred->x509Credential.x509CACrlFile) free(cred->x509Credential.x509CACrlFile);
|
||||
if (cred->x509Credential.x509ClientCertFile) free(cred->x509Credential.x509ClientCertFile);
|
||||
if (cred->x509Credential.x509ClientKeyFile) free(cred->x509Credential.x509ClientKeyFile);
|
||||
free(cred);
|
||||
}
|
||||
|
||||
static gnutls_certificate_credentials_t
|
||||
CreateX509CertCredential(rfbCredential *cred)
|
||||
{
|
||||
gnutls_certificate_credentials_t x509_cred;
|
||||
int ret;
|
||||
|
||||
if (!cred->x509Credential.x509CACertFile)
|
||||
{
|
||||
rfbClientLog("No CA certificate provided.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0)
|
||||
{
|
||||
rfbClientLog("Cannot allocate credentials: %s.\n", gnutls_strerror(ret));
|
||||
return NULL;
|
||||
}
|
||||
if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
|
||||
cred->x509Credential.x509CACertFile, GNUTLS_X509_FMT_PEM)) < 0)
|
||||
{
|
||||
rfbClientLog("Cannot load CA credentials: %s.\n", gnutls_strerror(ret));
|
||||
gnutls_certificate_free_credentials (x509_cred);
|
||||
return NULL;
|
||||
}
|
||||
if (cred->x509Credential.x509ClientCertFile && cred->x509Credential.x509ClientKeyFile)
|
||||
{
|
||||
if ((ret = gnutls_certificate_set_x509_key_file(x509_cred,
|
||||
cred->x509Credential.x509ClientCertFile, cred->x509Credential.x509ClientKeyFile,
|
||||
GNUTLS_X509_FMT_PEM)) < 0)
|
||||
{
|
||||
rfbClientLog("Cannot load client certificate or key: %s.\n", gnutls_strerror(ret));
|
||||
gnutls_certificate_free_credentials (x509_cred);
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
{
|
||||
rfbClientLog("No client certificate or key provided.\n");
|
||||
}
|
||||
if (cred->x509Credential.x509CACrlFile)
|
||||
{
|
||||
if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
|
||||
cred->x509Credential.x509CACrlFile, GNUTLS_X509_FMT_PEM)) < 0)
|
||||
{
|
||||
rfbClientLog("Cannot load CRL: %s.\n", gnutls_strerror(ret));
|
||||
gnutls_certificate_free_credentials (x509_cred);
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
{
|
||||
rfbClientLog("No CRL provided.\n");
|
||||
}
|
||||
gnutls_certificate_set_dh_params (x509_cred, rfbDHParams);
|
||||
return x509_cred;
|
||||
}
|
||||
|
||||
|
||||
rfbBool
|
||||
HandleAnonTLSAuth(rfbClient* client)
|
||||
{
|
||||
if (!InitializeTLS() || !InitializeTLSSession(client, TRUE)) return FALSE;
|
||||
|
||||
if (!SetTLSAnonCredential(client)) return FALSE;
|
||||
|
||||
if (!HandshakeTLS(client)) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rfbBool
|
||||
HandleVeNCryptAuth(rfbClient* client)
|
||||
{
|
||||
uint8_t major, minor, status;
|
||||
uint32_t authScheme;
|
||||
rfbBool anonTLS;
|
||||
gnutls_certificate_credentials_t x509_cred = NULL;
|
||||
int ret;
|
||||
|
||||
/* Read VeNCrypt version */
|
||||
if (!ReadFromRFBServer(client, (char *)&major, 1) ||
|
||||
!ReadFromRFBServer(client, (char *)&minor, 1))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
rfbClientLog("Got VeNCrypt version %d.%d from server.\n", (int)major, (int)minor);
|
||||
|
||||
if (major != 0 && minor != 2)
|
||||
{
|
||||
rfbClientLog("Unsupported VeNCrypt version.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!WriteToRFBServer(client, (char *)&major, 1) ||
|
||||
!WriteToRFBServer(client, (char *)&minor, 1) ||
|
||||
!ReadFromRFBServer(client, (char *)&status, 1))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
rfbClientLog("Server refused VeNCrypt version %d.%d.\n", (int)major, (int)minor);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ReadVeNCryptSecurityType(client, &authScheme)) return FALSE;
|
||||
client->subAuthScheme = authScheme;
|
||||
|
||||
switch (authScheme)
|
||||
{
|
||||
/* Unencrypted types do not require additional actions */
|
||||
case rfbNoAuth:
|
||||
case rfbVncAuth:
|
||||
case rfbVeNCryptPlain:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
/* Some VeNCrypt security types are anonymous TLS, others are X509 */
|
||||
case rfbVeNCryptTLSNone:
|
||||
case rfbVeNCryptTLSVNC:
|
||||
case rfbVeNCryptTLSPlain:
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
case rfbVeNCryptTLSSASL:
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
anonTLS = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
anonTLS = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Ack is only requred for the encrypted connection */
|
||||
if (!ReadFromRFBServer(client, (char *)&status, 1) || status != 1)
|
||||
{
|
||||
rfbClientLog("Server refused VeNCrypt authentication %d (%d).\n", authScheme, (int)status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!InitializeTLS()) return FALSE;
|
||||
|
||||
/* Get X509 Credentials if it's not anonymous */
|
||||
if (!anonTLS)
|
||||
{
|
||||
rfbCredential *cred;
|
||||
|
||||
if (!client->GetCredential)
|
||||
{
|
||||
rfbClientLog("GetCredential callback is not set.\n");
|
||||
return FALSE;
|
||||
}
|
||||
cred = client->GetCredential(client, rfbCredentialTypeX509);
|
||||
if (!cred)
|
||||
{
|
||||
rfbClientLog("Reading credential failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
x509_cred = CreateX509CertCredential(cred);
|
||||
FreeX509Credential(cred);
|
||||
if (!x509_cred) return FALSE;
|
||||
}
|
||||
|
||||
/* Start up the TLS session */
|
||||
if (!InitializeTLSSession(client, anonTLS)) return FALSE;
|
||||
|
||||
if (anonTLS)
|
||||
{
|
||||
if (!SetTLSAnonCredential(client)) return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set the certificate verification callback. */
|
||||
gnutls_certificate_set_verify_function (x509_cred, verify_certificate_callback);
|
||||
gnutls_session_set_ptr ((gnutls_session_t)client->tlsSession, (void *)client);
|
||||
|
||||
if ((ret = gnutls_credentials_set((gnutls_session_t)client->tlsSession, GNUTLS_CRD_CERTIFICATE, x509_cred)) < 0)
|
||||
{
|
||||
rfbClientLog("Cannot set x509 credential: %s.\n", gnutls_strerror(ret));
|
||||
FreeTLS(client);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HandshakeTLS(client)) return FALSE;
|
||||
|
||||
/* We are done here. The caller should continue with client->subAuthScheme
|
||||
* to do actual sub authentication.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
ReadFromTLS(rfbClient* client, char *out, unsigned int n)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
LOCK(client->tlsRwMutex);
|
||||
ret = gnutls_record_recv((gnutls_session_t)client->tlsSession, out, n);
|
||||
UNLOCK(client->tlsRwMutex);
|
||||
|
||||
if (ret >= 0) return ret;
|
||||
if (ret == GNUTLS_E_REHANDSHAKE || ret == GNUTLS_E_AGAIN)
|
||||
{
|
||||
errno = EAGAIN;
|
||||
} else
|
||||
{
|
||||
rfbClientLog("Error reading from TLS: %s.\n", gnutls_strerror(ret));
|
||||
errno = EINTR;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
WriteToTLS(rfbClient* client, const char *buf, unsigned int n)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
ssize_t ret;
|
||||
|
||||
while (offset < n)
|
||||
{
|
||||
LOCK(client->tlsRwMutex);
|
||||
ret = gnutls_record_send((gnutls_session_t)client->tlsSession, buf+offset, (size_t)(n-offset));
|
||||
UNLOCK(client->tlsRwMutex);
|
||||
|
||||
if (ret == 0) continue;
|
||||
if (ret < 0)
|
||||
{
|
||||
if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) continue;
|
||||
rfbClientLog("Error writing to TLS: %s.\n", gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
offset += (unsigned int)ret;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void FreeTLS(rfbClient* client)
|
||||
{
|
||||
if (client->tlsSession)
|
||||
{
|
||||
gnutls_deinit((gnutls_session_t)client->tlsSession);
|
||||
client->tlsSession = NULL;
|
||||
TINI_MUTEX(client->tlsRwMutex);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
int
|
||||
GetTLSCipherBits(rfbClient* client)
|
||||
{
|
||||
gnutls_cipher_algorithm_t cipher = gnutls_cipher_get((gnutls_session_t)client->tlsSession);
|
||||
|
||||
return gnutls_cipher_get_key_size(cipher) * 8;
|
||||
}
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
67
android/extern/libvncserver/src/libvncclient/tls_none.c
vendored
Normal file
67
android/extern/libvncserver/src/libvncclient/tls_none.c
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Christian Beier.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfbclient.h>
|
||||
#include <errno.h>
|
||||
#include "tls.h"
|
||||
|
||||
rfbBool HandleAnonTLSAuth(rfbClient* client)
|
||||
{
|
||||
rfbClientLog("TLS is not supported.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
rfbBool HandleVeNCryptAuth(rfbClient* client)
|
||||
{
|
||||
rfbClientLog("TLS is not supported.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int ReadFromTLS(rfbClient* client, char *out, unsigned int n)
|
||||
{
|
||||
rfbClientLog("TLS is not supported.\n");
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int WriteToTLS(rfbClient* client, const char *buf, unsigned int n)
|
||||
{
|
||||
rfbClientLog("TLS is not supported.\n");
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void FreeTLS(rfbClient* client)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
int
|
||||
GetTLSCipherBits(rfbClient* client)
|
||||
{
|
||||
rfbClientLog("TLS is not supported.\n");
|
||||
return 0;
|
||||
}
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
717
android/extern/libvncserver/src/libvncclient/tls_openssl.c
vendored
Normal file
717
android/extern/libvncserver/src/libvncclient/tls_openssl.c
vendored
Normal file
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Philip Van Hoof <philip@codeminded.be>
|
||||
* Copyright (C) 2009 Vic Lee.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "tls.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
static rfbBool rfbTLSInitialized = FALSE;
|
||||
|
||||
// Locking callbacks are only initialized if we have mutex support.
|
||||
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
|
||||
|
||||
static MUTEX(*mutex_buf) = NULL;
|
||||
|
||||
struct CRYPTO_dynlock_value {
|
||||
MUTEX(mutex);
|
||||
};
|
||||
|
||||
static void locking_function(int mode, int n, const char *file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
LOCK(mutex_buf[n]);
|
||||
else
|
||||
UNLOCK(mutex_buf[n]);
|
||||
}
|
||||
|
||||
static unsigned long id_function(void)
|
||||
{
|
||||
return ((unsigned long) CURRENT_THREAD_ID);
|
||||
}
|
||||
|
||||
static struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line)
|
||||
{
|
||||
struct CRYPTO_dynlock_value *value;
|
||||
|
||||
value = (struct CRYPTO_dynlock_value *)
|
||||
malloc(sizeof(struct CRYPTO_dynlock_value));
|
||||
if (!value)
|
||||
goto err;
|
||||
INIT_MUTEX(value->mutex);
|
||||
|
||||
return value;
|
||||
|
||||
err:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void dyn_lock_function (int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
LOCK(l->mutex);
|
||||
else
|
||||
UNLOCK(l->mutex);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
|
||||
{
|
||||
TINI_MUTEX(l->mutex);
|
||||
free(l);
|
||||
}
|
||||
|
||||
static rfbBool InitLockingCb()
|
||||
{
|
||||
mutex_buf = malloc(CRYPTO_num_locks() * MUTEX_SIZE);
|
||||
if (mutex_buf == NULL) {
|
||||
rfbClientLog("Failed to initialized OpenSSL: memory.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++)
|
||||
INIT_MUTEX(mutex_buf[i]);
|
||||
|
||||
CRYPTO_set_locking_callback(locking_function);
|
||||
CRYPTO_set_id_callback(id_function);
|
||||
CRYPTO_set_dynlock_create_callback(dyn_create_function);
|
||||
CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
|
||||
CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else
|
||||
//If mutex support is not available, locking initialization is a no-op.
|
||||
static rfbBool InitLockingCb() { return TRUE; }
|
||||
#endif
|
||||
|
||||
static int
|
||||
ssl_error_to_errno (int ssl_error)
|
||||
{
|
||||
switch (ssl_error) {
|
||||
case SSL_ERROR_NONE:
|
||||
return 0;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
/* this one does not map well at all */
|
||||
//d(printf ("ssl_errno: SSL_ERROR_ZERO_RETURN\n"));
|
||||
return EINVAL;
|
||||
case SSL_ERROR_WANT_READ: /* non-fatal; retry */
|
||||
case SSL_ERROR_WANT_WRITE: /* non-fatal; retry */
|
||||
//d(printf ("ssl_errno: SSL_ERROR_WANT_[READ,WRITE]\n"));
|
||||
return EAGAIN;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
//d(printf ("ssl_errno: SSL_ERROR_SYSCALL\n"));
|
||||
return EINTR;
|
||||
case SSL_ERROR_SSL:
|
||||
//d(printf ("ssl_errno: SSL_ERROR_SSL <-- very useful error...riiiiight\n"));
|
||||
return EINTR;
|
||||
default:
|
||||
//d(printf ("ssl_errno: default error\n"));
|
||||
return EINTR;
|
||||
}
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
InitializeTLS(void)
|
||||
{
|
||||
if (rfbTLSInitialized)
|
||||
return TRUE;
|
||||
|
||||
if (!InitLockingCb())
|
||||
return FALSE;
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSLeay_add_ssl_algorithms();
|
||||
RAND_load_file("/dev/urandom", 1024);
|
||||
|
||||
rfbClientLog("OpenSSL version %s initialized.\n", SSLeay_version(SSLEAY_VERSION));
|
||||
rfbTLSInitialized = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int sock_read_ready(SSL *ssl, uint32_t ms)
|
||||
{
|
||||
int r = 0;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
|
||||
FD_SET(SSL_get_fd(ssl), &fds);
|
||||
|
||||
tv.tv_sec = ms / 1000;
|
||||
tv.tv_usec = (ms % 1000) * 1000;
|
||||
|
||||
r = select (SSL_get_fd(ssl) + 1, &fds, NULL, NULL, &tv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wait_for_data(SSL *ssl, int ret, int timeout)
|
||||
{
|
||||
int err;
|
||||
int retval = 1;
|
||||
|
||||
err = SSL_get_error(ssl, ret);
|
||||
|
||||
switch(err)
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
ret = sock_read_ready(ssl, timeout*1000);
|
||||
|
||||
if (ret == -1) {
|
||||
retval = 2;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
retval = 3;
|
||||
long verify_res = SSL_get_verify_result(ssl);
|
||||
if (verify_res != X509_V_OK)
|
||||
rfbClientLog("Could not verify server certificate: %s.\n",
|
||||
X509_verify_cert_error_string(verify_res));
|
||||
break;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
load_crls_from_file(char *file, SSL_CTX *ssl_ctx)
|
||||
{
|
||||
X509_STORE *st;
|
||||
int i;
|
||||
int count = 0;
|
||||
BIO *bio;
|
||||
STACK_OF(X509_INFO) *xis = NULL;
|
||||
X509_INFO *xi;
|
||||
|
||||
st = SSL_CTX_get_cert_store(ssl_ctx);
|
||||
|
||||
bio = BIO_new_file(file, "r");
|
||||
if (bio == NULL)
|
||||
return FALSE;
|
||||
|
||||
xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
|
||||
for (i = 0; i < sk_X509_INFO_num(xis); i++)
|
||||
{
|
||||
xi = sk_X509_INFO_value(xis, i);
|
||||
if (xi->crl)
|
||||
{
|
||||
X509_STORE_add_crl(st, xi->crl);
|
||||
xi->crl = NULL;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
sk_X509_INFO_pop_free(xis, X509_INFO_free);
|
||||
|
||||
if (count > 0)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static SSL *
|
||||
open_ssl_connection (rfbClient *client, int sockfd, rfbBool anonTLS, rfbCredential *cred)
|
||||
{
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
SSL *ssl = NULL;
|
||||
int n, finished = 0;
|
||||
X509_VERIFY_PARAM *param;
|
||||
uint8_t verify_crls;
|
||||
|
||||
if (!(ssl_ctx = SSL_CTX_new(SSLv23_client_method())))
|
||||
{
|
||||
rfbClientLog("Could not create new SSL context.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
param = X509_VERIFY_PARAM_new();
|
||||
|
||||
/* Setup verification if not anonymous */
|
||||
if (!anonTLS)
|
||||
{
|
||||
verify_crls = cred->x509Credential.x509CrlVerifyMode;
|
||||
if (cred->x509Credential.x509CACertFile)
|
||||
{
|
||||
if (!SSL_CTX_load_verify_locations(ssl_ctx, cred->x509Credential.x509CACertFile, NULL))
|
||||
{
|
||||
rfbClientLog("Failed to load CA certificate from %s.\n",
|
||||
cred->x509Credential.x509CACertFile);
|
||||
goto error_free_ctx;
|
||||
}
|
||||
} else {
|
||||
rfbClientLog("Using default paths for certificate verification.\n");
|
||||
SSL_CTX_set_default_verify_paths (ssl_ctx);
|
||||
}
|
||||
|
||||
if (cred->x509Credential.x509CACrlFile)
|
||||
{
|
||||
if (!load_crls_from_file(cred->x509Credential.x509CACrlFile, ssl_ctx))
|
||||
{
|
||||
rfbClientLog("CRLs could not be loaded.\n");
|
||||
goto error_free_ctx;
|
||||
}
|
||||
if (verify_crls == rfbX509CrlVerifyNone) verify_crls = rfbX509CrlVerifyAll;
|
||||
}
|
||||
|
||||
if (cred->x509Credential.x509ClientCertFile && cred->x509Credential.x509ClientKeyFile)
|
||||
{
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cred->x509Credential.x509ClientCertFile) != 1)
|
||||
{
|
||||
rfbClientLog("Client certificate could not be loaded.\n");
|
||||
goto error_free_ctx;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, cred->x509Credential.x509ClientKeyFile,
|
||||
SSL_FILETYPE_PEM) != 1)
|
||||
{
|
||||
rfbClientLog("Client private key could not be loaded.\n");
|
||||
goto error_free_ctx;
|
||||
}
|
||||
|
||||
if (SSL_CTX_check_private_key(ssl_ctx) == 0) {
|
||||
rfbClientLog("Client certificate and private key do not match.\n");
|
||||
goto error_free_ctx;
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
|
||||
|
||||
if (verify_crls == rfbX509CrlVerifyClient)
|
||||
X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);
|
||||
else if (verify_crls == rfbX509CrlVerifyAll)
|
||||
X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
|
||||
|
||||
if(!X509_VERIFY_PARAM_set1_host(param, client->serverHost, strlen(client->serverHost)))
|
||||
{
|
||||
rfbClientLog("Could not set server name for verification.\n");
|
||||
goto error_free_ctx;
|
||||
}
|
||||
SSL_CTX_set1_param(ssl_ctx, param);
|
||||
SSL_CTX_set_cipher_list(ssl_ctx, "ALL");
|
||||
} else { /* anonTLS here */
|
||||
/* Need anonymous ciphers for anonTLS, see https://github.com/LibVNC/libvncserver/issues/347#issuecomment-597477103 */
|
||||
#ifdef LIBWOLFSSL_VERSION_STRING
|
||||
SSL_CTX_set_cipher_list(ssl_ctx, "ADH-AES256-GCM-SHA384:ADH-AES128-SHA"); // wolfSSL requires full cipher names
|
||||
#else
|
||||
SSL_CTX_set_cipher_list(ssl_ctx, "aNULL");
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER) ||\
|
||||
defined(LIBWOLFSSL_VERSION_STRING)
|
||||
/*
|
||||
See https://www.openssl.org/docs/man1.1.0/man3/SSL_set_security_level.html
|
||||
Not specifying 0 here makes LibVNCClient fail connecting to some servers.
|
||||
*/
|
||||
SSL_CTX_set_security_level(ssl_ctx, 0);
|
||||
/*
|
||||
Specifying a maximum protocol version of 1.2 gets us ADH cipher on OpenSSL 1.1.x,
|
||||
see https://github.com/LibVNC/libvncserver/issues/347#issuecomment-597974313
|
||||
*/
|
||||
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_2_VERSION);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!(ssl = SSL_new (ssl_ctx)))
|
||||
{
|
||||
rfbClientLog("Could not create a new SSL session.\n");
|
||||
goto error_free_ctx;
|
||||
}
|
||||
|
||||
SSL_set_fd (ssl, sockfd);
|
||||
SSL_CTX_set_app_data (ssl_ctx, client);
|
||||
|
||||
do
|
||||
{
|
||||
n = SSL_connect(ssl);
|
||||
|
||||
if (n != 1)
|
||||
{
|
||||
if (wait_for_data(ssl, n, 1) != 1)
|
||||
{
|
||||
finished = 1;
|
||||
SSL_shutdown(ssl);
|
||||
|
||||
goto error_free_ssl;
|
||||
}
|
||||
}
|
||||
} while( n != 1 && finished != 1 );
|
||||
|
||||
X509_VERIFY_PARAM_free(param);
|
||||
return ssl;
|
||||
|
||||
error_free_ssl:
|
||||
SSL_free(ssl);
|
||||
|
||||
error_free_ctx:
|
||||
X509_VERIFY_PARAM_free(param);
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static rfbBool
|
||||
InitializeTLSSession(rfbClient* client, rfbBool anonTLS, rfbCredential *cred)
|
||||
{
|
||||
if (client->tlsSession) return TRUE;
|
||||
|
||||
client->tlsSession = open_ssl_connection (client, client->sock, anonTLS, cred);
|
||||
|
||||
if (!client->tlsSession)
|
||||
return FALSE;
|
||||
|
||||
INIT_MUTEX(client->tlsRwMutex);
|
||||
|
||||
rfbClientLog("TLS session initialized.\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
HandshakeTLS(rfbClient* client)
|
||||
{
|
||||
int timeout = 15;
|
||||
int ret;
|
||||
|
||||
return TRUE;
|
||||
|
||||
while (timeout > 0 && (ret = SSL_do_handshake(client->tlsSession)) < 0)
|
||||
{
|
||||
if (ret != -1)
|
||||
{
|
||||
rfbClientLog("TLS handshake blocking.\n");
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
timeout--;
|
||||
continue;
|
||||
}
|
||||
rfbClientLog("TLS handshake failed.\n");
|
||||
|
||||
FreeTLS(client);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
{
|
||||
rfbClientLog("TLS handshake timeout.\n");
|
||||
FreeTLS(client);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rfbClientLog("TLS handshake done.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* VeNCrypt sub auth. 1 byte auth count, followed by count * 4 byte integers */
|
||||
static rfbBool
|
||||
ReadVeNCryptSecurityType(rfbClient* client, uint32_t *result)
|
||||
{
|
||||
uint8_t count=0;
|
||||
uint8_t loop=0;
|
||||
uint32_t tAuth[256], t;
|
||||
char buf1[500],buf2[10];
|
||||
uint32_t origAuthScheme, authScheme;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&count, 1)) return FALSE;
|
||||
|
||||
if (count==0)
|
||||
{
|
||||
rfbClientLog("List of security types is ZERO. Giving up.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rfbClientLog("We have %d security types to read\n", count);
|
||||
authScheme=0;
|
||||
/* now, we have a list of available security types to read ( uint8_t[] ) */
|
||||
for (loop=0;loop<count;loop++)
|
||||
{
|
||||
if (!ReadFromRFBServer(client, (char *)&tAuth[loop], 4)) return FALSE;
|
||||
t=rfbClientSwap32IfLE(tAuth[loop]);
|
||||
rfbClientLog("%d) Received security type %d\n", loop, t);
|
||||
if (t==rfbNoAuth ||
|
||||
t==rfbVncAuth ||
|
||||
t==rfbVeNCryptPlain ||
|
||||
t==rfbVeNCryptTLSNone ||
|
||||
t==rfbVeNCryptTLSVNC ||
|
||||
t==rfbVeNCryptTLSPlain ||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
t==rfbVeNCryptTLSSASL ||
|
||||
t==rfbVeNCryptX509SASL ||
|
||||
#endif /*LIBVNCSERVER_HAVE_SASL */
|
||||
t==rfbVeNCryptX509None ||
|
||||
t==rfbVeNCryptX509VNC ||
|
||||
t==rfbVeNCryptX509Plain)
|
||||
{
|
||||
if (
|
||||
authScheme==0 ||
|
||||
authScheme==rfbNoAuth ||
|
||||
authScheme==rfbVncAuth ||
|
||||
authScheme==rfbVeNCryptPlain)
|
||||
{
|
||||
/* for security reasons, the encrypted type has a higher priority */
|
||||
origAuthScheme=tAuth[loop];
|
||||
authScheme=t;
|
||||
}
|
||||
}
|
||||
tAuth[loop]=t;
|
||||
}
|
||||
if (authScheme==0)
|
||||
{
|
||||
memset(buf1, 0, sizeof(buf1));
|
||||
for (loop=0;loop<count;loop++)
|
||||
{
|
||||
if (strlen(buf1)>=sizeof(buf1)-1) break;
|
||||
snprintf(buf2, sizeof(buf2), (loop>0 ? ", %d" : "%d"), (int)tAuth[loop]);
|
||||
strncat(buf1, buf2, sizeof(buf1)-strlen(buf1)-1);
|
||||
}
|
||||
rfbClientLog("Unknown VeNCrypt authentication scheme from VNC server: %s\n",
|
||||
buf1);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rfbClientLog("Selecting security type %d\n", authScheme);
|
||||
/* send back 4 bytes (in original byte order!) indicating which security type to use */
|
||||
if (!WriteToRFBServer(client, (char *)&origAuthScheme, 4)) return FALSE;
|
||||
}
|
||||
*result = authScheme;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rfbBool
|
||||
HandleAnonTLSAuth(rfbClient* client)
|
||||
{
|
||||
if (!InitializeTLS() || !InitializeTLSSession(client, TRUE, NULL)) return FALSE;
|
||||
|
||||
if (!HandshakeTLS(client)) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeX509Credential(rfbCredential *cred)
|
||||
{
|
||||
if (cred->x509Credential.x509CACertFile) free(cred->x509Credential.x509CACertFile);
|
||||
if (cred->x509Credential.x509CACrlFile) free(cred->x509Credential.x509CACrlFile);
|
||||
if (cred->x509Credential.x509ClientCertFile) free(cred->x509Credential.x509ClientCertFile);
|
||||
if (cred->x509Credential.x509ClientKeyFile) free(cred->x509Credential.x509ClientKeyFile);
|
||||
free(cred);
|
||||
}
|
||||
|
||||
rfbBool
|
||||
HandleVeNCryptAuth(rfbClient* client)
|
||||
{
|
||||
uint8_t major, minor, status;
|
||||
uint32_t authScheme;
|
||||
rfbBool anonTLS;
|
||||
rfbCredential *cred = NULL;
|
||||
rfbBool result = TRUE;
|
||||
|
||||
/* Read VeNCrypt version */
|
||||
if (!ReadFromRFBServer(client, (char *)&major, 1) ||
|
||||
!ReadFromRFBServer(client, (char *)&minor, 1))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
rfbClientLog("Got VeNCrypt version %d.%d from server.\n", (int)major, (int)minor);
|
||||
|
||||
if (major != 0 && minor != 2)
|
||||
{
|
||||
rfbClientLog("Unsupported VeNCrypt version.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!WriteToRFBServer(client, (char *)&major, 1) ||
|
||||
!WriteToRFBServer(client, (char *)&minor, 1) ||
|
||||
!ReadFromRFBServer(client, (char *)&status, 1))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
rfbClientLog("Server refused VeNCrypt version %d.%d.\n", (int)major, (int)minor);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ReadVeNCryptSecurityType(client, &authScheme)) return FALSE;
|
||||
client->subAuthScheme = authScheme;
|
||||
|
||||
switch (authScheme)
|
||||
{
|
||||
/* Unencrypted types do not require additional actions */
|
||||
case rfbNoAuth:
|
||||
case rfbVncAuth:
|
||||
case rfbVeNCryptPlain:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
/* Some VeNCrypt security types are anonymous TLS, others are X509 */
|
||||
case rfbVeNCryptTLSNone:
|
||||
case rfbVeNCryptTLSVNC:
|
||||
case rfbVeNCryptTLSPlain:
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
case rfbVeNCryptTLSSASL:
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
anonTLS = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
anonTLS = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Ack is only requred for the encrypted connection */
|
||||
if (!ReadFromRFBServer(client, (char *)&status, 1) || status != 1)
|
||||
{
|
||||
rfbClientLog("Server refused VeNCrypt authentication %d (%d).\n", authScheme, (int)status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!InitializeTLS()) return FALSE;
|
||||
|
||||
/* Get X509 Credentials if it's not anonymous */
|
||||
if (!anonTLS)
|
||||
{
|
||||
|
||||
if (!client->GetCredential)
|
||||
{
|
||||
rfbClientLog("GetCredential callback is not set.\n");
|
||||
return FALSE;
|
||||
}
|
||||
cred = client->GetCredential(client, rfbCredentialTypeX509);
|
||||
if (!cred)
|
||||
{
|
||||
rfbClientLog("Reading credential failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start up the TLS session */
|
||||
if (!InitializeTLSSession(client, anonTLS, cred)) result = FALSE;
|
||||
|
||||
if (!HandshakeTLS(client)) result = FALSE;
|
||||
|
||||
/* We are done here. The caller should continue with client->subAuthScheme
|
||||
* to do actual sub authentication.
|
||||
*/
|
||||
if (cred) FreeX509Credential(cred);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
ReadFromTLS(rfbClient* client, char *out, unsigned int n)
|
||||
{
|
||||
int ret = 0;
|
||||
int ssl_error = SSL_ERROR_NONE;
|
||||
|
||||
LOCK(client->tlsRwMutex);
|
||||
ret = SSL_read (client->tlsSession, out, n);
|
||||
|
||||
if (ret < 0)
|
||||
ssl_error = SSL_get_error(client->tlsSession, ret);
|
||||
UNLOCK(client->tlsRwMutex);
|
||||
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
else {
|
||||
errno = ssl_error_to_errno(ssl_error);
|
||||
if (errno != EAGAIN) {
|
||||
rfbClientLog("Error reading from TLS: -.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
WriteToTLS(rfbClient* client, const char *buf, unsigned int n)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
int ret = 0;
|
||||
int ssl_error = SSL_ERROR_NONE;
|
||||
|
||||
while (offset < n)
|
||||
{
|
||||
LOCK(client->tlsRwMutex);
|
||||
ret = SSL_write (client->tlsSession, buf + offset, (size_t)(n-offset));
|
||||
|
||||
if (ret < 0)
|
||||
ssl_error = SSL_get_error (client->tlsSession, ret);
|
||||
UNLOCK(client->tlsRwMutex);
|
||||
|
||||
if (ret == 0) continue;
|
||||
if (ret < 0)
|
||||
{
|
||||
errno = ssl_error_to_errno(ssl_error);
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
|
||||
rfbClientLog("Error writing to TLS: -\n");
|
||||
return -1;
|
||||
}
|
||||
offset += (unsigned int)ret;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
void FreeTLS(rfbClient* client)
|
||||
{
|
||||
if (client->tlsSession)
|
||||
{
|
||||
SSL_free(client->tlsSession);
|
||||
client->tlsSession = NULL;
|
||||
TINI_MUTEX(client->tlsRwMutex);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
int GetTLSCipherBits(rfbClient* client)
|
||||
{
|
||||
SSL *ssl = (SSL *)(client->tlsSession);
|
||||
|
||||
const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
|
||||
|
||||
return SSL_CIPHER_get_bits(cipher, NULL);
|
||||
}
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
299
android/extern/libvncserver/src/libvncclient/trle.c
vendored
Normal file
299
android/extern/libvncserver/src/libvncclient/trle.c
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Wiki Wang <wikiwang@live.com>. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* trle.c - handle trle encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles a trle
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#ifndef REALBPP
|
||||
#define REALBPP BPP
|
||||
#endif
|
||||
|
||||
#if !defined(UNCOMP) || UNCOMP == 0
|
||||
#define HandleTRLE CONCAT2E(HandleTRLE, REALBPP)
|
||||
#elif UNCOMP > 0
|
||||
#define HandleTRLE CONCAT3E(HandleTRLE, REALBPP, Down)
|
||||
#else
|
||||
#define HandleTRLE CONCAT3E(HandleTRLE, REALBPP, Up)
|
||||
#endif
|
||||
#define CARDBPP CONCAT3E(uint, BPP, _t)
|
||||
#define CARDREALBPP CONCAT3E(uint, REALBPP, _t)
|
||||
|
||||
#if REALBPP != BPP && defined(UNCOMP) && UNCOMP != 0
|
||||
#if UNCOMP > 0
|
||||
#define UncompressCPixel(pointer) ((*(CARDBPP *)pointer) >> UNCOMP)
|
||||
#else
|
||||
#define UncompressCPixel(pointer) ((*(CARDBPP *)pointer) << (-(UNCOMP)))
|
||||
#endif
|
||||
#else
|
||||
#define UncompressCPixel(pointer) (*(CARDBPP *)pointer)
|
||||
#endif
|
||||
|
||||
static rfbBool HandleTRLE(rfbClient *client, int rx, int ry, int rw, int rh) {
|
||||
int x, y, w, h;
|
||||
uint8_t type, last_type = 0;
|
||||
int min_buffer_size = 16 * 16 * (REALBPP / 8) * 2;
|
||||
uint8_t *buffer;
|
||||
CARDBPP palette[128];
|
||||
int bpp = 0, mask = 0, divider = 0;
|
||||
CARDBPP color = 0;
|
||||
|
||||
/* First make sure we have a large enough raw buffer to hold the
|
||||
* decompressed data. In practice, with a fixed REALBPP, fixed frame
|
||||
* buffer size and the first update containing the entire frame
|
||||
* buffer, this buffer allocation should only happen once, on the
|
||||
* first update.
|
||||
*/
|
||||
if (client->raw_buffer_size < min_buffer_size) {
|
||||
|
||||
if (client->raw_buffer != NULL) {
|
||||
|
||||
free(client->raw_buffer);
|
||||
}
|
||||
|
||||
client->raw_buffer_size = min_buffer_size;
|
||||
client->raw_buffer = (char *)malloc(client->raw_buffer_size);
|
||||
}
|
||||
|
||||
rfbClientLog("Update %d %d %d %d\n", rx, ry, rw, rh);
|
||||
|
||||
for (y = ry; y < ry + rh; y += 16) {
|
||||
for (x = rx; x < rx + rw; x += 16) {
|
||||
w = h = 16;
|
||||
if (rx + rw - x < 16)
|
||||
w = rx + rw - x;
|
||||
if (ry + rh - y < 16)
|
||||
h = ry + rh - y;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)(&type), 1))
|
||||
return FALSE;
|
||||
|
||||
buffer = (uint8_t*)(client->raw_buffer);
|
||||
|
||||
switch (type) {
|
||||
case 0: {
|
||||
if (!ReadFromRFBServer(client, (char *)buffer, w * h * REALBPP / 8))
|
||||
return FALSE;
|
||||
#if REALBPP != BPP
|
||||
int i, j;
|
||||
|
||||
for (j = y * client->width; j < (y + h) * client->width;
|
||||
j += client->width)
|
||||
for (i = x; i < x + w; i++, buffer += REALBPP / 8)
|
||||
((CARDBPP *)client->frameBuffer)[j + i] = UncompressCPixel(buffer);
|
||||
#else
|
||||
client->GotBitmap(client, buffer, x, y, w, h);
|
||||
#endif
|
||||
type = last_type;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (!ReadFromRFBServer(client, (char *)buffer, REALBPP / 8))
|
||||
return FALSE;
|
||||
|
||||
color = UncompressCPixel(buffer);
|
||||
|
||||
client->GotFillRect(client, x, y, w, h, color);
|
||||
|
||||
last_type = type;
|
||||
break;
|
||||
}
|
||||
case_127:
|
||||
case 127:
|
||||
switch (last_type) {
|
||||
case 0:
|
||||
return FALSE;
|
||||
case 1:
|
||||
client->GotFillRect(client, x, y, w, h, color);
|
||||
type = last_type;
|
||||
break;
|
||||
case 128:
|
||||
return FALSE;
|
||||
default:
|
||||
if (last_type >= 130) {
|
||||
last_type = last_type & 0x7f;
|
||||
|
||||
bpp = (last_type > 4 ? (last_type > 16 ? 8 : 4)
|
||||
: (last_type > 2 ? 2 : 1)),
|
||||
mask = (1 << bpp) - 1, divider = (8 / bpp);
|
||||
}
|
||||
if (last_type <= 16) {
|
||||
int i, j, shift;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)buffer,
|
||||
(w + divider - 1) / divider * h))
|
||||
return FALSE;
|
||||
|
||||
/* read palettized pixels */
|
||||
for (j = y * client->width; j < (y + h) * client->width;
|
||||
j += client->width) {
|
||||
for (i = x, shift = 8 - bpp; i < x + w; i++) {
|
||||
((CARDBPP *)client->frameBuffer)[j + i] =
|
||||
palette[((*buffer) >> shift) & mask];
|
||||
shift -= bpp;
|
||||
if (shift < 0) {
|
||||
shift = 8 - bpp;
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
if (shift < 8 - bpp)
|
||||
buffer++;
|
||||
|
||||
type = last_type;
|
||||
}
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 128: {
|
||||
int i = 0, j = 0;
|
||||
while (j < h) {
|
||||
int color, length, buffer_pos = 0;
|
||||
/* read color */
|
||||
if (!ReadFromRFBServer(client, (char*)buffer, REALBPP / 8 + 1))
|
||||
return FALSE;
|
||||
color = UncompressCPixel(buffer);
|
||||
buffer += REALBPP / 8;
|
||||
buffer_pos += REALBPP / 8;
|
||||
/* read run length */
|
||||
length = 1;
|
||||
while (*buffer == 0xff && buffer_pos < client->raw_buffer_size-1) {
|
||||
if (!ReadFromRFBServer(client, (char*)buffer + 1, 1))
|
||||
return FALSE;
|
||||
length += *buffer;
|
||||
buffer++;
|
||||
buffer_pos++;
|
||||
}
|
||||
length += *buffer;
|
||||
buffer++;
|
||||
while (j < h && length > 0) {
|
||||
((CARDBPP *)client->frameBuffer)[(y + j) * client->width + x + i] =
|
||||
color;
|
||||
length--;
|
||||
i++;
|
||||
if (i >= w) {
|
||||
i = 0;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (length > 0)
|
||||
rfbClientLog("Warning: possible TRLE corruption\n");
|
||||
}
|
||||
|
||||
type = last_type;
|
||||
|
||||
break;
|
||||
}
|
||||
case_129:
|
||||
case 129: {
|
||||
int i, j;
|
||||
/* read palettized pixels */
|
||||
i = j = 0;
|
||||
while (j < h) {
|
||||
int color, length, buffer_pos = 0;
|
||||
/* read color */
|
||||
if (!ReadFromRFBServer(client, (char *)buffer, 1))
|
||||
return FALSE;
|
||||
color = palette[(*buffer) & 0x7f];
|
||||
length = 1;
|
||||
if (*buffer & 0x80) {
|
||||
if (!ReadFromRFBServer(client, (char *)buffer + 1, 1))
|
||||
return FALSE;
|
||||
buffer++;
|
||||
buffer_pos++;
|
||||
/* read run length */
|
||||
while (*buffer == 0xff && buffer_pos < client->raw_buffer_size-1) {
|
||||
if (!ReadFromRFBServer(client, (char *)buffer + 1, 1))
|
||||
return FALSE;
|
||||
length += *buffer;
|
||||
buffer++;
|
||||
buffer_pos++;
|
||||
}
|
||||
length += *buffer;
|
||||
}
|
||||
buffer++;
|
||||
while (j < h && length > 0) {
|
||||
((CARDBPP *)client->frameBuffer)[(y + j) * client->width + x + i] =
|
||||
color;
|
||||
length--;
|
||||
i++;
|
||||
if (i >= w) {
|
||||
i = 0;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (length > 0)
|
||||
rfbClientLog("Warning: possible TRLE corruption\n");
|
||||
}
|
||||
|
||||
if (type == 129) {
|
||||
type = last_type;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (type <= 16) {
|
||||
int i;
|
||||
|
||||
bpp = (type > 4 ? 4 : (type > 2 ? 2 : 1)),
|
||||
mask = (1 << bpp) - 1, divider = (8 / bpp);
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)buffer, type * REALBPP / 8))
|
||||
return FALSE;
|
||||
|
||||
/* read palette */
|
||||
for (i = 0; i < type; i++, buffer += REALBPP / 8)
|
||||
palette[i] = UncompressCPixel(buffer);
|
||||
|
||||
last_type = type;
|
||||
goto case_127;
|
||||
} else if (type >= 130) {
|
||||
int i;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)buffer, (type - 128) * REALBPP / 8))
|
||||
return FALSE;
|
||||
|
||||
/* read palette */
|
||||
for (i = 0; i < type - 128; i++, buffer += REALBPP / 8)
|
||||
palette[i] = UncompressCPixel(buffer);
|
||||
|
||||
last_type = type;
|
||||
goto case_129;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
last_type = type;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
||||
#undef CARDREALBPP
|
||||
#undef HandleTRLE
|
||||
#undef UncompressCPixel
|
||||
#undef REALBPP
|
||||
#undef UNCOMP
|
||||
224
android/extern/libvncserver/src/libvncclient/ultra.c
vendored
Normal file
224
android/extern/libvncserver/src/libvncclient/ultra.c
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ultrazip.c - handle ultrazip encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles an zlib
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleUltraZipBPP CONCAT2E(HandleUltraZip,BPP)
|
||||
#define HandleUltraBPP CONCAT2E(HandleUltra,BPP)
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
|
||||
static rfbBool
|
||||
HandleUltraBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbZlibHeader hdr;
|
||||
int toRead=0;
|
||||
int inflateResult=0;
|
||||
lzo_uint uncompressedBytes = (( rw * rh ) * ( BPP / 8 ));
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader))
|
||||
return FALSE;
|
||||
|
||||
toRead = rfbClientSwap32IfLE(hdr.nBytes);
|
||||
if (toRead==0) return TRUE;
|
||||
|
||||
if (toRead < 0) {
|
||||
rfbClientErr("ultra error: remote sent negative payload size\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (uncompressedBytes==0)
|
||||
{
|
||||
rfbClientLog("ultra error: rectangle has 0 uncomressed bytes ((%dw * %dh) * (%d / 8))\n", rw, rh, BPP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* First make sure we have a large enough raw buffer to hold the
|
||||
* decompressed data. In practice, with a fixed BPP, fixed frame
|
||||
* buffer size and the first update containing the entire frame
|
||||
* buffer, this buffer allocation should only happen once, on the
|
||||
* first update.
|
||||
*/
|
||||
if ( client->raw_buffer_size < (int)uncompressedBytes) {
|
||||
if ( client->raw_buffer != NULL ) {
|
||||
free( client->raw_buffer );
|
||||
}
|
||||
client->raw_buffer_size = uncompressedBytes;
|
||||
/* buffer needs to be aligned on 4-byte boundaries */
|
||||
if ((client->raw_buffer_size % 4)!=0)
|
||||
client->raw_buffer_size += (4-(client->raw_buffer_size % 4));
|
||||
client->raw_buffer = (char*) malloc( client->raw_buffer_size );
|
||||
if(client->raw_buffer == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* allocate enough space to store the incoming compressed packet */
|
||||
if ( client->ultra_buffer_size < toRead ) {
|
||||
if ( client->ultra_buffer != NULL ) {
|
||||
free( client->ultra_buffer );
|
||||
}
|
||||
client->ultra_buffer_size = toRead;
|
||||
/* buffer needs to be aligned on 4-byte boundaries */
|
||||
if ((client->ultra_buffer_size % 4)!=0)
|
||||
client->ultra_buffer_size += (4-(client->ultra_buffer_size % 4));
|
||||
client->ultra_buffer = (char*) malloc( client->ultra_buffer_size );
|
||||
}
|
||||
|
||||
/* Fill the buffer, obtaining data from the server. */
|
||||
if (!ReadFromRFBServer(client, client->ultra_buffer, toRead))
|
||||
return FALSE;
|
||||
|
||||
/* uncompress the data */
|
||||
uncompressedBytes = client->raw_buffer_size;
|
||||
inflateResult = lzo1x_decompress_safe(
|
||||
(lzo_byte *)client->ultra_buffer, toRead,
|
||||
(lzo_byte *)client->raw_buffer, (lzo_uintp) &uncompressedBytes,
|
||||
NULL);
|
||||
|
||||
/* Note that uncompressedBytes will be 0 on output overrun */
|
||||
if ((rw * rh * (BPP / 8)) != uncompressedBytes)
|
||||
rfbClientLog("Ultra decompressed unexpected amount of data (%d != %d)\n", (rw * rh * (BPP / 8)), uncompressedBytes);
|
||||
|
||||
/* Put the uncompressed contents of the update on the screen. */
|
||||
if ( inflateResult == LZO_E_OK )
|
||||
{
|
||||
client->GotBitmap(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh);
|
||||
}
|
||||
else
|
||||
{
|
||||
rfbClientLog("ultra decompress returned error: %d\n",
|
||||
inflateResult);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* UltraZip is like rre in that it is composed of subrects */
|
||||
static rfbBool
|
||||
HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbZlibHeader hdr;
|
||||
int i=0;
|
||||
int toRead=0;
|
||||
int inflateResult=0;
|
||||
unsigned char *ptr=NULL;
|
||||
lzo_uint uncompressedBytes = ry + (rw * 65535);
|
||||
unsigned int numCacheRects = rx;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader))
|
||||
return FALSE;
|
||||
|
||||
toRead = rfbClientSwap32IfLE(hdr.nBytes);
|
||||
|
||||
if (toRead==0) return TRUE;
|
||||
|
||||
if (toRead < 0) {
|
||||
rfbClientErr("ultrazip error: remote sent negative payload size\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (uncompressedBytes==0)
|
||||
{
|
||||
rfbClientLog("ultrazip error: rectangle has 0 uncomressed bytes (%dy + (%dw * 65535)) (%d rectangles)\n", ry, rw, rx);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* First make sure we have a large enough raw buffer to hold the
|
||||
* decompressed data. In practice, with a fixed BPP, fixed frame
|
||||
* buffer size and the first update containing the entire frame
|
||||
* buffer, this buffer allocation should only happen once, on the
|
||||
* first update.
|
||||
*/
|
||||
if ( client->raw_buffer_size < (int)(uncompressedBytes + 500)) {
|
||||
if ( client->raw_buffer != NULL ) {
|
||||
free( client->raw_buffer );
|
||||
}
|
||||
client->raw_buffer_size = uncompressedBytes + 500;
|
||||
/* buffer needs to be aligned on 4-byte boundaries */
|
||||
if ((client->raw_buffer_size % 4)!=0)
|
||||
client->raw_buffer_size += (4-(client->raw_buffer_size % 4));
|
||||
client->raw_buffer = (char*) malloc( client->raw_buffer_size );
|
||||
if(client->raw_buffer == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* allocate enough space to store the incoming compressed packet */
|
||||
if ( client->ultra_buffer_size < toRead ) {
|
||||
if ( client->ultra_buffer != NULL ) {
|
||||
free( client->ultra_buffer );
|
||||
}
|
||||
client->ultra_buffer_size = toRead;
|
||||
client->ultra_buffer = (char*) malloc( client->ultra_buffer_size );
|
||||
}
|
||||
|
||||
/* Fill the buffer, obtaining data from the server. */
|
||||
if (!ReadFromRFBServer(client, client->ultra_buffer, toRead))
|
||||
return FALSE;
|
||||
|
||||
/* uncompress the data */
|
||||
uncompressedBytes = client->raw_buffer_size;
|
||||
inflateResult = lzo1x_decompress_safe(
|
||||
(lzo_byte *)client->ultra_buffer, toRead,
|
||||
(lzo_byte *)client->raw_buffer, &uncompressedBytes, NULL);
|
||||
if ( inflateResult != LZO_E_OK )
|
||||
{
|
||||
rfbClientLog("ultra decompress returned error: %d\n",
|
||||
inflateResult);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Put the uncompressed contents of the update on the screen. */
|
||||
ptr = (unsigned char *)client->raw_buffer;
|
||||
for (i=0; i<numCacheRects; i++)
|
||||
{
|
||||
unsigned short sx, sy, sw, sh;
|
||||
unsigned int se;
|
||||
|
||||
memcpy((char *)&sx, ptr, 2); ptr += 2;
|
||||
memcpy((char *)&sy, ptr, 2); ptr += 2;
|
||||
memcpy((char *)&sw, ptr, 2); ptr += 2;
|
||||
memcpy((char *)&sh, ptr, 2); ptr += 2;
|
||||
memcpy((char *)&se, ptr, 4); ptr += 4;
|
||||
|
||||
sx = rfbClientSwap16IfLE(sx);
|
||||
sy = rfbClientSwap16IfLE(sy);
|
||||
sw = rfbClientSwap16IfLE(sw);
|
||||
sh = rfbClientSwap16IfLE(sh);
|
||||
se = rfbClientSwap32IfLE(se);
|
||||
|
||||
if (se == rfbEncodingRaw)
|
||||
{
|
||||
client->GotBitmap(client, (unsigned char *)ptr, sx, sy, sw, sh);
|
||||
ptr += ((sw * sh) * (BPP / 8));
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
||||
589
android/extern/libvncserver/src/libvncclient/vncviewer.c
vendored
Normal file
589
android/extern/libvncserver/src/libvncclient/vncviewer.c
vendored
Normal file
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* vncviewer.c - the Xt-based VNC viewer.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strdup _strdup /* Prevent POSIX deprecation warnings */
|
||||
#endif
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#define _POSIX_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
#include "tls.h"
|
||||
#if defined(LIBVNCSERVER_HAVE_LIBZ) && defined(LIBVNCSERVER_HAVE_LIBJPEG)
|
||||
#include "turbojpeg.h"
|
||||
#endif
|
||||
|
||||
static void Dummy(rfbClient* client) {
|
||||
}
|
||||
static rfbBool DummyPoint(rfbClient* client, int x, int y) {
|
||||
return TRUE;
|
||||
}
|
||||
static void DummyRect(rfbClient* client, int x, int y, int w, int h) {
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
static char* ReadPassword(rfbClient* client) {
|
||||
int i;
|
||||
char* p=calloc(1,9);
|
||||
if (!p) return p;
|
||||
#ifndef WIN32
|
||||
struct termios save,noecho;
|
||||
if(tcgetattr(fileno(stdin),&save)!=0) return p;
|
||||
noecho=save; noecho.c_lflag &= ~ECHO;
|
||||
if(tcsetattr(fileno(stdin),TCSAFLUSH,&noecho)!=0) return p;
|
||||
#endif
|
||||
fprintf(stderr,"Password: ");
|
||||
fflush(stderr);
|
||||
i=0;
|
||||
while(1) {
|
||||
int c=fgetc(stdin);
|
||||
if(c=='\n')
|
||||
break;
|
||||
if(i<8) {
|
||||
p[i]=c;
|
||||
i++;
|
||||
p[i]=0;
|
||||
}
|
||||
}
|
||||
#ifndef WIN32
|
||||
tcsetattr(fileno(stdin),TCSAFLUSH,&save);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
static rfbBool MallocFrameBuffer(rfbClient* client) {
|
||||
uint64_t allocSize;
|
||||
|
||||
if(client->frameBuffer) {
|
||||
free(client->frameBuffer);
|
||||
client->frameBuffer = NULL;
|
||||
}
|
||||
|
||||
/* SECURITY: promote 'width' into uint64_t so that the multiplication does not overflow
|
||||
'width' and 'height' are 16-bit integers per RFB protocol design
|
||||
SIZE_MAX is the maximum value that can fit into size_t
|
||||
*/
|
||||
allocSize = (uint64_t)client->width * client->height * client->format.bitsPerPixel/8;
|
||||
|
||||
if (allocSize >= SIZE_MAX) {
|
||||
rfbClientErr("CRITICAL: cannot allocate frameBuffer, requested size is too large\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
client->frameBuffer=malloc( (size_t)allocSize );
|
||||
|
||||
if (client->frameBuffer == NULL)
|
||||
rfbClientErr("CRITICAL: frameBuffer allocation failed, requested size too large or not enough memory?\n");
|
||||
|
||||
return client->frameBuffer?TRUE:FALSE;
|
||||
}
|
||||
|
||||
/* messages */
|
||||
|
||||
static rfbBool CheckRect(rfbClient* client, int x, int y, int w, int h) {
|
||||
return x + w <= client->width && y + h <= client->height;
|
||||
}
|
||||
|
||||
static void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) {
|
||||
int i,j;
|
||||
|
||||
if (client->frameBuffer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckRect(client, x, y, w, h)) {
|
||||
rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
#define FILL_RECT(BPP) \
|
||||
for(j=y*client->width;j<(y+h)*client->width;j+=client->width) \
|
||||
for(i=x;i<x+w;i++) \
|
||||
((uint##BPP##_t*)client->frameBuffer)[j+i]=colour;
|
||||
|
||||
switch(client->format.bitsPerPixel) {
|
||||
case 8: FILL_RECT(8); break;
|
||||
case 16: FILL_RECT(16); break;
|
||||
case 32: FILL_RECT(32); break;
|
||||
default:
|
||||
rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
static void CopyRectangle(rfbClient* client, const uint8_t* buffer, int x, int y, int w, int h) {
|
||||
int j;
|
||||
|
||||
if (client->frameBuffer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckRect(client, x, y, w, h)) {
|
||||
rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
#define COPY_RECT(BPP) \
|
||||
{ \
|
||||
int rs = w * BPP / 8, rs2 = client->width * BPP / 8; \
|
||||
for (j = ((x * (BPP / 8)) + (y * rs2)); j < (y + h) * rs2; j += rs2) { \
|
||||
memcpy(client->frameBuffer + j, buffer, rs); \
|
||||
buffer += rs; \
|
||||
} \
|
||||
}
|
||||
|
||||
switch(client->format.bitsPerPixel) {
|
||||
case 8: COPY_RECT(8); break;
|
||||
case 16: COPY_RECT(16); break;
|
||||
case 32: COPY_RECT(32); break;
|
||||
default:
|
||||
rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: test */
|
||||
static void CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
|
||||
int i,j;
|
||||
|
||||
if (client->frameBuffer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckRect(client, src_x, src_y, w, h)) {
|
||||
rfbClientLog("Source rect out of bounds: %dx%d at (%d, %d)\n", src_x, src_y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckRect(client, dest_x, dest_y, w, h)) {
|
||||
rfbClientLog("Dest rect out of bounds: %dx%d at (%d, %d)\n", dest_x, dest_y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
#define COPY_RECT_FROM_RECT(BPP) \
|
||||
{ \
|
||||
uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \
|
||||
if (dest_y < src_y) { \
|
||||
for(j = dest_y*client->width; j < (dest_y+h)*client->width; j += client->width) { \
|
||||
if (dest_x < src_x) { \
|
||||
for(i = dest_x; i < dest_x+w; i++) { \
|
||||
((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
|
||||
} \
|
||||
} else { \
|
||||
for(i = dest_x+w-1; i >= dest_x; i--) { \
|
||||
((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
for(j = (dest_y+h-1)*client->width; j >= dest_y*client->width; j-=client->width) { \
|
||||
if (dest_x < src_x) { \
|
||||
for(i = dest_x; i < dest_x+w; i++) { \
|
||||
((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
|
||||
} \
|
||||
} else { \
|
||||
for(i = dest_x+w-1; i >= dest_x; i--) { \
|
||||
((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
switch(client->format.bitsPerPixel) {
|
||||
case 8: COPY_RECT_FROM_RECT(8); break;
|
||||
case 16: COPY_RECT_FROM_RECT(16); break;
|
||||
case 32: COPY_RECT_FROM_RECT(32); break;
|
||||
default:
|
||||
rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
static void initAppData(AppData* data) {
|
||||
data->shareDesktop=TRUE;
|
||||
data->viewOnly=FALSE;
|
||||
data->encodingsString="tight zrle ultra copyrect hextile zlib corre rre raw";
|
||||
data->useBGR233=FALSE;
|
||||
data->nColours=0;
|
||||
data->forceOwnCmap=FALSE;
|
||||
data->forceTrueColour=FALSE;
|
||||
data->requestedDepth=0;
|
||||
data->compressLevel=3;
|
||||
data->qualityLevel=5;
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
|
||||
data->enableJPEG=TRUE;
|
||||
#else
|
||||
data->enableJPEG=FALSE;
|
||||
#endif
|
||||
data->useRemoteCursor=FALSE;
|
||||
}
|
||||
|
||||
rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel,
|
||||
int bytesPerPixel) {
|
||||
#ifdef WIN32
|
||||
WSADATA unused;
|
||||
#endif
|
||||
rfbClient* client=(rfbClient*)calloc(sizeof(rfbClient),1);
|
||||
if(!client) {
|
||||
rfbClientErr("Couldn't allocate client structure!\n");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef WIN32
|
||||
if((errno = WSAStartup(MAKEWORD(2,0), &unused)) != 0) {
|
||||
rfbClientErr("Could not init Windows Sockets: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
initAppData(&client->appData);
|
||||
client->endianTest = 1;
|
||||
client->programName="";
|
||||
client->serverHost=strdup("");
|
||||
client->serverPort=5900;
|
||||
|
||||
client->destHost = NULL;
|
||||
client->destPort = 5900;
|
||||
|
||||
client->connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
client->readTimeout = DEFAULT_READ_TIMEOUT;
|
||||
|
||||
/* default: use complete frame buffer */
|
||||
client->updateRect.x = -1;
|
||||
|
||||
client->frameBuffer = NULL;
|
||||
client->outputWindow = 0;
|
||||
|
||||
client->format.bitsPerPixel = bytesPerPixel*8;
|
||||
client->format.depth = bitsPerSample*samplesPerPixel;
|
||||
client->appData.requestedDepth=client->format.depth;
|
||||
client->format.bigEndian = *(char *)&client->endianTest?FALSE:TRUE;
|
||||
client->format.trueColour = 1;
|
||||
|
||||
if (client->format.bitsPerPixel == 8) {
|
||||
client->format.redMax = 7;
|
||||
client->format.greenMax = 7;
|
||||
client->format.blueMax = 3;
|
||||
client->format.redShift = 0;
|
||||
client->format.greenShift = 3;
|
||||
client->format.blueShift = 6;
|
||||
} else {
|
||||
client->format.redMax = (1 << bitsPerSample) - 1;
|
||||
client->format.greenMax = (1 << bitsPerSample) - 1;
|
||||
client->format.blueMax = (1 << bitsPerSample) - 1;
|
||||
if(!client->format.bigEndian) {
|
||||
client->format.redShift = 0;
|
||||
client->format.greenShift = bitsPerSample;
|
||||
client->format.blueShift = bitsPerSample * 2;
|
||||
} else {
|
||||
if(client->format.bitsPerPixel==8*3) {
|
||||
client->format.redShift = bitsPerSample*2;
|
||||
client->format.greenShift = bitsPerSample*1;
|
||||
client->format.blueShift = 0;
|
||||
} else {
|
||||
client->format.redShift = bitsPerSample*3;
|
||||
client->format.greenShift = bitsPerSample*2;
|
||||
client->format.blueShift = bitsPerSample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client->bufoutptr=client->buf;
|
||||
client->buffered=0;
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||||
client->raw_buffer_size = -1;
|
||||
client->decompStreamInited = FALSE;
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
|
||||
memset(client->zlibStreamActive,0,sizeof(rfbBool)*4);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
client->HandleCursorPos = DummyPoint;
|
||||
client->SoftCursorLockArea = DummyRect;
|
||||
client->SoftCursorUnlockScreen = Dummy;
|
||||
client->GotFrameBufferUpdate = DummyRect;
|
||||
client->GotCopyRect = CopyRectangleFromRectangle;
|
||||
client->GotFillRect = FillRectangle;
|
||||
client->GotBitmap = CopyRectangle;
|
||||
client->FinishedFrameBufferUpdate = NULL;
|
||||
client->GetPassword = ReadPassword;
|
||||
client->MallocFrameBuffer = MallocFrameBuffer;
|
||||
client->Bell = Dummy;
|
||||
client->CurrentKeyboardLedState = 0;
|
||||
client->HandleKeyboardLedState = (HandleKeyboardLedStateProc)DummyPoint;
|
||||
client->QoS_DSCP = 0;
|
||||
|
||||
client->authScheme = 0;
|
||||
client->subAuthScheme = 0;
|
||||
client->GetCredential = NULL;
|
||||
client->tlsSession = NULL;
|
||||
client->LockWriteToTLS = NULL;
|
||||
client->UnlockWriteToTLS = NULL;
|
||||
client->sock = RFB_INVALID_SOCKET;
|
||||
client->listenSock = RFB_INVALID_SOCKET;
|
||||
client->listenAddress = NULL;
|
||||
client->listen6Sock = RFB_INVALID_SOCKET;
|
||||
client->listen6Address = NULL;
|
||||
client->clientAuthSchemes = NULL;
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
client->GetSASLMechanism = NULL;
|
||||
client->GetUser = NULL;
|
||||
client->saslSecret = NULL;
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
client->requestedResize = FALSE;
|
||||
client->screen.width = 0;
|
||||
client->screen.height = 0;
|
||||
|
||||
client->automaticUpdateRequests = TRUE;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
static rfbBool rfbInitConnection(rfbClient* client)
|
||||
{
|
||||
/* Unless we accepted an incoming connection, make a TCP connection to the
|
||||
given VNC server */
|
||||
|
||||
if (!client->listenSpecified) {
|
||||
if (!client->serverHost)
|
||||
return FALSE;
|
||||
if (client->destHost) {
|
||||
if (!ConnectToRFBRepeater(client,client->serverHost,client->serverPort,client->destHost,client->destPort))
|
||||
return FALSE;
|
||||
} else {
|
||||
if (!ConnectToRFBServer(client,client->serverHost,client->serverPort))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise the VNC connection, including reading the password */
|
||||
|
||||
if (!InitialiseRFBConnection(client))
|
||||
return FALSE;
|
||||
|
||||
client->width=client->si.framebufferWidth;
|
||||
client->height=client->si.framebufferHeight;
|
||||
if (!client->MallocFrameBuffer(client))
|
||||
return FALSE;
|
||||
|
||||
if (!SetFormatAndEncodings(client))
|
||||
return FALSE;
|
||||
|
||||
if (client->updateRect.x < 0) {
|
||||
client->updateRect.x = client->updateRect.y = 0;
|
||||
client->updateRect.w = client->width;
|
||||
client->updateRect.h = client->height;
|
||||
}
|
||||
|
||||
if (client->appData.scaleSetting>1)
|
||||
{
|
||||
if (!SendScaleSetting(client, client->appData.scaleSetting))
|
||||
return FALSE;
|
||||
if (!SendFramebufferUpdateRequest(client,
|
||||
client->updateRect.x / client->appData.scaleSetting,
|
||||
client->updateRect.y / client->appData.scaleSetting,
|
||||
client->updateRect.w / client->appData.scaleSetting,
|
||||
client->updateRect.h / client->appData.scaleSetting,
|
||||
FALSE))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!SendFramebufferUpdateRequest(client,
|
||||
client->updateRect.x, client->updateRect.y,
|
||||
client->updateRect.w, client->updateRect.h,
|
||||
FALSE))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rfbBool rfbInitClient(rfbClient* client,int* argc,char** argv) {
|
||||
int i,j;
|
||||
|
||||
if(argv && argc && *argc) {
|
||||
if(client->programName==0)
|
||||
client->programName=argv[0];
|
||||
|
||||
for (i = 1; i < *argc; i++) {
|
||||
j = i;
|
||||
if (strcmp(argv[i], "-listen") == 0) {
|
||||
listenForIncomingConnections(client);
|
||||
break;
|
||||
} else if (strcmp(argv[i], "-listennofork") == 0) {
|
||||
listenForIncomingConnectionsNoFork(client, -1);
|
||||
break;
|
||||
} else if (strcmp(argv[i], "-play") == 0) {
|
||||
client->serverPort = -1;
|
||||
j++;
|
||||
} else if (i+1<*argc && strcmp(argv[i], "-encodings") == 0) {
|
||||
client->appData.encodingsString = argv[i+1];
|
||||
j+=2;
|
||||
} else if (i+1<*argc && strcmp(argv[i], "-compress") == 0) {
|
||||
client->appData.compressLevel = atoi(argv[i+1]);
|
||||
j+=2;
|
||||
} else if (i+1<*argc && strcmp(argv[i], "-quality") == 0) {
|
||||
client->appData.qualityLevel = atoi(argv[i+1]);
|
||||
j+=2;
|
||||
} else if (i+1<*argc && strcmp(argv[i], "-scale") == 0) {
|
||||
client->appData.scaleSetting = atoi(argv[i+1]);
|
||||
j+=2;
|
||||
} else if (i+1<*argc && strcmp(argv[i], "-qosdscp") == 0) {
|
||||
client->QoS_DSCP = atoi(argv[i+1]);
|
||||
j+=2;
|
||||
} else if (i+1<*argc && strcmp(argv[i], "-repeaterdest") == 0) {
|
||||
char* colon=strchr(argv[i+1],':');
|
||||
|
||||
if(client->destHost)
|
||||
free(client->destHost);
|
||||
client->destPort = 5900;
|
||||
|
||||
client->destHost = strdup(argv[i+1]);
|
||||
if(client->destHost && colon) {
|
||||
client->destHost[(int)(colon-argv[i+1])] = '\0';
|
||||
client->destPort = atoi(colon+1);
|
||||
}
|
||||
j+=2;
|
||||
} else {
|
||||
char* colon=strrchr(argv[i],':');
|
||||
|
||||
if(client->serverHost)
|
||||
free(client->serverHost);
|
||||
|
||||
if(colon) {
|
||||
client->serverHost = strdup(argv[i]);
|
||||
if(client->serverHost) {
|
||||
client->serverHost[(int)(colon-argv[i])] = '\0';
|
||||
client->serverPort = atoi(colon+1);
|
||||
}
|
||||
} else {
|
||||
client->serverHost = strdup(argv[i]);
|
||||
}
|
||||
if(client->serverPort >= 0 && client->serverPort < 5900)
|
||||
client->serverPort += 5900;
|
||||
}
|
||||
/* purge arguments */
|
||||
if (j>i) {
|
||||
*argc-=j-i;
|
||||
memmove(argv+i,argv+j,(*argc-i)*sizeof(char*));
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!rfbInitConnection(client)) {
|
||||
//cleanup should not happen silently
|
||||
//rfbClientCleanup(client);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void rfbClientCleanup(rfbClient* client) {
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < 4; i++ ) {
|
||||
if (client->zlibStreamActive[i] == TRUE ) {
|
||||
if (inflateEnd (&client->zlibStream[i]) != Z_OK &&
|
||||
client->zlibStream[i].msg != NULL)
|
||||
rfbClientLog("inflateEnd: %s\n", client->zlibStream[i].msg);
|
||||
}
|
||||
}
|
||||
|
||||
if ( client->decompStreamInited == TRUE ) {
|
||||
if (inflateEnd (&client->decompStream) != Z_OK &&
|
||||
client->decompStream.msg != NULL)
|
||||
rfbClientLog("inflateEnd: %s\n", client->decompStream.msg );
|
||||
}
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
|
||||
if(client->tjhnd){
|
||||
tjDestroy(client->tjhnd);
|
||||
client->tjhnd = NULL;
|
||||
}
|
||||
#endif /* LIBVNCSERVER_HAVE_LIBJPEG */
|
||||
#endif
|
||||
|
||||
if (client->ultra_buffer)
|
||||
free(client->ultra_buffer);
|
||||
|
||||
if (client->raw_buffer)
|
||||
free(client->raw_buffer);
|
||||
|
||||
FreeTLS(client);
|
||||
|
||||
while (client->clientData) {
|
||||
rfbClientData* next = client->clientData->next;
|
||||
free(client->clientData);
|
||||
client->clientData = next;
|
||||
}
|
||||
|
||||
if(client->vncRec)
|
||||
free(client->vncRec);
|
||||
|
||||
if (client->sock != RFB_INVALID_SOCKET)
|
||||
rfbCloseSocket(client->sock);
|
||||
if (client->listenSock != RFB_INVALID_SOCKET)
|
||||
rfbCloseSocket(client->listenSock);
|
||||
free(client->desktopName);
|
||||
free(client->serverHost);
|
||||
if (client->destHost)
|
||||
free(client->destHost);
|
||||
if (client->clientAuthSchemes)
|
||||
free(client->clientAuthSchemes);
|
||||
if(client->rcSource)
|
||||
free(client->rcSource);
|
||||
if(client->rcMask)
|
||||
free(client->rcMask);
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
if (client->saslSecret)
|
||||
free(client->saslSecret);
|
||||
if (client->saslconn)
|
||||
sasl_dispose(&client->saslconn);
|
||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
||||
|
||||
#ifdef WIN32
|
||||
if(WSACleanup() != 0) {
|
||||
errno=WSAGetLastError();
|
||||
rfbClientErr("Could not terminate Windows Sockets: %s\n", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
free(client);
|
||||
}
|
||||
162
android/extern/libvncserver/src/libvncclient/zlib.c
vendored
Normal file
162
android/extern/libvncserver/src/libvncclient/zlib.c
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||||
|
||||
/*
|
||||
* zlib.c - handle zlib encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles an zlib
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleZlibBPP CONCAT2E(HandleZlib,BPP)
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
|
||||
static rfbBool
|
||||
HandleZlibBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbZlibHeader hdr;
|
||||
int remaining;
|
||||
int inflateResult;
|
||||
int toRead;
|
||||
|
||||
/* First make sure we have a large enough raw buffer to hold the
|
||||
* decompressed data. In practice, with a fixed BPP, fixed frame
|
||||
* buffer size and the first update containing the entire frame
|
||||
* buffer, this buffer allocation should only happen once, on the
|
||||
* first update.
|
||||
*/
|
||||
if ( client->raw_buffer_size < (( rw * rh ) * ( BPP / 8 ))) {
|
||||
|
||||
if ( client->raw_buffer != NULL ) {
|
||||
|
||||
free( client->raw_buffer );
|
||||
|
||||
}
|
||||
|
||||
client->raw_buffer_size = (( rw * rh ) * ( BPP / 8 ));
|
||||
client->raw_buffer = (char*) malloc( client->raw_buffer_size );
|
||||
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader))
|
||||
return FALSE;
|
||||
|
||||
remaining = rfbClientSwap32IfLE(hdr.nBytes);
|
||||
|
||||
/* Need to initialize the decompressor state. */
|
||||
client->decompStream.next_in = ( Bytef * )client->buffer;
|
||||
client->decompStream.avail_in = 0;
|
||||
client->decompStream.next_out = ( Bytef * )client->raw_buffer;
|
||||
client->decompStream.avail_out = client->raw_buffer_size;
|
||||
client->decompStream.data_type = Z_BINARY;
|
||||
|
||||
/* Initialize the decompression stream structures on the first invocation. */
|
||||
if ( client->decompStreamInited == FALSE ) {
|
||||
|
||||
inflateResult = inflateInit( &client->decompStream );
|
||||
|
||||
if ( inflateResult != Z_OK ) {
|
||||
rfbClientLog(
|
||||
"inflateInit returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
client->decompStream.msg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
client->decompStreamInited = TRUE;
|
||||
|
||||
}
|
||||
|
||||
inflateResult = Z_OK;
|
||||
|
||||
/* Process buffer full of data until no more to process, or
|
||||
* some type of inflater error, or Z_STREAM_END.
|
||||
*/
|
||||
while (( remaining > 0 ) &&
|
||||
( inflateResult == Z_OK )) {
|
||||
|
||||
if ( remaining > RFB_BUFFER_SIZE ) {
|
||||
toRead = RFB_BUFFER_SIZE;
|
||||
}
|
||||
else {
|
||||
toRead = remaining;
|
||||
}
|
||||
|
||||
/* Fill the buffer, obtaining data from the server. */
|
||||
if (!ReadFromRFBServer(client, client->buffer,toRead))
|
||||
return FALSE;
|
||||
|
||||
client->decompStream.next_in = ( Bytef * )client->buffer;
|
||||
client->decompStream.avail_in = toRead;
|
||||
|
||||
/* Need to uncompress buffer full. */
|
||||
inflateResult = inflate( &client->decompStream, Z_SYNC_FLUSH );
|
||||
|
||||
/* We never supply a dictionary for compression. */
|
||||
if ( inflateResult == Z_NEED_DICT ) {
|
||||
rfbClientLog("zlib inflate needs a dictionary!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if ( inflateResult < 0 ) {
|
||||
rfbClientLog(
|
||||
"zlib inflate returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
client->decompStream.msg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Result buffer allocated to be at least large enough. We should
|
||||
* never run out of space!
|
||||
*/
|
||||
if (( client->decompStream.avail_in > 0 ) &&
|
||||
( client->decompStream.avail_out <= 0 )) {
|
||||
rfbClientLog("zlib inflate ran out of space!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
remaining -= toRead;
|
||||
|
||||
} /* while ( remaining > 0 ) */
|
||||
|
||||
if ( inflateResult == Z_OK ) {
|
||||
|
||||
/* Put the uncompressed contents of the update on the screen. */
|
||||
client->GotBitmap(client, (uint8_t *)client->raw_buffer, rx, ry, rw, rh);
|
||||
}
|
||||
else {
|
||||
|
||||
rfbClientLog(
|
||||
"zlib inflate returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
client->decompStream.msg);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
||||
|
||||
#endif
|
||||
427
android/extern/libvncserver/src/libvncclient/zrle.c
vendored
Normal file
427
android/extern/libvncserver/src/libvncclient/zrle.c
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Johannes E. Schindelin. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||||
|
||||
/*
|
||||
* zrle.c - handle zrle encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles an zrle
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#ifndef REALBPP
|
||||
#define REALBPP BPP
|
||||
#endif
|
||||
|
||||
#if !defined(UNCOMP) || UNCOMP==0
|
||||
#define HandleZRLE CONCAT2E(HandleZRLE,REALBPP)
|
||||
#define HandleZRLETile CONCAT2E(HandleZRLETile,REALBPP)
|
||||
#elif UNCOMP>0
|
||||
#define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Down)
|
||||
#define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Down)
|
||||
#else
|
||||
#define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Up)
|
||||
#define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Up)
|
||||
#endif
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
#define CARDREALBPP CONCAT3E(uint,REALBPP,_t)
|
||||
|
||||
#define ENDIAN_LITTLE 0
|
||||
#define ENDIAN_BIG 1
|
||||
#define ENDIAN_NO 2
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#undef END_FIX
|
||||
#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
|
||||
# define END_FIX LE
|
||||
#elif ZYWRLE_ENDIAN == ENDIAN_BIG
|
||||
# define END_FIX BE
|
||||
#else
|
||||
# define END_FIX NE
|
||||
#endif
|
||||
#define __RFB_CONCAT3E(a,b,c) CONCAT3E(a,b,c)
|
||||
#define __RFB_CONCAT2E(a,b) CONCAT2E(a,b)
|
||||
#undef CPIXEL
|
||||
#if REALBPP != BPP
|
||||
#if UNCOMP == 0
|
||||
#define CPIXEL REALBPP
|
||||
#elif UNCOMP>0
|
||||
#define CPIXEL CONCAT2E(REALBPP,Down)
|
||||
#else
|
||||
#define CPIXEL CONCAT2E(REALBPP,Up)
|
||||
#endif
|
||||
#endif
|
||||
#define PIXEL_T __RFB_CONCAT3E(uint,BPP,_t)
|
||||
#if BPP!=8
|
||||
#define ZYWRLE_DECODE 1
|
||||
#include "zywrletemplate.c"
|
||||
#endif
|
||||
#undef CPIXEL
|
||||
|
||||
static int HandleZRLETile(rfbClient* client,
|
||||
uint8_t* buffer,size_t buffer_length,
|
||||
int x,int y,int w,int h);
|
||||
|
||||
static rfbBool
|
||||
HandleZRLE (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbZRLEHeader header;
|
||||
int remaining;
|
||||
int inflateResult;
|
||||
int toRead;
|
||||
int min_buffer_size = rw * rh * (REALBPP / 8) * 2;
|
||||
|
||||
/* First make sure we have a large enough raw buffer to hold the
|
||||
* decompressed data. In practice, with a fixed REALBPP, fixed frame
|
||||
* buffer size and the first update containing the entire frame
|
||||
* buffer, this buffer allocation should only happen once, on the
|
||||
* first update.
|
||||
*/
|
||||
if ( client->raw_buffer_size < min_buffer_size) {
|
||||
|
||||
if ( client->raw_buffer != NULL ) {
|
||||
|
||||
free( client->raw_buffer );
|
||||
|
||||
}
|
||||
|
||||
client->raw_buffer_size = min_buffer_size;
|
||||
client->raw_buffer = (char*) malloc( client->raw_buffer_size );
|
||||
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&header, sz_rfbZRLEHeader))
|
||||
return FALSE;
|
||||
|
||||
remaining = rfbClientSwap32IfLE(header.length);
|
||||
|
||||
/* Need to initialize the decompressor state. */
|
||||
client->decompStream.next_in = ( Bytef * )client->buffer;
|
||||
client->decompStream.avail_in = 0;
|
||||
client->decompStream.next_out = ( Bytef * )client->raw_buffer;
|
||||
client->decompStream.avail_out = client->raw_buffer_size;
|
||||
client->decompStream.data_type = Z_BINARY;
|
||||
|
||||
/* Initialize the decompression stream structures on the first invocation. */
|
||||
if ( client->decompStreamInited == FALSE ) {
|
||||
|
||||
inflateResult = inflateInit( &client->decompStream );
|
||||
|
||||
if ( inflateResult != Z_OK ) {
|
||||
rfbClientLog(
|
||||
"inflateInit returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
client->decompStream.msg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
client->decompStreamInited = TRUE;
|
||||
|
||||
}
|
||||
|
||||
inflateResult = Z_OK;
|
||||
|
||||
/* Process buffer full of data until no more to process, or
|
||||
* some type of inflater error, or Z_STREAM_END.
|
||||
*/
|
||||
while (( remaining > 0 ) &&
|
||||
( inflateResult == Z_OK )) {
|
||||
|
||||
if ( remaining > RFB_BUFFER_SIZE ) {
|
||||
toRead = RFB_BUFFER_SIZE;
|
||||
}
|
||||
else {
|
||||
toRead = remaining;
|
||||
}
|
||||
|
||||
/* Fill the buffer, obtaining data from the server. */
|
||||
if (!ReadFromRFBServer(client, client->buffer,toRead))
|
||||
return FALSE;
|
||||
|
||||
client->decompStream.next_in = ( Bytef * )client->buffer;
|
||||
client->decompStream.avail_in = toRead;
|
||||
|
||||
/* Need to uncompress buffer full. */
|
||||
inflateResult = inflate( &client->decompStream, Z_SYNC_FLUSH );
|
||||
|
||||
/* We never supply a dictionary for compression. */
|
||||
if ( inflateResult == Z_NEED_DICT ) {
|
||||
rfbClientLog("zlib inflate needs a dictionary!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if ( inflateResult < 0 ) {
|
||||
rfbClientLog(
|
||||
"zlib inflate returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
client->decompStream.msg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Result buffer allocated to be at least large enough. We should
|
||||
* never run out of space!
|
||||
*/
|
||||
if (( client->decompStream.avail_in > 0 ) &&
|
||||
( client->decompStream.avail_out <= 0 )) {
|
||||
rfbClientLog("zlib inflate ran out of space!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
remaining -= toRead;
|
||||
|
||||
} /* while ( remaining > 0 ) */
|
||||
|
||||
if ( inflateResult == Z_OK ) {
|
||||
char* buf=client->raw_buffer;
|
||||
int i,j;
|
||||
|
||||
remaining = client->raw_buffer_size-client->decompStream.avail_out;
|
||||
|
||||
for(j=0; j<rh; j+=rfbZRLETileHeight)
|
||||
for(i=0; i<rw; i+=rfbZRLETileWidth) {
|
||||
int subWidth=(i+rfbZRLETileWidth>rw)?rw-i:rfbZRLETileWidth;
|
||||
int subHeight=(j+rfbZRLETileHeight>rh)?rh-j:rfbZRLETileHeight;
|
||||
int result=HandleZRLETile(client,(uint8_t *)buf,remaining,rx+i,ry+j,subWidth,subHeight);
|
||||
|
||||
if(result<0) {
|
||||
rfbClientLog("ZRLE decoding failed (%d)\n",result);
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
buf+=result;
|
||||
remaining-=result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
rfbClientLog(
|
||||
"zlib inflate returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
client->decompStream.msg);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if REALBPP!=BPP && defined(UNCOMP) && UNCOMP!=0
|
||||
#if UNCOMP>0
|
||||
#define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)>>UNCOMP)
|
||||
#else
|
||||
#define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)<<(-(UNCOMP)))
|
||||
#endif
|
||||
#else
|
||||
#define UncompressCPixel(pointer) (*(CARDBPP*)pointer)
|
||||
#endif
|
||||
|
||||
static int HandleZRLETile(rfbClient* client,
|
||||
uint8_t* buffer,size_t buffer_length,
|
||||
int x,int y,int w,int h) {
|
||||
uint8_t* buffer_copy = buffer;
|
||||
uint8_t* buffer_end = buffer+buffer_length;
|
||||
uint8_t type;
|
||||
#if BPP!=8
|
||||
uint8_t zywrle_level = (client->appData.qualityLevel & 0x80) ?
|
||||
0 : (3 - client->appData.qualityLevel / 3);
|
||||
#endif
|
||||
|
||||
if(buffer_length<1)
|
||||
return -2;
|
||||
|
||||
type = *buffer;
|
||||
buffer++;
|
||||
{
|
||||
if( type == 0 ) /* raw */
|
||||
#if BPP!=8
|
||||
if( zywrle_level > 0 ){
|
||||
CARDBPP* pFrame = (CARDBPP*)client->frameBuffer + y*client->width+x;
|
||||
int ret;
|
||||
client->appData.qualityLevel |= 0x80;
|
||||
ret = HandleZRLETile(client, buffer, buffer_end-buffer, x, y, w, h);
|
||||
client->appData.qualityLevel &= 0x7F;
|
||||
if( ret < 0 ){
|
||||
return ret;
|
||||
}
|
||||
ZYWRLE_SYNTHESIZE( pFrame, pFrame, w, h, client->width, zywrle_level, (int*)client->zlib_buffer );
|
||||
buffer += ret;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
#if REALBPP!=BPP
|
||||
int i,j;
|
||||
|
||||
if(1+w*h*REALBPP/8>buffer_length) {
|
||||
rfbClientLog("expected %d bytes, got only %d (%dx%d)\n",1+w*h*REALBPP/8,buffer_length,w,h);
|
||||
return -3;
|
||||
}
|
||||
|
||||
for(j=y*client->width; j<(y+h)*client->width; j+=client->width)
|
||||
for(i=x; i<x+w; i++,buffer+=REALBPP/8)
|
||||
((CARDBPP*)client->frameBuffer)[j+i] = UncompressCPixel(buffer);
|
||||
#else
|
||||
client->GotBitmap(client, buffer, x, y, w, h);
|
||||
buffer+=w*h*REALBPP/8;
|
||||
#endif
|
||||
}
|
||||
else if( type == 1 ) /* solid */
|
||||
{
|
||||
CARDBPP color = UncompressCPixel(buffer);
|
||||
|
||||
if(1+REALBPP/8>buffer_length)
|
||||
return -4;
|
||||
|
||||
client->GotFillRect(client, x, y, w, h, color);
|
||||
|
||||
buffer+=REALBPP/8;
|
||||
|
||||
}
|
||||
else if( type <= 127 ) /* packed Palette */
|
||||
{
|
||||
CARDBPP palette[128];
|
||||
int i,j,shift,
|
||||
bpp=(type>4?(type>16?8:4):(type>2?2:1)),
|
||||
mask=(1<<bpp)-1,
|
||||
divider=(8/bpp);
|
||||
|
||||
if(1+type*REALBPP/8+((w+divider-1)/divider)*h>buffer_length)
|
||||
return -5;
|
||||
|
||||
/* read palette */
|
||||
for(i=0; i<type; i++,buffer+=REALBPP/8)
|
||||
palette[i] = UncompressCPixel(buffer);
|
||||
|
||||
/* read palettized pixels */
|
||||
for(j=y*client->width; j<(y+h)*client->width; j+=client->width) {
|
||||
for(i=x,shift=8-bpp; i<x+w; i++) {
|
||||
((CARDBPP*)client->frameBuffer)[j+i] = palette[((*buffer)>>shift)&mask];
|
||||
shift-=bpp;
|
||||
if(shift<0) {
|
||||
shift=8-bpp;
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
if(shift<8-bpp)
|
||||
buffer++;
|
||||
}
|
||||
|
||||
}
|
||||
/* case 17 ... 127: not used, but valid */
|
||||
else if( type == 128 ) /* plain RLE */
|
||||
{
|
||||
int i=0,j=0;
|
||||
while(j<h) {
|
||||
int color,length;
|
||||
/* read color */
|
||||
if(buffer+REALBPP/8+1>buffer_end)
|
||||
return -7;
|
||||
color = UncompressCPixel(buffer);
|
||||
buffer+=REALBPP/8;
|
||||
/* read run length */
|
||||
length=1;
|
||||
while(*buffer==0xff) {
|
||||
if(buffer+1>=buffer_end)
|
||||
return -8;
|
||||
length+=*buffer;
|
||||
buffer++;
|
||||
}
|
||||
length+=*buffer;
|
||||
buffer++;
|
||||
while(j<h && length>0) {
|
||||
((CARDBPP*)client->frameBuffer)[(y+j)*client->width+x+i] = color;
|
||||
length--;
|
||||
i++;
|
||||
if(i>=w) {
|
||||
i=0;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if(length>0)
|
||||
rfbClientLog("Warning: possible ZRLE corruption\n");
|
||||
}
|
||||
|
||||
}
|
||||
else if( type == 129 ) /* unused */
|
||||
{
|
||||
return -8;
|
||||
}
|
||||
else if( type >= 130 ) /* palette RLE */
|
||||
{
|
||||
CARDBPP palette[128];
|
||||
int i,j;
|
||||
|
||||
if(2+(type-128)*REALBPP/8>buffer_length)
|
||||
return -9;
|
||||
|
||||
/* read palette */
|
||||
for(i=0; i<type-128; i++,buffer+=REALBPP/8)
|
||||
palette[i] = UncompressCPixel(buffer);
|
||||
/* read palettized pixels */
|
||||
i=j=0;
|
||||
while(j<h) {
|
||||
int color,length;
|
||||
/* read color */
|
||||
if(buffer>=buffer_end)
|
||||
return -10;
|
||||
color = palette[(*buffer)&0x7f];
|
||||
length=1;
|
||||
if(*buffer&0x80) {
|
||||
if(buffer+1>=buffer_end)
|
||||
return -11;
|
||||
buffer++;
|
||||
/* read run length */
|
||||
while(*buffer==0xff) {
|
||||
if(buffer+1>=buffer_end)
|
||||
return -8;
|
||||
length+=*buffer;
|
||||
buffer++;
|
||||
}
|
||||
length+=*buffer;
|
||||
}
|
||||
buffer++;
|
||||
while(j<h && length>0) {
|
||||
((CARDBPP*)client->frameBuffer)[(y+j)*client->width+x+i] = color;
|
||||
length--;
|
||||
i++;
|
||||
if(i>=w) {
|
||||
i=0;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if(length>0)
|
||||
rfbClientLog("Warning: possible ZRLE corruption\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer-buffer_copy;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
||||
#undef CARDREALBPP
|
||||
#undef HandleZRLE
|
||||
#undef HandleZRLETile
|
||||
#undef UncompressCPixel
|
||||
|
||||
#endif
|
||||
|
||||
#undef UNCOMP
|
||||
#undef REALBPP
|
||||
407
android/extern/libvncserver/src/libvncserver/auth.c
vendored
Normal file
407
android/extern/libvncserver/src/libvncserver/auth.c
vendored
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* auth.c - deal with authentication.
|
||||
*
|
||||
* This file implements the VNC authentication protocol when setting up an RFB
|
||||
* connection.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
/* RFB 3.8 clients are well informed */
|
||||
void rfbClientSendString(rfbClientPtr cl, const char *reason);
|
||||
|
||||
|
||||
/*
|
||||
* Handle security types
|
||||
*/
|
||||
|
||||
static rfbSecurityHandler* securityHandlers = NULL;
|
||||
|
||||
/*
|
||||
* This method registers a list of new security types.
|
||||
* It avoids same security type getting registered multiple times.
|
||||
* The order is not preserved if multiple security types are
|
||||
* registered at one-go.
|
||||
*/
|
||||
void
|
||||
rfbRegisterSecurityHandler(rfbSecurityHandler* handler)
|
||||
{
|
||||
rfbSecurityHandler *head = securityHandlers, *next = NULL;
|
||||
|
||||
if(handler == NULL)
|
||||
return;
|
||||
|
||||
next = handler->next;
|
||||
|
||||
while(head != NULL) {
|
||||
if(head == handler) {
|
||||
rfbRegisterSecurityHandler(next);
|
||||
return;
|
||||
}
|
||||
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
handler->next = securityHandlers;
|
||||
securityHandlers = handler;
|
||||
|
||||
rfbRegisterSecurityHandler(next);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method unregisters a list of security types.
|
||||
* These security types won't be available for any new
|
||||
* client connection.
|
||||
*/
|
||||
void
|
||||
rfbUnregisterSecurityHandler(rfbSecurityHandler* handler)
|
||||
{
|
||||
rfbSecurityHandler *cur = NULL, *pre = NULL;
|
||||
|
||||
if(handler == NULL)
|
||||
return;
|
||||
|
||||
if(securityHandlers == handler) {
|
||||
securityHandlers = securityHandlers->next;
|
||||
rfbUnregisterSecurityHandler(handler->next);
|
||||
return;
|
||||
}
|
||||
|
||||
cur = pre = securityHandlers;
|
||||
|
||||
while(cur) {
|
||||
if(cur == handler) {
|
||||
pre->next = cur->next;
|
||||
break;
|
||||
}
|
||||
pre = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
rfbUnregisterSecurityHandler(handler->next);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the authentication challenge.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbVncAuthSendChallenge(rfbClientPtr cl)
|
||||
{
|
||||
|
||||
/* 4 byte header is alreay sent. Which is rfbSecTypeVncAuth
|
||||
(same as rfbVncAuth). Just send the challenge. */
|
||||
rfbRandomBytes(cl->authChallenge);
|
||||
if (rfbWriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
|
||||
rfbLogPerror("rfbAuthNewClient: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dispatch client input to rfbVncAuthProcessResponse. */
|
||||
cl->state = RFB_AUTHENTICATION;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the NO AUTHENTICATION. SCARR
|
||||
*/
|
||||
|
||||
/*
|
||||
* The rfbVncAuthNone function is currently the only function that contains
|
||||
* special logic for the built-in Mac OS X VNC client which is activated by
|
||||
* a protocolMinorVersion == 889 coming from the Mac OS X VNC client.
|
||||
* The rfbProcessClientInitMessage function does understand how to handle the
|
||||
* RFB_INITIALISATION_SHARED state which was introduced to support the built-in
|
||||
* Mac OS X VNC client, but rfbProcessClientInitMessage does not examine the
|
||||
* protocolMinorVersion version field and so its support for the
|
||||
* RFB_INITIALISATION_SHARED state is not restricted to just the OS X client.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbVncAuthNone(rfbClientPtr cl)
|
||||
{
|
||||
/* The built-in Mac OS X VNC client behaves in a non-conforming fashion
|
||||
* when the server version is 3.7 or later AND the list of security types
|
||||
* sent to the OS X client contains the 'None' authentication type AND
|
||||
* the OS X client sends back the 'None' type as its choice. In this case,
|
||||
* and this case ONLY, the built-in Mac OS X VNC client will NOT send the
|
||||
* ClientInit message and instead will behave as though an implicit
|
||||
* ClientInit message containing a shared-flag of true has been sent.
|
||||
* The special state RFB_INITIALISATION_SHARED represents this case.
|
||||
* The Mac OS X VNC client can be detected by checking protocolMinorVersion
|
||||
* for a value of 889. No other VNC client is known to use this value
|
||||
* for protocolMinorVersion. */
|
||||
uint32_t authResult;
|
||||
|
||||
/* The built-in Mac OS X VNC client expects to NOT receive a SecurityResult
|
||||
* message for authentication type 'None'. Since its protocolMinorVersion
|
||||
* is greater than 7 (it is 889) this case must be tested for specially. */
|
||||
if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7 && cl->protocolMinorVersion != 889) {
|
||||
rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n");
|
||||
authResult = Swap32IfLE(rfbVncAuthOK);
|
||||
if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
|
||||
rfbLogPerror("rfbAuthProcessClientMessage: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cl->state = cl->protocolMinorVersion == 889 ? RFB_INITIALISATION_SHARED : RFB_INITIALISATION;
|
||||
if (cl->state == RFB_INITIALISATION_SHARED)
|
||||
/* In this case we must call rfbProcessClientMessage now because
|
||||
* otherwise we would hang waiting for data to be received from the
|
||||
* client (the ClientInit message which will never come). */
|
||||
rfbProcessClientMessage(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Advertise the supported security types (protocol 3.7). Here before sending
|
||||
* the list of security types to the client one more security type is added
|
||||
* to the list if primaryType is not set to rfbSecTypeInvalid. This security
|
||||
* type is the standard vnc security type which does the vnc authentication
|
||||
* or it will be security type for no authentication.
|
||||
* Different security types will be added by applications using this library.
|
||||
*/
|
||||
|
||||
static rfbSecurityHandler VncSecurityHandlerVncAuth = {
|
||||
rfbSecTypeVncAuth,
|
||||
rfbVncAuthSendChallenge,
|
||||
NULL
|
||||
};
|
||||
|
||||
static rfbSecurityHandler VncSecurityHandlerNone = {
|
||||
rfbSecTypeNone,
|
||||
rfbVncAuthNone,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType)
|
||||
{
|
||||
/* The size of the message is the count of security types +1,
|
||||
* since the first byte is the number of types. */
|
||||
int size = 1;
|
||||
rfbSecurityHandler* handler;
|
||||
#define MAX_SECURITY_TYPES 255
|
||||
uint8_t buffer[MAX_SECURITY_TYPES+1];
|
||||
|
||||
|
||||
/* Fill in the list of security types in the client structure. (NOTE: Not really in the client structure) */
|
||||
switch (primaryType) {
|
||||
case rfbSecTypeNone:
|
||||
rfbUnregisterSecurityHandler(&VncSecurityHandlerVncAuth);
|
||||
rfbRegisterSecurityHandler(&VncSecurityHandlerNone);
|
||||
break;
|
||||
case rfbSecTypeVncAuth:
|
||||
rfbUnregisterSecurityHandler(&VncSecurityHandlerNone);
|
||||
rfbRegisterSecurityHandler(&VncSecurityHandlerVncAuth);
|
||||
break;
|
||||
}
|
||||
|
||||
for (handler = securityHandlers;
|
||||
handler && size<MAX_SECURITY_TYPES; handler = handler->next) {
|
||||
buffer[size] = handler->type;
|
||||
size++;
|
||||
}
|
||||
buffer[0] = (unsigned char)size-1;
|
||||
|
||||
/* Send the list. */
|
||||
if (rfbWriteExact(cl, (char *)buffer, size) < 0) {
|
||||
rfbLogPerror("rfbSendSecurityTypeList: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* if count is 0, we need to send the reason and close the connection.
|
||||
*/
|
||||
if(size <= 1) {
|
||||
/* This means total count is Zero and so reason msg should be sent */
|
||||
/* The execution should never reach here */
|
||||
char* reason = "No authentication mode is registered!";
|
||||
|
||||
rfbClientSendString(cl, reason);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dispatch client input to rfbProcessClientSecurityType. */
|
||||
cl->state = RFB_SECURITY_TYPE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Tell the client what security type will be used (protocol 3.3).
|
||||
*/
|
||||
static void
|
||||
rfbSendSecurityType(rfbClientPtr cl, int32_t securityType)
|
||||
{
|
||||
uint32_t value32;
|
||||
|
||||
/* Send the value. */
|
||||
value32 = Swap32IfLE(securityType);
|
||||
if (rfbWriteExact(cl, (char *)&value32, 4) < 0) {
|
||||
rfbLogPerror("rfbSendSecurityType: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decide what to do next. */
|
||||
switch (securityType) {
|
||||
case rfbSecTypeNone:
|
||||
/* Dispatch client input to rfbProcessClientInitMessage. */
|
||||
cl->state = RFB_INITIALISATION;
|
||||
break;
|
||||
case rfbSecTypeVncAuth:
|
||||
/* Begin the standard VNC authentication procedure. */
|
||||
rfbVncAuthSendChallenge(cl);
|
||||
break;
|
||||
default:
|
||||
/* Impossible case (hopefully). */
|
||||
rfbLogPerror("rfbSendSecurityType: assertion failed");
|
||||
rfbCloseClient(cl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* rfbAuthNewClient is called right after negotiating the protocol
|
||||
* version. Depending on the protocol version, we send either a code
|
||||
* for authentication scheme to be used (protocol 3.3), or a list of
|
||||
* possible "security types" (protocol 3.7).
|
||||
*/
|
||||
|
||||
void
|
||||
rfbAuthNewClient(rfbClientPtr cl)
|
||||
{
|
||||
int32_t securityType = rfbSecTypeInvalid;
|
||||
|
||||
if (!cl->screen->authPasswdData || cl->reverseConnection) {
|
||||
/* chk if this condition is valid or not. */
|
||||
securityType = rfbSecTypeNone;
|
||||
} else if (cl->screen->authPasswdData) {
|
||||
securityType = rfbSecTypeVncAuth;
|
||||
}
|
||||
|
||||
if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion < 7)
|
||||
{
|
||||
/* Make sure we use only RFB 3.3 compatible security types. */
|
||||
if (securityType == rfbSecTypeInvalid) {
|
||||
rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n");
|
||||
rfbClientConnFailed(cl, "Your viewer cannot handle required "
|
||||
"authentication methods");
|
||||
return;
|
||||
}
|
||||
rfbSendSecurityType(cl, securityType);
|
||||
} else {
|
||||
/* Here it's ok when securityType is set to rfbSecTypeInvalid. */
|
||||
rfbSendSecurityTypeList(cl, securityType);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the security type chosen by the client (protocol 3.7).
|
||||
*/
|
||||
|
||||
void
|
||||
rfbProcessClientSecurityType(rfbClientPtr cl)
|
||||
{
|
||||
int n;
|
||||
uint8_t chosenType;
|
||||
rfbSecurityHandler* handler;
|
||||
|
||||
/* Read the security type. */
|
||||
n = rfbReadExact(cl, (char *)&chosenType, 1);
|
||||
if (n <= 0) {
|
||||
if (n == 0)
|
||||
rfbLog("rfbProcessClientSecurityType: client gone\n");
|
||||
else
|
||||
rfbLogPerror("rfbProcessClientSecurityType: read");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure it was present in the list sent by the server. */
|
||||
for (handler = securityHandlers; handler; handler = handler->next) {
|
||||
if (chosenType == handler->type) {
|
||||
rfbLog("rfbProcessClientSecurityType: executing handler for type %d\n", chosenType);
|
||||
handler->handler(cl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rfbLog("rfbProcessClientSecurityType: wrong security type (%d) requested\n", chosenType);
|
||||
rfbCloseClient(cl);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* rfbAuthProcessClientMessage is called when the client sends its
|
||||
* authentication response.
|
||||
*/
|
||||
|
||||
void
|
||||
rfbAuthProcessClientMessage(rfbClientPtr cl)
|
||||
{
|
||||
int n;
|
||||
uint8_t response[CHALLENGESIZE];
|
||||
uint32_t authResult;
|
||||
|
||||
if ((n = rfbReadExact(cl, (char *)response, CHALLENGESIZE)) <= 0) {
|
||||
if (n != 0)
|
||||
rfbLogPerror("rfbAuthProcessClientMessage: read");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!cl->screen->passwordCheck(cl,(const char*)response,CHALLENGESIZE)) {
|
||||
rfbErr("rfbAuthProcessClientMessage: password check failed\n");
|
||||
authResult = Swap32IfLE(rfbVncAuthFailed);
|
||||
if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
|
||||
rfbLogPerror("rfbAuthProcessClientMessage: write");
|
||||
}
|
||||
/* support RFB 3.8 clients, they expect a reason *why* it was disconnected */
|
||||
if (cl->protocolMinorVersion > 7) {
|
||||
rfbClientSendString(cl, "password check failed!");
|
||||
}
|
||||
else
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
authResult = Swap32IfLE(rfbVncAuthOK);
|
||||
|
||||
if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
|
||||
rfbLogPerror("rfbAuthProcessClientMessage: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
cl->state = RFB_INITIALISATION;
|
||||
}
|
||||
266
android/extern/libvncserver/src/libvncserver/cargs.c
vendored
Normal file
266
android/extern/libvncserver/src/libvncserver/cargs.c
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* This parses the command line arguments. It was separated from main.c by
|
||||
* Justin Dearing <jdeari01@longisland.poly.edu>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* LibVNCServer (C) 2001 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
|
||||
* Original OSXvnc (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* see GPL (latest version) for full details
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
extern int rfbStringToAddr(char *str, in_addr_t *iface);
|
||||
|
||||
void
|
||||
rfbUsage(void)
|
||||
{
|
||||
rfbProtocolExtension* extension;
|
||||
|
||||
fprintf(stderr, "-rfbport port TCP port for RFB protocol\n");
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
fprintf(stderr, "-rfbportv6 port TCP6 port for RFB protocol\n");
|
||||
#endif
|
||||
fprintf(stderr, "-rfbwait time max time in ms to wait for RFB client\n");
|
||||
fprintf(stderr, "-rfbauth passwd-file use authentication on RFB protocol\n"
|
||||
" (use 'storepasswd' to create a password file)\n");
|
||||
fprintf(stderr, "-rfbversion 3.x Set the version of the RFB we choose to advertise\n");
|
||||
fprintf(stderr, "-permitfiletransfer permit file transfer support\n");
|
||||
fprintf(stderr, "-passwd plain-password use authentication \n"
|
||||
" (use plain-password as password, USE AT YOUR RISK)\n");
|
||||
fprintf(stderr, "-deferupdate time time in ms to defer updates "
|
||||
"(default 40)\n");
|
||||
fprintf(stderr, "-deferptrupdate time time in ms to defer pointer updates"
|
||||
" (default none)\n");
|
||||
fprintf(stderr, "-desktop name VNC desktop name (default \"LibVNCServer\")\n");
|
||||
fprintf(stderr, "-alwaysshared always treat new clients as shared\n");
|
||||
fprintf(stderr, "-nevershared never treat new clients as shared\n");
|
||||
fprintf(stderr, "-dontdisconnect don't disconnect existing clients when a "
|
||||
"new non-shared\n"
|
||||
" connection comes in (refuse new connection "
|
||||
"instead)\n");
|
||||
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
|
||||
fprintf(stderr, "-sslkeyfile path set path to private key file for encrypted WebSockets connections\n");
|
||||
fprintf(stderr, "-sslcertfile path set path to certificate file for encrypted WebSockets connections\n");
|
||||
#endif
|
||||
fprintf(stderr, "-httpdir dir-path enable http server using dir-path home\n");
|
||||
fprintf(stderr, "-httpport portnum use portnum for http connection\n");
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
fprintf(stderr, "-httpportv6 portnum use portnum for IPv6 http connection\n");
|
||||
#endif
|
||||
fprintf(stderr, "-enablehttpproxy enable http proxy support\n");
|
||||
fprintf(stderr, "-progressive height enable progressive updating for slow links\n");
|
||||
fprintf(stderr, "-listen ipaddr listen for connections only on network interface with\n");
|
||||
fprintf(stderr, " addr ipaddr. '-listen localhost' and hostname work too.\n");
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
fprintf(stderr, "-listenv6 ipv6addr listen for IPv6 connections only on network interface with\n");
|
||||
fprintf(stderr, " addr ipv6addr. '-listen localhost' and hostname work too.\n");
|
||||
#endif
|
||||
|
||||
for(extension=rfbGetExtensionIterator();extension;extension=extension->next)
|
||||
if(extension->usage)
|
||||
extension->usage();
|
||||
rfbReleaseExtensionIterator();
|
||||
}
|
||||
|
||||
/* purges COUNT arguments from ARGV at POSITION and decrements ARGC.
|
||||
POSITION points to the first non purged argument afterwards. */
|
||||
void rfbPurgeArguments(int* argc,int* position,int count,char *argv[])
|
||||
{
|
||||
int amount=(*argc)-(*position)-count;
|
||||
if(amount)
|
||||
memmove(argv+(*position),argv+(*position)+count,sizeof(char*)*amount);
|
||||
(*argc)-=count;
|
||||
}
|
||||
|
||||
rfbBool
|
||||
rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[])
|
||||
{
|
||||
int i,i1;
|
||||
|
||||
if(!argc) return TRUE;
|
||||
|
||||
for (i = i1 = 1; i < *argc;) {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
} else if (strcmp(argv[i], "-rfbport") == 0) { /* -rfbport port */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->port = atoi(argv[++i]);
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
} else if (strcmp(argv[i], "-rfbportv6") == 0) { /* -rfbportv6 port */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->ipv6port = atoi(argv[++i]);
|
||||
#endif
|
||||
} else if (strcmp(argv[i], "-rfbwait") == 0) { /* -rfbwait ms */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->maxClientWait = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-rfbauth") == 0) { /* -rfbauth passwd-file */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->authPasswdData = argv[++i];
|
||||
|
||||
} else if (strcmp(argv[i], "-permitfiletransfer") == 0) { /* -permitfiletransfer */
|
||||
rfbScreen->permitFileTransfer = TRUE;
|
||||
} else if (strcmp(argv[i], "-rfbversion") == 0) { /* -rfbversion 3.6 */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
sscanf(argv[++i],"%d.%d", &rfbScreen->protocolMajorVersion, &rfbScreen->protocolMinorVersion);
|
||||
} else if (strcmp(argv[i], "-passwd") == 0) { /* -passwd password */
|
||||
char **passwds = malloc(sizeof(char**)*2);
|
||||
if (!passwds || i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
free(passwds);
|
||||
return FALSE;
|
||||
}
|
||||
passwds[0] = argv[++i];
|
||||
passwds[1] = NULL;
|
||||
rfbScreen->authPasswdData = (void*)passwds;
|
||||
rfbScreen->passwordCheck = rfbCheckPasswordByList;
|
||||
} else if (strcmp(argv[i], "-deferupdate") == 0) { /* -deferupdate milliseconds */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->deferUpdateTime = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-deferptrupdate") == 0) { /* -deferptrupdate milliseconds */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->deferPtrUpdateTime = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-desktop") == 0) { /* -desktop desktop-name */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->desktopName = argv[++i];
|
||||
} else if (strcmp(argv[i], "-alwaysshared") == 0) {
|
||||
rfbScreen->alwaysShared = TRUE;
|
||||
} else if (strcmp(argv[i], "-nevershared") == 0) {
|
||||
rfbScreen->neverShared = TRUE;
|
||||
} else if (strcmp(argv[i], "-dontdisconnect") == 0) {
|
||||
rfbScreen->dontDisconnect = TRUE;
|
||||
} else if (strcmp(argv[i], "-httpdir") == 0) { /* -httpdir directory-path */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->httpDir = argv[++i];
|
||||
} else if (strcmp(argv[i], "-httpport") == 0) { /* -httpport portnum */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->httpPort = atoi(argv[++i]);
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
} else if (strcmp(argv[i], "-httpportv6") == 0) { /* -httpportv6 portnum */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->http6Port = atoi(argv[++i]);
|
||||
#endif
|
||||
} else if (strcmp(argv[i], "-enablehttpproxy") == 0) {
|
||||
rfbScreen->httpEnableProxyConnect = TRUE;
|
||||
} else if (strcmp(argv[i], "-progressive") == 0) { /* -httpport portnum */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->progressiveSliceHeight = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-listen") == 0) { /* -listen ipaddr */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
if (! rfbStringToAddr(argv[++i], &(rfbScreen->listenInterface))) {
|
||||
return FALSE;
|
||||
}
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
} else if (strcmp(argv[i], "-listenv6") == 0) { /* -listenv6 ipv6addr */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->listen6Interface = argv[++i];
|
||||
#endif
|
||||
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
|
||||
} else if (strcmp(argv[i], "-sslkeyfile") == 0) { /* -sslkeyfile sslkeyfile */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->sslkeyfile = argv[++i];
|
||||
} else if (strcmp(argv[i], "-sslcertfile") == 0) { /* -sslcertfile sslcertfile */
|
||||
if (i + 1 >= *argc) {
|
||||
rfbUsage();
|
||||
return FALSE;
|
||||
}
|
||||
rfbScreen->sslcertfile = argv[++i];
|
||||
#endif
|
||||
} else {
|
||||
rfbProtocolExtension* extension;
|
||||
int handled=0;
|
||||
|
||||
for(extension=rfbGetExtensionIterator();handled==0 && extension;
|
||||
extension=extension->next)
|
||||
if(extension->processArgument)
|
||||
handled = extension->processArgument(*argc - i, argv + i);
|
||||
rfbReleaseExtensionIterator();
|
||||
|
||||
if(handled==0) {
|
||||
i++;
|
||||
i1=i;
|
||||
continue;
|
||||
}
|
||||
i+=handled-1;
|
||||
}
|
||||
/* we just remove the processed arguments from the list */
|
||||
rfbPurgeArguments(argc,&i1,i-i1+1,argv);
|
||||
i=i1;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rfbBool
|
||||
rfbProcessSizeArguments(int* width,int* height,int* bpp,int* argc, char *argv[])
|
||||
{
|
||||
int i,i1;
|
||||
|
||||
if(!argc) return TRUE;
|
||||
for (i = i1 = 1; i < *argc-1;) {
|
||||
if (strcmp(argv[i], "-bpp") == 0) {
|
||||
*bpp = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-width") == 0) {
|
||||
*width = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-height") == 0) {
|
||||
*height = atoi(argv[++i]);
|
||||
} else {
|
||||
i++;
|
||||
i1=i;
|
||||
continue;
|
||||
}
|
||||
rfbPurgeArguments(argc,&i1,i-i1,argv);
|
||||
i=i1;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
358
android/extern/libvncserver/src/libvncserver/corre.c
vendored
Normal file
358
android/extern/libvncserver/src/libvncserver/corre.c
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* corre.c
|
||||
*
|
||||
* Routines to implement Compact Rise-and-Run-length Encoding (CoRRE). This
|
||||
* code is based on krw's original javatel rfbserver.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd.
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
/*
|
||||
* cl->beforeEncBuf contains pixel data in the client's format.
|
||||
* cl->afterEncBuf contains the RRE encoded version. If the RRE encoded version is
|
||||
* larger than the raw data or if it exceeds cl->afterEncBufSize then
|
||||
* raw encoding is used instead.
|
||||
*/
|
||||
|
||||
static int subrectEncode8(rfbClientPtr cl, uint8_t *data, int w, int h);
|
||||
static int subrectEncode16(rfbClientPtr cl, uint16_t *data, int w, int h);
|
||||
static int subrectEncode32(rfbClientPtr cl, uint32_t *data, int w, int h);
|
||||
static uint32_t getBgColour(char *data, int size, int bpp);
|
||||
static rfbBool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y,
|
||||
int w, int h);
|
||||
|
||||
|
||||
/*
|
||||
* rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE
|
||||
* encoding.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSendRectEncodingCoRRE(rfbClientPtr cl,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
if (h > cl->correMaxHeight) {
|
||||
return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) &&
|
||||
rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, w,
|
||||
h - cl->correMaxHeight));
|
||||
}
|
||||
|
||||
if (w > cl->correMaxWidth) {
|
||||
return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) &&
|
||||
rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y,
|
||||
w - cl->correMaxWidth, h));
|
||||
}
|
||||
|
||||
rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256)
|
||||
* rectangle using CoRRE encoding.
|
||||
*/
|
||||
|
||||
static rfbBool
|
||||
rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
rfbRREHeader hdr;
|
||||
int nSubrects;
|
||||
int i;
|
||||
char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
|
||||
+ (x * (cl->scaledScreen->bitsPerPixel / 8)));
|
||||
|
||||
int maxRawSize = (cl->scaledScreen->width * cl->scaledScreen->height
|
||||
* (cl->format.bitsPerPixel / 8));
|
||||
|
||||
if (!cl->beforeEncBuf || cl->beforeEncBufSize < maxRawSize) {
|
||||
if (cl->beforeEncBuf == NULL)
|
||||
cl->beforeEncBuf = (char *)malloc(maxRawSize);
|
||||
else {
|
||||
char *reallocedBeforeEncBuf = (char *)realloc(cl->beforeEncBuf, maxRawSize);
|
||||
if (!reallocedBeforeEncBuf) return FALSE;
|
||||
cl->beforeEncBuf = reallocedBeforeEncBuf;
|
||||
}
|
||||
if(cl->beforeEncBuf)
|
||||
cl->beforeEncBufSize = maxRawSize;
|
||||
}
|
||||
|
||||
if (!cl->afterEncBuf || cl->afterEncBufSize < maxRawSize) {
|
||||
if (cl->afterEncBuf == NULL)
|
||||
cl->afterEncBuf = (char *)malloc(maxRawSize);
|
||||
else {
|
||||
char *reallocedAfterEncBuf = (char *)realloc(cl->afterEncBuf, maxRawSize);
|
||||
if (!reallocedAfterEncBuf) return FALSE;
|
||||
cl->afterEncBuf = reallocedAfterEncBuf;
|
||||
}
|
||||
if(cl->afterEncBuf)
|
||||
cl->afterEncBufSize = maxRawSize;
|
||||
}
|
||||
|
||||
if (!cl->beforeEncBuf || !cl->afterEncBuf)
|
||||
{
|
||||
rfbLog("rfbSendSmallRectEncodingCoRRE: failed to allocate memory\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
(*cl->translateFn)(cl->translateLookupTable,&(cl->screen->serverFormat),
|
||||
&cl->format, fbptr, cl->beforeEncBuf,
|
||||
cl->scaledScreen->paddedWidthInBytes, w, h);
|
||||
|
||||
switch (cl->format.bitsPerPixel) {
|
||||
case 8:
|
||||
nSubrects = subrectEncode8(cl, (uint8_t *)cl->beforeEncBuf, w, h);
|
||||
break;
|
||||
case 16:
|
||||
nSubrects = subrectEncode16(cl, (uint16_t *)cl->beforeEncBuf, w, h);
|
||||
break;
|
||||
case 32:
|
||||
nSubrects = subrectEncode32(cl, (uint32_t *)cl->beforeEncBuf, w, h);
|
||||
break;
|
||||
default:
|
||||
rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nSubrects < 0) {
|
||||
|
||||
/* RRE encoding was too large, use raw */
|
||||
|
||||
return rfbSendRectEncodingRaw(cl, x, y, w, h);
|
||||
}
|
||||
|
||||
rfbStatRecordEncodingSent(cl,rfbEncodingCoRRE,
|
||||
sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + cl->afterEncBufLen,
|
||||
sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8));
|
||||
|
||||
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
|
||||
> UPDATE_BUF_SIZE)
|
||||
{
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rect.r.x = Swap16IfLE(x);
|
||||
rect.r.y = Swap16IfLE(y);
|
||||
rect.r.w = Swap16IfLE(w);
|
||||
rect.r.h = Swap16IfLE(h);
|
||||
rect.encoding = Swap32IfLE(rfbEncodingCoRRE);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
|
||||
sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
hdr.nSubrects = Swap32IfLE(nSubrects);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader);
|
||||
cl->ublen += sz_rfbRREHeader;
|
||||
|
||||
for (i = 0; i < cl->afterEncBufLen;) {
|
||||
|
||||
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
|
||||
|
||||
if (i + bytesToCopy > cl->afterEncBufLen) {
|
||||
bytesToCopy = cl->afterEncBufLen - i;
|
||||
}
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], &cl->afterEncBuf[i], bytesToCopy);
|
||||
|
||||
cl->ublen += bytesToCopy;
|
||||
i += bytesToCopy;
|
||||
|
||||
if (cl->ublen == UPDATE_BUF_SIZE) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* subrectEncode() encodes the given multicoloured rectangle as a background
|
||||
* colour overwritten by single-coloured rectangles. It returns the number
|
||||
* of subrectangles in the encoded buffer, or -1 if subrect encoding won't
|
||||
* fit in the buffer. It puts the encoded rectangles in cl->afterEncBuf. The
|
||||
* single-colour rectangle partition is not optimal, but does find the biggest
|
||||
* horizontal or vertical rectangle top-left anchored to each consecutive
|
||||
* coordinate position.
|
||||
*
|
||||
* The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
|
||||
* <subrect> is [<colour><x><y><w><h>].
|
||||
*/
|
||||
|
||||
#define DEFINE_SUBRECT_ENCODE(bpp) \
|
||||
static int \
|
||||
subrectEncode##bpp(rfbClientPtr client, uint##bpp##_t *data, int w, int h) { \
|
||||
uint##bpp##_t cl; \
|
||||
rfbCoRRERectangle subrect; \
|
||||
int x,y; \
|
||||
int i,j; \
|
||||
int hx=0,hy,vx=0,vy; \
|
||||
int hyflag; \
|
||||
uint##bpp##_t *seg; \
|
||||
uint##bpp##_t *line; \
|
||||
int hw,hh,vw,vh; \
|
||||
int thex,they,thew,theh; \
|
||||
int numsubs = 0; \
|
||||
int newLen; \
|
||||
uint##bpp##_t bg = (uint##bpp##_t)getBgColour((char*)data,w*h,bpp); \
|
||||
\
|
||||
*((uint##bpp##_t*)client->afterEncBuf) = bg; \
|
||||
\
|
||||
client->afterEncBufLen = (bpp/8); \
|
||||
\
|
||||
for (y=0; y<h; y++) { \
|
||||
line = data+(y*w); \
|
||||
for (x=0; x<w; x++) { \
|
||||
if (line[x] != bg) { \
|
||||
cl = line[x]; \
|
||||
hy = y-1; \
|
||||
hyflag = 1; \
|
||||
for (j=y; j<h; j++) { \
|
||||
seg = data+(j*w); \
|
||||
if (seg[x] != cl) {break;} \
|
||||
i = x; \
|
||||
while ((i < w) && (seg[i] == cl)) i += 1; \
|
||||
i -= 1; \
|
||||
if (j == y) vx = hx = i; \
|
||||
if (i < vx) vx = i; \
|
||||
if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
|
||||
} \
|
||||
vy = j-1; \
|
||||
\
|
||||
/* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
|
||||
* We'll choose the bigger of the two. \
|
||||
*/ \
|
||||
hw = hx-x+1; \
|
||||
hh = hy-y+1; \
|
||||
vw = vx-x+1; \
|
||||
vh = vy-y+1; \
|
||||
\
|
||||
thex = x; \
|
||||
they = y; \
|
||||
\
|
||||
if ((hw*hh) > (vw*vh)) { \
|
||||
thew = hw; \
|
||||
theh = hh; \
|
||||
} else { \
|
||||
thew = vw; \
|
||||
theh = vh; \
|
||||
} \
|
||||
\
|
||||
subrect.x = thex; \
|
||||
subrect.y = they; \
|
||||
subrect.w = thew; \
|
||||
subrect.h = theh; \
|
||||
\
|
||||
newLen = client->afterEncBufLen + (bpp/8) + sz_rfbCoRRERectangle; \
|
||||
if ((newLen > (w * h * (bpp/8))) || (newLen > client->afterEncBufSize)) \
|
||||
return -1; \
|
||||
\
|
||||
numsubs += 1; \
|
||||
*((uint##bpp##_t*)(client->afterEncBuf + client->afterEncBufLen)) = cl; \
|
||||
client->afterEncBufLen += (bpp/8); \
|
||||
memcpy(&client->afterEncBuf[client->afterEncBufLen],&subrect,sz_rfbCoRRERectangle); \
|
||||
client->afterEncBufLen += sz_rfbCoRRERectangle; \
|
||||
\
|
||||
/* \
|
||||
* Now mark the subrect as done. \
|
||||
*/ \
|
||||
for (j=they; j < (they+theh); j++) { \
|
||||
for (i=thex; i < (thex+thew); i++) { \
|
||||
data[j*w+i] = bg; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return numsubs; \
|
||||
}
|
||||
|
||||
DEFINE_SUBRECT_ENCODE(8)
|
||||
DEFINE_SUBRECT_ENCODE(16)
|
||||
DEFINE_SUBRECT_ENCODE(32)
|
||||
|
||||
|
||||
/*
|
||||
* getBgColour() gets the most prevalent colour in a byte array.
|
||||
*/
|
||||
static uint32_t
|
||||
getBgColour(char *data, int size, int bpp)
|
||||
{
|
||||
|
||||
#define NUMCLRS 256
|
||||
|
||||
static int counts[NUMCLRS];
|
||||
int i,j,k;
|
||||
|
||||
int maxcount = 0;
|
||||
uint8_t maxclr = 0;
|
||||
|
||||
if (bpp != 8) {
|
||||
if (bpp == 16) {
|
||||
return ((uint16_t *)data)[0];
|
||||
} else if (bpp == 32) {
|
||||
return ((uint32_t *)data)[0];
|
||||
} else {
|
||||
rfbLog("getBgColour: bpp %d?\n",bpp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<NUMCLRS; i++) {
|
||||
counts[i] = 0;
|
||||
}
|
||||
|
||||
for (j=0; j<size; j++) {
|
||||
k = (int)(((uint8_t *)data)[j]);
|
||||
#if NUMCLRS != 256
|
||||
if (k >= NUMCLRS) {
|
||||
rfbLog("getBgColour: unusual colour = %d\n", k);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
counts[k] += 1;
|
||||
if (counts[k] > maxcount) {
|
||||
maxcount = counts[k];
|
||||
maxclr = ((uint8_t *)data)[j];
|
||||
}
|
||||
}
|
||||
|
||||
return maxclr;
|
||||
}
|
||||
792
android/extern/libvncserver/src/libvncserver/cursor.c
vendored
Normal file
792
android/extern/libvncserver/src/libvncserver/cursor.c
vendored
Normal file
@@ -0,0 +1,792 @@
|
||||
/*
|
||||
* cursor.c - support for cursor shape updates.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/rfbregion.h>
|
||||
#include "private.h"
|
||||
|
||||
void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
|
||||
|
||||
/*
|
||||
* Send cursor shape either in X-style format or in client pixel format.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSendCursorShape(rfbClientPtr cl)
|
||||
{
|
||||
rfbCursorPtr pCursor;
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
rfbXCursorColors colors;
|
||||
int saved_ublen;
|
||||
int bitmapRowBytes, maskBytes, dataBytes;
|
||||
int i, j;
|
||||
uint8_t *bitmapData;
|
||||
uint8_t bitmapByte;
|
||||
|
||||
/* TODO: scale the cursor data to the correct size */
|
||||
|
||||
pCursor = cl->screen->getCursorPtr(cl);
|
||||
/*if(!pCursor) return TRUE;*/
|
||||
|
||||
if (cl->useRichCursorEncoding) {
|
||||
if(pCursor && !pCursor->richSource)
|
||||
rfbMakeRichCursorFromXCursor(cl->screen,pCursor);
|
||||
rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
|
||||
} else {
|
||||
if(pCursor && !pCursor->source)
|
||||
rfbMakeXCursorFromRichCursor(cl->screen,pCursor);
|
||||
rect.encoding = Swap32IfLE(rfbEncodingXCursor);
|
||||
}
|
||||
|
||||
/* If there is no cursor, send update with empty cursor data. */
|
||||
|
||||
if ( pCursor && pCursor->width == 1 &&
|
||||
pCursor->height == 1 &&
|
||||
pCursor->mask[0] == 0 ) {
|
||||
pCursor = NULL;
|
||||
}
|
||||
|
||||
if (pCursor == NULL) {
|
||||
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
rect.r.x = rect.r.y = 0;
|
||||
rect.r.w = rect.r.h = 0;
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
|
||||
sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Calculate data sizes. */
|
||||
|
||||
bitmapRowBytes = (pCursor->width + 7) / 8;
|
||||
maskBytes = bitmapRowBytes * pCursor->height;
|
||||
dataBytes = (cl->useRichCursorEncoding) ?
|
||||
(pCursor->width * pCursor->height *
|
||||
(cl->format.bitsPerPixel / 8)) : maskBytes;
|
||||
|
||||
/* Send buffer contents if needed. */
|
||||
|
||||
if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
|
||||
sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
|
||||
sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
|
||||
return FALSE; /* FIXME. */
|
||||
}
|
||||
|
||||
saved_ublen = cl->ublen;
|
||||
|
||||
/* Prepare rectangle header. */
|
||||
|
||||
rect.r.x = Swap16IfLE(pCursor->xhot);
|
||||
rect.r.y = Swap16IfLE(pCursor->yhot);
|
||||
rect.r.w = Swap16IfLE(pCursor->width);
|
||||
rect.r.h = Swap16IfLE(pCursor->height);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
/* Prepare actual cursor data (depends on encoding used). */
|
||||
|
||||
if (!cl->useRichCursorEncoding) {
|
||||
/* XCursor encoding. */
|
||||
colors.foreRed = (char)(pCursor->foreRed >> 8);
|
||||
colors.foreGreen = (char)(pCursor->foreGreen >> 8);
|
||||
colors.foreBlue = (char)(pCursor->foreBlue >> 8);
|
||||
colors.backRed = (char)(pCursor->backRed >> 8);
|
||||
colors.backGreen = (char)(pCursor->backGreen >> 8);
|
||||
colors.backBlue = (char)(pCursor->backBlue >> 8);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors);
|
||||
cl->ublen += sz_rfbXCursorColors;
|
||||
|
||||
bitmapData = (uint8_t *)pCursor->source;
|
||||
|
||||
for (i = 0; i < pCursor->height; i++) {
|
||||
for (j = 0; j < bitmapRowBytes; j++) {
|
||||
bitmapByte = bitmapData[i * bitmapRowBytes + j];
|
||||
cl->updateBuf[cl->ublen++] = (char)bitmapByte;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* RichCursor encoding. */
|
||||
int bpp1=cl->screen->serverFormat.bitsPerPixel/8,
|
||||
bpp2=cl->format.bitsPerPixel/8;
|
||||
(*cl->translateFn)(cl->translateLookupTable,
|
||||
&(cl->screen->serverFormat),
|
||||
&cl->format, (char*)pCursor->richSource,
|
||||
&cl->updateBuf[cl->ublen],
|
||||
pCursor->width*bpp1, pCursor->width, pCursor->height);
|
||||
|
||||
cl->ublen += pCursor->width*bpp2*pCursor->height;
|
||||
}
|
||||
|
||||
/* Prepare transparency mask. */
|
||||
|
||||
bitmapData = (uint8_t *)pCursor->mask;
|
||||
|
||||
for (i = 0; i < pCursor->height; i++) {
|
||||
for (j = 0; j < bitmapRowBytes; j++) {
|
||||
bitmapByte = bitmapData[i * bitmapRowBytes + j];
|
||||
cl->updateBuf[cl->ublen++] = (char)bitmapByte;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send everything we have prepared in the cl->updateBuf[]. */
|
||||
rfbStatRecordEncodingSent(cl, (cl->useRichCursorEncoding ? rfbEncodingRichCursor : rfbEncodingXCursor),
|
||||
sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen), sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen));
|
||||
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send cursor position (PointerPos pseudo-encoding).
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSendCursorPos(rfbClientPtr cl)
|
||||
{
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
|
||||
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
|
||||
rect.r.x = Swap16IfLE(cl->screen->cursorX);
|
||||
rect.r.y = Swap16IfLE(cl->screen->cursorY);
|
||||
rect.r.w = 0;
|
||||
rect.r.h = 0;
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
|
||||
sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
rfbStatRecordEncodingSent(cl, rfbEncodingPointerPos, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
|
||||
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* conversion routine for predefined cursors in LSB order */
|
||||
unsigned char rfbReverseByte[0x100] = {
|
||||
/* copied from Xvnc/lib/font/util/utilbitmap.c */
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||||
};
|
||||
|
||||
void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap)
|
||||
{
|
||||
int i,t=(width+7)/8*height;
|
||||
for(i=0;i<t;i++)
|
||||
bitmap[i]=rfbReverseByte[(int)bitmap[i]];
|
||||
}
|
||||
|
||||
/* Cursor creation. You "paint" a cursor and let these routines do the work */
|
||||
|
||||
rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString)
|
||||
{
|
||||
int i,j,w=(width+7)/8;
|
||||
rfbCursorPtr cursor = (rfbCursorPtr)calloc(1,sizeof(rfbCursor));
|
||||
char* cp;
|
||||
unsigned char bit;
|
||||
|
||||
if (!cursor)
|
||||
return NULL;
|
||||
|
||||
cursor->cleanup=TRUE;
|
||||
cursor->width=width;
|
||||
cursor->height=height;
|
||||
/*cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;*/
|
||||
cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff;
|
||||
|
||||
cursor->source = (unsigned char*)calloc(w,height);
|
||||
if (!cursor->source) {
|
||||
free(cursor);
|
||||
return NULL;
|
||||
}
|
||||
cursor->cleanupSource = TRUE;
|
||||
for(j=0,cp=cursorString;j<height;j++)
|
||||
for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
|
||||
if(*cp!=' ') cursor->source[j*w+i/8]|=bit;
|
||||
|
||||
if(maskString) {
|
||||
cursor->mask = (unsigned char*)calloc(w,height);
|
||||
if (!cursor->mask) {
|
||||
free(cursor->source);
|
||||
free(cursor);
|
||||
return NULL;
|
||||
}
|
||||
for(j=0,cp=maskString;j<height;j++)
|
||||
for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
|
||||
if(*cp!=' ') cursor->mask[j*w+i/8]|=bit;
|
||||
} else
|
||||
cursor->mask = (unsigned char*)rfbMakeMaskForXCursor(width,height,(char*)cursor->source);
|
||||
cursor->cleanupMask = TRUE;
|
||||
|
||||
return(cursor);
|
||||
}
|
||||
|
||||
char* rfbMakeMaskForXCursor(int width,int height,char* source)
|
||||
{
|
||||
int i,j,w=(width+7)/8;
|
||||
char* mask=(char*)calloc(w,height);
|
||||
unsigned char c;
|
||||
|
||||
if (!mask)
|
||||
return NULL;
|
||||
|
||||
for(j=0;j<height;j++)
|
||||
for(i=w-1;i>=0;i--) {
|
||||
c=source[j*w+i];
|
||||
if(j>0) c|=source[(j-1)*w+i];
|
||||
if(j<height-1) c|=source[(j+1)*w+i];
|
||||
|
||||
if(i>0 && (c&0x80))
|
||||
mask[j*w+i-1]|=0x01;
|
||||
if(i<w-1 && (c&0x01))
|
||||
mask[j*w+i+1]|=0x80;
|
||||
|
||||
mask[j*w+i]|=(c<<1)|c|(c>>1);
|
||||
}
|
||||
|
||||
return(mask);
|
||||
}
|
||||
|
||||
/* this function dithers the alpha using Floyd-Steinberg */
|
||||
|
||||
char* rfbMakeMaskFromAlphaSource(int width,int height,unsigned char* alphaSource)
|
||||
{
|
||||
int* error=(int*)calloc(sizeof(int),width);
|
||||
int i,j,currentError=0,maskStride=(width+7)/8;
|
||||
unsigned char* result=(unsigned char*)calloc(maskStride,height);
|
||||
|
||||
if (!error || !result) {
|
||||
free(error);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(j=0;j<height;j++)
|
||||
for(i=0;i<width;i++) {
|
||||
int right,middle,left;
|
||||
currentError+=alphaSource[i+width*j]+error[i];
|
||||
|
||||
if(currentError<0x80) {
|
||||
/* set to transparent */
|
||||
/* alpha was treated as 0 */
|
||||
} else {
|
||||
/* set to solid */
|
||||
result[i/8+j*maskStride]|=(0x100>>(i&7));
|
||||
/* alpha was treated as 0xff */
|
||||
currentError-=0xff;
|
||||
}
|
||||
/* propagate to next row */
|
||||
right=currentError/16;
|
||||
middle=currentError*5/16;
|
||||
left=currentError*3/16;
|
||||
currentError-=right+middle+left;
|
||||
error[i]=right;
|
||||
if(i>0) {
|
||||
error[i-1]=middle;
|
||||
if(i>1)
|
||||
error[i-2]=left;
|
||||
}
|
||||
}
|
||||
free(error);
|
||||
return (char *) result;
|
||||
}
|
||||
|
||||
void rfbFreeCursor(rfbCursorPtr cursor)
|
||||
{
|
||||
if(cursor) {
|
||||
if(cursor->cleanupRichSource && cursor->richSource)
|
||||
free(cursor->richSource);
|
||||
if(cursor->cleanupRichSource && cursor->alphaSource)
|
||||
free(cursor->alphaSource);
|
||||
if(cursor->cleanupSource && cursor->source)
|
||||
free(cursor->source);
|
||||
if(cursor->cleanupMask && cursor->mask)
|
||||
free(cursor->mask);
|
||||
if(cursor->cleanup)
|
||||
free(cursor);
|
||||
else {
|
||||
cursor->cleanup=cursor->cleanupSource=cursor->cleanupMask
|
||||
=cursor->cleanupRichSource=FALSE;
|
||||
cursor->source=cursor->mask=cursor->richSource=NULL;
|
||||
cursor->alphaSource=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* background and foregroud colour have to be set beforehand */
|
||||
void rfbMakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
|
||||
{
|
||||
rfbPixelFormat* format=&rfbScreen->serverFormat;
|
||||
int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8,
|
||||
width=cursor->width*bpp;
|
||||
uint32_t background;
|
||||
char *back=(char*)&background;
|
||||
unsigned char bit;
|
||||
int interp = 0;
|
||||
|
||||
if(cursor->source && cursor->cleanupSource)
|
||||
free(cursor->source);
|
||||
cursor->source=(unsigned char*)calloc(w,cursor->height);
|
||||
if(!cursor->source)
|
||||
return;
|
||||
cursor->cleanupSource=TRUE;
|
||||
|
||||
if(format->bigEndian) {
|
||||
back+=4-bpp;
|
||||
}
|
||||
|
||||
/* all zeros means we should interpolate to black+white ourselves */
|
||||
if (!cursor->backRed && !cursor->backGreen && !cursor->backBlue &&
|
||||
!cursor->foreRed && !cursor->foreGreen && !cursor->foreBlue) {
|
||||
if (format->trueColour && (bpp == 1 || bpp == 2 || bpp == 4)) {
|
||||
interp = 1;
|
||||
cursor->foreRed = cursor->foreGreen = cursor->foreBlue = 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
background = ((format->redMax * cursor->backRed) / 0xffff) << format->redShift |
|
||||
((format->greenMax * cursor->backGreen) / 0xffff) << format->greenShift |
|
||||
((format->blueMax * cursor->backBlue) / 0xffff) << format->blueShift;
|
||||
|
||||
#define SETRGB(u) \
|
||||
r = (255 * (((format->redMax << format->redShift) & (*u)) >> format->redShift)) / format->redMax; \
|
||||
g = (255 * (((format->greenMax << format->greenShift) & (*u)) >> format->greenShift)) / format->greenMax; \
|
||||
b = (255 * (((format->blueMax << format->blueShift) & (*u)) >> format->blueShift)) / format->blueMax;
|
||||
|
||||
#ifdef DEBUG_CURSOR
|
||||
fprintf(stderr, "interp: %d\n", interp);
|
||||
#endif
|
||||
|
||||
for(j=0;j<cursor->height;j++) {
|
||||
for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1) {
|
||||
if (interp) {
|
||||
int r = 0, g = 0, b = 0, grey;
|
||||
unsigned char *p = cursor->richSource+j*width+i*bpp;
|
||||
if (bpp == 1) {
|
||||
unsigned char* uc = (unsigned char*) p;
|
||||
SETRGB(uc);
|
||||
} else if (bpp == 2) {
|
||||
unsigned short* us = (unsigned short*) p;
|
||||
SETRGB(us);
|
||||
} else if (bpp == 4) {
|
||||
unsigned int* ui = (unsigned int*) p;
|
||||
SETRGB(ui);
|
||||
}
|
||||
grey = (r + g + b) / 3;
|
||||
if (grey >= 128) {
|
||||
cursor->source[j*w+i/8]|=bit;
|
||||
#ifdef DEBUG_CURSOR
|
||||
fprintf(stderr, "1");
|
||||
} else {
|
||||
fprintf(stderr, "0");
|
||||
#endif
|
||||
}
|
||||
|
||||
} else if(memcmp(cursor->richSource+j*width+i*bpp, back, bpp)) {
|
||||
cursor->source[j*w+i/8]|=bit;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_CURSOR
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
|
||||
{
|
||||
rfbPixelFormat* format=&rfbScreen->serverFormat;
|
||||
int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8;
|
||||
uint32_t background,foreground;
|
||||
char *back=(char*)&background,*fore=(char*)&foreground;
|
||||
unsigned char *cp;
|
||||
unsigned char bit;
|
||||
|
||||
if(cursor->richSource && cursor->cleanupRichSource)
|
||||
free(cursor->richSource);
|
||||
cp=cursor->richSource=(unsigned char*)calloc((size_t)cursor->width*bpp,cursor->height);
|
||||
if(!cp)
|
||||
return;
|
||||
cursor->cleanupRichSource=TRUE;
|
||||
|
||||
if(format->bigEndian) {
|
||||
back+=4-bpp;
|
||||
fore+=4-bpp;
|
||||
}
|
||||
|
||||
background=(uint32_t)cursor->backRed<<format->redShift|
|
||||
(uint32_t)cursor->backGreen<<format->greenShift|(uint32_t)cursor->backBlue<<format->blueShift;
|
||||
foreground=(uint32_t)cursor->foreRed<<format->redShift|
|
||||
(uint32_t)cursor->foreGreen<<format->greenShift|(uint32_t)cursor->foreBlue<<format->blueShift;
|
||||
|
||||
for(j=0;j<cursor->height;j++)
|
||||
for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp)
|
||||
if(cursor->source[j*w+i/8]&bit) memcpy(cp,fore,bpp);
|
||||
else memcpy(cp,back,bpp);
|
||||
}
|
||||
|
||||
/* functions to draw/hide cursor directly in the frame buffer */
|
||||
|
||||
void rfbHideCursor(rfbClientPtr cl)
|
||||
{
|
||||
rfbScreenInfoPtr s=cl->screen;
|
||||
rfbCursorPtr c;
|
||||
int j,x1,x2,y1,y2,bpp=s->serverFormat.bitsPerPixel/8,
|
||||
rowstride=s->paddedWidthInBytes;
|
||||
LOCK(s->cursorMutex);
|
||||
c=s->cursor;
|
||||
if(!c) {
|
||||
UNLOCK(s->cursorMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
/* restore what is under the cursor */
|
||||
x1=cl->cursorX-c->xhot;
|
||||
x2=x1+c->width;
|
||||
if(x1<0) x1=0;
|
||||
if(x2>=s->width) x2=s->width-1;
|
||||
x2-=x1; if(x2<=0) {
|
||||
UNLOCK(s->cursorMutex);
|
||||
return;
|
||||
}
|
||||
y1=cl->cursorY-c->yhot;
|
||||
y2=y1+c->height;
|
||||
if(y1<0) y1=0;
|
||||
if(y2>=s->height) y2=s->height-1;
|
||||
y2-=y1; if(y2<=0) {
|
||||
UNLOCK(s->cursorMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get saved data */
|
||||
for(j=0;j<y2;j++)
|
||||
memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp,
|
||||
s->underCursorBuffer+j*x2*bpp,
|
||||
(size_t)x2*bpp);
|
||||
|
||||
/* Copy to all scaled versions */
|
||||
rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
|
||||
|
||||
UNLOCK(s->cursorMutex);
|
||||
}
|
||||
|
||||
void rfbShowCursor(rfbClientPtr cl)
|
||||
{
|
||||
rfbScreenInfoPtr s=cl->screen;
|
||||
rfbCursorPtr c;
|
||||
int i,j,x1,x2,y1,y2,i1,j1,bpp=s->serverFormat.bitsPerPixel/8,
|
||||
rowstride=s->paddedWidthInBytes,
|
||||
bufSize,w;
|
||||
rfbBool wasChanged=FALSE;
|
||||
|
||||
LOCK(s->cursorMutex);
|
||||
c=s->cursor;
|
||||
if(!c) {
|
||||
UNLOCK(s->cursorMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
bufSize=c->width*c->height*bpp;
|
||||
w=(c->width+7)/8;
|
||||
if(s->underCursorBufferLen<bufSize) {
|
||||
if(s->underCursorBuffer!=NULL)
|
||||
free(s->underCursorBuffer);
|
||||
s->underCursorBuffer=malloc(bufSize);
|
||||
s->underCursorBufferLen=bufSize;
|
||||
}
|
||||
|
||||
/* save what is under the cursor */
|
||||
i1=j1=0; /* offset in cursor */
|
||||
x1=cl->cursorX-c->xhot;
|
||||
x2=x1+c->width;
|
||||
if(x1<0) { i1=-x1; x1=0; }
|
||||
if(x2>=s->width) x2=s->width-1;
|
||||
x2-=x1; if(x2<=0) {
|
||||
UNLOCK(s->cursorMutex);
|
||||
return; /* nothing to do */
|
||||
}
|
||||
|
||||
y1=cl->cursorY-c->yhot;
|
||||
y2=y1+c->height;
|
||||
if(y1<0) { j1=-y1; y1=0; }
|
||||
if(y2>=s->height) y2=s->height-1;
|
||||
y2-=y1; if(y2<=0) {
|
||||
UNLOCK(s->cursorMutex);
|
||||
return; /* nothing to do */
|
||||
}
|
||||
|
||||
/* save data */
|
||||
for(j=0;j<y2;j++) {
|
||||
char* dest=s->underCursorBuffer+j*x2*bpp;
|
||||
const char* src=s->frameBuffer+(y1+j)*rowstride+x1*bpp;
|
||||
unsigned int count=x2*bpp;
|
||||
if(wasChanged || memcmp(dest,src,count)) {
|
||||
wasChanged=TRUE;
|
||||
memcpy(dest,src,count);
|
||||
}
|
||||
}
|
||||
|
||||
if(!c->richSource)
|
||||
rfbMakeRichCursorFromXCursor(s,c);
|
||||
|
||||
if (c->alphaSource) {
|
||||
int rmax, rshift;
|
||||
int gmax, gshift;
|
||||
int bmax, bshift;
|
||||
int amax = 255; /* alphaSource is always 8bits of info per pixel */
|
||||
unsigned int rmask, gmask, bmask;
|
||||
|
||||
rmax = s->serverFormat.redMax;
|
||||
gmax = s->serverFormat.greenMax;
|
||||
bmax = s->serverFormat.blueMax;
|
||||
rshift = s->serverFormat.redShift;
|
||||
gshift = s->serverFormat.greenShift;
|
||||
bshift = s->serverFormat.blueShift;
|
||||
|
||||
rmask = (rmax << rshift);
|
||||
gmask = (gmax << gshift);
|
||||
bmask = (bmax << bshift);
|
||||
|
||||
for(j=0;j<y2;j++) {
|
||||
for(i=0;i<x2;i++) {
|
||||
/*
|
||||
* we loop over the whole cursor ignoring c->mask[],
|
||||
* using the extracted alpha value instead.
|
||||
*/
|
||||
char *dest;
|
||||
unsigned char *src, *aptr;
|
||||
unsigned int val, dval, sval;
|
||||
int rdst, gdst, bdst; /* fb RGB */
|
||||
int asrc, rsrc, gsrc, bsrc; /* rich source ARGB */
|
||||
|
||||
dest = s->frameBuffer + (j+y1)*rowstride + (i+x1)*bpp;
|
||||
src = c->richSource + (j+j1)*c->width*bpp + (i+i1)*bpp;
|
||||
aptr = c->alphaSource + (j+j1)*c->width + (i+i1);
|
||||
|
||||
asrc = *aptr;
|
||||
if (!asrc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bpp == 1) {
|
||||
dval = *((unsigned char*) dest);
|
||||
sval = *((unsigned char*) src);
|
||||
} else if (bpp == 2) {
|
||||
dval = *((unsigned short*) dest);
|
||||
sval = *((unsigned short*) src);
|
||||
} else if (bpp == 3) {
|
||||
unsigned char *dst = (unsigned char *) dest;
|
||||
dval = 0;
|
||||
dval |= ((*(dst+0)) << 0);
|
||||
dval |= ((*(dst+1)) << 8);
|
||||
dval |= ((*(dst+2)) << 16);
|
||||
sval = 0;
|
||||
sval |= ((*(src+0)) << 0);
|
||||
sval |= ((*(src+1)) << 8);
|
||||
sval |= ((*(src+2)) << 16);
|
||||
} else if (bpp == 4) {
|
||||
dval = *((unsigned int*) dest);
|
||||
sval = *((unsigned int*) src);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* extract dest and src RGB */
|
||||
rdst = (dval & rmask) >> rshift; /* fb */
|
||||
gdst = (dval & gmask) >> gshift;
|
||||
bdst = (dval & bmask) >> bshift;
|
||||
|
||||
rsrc = (sval & rmask) >> rshift; /* richcursor */
|
||||
gsrc = (sval & gmask) >> gshift;
|
||||
bsrc = (sval & bmask) >> bshift;
|
||||
|
||||
/* blend in fb data. */
|
||||
if (! c->alphaPreMultiplied) {
|
||||
rsrc = (asrc * rsrc)/amax;
|
||||
gsrc = (asrc * gsrc)/amax;
|
||||
bsrc = (asrc * bsrc)/amax;
|
||||
}
|
||||
rdst = rsrc + ((amax - asrc) * rdst)/amax;
|
||||
gdst = gsrc + ((amax - asrc) * gdst)/amax;
|
||||
bdst = bsrc + ((amax - asrc) * bdst)/amax;
|
||||
|
||||
val = 0;
|
||||
val |= (rdst << rshift);
|
||||
val |= (gdst << gshift);
|
||||
val |= (bdst << bshift);
|
||||
|
||||
/* insert the cooked pixel into the fb */
|
||||
memcpy(dest, &val, bpp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* now the cursor has to be drawn */
|
||||
for(j=0;j<y2;j++)
|
||||
for(i=0;i<x2;i++)
|
||||
if((c->mask[(j+j1)*w+(i+i1)/8]<<((i+i1)&7))&0x80)
|
||||
memcpy(s->frameBuffer+(j+y1)*rowstride+(i+x1)*bpp,
|
||||
c->richSource+(j+j1)*c->width*bpp+(i+i1)*bpp,bpp);
|
||||
}
|
||||
|
||||
/* Copy to all scaled versions */
|
||||
rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
|
||||
|
||||
UNLOCK(s->cursorMutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* If enableCursorShapeUpdates is FALSE, and the cursor is hidden, make sure
|
||||
* that if the frameBuffer was transmitted with a cursor drawn, then that
|
||||
* region gets redrawn.
|
||||
*/
|
||||
|
||||
void rfbRedrawAfterHideCursor(rfbClientPtr cl,sraRegionPtr updateRegion)
|
||||
{
|
||||
rfbScreenInfoPtr s = cl->screen;
|
||||
rfbCursorPtr c = s->cursor;
|
||||
|
||||
if(c) {
|
||||
int x,y,x2,y2;
|
||||
|
||||
x = cl->cursorX-c->xhot;
|
||||
y = cl->cursorY-c->yhot;
|
||||
x2 = x+c->width;
|
||||
y2 = y+c->height;
|
||||
|
||||
if(sraClipRect2(&x,&y,&x2,&y2,0,0,s->width,s->height)) {
|
||||
sraRegionPtr rect;
|
||||
rect = sraRgnCreateRect(x,y,x2,y2);
|
||||
if(updateRegion) {
|
||||
sraRgnOr(updateRegion,rect);
|
||||
} else {
|
||||
LOCK(cl->updateMutex);
|
||||
sraRgnOr(cl->modifiedRegion,rect);
|
||||
UNLOCK(cl->updateMutex);
|
||||
}
|
||||
sraRgnDestroy(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static void rfbPrintXCursor(rfbCursorPtr cursor)
|
||||
{
|
||||
int i,i1,j,w=(cursor->width+7)/8;
|
||||
unsigned char bit;
|
||||
for(j=0;j<cursor->height;j++) {
|
||||
for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
|
||||
if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' ');
|
||||
putchar(':');
|
||||
for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
|
||||
if(cursor->mask[j*w+i]&bit) putchar('#'); else putchar(' ');
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)
|
||||
{
|
||||
rfbClientIteratorPtr iterator;
|
||||
rfbClientPtr cl;
|
||||
|
||||
LOCK(rfbScreen->cursorMutex);
|
||||
|
||||
if(rfbScreen->cursor) {
|
||||
iterator=rfbGetClientIterator(rfbScreen);
|
||||
while((cl=rfbClientIteratorNext(iterator)))
|
||||
if(!cl->enableCursorShapeUpdates)
|
||||
rfbRedrawAfterHideCursor(cl,NULL);
|
||||
rfbReleaseClientIterator(iterator);
|
||||
|
||||
if(rfbScreen->cursor->cleanup)
|
||||
rfbFreeCursor(rfbScreen->cursor);
|
||||
}
|
||||
|
||||
rfbScreen->cursor = c;
|
||||
|
||||
iterator=rfbGetClientIterator(rfbScreen);
|
||||
while((cl=rfbClientIteratorNext(iterator))) {
|
||||
cl->cursorWasChanged = TRUE;
|
||||
if(!cl->enableCursorShapeUpdates)
|
||||
rfbRedrawAfterHideCursor(cl,NULL);
|
||||
}
|
||||
rfbReleaseClientIterator(iterator);
|
||||
|
||||
UNLOCK(rfbScreen->cursorMutex);
|
||||
}
|
||||
|
||||
38
android/extern/libvncserver/src/libvncserver/cutpaste.c
vendored
Normal file
38
android/extern/libvncserver/src/libvncserver/cutpaste.c
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* cutpaste.c - routines to deal with cut & paste buffers / selection.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
|
||||
/*
|
||||
* rfbSetXCutText sets the cut buffer to be the given string. We also clear
|
||||
* the primary selection. Ideally we'd like to set it to the same thing, but I
|
||||
* can't work out how to do that without some kind of helper X client.
|
||||
*/
|
||||
|
||||
void rfbGotXCutText(rfbScreenInfoPtr rfbScreen, char *str, int len)
|
||||
{
|
||||
rfbSendServerCutText(rfbScreen, str, len);
|
||||
}
|
||||
61
android/extern/libvncserver/src/libvncserver/draw.c
vendored
Normal file
61
android/extern/libvncserver/src/libvncserver/draw.c
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
void rfbFillRect(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2,rfbPixel col)
|
||||
{
|
||||
int rowstride = s->paddedWidthInBytes, bpp = s->bitsPerPixel>>3;
|
||||
int i,j;
|
||||
char* colour=(char*)&col;
|
||||
|
||||
if(!rfbEndianTest)
|
||||
colour += 4-bpp;
|
||||
for(j=y1;j<y2;j++)
|
||||
for(i=x1;i<x2;i++)
|
||||
memcpy(s->frameBuffer+j*rowstride+i*bpp,colour,bpp);
|
||||
rfbMarkRectAsModified(s,x1,y1,x2,y2);
|
||||
}
|
||||
|
||||
#define SETPIXEL(x,y) \
|
||||
memcpy(s->frameBuffer+(y)*rowstride+(x)*bpp,colour,bpp)
|
||||
|
||||
void rfbDrawPixel(rfbScreenInfoPtr s,int x,int y,rfbPixel col)
|
||||
{
|
||||
int rowstride = s->paddedWidthInBytes, bpp = s->bitsPerPixel>>3;
|
||||
char* colour=(char*)&col;
|
||||
|
||||
if(!rfbEndianTest)
|
||||
colour += 4-bpp;
|
||||
SETPIXEL(x,y);
|
||||
rfbMarkRectAsModified(s,x,y,x+1,y+1);
|
||||
}
|
||||
|
||||
void rfbDrawLine(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2,rfbPixel col)
|
||||
{
|
||||
int rowstride = s->paddedWidthInBytes, bpp = s->bitsPerPixel>>3;
|
||||
int i;
|
||||
char* colour=(char*)&col;
|
||||
|
||||
if(!rfbEndianTest)
|
||||
colour += 4-bpp;
|
||||
|
||||
#define SWAPPOINTS { i=x1; x1=x2; x2=i; i=y1; y1=y2; y2=i; }
|
||||
if(abs(x1-x2)<abs(y1-y2)) {
|
||||
if(y1>y2)
|
||||
SWAPPOINTS
|
||||
for(i=y1;i<=y2;i++)
|
||||
SETPIXEL(x1+(i-y1)*(x2-x1)/(y2-y1),i);
|
||||
/* TODO: Maybe make this more intelligently? */
|
||||
if(x2<x1) { i=x1; x1=x2; x2=i; }
|
||||
rfbMarkRectAsModified(s,x1,y1,x2+1,y2+1);
|
||||
} else {
|
||||
if(x1>x2)
|
||||
SWAPPOINTS
|
||||
else if(x1==x2) {
|
||||
rfbDrawPixel(s,x1,y1,col);
|
||||
return;
|
||||
}
|
||||
for(i=x1;i<=x2;i++)
|
||||
SETPIXEL(i,y1+(i-x1)*(y2-y1)/(x2-x1));
|
||||
if(y2<y1) { i=y1; y1=y2; y2=i; }
|
||||
rfbMarkRectAsModified(s,x1,y1,x2+1,y2+1);
|
||||
}
|
||||
}
|
||||
203
android/extern/libvncserver/src/libvncserver/font.c
vendored
Normal file
203
android/extern/libvncserver/src/libvncserver/font.c
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
int rfbDrawChar(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
|
||||
int x,int y,unsigned char c,rfbPixel col)
|
||||
{
|
||||
int i,j,width,height;
|
||||
unsigned char* data=font->data+font->metaData[c*5];
|
||||
unsigned char d=*data;
|
||||
int rowstride=rfbScreen->paddedWidthInBytes;
|
||||
int bpp=rfbScreen->serverFormat.bitsPerPixel/8;
|
||||
char *colour=(char*)&col;
|
||||
|
||||
if(!rfbEndianTest)
|
||||
colour += 4-bpp;
|
||||
|
||||
width=font->metaData[c*5+1];
|
||||
height=font->metaData[c*5+2];
|
||||
x+=font->metaData[c*5+3];
|
||||
y+=-font->metaData[c*5+4]-height+1;
|
||||
|
||||
for(j=0;j<height;j++) {
|
||||
for(i=0;i<width;i++) {
|
||||
if((i&7)==0) {
|
||||
d=*data;
|
||||
data++;
|
||||
}
|
||||
if(d&0x80 && y+j >= 0 && y+j < rfbScreen->height &&
|
||||
x+i >= 0 && x+i < rfbScreen->width)
|
||||
memcpy(rfbScreen->frameBuffer+(y+j)*rowstride+(x+i)*bpp,colour,bpp);
|
||||
d<<=1;
|
||||
}
|
||||
/* if((i&7)!=0) data++; */
|
||||
}
|
||||
return(width);
|
||||
}
|
||||
|
||||
void rfbDrawString(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
|
||||
int x,int y,const char* string,rfbPixel colour)
|
||||
{
|
||||
while(*string) {
|
||||
x+=rfbDrawChar(rfbScreen,font,x,y,*string,colour);
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: these two functions need to be more efficient */
|
||||
/* if col==bcol, assume transparent background */
|
||||
int rfbDrawCharWithClip(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
|
||||
int x,int y,unsigned char c,
|
||||
int x1,int y1,int x2,int y2,
|
||||
rfbPixel col,rfbPixel bcol)
|
||||
{
|
||||
int i,j,width,height;
|
||||
unsigned char* data=font->data+font->metaData[c*5];
|
||||
unsigned char d;
|
||||
int rowstride=rfbScreen->paddedWidthInBytes;
|
||||
int bpp=rfbScreen->serverFormat.bitsPerPixel/8,extra_bytes=0;
|
||||
char* colour=(char*)&col;
|
||||
char* bcolour=(char*)&bcol;
|
||||
|
||||
if(!rfbEndianTest) {
|
||||
colour+=4-bpp;
|
||||
bcolour+=4-bpp;
|
||||
}
|
||||
|
||||
width=font->metaData[c*5+1];
|
||||
height=font->metaData[c*5+2];
|
||||
x+=font->metaData[c*5+3];
|
||||
y+=-font->metaData[c*5+4]-height+1;
|
||||
|
||||
/* after clipping, x2 will be count of bytes between rows,
|
||||
* x1 start of i, y1 start of j, width and height will be adjusted. */
|
||||
if(y1>y) { y1-=y; data+=(width+7)/8; height-=y1; y+=y1; } else y1=0;
|
||||
if(x1>x) { x1-=x; data+=x1; width-=x1; x+=x1; extra_bytes+=x1/8; } else x1=0;
|
||||
if(y2<y+height) height-=y+height-y2;
|
||||
if(x2<x+width) { extra_bytes+=(x1+width)/8-(x+width-x2+7)/8; width-=x+width-x2; }
|
||||
|
||||
d=*data;
|
||||
for(j=y1;j<height;j++) {
|
||||
if((x1&7)!=0)
|
||||
d=data[-1]; /* TODO: check if in this case extra_bytes is correct! */
|
||||
for(i=x1;i<width;i++) {
|
||||
if((i&7)==0) {
|
||||
d=*data;
|
||||
data++;
|
||||
}
|
||||
/* if(x+i>=x1 && x+i<x2 && y+j>=y1 && y+j<y2) */ {
|
||||
if(d&0x80) {
|
||||
memcpy(rfbScreen->frameBuffer+(y+j)*rowstride+(x+i)*bpp,
|
||||
colour,bpp);
|
||||
} else if(bcol!=col) {
|
||||
memcpy(rfbScreen->frameBuffer+(y+j)*rowstride+(x+i)*bpp,
|
||||
bcolour,bpp);
|
||||
}
|
||||
}
|
||||
d<<=1;
|
||||
}
|
||||
/* if((i&7)==0) data++; */
|
||||
data += extra_bytes;
|
||||
}
|
||||
return(width);
|
||||
}
|
||||
|
||||
void rfbDrawStringWithClip(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
|
||||
int x,int y,const char* string,
|
||||
int x1,int y1,int x2,int y2,
|
||||
rfbPixel colour,rfbPixel backColour)
|
||||
{
|
||||
while(*string) {
|
||||
x+=rfbDrawCharWithClip(rfbScreen,font,x,y,*string,x1,y1,x2,y2,
|
||||
colour,backColour);
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
int rfbWidthOfString(rfbFontDataPtr font,const char* string)
|
||||
{
|
||||
int i=0;
|
||||
while(*string) {
|
||||
i+=font->metaData[*string*5+1];
|
||||
string++;
|
||||
}
|
||||
return(i);
|
||||
}
|
||||
|
||||
int rfbWidthOfChar(rfbFontDataPtr font,unsigned char c)
|
||||
{
|
||||
return(font->metaData[c*5+1]+font->metaData[c*5+3]);
|
||||
}
|
||||
|
||||
void rfbFontBBox(rfbFontDataPtr font,unsigned char c,int* x1,int* y1,int* x2,int* y2)
|
||||
{
|
||||
*x1+=font->metaData[c*5+3];
|
||||
*y1+=-font->metaData[c*5+4]-font->metaData[c*5+2]+1;
|
||||
*x2=*x1+font->metaData[c*5+1]+1;
|
||||
*y2=*y1+font->metaData[c*5+2]+1;
|
||||
}
|
||||
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX 0x7fffffff
|
||||
#endif
|
||||
|
||||
void rfbWholeFontBBox(rfbFontDataPtr font,
|
||||
int *x1, int *y1, int *x2, int *y2)
|
||||
{
|
||||
int i;
|
||||
int* m=font->metaData;
|
||||
|
||||
(*x1)=(*y1)=INT_MAX; (*x2)=(*y2)=1-(INT_MAX);
|
||||
for(i=0;i<256;i++) {
|
||||
if(m[i*5+1]-m[i*5+3]>(*x2))
|
||||
(*x2)=m[i*5+1]-m[i*5+3];
|
||||
if(-m[i*5+2]+m[i*5+4]<(*y1))
|
||||
(*y1)=-m[i*5+2]+m[i*5+4];
|
||||
if(m[i*5+3]<(*x1))
|
||||
(*x1)=m[i*5+3];
|
||||
if(-m[i*5+4]>(*y2))
|
||||
(*y2)=-m[i*5+4];
|
||||
}
|
||||
(*x2)++;
|
||||
(*y2)++;
|
||||
}
|
||||
|
||||
rfbFontDataPtr rfbLoadConsoleFont(char *filename)
|
||||
{
|
||||
FILE *f=fopen(filename,"rb");
|
||||
rfbFontDataPtr p;
|
||||
int i;
|
||||
|
||||
if(!f) return NULL;
|
||||
|
||||
p=(rfbFontDataPtr)malloc(sizeof(rfbFontData));
|
||||
if(!p) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p->data=(unsigned char*)malloc(4096);
|
||||
p->metaData=(int*)malloc(256*5*sizeof(int));
|
||||
if(!p->data || !p->metaData || 1!=fread(p->data,4096,1,f)) {
|
||||
free(p->data);
|
||||
free(p->metaData);
|
||||
free(p);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
fclose(f);
|
||||
for(i=0;i<256;i++) {
|
||||
p->metaData[i*5+0]=i*16; /* offset */
|
||||
p->metaData[i*5+1]=8; /* width */
|
||||
p->metaData[i*5+2]=16; /* height */
|
||||
p->metaData[i*5+3]=0; /* xhot */
|
||||
p->metaData[i*5+4]=0; /* yhot */
|
||||
}
|
||||
return(p);
|
||||
}
|
||||
|
||||
void rfbFreeFont(rfbFontDataPtr f)
|
||||
{
|
||||
free(f->data);
|
||||
free(f->metaData);
|
||||
free(f);
|
||||
}
|
||||
342
android/extern/libvncserver/src/libvncserver/hextile.c
vendored
Normal file
342
android/extern/libvncserver/src/libvncserver/hextile.c
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* hextile.c
|
||||
*
|
||||
* Routines to implement Hextile Encoding
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
static rfbBool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h);
|
||||
static rfbBool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h);
|
||||
static rfbBool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h);
|
||||
|
||||
|
||||
/*
|
||||
* rfbSendRectEncodingHextile - send a rectangle using hextile encoding.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSendRectEncodingHextile(rfbClientPtr cl,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
|
||||
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rect.r.x = Swap16IfLE(x);
|
||||
rect.r.y = Swap16IfLE(y);
|
||||
rect.r.w = Swap16IfLE(w);
|
||||
rect.r.h = Swap16IfLE(h);
|
||||
rect.encoding = Swap32IfLE(rfbEncodingHextile);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
|
||||
sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
rfbStatRecordEncodingSent(cl, rfbEncodingHextile,
|
||||
sz_rfbFramebufferUpdateRectHeader,
|
||||
sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
|
||||
|
||||
switch (cl->format.bitsPerPixel) {
|
||||
case 8:
|
||||
return sendHextiles8(cl, x, y, w, h);
|
||||
case 16:
|
||||
return sendHextiles16(cl, x, y, w, h);
|
||||
case 32:
|
||||
return sendHextiles32(cl, x, y, w, h);
|
||||
}
|
||||
|
||||
rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
#define PUT_PIXEL8(pix) (cl->updateBuf[cl->ublen++] = (pix))
|
||||
|
||||
#define PUT_PIXEL16(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
|
||||
cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1])
|
||||
|
||||
#define PUT_PIXEL32(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
|
||||
cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1], \
|
||||
cl->updateBuf[cl->ublen++] = ((char*)&(pix))[2], \
|
||||
cl->updateBuf[cl->ublen++] = ((char*)&(pix))[3])
|
||||
|
||||
|
||||
#define DEFINE_SEND_HEXTILES(bpp) \
|
||||
\
|
||||
\
|
||||
static rfbBool subrectEncode##bpp(rfbClientPtr cli, uint##bpp##_t *data, \
|
||||
int w, int h, uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono);\
|
||||
static void testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono, \
|
||||
rfbBool *solid, uint##bpp##_t *bg, uint##bpp##_t *fg); \
|
||||
\
|
||||
\
|
||||
/* \
|
||||
* rfbSendHextiles \
|
||||
*/ \
|
||||
\
|
||||
static rfbBool \
|
||||
sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) { \
|
||||
int x, y, w, h; \
|
||||
int startUblen; \
|
||||
char *fbptr; \
|
||||
uint##bpp##_t bg = 0, fg = 0, newBg, newFg; \
|
||||
rfbBool mono, solid; \
|
||||
rfbBool validBg = FALSE; \
|
||||
rfbBool validFg = FALSE; \
|
||||
uint##bpp##_t clientPixelData[16*16*(bpp/8)]; \
|
||||
\
|
||||
for (y = ry; y < ry+rh; y += 16) { \
|
||||
for (x = rx; x < rx+rw; x += 16) { \
|
||||
w = h = 16; \
|
||||
if (rx+rw - x < 16) \
|
||||
w = rx+rw - x; \
|
||||
if (ry+rh - y < 16) \
|
||||
h = ry+rh - y; \
|
||||
\
|
||||
if ((cl->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > \
|
||||
UPDATE_BUF_SIZE) { \
|
||||
if (!rfbSendUpdateBuf(cl)) \
|
||||
return FALSE; \
|
||||
} \
|
||||
\
|
||||
fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y) \
|
||||
+ (x * (cl->scaledScreen->bitsPerPixel / 8))); \
|
||||
\
|
||||
(*cl->translateFn)(cl->translateLookupTable, &(cl->screen->serverFormat), \
|
||||
&cl->format, fbptr, (char *)clientPixelData, \
|
||||
cl->scaledScreen->paddedWidthInBytes, w, h); \
|
||||
\
|
||||
startUblen = cl->ublen; \
|
||||
cl->updateBuf[startUblen] = 0; \
|
||||
cl->ublen++; \
|
||||
rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
|
||||
\
|
||||
testColours##bpp(clientPixelData, w * h, \
|
||||
&mono, &solid, &newBg, &newFg); \
|
||||
\
|
||||
if (!validBg || (newBg != bg)) { \
|
||||
validBg = TRUE; \
|
||||
bg = newBg; \
|
||||
cl->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \
|
||||
PUT_PIXEL##bpp(bg); \
|
||||
} \
|
||||
\
|
||||
if (solid) { \
|
||||
continue; \
|
||||
} \
|
||||
\
|
||||
cl->updateBuf[startUblen] |= rfbHextileAnySubrects; \
|
||||
\
|
||||
if (mono) { \
|
||||
if (!validFg || (newFg != fg)) { \
|
||||
validFg = TRUE; \
|
||||
fg = newFg; \
|
||||
cl->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
|
||||
PUT_PIXEL##bpp(fg); \
|
||||
} \
|
||||
} else { \
|
||||
validFg = FALSE; \
|
||||
cl->updateBuf[startUblen] |= rfbHextileSubrectsColoured; \
|
||||
} \
|
||||
\
|
||||
if (!subrectEncode##bpp(cl, clientPixelData, w, h, bg, fg, mono)) { \
|
||||
/* encoding was too large, use raw */ \
|
||||
validBg = FALSE; \
|
||||
validFg = FALSE; \
|
||||
cl->ublen = startUblen; \
|
||||
cl->updateBuf[cl->ublen++] = rfbHextileRaw; \
|
||||
(*cl->translateFn)(cl->translateLookupTable, \
|
||||
&(cl->screen->serverFormat), &cl->format, fbptr, \
|
||||
(char *)clientPixelData, \
|
||||
cl->scaledScreen->paddedWidthInBytes, w, h); \
|
||||
\
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)clientPixelData, \
|
||||
(size_t)w * h * (bpp/8)); \
|
||||
\
|
||||
cl->ublen += w * h * (bpp/8); \
|
||||
rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, \
|
||||
w * h * (bpp/8)); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return TRUE; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static rfbBool \
|
||||
subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h, \
|
||||
uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono) \
|
||||
{ \
|
||||
uint##bpp##_t cl2; \
|
||||
int x,y; \
|
||||
int i,j; \
|
||||
int hx=0,hy,vx=0,vy; \
|
||||
int hyflag; \
|
||||
uint##bpp##_t *seg; \
|
||||
uint##bpp##_t *line; \
|
||||
int hw,hh,vw,vh; \
|
||||
int thex,they,thew,theh; \
|
||||
int numsubs = 0; \
|
||||
int newLen; \
|
||||
int nSubrectsUblen; \
|
||||
\
|
||||
nSubrectsUblen = cl->ublen; \
|
||||
cl->ublen++; \
|
||||
rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
|
||||
\
|
||||
for (y=0; y<h; y++) { \
|
||||
line = data+(y*w); \
|
||||
for (x=0; x<w; x++) { \
|
||||
if (line[x] != bg) { \
|
||||
cl2 = line[x]; \
|
||||
hy = y-1; \
|
||||
hyflag = 1; \
|
||||
for (j=y; j<h; j++) { \
|
||||
seg = data+(j*w); \
|
||||
if (seg[x] != cl2) {break;} \
|
||||
i = x; \
|
||||
while ((i < w) && (seg[i] == cl2)) i += 1; \
|
||||
i -= 1; \
|
||||
if (j == y) vx = hx = i; \
|
||||
if (i < vx) vx = i; \
|
||||
if ((hyflag > 0) && (i >= hx)) { \
|
||||
hy += 1; \
|
||||
} else { \
|
||||
hyflag = 0; \
|
||||
} \
|
||||
} \
|
||||
vy = j-1; \
|
||||
\
|
||||
/* We now have two possible subrects: (x,y,hx,hy) and \
|
||||
* (x,y,vx,vy). We'll choose the bigger of the two. \
|
||||
*/ \
|
||||
hw = hx-x+1; \
|
||||
hh = hy-y+1; \
|
||||
vw = vx-x+1; \
|
||||
vh = vy-y+1; \
|
||||
\
|
||||
thex = x; \
|
||||
they = y; \
|
||||
\
|
||||
if ((hw*hh) > (vw*vh)) { \
|
||||
thew = hw; \
|
||||
theh = hh; \
|
||||
} else { \
|
||||
thew = vw; \
|
||||
theh = vh; \
|
||||
} \
|
||||
\
|
||||
if (mono) { \
|
||||
newLen = cl->ublen - nSubrectsUblen + 2; \
|
||||
} else { \
|
||||
newLen = cl->ublen - nSubrectsUblen + bpp/8 + 2; \
|
||||
} \
|
||||
\
|
||||
if (newLen > (w * h * (bpp/8))) \
|
||||
return FALSE; \
|
||||
\
|
||||
numsubs += 1; \
|
||||
\
|
||||
if (!mono) PUT_PIXEL##bpp(cl2); \
|
||||
\
|
||||
cl->updateBuf[cl->ublen++] = rfbHextilePackXY(thex,they); \
|
||||
cl->updateBuf[cl->ublen++] = rfbHextilePackWH(thew,theh); \
|
||||
rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
|
||||
\
|
||||
/* \
|
||||
* Now mark the subrect as done. \
|
||||
*/ \
|
||||
for (j=they; j < (they+theh); j++) { \
|
||||
for (i=thex; i < (thex+thew); i++) { \
|
||||
data[j*w+i] = bg; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
cl->updateBuf[nSubrectsUblen] = numsubs; \
|
||||
\
|
||||
return TRUE; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
/* \
|
||||
* testColours() tests if there are one (solid), two (mono) or more \
|
||||
* colours in a tile and gets a reasonable guess at the best background \
|
||||
* pixel, and the foreground pixel for mono. \
|
||||
*/ \
|
||||
\
|
||||
static void \
|
||||
testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono, rfbBool *solid, \
|
||||
uint##bpp##_t *bg, uint##bpp##_t *fg) { \
|
||||
uint##bpp##_t colour1 = 0, colour2 = 0; \
|
||||
int n1 = 0, n2 = 0; \
|
||||
*mono = TRUE; \
|
||||
*solid = TRUE; \
|
||||
\
|
||||
for (; size > 0; size--, data++) { \
|
||||
\
|
||||
if (n1 == 0) \
|
||||
colour1 = *data; \
|
||||
\
|
||||
if (*data == colour1) { \
|
||||
n1++; \
|
||||
continue; \
|
||||
} \
|
||||
\
|
||||
if (n2 == 0) { \
|
||||
*solid = FALSE; \
|
||||
colour2 = *data; \
|
||||
} \
|
||||
\
|
||||
if (*data == colour2) { \
|
||||
n2++; \
|
||||
continue; \
|
||||
} \
|
||||
\
|
||||
*mono = FALSE; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
if (n1 > n2) { \
|
||||
*bg = colour1; \
|
||||
*fg = colour2; \
|
||||
} else { \
|
||||
*bg = colour2; \
|
||||
*fg = colour1; \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_SEND_HEXTILES(8)
|
||||
DEFINE_SEND_HEXTILES(16)
|
||||
DEFINE_SEND_HEXTILES(32)
|
||||
666
android/extern/libvncserver/src/libvncserver/httpd.c
vendored
Normal file
666
android/extern/libvncserver/src/libvncserver/httpd.c
vendored
Normal file
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* httpd.c - a simple HTTP server
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org>
|
||||
* Copyright (C) 2002 RealVNC Ltd.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#define _POSIX_SOURCE
|
||||
#endif
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#ifdef LIBVNCSERVER_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef LIBVNCSERVER_HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#define strcasecmp _stricmp
|
||||
#if defined(_MSC_VER)
|
||||
#include <BaseTsd.h> /* For the missing ssize_t */
|
||||
#define ssize_t SSIZE_T
|
||||
#define read _read /* Prevent POSIX deprecation warnings */
|
||||
#endif
|
||||
#else
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include "sockets.h"
|
||||
|
||||
#ifdef USE_LIBWRAP
|
||||
#include <tcpd.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\nConnection: close\r\n\r\n" \
|
||||
"<HEAD><TITLE>File Not Found</TITLE></HEAD>\n" \
|
||||
"<BODY><H1>File Not Found</H1></BODY>\n"
|
||||
|
||||
#define INVALID_REQUEST_STR "HTTP/1.0 400 Invalid Request\r\nConnection: close\r\n\r\n" \
|
||||
"<HEAD><TITLE>Invalid Request</TITLE></HEAD>\n" \
|
||||
"<BODY><H1>Invalid request</H1></BODY>\n"
|
||||
|
||||
#define OK_STR "HTTP/1.0 200 OK\r\nConnection: close\r\n"
|
||||
|
||||
|
||||
static void httpProcessInput(rfbScreenInfoPtr screen);
|
||||
static rfbBool compareAndSkip(char **ptr, const char *str);
|
||||
static rfbBool parseParams(const char *request, char *result, int max_bytes);
|
||||
static rfbBool validateString(char *str);
|
||||
|
||||
#define BUF_SIZE 32768
|
||||
|
||||
static char buf[BUF_SIZE];
|
||||
static size_t buf_filled=0;
|
||||
|
||||
/*
|
||||
* httpInitSockets sets up the TCP socket to listen for HTTP connections.
|
||||
*/
|
||||
|
||||
void
|
||||
rfbHttpInitSockets(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
if (rfbScreen->httpInitDone)
|
||||
return;
|
||||
|
||||
rfbScreen->httpInitDone = TRUE;
|
||||
|
||||
if (!rfbScreen->httpDir)
|
||||
return;
|
||||
|
||||
if (rfbScreen->httpPort == 0) {
|
||||
rfbScreen->httpPort = rfbScreen->port-100;
|
||||
}
|
||||
|
||||
if ((rfbScreen->httpListenSock =
|
||||
rfbListenOnTCPPort(rfbScreen->httpPort, rfbScreen->listenInterface)) == RFB_INVALID_SOCKET) {
|
||||
rfbLogPerror("ListenOnTCPPort");
|
||||
return;
|
||||
}
|
||||
rfbLog("Listening for HTTP connections on TCP port %d\n", rfbScreen->httpPort);
|
||||
rfbLog(" URL http://%s:%d\n",rfbScreen->thisHost,rfbScreen->httpPort);
|
||||
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
if (rfbScreen->http6Port == 0) {
|
||||
rfbScreen->http6Port = rfbScreen->ipv6port-100;
|
||||
}
|
||||
|
||||
if ((rfbScreen->httpListen6Sock
|
||||
= rfbListenOnTCP6Port(rfbScreen->http6Port, rfbScreen->listen6Interface)) == RFB_INVALID_SOCKET) {
|
||||
/* ListenOnTCP6Port has its own detailed error printout */
|
||||
return;
|
||||
}
|
||||
rfbLog("Listening for HTTP connections on TCP6 port %d\n", rfbScreen->http6Port);
|
||||
rfbLog(" URL http://%s:%d\n",rfbScreen->thisHost,rfbScreen->http6Port);
|
||||
#endif
|
||||
}
|
||||
|
||||
void rfbHttpShutdownSockets(rfbScreenInfoPtr rfbScreen) {
|
||||
if(rfbScreen->httpSock>-1) {
|
||||
FD_CLR(rfbScreen->httpSock,&rfbScreen->allFds);
|
||||
rfbCloseSocket(rfbScreen->httpSock);
|
||||
rfbScreen->httpSock=RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if(rfbScreen->httpListenSock>-1) {
|
||||
FD_CLR(rfbScreen->httpListenSock,&rfbScreen->allFds);
|
||||
rfbCloseSocket(rfbScreen->httpListenSock);
|
||||
rfbScreen->httpListenSock=RFB_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if(rfbScreen->httpListen6Sock>-1) {
|
||||
FD_CLR(rfbScreen->httpListen6Sock,&rfbScreen->allFds);
|
||||
rfbCloseSocket(rfbScreen->httpListen6Sock);
|
||||
rfbScreen->httpListen6Sock=RFB_INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* httpCheckFds is called from ProcessInputEvents to check for input on the
|
||||
* HTTP socket(s). If there is input to process, httpProcessInput is called.
|
||||
*/
|
||||
|
||||
void
|
||||
rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
int nfds;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
struct sockaddr_storage addr;
|
||||
#else
|
||||
struct sockaddr_in addr;
|
||||
#endif
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
|
||||
if (!rfbScreen->httpDir)
|
||||
return;
|
||||
|
||||
if (rfbScreen->httpListenSock == RFB_INVALID_SOCKET)
|
||||
return;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(rfbScreen->httpListenSock, &fds);
|
||||
if (rfbScreen->httpListen6Sock != RFB_INVALID_SOCKET) {
|
||||
FD_SET(rfbScreen->httpListen6Sock, &fds);
|
||||
}
|
||||
if (rfbScreen->httpSock != RFB_INVALID_SOCKET) {
|
||||
FD_SET(rfbScreen->httpSock, &fds);
|
||||
}
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
nfds = select(rfbMax(rfbScreen->httpListen6Sock, rfbMax(rfbScreen->httpSock,rfbScreen->httpListenSock)) + 1, &fds, NULL, NULL, &tv);
|
||||
if (nfds == 0) {
|
||||
return;
|
||||
}
|
||||
if (nfds < 0) {
|
||||
#ifdef WIN32
|
||||
errno = WSAGetLastError();
|
||||
#endif
|
||||
if (errno != EINTR)
|
||||
rfbLogPerror("httpCheckFds: select");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((rfbScreen->httpSock != RFB_INVALID_SOCKET) && FD_ISSET(rfbScreen->httpSock, &fds)) {
|
||||
httpProcessInput(rfbScreen);
|
||||
}
|
||||
|
||||
if (FD_ISSET(rfbScreen->httpListenSock, &fds) || FD_ISSET(rfbScreen->httpListen6Sock, &fds)) {
|
||||
if (rfbScreen->httpSock != RFB_INVALID_SOCKET) rfbCloseSocket(rfbScreen->httpSock);
|
||||
|
||||
if(FD_ISSET(rfbScreen->httpListenSock, &fds)) {
|
||||
if ((rfbScreen->httpSock = accept(rfbScreen->httpListenSock, (struct sockaddr *)&addr, &addrlen)) == RFB_INVALID_SOCKET) {
|
||||
rfbLogPerror("httpCheckFds: accept");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(FD_ISSET(rfbScreen->httpListen6Sock, &fds)) {
|
||||
if ((rfbScreen->httpSock = accept(rfbScreen->httpListen6Sock, (struct sockaddr *)&addr, &addrlen)) == RFB_INVALID_SOCKET) {
|
||||
rfbLogPerror("httpCheckFds: accept");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_LIBWRAP
|
||||
char host[1024];
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) {
|
||||
rfbLogPerror("httpCheckFds: error in getnameinfo");
|
||||
host[0] = '\0';
|
||||
}
|
||||
#else
|
||||
memcpy(host, inet_ntoa(addr.sin_addr), sizeof(host));
|
||||
#endif
|
||||
if(!hosts_ctl("vnc",STRING_UNKNOWN, host,
|
||||
STRING_UNKNOWN)) {
|
||||
rfbLog("Rejected HTTP connection from client %s\n",
|
||||
host);
|
||||
rfbCloseSocket(rfbScreen->httpSock);
|
||||
rfbScreen->httpSock=RFB_INVALID_SOCKET;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if(!rfbSetNonBlocking(rfbScreen->httpSock)) {
|
||||
rfbCloseSocket(rfbScreen->httpSock);
|
||||
rfbScreen->httpSock=RFB_INVALID_SOCKET;
|
||||
return;
|
||||
}
|
||||
/*AddEnabledDevice(httpSock);*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
httpCloseSock(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
rfbCloseSocket(rfbScreen->httpSock);
|
||||
rfbScreen->httpSock = RFB_INVALID_SOCKET;
|
||||
buf_filled = 0;
|
||||
}
|
||||
|
||||
static rfbClientRec cl;
|
||||
|
||||
/*
|
||||
* httpProcessInput is called when input is received on the HTTP socket.
|
||||
*/
|
||||
|
||||
static void
|
||||
httpProcessInput(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
struct sockaddr_storage addr;
|
||||
#else
|
||||
struct sockaddr_in addr;
|
||||
#endif
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
char fullFname[512];
|
||||
char params[1024];
|
||||
char *ptr;
|
||||
char *fname;
|
||||
unsigned int maxFnameLen;
|
||||
FILE* fd;
|
||||
rfbBool performSubstitutions = FALSE;
|
||||
char str[256+32];
|
||||
#ifndef WIN32
|
||||
char* user=getenv("USER");
|
||||
#endif
|
||||
|
||||
cl.sock=rfbScreen->httpSock;
|
||||
|
||||
if (strlen(rfbScreen->httpDir) > 255) {
|
||||
rfbErr("-httpd directory too long\n");
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
strcpy(fullFname, rfbScreen->httpDir);
|
||||
fname = &fullFname[strlen(fullFname)];
|
||||
maxFnameLen = 511 - strlen(fullFname);
|
||||
|
||||
buf_filled=0;
|
||||
|
||||
/* Read data from the HTTP client until we get a complete request. */
|
||||
while (1) {
|
||||
ssize_t got;
|
||||
|
||||
if (buf_filled > sizeof (buf)) {
|
||||
rfbErr("httpProcessInput: HTTP request is too long\n");
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
got = read (rfbScreen->httpSock, buf + buf_filled,
|
||||
sizeof (buf) - buf_filled - 1);
|
||||
|
||||
if (got <= 0) {
|
||||
if (got == 0) {
|
||||
rfbErr("httpd: premature connection close\n");
|
||||
} else {
|
||||
#ifdef WIN32
|
||||
errno=WSAGetLastError();
|
||||
#endif
|
||||
if (errno == EAGAIN) {
|
||||
return;
|
||||
}
|
||||
rfbLogPerror("httpProcessInput: read");
|
||||
}
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
buf_filled += got;
|
||||
buf[buf_filled] = '\0';
|
||||
|
||||
/* Is it complete yet (is there a blank line)? */
|
||||
if (strstr (buf, "\r\r") || strstr (buf, "\n\n") ||
|
||||
strstr (buf, "\r\n\r\n") || strstr (buf, "\n\r\n\r"))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Process the request. */
|
||||
if(rfbScreen->httpEnableProxyConnect) {
|
||||
const static char* PROXY_OK_STR = "HTTP/1.0 200 OK\r\nContent-Type: octet-stream\r\nPragma: no-cache\r\n\r\n";
|
||||
if(!strncmp(buf, "CONNECT ", 8)) {
|
||||
if(atoi(strchr(buf, ':')+1)!=rfbScreen->port) {
|
||||
rfbErr("httpd: CONNECT format invalid.\n");
|
||||
rfbWriteExact(&cl,INVALID_REQUEST_STR, strlen(INVALID_REQUEST_STR));
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
/* proxy connection */
|
||||
rfbLog("httpd: client asked for CONNECT\n");
|
||||
rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
|
||||
rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
|
||||
rfbScreen->httpSock = RFB_INVALID_SOCKET;
|
||||
return;
|
||||
}
|
||||
if (!strncmp(buf, "GET ",4) && !strncmp(strchr(buf,'/'),"/proxied.connection HTTP/1.", 27)) {
|
||||
/* proxy connection */
|
||||
rfbLog("httpd: client asked for /proxied.connection\n");
|
||||
rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
|
||||
rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
|
||||
rfbScreen->httpSock = RFB_INVALID_SOCKET;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(buf, "GET ", 4)) {
|
||||
rfbErr("httpd: no GET line\n");
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
} else {
|
||||
/* Only use the first line. */
|
||||
buf[strcspn(buf, "\n\r")] = '\0';
|
||||
}
|
||||
|
||||
if (strlen(buf) > maxFnameLen) {
|
||||
rfbErr("httpd: GET line too long\n");
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "GET %s HTTP/1.", fname) != 1) {
|
||||
rfbErr("httpd: couldn't parse GET line\n");
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fname[0] != '/') {
|
||||
rfbErr("httpd: filename didn't begin with '/'\n");
|
||||
rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen);
|
||||
#ifdef LIBVNCSERVER_IPv6
|
||||
{
|
||||
char host[1024];
|
||||
if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) {
|
||||
rfbLogPerror("httpProcessInput: error in getnameinfo");
|
||||
}
|
||||
rfbLog("httpd: get '%s' for %s\n", fname+1, host);
|
||||
}
|
||||
#else
|
||||
rfbLog("httpd: get '%s' for %s\n", fname+1,
|
||||
inet_ntoa(addr.sin_addr));
|
||||
#endif
|
||||
|
||||
/* Extract parameters from the URL string if necessary */
|
||||
|
||||
params[0] = '\0';
|
||||
ptr = strchr(fname, '?');
|
||||
if (ptr != NULL) {
|
||||
*ptr = '\0';
|
||||
if (!parseParams(&ptr[1], params, 1024)) {
|
||||
params[0] = '\0';
|
||||
rfbErr("httpd: bad parameters in the URL\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Basic protection against directory traversal outside webroot */
|
||||
|
||||
if (strstr(fname, "..")) {
|
||||
rfbErr("httpd: URL should not contain '..'\n");
|
||||
rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we were asked for '/', actually read the file index.vnc */
|
||||
|
||||
if (strcmp(fname, "/") == 0) {
|
||||
strcpy(fname, "/index.vnc");
|
||||
rfbLog("httpd: defaulting to '%s'\n", fname+1);
|
||||
}
|
||||
|
||||
/* Substitutions are performed on files ending .vnc */
|
||||
|
||||
if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) {
|
||||
performSubstitutions = TRUE;
|
||||
}
|
||||
|
||||
/* Open the file */
|
||||
|
||||
if ((fd = fopen(fullFname, "r")) == 0) {
|
||||
rfbLogPerror("httpProcessInput: open");
|
||||
rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
rfbWriteExact(&cl, OK_STR, strlen(OK_STR));
|
||||
char *ext = strrchr(fname, '.');
|
||||
char *contentType = "";
|
||||
if(ext && strcasecmp(ext, ".vnc") == 0)
|
||||
contentType = "Content-Type: text/html\r\n";
|
||||
else if(ext && strcasecmp(ext, ".css") == 0)
|
||||
contentType = "Content-Type: text/css\r\n";
|
||||
else if(ext && strcasecmp(ext, ".svg") == 0)
|
||||
contentType = "Content-Type: image/svg+xml\r\n";
|
||||
else if(ext && strcasecmp(ext, ".js") == 0)
|
||||
contentType = "Content-Type: application/javascript\r\n";
|
||||
rfbWriteExact(&cl, contentType, strlen(contentType));
|
||||
/* end the header */
|
||||
rfbWriteExact(&cl, "\r\n", 2);
|
||||
|
||||
while (1) {
|
||||
int n = fread(buf, 1, BUF_SIZE-1, fd);
|
||||
if (n < 0) {
|
||||
rfbLogPerror("httpProcessInput: read");
|
||||
fclose(fd);
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
if (performSubstitutions) {
|
||||
|
||||
/* Substitute $WIDTH, $HEIGHT, etc with the appropriate values.
|
||||
This won't quite work properly if the .vnc file is longer than
|
||||
BUF_SIZE, but it's reasonable to assume that .vnc files will
|
||||
always be short. */
|
||||
|
||||
char *ptr = buf;
|
||||
char *dollar;
|
||||
buf[n] = 0; /* make sure it's null-terminated */
|
||||
|
||||
while ((dollar = strchr(ptr, '$'))!=NULL) {
|
||||
rfbWriteExact(&cl, ptr, (dollar - ptr));
|
||||
|
||||
ptr = dollar;
|
||||
|
||||
if (compareAndSkip(&ptr, "$WIDTH")) {
|
||||
|
||||
sprintf(str, "%d", rfbScreen->width);
|
||||
rfbWriteExact(&cl, str, strlen(str));
|
||||
|
||||
} else if (compareAndSkip(&ptr, "$HEIGHT")) {
|
||||
|
||||
sprintf(str, "%d", rfbScreen->height);
|
||||
rfbWriteExact(&cl, str, strlen(str));
|
||||
|
||||
} else if (compareAndSkip(&ptr, "$APPLETWIDTH")) {
|
||||
|
||||
sprintf(str, "%d", rfbScreen->width);
|
||||
rfbWriteExact(&cl, str, strlen(str));
|
||||
|
||||
} else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) {
|
||||
|
||||
sprintf(str, "%d", rfbScreen->height + 32);
|
||||
rfbWriteExact(&cl, str, strlen(str));
|
||||
|
||||
} else if (compareAndSkip(&ptr, "$PORT")) {
|
||||
|
||||
sprintf(str, "%d", rfbScreen->port);
|
||||
rfbWriteExact(&cl, str, strlen(str));
|
||||
|
||||
} else if (compareAndSkip(&ptr, "$DESKTOP")) {
|
||||
|
||||
rfbWriteExact(&cl, rfbScreen->desktopName, strlen(rfbScreen->desktopName));
|
||||
|
||||
} else if (compareAndSkip(&ptr, "$DISPLAY")) {
|
||||
|
||||
sprintf(str, "%s:%d", rfbScreen->thisHost, rfbScreen->port-5900);
|
||||
rfbWriteExact(&cl, str, strlen(str));
|
||||
|
||||
} else if (compareAndSkip(&ptr, "$USER")) {
|
||||
#ifndef WIN32
|
||||
if (user) {
|
||||
rfbWriteExact(&cl, user,
|
||||
strlen(user));
|
||||
} else
|
||||
#endif
|
||||
rfbWriteExact(&cl, "?", 1);
|
||||
} else if (compareAndSkip(&ptr, "$PARAMS")) {
|
||||
if (params[0] != '\0')
|
||||
rfbWriteExact(&cl, params, strlen(params));
|
||||
} else {
|
||||
if (!compareAndSkip(&ptr, "$$"))
|
||||
ptr++;
|
||||
|
||||
if (rfbWriteExact(&cl, "$", 1) < 0) {
|
||||
fclose(fd);
|
||||
httpCloseSock(rfbScreen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rfbWriteExact(&cl, ptr, (&buf[n] - ptr)) < 0)
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
/* For files not ending .vnc, just write out the buffer */
|
||||
|
||||
if (rfbWriteExact(&cl, buf, n) < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
httpCloseSock(rfbScreen);
|
||||
}
|
||||
|
||||
|
||||
static rfbBool
|
||||
compareAndSkip(char **ptr, const char *str)
|
||||
{
|
||||
if (strncmp(*ptr, str, strlen(str)) == 0) {
|
||||
*ptr += strlen(str);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the request tail after the '?' character, and format a sequence
|
||||
* of <param> tags for inclusion into an HTML page with embedded applet.
|
||||
*/
|
||||
|
||||
static rfbBool
|
||||
parseParams(const char *request, char *result, int max_bytes)
|
||||
{
|
||||
char param_request[128];
|
||||
char param_formatted[196];
|
||||
const char *tail;
|
||||
char *delim_ptr;
|
||||
char *value_str;
|
||||
int cur_bytes, len;
|
||||
|
||||
result[0] = '\0';
|
||||
cur_bytes = 0;
|
||||
|
||||
tail = request;
|
||||
for (;;) {
|
||||
/* Copy individual "name=value" string into a buffer */
|
||||
delim_ptr = strchr((char *)tail, '&');
|
||||
if (delim_ptr == NULL) {
|
||||
if (strlen(tail) >= sizeof(param_request)) {
|
||||
return FALSE;
|
||||
}
|
||||
strcpy(param_request, tail);
|
||||
} else {
|
||||
len = delim_ptr - tail;
|
||||
if (len >= sizeof(param_request)) {
|
||||
return FALSE;
|
||||
}
|
||||
memcpy(param_request, tail, len);
|
||||
param_request[len] = '\0';
|
||||
}
|
||||
|
||||
/* Split the request into parameter name and value */
|
||||
value_str = strchr(¶m_request[1], '=');
|
||||
if (value_str == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
*value_str++ = '\0';
|
||||
if (strlen(value_str) == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Validate both parameter name and value */
|
||||
if (!validateString(param_request) || !validateString(value_str)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Prepare HTML-formatted representation of the name=value pair */
|
||||
len = sprintf(param_formatted,
|
||||
"<PARAM NAME=\"%s\" VALUE=\"%s\">\n",
|
||||
param_request, value_str);
|
||||
if (cur_bytes + len + 1 > max_bytes) {
|
||||
return FALSE;
|
||||
}
|
||||
strcat(result, param_formatted);
|
||||
cur_bytes += len;
|
||||
|
||||
/* Go to the next parameter */
|
||||
if (delim_ptr == NULL) {
|
||||
break;
|
||||
}
|
||||
tail = delim_ptr + 1;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the string consists only of alphanumeric characters, '+'
|
||||
* signs, underscores, dots, colons and square brackets.
|
||||
* Replace all '+' signs with spaces.
|
||||
*/
|
||||
|
||||
static rfbBool
|
||||
validateString(char *str)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
for (ptr = str; *ptr != '\0'; ptr++) {
|
||||
if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.'
|
||||
&& *ptr != ':' && *ptr != '[' && *ptr != ']' ) {
|
||||
if (*ptr == '+') {
|
||||
*ptr = ' ';
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
13
android/extern/libvncserver/src/libvncserver/libvncserver.pc.cmakein
vendored
Normal file
13
android/extern/libvncserver/src/libvncserver/libvncserver.pc.cmakein
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_PREFIX@/include
|
||||
|
||||
Name: LibVNCServer
|
||||
Description: A library for easy implementation of a VNC server.
|
||||
Version: @LibVNCServer_VERSION@
|
||||
Requires:
|
||||
Requires.private:
|
||||
Libs: -L${libdir} -lvncserver
|
||||
Libs.private: @PRIVATE_LIBS@
|
||||
Cflags: -I${includedir}
|
||||
1376
android/extern/libvncserver/src/libvncserver/main.c
vendored
Normal file
1376
android/extern/libvncserver/src/libvncserver/main.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
32
android/extern/libvncserver/src/libvncserver/private.h
vendored
Normal file
32
android/extern/libvncserver/src/libvncserver/private.h
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef RFB_PRIVATE_H
|
||||
#define RFB_PRIVATE_H
|
||||
|
||||
/* from cursor.c */
|
||||
|
||||
void rfbShowCursor(rfbClientPtr cl);
|
||||
void rfbHideCursor(rfbClientPtr cl);
|
||||
void rfbRedrawAfterHideCursor(rfbClientPtr cl,sraRegionPtr updateRegion);
|
||||
|
||||
/* from main.c */
|
||||
|
||||
rfbClientPtr rfbClientIteratorHead(rfbClientIteratorPtr i);
|
||||
|
||||
/* from tight.c */
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
|
||||
extern void rfbFreeTightData(rfbClientPtr cl);
|
||||
#endif
|
||||
|
||||
/* from zrle.c */
|
||||
void rfbFreeZrleData(rfbClientPtr cl);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* from ultra.c */
|
||||
|
||||
extern void rfbFreeUltraData(rfbClientPtr cl);
|
||||
|
||||
#endif
|
||||
|
||||
890
android/extern/libvncserver/src/libvncserver/rfbregion.c
vendored
Normal file
890
android/extern/libvncserver/src/libvncserver/rfbregion.c
vendored
Normal file
@@ -0,0 +1,890 @@
|
||||
/* -=- sraRegion.c
|
||||
* Copyright (c) 2001 James "Wez" Weatherall, Johannes E. Schindelin
|
||||
*
|
||||
* A general purpose region clipping library
|
||||
* Only deals with rectangular regions, though.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/rfbregion.h>
|
||||
|
||||
/* -=- Internal Span structure */
|
||||
|
||||
struct sraRegion;
|
||||
|
||||
typedef struct sraSpan {
|
||||
struct sraSpan *_next;
|
||||
struct sraSpan *_prev;
|
||||
int start;
|
||||
int end;
|
||||
struct sraRegion *subspan;
|
||||
} sraSpan;
|
||||
|
||||
typedef struct sraRegion {
|
||||
sraSpan front;
|
||||
sraSpan back;
|
||||
} sraSpanList;
|
||||
|
||||
/* -=- Span routines */
|
||||
|
||||
sraSpanList *sraSpanListDup(const sraSpanList *src);
|
||||
void sraSpanListDestroy(sraSpanList *list);
|
||||
|
||||
static sraSpan *
|
||||
sraSpanCreate(int start, int end, const sraSpanList *subspan) {
|
||||
sraSpan *item = (sraSpan*)malloc(sizeof(sraSpan));
|
||||
if (!item) return NULL;
|
||||
item->_next = item->_prev = NULL;
|
||||
item->start = start;
|
||||
item->end = end;
|
||||
item->subspan = sraSpanListDup(subspan);
|
||||
return item;
|
||||
}
|
||||
|
||||
static sraSpan *
|
||||
sraSpanDup(const sraSpan *src) {
|
||||
sraSpan *span;
|
||||
if (!src) return NULL;
|
||||
span = sraSpanCreate(src->start, src->end, src->subspan);
|
||||
return span;
|
||||
}
|
||||
|
||||
static void
|
||||
sraSpanInsertAfter(sraSpan *newspan, sraSpan *after) {
|
||||
if(newspan && after) {
|
||||
newspan->_next = after->_next;
|
||||
newspan->_prev = after;
|
||||
after->_next->_prev = newspan;
|
||||
after->_next = newspan;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sraSpanInsertBefore(sraSpan *newspan, sraSpan *before) {
|
||||
if(newspan && before) {
|
||||
newspan->_next = before;
|
||||
newspan->_prev = before->_prev;
|
||||
before->_prev->_next = newspan;
|
||||
before->_prev = newspan;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sraSpanRemove(sraSpan *span) {
|
||||
if(span) {
|
||||
span->_prev->_next = span->_next;
|
||||
span->_next->_prev = span->_prev;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sraSpanDestroy(sraSpan *span) {
|
||||
if (span->subspan) sraSpanListDestroy(span->subspan);
|
||||
free(span);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
sraSpanCheck(const sraSpan *span, const char *text) {
|
||||
/* Check the span is valid! */
|
||||
if (span->start == span->end) {
|
||||
printf(text);
|
||||
printf(":%d-%d\n", span->start, span->end);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -=- SpanList routines */
|
||||
|
||||
static void sraSpanPrint(const sraSpan *s);
|
||||
|
||||
static void
|
||||
sraSpanListPrint(const sraSpanList *l) {
|
||||
sraSpan *curr;
|
||||
if (!l) {
|
||||
printf("NULL");
|
||||
return;
|
||||
}
|
||||
curr = l->front._next;
|
||||
printf("[");
|
||||
while (curr != &(l->back)) {
|
||||
sraSpanPrint(curr);
|
||||
curr = curr->_next;
|
||||
}
|
||||
printf("]");
|
||||
}
|
||||
|
||||
void
|
||||
sraSpanPrint(const sraSpan *s) {
|
||||
printf("(%d-%d)", (s->start), (s->end));
|
||||
if (s->subspan)
|
||||
sraSpanListPrint(s->subspan);
|
||||
}
|
||||
|
||||
static sraSpanList *
|
||||
sraSpanListCreate(void) {
|
||||
sraSpanList *item = (sraSpanList*)malloc(sizeof(sraSpanList));
|
||||
if (!item) return NULL;
|
||||
item->front._next = &(item->back);
|
||||
item->front._prev = NULL;
|
||||
item->back._prev = &(item->front);
|
||||
item->back._next = NULL;
|
||||
return item;
|
||||
}
|
||||
|
||||
sraSpanList *
|
||||
sraSpanListDup(const sraSpanList *src) {
|
||||
sraSpanList *newlist;
|
||||
sraSpan *newspan, *curr;
|
||||
|
||||
if (!src) return NULL;
|
||||
newlist = sraSpanListCreate();
|
||||
curr = src->front._next;
|
||||
while (curr != &(src->back)) {
|
||||
newspan = sraSpanDup(curr);
|
||||
sraSpanInsertBefore(newspan, &(newlist->back));
|
||||
curr = curr->_next;
|
||||
}
|
||||
|
||||
return newlist;
|
||||
}
|
||||
|
||||
void
|
||||
sraSpanListDestroy(sraSpanList *list) {
|
||||
sraSpan *curr;
|
||||
while (list->front._next != &(list->back)) {
|
||||
curr = list->front._next;
|
||||
sraSpanRemove(curr);
|
||||
sraSpanDestroy(curr);
|
||||
}
|
||||
free(list);
|
||||
}
|
||||
|
||||
static void
|
||||
sraSpanListMakeEmpty(sraSpanList *list) {
|
||||
sraSpan *curr;
|
||||
while (list->front._next != &(list->back)) {
|
||||
curr = list->front._next;
|
||||
sraSpanRemove(curr);
|
||||
sraSpanDestroy(curr);
|
||||
}
|
||||
list->front._next = &(list->back);
|
||||
list->front._prev = NULL;
|
||||
list->back._prev = &(list->front);
|
||||
list->back._next = NULL;
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
sraSpanListEqual(const sraSpanList *s1, const sraSpanList *s2) {
|
||||
sraSpan *sp1, *sp2;
|
||||
|
||||
if (!s1) {
|
||||
if (!s2) {
|
||||
return 1;
|
||||
} else {
|
||||
rfbErr("sraSpanListEqual:incompatible spans (only one NULL!)\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
sp1 = s1->front._next;
|
||||
sp2 = s2->front._next;
|
||||
while ((sp1 != &(s1->back)) &&
|
||||
(sp2 != &(s2->back))) {
|
||||
if ((sp1->start != sp2->start) ||
|
||||
(sp1->end != sp2->end) ||
|
||||
(!sraSpanListEqual(sp1->subspan, sp2->subspan))) {
|
||||
return 0;
|
||||
}
|
||||
sp1 = sp1->_next;
|
||||
sp2 = sp2->_next;
|
||||
}
|
||||
|
||||
if ((sp1 == &(s1->back)) && (sp2 == &(s2->back))) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
sraSpanListEmpty(const sraSpanList *list) {
|
||||
return (list->front._next == &(list->back));
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
sraSpanListCount(const sraSpanList *list) {
|
||||
sraSpan *curr = list->front._next;
|
||||
unsigned long count = 0;
|
||||
while (curr != &(list->back)) {
|
||||
if (curr->subspan) {
|
||||
count += sraSpanListCount(curr->subspan);
|
||||
} else {
|
||||
count += 1;
|
||||
}
|
||||
curr = curr->_next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
sraSpanMergePrevious(sraSpan *dest) {
|
||||
sraSpan *prev = dest->_prev;
|
||||
|
||||
while ((prev->_prev) &&
|
||||
(prev->end == dest->start) &&
|
||||
(sraSpanListEqual(prev->subspan, dest->subspan))) {
|
||||
/*
|
||||
printf("merge_prev:");
|
||||
sraSpanPrint(prev);
|
||||
printf(" & ");
|
||||
sraSpanPrint(dest);
|
||||
printf("\n");
|
||||
*/
|
||||
dest->start = prev->start;
|
||||
sraSpanRemove(prev);
|
||||
sraSpanDestroy(prev);
|
||||
prev = dest->_prev;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sraSpanMergeNext(sraSpan *dest) {
|
||||
sraSpan *next = dest->_next;
|
||||
while ((next->_next) &&
|
||||
(next->start == dest->end) &&
|
||||
(sraSpanListEqual(next->subspan, dest->subspan))) {
|
||||
/*
|
||||
printf("merge_next:");
|
||||
sraSpanPrint(dest);
|
||||
printf(" & ");
|
||||
sraSpanPrint(next);
|
||||
printf("\n");
|
||||
*/
|
||||
dest->end = next->end;
|
||||
sraSpanRemove(next);
|
||||
sraSpanDestroy(next);
|
||||
next = dest->_next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sraSpanListOr(sraSpanList *dest, const sraSpanList *src) {
|
||||
sraSpan *d_curr, *s_curr;
|
||||
int s_start, s_end;
|
||||
|
||||
if (!dest) {
|
||||
if (!src) {
|
||||
return;
|
||||
} else {
|
||||
rfbErr("sraSpanListOr:incompatible spans (only one NULL!)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
d_curr = dest->front._next;
|
||||
s_curr = src->front._next;
|
||||
s_start = s_curr->start;
|
||||
s_end = s_curr->end;
|
||||
while (s_curr != &(src->back)) {
|
||||
|
||||
/* - If we are at end of destination list OR
|
||||
If the new span comes before the next destination one */
|
||||
if ((d_curr == &(dest->back)) ||
|
||||
(d_curr->start >= s_end)) {
|
||||
/* - Add the span */
|
||||
sraSpanInsertBefore(sraSpanCreate(s_start, s_end,
|
||||
s_curr->subspan),
|
||||
d_curr);
|
||||
if (d_curr != &(dest->back))
|
||||
sraSpanMergePrevious(d_curr);
|
||||
s_curr = s_curr->_next;
|
||||
s_start = s_curr->start;
|
||||
s_end = s_curr->end;
|
||||
} else {
|
||||
|
||||
/* - If the new span overlaps the existing one */
|
||||
if ((s_start < d_curr->end) &&
|
||||
(s_end > d_curr->start)) {
|
||||
|
||||
/* - Insert new span before the existing destination one? */
|
||||
if (s_start < d_curr->start) {
|
||||
sraSpanInsertBefore(sraSpanCreate(s_start,
|
||||
d_curr->start,
|
||||
s_curr->subspan),
|
||||
d_curr);
|
||||
sraSpanMergePrevious(d_curr);
|
||||
}
|
||||
|
||||
/* Split the existing span if necessary */
|
||||
if (s_end < d_curr->end) {
|
||||
sraSpanInsertAfter(sraSpanCreate(s_end,
|
||||
d_curr->end,
|
||||
d_curr->subspan),
|
||||
d_curr);
|
||||
d_curr->end = s_end;
|
||||
}
|
||||
if (s_start > d_curr->start) {
|
||||
sraSpanInsertBefore(sraSpanCreate(d_curr->start,
|
||||
s_start,
|
||||
d_curr->subspan),
|
||||
d_curr);
|
||||
d_curr->start = s_start;
|
||||
}
|
||||
|
||||
/* Recursively OR subspans */
|
||||
sraSpanListOr(d_curr->subspan, s_curr->subspan);
|
||||
|
||||
/* Merge this span with previous or next? */
|
||||
if (d_curr->_prev != &(dest->front))
|
||||
sraSpanMergePrevious(d_curr);
|
||||
if (d_curr->_next != &(dest->back))
|
||||
sraSpanMergeNext(d_curr);
|
||||
|
||||
/* Move onto the next pair to compare */
|
||||
if (s_end > d_curr->end) {
|
||||
s_start = d_curr->end;
|
||||
d_curr = d_curr->_next;
|
||||
} else {
|
||||
s_curr = s_curr->_next;
|
||||
s_start = s_curr->start;
|
||||
s_end = s_curr->end;
|
||||
}
|
||||
} else {
|
||||
/* - No overlap. Move to the next destination span */
|
||||
d_curr = d_curr->_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
sraSpanListAnd(sraSpanList *dest, const sraSpanList *src) {
|
||||
sraSpan *d_curr, *s_curr, *d_next;
|
||||
|
||||
if (!dest) {
|
||||
if (!src) {
|
||||
return 1;
|
||||
} else {
|
||||
rfbErr("sraSpanListAnd:incompatible spans (only one NULL!)\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
d_curr = dest->front._next;
|
||||
s_curr = src->front._next;
|
||||
while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) {
|
||||
|
||||
/* - If we haven't reached a destination span yet then move on */
|
||||
if (d_curr->start >= s_curr->end) {
|
||||
s_curr = s_curr->_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* - If we are beyond the current destination span then remove it */
|
||||
if (d_curr->end <= s_curr->start) {
|
||||
sraSpan *next = d_curr->_next;
|
||||
sraSpanRemove(d_curr);
|
||||
sraSpanDestroy(d_curr);
|
||||
d_curr = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* - If we partially overlap a span then split it up or remove bits */
|
||||
if (s_curr->start > d_curr->start) {
|
||||
/* - The top bit of the span does not match */
|
||||
d_curr->start = s_curr->start;
|
||||
}
|
||||
if (s_curr->end < d_curr->end) {
|
||||
/* - The end of the span does not match */
|
||||
sraSpanInsertAfter(sraSpanCreate(s_curr->end,
|
||||
d_curr->end,
|
||||
d_curr->subspan),
|
||||
d_curr);
|
||||
d_curr->end = s_curr->end;
|
||||
}
|
||||
|
||||
/* - Now recursively process the affected span */
|
||||
if (!sraSpanListAnd(d_curr->subspan, s_curr->subspan)) {
|
||||
/* - The destination subspan is now empty, so we should remove it */
|
||||
sraSpan *next = d_curr->_next;
|
||||
sraSpanRemove(d_curr);
|
||||
sraSpanDestroy(d_curr);
|
||||
d_curr = next;
|
||||
} else {
|
||||
/* Merge this span with previous or next? */
|
||||
if (d_curr->_prev != &(dest->front))
|
||||
sraSpanMergePrevious(d_curr);
|
||||
|
||||
/* - Move on to the next span */
|
||||
d_next = d_curr;
|
||||
if (s_curr->end >= d_curr->end) {
|
||||
d_next = d_curr->_next;
|
||||
}
|
||||
if (s_curr->end <= d_curr->end) {
|
||||
s_curr = s_curr->_next;
|
||||
}
|
||||
d_curr = d_next;
|
||||
}
|
||||
}
|
||||
|
||||
while (d_curr != &(dest->back)) {
|
||||
sraSpan *next = d_curr->_next;
|
||||
sraSpanRemove(d_curr);
|
||||
sraSpanDestroy(d_curr);
|
||||
d_curr=next;
|
||||
}
|
||||
|
||||
return !sraSpanListEmpty(dest);
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
sraSpanListSubtract(sraSpanList *dest, const sraSpanList *src) {
|
||||
sraSpan *d_curr, *s_curr;
|
||||
|
||||
if (!dest) {
|
||||
if (!src) {
|
||||
return 1;
|
||||
} else {
|
||||
rfbErr("sraSpanListSubtract:incompatible spans (only one NULL!)\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
d_curr = dest->front._next;
|
||||
s_curr = src->front._next;
|
||||
while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) {
|
||||
|
||||
/* - If we haven't reached a destination span yet then move on */
|
||||
if (d_curr->start >= s_curr->end) {
|
||||
s_curr = s_curr->_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* - If we are beyond the current destination span then skip it */
|
||||
if (d_curr->end <= s_curr->start) {
|
||||
d_curr = d_curr->_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* - If we partially overlap the current span then split it up */
|
||||
if (s_curr->start > d_curr->start) {
|
||||
sraSpanInsertBefore(sraSpanCreate(d_curr->start,
|
||||
s_curr->start,
|
||||
d_curr->subspan),
|
||||
d_curr);
|
||||
d_curr->start = s_curr->start;
|
||||
}
|
||||
if (s_curr->end < d_curr->end) {
|
||||
sraSpanInsertAfter(sraSpanCreate(s_curr->end,
|
||||
d_curr->end,
|
||||
d_curr->subspan),
|
||||
d_curr);
|
||||
d_curr->end = s_curr->end;
|
||||
}
|
||||
|
||||
/* - Now recursively process the affected span */
|
||||
if ((!d_curr->subspan) || !sraSpanListSubtract(d_curr->subspan, s_curr->subspan)) {
|
||||
/* - The destination subspan is now empty, so we should remove it */
|
||||
sraSpan *next = d_curr->_next;
|
||||
sraSpanRemove(d_curr);
|
||||
sraSpanDestroy(d_curr);
|
||||
d_curr = next;
|
||||
} else {
|
||||
/* Merge this span with previous or next? */
|
||||
if (d_curr->_prev != &(dest->front))
|
||||
sraSpanMergePrevious(d_curr);
|
||||
if (d_curr->_next != &(dest->back))
|
||||
sraSpanMergeNext(d_curr);
|
||||
|
||||
/* - Move on to the next span */
|
||||
if (s_curr->end > d_curr->end) {
|
||||
d_curr = d_curr->_next;
|
||||
} else {
|
||||
s_curr = s_curr->_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !sraSpanListEmpty(dest);
|
||||
}
|
||||
|
||||
/* -=- Region routines */
|
||||
|
||||
sraRegion *
|
||||
sraRgnCreate(void) {
|
||||
return (sraRegion*)sraSpanListCreate();
|
||||
}
|
||||
|
||||
sraRegion *
|
||||
sraRgnCreateRect(int x1, int y1, int x2, int y2) {
|
||||
sraSpanList *vlist, *hlist;
|
||||
sraSpan *vspan, *hspan;
|
||||
|
||||
/* - Build the horizontal portion of the span */
|
||||
hlist = sraSpanListCreate();
|
||||
hspan = sraSpanCreate(x1, x2, NULL);
|
||||
sraSpanInsertAfter(hspan, &(hlist->front));
|
||||
|
||||
/* - Build the vertical portion of the span */
|
||||
vlist = sraSpanListCreate();
|
||||
vspan = sraSpanCreate(y1, y2, hlist);
|
||||
sraSpanInsertAfter(vspan, &(vlist->front));
|
||||
|
||||
sraSpanListDestroy(hlist);
|
||||
|
||||
return (sraRegion*)vlist;
|
||||
}
|
||||
|
||||
sraRegion *
|
||||
sraRgnCreateRgn(const sraRegion *src) {
|
||||
return (sraRegion*)sraSpanListDup((sraSpanList*)src);
|
||||
}
|
||||
|
||||
void
|
||||
sraRgnDestroy(sraRegion *rgn) {
|
||||
sraSpanListDestroy((sraSpanList*)rgn);
|
||||
}
|
||||
|
||||
void
|
||||
sraRgnMakeEmpty(sraRegion *rgn) {
|
||||
sraSpanListMakeEmpty((sraSpanList*)rgn);
|
||||
}
|
||||
|
||||
/* -=- Boolean Region ops */
|
||||
|
||||
rfbBool
|
||||
sraRgnAnd(sraRegion *dst, const sraRegion *src) {
|
||||
return sraSpanListAnd((sraSpanList*)dst, (sraSpanList*)src);
|
||||
}
|
||||
|
||||
void
|
||||
sraRgnOr(sraRegion *dst, const sraRegion *src) {
|
||||
sraSpanListOr((sraSpanList*)dst, (sraSpanList*)src);
|
||||
}
|
||||
|
||||
rfbBool
|
||||
sraRgnSubtract(sraRegion *dst, const sraRegion *src) {
|
||||
return sraSpanListSubtract((sraSpanList*)dst, (sraSpanList*)src);
|
||||
}
|
||||
|
||||
void
|
||||
sraRgnOffset(sraRegion *dst, int dx, int dy) {
|
||||
sraSpan *vcurr, *hcurr;
|
||||
|
||||
vcurr = ((sraSpanList*)dst)->front._next;
|
||||
while (vcurr != &(((sraSpanList*)dst)->back)) {
|
||||
vcurr->start += dy;
|
||||
vcurr->end += dy;
|
||||
|
||||
hcurr = vcurr->subspan->front._next;
|
||||
while (hcurr != &(vcurr->subspan->back)) {
|
||||
hcurr->start += dx;
|
||||
hcurr->end += dx;
|
||||
hcurr = hcurr->_next;
|
||||
}
|
||||
|
||||
vcurr = vcurr->_next;
|
||||
}
|
||||
}
|
||||
|
||||
sraRegion *sraRgnBBox(const sraRegion *src) {
|
||||
int xmin=((unsigned int)(int)-1)>>1,ymin=xmin,xmax=1-xmin,ymax=xmax;
|
||||
sraSpan *vcurr, *hcurr;
|
||||
|
||||
if(!src)
|
||||
return sraRgnCreate();
|
||||
|
||||
vcurr = ((sraSpanList*)src)->front._next;
|
||||
while (vcurr != &(((sraSpanList*)src)->back)) {
|
||||
if(vcurr->start<ymin)
|
||||
ymin=vcurr->start;
|
||||
if(vcurr->end>ymax)
|
||||
ymax=vcurr->end;
|
||||
|
||||
hcurr = vcurr->subspan->front._next;
|
||||
while (hcurr != &(vcurr->subspan->back)) {
|
||||
if(hcurr->start<xmin)
|
||||
xmin=hcurr->start;
|
||||
if(hcurr->end>xmax)
|
||||
xmax=hcurr->end;
|
||||
hcurr = hcurr->_next;
|
||||
}
|
||||
|
||||
vcurr = vcurr->_next;
|
||||
}
|
||||
|
||||
if(xmax<xmin || ymax<ymin)
|
||||
return sraRgnCreate();
|
||||
|
||||
return sraRgnCreateRect(xmin,ymin,xmax,ymax);
|
||||
}
|
||||
|
||||
rfbBool
|
||||
sraRgnPopRect(sraRegion *rgn, sraRect *rect, unsigned long flags) {
|
||||
sraSpan *vcurr, *hcurr;
|
||||
sraSpan *vend, *hend;
|
||||
rfbBool right2left = (flags & 2) == 2;
|
||||
rfbBool bottom2top = (flags & 1) == 1;
|
||||
|
||||
/* - Pick correct order */
|
||||
if (bottom2top) {
|
||||
vcurr = ((sraSpanList*)rgn)->back._prev;
|
||||
vend = &(((sraSpanList*)rgn)->front);
|
||||
} else {
|
||||
vcurr = ((sraSpanList*)rgn)->front._next;
|
||||
vend = &(((sraSpanList*)rgn)->back);
|
||||
}
|
||||
|
||||
if (vcurr != vend) {
|
||||
rect->y1 = vcurr->start;
|
||||
rect->y2 = vcurr->end;
|
||||
|
||||
/* - Pick correct order */
|
||||
if (right2left) {
|
||||
hcurr = vcurr->subspan->back._prev;
|
||||
hend = &(vcurr->subspan->front);
|
||||
} else {
|
||||
hcurr = vcurr->subspan->front._next;
|
||||
hend = &(vcurr->subspan->back);
|
||||
}
|
||||
|
||||
if (hcurr != hend) {
|
||||
rect->x1 = hcurr->start;
|
||||
rect->x2 = hcurr->end;
|
||||
|
||||
sraSpanRemove(hcurr);
|
||||
sraSpanDestroy(hcurr);
|
||||
|
||||
if (sraSpanListEmpty(vcurr->subspan)) {
|
||||
sraSpanRemove(vcurr);
|
||||
sraSpanDestroy(vcurr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
printf("poprect:(%dx%d)-(%dx%d)\n",
|
||||
rect->x1, rect->y1, rect->x2, rect->y2);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
sraRgnCountRects(const sraRegion *rgn) {
|
||||
unsigned long count = sraSpanListCount((sraSpanList*)rgn);
|
||||
return count;
|
||||
}
|
||||
|
||||
rfbBool
|
||||
sraRgnEmpty(const sraRegion *rgn) {
|
||||
return sraSpanListEmpty((sraSpanList*)rgn);
|
||||
}
|
||||
|
||||
/* iterator stuff */
|
||||
sraRectangleIterator *sraRgnGetIterator(sraRegion *s)
|
||||
{
|
||||
/* these values have to be multiples of 4 */
|
||||
#define DEFSIZE 4
|
||||
#define DEFSTEP 8
|
||||
sraRectangleIterator *i =
|
||||
(sraRectangleIterator*)malloc(sizeof(sraRectangleIterator));
|
||||
if(!i)
|
||||
return NULL;
|
||||
|
||||
/* we have to recurse eventually. So, the first sPtr is the pointer to
|
||||
the sraSpan in the first level. the second sPtr is the pointer to
|
||||
the sraRegion.back. The third and fourth sPtr are for the second
|
||||
recursion level and so on. */
|
||||
i->sPtrs = (sraSpan**)malloc(sizeof(sraSpan*)*DEFSIZE);
|
||||
if(!i->sPtrs) {
|
||||
free(i);
|
||||
return NULL;
|
||||
}
|
||||
i->ptrSize = DEFSIZE;
|
||||
i->sPtrs[0] = &(s->front);
|
||||
i->sPtrs[1] = &(s->back);
|
||||
i->ptrPos = 0;
|
||||
i->reverseX = 0;
|
||||
i->reverseY = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
sraRectangleIterator *sraRgnGetReverseIterator(sraRegion *s,rfbBool reverseX,rfbBool reverseY)
|
||||
{
|
||||
sraRectangleIterator *i = sraRgnGetIterator(s);
|
||||
if(reverseY) {
|
||||
i->sPtrs[1] = &(s->front);
|
||||
i->sPtrs[0] = &(s->back);
|
||||
}
|
||||
i->reverseX = reverseX;
|
||||
i->reverseY = reverseY;
|
||||
return(i);
|
||||
}
|
||||
|
||||
static rfbBool sraReverse(sraRectangleIterator *i)
|
||||
{
|
||||
return( ((i->ptrPos&2) && i->reverseX) ||
|
||||
(!(i->ptrPos&2) && i->reverseY));
|
||||
}
|
||||
|
||||
static sraSpan* sraNextSpan(sraRectangleIterator *i)
|
||||
{
|
||||
if(sraReverse(i))
|
||||
return(i->sPtrs[i->ptrPos]->_prev);
|
||||
else
|
||||
return(i->sPtrs[i->ptrPos]->_next);
|
||||
}
|
||||
|
||||
rfbBool sraRgnIteratorNext(sraRectangleIterator* i,sraRect* r)
|
||||
{
|
||||
/* is the subspan finished? */
|
||||
while(sraNextSpan(i) == i->sPtrs[i->ptrPos+1]) {
|
||||
i->ptrPos -= 2;
|
||||
if(i->ptrPos < 0) /* the end */
|
||||
return(0);
|
||||
}
|
||||
|
||||
i->sPtrs[i->ptrPos] = sraNextSpan(i);
|
||||
|
||||
/* is this a new subspan? */
|
||||
while(i->sPtrs[i->ptrPos]->subspan) {
|
||||
if(i->ptrPos+2 > i->ptrSize) { /* array is too small */
|
||||
i->ptrSize += DEFSTEP;
|
||||
i->sPtrs = (sraSpan**)realloc(i->sPtrs, sizeof(sraSpan*)*i->ptrSize);
|
||||
}
|
||||
i->ptrPos += 2;
|
||||
if(sraReverse(i)) {
|
||||
i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->back._prev;
|
||||
i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->front);
|
||||
} else {
|
||||
i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->front._next;
|
||||
i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->back);
|
||||
}
|
||||
}
|
||||
|
||||
if((i->ptrPos%4)!=2) {
|
||||
rfbErr("sraRgnIteratorNext: offset is wrong (%d%%4!=2)\n",i->ptrPos);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
r->y1 = i->sPtrs[i->ptrPos-2]->start;
|
||||
r->y2 = i->sPtrs[i->ptrPos-2]->end;
|
||||
r->x1 = i->sPtrs[i->ptrPos]->start;
|
||||
r->x2 = i->sPtrs[i->ptrPos]->end;
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
void sraRgnReleaseIterator(sraRectangleIterator* i)
|
||||
{
|
||||
free(i->sPtrs);
|
||||
free(i);
|
||||
}
|
||||
|
||||
void
|
||||
sraRgnPrint(const sraRegion *rgn) {
|
||||
sraSpanListPrint((sraSpanList*)rgn);
|
||||
}
|
||||
|
||||
rfbBool
|
||||
sraClipRect(int *x, int *y, int *w, int *h,
|
||||
int cx, int cy, int cw, int ch) {
|
||||
if (*x < cx) {
|
||||
*w -= (cx-*x);
|
||||
*x = cx;
|
||||
}
|
||||
if (*y < cy) {
|
||||
*h -= (cy-*y);
|
||||
*y = cy;
|
||||
}
|
||||
if (*x+*w > cx+cw) {
|
||||
*w = (cx+cw)-*x;
|
||||
}
|
||||
if (*y+*h > cy+ch) {
|
||||
*h = (cy+ch)-*y;
|
||||
}
|
||||
return (*w>0) && (*h>0);
|
||||
}
|
||||
|
||||
rfbBool
|
||||
sraClipRect2(int *x, int *y, int *x2, int *y2,
|
||||
int cx, int cy, int cx2, int cy2) {
|
||||
if (*x < cx)
|
||||
*x = cx;
|
||||
if (*y < cy)
|
||||
*y = cy;
|
||||
if (*x >= cx2)
|
||||
*x = cx2-1;
|
||||
if (*y >= cy2)
|
||||
*y = cy2-1;
|
||||
if (*x2 <= cx)
|
||||
*x2 = cx+1;
|
||||
if (*y2 <= cy)
|
||||
*y2 = cy+1;
|
||||
if (*x2 > cx2)
|
||||
*x2 = cx2;
|
||||
if (*y2 > cy2)
|
||||
*y2 = cy2;
|
||||
return (*x2>*x) && (*y2>*y);
|
||||
}
|
||||
|
||||
/* test */
|
||||
|
||||
#ifdef SRA_TEST
|
||||
/* pipe the output to sort|uniq -u and you'll get the errors. */
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
sraRegionPtr region, region1, region2;
|
||||
sraRectangleIterator* i;
|
||||
sraRect rect;
|
||||
rfbBool b;
|
||||
|
||||
region = sraRgnCreateRect(10, 10, 600, 300);
|
||||
region1 = sraRgnCreateRect(40, 50, 350, 200);
|
||||
region2 = sraRgnCreateRect(0, 0, 20, 40);
|
||||
|
||||
sraRgnPrint(region);
|
||||
printf("\n[(10-300)[(10-600)]]\n\n");
|
||||
|
||||
b = sraRgnSubtract(region, region1);
|
||||
printf("%s ",b?"true":"false");
|
||||
sraRgnPrint(region);
|
||||
printf("\ntrue [(10-50)[(10-600)](50-200)[(10-40)(350-600)](200-300)[(10-600)]]\n\n");
|
||||
|
||||
sraRgnOr(region, region2);
|
||||
printf("%ld\n6\n\n", sraRgnCountRects(region));
|
||||
|
||||
i = sraRgnGetIterator(region);
|
||||
while(sraRgnIteratorNext(i, &rect))
|
||||
printf("%dx%d+%d+%d ",
|
||||
rect.x2-rect.x1,rect.y2-rect.y1,
|
||||
rect.x1,rect.y1);
|
||||
sraRgnReleaseIterator(i);
|
||||
printf("\n20x10+0+0 600x30+0+10 590x10+10+40 30x150+10+50 250x150+350+50 590x100+10+200 \n\n");
|
||||
|
||||
i = sraRgnGetReverseIterator(region,1,0);
|
||||
while(sraRgnIteratorNext(i, &rect))
|
||||
printf("%dx%d+%d+%d ",
|
||||
rect.x2-rect.x1,rect.y2-rect.y1,
|
||||
rect.x1,rect.y1);
|
||||
sraRgnReleaseIterator(i);
|
||||
printf("\n20x10+0+0 600x30+0+10 590x10+10+40 250x150+350+50 30x150+10+50 590x100+10+200 \n\n");
|
||||
|
||||
i = sraRgnGetReverseIterator(region,1,1);
|
||||
while(sraRgnIteratorNext(i, &rect))
|
||||
printf("%dx%d+%d+%d ",
|
||||
rect.x2-rect.x1,rect.y2-rect.y1,
|
||||
rect.x1,rect.y1);
|
||||
sraRgnReleaseIterator(i);
|
||||
printf("\n590x100+10+200 250x150+350+50 30x150+10+50 590x10+10+40 600x30+0+10 20x10+0+0 \n\n");
|
||||
|
||||
sraRgnDestroy(region);
|
||||
sraRgnDestroy(region1);
|
||||
sraRgnDestroy(region2);
|
||||
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
4168
android/extern/libvncserver/src/libvncserver/rfbserver.c
vendored
Normal file
4168
android/extern/libvncserver/src/libvncserver/rfbserver.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
15
android/extern/libvncserver/src/libvncserver/rfbssl.h
vendored
Normal file
15
android/extern/libvncserver/src/libvncserver/rfbssl.h
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _VNCSSL_H
|
||||
#define _VNCSSL_H 1
|
||||
|
||||
#include "rfb/rfb.h"
|
||||
#include "rfb/rfbconfig.h"
|
||||
|
||||
int rfbssl_init(rfbClientPtr cl);
|
||||
int rfbssl_pending(rfbClientPtr cl);
|
||||
int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize);
|
||||
int rfbssl_read(rfbClientPtr cl, char *buf, int bufsize);
|
||||
int rfbssl_write(rfbClientPtr cl, const char *buf, int bufsize);
|
||||
void rfbssl_destroy(rfbClientPtr cl);
|
||||
|
||||
|
||||
#endif /* _VNCSSL_H */
|
||||
272
android/extern/libvncserver/src/libvncserver/rfbssl_gnutls.c
vendored
Normal file
272
android/extern/libvncserver/src/libvncserver/rfbssl_gnutls.c
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* rfbssl_gnutls.c - Secure socket functions (gnutls version)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011 Gernot Tenchio
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include "rfbssl.h"
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct rfbssl_ctx {
|
||||
char peekbuf[2048];
|
||||
int peeklen;
|
||||
int peekstart;
|
||||
gnutls_session_t session;
|
||||
gnutls_certificate_credentials_t x509_cred;
|
||||
gnutls_dh_params_t dh_params;
|
||||
#ifdef I_LIKE_RSA_PARAMS_THAT_MUCH
|
||||
gnutls_rsa_params_t rsa_params;
|
||||
#endif
|
||||
};
|
||||
|
||||
void rfbssl_log_func(int level, const char *msg)
|
||||
{
|
||||
rfbErr("SSL: %s", msg);
|
||||
}
|
||||
|
||||
static void rfbssl_error(const char *msg, int e)
|
||||
{
|
||||
rfbErr("%s: %s (%ld)\n", msg, gnutls_strerror(e), e);
|
||||
}
|
||||
|
||||
static int rfbssl_init_session(struct rfbssl_ctx *ctx, int fd)
|
||||
{
|
||||
gnutls_session_t session;
|
||||
int ret;
|
||||
|
||||
if (GNUTLS_E_SUCCESS != (ret = gnutls_init(&session, GNUTLS_SERVER))) {
|
||||
/* */
|
||||
} else if (GNUTLS_E_SUCCESS != (ret = gnutls_set_default_priority(session))) {
|
||||
/* */
|
||||
} else if (GNUTLS_E_SUCCESS != (ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctx->x509_cred))) {
|
||||
/* */
|
||||
} else {
|
||||
gnutls_session_enable_compatibility_mode(session);
|
||||
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t)(uintptr_t)fd);
|
||||
ctx->session = session;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int generate_dh_params(struct rfbssl_ctx *ctx)
|
||||
{
|
||||
int ret;
|
||||
if (GNUTLS_E_SUCCESS == (ret = gnutls_dh_params_init(&ctx->dh_params)))
|
||||
ret = gnutls_dh_params_generate2(ctx->dh_params, 1024);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef I_LIKE_RSA_PARAMS_THAT_MUCH
|
||||
static int generate_rsa_params(struct rfbssl_ctx *ctx)
|
||||
{
|
||||
int ret;
|
||||
if (GNUTLS_E_SUCCESS == (ret = gnutls_rsa_params_init(&ctx->rsa_params)))
|
||||
ret = gnutls_rsa_params_generate2(ctx->rsa_params, 512);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct rfbssl_ctx *rfbssl_init_global(char *key, char *cert)
|
||||
{
|
||||
int ret = GNUTLS_E_SUCCESS;
|
||||
struct rfbssl_ctx *ctx = NULL;
|
||||
|
||||
if (NULL == (ctx = malloc(sizeof(struct rfbssl_ctx)))) {
|
||||
return NULL;
|
||||
} else if (GNUTLS_E_SUCCESS != (ret = gnutls_global_init())) {
|
||||
/* */
|
||||
} else if (GNUTLS_E_SUCCESS != (ret = gnutls_certificate_allocate_credentials(&ctx->x509_cred))) {
|
||||
/* */
|
||||
} else if ((ret = gnutls_certificate_set_x509_trust_file(ctx->x509_cred, cert, GNUTLS_X509_FMT_PEM)) < 0) {
|
||||
/* */
|
||||
} else if (GNUTLS_E_SUCCESS != (ret = gnutls_certificate_set_x509_key_file(ctx->x509_cred, cert, key, GNUTLS_X509_FMT_PEM))) {
|
||||
/* */
|
||||
} else if (GNUTLS_E_SUCCESS != (ret = generate_dh_params(ctx))) {
|
||||
/* */
|
||||
#ifdef I_LIKE_RSA_PARAMS_THAT_MUCH
|
||||
} else if (GNUTLS_E_SUCCESS != (ret = generate_rsa_params(ctx))) {
|
||||
/* */
|
||||
#endif
|
||||
} else {
|
||||
gnutls_global_set_log_function(rfbssl_log_func);
|
||||
gnutls_global_set_log_level(1);
|
||||
gnutls_certificate_set_dh_params(ctx->x509_cred, ctx->dh_params);
|
||||
/* newly allocated memory should be initialized, at least where it is important */
|
||||
ctx->peekstart = ctx->peeklen = 0;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rfbssl_init(rfbClientPtr cl)
|
||||
{
|
||||
int ret = -1;
|
||||
struct rfbssl_ctx *ctx;
|
||||
char *keyfile;
|
||||
if (!(keyfile = cl->screen->sslkeyfile))
|
||||
keyfile = cl->screen->sslcertfile;
|
||||
|
||||
if (!cl->screen->sslcertfile || !cl->screen->sslcertfile[0]) {
|
||||
rfbErr("SSL connection but no cert specified\n");
|
||||
} else if (NULL == (ctx = rfbssl_init_global(keyfile, cl->screen->sslcertfile))) {
|
||||
/* */
|
||||
} else if (GNUTLS_E_SUCCESS != (ret = rfbssl_init_session(ctx, cl->sock))) {
|
||||
/* */
|
||||
} else {
|
||||
while (GNUTLS_E_SUCCESS != (ret = gnutls_handshake(ctx->session))) {
|
||||
if (ret == GNUTLS_E_AGAIN)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
rfbssl_error(__func__, ret);
|
||||
} else {
|
||||
cl->sslctx = (rfbSslCtx *)ctx;
|
||||
rfbLog("%s protocol initialized\n", gnutls_protocol_get_name(gnutls_protocol_get_version(ctx->session)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rfbssl_do_read(rfbClientPtr cl, char *buf, int bufsize)
|
||||
{
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
int ret;
|
||||
|
||||
while ((ret = gnutls_record_recv(ctx->session, buf, bufsize)) < 0) {
|
||||
if (ret == GNUTLS_E_AGAIN) {
|
||||
/* continue */
|
||||
} else if (ret == GNUTLS_E_INTERRUPTED) {
|
||||
/* continue */
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
rfbssl_error(__func__, ret);
|
||||
errno = EIO;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret < 0 ? -1 : ret;
|
||||
}
|
||||
|
||||
int rfbssl_write(rfbClientPtr cl, const char *buf, int bufsize)
|
||||
{
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
int ret;
|
||||
|
||||
while ((ret = gnutls_record_send(ctx->session, buf, bufsize)) < 0) {
|
||||
if (ret == GNUTLS_E_AGAIN) {
|
||||
/* continue */
|
||||
} else if (ret == GNUTLS_E_INTERRUPTED) {
|
||||
/* continue */
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
rfbssl_error(__func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rfbssl_gc_peekbuf(struct rfbssl_ctx *ctx, int bufsize)
|
||||
{
|
||||
if (ctx->peekstart) {
|
||||
int spaceleft = sizeof(ctx->peekbuf) - ctx->peeklen - ctx->peekstart;
|
||||
if (spaceleft < bufsize) {
|
||||
memmove(ctx->peekbuf, ctx->peekbuf + ctx->peekstart, ctx->peeklen);
|
||||
ctx->peekstart = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int __rfbssl_read(rfbClientPtr cl, char *buf, int bufsize, int peek)
|
||||
{
|
||||
int ret = 0;
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
|
||||
rfbssl_gc_peekbuf(ctx, bufsize);
|
||||
|
||||
if (ctx->peeklen) {
|
||||
/* If we have any peek data, simply return that. */
|
||||
ret = bufsize < ctx->peeklen ? bufsize : ctx->peeklen;
|
||||
memcpy (buf, ctx->peekbuf + ctx->peekstart, ret);
|
||||
if (!peek) {
|
||||
ctx->peeklen -= ret;
|
||||
if (ctx->peeklen != 0)
|
||||
ctx->peekstart += ret;
|
||||
else
|
||||
ctx->peekstart = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < bufsize) {
|
||||
int n;
|
||||
/* read the remaining data */
|
||||
if ((n = rfbssl_do_read(cl, buf + ret, bufsize - ret)) <= 0) {
|
||||
rfbErr("rfbssl_%s: %s error\n", __func__, peek ? "peek" : "read");
|
||||
return n;
|
||||
}
|
||||
if (peek) {
|
||||
memcpy(ctx->peekbuf + ctx->peekstart + ctx->peeklen, buf + ret, n);
|
||||
ctx->peeklen += n;
|
||||
}
|
||||
ret += n;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rfbssl_read(rfbClientPtr cl, char *buf, int bufsize)
|
||||
{
|
||||
return __rfbssl_read(cl, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize)
|
||||
{
|
||||
return __rfbssl_read(cl, buf, bufsize, 1);
|
||||
}
|
||||
|
||||
int rfbssl_pending(rfbClientPtr cl)
|
||||
{
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
int ret = ctx->peeklen;
|
||||
|
||||
if (ret <= 0)
|
||||
ret = gnutls_record_check_pending(ctx->session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rfbssl_destroy(rfbClientPtr cl)
|
||||
{
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
gnutls_bye(ctx->session, GNUTLS_SHUT_WR);
|
||||
gnutls_deinit(ctx->session);
|
||||
gnutls_certificate_free_credentials(ctx->x509_cred);
|
||||
}
|
||||
58
android/extern/libvncserver/src/libvncserver/rfbssl_none.c
vendored
Normal file
58
android/extern/libvncserver/src/libvncserver/rfbssl_none.c
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* rfbssl_none.c - Secure socket functions (fallback to failing)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011 Johannes Schindelin
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include "rfbssl.h"
|
||||
|
||||
struct rfbssl_ctx *rfbssl_init_global(char *key, char *cert)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rfbssl_init(rfbClientPtr cl)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rfbssl_write(rfbClientPtr cl, const char *buf, int bufsize)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rfbssl_read(rfbClientPtr cl, char *buf, int bufsize)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rfbssl_pending(rfbClientPtr cl)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void rfbssl_destroy(rfbClientPtr cl)
|
||||
{
|
||||
}
|
||||
135
android/extern/libvncserver/src/libvncserver/rfbssl_openssl.c
vendored
Normal file
135
android/extern/libvncserver/src/libvncserver/rfbssl_openssl.c
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* rfbssl_openssl.c - Secure socket functions (openssl version)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011 Gernot Tenchio
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include "rfbssl.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
struct rfbssl_ctx {
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL *ssl;
|
||||
};
|
||||
|
||||
static void rfbssl_error(void)
|
||||
{
|
||||
char buf[1024];
|
||||
unsigned long e = ERR_get_error();
|
||||
rfbErr("%s (%ld)\n", ERR_error_string(e, buf), e);
|
||||
}
|
||||
|
||||
int rfbssl_init(rfbClientPtr cl)
|
||||
{
|
||||
char *keyfile;
|
||||
int r, ret = -1;
|
||||
struct rfbssl_ctx *ctx;
|
||||
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
|
||||
if (cl->screen->sslkeyfile && *cl->screen->sslkeyfile) {
|
||||
keyfile = cl->screen->sslkeyfile;
|
||||
} else {
|
||||
keyfile = cl->screen->sslcertfile;
|
||||
}
|
||||
|
||||
if (NULL == (ctx = malloc(sizeof(struct rfbssl_ctx)))) {
|
||||
rfbErr("OOM\n");
|
||||
} else if (!cl->screen->sslcertfile || !cl->screen->sslcertfile[0]) {
|
||||
rfbErr("SSL connection but no cert specified\n");
|
||||
} else if (NULL == (ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
|
||||
rfbssl_error();
|
||||
} else if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, keyfile, SSL_FILETYPE_PEM) <= 0) {
|
||||
rfbErr("Unable to load private key file %s\n", keyfile);
|
||||
} else if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, cl->screen->sslcertfile, SSL_FILETYPE_PEM) <= 0) {
|
||||
rfbErr("Unable to load certificate file %s\n", cl->screen->sslcertfile);
|
||||
} else if (NULL == (ctx->ssl = SSL_new(ctx->ssl_ctx))) {
|
||||
rfbErr("SSL_new failed\n");
|
||||
rfbssl_error();
|
||||
} else if (!(SSL_set_fd(ctx->ssl, cl->sock))) {
|
||||
rfbErr("SSL_set_fd failed\n");
|
||||
rfbssl_error();
|
||||
} else {
|
||||
while ((r = SSL_accept(ctx->ssl)) < 0) {
|
||||
if (SSL_get_error(ctx->ssl, r) != SSL_ERROR_WANT_READ)
|
||||
break;
|
||||
}
|
||||
if (r < 0) {
|
||||
rfbErr("SSL_accept failed %d\n", SSL_get_error(ctx->ssl, r));
|
||||
} else {
|
||||
cl->sslctx = (rfbSslCtx *)ctx;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rfbssl_write(rfbClientPtr cl, const char *buf, int bufsize)
|
||||
{
|
||||
int ret;
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
|
||||
while ((ret = SSL_write(ctx->ssl, buf, bufsize)) <= 0) {
|
||||
if (SSL_get_error(ctx->ssl, ret) != SSL_ERROR_WANT_WRITE)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize)
|
||||
{
|
||||
int ret;
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
|
||||
while ((ret = SSL_peek(ctx->ssl, buf, bufsize)) <= 0) {
|
||||
if (SSL_get_error(ctx->ssl, ret) != SSL_ERROR_WANT_READ)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rfbssl_read(rfbClientPtr cl, char *buf, int bufsize)
|
||||
{
|
||||
int ret;
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
|
||||
while ((ret = SSL_read(ctx->ssl, buf, bufsize)) <= 0) {
|
||||
if (SSL_get_error(ctx->ssl, ret) != SSL_ERROR_WANT_READ)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rfbssl_pending(rfbClientPtr cl)
|
||||
{
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
return SSL_pending(ctx->ssl);
|
||||
}
|
||||
|
||||
void rfbssl_destroy(rfbClientPtr cl)
|
||||
{
|
||||
struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
|
||||
if (ctx->ssl)
|
||||
SSL_free(ctx->ssl);
|
||||
if (ctx->ssl_ctx)
|
||||
SSL_CTX_free(ctx->ssl_ctx);
|
||||
}
|
||||
325
android/extern/libvncserver/src/libvncserver/rre.c
vendored
Normal file
325
android/extern/libvncserver/src/libvncserver/rre.c
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* rre.c
|
||||
*
|
||||
* Routines to implement Rise-and-Run-length Encoding (RRE). This
|
||||
* code is based on krw's original javatel rfbserver.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
/*
|
||||
* cl->beforeEncBuf contains pixel data in the client's format.
|
||||
* cl->afterEncBuf contains the RRE encoded version. If the RRE encoded version is
|
||||
* larger than the raw data or if it exceeds cl->afterEncBufSize then
|
||||
* raw encoding is used instead.
|
||||
*/
|
||||
|
||||
static int subrectEncode8(rfbClientPtr cl, uint8_t *data, int w, int h);
|
||||
static int subrectEncode16(rfbClientPtr cl, uint16_t *data, int w, int h);
|
||||
static int subrectEncode32(rfbClientPtr cl, uint32_t *data, int w, int h);
|
||||
static uint32_t getBgColour(char *data, int size, int bpp);
|
||||
|
||||
|
||||
/*
|
||||
* rfbSendRectEncodingRRE - send a given rectangle using RRE encoding.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSendRectEncodingRRE(rfbClientPtr cl,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
rfbRREHeader hdr;
|
||||
int nSubrects;
|
||||
int i;
|
||||
char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
|
||||
+ (x * (cl->scaledScreen->bitsPerPixel / 8)));
|
||||
|
||||
int maxRawSize = (cl->scaledScreen->width * cl->scaledScreen->height
|
||||
* (cl->format.bitsPerPixel / 8));
|
||||
|
||||
if (!cl->beforeEncBuf || cl->beforeEncBufSize < maxRawSize) {
|
||||
if (cl->beforeEncBuf == NULL)
|
||||
cl->beforeEncBuf = (char *)malloc(maxRawSize);
|
||||
else {
|
||||
char *reallocedBeforeEncBuf = (char *)realloc(cl->beforeEncBuf, maxRawSize);
|
||||
if (!reallocedBeforeEncBuf) return FALSE;
|
||||
cl->beforeEncBuf = reallocedBeforeEncBuf;
|
||||
}
|
||||
if(cl->beforeEncBuf)
|
||||
cl->beforeEncBufSize = maxRawSize;
|
||||
}
|
||||
|
||||
if (!cl->afterEncBuf || cl->afterEncBufSize < maxRawSize) {
|
||||
if (cl->afterEncBuf == NULL)
|
||||
cl->afterEncBuf = (char *)malloc(maxRawSize);
|
||||
else {
|
||||
char *reallocedAfterEncBuf = (char *)realloc(cl->afterEncBuf, maxRawSize);
|
||||
if (!reallocedAfterEncBuf) return FALSE;
|
||||
cl->afterEncBuf = reallocedAfterEncBuf;
|
||||
}
|
||||
if(cl->afterEncBuf)
|
||||
cl->afterEncBufSize = maxRawSize;
|
||||
}
|
||||
|
||||
if (!cl->beforeEncBuf || !cl->afterEncBuf)
|
||||
{
|
||||
rfbLog("rfbSendRectEncodingRRE: failed to allocate memory\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
(*cl->translateFn)(cl->translateLookupTable,
|
||||
&(cl->screen->serverFormat),
|
||||
&cl->format, fbptr, cl->beforeEncBuf,
|
||||
cl->scaledScreen->paddedWidthInBytes, w, h);
|
||||
|
||||
switch (cl->format.bitsPerPixel) {
|
||||
case 8:
|
||||
nSubrects = subrectEncode8(cl, (uint8_t *)cl->beforeEncBuf, w, h);
|
||||
break;
|
||||
case 16:
|
||||
nSubrects = subrectEncode16(cl, (uint16_t *)cl->beforeEncBuf, w, h);
|
||||
break;
|
||||
case 32:
|
||||
nSubrects = subrectEncode32(cl, (uint32_t *)cl->beforeEncBuf, w, h);
|
||||
break;
|
||||
default:
|
||||
rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nSubrects < 0) {
|
||||
|
||||
/* RRE encoding was too large, use raw */
|
||||
|
||||
return rfbSendRectEncodingRaw(cl, x, y, w, h);
|
||||
}
|
||||
|
||||
rfbStatRecordEncodingSent(cl, rfbEncodingRRE,
|
||||
sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + cl->afterEncBufLen,
|
||||
sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8));
|
||||
|
||||
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
|
||||
> UPDATE_BUF_SIZE)
|
||||
{
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rect.r.x = Swap16IfLE(x);
|
||||
rect.r.y = Swap16IfLE(y);
|
||||
rect.r.w = Swap16IfLE(w);
|
||||
rect.r.h = Swap16IfLE(h);
|
||||
rect.encoding = Swap32IfLE(rfbEncodingRRE);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
|
||||
sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
hdr.nSubrects = Swap32IfLE(nSubrects);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader);
|
||||
cl->ublen += sz_rfbRREHeader;
|
||||
|
||||
for (i = 0; i < cl->afterEncBufLen;) {
|
||||
|
||||
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
|
||||
|
||||
if (i + bytesToCopy > cl->afterEncBufLen) {
|
||||
bytesToCopy = cl->afterEncBufLen - i;
|
||||
}
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], &cl->afterEncBuf[i], bytesToCopy);
|
||||
|
||||
cl->ublen += bytesToCopy;
|
||||
i += bytesToCopy;
|
||||
|
||||
if (cl->ublen == UPDATE_BUF_SIZE) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* subrectEncode() encodes the given multicoloured rectangle as a background
|
||||
* colour overwritten by single-coloured rectangles. It returns the number
|
||||
* of subrectangles in the encoded buffer, or -1 if subrect encoding won't
|
||||
* fit in the buffer. It puts the encoded rectangles in cl->afterEncBuf. The
|
||||
* single-colour rectangle partition is not optimal, but does find the biggest
|
||||
* horizontal or vertical rectangle top-left anchored to each consecutive
|
||||
* coordinate position.
|
||||
*
|
||||
* The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
|
||||
* <subrect> is [<colour><x><y><w><h>].
|
||||
*/
|
||||
|
||||
#define DEFINE_SUBRECT_ENCODE(bpp) \
|
||||
static int \
|
||||
subrectEncode##bpp(rfbClientPtr client, uint##bpp##_t *data, int w, int h) { \
|
||||
uint##bpp##_t cl; \
|
||||
rfbRectangle subrect; \
|
||||
int x,y; \
|
||||
int i,j; \
|
||||
int hx=0,hy,vx=0,vy; \
|
||||
int hyflag; \
|
||||
uint##bpp##_t *seg; \
|
||||
uint##bpp##_t *line; \
|
||||
int hw,hh,vw,vh; \
|
||||
int thex,they,thew,theh; \
|
||||
int numsubs = 0; \
|
||||
int newLen; \
|
||||
uint##bpp##_t bg = (uint##bpp##_t)getBgColour((char*)data,w*h,bpp); \
|
||||
\
|
||||
*((uint##bpp##_t*)client->afterEncBuf) = bg; \
|
||||
\
|
||||
client->afterEncBufLen = (bpp/8); \
|
||||
\
|
||||
for (y=0; y<h; y++) { \
|
||||
line = data+(y*w); \
|
||||
for (x=0; x<w; x++) { \
|
||||
if (line[x] != bg) { \
|
||||
cl = line[x]; \
|
||||
hy = y-1; \
|
||||
hyflag = 1; \
|
||||
for (j=y; j<h; j++) { \
|
||||
seg = data+(j*w); \
|
||||
if (seg[x] != cl) {break;} \
|
||||
i = x; \
|
||||
while ((i < w) && (seg[i] == cl)) i += 1; \
|
||||
i -= 1; \
|
||||
if (j == y) vx = hx = i; \
|
||||
if (i < vx) vx = i; \
|
||||
if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
|
||||
} \
|
||||
vy = j-1; \
|
||||
\
|
||||
/* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
|
||||
* We'll choose the bigger of the two. \
|
||||
*/ \
|
||||
hw = hx-x+1; \
|
||||
hh = hy-y+1; \
|
||||
vw = vx-x+1; \
|
||||
vh = vy-y+1; \
|
||||
\
|
||||
thex = x; \
|
||||
they = y; \
|
||||
\
|
||||
if ((hw*hh) > (vw*vh)) { \
|
||||
thew = hw; \
|
||||
theh = hh; \
|
||||
} else { \
|
||||
thew = vw; \
|
||||
theh = vh; \
|
||||
} \
|
||||
\
|
||||
subrect.x = Swap16IfLE(thex); \
|
||||
subrect.y = Swap16IfLE(they); \
|
||||
subrect.w = Swap16IfLE(thew); \
|
||||
subrect.h = Swap16IfLE(theh); \
|
||||
\
|
||||
newLen = client->afterEncBufLen + (bpp/8) + sz_rfbRectangle; \
|
||||
if ((newLen > (w * h * (bpp/8))) || (newLen > client->afterEncBufSize)) \
|
||||
return -1; \
|
||||
\
|
||||
numsubs += 1; \
|
||||
*((uint##bpp##_t*)(client->afterEncBuf + client->afterEncBufLen)) = cl; \
|
||||
client->afterEncBufLen += (bpp/8); \
|
||||
memcpy(&client->afterEncBuf[client->afterEncBufLen],&subrect,sz_rfbRectangle); \
|
||||
client->afterEncBufLen += sz_rfbRectangle; \
|
||||
\
|
||||
/* \
|
||||
* Now mark the subrect as done. \
|
||||
*/ \
|
||||
for (j=they; j < (they+theh); j++) { \
|
||||
for (i=thex; i < (thex+thew); i++) { \
|
||||
data[j*w+i] = bg; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return numsubs; \
|
||||
}
|
||||
|
||||
DEFINE_SUBRECT_ENCODE(8)
|
||||
DEFINE_SUBRECT_ENCODE(16)
|
||||
DEFINE_SUBRECT_ENCODE(32)
|
||||
|
||||
|
||||
/*
|
||||
* getBgColour() gets the most prevalent colour in a byte array.
|
||||
*/
|
||||
static uint32_t
|
||||
getBgColour(char *data, int size, int bpp)
|
||||
{
|
||||
|
||||
#define NUMCLRS 256
|
||||
|
||||
static int counts[NUMCLRS];
|
||||
int i,j,k;
|
||||
|
||||
int maxcount = 0;
|
||||
uint8_t maxclr = 0;
|
||||
|
||||
if (bpp != 8) {
|
||||
if (bpp == 16) {
|
||||
return ((uint16_t *)data)[0];
|
||||
} else if (bpp == 32) {
|
||||
return ((uint32_t *)data)[0];
|
||||
} else {
|
||||
rfbLog("getBgColour: bpp %d?\n",bpp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<NUMCLRS; i++) {
|
||||
counts[i] = 0;
|
||||
}
|
||||
|
||||
for (j=0; j<size; j++) {
|
||||
k = (int)(((uint8_t *)data)[j]);
|
||||
#if NUMCLRS != 256
|
||||
if (k >= NUMCLRS) {
|
||||
rfbErr("getBgColour: unusual colour = %d\n", k);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
counts[k] += 1;
|
||||
if (counts[k] > maxcount) {
|
||||
maxcount = counts[k];
|
||||
maxclr = ((uint8_t *)data)[j];
|
||||
}
|
||||
}
|
||||
|
||||
return maxclr;
|
||||
}
|
||||
436
android/extern/libvncserver/src/libvncserver/scale.c
vendored
Normal file
436
android/extern/libvncserver/src/libvncserver/scale.c
vendored
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* scale.c - deal with server-side scaling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
|
||||
* Copyright (C) 2002 RealVNC Ltd.
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/rfbregion.h>
|
||||
#include "private.h"
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUGPROTO
|
||||
#undef DEBUGPROTO
|
||||
#define DEBUGPROTO(x) x
|
||||
#else
|
||||
#define DEBUGPROTO(x)
|
||||
#endif
|
||||
|
||||
/****************************/
|
||||
#define CEIL(x) ( (double) ((int) (x)) == (x) ? \
|
||||
(double) ((int) (x)) : (double) ((int) (x) + 1) )
|
||||
#define FLOOR(x) ( (double) ((int) (x)) )
|
||||
|
||||
#ifdef WIN32
|
||||
#define InlineX __inline
|
||||
#else
|
||||
# ifndef __STRICT_ANSI__
|
||||
# define InlineX inline
|
||||
# else
|
||||
# define InlineX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
static InlineX int pad4(int value)
|
||||
{
|
||||
int remainder = value & 3;
|
||||
if (!remainder) return value;
|
||||
return value + 4 - remainder;
|
||||
}
|
||||
|
||||
int ScaleX(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int x)
|
||||
{
|
||||
if ((from==to) || (from==NULL) || (to==NULL)) return x;
|
||||
return ((int)(((double) x / (double)from->width) * (double)to->width ));
|
||||
}
|
||||
|
||||
int ScaleY(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int y)
|
||||
{
|
||||
if ((from==to) || (from==NULL) || (to==NULL)) return y;
|
||||
return ((int)(((double) y / (double)from->height) * (double)to->height ));
|
||||
}
|
||||
|
||||
/* So, all of the encodings point to the ->screen->frameBuffer,
|
||||
* We need to change this!
|
||||
*/
|
||||
void rfbScaledCorrection(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int *x, int *y, int *w, int *h, const char *function)
|
||||
{
|
||||
double x1,y1,w1,h1, x2, y2, w2, h2;
|
||||
double scaleW = ((double) to->width) / ((double) from->width);
|
||||
double scaleH = ((double) to->height) / ((double) from->height);
|
||||
|
||||
|
||||
/*
|
||||
* rfbLog("rfbScaledCorrection(%p -> %p, %dx%d->%dx%d (%dXx%dY-%dWx%dH)\n",
|
||||
* from, to, from->width, from->height, to->width, to->height, *x, *y, *w, *h);
|
||||
*/
|
||||
|
||||
/* If it's the original framebuffer... */
|
||||
if (from==to) return;
|
||||
|
||||
x1 = ((double) *x) * scaleW;
|
||||
y1 = ((double) *y) * scaleH;
|
||||
w1 = ((double) *w) * scaleW;
|
||||
h1 = ((double) *h) * scaleH;
|
||||
|
||||
|
||||
/*cast from double to int is same as "*x = floor(x1);" */
|
||||
x2 = FLOOR(x1);
|
||||
y2 = FLOOR(y1);
|
||||
|
||||
/* include into W and H the jitter of scaling X and Y */
|
||||
w2 = CEIL(w1 + ( x1 - x2 ));
|
||||
h2 = CEIL(h1 + ( y1 - y2 ));
|
||||
|
||||
/*
|
||||
* rfbLog("%s (%dXx%dY-%dWx%dH -> %fXx%fY-%fWx%fH) {%dWx%dH -> %dWx%dH}\n",
|
||||
* function, *x, *y, *w, *h, x2, y2, w2, h2,
|
||||
* from->width, from->height, to->width, to->height);
|
||||
*/
|
||||
|
||||
/* simulate ceil() without math library */
|
||||
*x = (int)x2;
|
||||
*y = (int)y2;
|
||||
*w = (int)w2;
|
||||
*h = (int)h2;
|
||||
|
||||
/* Small changes for a thumbnail may be scaled to zero */
|
||||
if (*w==0) (*w)++;
|
||||
if (*h==0) (*h)++;
|
||||
/* scaling from small to big may overstep the size a bit */
|
||||
if (*x+*w > to->width) *w=to->width - *x;
|
||||
if (*y+*h > to->height) *h=to->height - *y;
|
||||
}
|
||||
|
||||
void rfbScaledScreenUpdateRect(rfbScreenInfoPtr screen, rfbScreenInfoPtr ptr, int x0, int y0, int w0, int h0)
|
||||
{
|
||||
int x,y,w,v,z;
|
||||
int x1, y1, w1, h1;
|
||||
int bitsPerPixel, bytesPerPixel, bytesPerLine, areaX, areaY, area2;
|
||||
unsigned char *srcptr, *dstptr;
|
||||
|
||||
/* Nothing to do!!! */
|
||||
if (screen==ptr) return;
|
||||
|
||||
x1 = x0;
|
||||
y1 = y0;
|
||||
w1 = w0;
|
||||
h1 = h0;
|
||||
|
||||
rfbScaledCorrection(screen, ptr, &x1, &y1, &w1, &h1, "rfbScaledScreenUpdateRect");
|
||||
x0 = ScaleX(ptr, screen, x1);
|
||||
y0 = ScaleY(ptr, screen, y1);
|
||||
w0 = ScaleX(ptr, screen, w1);
|
||||
h0 = ScaleY(ptr, screen, h1);
|
||||
|
||||
bitsPerPixel = screen->bitsPerPixel;
|
||||
bytesPerPixel = bitsPerPixel / 8;
|
||||
bytesPerLine = w1 * bytesPerPixel;
|
||||
srcptr = (unsigned char *)(screen->frameBuffer +
|
||||
(y0 * screen->paddedWidthInBytes + x0 * bytesPerPixel));
|
||||
dstptr = (unsigned char *)(ptr->frameBuffer +
|
||||
( y1 * ptr->paddedWidthInBytes + x1 * bytesPerPixel));
|
||||
/* The area of the source framebuffer for each destination pixel */
|
||||
areaX = ScaleX(ptr,screen,1);
|
||||
areaY = ScaleY(ptr,screen,1);
|
||||
area2 = areaX*areaY;
|
||||
|
||||
|
||||
/* Ensure that we do not go out of bounds */
|
||||
if ((x1+w1) > (ptr->width))
|
||||
{
|
||||
if (x1==0) w1=ptr->width; else x1 = ptr->width - w1;
|
||||
}
|
||||
if ((y1+h1) > (ptr->height))
|
||||
{
|
||||
if (y1==0) h1=ptr->height; else y1 = ptr->height - h1;
|
||||
}
|
||||
/*
|
||||
* rfbLog("rfbScaledScreenUpdateRect(%dXx%dY-%dWx%dH -> %dXx%dY-%dWx%dH <%dx%d>) {%dWx%dH -> %dWx%dH} 0x%p\n",
|
||||
* x0, y0, w0, h0, x1, y1, w1, h1, areaX, areaY,
|
||||
* screen->width, screen->height, ptr->width, ptr->height, ptr->frameBuffer);
|
||||
*/
|
||||
|
||||
if (screen->serverFormat.trueColour) { /* Blend neighbouring pixels together */
|
||||
unsigned char *srcptr2;
|
||||
unsigned long pixel_value, red, green, blue;
|
||||
unsigned int redShift = screen->serverFormat.redShift;
|
||||
unsigned int greenShift = screen->serverFormat.greenShift;
|
||||
unsigned int blueShift = screen->serverFormat.blueShift;
|
||||
unsigned long redMax = screen->serverFormat.redMax;
|
||||
unsigned long greenMax = screen->serverFormat.greenMax;
|
||||
unsigned long blueMax = screen->serverFormat.blueMax;
|
||||
|
||||
/* for each *destination* pixel... */
|
||||
for (y = 0; y < h1; y++) {
|
||||
for (x = 0; x < w1; x++) {
|
||||
red = green = blue = 0;
|
||||
/* Get the totals for rgb from the source grid... */
|
||||
for (w = 0; w < areaX; w++) {
|
||||
for (v = 0; v < areaY; v++) {
|
||||
srcptr2 = &srcptr[(((x * areaX) + w) * bytesPerPixel) +
|
||||
(v * screen->paddedWidthInBytes)];
|
||||
pixel_value = 0;
|
||||
|
||||
|
||||
switch (bytesPerPixel) {
|
||||
case 4: pixel_value = *((unsigned int *)srcptr2); break;
|
||||
case 2: pixel_value = *((unsigned short *)srcptr2); break;
|
||||
case 1: pixel_value = *((unsigned char *)srcptr2); break;
|
||||
default:
|
||||
/* fixme: endianness problem? */
|
||||
for (z = 0; z < bytesPerPixel; z++)
|
||||
pixel_value += ((unsigned long)srcptr2[z] << (8 * z));
|
||||
break;
|
||||
}
|
||||
/*
|
||||
srcptr2 += bytesPerPixel;
|
||||
*/
|
||||
|
||||
red += ((pixel_value >> redShift) & redMax);
|
||||
green += ((pixel_value >> greenShift) & greenMax);
|
||||
blue += ((pixel_value >> blueShift) & blueMax);
|
||||
|
||||
}
|
||||
}
|
||||
/* We now have a total for all of the colors, find the average! */
|
||||
red /= area2;
|
||||
green /= area2;
|
||||
blue /= area2;
|
||||
/* Stuff the new value back into memory */
|
||||
pixel_value = ((red & redMax) << redShift) | ((green & greenMax) << greenShift) | ((blue & blueMax) << blueShift);
|
||||
|
||||
switch (bytesPerPixel) {
|
||||
case 4: *((unsigned int *)dstptr) = (unsigned int) pixel_value; break;
|
||||
case 2: *((unsigned short *)dstptr) = (unsigned short) pixel_value; break;
|
||||
case 1: *((unsigned char *)dstptr) = (unsigned char) pixel_value; break;
|
||||
default:
|
||||
/* fixme: endianness problem? */
|
||||
for (z = 0; z < bytesPerPixel; z++)
|
||||
dstptr[z]=(pixel_value >> (8 * z)) & 0xff;
|
||||
break;
|
||||
}
|
||||
dstptr += bytesPerPixel;
|
||||
}
|
||||
srcptr += (screen->paddedWidthInBytes * areaY);
|
||||
dstptr += (ptr->paddedWidthInBytes - bytesPerLine);
|
||||
}
|
||||
} else
|
||||
{ /* Not truecolour, so we can't blend. Just use the top-left pixel instead */
|
||||
for (y = y1; y < (y1+h1); y++) {
|
||||
for (x = x1; x < (x1+w1); x++)
|
||||
memcpy (&ptr->frameBuffer[(y *ptr->paddedWidthInBytes) + (x * bytesPerPixel)],
|
||||
&screen->frameBuffer[(y * areaY * screen->paddedWidthInBytes) + (x *areaX * bytesPerPixel)], bytesPerPixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
/* ok, now the task is to update each and every scaled version of the framebuffer
|
||||
* and we only have to do this for this specific changed rectangle!
|
||||
*/
|
||||
rfbScreenInfoPtr ptr;
|
||||
int count=0;
|
||||
|
||||
/* We don't point to cl->screen as it is the original */
|
||||
for (ptr=screen->scaledScreenNext;ptr!=NULL;ptr=ptr->scaledScreenNext)
|
||||
{
|
||||
/* Only update if it has active clients... */
|
||||
if (ptr->scaledScreenRefCount>0)
|
||||
{
|
||||
rfbScaledScreenUpdateRect(screen, ptr, x1, y1, x2-x1, y2-y1);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a new scaled version of the framebuffer */
|
||||
rfbScreenInfoPtr rfbScaledScreenAllocate(rfbClientPtr cl, int width, int height)
|
||||
{
|
||||
rfbScreenInfoPtr ptr;
|
||||
ptr = malloc(sizeof(rfbScreenInfo));
|
||||
if (ptr!=NULL)
|
||||
{
|
||||
int allocSize;
|
||||
|
||||
/* copy *everything* (we don't use most of it, but just in case) */
|
||||
memcpy(ptr, cl->screen, sizeof(rfbScreenInfo));
|
||||
|
||||
/* SECURITY: make sure that no integer overflow will occur afterwards.
|
||||
* Note: this is defensive coding, as the check should have already been
|
||||
* performed during initial, non-scaled screen setup.
|
||||
*/
|
||||
allocSize = pad4(width * (ptr->bitsPerPixel/8)); /* per protocol, width<2**16 and bpp<256 */
|
||||
if (height == 0 || allocSize >= SIZE_MAX / height)
|
||||
{
|
||||
free(ptr);
|
||||
return NULL; /* malloc() will allocate an incorrect buffer size - early abort */
|
||||
}
|
||||
|
||||
/* Resume copy everything */
|
||||
ptr->width = width;
|
||||
ptr->height = height;
|
||||
ptr->paddedWidthInBytes = (ptr->bitsPerPixel/8)*ptr->width;
|
||||
|
||||
/* Need to by multiples of 4 for Sparc systems */
|
||||
ptr->paddedWidthInBytes = pad4(ptr->paddedWidthInBytes);
|
||||
|
||||
/* Reset the reference count to 0! */
|
||||
ptr->scaledScreenRefCount = 0;
|
||||
|
||||
ptr->sizeInBytes = ptr->paddedWidthInBytes * ptr->height;
|
||||
ptr->serverFormat = cl->screen->serverFormat;
|
||||
|
||||
ptr->frameBuffer = malloc(ptr->sizeInBytes);
|
||||
if (ptr->frameBuffer!=NULL)
|
||||
{
|
||||
/* Reset to a known condition: scale the entire framebuffer */
|
||||
rfbScaledScreenUpdateRect(cl->screen, ptr, 0, 0, cl->screen->width, cl->screen->height);
|
||||
/* Now, insert into the chain */
|
||||
LOCK(cl->updateMutex);
|
||||
ptr->scaledScreenNext = cl->screen->scaledScreenNext;
|
||||
cl->screen->scaledScreenNext = ptr;
|
||||
UNLOCK(cl->updateMutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Failed to malloc the new frameBuffer, cleanup */
|
||||
free(ptr);
|
||||
ptr=NULL;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Find an active scaled version of the framebuffer
|
||||
* TODO: implement a refcount per scaled screen to prevent
|
||||
* unreferenced scaled screens from hanging around
|
||||
*/
|
||||
rfbScreenInfoPtr rfbScalingFind(rfbClientPtr cl, int width, int height)
|
||||
{
|
||||
rfbScreenInfoPtr ptr;
|
||||
/* include the original in the search (ie: fine 1:1 scaled version of the frameBuffer) */
|
||||
for (ptr=cl->screen; ptr!=NULL; ptr=ptr->scaledScreenNext)
|
||||
{
|
||||
if ((ptr->width==width) && (ptr->height==height))
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Future needs "scale to 320x240, as that's the client's screen size */
|
||||
void rfbScalingSetup(rfbClientPtr cl, int width, int height)
|
||||
{
|
||||
rfbScreenInfoPtr ptr;
|
||||
|
||||
ptr = rfbScalingFind(cl,width,height);
|
||||
if (ptr==NULL)
|
||||
ptr = rfbScaledScreenAllocate(cl,width,height);
|
||||
/* Now, there is a new screen available (if ptr is not NULL) */
|
||||
if (ptr!=NULL)
|
||||
{
|
||||
/* Update it! */
|
||||
if (ptr->scaledScreenRefCount<1)
|
||||
rfbScaledScreenUpdateRect(cl->screen, ptr, 0, 0, cl->screen->width, cl->screen->height);
|
||||
/*
|
||||
* rfbLog("Taking one from %dx%d-%d and adding it to %dx%d-%d\n",
|
||||
* cl->scaledScreen->width, cl->scaledScreen->height,
|
||||
* cl->scaledScreen->scaledScreenRefCount,
|
||||
* ptr->width, ptr->height, ptr->scaledScreenRefCount);
|
||||
*/
|
||||
|
||||
LOCK(cl->updateMutex);
|
||||
cl->scaledScreen->scaledScreenRefCount--;
|
||||
ptr->scaledScreenRefCount++;
|
||||
cl->scaledScreen=ptr;
|
||||
cl->newFBSizePending = TRUE;
|
||||
UNLOCK(cl->updateMutex);
|
||||
|
||||
rfbLog("Scaling to %dx%d (refcount=%d)\n",width,height,ptr->scaledScreenRefCount);
|
||||
}
|
||||
else
|
||||
rfbLog("Scaling to %dx%d failed, leaving things alone\n",width,height);
|
||||
}
|
||||
|
||||
int rfbSendNewScaleSize(rfbClientPtr cl)
|
||||
{
|
||||
/* if the client supports newFBsize Encoding, use it */
|
||||
if (cl->useNewFBSize && cl->newFBSizePending)
|
||||
return FALSE;
|
||||
|
||||
LOCK(cl->updateMutex);
|
||||
cl->newFBSizePending = FALSE;
|
||||
UNLOCK(cl->updateMutex);
|
||||
|
||||
if (cl->PalmVNC==TRUE)
|
||||
{
|
||||
rfbPalmVNCReSizeFrameBufferMsg pmsg;
|
||||
pmsg.type = rfbPalmVNCReSizeFrameBuffer;
|
||||
pmsg.pad1 = 0;
|
||||
pmsg.desktop_w = Swap16IfLE(cl->screen->width);
|
||||
pmsg.desktop_h = Swap16IfLE(cl->screen->height);
|
||||
pmsg.buffer_w = Swap16IfLE(cl->scaledScreen->width);
|
||||
pmsg.buffer_h = Swap16IfLE(cl->scaledScreen->height);
|
||||
pmsg.pad2 = 0;
|
||||
|
||||
rfbLog("Sending a response to a PalmVNC style frameuffer resize event (%dx%d)\n", cl->scaledScreen->width, cl->scaledScreen->height);
|
||||
LOCK(cl->sendMutex);
|
||||
if (rfbWriteExact(cl, (char *)&pmsg, sz_rfbPalmVNCReSizeFrameBufferMsg) < 0) {
|
||||
rfbLogPerror("rfbNewClient: write");
|
||||
rfbCloseClient(cl);
|
||||
UNLOCK(cl->sendMutex);
|
||||
return FALSE;
|
||||
}
|
||||
UNLOCK(cl->sendMutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
rfbResizeFrameBufferMsg rmsg;
|
||||
rmsg.type = rfbResizeFrameBuffer;
|
||||
rmsg.pad1=0;
|
||||
rmsg.framebufferWidth = Swap16IfLE(cl->scaledScreen->width);
|
||||
rmsg.framebufferHeigth = Swap16IfLE(cl->scaledScreen->height);
|
||||
rfbLog("Sending a response to a UltraVNC style frameuffer resize event (%dx%d)\n", cl->scaledScreen->width, cl->scaledScreen->height);
|
||||
LOCK(cl->sendMutex);
|
||||
if (rfbWriteExact(cl, (char *)&rmsg, sz_rfbResizeFrameBufferMsg) < 0) {
|
||||
rfbLogPerror("rfbNewClient: write");
|
||||
rfbCloseClient(cl);
|
||||
UNLOCK(cl->sendMutex);
|
||||
return FALSE;
|
||||
}
|
||||
UNLOCK(cl->sendMutex);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
/****************************/
|
||||
10
android/extern/libvncserver/src/libvncserver/scale.h
vendored
Normal file
10
android/extern/libvncserver/src/libvncserver/scale.h
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
int ScaleX(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int x);
|
||||
int ScaleY(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int y);
|
||||
void rfbScaledCorrection(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int *x, int *y, int *w, int *h, const char *function);
|
||||
void rfbScaledScreenUpdateRect(rfbScreenInfoPtr screen, rfbScreenInfoPtr ptr, int x0, int y0, int w0, int h0);
|
||||
void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
|
||||
rfbScreenInfoPtr rfbScaledScreenAllocate(rfbClientPtr cl, int width, int height);
|
||||
rfbScreenInfoPtr rfbScalingFind(rfbClientPtr cl, int width, int height);
|
||||
void rfbScalingSetup(rfbClientPtr cl, int width, int height);
|
||||
int rfbSendNewScaleSize(rfbClientPtr cl);
|
||||
302
android/extern/libvncserver/src/libvncserver/selbox.c
vendored
Normal file
302
android/extern/libvncserver/src/libvncserver/selbox.c
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
#include <ctype.h>
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/keysym.h>
|
||||
|
||||
typedef struct {
|
||||
rfbScreenInfoPtr screen;
|
||||
rfbFontDataPtr font;
|
||||
char** list;
|
||||
int listSize;
|
||||
int selected;
|
||||
int displayStart;
|
||||
int x1,y1,x2,y2,textH,pageH;
|
||||
int xhot,yhot;
|
||||
int buttonWidth,okBX,cancelBX,okX,cancelX,okY;
|
||||
rfbBool okInverted,cancelInverted;
|
||||
int lastButtons;
|
||||
rfbPixel colour,backColour;
|
||||
SelectionChangedHookPtr selChangedHook;
|
||||
enum { SELECTING, OK, CANCEL } state;
|
||||
} rfbSelectData;
|
||||
|
||||
static const char* okStr="OK";
|
||||
static const char* cancelStr="Cancel";
|
||||
|
||||
static void selPaintButtons(rfbSelectData* m,rfbBool invertOk,rfbBool invertCancel)
|
||||
{
|
||||
rfbScreenInfoPtr s = m->screen;
|
||||
rfbPixel bcolour = m->backColour;
|
||||
rfbPixel colour = m->colour;
|
||||
|
||||
rfbFillRect(s,m->x1,m->okY-m->textH,m->x2,m->okY,bcolour);
|
||||
|
||||
if(invertOk) {
|
||||
rfbFillRect(s,m->okBX,m->okY-m->textH,m->okBX+m->buttonWidth,m->okY,colour);
|
||||
rfbDrawStringWithClip(s,m->font,m->okX+m->xhot,m->okY-1+m->yhot,okStr,
|
||||
m->x1,m->okY-m->textH,m->x2,m->okY,
|
||||
bcolour,colour);
|
||||
} else
|
||||
rfbDrawString(s,m->font,m->okX+m->xhot,m->okY-1+m->yhot,okStr,colour);
|
||||
|
||||
if(invertCancel) {
|
||||
rfbFillRect(s,m->cancelBX,m->okY-m->textH,
|
||||
m->cancelBX+m->buttonWidth,m->okY,colour);
|
||||
rfbDrawStringWithClip(s,m->font,m->cancelX+m->xhot,m->okY-1+m->yhot,
|
||||
cancelStr,m->x1,m->okY-m->textH,m->x2,m->okY,
|
||||
bcolour,colour);
|
||||
} else
|
||||
rfbDrawString(s,m->font,m->cancelX+m->xhot,m->okY-1+m->yhot,cancelStr,colour);
|
||||
|
||||
m->okInverted = invertOk;
|
||||
m->cancelInverted = invertCancel;
|
||||
}
|
||||
|
||||
/* line is relative to displayStart */
|
||||
static void selPaintLine(rfbSelectData* m,int line,rfbBool invert)
|
||||
{
|
||||
int y1 = m->y1+line*m->textH, y2 = y1+m->textH;
|
||||
if(y2>m->y2)
|
||||
y2=m->y2;
|
||||
rfbFillRect(m->screen,m->x1,y1,m->x2,y2,invert?m->colour:m->backColour);
|
||||
if(m->displayStart+line<m->listSize)
|
||||
rfbDrawStringWithClip(m->screen,m->font,m->x1+m->xhot,y2-1+m->yhot,
|
||||
m->list[m->displayStart+line],
|
||||
m->x1,y1,m->x2,y2,
|
||||
invert?m->backColour:m->colour,
|
||||
invert?m->backColour:m->colour);
|
||||
}
|
||||
|
||||
static void selSelect(rfbSelectData* m,int _index)
|
||||
{
|
||||
int delta;
|
||||
|
||||
if(_index==m->selected || _index<0 || _index>=m->listSize)
|
||||
return;
|
||||
|
||||
if(m->selected>=0)
|
||||
selPaintLine(m,m->selected-m->displayStart,FALSE);
|
||||
|
||||
if(_index<m->displayStart || _index>=m->displayStart+m->pageH) {
|
||||
/* targetLine is the screen line in which the selected line will
|
||||
be displayed.
|
||||
targetLine = m->pageH/2 doesn't look so nice */
|
||||
int targetLine = m->selected-m->displayStart;
|
||||
int lineStart,lineEnd;
|
||||
|
||||
/* scroll */
|
||||
if(_index<targetLine)
|
||||
targetLine = _index;
|
||||
else if(_index+m->pageH-targetLine>=m->listSize)
|
||||
targetLine = _index+m->pageH-m->listSize;
|
||||
delta = _index-(m->displayStart+targetLine);
|
||||
|
||||
if(delta>-m->pageH && delta<m->pageH) {
|
||||
if(delta>0) {
|
||||
lineStart = m->pageH-delta;
|
||||
lineEnd = m->pageH;
|
||||
rfbDoCopyRect(m->screen,m->x1,m->y1,m->x2,m->y1+lineStart*m->textH,
|
||||
0,-delta*m->textH);
|
||||
} else {
|
||||
lineStart = 0;
|
||||
lineEnd = -delta;
|
||||
rfbDoCopyRect(m->screen,
|
||||
m->x1,m->y1+lineEnd*m->textH,m->x2,m->y2,
|
||||
0,-delta*m->textH);
|
||||
}
|
||||
} else {
|
||||
lineStart = 0;
|
||||
lineEnd = m->pageH;
|
||||
}
|
||||
m->displayStart += delta;
|
||||
for(delta=lineStart;delta<lineEnd;delta++)
|
||||
if(delta!=_index)
|
||||
selPaintLine(m,delta,FALSE);
|
||||
}
|
||||
|
||||
m->selected = _index;
|
||||
selPaintLine(m,m->selected-m->displayStart,TRUE);
|
||||
|
||||
if(m->selChangedHook)
|
||||
m->selChangedHook(_index);
|
||||
|
||||
/* todo: scrollbars */
|
||||
}
|
||||
|
||||
static void selKbdAddEvent(rfbBool down,rfbKeySym keySym,rfbClientPtr cl)
|
||||
{
|
||||
if(down) {
|
||||
if(keySym>' ' && keySym<0xff) {
|
||||
int i;
|
||||
rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
|
||||
char c = tolower(keySym);
|
||||
|
||||
for(i=m->selected+1;m->list[i] && tolower(m->list[i][0])!=c;i++);
|
||||
if(!m->list[i])
|
||||
for(i=0;i<m->selected && tolower(m->list[i][0])!=c;i++);
|
||||
selSelect(m,i);
|
||||
} else if(keySym==XK_Escape) {
|
||||
rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
|
||||
m->state = CANCEL;
|
||||
} else if(keySym==XK_Return) {
|
||||
rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
|
||||
m->state = OK;
|
||||
} else {
|
||||
rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
|
||||
int curSel=m->selected;
|
||||
if(keySym==XK_Up) {
|
||||
if(curSel>0)
|
||||
selSelect(m,curSel-1);
|
||||
} else if(keySym==XK_Down) {
|
||||
if(curSel+1<m->listSize)
|
||||
selSelect(m,curSel+1);
|
||||
} else {
|
||||
if(keySym==XK_Page_Down) {
|
||||
if(curSel+m->pageH<m->listSize)
|
||||
selSelect(m,curSel+m->pageH);
|
||||
else
|
||||
selSelect(m,m->listSize-1);
|
||||
} else if(keySym==XK_Page_Up) {
|
||||
if(curSel-m->pageH>=0)
|
||||
selSelect(m,curSel-m->pageH);
|
||||
else
|
||||
selSelect(m,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void selPtrAddEvent(int buttonMask,int x,int y,rfbClientPtr cl)
|
||||
{
|
||||
rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
|
||||
if(y<m->okY && y>=m->okY-m->textH) {
|
||||
if(x>=m->okBX && x<m->okBX+m->buttonWidth) {
|
||||
if(!m->okInverted)
|
||||
selPaintButtons(m,TRUE,FALSE);
|
||||
if(buttonMask)
|
||||
m->state = OK;
|
||||
} else if(x>=m->cancelBX && x<m->cancelBX+m->buttonWidth) {
|
||||
if(!m->cancelInverted)
|
||||
selPaintButtons(m,FALSE,TRUE);
|
||||
if(buttonMask)
|
||||
m->state = CANCEL;
|
||||
} else if(m->okInverted || m->cancelInverted)
|
||||
selPaintButtons(m,FALSE,FALSE);
|
||||
} else {
|
||||
if(m->okInverted || m->cancelInverted)
|
||||
selPaintButtons(m,FALSE,FALSE);
|
||||
if(!m->lastButtons && buttonMask) {
|
||||
if(x>=m->x1 && x<m->x2 && y>=m->y1 && y<m->y2)
|
||||
selSelect(m,m->displayStart+(y-m->y1)/m->textH);
|
||||
}
|
||||
}
|
||||
m->lastButtons = buttonMask;
|
||||
|
||||
/* todo: scrollbars */
|
||||
}
|
||||
|
||||
static rfbCursorPtr selGetCursorPtr(rfbClientPtr cl)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rfbSelectBox(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
|
||||
char** list,
|
||||
int x1,int y1,int x2,int y2,
|
||||
rfbPixel colour,rfbPixel backColour,
|
||||
int border,SelectionChangedHookPtr selChangedHook)
|
||||
{
|
||||
int bpp = rfbScreen->bitsPerPixel/8;
|
||||
char* frameBufferBackup;
|
||||
void* screenDataBackup = rfbScreen->screenData;
|
||||
rfbKbdAddEventProcPtr kbdAddEventBackup = rfbScreen->kbdAddEvent;
|
||||
rfbPtrAddEventProcPtr ptrAddEventBackup = rfbScreen->ptrAddEvent;
|
||||
rfbGetCursorProcPtr getCursorPtrBackup = rfbScreen->getCursorPtr;
|
||||
rfbDisplayHookPtr displayHookBackup = rfbScreen->displayHook;
|
||||
rfbSelectData selData;
|
||||
int i,j,k;
|
||||
int fx1,fy1,fx2,fy2; /* for font bbox */
|
||||
|
||||
if(list==0 || *list==0)
|
||||
return(-1);
|
||||
|
||||
rfbWholeFontBBox(font, &fx1, &fy1, &fx2, &fy2);
|
||||
selData.textH = fy2-fy1;
|
||||
/* I need at least one line for the choice and one for the buttons */
|
||||
if(y2-y1<selData.textH*2+3*border)
|
||||
return(-1);
|
||||
selData.xhot = -fx1;
|
||||
selData.yhot = -fy2;
|
||||
selData.x1 = x1+border;
|
||||
selData.y1 = y1+border;
|
||||
selData.y2 = y2-selData.textH-3*border;
|
||||
selData.x2 = x2-2*border;
|
||||
selData.pageH = (selData.y2-selData.y1)/selData.textH;
|
||||
|
||||
i = rfbWidthOfString(font,okStr);
|
||||
j = rfbWidthOfString(font,cancelStr);
|
||||
selData.buttonWidth= k = 4*border+(i<j?j:i);
|
||||
selData.okBX = x1+(x2-x1-2*k)/3;
|
||||
if(selData.okBX<x1+border) /* too narrow! */
|
||||
return(-1);
|
||||
selData.cancelBX = x1+k+(x2-x1-2*k)*2/3;
|
||||
selData.okX = selData.okBX+(k-i)/2;
|
||||
selData.cancelX = selData.cancelBX+(k-j)/2;
|
||||
selData.okY = y2-border;
|
||||
|
||||
frameBufferBackup = (char*)malloc((size_t)bpp*(x2-x1)*(y2-y1));
|
||||
if (!frameBufferBackup)
|
||||
return(-1);
|
||||
|
||||
selData.state = SELECTING;
|
||||
selData.screen = rfbScreen;
|
||||
selData.font = font;
|
||||
selData.list = list;
|
||||
selData.colour = colour;
|
||||
selData.backColour = backColour;
|
||||
for(i=0;list[i];i++);
|
||||
selData.selected = i;
|
||||
selData.listSize = i;
|
||||
selData.displayStart = i;
|
||||
selData.lastButtons = 0;
|
||||
selData.selChangedHook = selChangedHook;
|
||||
|
||||
rfbScreen->screenData = &selData;
|
||||
rfbScreen->kbdAddEvent = selKbdAddEvent;
|
||||
rfbScreen->ptrAddEvent = selPtrAddEvent;
|
||||
rfbScreen->getCursorPtr = selGetCursorPtr;
|
||||
rfbScreen->displayHook = NULL;
|
||||
|
||||
/* backup screen */
|
||||
for(j=0;j<y2-y1;j++)
|
||||
memcpy(frameBufferBackup+j*(x2-x1)*bpp,
|
||||
rfbScreen->frameBuffer+j*rfbScreen->paddedWidthInBytes+x1*bpp,
|
||||
(size_t)(x2-x1)*bpp);
|
||||
|
||||
/* paint list and buttons */
|
||||
rfbFillRect(rfbScreen,x1,y1,x2,y2,colour);
|
||||
selPaintButtons(&selData,FALSE,FALSE);
|
||||
selSelect(&selData,0);
|
||||
|
||||
/* modal loop */
|
||||
while(selData.state == SELECTING)
|
||||
rfbProcessEvents(rfbScreen,20000);
|
||||
|
||||
/* copy back screen data */
|
||||
for(j=0;j<y2-y1;j++)
|
||||
memcpy(rfbScreen->frameBuffer+j*rfbScreen->paddedWidthInBytes+x1*bpp,
|
||||
frameBufferBackup+j*(x2-x1)*bpp,
|
||||
(size_t)(x2-x1)*bpp);
|
||||
free(frameBufferBackup);
|
||||
rfbMarkRectAsModified(rfbScreen,x1,y1,x2,y2);
|
||||
rfbScreen->screenData = screenDataBackup;
|
||||
rfbScreen->kbdAddEvent = kbdAddEventBackup;
|
||||
rfbScreen->ptrAddEvent = ptrAddEventBackup;
|
||||
rfbScreen->getCursorPtr = getCursorPtrBackup;
|
||||
rfbScreen->displayHook = displayHookBackup;
|
||||
|
||||
if(selData.state==CANCEL)
|
||||
selData.selected=-1;
|
||||
return(selData.selected);
|
||||
}
|
||||
|
||||
1218
android/extern/libvncserver/src/libvncserver/sockets.c
vendored
Normal file
1218
android/extern/libvncserver/src/libvncserver/sockets.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
481
android/extern/libvncserver/src/libvncserver/stats.c
vendored
Normal file
481
android/extern/libvncserver/src/libvncserver/stats.c
vendored
Normal file
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
* stats.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd.
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
char *messageNameServer2Client(uint32_t type, char *buf, int len);
|
||||
char *messageNameClient2Server(uint32_t type, char *buf, int len);
|
||||
char *encodingName(uint32_t enc, char *buf, int len);
|
||||
|
||||
rfbStatList *rfbStatLookupEncoding(rfbClientPtr cl, uint32_t type);
|
||||
rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type);
|
||||
|
||||
void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
|
||||
void rfbStatRecordEncodingRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
|
||||
void rfbStatRecordMessageSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
|
||||
void rfbStatRecordMessageRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
|
||||
void rfbResetStats(rfbClientPtr cl);
|
||||
void rfbPrintStats(rfbClientPtr cl);
|
||||
|
||||
|
||||
|
||||
|
||||
char *messageNameServer2Client(uint32_t type, char *buf, int len) {
|
||||
if (buf==NULL) return "error";
|
||||
switch (type) {
|
||||
case rfbFramebufferUpdate: snprintf(buf, len, "FramebufferUpdate"); break;
|
||||
case rfbSetColourMapEntries: snprintf(buf, len, "SetColourMapEntries"); break;
|
||||
case rfbBell: snprintf(buf, len, "Bell"); break;
|
||||
case rfbServerCutText: snprintf(buf, len, "ServerCutText"); break;
|
||||
case rfbResizeFrameBuffer: snprintf(buf, len, "ResizeFrameBuffer"); break;
|
||||
case rfbFileTransfer: snprintf(buf, len, "FileTransfer"); break;
|
||||
case rfbTextChat: snprintf(buf, len, "TextChat"); break;
|
||||
case rfbPalmVNCReSizeFrameBuffer: snprintf(buf, len, "PalmVNCReSize"); break;
|
||||
case rfbXvp: snprintf(buf, len, "XvpServerMessage"); break;
|
||||
default:
|
||||
snprintf(buf, len, "svr2cli-0x%08X", 0xFF);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *messageNameClient2Server(uint32_t type, char *buf, int len) {
|
||||
if (buf==NULL) return "error";
|
||||
switch (type) {
|
||||
case rfbSetPixelFormat: snprintf(buf, len, "SetPixelFormat"); break;
|
||||
case rfbFixColourMapEntries: snprintf(buf, len, "FixColourMapEntries"); break;
|
||||
case rfbSetEncodings: snprintf(buf, len, "SetEncodings"); break;
|
||||
case rfbFramebufferUpdateRequest: snprintf(buf, len, "FramebufferUpdate"); break;
|
||||
case rfbKeyEvent: snprintf(buf, len, "KeyEvent"); break;
|
||||
case rfbPointerEvent: snprintf(buf, len, "PointerEvent"); break;
|
||||
case rfbClientCutText: snprintf(buf, len, "ClientCutText"); break;
|
||||
case rfbFileTransfer: snprintf(buf, len, "FileTransfer"); break;
|
||||
case rfbSetScale: snprintf(buf, len, "SetScale"); break;
|
||||
case rfbSetServerInput: snprintf(buf, len, "SetServerInput"); break;
|
||||
case rfbSetSW: snprintf(buf, len, "SetSingleWindow"); break;
|
||||
case rfbTextChat: snprintf(buf, len, "TextChat"); break;
|
||||
case rfbPalmVNCSetScaleFactor: snprintf(buf, len, "PalmVNCSetScale"); break;
|
||||
case rfbXvp: snprintf(buf, len, "XvpClientMessage"); break;
|
||||
case rfbSetDesktopSize: snprintf(buf, len, "SetDesktopSize"); break;
|
||||
default:
|
||||
snprintf(buf, len, "cli2svr-0x%08X", type);
|
||||
|
||||
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Encoding name must be <=16 characters to fit nicely on the status output in
|
||||
* an 80 column terminal window
|
||||
*/
|
||||
char *encodingName(uint32_t type, char *buf, int len) {
|
||||
if (buf==NULL) return "error";
|
||||
|
||||
switch (type) {
|
||||
case rfbEncodingRaw: snprintf(buf, len, "raw"); break;
|
||||
case rfbEncodingCopyRect: snprintf(buf, len, "copyRect"); break;
|
||||
case rfbEncodingRRE: snprintf(buf, len, "RRE"); break;
|
||||
case rfbEncodingCoRRE: snprintf(buf, len, "CoRRE"); break;
|
||||
case rfbEncodingHextile: snprintf(buf, len, "hextile"); break;
|
||||
case rfbEncodingZlib: snprintf(buf, len, "zlib"); break;
|
||||
case rfbEncodingTight: snprintf(buf, len, "tight"); break;
|
||||
case rfbEncodingTightPng: snprintf(buf, len, "tightPng"); break;
|
||||
case rfbEncodingZlibHex: snprintf(buf, len, "zlibhex"); break;
|
||||
case rfbEncodingUltra: snprintf(buf, len, "ultra"); break;
|
||||
case rfbEncodingZRLE: snprintf(buf, len, "ZRLE"); break;
|
||||
case rfbEncodingZYWRLE: snprintf(buf, len, "ZYWRLE"); break;
|
||||
case rfbEncodingCache: snprintf(buf, len, "cache"); break;
|
||||
case rfbEncodingCacheEnable: snprintf(buf, len, "cacheEnable"); break;
|
||||
case rfbEncodingXOR_Zlib: snprintf(buf, len, "xorZlib"); break;
|
||||
case rfbEncodingXORMonoColor_Zlib: snprintf(buf, len, "xorMonoZlib"); break;
|
||||
case rfbEncodingXORMultiColor_Zlib: snprintf(buf, len, "xorColorZlib"); break;
|
||||
case rfbEncodingSolidColor: snprintf(buf, len, "solidColor"); break;
|
||||
case rfbEncodingXOREnable: snprintf(buf, len, "xorEnable"); break;
|
||||
case rfbEncodingCacheZip: snprintf(buf, len, "cacheZip"); break;
|
||||
case rfbEncodingSolMonoZip: snprintf(buf, len, "monoZip"); break;
|
||||
case rfbEncodingUltraZip: snprintf(buf, len, "ultraZip"); break;
|
||||
|
||||
case rfbEncodingXCursor: snprintf(buf, len, "Xcursor"); break;
|
||||
case rfbEncodingRichCursor: snprintf(buf, len, "RichCursor"); break;
|
||||
case rfbEncodingPointerPos: snprintf(buf, len, "PointerPos"); break;
|
||||
|
||||
case rfbEncodingLastRect: snprintf(buf, len, "LastRect"); break;
|
||||
case rfbEncodingNewFBSize: snprintf(buf, len, "NewFBSize"); break;
|
||||
case rfbEncodingExtDesktopSize: snprintf(buf, len, "ExtendedDesktopSize"); break;
|
||||
case rfbEncodingKeyboardLedState: snprintf(buf, len, "LedState"); break;
|
||||
case rfbEncodingSupportedMessages: snprintf(buf, len, "SupportedMessage"); break;
|
||||
case rfbEncodingSupportedEncodings: snprintf(buf, len, "SupportedEncoding"); break;
|
||||
case rfbEncodingServerIdentity: snprintf(buf, len, "ServerIdentify"); break;
|
||||
|
||||
/* The following lookups do not report in stats */
|
||||
case rfbEncodingCompressLevel0: snprintf(buf, len, "CompressLevel0"); break;
|
||||
case rfbEncodingCompressLevel1: snprintf(buf, len, "CompressLevel1"); break;
|
||||
case rfbEncodingCompressLevel2: snprintf(buf, len, "CompressLevel2"); break;
|
||||
case rfbEncodingCompressLevel3: snprintf(buf, len, "CompressLevel3"); break;
|
||||
case rfbEncodingCompressLevel4: snprintf(buf, len, "CompressLevel4"); break;
|
||||
case rfbEncodingCompressLevel5: snprintf(buf, len, "CompressLevel5"); break;
|
||||
case rfbEncodingCompressLevel6: snprintf(buf, len, "CompressLevel6"); break;
|
||||
case rfbEncodingCompressLevel7: snprintf(buf, len, "CompressLevel7"); break;
|
||||
case rfbEncodingCompressLevel8: snprintf(buf, len, "CompressLevel8"); break;
|
||||
case rfbEncodingCompressLevel9: snprintf(buf, len, "CompressLevel9"); break;
|
||||
|
||||
case rfbEncodingQualityLevel0: snprintf(buf, len, "QualityLevel0"); break;
|
||||
case rfbEncodingQualityLevel1: snprintf(buf, len, "QualityLevel1"); break;
|
||||
case rfbEncodingQualityLevel2: snprintf(buf, len, "QualityLevel2"); break;
|
||||
case rfbEncodingQualityLevel3: snprintf(buf, len, "QualityLevel3"); break;
|
||||
case rfbEncodingQualityLevel4: snprintf(buf, len, "QualityLevel4"); break;
|
||||
case rfbEncodingQualityLevel5: snprintf(buf, len, "QualityLevel5"); break;
|
||||
case rfbEncodingQualityLevel6: snprintf(buf, len, "QualityLevel6"); break;
|
||||
case rfbEncodingQualityLevel7: snprintf(buf, len, "QualityLevel7"); break;
|
||||
case rfbEncodingQualityLevel8: snprintf(buf, len, "QualityLevel8"); break;
|
||||
case rfbEncodingQualityLevel9: snprintf(buf, len, "QualityLevel9"); break;
|
||||
|
||||
|
||||
default:
|
||||
snprintf(buf, len, "Enc(0x%08X)", type);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
rfbStatList *rfbStatLookupEncoding(rfbClientPtr cl, uint32_t type)
|
||||
{
|
||||
rfbStatList *ptr;
|
||||
if (cl==NULL) return NULL;
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
{
|
||||
if (ptr->type==type) return ptr;
|
||||
}
|
||||
/* Well, we are here... need to *CREATE* an entry */
|
||||
ptr = (rfbStatList *)malloc(sizeof(rfbStatList));
|
||||
if (ptr!=NULL)
|
||||
{
|
||||
memset((char *)ptr, 0, sizeof(rfbStatList));
|
||||
ptr->type = type;
|
||||
/* add to the top of the list */
|
||||
ptr->Next = cl->statEncList;
|
||||
cl->statEncList = ptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type)
|
||||
{
|
||||
rfbStatList *ptr;
|
||||
if (cl==NULL) return NULL;
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
{
|
||||
if (ptr->type==type) return ptr;
|
||||
}
|
||||
/* Well, we are here... need to *CREATE* an entry */
|
||||
ptr = (rfbStatList *)malloc(sizeof(rfbStatList));
|
||||
if (ptr!=NULL)
|
||||
{
|
||||
memset((char *)ptr, 0, sizeof(rfbStatList));
|
||||
ptr->type = type;
|
||||
/* add to the top of the list */
|
||||
ptr->Next = cl->statMsgList;
|
||||
cl->statMsgList = ptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void rfbStatRecordEncodingSentAdd(rfbClientPtr cl, uint32_t type, int byteCount) /* Specifically for tight encoding */
|
||||
{
|
||||
rfbStatList *ptr;
|
||||
|
||||
ptr = rfbStatLookupEncoding(cl, type);
|
||||
if (ptr!=NULL)
|
||||
ptr->bytesSent += byteCount;
|
||||
}
|
||||
|
||||
|
||||
void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
|
||||
{
|
||||
rfbStatList *ptr;
|
||||
|
||||
ptr = rfbStatLookupEncoding(cl, type);
|
||||
if (ptr!=NULL)
|
||||
{
|
||||
ptr->sentCount++;
|
||||
ptr->bytesSent += byteCount;
|
||||
ptr->bytesSentIfRaw += byteIfRaw;
|
||||
}
|
||||
}
|
||||
|
||||
void rfbStatRecordEncodingRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
|
||||
{
|
||||
rfbStatList *ptr;
|
||||
|
||||
ptr = rfbStatLookupEncoding(cl, type);
|
||||
if (ptr!=NULL)
|
||||
{
|
||||
ptr->rcvdCount++;
|
||||
ptr->bytesRcvd += byteCount;
|
||||
ptr->bytesRcvdIfRaw += byteIfRaw;
|
||||
}
|
||||
}
|
||||
|
||||
void rfbStatRecordMessageSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
|
||||
{
|
||||
rfbStatList *ptr;
|
||||
|
||||
ptr = rfbStatLookupMessage(cl, type);
|
||||
if (ptr!=NULL)
|
||||
{
|
||||
ptr->sentCount++;
|
||||
ptr->bytesSent += byteCount;
|
||||
ptr->bytesSentIfRaw += byteIfRaw;
|
||||
}
|
||||
}
|
||||
|
||||
void rfbStatRecordMessageRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
|
||||
{
|
||||
rfbStatList *ptr;
|
||||
|
||||
ptr = rfbStatLookupMessage(cl, type);
|
||||
if (ptr!=NULL)
|
||||
{
|
||||
ptr->rcvdCount++;
|
||||
ptr->bytesRcvd += byteCount;
|
||||
ptr->bytesRcvdIfRaw += byteIfRaw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int rfbStatGetSentBytes(rfbClientPtr cl)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
int bytes=0;
|
||||
if (cl==NULL) return 0;
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
bytes += ptr->bytesSent;
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
bytes += ptr->bytesSent;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int rfbStatGetSentBytesIfRaw(rfbClientPtr cl)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
int bytes=0;
|
||||
if (cl==NULL) return 0;
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
bytes += ptr->bytesSentIfRaw;
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
bytes += ptr->bytesSentIfRaw;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int rfbStatGetRcvdBytes(rfbClientPtr cl)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
int bytes=0;
|
||||
if (cl==NULL) return 0;
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
bytes += ptr->bytesRcvd;
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
bytes += ptr->bytesRcvd;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int rfbStatGetRcvdBytesIfRaw(rfbClientPtr cl)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
int bytes=0;
|
||||
if (cl==NULL) return 0;
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
bytes += ptr->bytesRcvdIfRaw;
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
bytes += ptr->bytesRcvdIfRaw;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int rfbStatGetMessageCountSent(rfbClientPtr cl, uint32_t type)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
if (cl==NULL) return 0;
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
if (ptr->type==type) return ptr->sentCount;
|
||||
return 0;
|
||||
}
|
||||
int rfbStatGetMessageCountRcvd(rfbClientPtr cl, uint32_t type)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
if (cl==NULL) return 0;
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
if (ptr->type==type) return ptr->rcvdCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rfbStatGetEncodingCountSent(rfbClientPtr cl, uint32_t type)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
if (cl==NULL) return 0;
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
if (ptr->type==type) return ptr->sentCount;
|
||||
return 0;
|
||||
}
|
||||
int rfbStatGetEncodingCountRcvd(rfbClientPtr cl, uint32_t type)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
if (cl==NULL) return 0;
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
if (ptr->type==type) return ptr->rcvdCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void rfbResetStats(rfbClientPtr cl)
|
||||
{
|
||||
rfbStatList *ptr;
|
||||
if (cl==NULL) return;
|
||||
while (cl->statEncList!=NULL)
|
||||
{
|
||||
ptr = cl->statEncList;
|
||||
cl->statEncList = ptr->Next;
|
||||
free(ptr);
|
||||
}
|
||||
while (cl->statMsgList!=NULL)
|
||||
{
|
||||
ptr = cl->statMsgList;
|
||||
cl->statMsgList = ptr->Next;
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rfbPrintStats(rfbClientPtr cl)
|
||||
{
|
||||
rfbStatList *ptr=NULL;
|
||||
char encBuf[64];
|
||||
double savings=0.0;
|
||||
int totalRects=0;
|
||||
double totalBytes=0.0;
|
||||
double totalBytesIfRaw=0.0;
|
||||
|
||||
char *name=NULL;
|
||||
int bytes=0;
|
||||
int bytesIfRaw=0;
|
||||
int count=0;
|
||||
|
||||
if (cl==NULL) return;
|
||||
|
||||
rfbLog("%-21.21s %-6.6s %9.9s/%9.9s (%6.6s)\n", "Statistics", "events", "Transmit","RawEquiv","saved");
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
{
|
||||
name = messageNameServer2Client(ptr->type, encBuf, sizeof(encBuf));
|
||||
count = ptr->sentCount;
|
||||
bytes = ptr->bytesSent;
|
||||
bytesIfRaw = ptr->bytesSentIfRaw;
|
||||
|
||||
savings = 0.0;
|
||||
if (bytesIfRaw>0.0)
|
||||
savings = 100.0 - (((double)bytes / (double)bytesIfRaw) * 100.0);
|
||||
if ((bytes>0) || (count>0) || (bytesIfRaw>0))
|
||||
rfbLog(" %-20.20s: %6d | %9d/%9d (%5.1f%%)\n",
|
||||
name, count, bytes, bytesIfRaw, savings);
|
||||
totalRects += count;
|
||||
totalBytes += bytes;
|
||||
totalBytesIfRaw += bytesIfRaw;
|
||||
}
|
||||
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
{
|
||||
name = encodingName(ptr->type, encBuf, sizeof(encBuf));
|
||||
count = ptr->sentCount;
|
||||
bytes = ptr->bytesSent;
|
||||
bytesIfRaw = ptr->bytesSentIfRaw;
|
||||
savings = 0.0;
|
||||
|
||||
if (bytesIfRaw>0.0)
|
||||
savings = 100.0 - (((double)bytes / (double)bytesIfRaw) * 100.0);
|
||||
if ((bytes>0) || (count>0) || (bytesIfRaw>0))
|
||||
rfbLog(" %-20.20s: %6d | %9d/%9d (%5.1f%%)\n",
|
||||
name, count, bytes, bytesIfRaw, savings);
|
||||
totalRects += count;
|
||||
totalBytes += bytes;
|
||||
totalBytesIfRaw += bytesIfRaw;
|
||||
}
|
||||
savings=0.0;
|
||||
if (totalBytesIfRaw>0.0)
|
||||
savings = 100.0 - ((totalBytes/totalBytesIfRaw)*100.0);
|
||||
rfbLog(" %-20.20s: %6d | %9.0f/%9.0f (%5.1f%%)\n",
|
||||
"TOTALS", totalRects, totalBytes,totalBytesIfRaw, savings);
|
||||
|
||||
totalRects=0.0;
|
||||
totalBytes=0.0;
|
||||
totalBytesIfRaw=0.0;
|
||||
|
||||
rfbLog("%-21.21s %-6.6s %9.9s/%9.9s (%6.6s)\n", "Statistics", "events", "Received","RawEquiv","saved");
|
||||
for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
|
||||
{
|
||||
name = messageNameClient2Server(ptr->type, encBuf, sizeof(encBuf));
|
||||
count = ptr->rcvdCount;
|
||||
bytes = ptr->bytesRcvd;
|
||||
bytesIfRaw = ptr->bytesRcvdIfRaw;
|
||||
savings = 0.0;
|
||||
|
||||
if (bytesIfRaw>0.0)
|
||||
savings = 100.0 - (((double)bytes / (double)bytesIfRaw) * 100.0);
|
||||
if ((bytes>0) || (count>0) || (bytesIfRaw>0))
|
||||
rfbLog(" %-20.20s: %6d | %9d/%9d (%5.1f%%)\n",
|
||||
name, count, bytes, bytesIfRaw, savings);
|
||||
totalRects += count;
|
||||
totalBytes += bytes;
|
||||
totalBytesIfRaw += bytesIfRaw;
|
||||
}
|
||||
for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
|
||||
{
|
||||
name = encodingName(ptr->type, encBuf, sizeof(encBuf));
|
||||
count = ptr->rcvdCount;
|
||||
bytes = ptr->bytesRcvd;
|
||||
bytesIfRaw = ptr->bytesRcvdIfRaw;
|
||||
savings = 0.0;
|
||||
|
||||
if (bytesIfRaw>0.0)
|
||||
savings = 100.0 - (((double)bytes / (double)bytesIfRaw) * 100.0);
|
||||
if ((bytes>0) || (count>0) || (bytesIfRaw>0))
|
||||
rfbLog(" %-20.20s: %6d | %9d/%9d (%5.1f%%)\n",
|
||||
name, count, bytes, bytesIfRaw, savings);
|
||||
totalRects += count;
|
||||
totalBytes += bytes;
|
||||
totalBytesIfRaw += bytesIfRaw;
|
||||
}
|
||||
savings=0.0;
|
||||
if (totalBytesIfRaw>0.0)
|
||||
savings = 100.0 - ((totalBytes/totalBytesIfRaw)*100.0);
|
||||
rfbLog(" %-20.20s: %6d | %9.0f/%9.0f (%5.1f%%)\n",
|
||||
"TOTALS", totalRects, totalBytes,totalBytesIfRaw, savings);
|
||||
|
||||
}
|
||||
|
||||
158
android/extern/libvncserver/src/libvncserver/tableinit24.c
vendored
Normal file
158
android/extern/libvncserver/src/libvncserver/tableinit24.c
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
24 bit
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbInitOneRGBTable24 (uint8_t *table, int inMax, int outMax, int outShift,int swap);
|
||||
|
||||
|
||||
static void
|
||||
rfbInitColourMapSingleTable24(char **table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,rfbColourMap* colourMap)
|
||||
{
|
||||
uint32_t i, r, g, b, outValue;
|
||||
uint8_t *t;
|
||||
uint8_t c;
|
||||
unsigned int nEntries = 1 << in->bitsPerPixel;
|
||||
int shift = colourMap->is16?16:8;
|
||||
|
||||
if (*table) free(*table);
|
||||
*table = (char *)malloc(nEntries * 3 + 1);
|
||||
t = (uint8_t *)*table;
|
||||
|
||||
for (i = 0; i < nEntries; i++) {
|
||||
r = g = b = 0;
|
||||
if(i < colourMap->count) {
|
||||
if(colourMap->is16) {
|
||||
r = colourMap->data.shorts[3*i+0];
|
||||
g = colourMap->data.shorts[3*i+1];
|
||||
b = colourMap->data.shorts[3*i+2];
|
||||
} else {
|
||||
r = colourMap->data.bytes[3*i+0];
|
||||
g = colourMap->data.bytes[3*i+1];
|
||||
b = colourMap->data.bytes[3*i+2];
|
||||
}
|
||||
}
|
||||
outValue = ((((r * (1 + out->redMax)) >> shift) << out->redShift) |
|
||||
(((g * (1 + out->greenMax)) >> shift) << out->greenShift) |
|
||||
(((b * (1 + out->blueMax)) >> shift) << out->blueShift));
|
||||
*(uint32_t*)&t[3*i] = outValue;
|
||||
if(!rfbEndianTest)
|
||||
memmove(t+3*i,t+3*i+1,3);
|
||||
if (out->bigEndian != in->bigEndian) {
|
||||
c = t[3*i]; t[3*i] = t[3*i+2]; t[3*i+2] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rfbInitTrueColourSingleTable sets up a single lookup table for truecolour
|
||||
* translation.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbInitTrueColourSingleTable24 (char **table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out)
|
||||
{
|
||||
int i,outValue;
|
||||
int inRed, inGreen, inBlue, outRed, outGreen, outBlue;
|
||||
uint8_t *t;
|
||||
uint8_t c;
|
||||
int nEntries = 1 << in->bitsPerPixel;
|
||||
|
||||
if (*table) free(*table);
|
||||
*table = (char *)malloc(nEntries * 3 + 1);
|
||||
t = (uint8_t *)*table;
|
||||
|
||||
for (i = 0; i < nEntries; i++) {
|
||||
inRed = (i >> in->redShift) & in->redMax;
|
||||
inGreen = (i >> in->greenShift) & in->greenMax;
|
||||
inBlue = (i >> in->blueShift) & in->blueMax;
|
||||
|
||||
outRed = (inRed * out->redMax + in->redMax / 2) / in->redMax;
|
||||
outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax;
|
||||
outBlue = (inBlue * out->blueMax + in->blueMax / 2) / in->blueMax;
|
||||
|
||||
outValue = ((outRed << out->redShift) |
|
||||
(outGreen << out->greenShift) |
|
||||
(outBlue << out->blueShift));
|
||||
*(uint32_t*)&t[3*i] = outValue;
|
||||
if(!rfbEndianTest)
|
||||
memmove(t+3*i,t+3*i+1,3);
|
||||
if (out->bigEndian != in->bigEndian) {
|
||||
c = t[3*i]; t[3*i] = t[3*i+2]; t[3*i+2] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rfbInitTrueColourRGBTables sets up three separate lookup tables for the
|
||||
* red, green and blue values.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbInitTrueColourRGBTables24 (char **table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out)
|
||||
{
|
||||
uint8_t *redTable;
|
||||
uint8_t *greenTable;
|
||||
uint8_t *blueTable;
|
||||
|
||||
if (*table) free(*table);
|
||||
*table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3)
|
||||
* 3 + 1);
|
||||
redTable = (uint8_t *)*table;
|
||||
greenTable = redTable + 3*(in->redMax + 1);
|
||||
blueTable = greenTable + 3*(in->greenMax + 1);
|
||||
|
||||
rfbInitOneRGBTable24 (redTable, in->redMax, out->redMax,
|
||||
out->redShift, (out->bigEndian != in->bigEndian));
|
||||
rfbInitOneRGBTable24 (greenTable, in->greenMax, out->greenMax,
|
||||
out->greenShift, (out->bigEndian != in->bigEndian));
|
||||
rfbInitOneRGBTable24 (blueTable, in->blueMax, out->blueMax,
|
||||
out->blueShift, (out->bigEndian != in->bigEndian));
|
||||
}
|
||||
|
||||
static void
|
||||
rfbInitOneRGBTable24 (uint8_t *table, int inMax, int outMax, int outShift,
|
||||
int swap)
|
||||
{
|
||||
int i;
|
||||
int nEntries = inMax + 1;
|
||||
uint32_t outValue;
|
||||
uint8_t c;
|
||||
|
||||
for (i = 0; i < nEntries; i++) {
|
||||
outValue = ((i * outMax + inMax / 2) / inMax) << outShift;
|
||||
*(uint32_t *)&table[3*i] = outValue;
|
||||
if(!rfbEndianTest) {
|
||||
memmove(table+3*i,table+3*i+1,3);
|
||||
}
|
||||
if (swap) {
|
||||
c = table[3*i]; table[3*i] = table[3*i+2];
|
||||
table[3*i+2] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
84
android/extern/libvncserver/src/libvncserver/tableinitcmtemplate.c
vendored
Normal file
84
android/extern/libvncserver/src/libvncserver/tableinitcmtemplate.c
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* tableinitcmtemplate.c - template for initialising lookup tables for
|
||||
* translation from a colour map to true colour.
|
||||
*
|
||||
* This file shouldn't be compiled. It is included multiple times by
|
||||
* translate.c, each time with a different definition of the macro OUT.
|
||||
* For each value of OUT, this file defines a function which allocates an
|
||||
* appropriately sized lookup table and initialises it.
|
||||
*
|
||||
* I know this code isn't nice to read because of all the macros, but
|
||||
* efficiency is important here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#if !defined(OUT)
|
||||
#error "This file shouldn't be compiled."
|
||||
#error "It is included as part of translate.c"
|
||||
#endif
|
||||
|
||||
#define OUT_T CONCAT3E(uint,OUT,_t)
|
||||
#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
|
||||
#define rfbInitColourMapSingleTableOUT \
|
||||
CONCAT2E(rfbInitColourMapSingleTable,OUT)
|
||||
|
||||
static void
|
||||
rfbInitColourMapSingleTableOUT(char **table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,rfbColourMap* colourMap)
|
||||
{
|
||||
uint32_t i, r, g, b;
|
||||
OUT_T *t;
|
||||
uint32_t nEntries = 1 << in->bitsPerPixel;
|
||||
int shift = colourMap->is16?16:8;
|
||||
|
||||
if (*table) free(*table);
|
||||
*table = (char *)malloc(nEntries * sizeof(OUT_T));
|
||||
t = (OUT_T *)*table;
|
||||
|
||||
for (i = 0; i < nEntries; i++) {
|
||||
r = g = b = 0;
|
||||
if(i < colourMap->count) {
|
||||
if(colourMap->is16) {
|
||||
r = colourMap->data.shorts[3*i+0];
|
||||
g = colourMap->data.shorts[3*i+1];
|
||||
b = colourMap->data.shorts[3*i+2];
|
||||
} else {
|
||||
r = colourMap->data.bytes[3*i+0];
|
||||
g = colourMap->data.bytes[3*i+1];
|
||||
b = colourMap->data.bytes[3*i+2];
|
||||
}
|
||||
}
|
||||
t[i] = ((((r * (1 + out->redMax)) >> shift) << out->redShift) |
|
||||
(((g * (1 + out->greenMax)) >> shift) << out->greenShift) |
|
||||
(((b * (1 + out->blueMax)) >> shift) << out->blueShift));
|
||||
#if (OUT != 8)
|
||||
if (out->bigEndian != in->bigEndian) {
|
||||
t[i] = SwapOUT(t[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#undef OUT_T
|
||||
#undef SwapOUT
|
||||
#undef rfbInitColourMapSingleTableOUT
|
||||
146
android/extern/libvncserver/src/libvncserver/tableinittctemplate.c
vendored
Normal file
146
android/extern/libvncserver/src/libvncserver/tableinittctemplate.c
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* tableinittctemplate.c - template for initialising lookup tables for
|
||||
* truecolour to truecolour translation.
|
||||
*
|
||||
* This file shouldn't be compiled. It is included multiple times by
|
||||
* translate.c, each time with a different definition of the macro OUT.
|
||||
* For each value of OUT, this file defines two functions for initialising
|
||||
* lookup tables. One is for truecolour translation using a single lookup
|
||||
* table, the other is for truecolour translation using three separate
|
||||
* lookup tables for the red, green and blue values.
|
||||
*
|
||||
* I know this code isn't nice to read because of all the macros, but
|
||||
* efficiency is important here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#if !defined(OUT)
|
||||
#error "This file shouldn't be compiled."
|
||||
#error "It is included as part of translate.c"
|
||||
#endif
|
||||
|
||||
#define OUT_T CONCAT3E(uint,OUT,_t)
|
||||
#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
|
||||
#define rfbInitTrueColourSingleTableOUT \
|
||||
CONCAT2E(rfbInitTrueColourSingleTable,OUT)
|
||||
#define rfbInitTrueColourRGBTablesOUT CONCAT2E(rfbInitTrueColourRGBTables,OUT)
|
||||
#define rfbInitOneRGBTableOUT CONCAT2E(rfbInitOneRGBTable,OUT)
|
||||
|
||||
static void
|
||||
rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
|
||||
int swap);
|
||||
|
||||
|
||||
/*
|
||||
* rfbInitTrueColourSingleTable sets up a single lookup table for truecolour
|
||||
* translation.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbInitTrueColourSingleTableOUT (char **table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out)
|
||||
{
|
||||
int i;
|
||||
int inRed, inGreen, inBlue, outRed, outGreen, outBlue;
|
||||
OUT_T *t;
|
||||
int nEntries = 1 << in->bitsPerPixel;
|
||||
|
||||
if (*table) free(*table);
|
||||
*table = (char *)malloc(nEntries * sizeof(OUT_T));
|
||||
t = (OUT_T *)*table;
|
||||
|
||||
for (i = 0; i < nEntries; i++) {
|
||||
inRed = (i >> in->redShift) & in->redMax;
|
||||
inGreen = (i >> in->greenShift) & in->greenMax;
|
||||
inBlue = (i >> in->blueShift) & in->blueMax;
|
||||
|
||||
outRed = (inRed * out->redMax + in->redMax / 2) / in->redMax;
|
||||
outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax;
|
||||
outBlue = (inBlue * out->blueMax + in->blueMax / 2) / in->blueMax;
|
||||
|
||||
t[i] = ((outRed << out->redShift) |
|
||||
(outGreen << out->greenShift) |
|
||||
(outBlue << out->blueShift));
|
||||
#if (OUT != 8)
|
||||
if (out->bigEndian != in->bigEndian) {
|
||||
t[i] = SwapOUT(t[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rfbInitTrueColourRGBTables sets up three separate lookup tables for the
|
||||
* red, green and blue values.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbInitTrueColourRGBTablesOUT (char **table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out)
|
||||
{
|
||||
OUT_T *redTable;
|
||||
OUT_T *greenTable;
|
||||
OUT_T *blueTable;
|
||||
|
||||
if (*table) free(*table);
|
||||
*table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3)
|
||||
* sizeof(OUT_T));
|
||||
redTable = (OUT_T *)*table;
|
||||
greenTable = redTable + in->redMax + 1;
|
||||
blueTable = greenTable + in->greenMax + 1;
|
||||
|
||||
rfbInitOneRGBTableOUT (redTable, in->redMax, out->redMax,
|
||||
out->redShift, (out->bigEndian != in->bigEndian));
|
||||
rfbInitOneRGBTableOUT (greenTable, in->greenMax, out->greenMax,
|
||||
out->greenShift, (out->bigEndian != in->bigEndian));
|
||||
rfbInitOneRGBTableOUT (blueTable, in->blueMax, out->blueMax,
|
||||
out->blueShift, (out->bigEndian != in->bigEndian));
|
||||
}
|
||||
|
||||
static void
|
||||
rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
|
||||
int swap)
|
||||
{
|
||||
int i;
|
||||
int nEntries = inMax + 1;
|
||||
|
||||
for (i = 0; i < nEntries; i++) {
|
||||
if (outShift < 32) {
|
||||
table[i] = ((OUT_T)((i * outMax + inMax / 2) / inMax)) << outShift;
|
||||
} else {
|
||||
table[i] = 0;
|
||||
}
|
||||
#if (OUT != 8)
|
||||
if (swap) {
|
||||
table[i] = SwapOUT(table[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#undef OUT_T
|
||||
#undef SwapOUT
|
||||
#undef rfbInitTrueColourSingleTableOUT
|
||||
#undef rfbInitTrueColourRGBTablesOUT
|
||||
#undef rfbInitOneRGBTableOUT
|
||||
281
android/extern/libvncserver/src/libvncserver/tabletrans24template.c
vendored
Normal file
281
android/extern/libvncserver/src/libvncserver/tabletrans24template.c
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* tabletranstemplate.c - template for translation using lookup tables.
|
||||
*
|
||||
* This file shouldn't be compiled. It is included multiple times by
|
||||
* translate.c, each time with different definitions of the macros IN and OUT.
|
||||
*
|
||||
* For each pair of values IN and OUT, this file defines two functions for
|
||||
* translating a given rectangle of pixel data. One uses a single lookup
|
||||
* table, and the other uses three separate lookup tables for the red, green
|
||||
* and blue values.
|
||||
*
|
||||
* I know this code isn't nice to read because of all the macros, but
|
||||
* efficiency is important here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#if !defined(BPP)
|
||||
#error "This file shouldn't be compiled."
|
||||
#error "It is included as part of translate.c"
|
||||
#endif
|
||||
|
||||
#if BPP == 24
|
||||
|
||||
/*
|
||||
* rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
|
||||
* using a single lookup table.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbTranslateWithSingleTable24to24 (char *table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,
|
||||
char *iptr, char *optr,
|
||||
int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
uint8_t *ip = (uint8_t *)iptr;
|
||||
uint8_t *op = (uint8_t *)optr;
|
||||
int ipextra = bytesBetweenInputLines - width * 3;
|
||||
uint8_t *opLineEnd;
|
||||
uint8_t *t = (uint8_t *)table;
|
||||
int shift = rfbEndianTest?0:8;
|
||||
uint8_t c;
|
||||
|
||||
while (height > 0) {
|
||||
opLineEnd = op + width*3;
|
||||
|
||||
while (op < opLineEnd) {
|
||||
*(uint32_t*)op = t[((*(uint32_t *)ip)>>shift)&0x00ffffff];
|
||||
if(!rfbEndianTest)
|
||||
memmove(op,op+1,3);
|
||||
if (out->bigEndian != in->bigEndian) {
|
||||
c = op[0]; op[0] = op[2]; op[2] = c;
|
||||
}
|
||||
op += 3;
|
||||
ip += 3;
|
||||
}
|
||||
|
||||
ip += ipextra;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
|
||||
* using three separate lookup tables for the red, green and blue values.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbTranslateWithRGBTables24to24 (char *table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,
|
||||
char *iptr, char *optr,
|
||||
int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
uint8_t *ip = (uint8_t *)iptr;
|
||||
uint8_t *op = (uint8_t *)optr;
|
||||
int ipextra = bytesBetweenInputLines - width*3;
|
||||
uint8_t *opLineEnd;
|
||||
uint8_t *redTable = (uint8_t *)table;
|
||||
uint8_t *greenTable = redTable + 3*(in->redMax + 1);
|
||||
uint8_t *blueTable = greenTable + 3*(in->greenMax + 1);
|
||||
uint32_t outValue,inValue;
|
||||
int shift = rfbEndianTest?0:8;
|
||||
|
||||
while (height > 0) {
|
||||
opLineEnd = op+3*width;
|
||||
|
||||
while (op < opLineEnd) {
|
||||
inValue = ((*(uint32_t *)ip)>>shift)&0x00ffffff;
|
||||
outValue = (redTable[(inValue >> in->redShift) & in->redMax] |
|
||||
greenTable[(inValue >> in->greenShift) & in->greenMax] |
|
||||
blueTable[(inValue >> in->blueShift) & in->blueMax]);
|
||||
memcpy(op,&outValue,3);
|
||||
op += 3;
|
||||
ip+=3;
|
||||
}
|
||||
ip += ipextra;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define IN_T CONCAT3E(uint,BPP,_t)
|
||||
#define OUT_T CONCAT3E(uint,BPP,_t)
|
||||
#define rfbTranslateWithSingleTable24toOUT \
|
||||
CONCAT4E(rfbTranslateWithSingleTable,24,to,BPP)
|
||||
#define rfbTranslateWithSingleTableINto24 \
|
||||
CONCAT4E(rfbTranslateWithSingleTable,BPP,to,24)
|
||||
#define rfbTranslateWithRGBTables24toOUT \
|
||||
CONCAT4E(rfbTranslateWithRGBTables,24,to,BPP)
|
||||
#define rfbTranslateWithRGBTablesINto24 \
|
||||
CONCAT4E(rfbTranslateWithRGBTables,BPP,to,24)
|
||||
|
||||
/*
|
||||
* rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
|
||||
* using a single lookup table.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbTranslateWithSingleTable24toOUT (char *table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,
|
||||
char *iptr, char *optr,
|
||||
int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
uint8_t *ip = (uint8_t *)iptr;
|
||||
OUT_T *op = (OUT_T *)optr;
|
||||
int ipextra = bytesBetweenInputLines - width*3;
|
||||
OUT_T *opLineEnd;
|
||||
OUT_T *t = (OUT_T *)table;
|
||||
int shift = rfbEndianTest?0:8;
|
||||
|
||||
while (height > 0) {
|
||||
opLineEnd = op + width;
|
||||
|
||||
while (op < opLineEnd) {
|
||||
*(op++) = t[((*(uint32_t *)ip)>>shift)&0x00ffffff];
|
||||
ip+=3;
|
||||
}
|
||||
|
||||
ip += ipextra;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
|
||||
* using three separate lookup tables for the red, green and blue values.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbTranslateWithRGBTables24toOUT (char *table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,
|
||||
char *iptr, char *optr,
|
||||
int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
uint8_t *ip = (uint8_t *)iptr;
|
||||
OUT_T *op = (OUT_T *)optr;
|
||||
int ipextra = bytesBetweenInputLines - width*3;
|
||||
OUT_T *opLineEnd;
|
||||
OUT_T *redTable = (OUT_T *)table;
|
||||
OUT_T *greenTable = redTable + in->redMax + 1;
|
||||
OUT_T *blueTable = greenTable + in->greenMax + 1;
|
||||
uint32_t inValue;
|
||||
int shift = rfbEndianTest?0:8;
|
||||
|
||||
while (height > 0) {
|
||||
opLineEnd = &op[width];
|
||||
|
||||
while (op < opLineEnd) {
|
||||
inValue = ((*(uint32_t *)ip)>>shift)&0x00ffffff;
|
||||
*(op++) = (redTable[(inValue >> in->redShift) & in->redMax] |
|
||||
greenTable[(inValue >> in->greenShift) & in->greenMax] |
|
||||
blueTable[(inValue >> in->blueShift) & in->blueMax]);
|
||||
ip+=3;
|
||||
}
|
||||
ip += ipextra;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rfbTranslateWithSingleTableINto24 translates a rectangle of pixel data
|
||||
* using a single lookup table.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbTranslateWithSingleTableINto24 (char *table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,
|
||||
char *iptr, char *optr,
|
||||
int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
IN_T *ip = (IN_T *)iptr;
|
||||
uint8_t *op = (uint8_t *)optr;
|
||||
int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
|
||||
uint8_t *opLineEnd;
|
||||
uint8_t *t = (uint8_t *)table;
|
||||
|
||||
while (height > 0) {
|
||||
opLineEnd = op + width * 3;
|
||||
|
||||
while (op < opLineEnd) {
|
||||
memcpy(op,&t[3*(*(ip++))],3);
|
||||
op += 3;
|
||||
}
|
||||
|
||||
ip += ipextra;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rfbTranslateWithRGBTablesINto24 translates a rectangle of pixel data
|
||||
* using three separate lookup tables for the red, green and blue values.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbTranslateWithRGBTablesINto24 (char *table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,
|
||||
char *iptr, char *optr,
|
||||
int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
IN_T *ip = (IN_T *)iptr;
|
||||
uint8_t *op = (uint8_t *)optr;
|
||||
int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
|
||||
uint8_t *opLineEnd;
|
||||
uint8_t *redTable = (uint8_t *)table;
|
||||
uint8_t *greenTable = redTable + 3*(in->redMax + 1);
|
||||
uint8_t *blueTable = greenTable + 3*(in->greenMax + 1);
|
||||
uint32_t outValue;
|
||||
|
||||
while (height > 0) {
|
||||
opLineEnd = op+3*width;
|
||||
|
||||
while (op < opLineEnd) {
|
||||
outValue = (redTable[(*ip >> in->redShift) & in->redMax] |
|
||||
greenTable[(*ip >> in->greenShift) & in->greenMax] |
|
||||
blueTable[(*ip >> in->blueShift) & in->blueMax]);
|
||||
memcpy(op,&outValue,3);
|
||||
op += 3;
|
||||
ip++;
|
||||
}
|
||||
ip += ipextra;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
#undef IN_T
|
||||
#undef OUT_T
|
||||
#undef rfbTranslateWithSingleTable24toOUT
|
||||
#undef rfbTranslateWithRGBTables24toOUT
|
||||
#undef rfbTranslateWithSingleTableINto24
|
||||
#undef rfbTranslateWithRGBTablesINto24
|
||||
|
||||
#endif
|
||||
117
android/extern/libvncserver/src/libvncserver/tabletranstemplate.c
vendored
Normal file
117
android/extern/libvncserver/src/libvncserver/tabletranstemplate.c
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* tabletranstemplate.c - template for translation using lookup tables.
|
||||
*
|
||||
* This file shouldn't be compiled. It is included multiple times by
|
||||
* translate.c, each time with different definitions of the macros IN and OUT.
|
||||
*
|
||||
* For each pair of values IN and OUT, this file defines two functions for
|
||||
* translating a given rectangle of pixel data. One uses a single lookup
|
||||
* table, and the other uses three separate lookup tables for the red, green
|
||||
* and blue values.
|
||||
*
|
||||
* I know this code isn't nice to read because of all the macros, but
|
||||
* efficiency is important here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#if !defined(IN) || !defined(OUT)
|
||||
#error "This file shouldn't be compiled."
|
||||
#error "It is included as part of translate.c"
|
||||
#endif
|
||||
|
||||
#define IN_T CONCAT3E(uint,IN,_t)
|
||||
#define OUT_T CONCAT3E(uint,OUT,_t)
|
||||
#define rfbTranslateWithSingleTableINtoOUT \
|
||||
CONCAT4E(rfbTranslateWithSingleTable,IN,to,OUT)
|
||||
#define rfbTranslateWithRGBTablesINtoOUT \
|
||||
CONCAT4E(rfbTranslateWithRGBTables,IN,to,OUT)
|
||||
|
||||
/*
|
||||
* rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
|
||||
* using a single lookup table.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbTranslateWithSingleTableINtoOUT (char *table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,
|
||||
char *iptr, char *optr,
|
||||
int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
IN_T *ip = (IN_T *)iptr;
|
||||
OUT_T *op = (OUT_T *)optr;
|
||||
int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
|
||||
OUT_T *opLineEnd;
|
||||
OUT_T *t = (OUT_T *)table;
|
||||
|
||||
while (height > 0) {
|
||||
opLineEnd = op + width;
|
||||
|
||||
while (op < opLineEnd) {
|
||||
*(op++) = t[*(ip++)];
|
||||
}
|
||||
|
||||
ip += ipextra;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
|
||||
* using three separate lookup tables for the red, green and blue values.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbTranslateWithRGBTablesINtoOUT (char *table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,
|
||||
char *iptr, char *optr,
|
||||
int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
IN_T *ip = (IN_T *)iptr;
|
||||
OUT_T *op = (OUT_T *)optr;
|
||||
int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
|
||||
OUT_T *opLineEnd;
|
||||
OUT_T *redTable = (OUT_T *)table;
|
||||
OUT_T *greenTable = redTable + in->redMax + 1;
|
||||
OUT_T *blueTable = greenTable + in->greenMax + 1;
|
||||
|
||||
while (height > 0) {
|
||||
opLineEnd = &op[width];
|
||||
|
||||
while (op < opLineEnd) {
|
||||
*(op++) = (redTable[(*ip >> in->redShift) & in->redMax] |
|
||||
greenTable[(*ip >> in->greenShift) & in->greenMax] |
|
||||
blueTable[(*ip >> in->blueShift) & in->blueMax]);
|
||||
ip++;
|
||||
}
|
||||
ip += ipextra;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
#undef IN_T
|
||||
#undef OUT_T
|
||||
#undef rfbTranslateWithSingleTableINtoOUT
|
||||
#undef rfbTranslateWithRGBTablesINtoOUT
|
||||
1877
android/extern/libvncserver/src/libvncserver/tight.c
vendored
Normal file
1877
android/extern/libvncserver/src/libvncserver/tight.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
133
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/filelistinfo.c
vendored
Normal file
133
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/filelistinfo.c
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Novell, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail,
|
||||
* you may find current contact information at www.novell.com
|
||||
*
|
||||
* Author : Rohit Kumar
|
||||
* Email ID : rokumar@novell.com
|
||||
* Date : 14th July 2005
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "rfb/rfb.h"
|
||||
#include "filelistinfo.h"
|
||||
|
||||
|
||||
/* This method is used for debugging purpose */
|
||||
void
|
||||
DisplayFileList(FileListInfo fli)
|
||||
{
|
||||
int i = 0;
|
||||
if((fli.pEntries == NULL) || (fli.numEntries == 0)) return;
|
||||
|
||||
rfbLog("DISPLAYING FILE NAMES IN THE LIST ...START\n\n");
|
||||
rfbLog("Numer of entries:: %d\n", fli.numEntries);
|
||||
for(i = 0; i < fli.numEntries; i++)
|
||||
rfbLog("file[%d]\t<%s>\n", i, fli.pEntries[i].name);
|
||||
rfbLog("DISPLAYING FILE NAMES IN THE LIST ...END\n\n");
|
||||
}
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __FUNCTION__ "unknown"
|
||||
#endif
|
||||
|
||||
int
|
||||
AddFileListItemInfo(FileListInfoPtr fileListInfoPtr, char* name,
|
||||
unsigned int size, unsigned int data)
|
||||
{
|
||||
FileListItemInfoPtr fileListItemInfoPtr = (FileListItemInfoPtr)
|
||||
calloc((fileListInfoPtr->numEntries + 1),
|
||||
sizeof(FileListItemInfo));
|
||||
if(fileListItemInfoPtr == NULL) {
|
||||
rfbLog("File [%s]: Method [%s]: fileListItemInfoPtr is NULL\n",
|
||||
__FILE__, __FUNCTION__);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if(fileListInfoPtr->numEntries != 0) {
|
||||
memcpy(fileListItemInfoPtr, fileListInfoPtr->pEntries,
|
||||
fileListInfoPtr->numEntries * sizeof(FileListItemInfo));
|
||||
}
|
||||
|
||||
strcpy(fileListItemInfoPtr[fileListInfoPtr->numEntries].name, name);
|
||||
fileListItemInfoPtr[fileListInfoPtr->numEntries].size = size;
|
||||
fileListItemInfoPtr[fileListInfoPtr->numEntries].data = data;
|
||||
|
||||
if(fileListInfoPtr->pEntries != NULL) {
|
||||
free(fileListInfoPtr->pEntries);
|
||||
fileListInfoPtr->pEntries = NULL;
|
||||
}
|
||||
|
||||
fileListInfoPtr->pEntries = fileListItemInfoPtr;
|
||||
fileListItemInfoPtr = NULL;
|
||||
fileListInfoPtr->numEntries++;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
GetFileNameAt(FileListInfo fileListInfo, int number)
|
||||
{
|
||||
char* name = NULL;
|
||||
if(number >= 0 && number < fileListInfo.numEntries)
|
||||
name = fileListInfo.pEntries[number].name;
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
GetFileSizeAt(FileListInfo fileListInfo, int number)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
if(number >= 0 && number < fileListInfo.numEntries)
|
||||
size = fileListInfo.pEntries[number].size;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
GetFileDataAt(FileListInfo fileListInfo, int number)
|
||||
{
|
||||
unsigned int data = 0;
|
||||
if(number >= 0 && number < fileListInfo.numEntries)
|
||||
data = fileListInfo.pEntries[number].data;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
GetSumOfFileNamesLength(FileListInfo fileListInfo)
|
||||
{
|
||||
int i = 0, sumLen = 0;
|
||||
for(i = 0; i < fileListInfo.numEntries; i++)
|
||||
sumLen += strlen(fileListInfo.pEntries[i].name);
|
||||
return sumLen;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FreeFileListInfo(FileListInfo fileListInfo)
|
||||
{
|
||||
if(fileListInfo.pEntries != NULL) {
|
||||
free(fileListInfo.pEntries);
|
||||
fileListInfo.pEntries = NULL;
|
||||
}
|
||||
fileListInfo.numEntries = 0;
|
||||
}
|
||||
|
||||
65
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/filelistinfo.h
vendored
Normal file
65
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/filelistinfo.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Novell, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail,
|
||||
* you may find current contact information at www.novell.com
|
||||
*
|
||||
* Author : Rohit Kumar
|
||||
* Email ID : rokumar@novell.com
|
||||
* Date : 14th July 2005
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FILE_LIST_INFO_H
|
||||
#define FILE_LIST_INFO_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if !defined(NAME_MAX)
|
||||
#define NAME_MAX 255
|
||||
#endif
|
||||
|
||||
|
||||
#define SUCCESS 1
|
||||
#define FAILURE 0
|
||||
|
||||
typedef struct _FileListItemInfo {
|
||||
char name[NAME_MAX];
|
||||
unsigned int size;
|
||||
unsigned int data;
|
||||
} FileListItemInfo, *FileListItemInfoPtr;
|
||||
|
||||
typedef struct _FileListItemSize {
|
||||
unsigned int size;
|
||||
unsigned int data;
|
||||
} FileListItemSize, *FileListItemSizePtr;
|
||||
|
||||
typedef struct _FileListInfo {
|
||||
FileListItemInfoPtr pEntries;
|
||||
int numEntries;
|
||||
} FileListInfo, *FileListInfoPtr;
|
||||
|
||||
int AddFileListItemInfo(FileListInfoPtr fileListInfoPtr, char* name, unsigned int size, unsigned int data);
|
||||
char* GetFileNameAt(FileListInfo fileListInfo, int number);
|
||||
unsigned int GetFileSizeAt(FileListInfo fileListInfo, int number);
|
||||
unsigned int GetFileDataAt(FileListInfo fileListInfo, int number);
|
||||
unsigned int GetSumOfFileNamesLength(FileListInfo fileListInfo);
|
||||
void FreeFileListInfo(FileListInfo fileListInfo);
|
||||
|
||||
void DisplayFileList(FileListInfo fli);
|
||||
|
||||
#endif
|
||||
|
||||
801
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/filetransfermsg.c
vendored
Normal file
801
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/filetransfermsg.c
vendored
Normal file
@@ -0,0 +1,801 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Novell, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail,
|
||||
* you may find current contact information at www.novell.com
|
||||
*
|
||||
* Author : Rohit Kumar
|
||||
* Email ID : rokumar@novell.com
|
||||
* Date : 14th July 2005
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <sys/utime.h>
|
||||
#define mkdir(path, perms) _mkdir(path) /* Match POSIX signature */
|
||||
#ifdef _MSC_VER
|
||||
#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)
|
||||
#define S_IWUSR S_IWRITE
|
||||
#define S_IRUSR S_IREAD
|
||||
#define S_IWOTH 0x0000002
|
||||
#define S_IROTH 0x0000004
|
||||
#define S_IWGRP 0x0000010
|
||||
#define S_IRGRP 0x0000020
|
||||
/* Prevent POSIX deprecation warnings on MSVC */
|
||||
#define creat _creat
|
||||
#define open _open
|
||||
#define read _read
|
||||
#define write _write
|
||||
#define close _close
|
||||
#define unlink _unlink
|
||||
#endif /* _MSC_VER */
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#if LIBVNCSERVER_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#include "rfbtightproto.h"
|
||||
#include "filelistinfo.h"
|
||||
#include "filetransfermsg.h"
|
||||
#include "handlefiletransferrequest.h"
|
||||
|
||||
#define SZ_RFBBLOCKSIZE 8192
|
||||
|
||||
|
||||
void
|
||||
FreeFileTransferMsg(FileTransferMsg ftm)
|
||||
{
|
||||
|
||||
if(ftm.data != NULL) {
|
||||
free(ftm.data);
|
||||
ftm.data = NULL;
|
||||
}
|
||||
|
||||
ftm.length = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Methods to handle file list request.
|
||||
******************************************************************************/
|
||||
|
||||
int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
|
||||
FileTransferMsg CreateFileListErrMsg(char flags);
|
||||
FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
|
||||
|
||||
|
||||
/*
|
||||
* This is the method called by HandleFileListRequest to get the file list
|
||||
*/
|
||||
|
||||
FileTransferMsg
|
||||
GetFileListResponseMsg(char* path, char flags)
|
||||
{
|
||||
FileTransferMsg fileListMsg;
|
||||
FileListInfo fileListInfo;
|
||||
int status = -1;
|
||||
|
||||
memset(&fileListMsg, 0, sizeof(FileTransferMsg));
|
||||
memset(&fileListInfo, 0, sizeof(FileListInfo));
|
||||
|
||||
|
||||
/* fileListInfo can have null data if the folder is Empty
|
||||
or if some error condition has occurred.
|
||||
The return value is 'failure' only if some error condition has occurred.
|
||||
*/
|
||||
status = CreateFileListInfo(&fileListInfo, path, !(flags & 0x10));
|
||||
|
||||
if(status == FAILURE) {
|
||||
fileListMsg = CreateFileListErrMsg(flags);
|
||||
}
|
||||
else {
|
||||
/* DisplayFileList(fileListInfo); For Debugging */
|
||||
|
||||
fileListMsg = CreateFileListMsg(fileListInfo, flags);
|
||||
FreeFileListInfo(fileListInfo);
|
||||
}
|
||||
|
||||
return fileListMsg;
|
||||
}
|
||||
|
||||
#if !defined(__GNUC__) && !defined(_MSC_VER)
|
||||
#define __FUNCTION__ "unknown"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/* Most of the Windows version here is based on https://github.com/danielgindi/FileDir */
|
||||
|
||||
#define FILETIME_TO_TIME_T(FILETIME) (((((__int64)FILETIME.dwLowDateTime) | (((__int64)FILETIME.dwHighDateTime) << 32)) - 116444736000000000L) / 10000000L)
|
||||
|
||||
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
||||
#define IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM))
|
||||
#else
|
||||
#define IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) 0
|
||||
#endif
|
||||
|
||||
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
||||
#define IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA))
|
||||
#else
|
||||
#define IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) 0
|
||||
#endif
|
||||
|
||||
#define IS_REGULAR_FILE(dwFileAttributes) \
|
||||
( \
|
||||
!!(dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || \
|
||||
( \
|
||||
!(dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && \
|
||||
!(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && \
|
||||
!(dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && \
|
||||
!IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) && \
|
||||
!IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) && \
|
||||
!(dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && \
|
||||
!(dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define IS_FOLDER(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
|
||||
int
|
||||
CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
|
||||
{
|
||||
int pathLen, basePathLength;
|
||||
char *basePath, *pChar;
|
||||
WIN32_FIND_DATAA winFindData;
|
||||
HANDLE findHandle;
|
||||
|
||||
if(path == NULL) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if(strlen(path) == 0) {
|
||||
/* In this case we will send the list of entries in ftp root*/
|
||||
sprintf(path, "%s%s", GetFtpRoot(), "/");
|
||||
}
|
||||
|
||||
/* Create a search string, like C:\folder\* */
|
||||
|
||||
pathLen = strlen(path);
|
||||
basePath = malloc(pathLen + 3);
|
||||
memcpy(basePath, path, pathLen);
|
||||
basePathLength = pathLen;
|
||||
basePath[basePathLength] = '\\';
|
||||
basePath[basePathLength + 1] = '*';
|
||||
basePath[basePathLength + 2] = '\0';
|
||||
|
||||
/* Start a search */
|
||||
memset(&winFindData, 0, sizeof(winFindData));
|
||||
findHandle = FindFirstFileA(path, &winFindData);
|
||||
|
||||
basePath[basePathLength] = '\0'; /* Restore to a basePath + \ */
|
||||
/* Convert \ to / */
|
||||
for(pChar = basePath; *pChar; pChar++) {
|
||||
if (*pChar == '\\') {
|
||||
*pChar = '/';
|
||||
}
|
||||
}
|
||||
|
||||
/* While we can find a next file do...
|
||||
But ignore \. and '.. entries, which are current folder and parent folder respectively */
|
||||
while(findHandle != INVALID_HANDLE_VALUE && winFindData.cFileName[0] == '.' &&
|
||||
(winFindData.cFileName[1] == '\0' ||
|
||||
(winFindData.cFileName[1] == '.' && winFindData.cFileName[2] == '\0'))) {
|
||||
char fullpath[PATH_MAX];
|
||||
fullpath[0] = 0;
|
||||
|
||||
strncpy_s(fullpath, PATH_MAX, basePath, basePathLength);
|
||||
strncpy_s(fullpath + basePathLength, PATH_MAX - basePathLength, winFindData.cFileName, (int)strlen(winFindData.cFileName));
|
||||
|
||||
if(IS_FOLDER(winFindData.dwFileAttributes)) {
|
||||
if (AddFileListItemInfo(pFileListInfo, winFindData.cFileName, -1, 0) == 0) {
|
||||
rfbLog("File [%s]: Method [%s]: Add directory %s in the"
|
||||
" list failed\n", __FILE__, __FUNCTION__, fullpath);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if(IS_REGULAR_FILE(winFindData.dwFileAttributes)) {
|
||||
if(flag) {
|
||||
unsigned int fileSize = (winFindData.nFileSizeHigh * (MAXDWORD+1)) + winFindData.nFileSizeLow;
|
||||
if(AddFileListItemInfo(pFileListInfo, winFindData.cFileName, fileSize, FILETIME_TO_TIME_T(winFindData.ftLastWriteTime)) == 0) {
|
||||
rfbLog("File [%s]: Method [%s]: Add file %s in the "
|
||||
"list failed\n", __FILE__, __FUNCTION__, fullpath);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(FindNextFileA(findHandle, &winFindData) == 0) {
|
||||
FindClose(findHandle);
|
||||
findHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(findHandle != INVALID_HANDLE_VALUE) {
|
||||
FindClose(findHandle);
|
||||
}
|
||||
|
||||
free(basePath);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#else /* WIN32 */
|
||||
|
||||
int
|
||||
CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
|
||||
{
|
||||
DIR* pDir = NULL;
|
||||
struct dirent* pDirent = NULL;
|
||||
|
||||
if(path == NULL) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if(strlen(path) == 0) {
|
||||
/* In this case we will send the list of entries in ftp root*/
|
||||
sprintf(path, "%s%s", GetFtpRoot(), "/");
|
||||
}
|
||||
|
||||
if((pDir = opendir(path)) == NULL) {
|
||||
rfbLog("File [%s]: Method [%s]: not able to open the dir\n",
|
||||
__FILE__, __FUNCTION__);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
while((pDirent = readdir(pDir))) {
|
||||
if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) {
|
||||
struct stat stat_buf;
|
||||
/*
|
||||
int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2);
|
||||
*/
|
||||
char fullpath[PATH_MAX];
|
||||
|
||||
memset(fullpath, 0, PATH_MAX);
|
||||
|
||||
strcpy(fullpath, path);
|
||||
if(path[strlen(path)-1] != '/')
|
||||
strcat(fullpath, "/");
|
||||
strcat(fullpath, pDirent->d_name);
|
||||
|
||||
if(stat(fullpath, &stat_buf) < 0) {
|
||||
rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
|
||||
__FILE__, __FUNCTION__, fullpath);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(S_ISDIR(stat_buf.st_mode)) {
|
||||
if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, -1, 0) == 0) {
|
||||
rfbLog("File [%s]: Method [%s]: Add directory %s in the"
|
||||
" list failed\n", __FILE__, __FUNCTION__, fullpath);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(flag) {
|
||||
if(AddFileListItemInfo(pFileListInfo, pDirent->d_name,
|
||||
stat_buf.st_size,
|
||||
stat_buf.st_mtime) == 0) {
|
||||
rfbLog("File [%s]: Method [%s]: Add file %s in the "
|
||||
"list failed\n", __FILE__, __FUNCTION__, fullpath);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(closedir(pDir) < 0) {
|
||||
rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n",
|
||||
__FILE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
CreateFileListErrMsg(char flags)
|
||||
{
|
||||
FileTransferMsg fileListMsg;
|
||||
rfbFileListDataMsg* pFLD = NULL;
|
||||
char* data = NULL;
|
||||
unsigned int length = 0;
|
||||
|
||||
memset(&fileListMsg, 0, sizeof(FileTransferMsg));
|
||||
|
||||
data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char));
|
||||
if(data == NULL) {
|
||||
return fileListMsg;
|
||||
}
|
||||
length = sizeof(rfbFileListDataMsg) * sizeof(char);
|
||||
pFLD = (rfbFileListDataMsg*) data;
|
||||
|
||||
pFLD->type = rfbFileListData;
|
||||
pFLD->numFiles = Swap16IfLE(0);
|
||||
pFLD->dataSize = Swap16IfLE(0);
|
||||
pFLD->compressedSize = Swap16IfLE(0);
|
||||
pFLD->flags = flags | 0x80;
|
||||
|
||||
fileListMsg.data = data;
|
||||
fileListMsg.length = length;
|
||||
|
||||
return fileListMsg;
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
CreateFileListMsg(FileListInfo fileListInfo, char flags)
|
||||
{
|
||||
FileTransferMsg fileListMsg;
|
||||
rfbFileListDataMsg* pFLD = NULL;
|
||||
char *data = NULL, *pFileNames = NULL;
|
||||
unsigned int length = 0, dsSize = 0, i = 0;
|
||||
FileListItemSizePtr pFileListItemSize = NULL;
|
||||
|
||||
memset(&fileListMsg, 0, sizeof(FileTransferMsg));
|
||||
dsSize = fileListInfo.numEntries * 8;
|
||||
length = sz_rfbFileListDataMsg + dsSize +
|
||||
GetSumOfFileNamesLength(fileListInfo) +
|
||||
fileListInfo.numEntries;
|
||||
|
||||
data = (char*) calloc(length, sizeof(char));
|
||||
if(data == NULL) {
|
||||
return fileListMsg;
|
||||
}
|
||||
pFLD = (rfbFileListDataMsg*) data;
|
||||
pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg];
|
||||
pFileNames = &data[sz_rfbFileListDataMsg + dsSize];
|
||||
|
||||
pFLD->type = rfbFileListData;
|
||||
pFLD->flags = flags & 0xF0;
|
||||
pFLD->numFiles = Swap16IfLE(fileListInfo.numEntries);
|
||||
pFLD->dataSize = Swap16IfLE(GetSumOfFileNamesLength(fileListInfo) +
|
||||
fileListInfo.numEntries);
|
||||
pFLD->compressedSize = pFLD->dataSize;
|
||||
|
||||
for(i =0; i <fileListInfo.numEntries; i++) {
|
||||
pFileListItemSize[i].size = Swap32IfLE(GetFileSizeAt(fileListInfo, i));
|
||||
pFileListItemSize[i].data = Swap32IfLE(GetFileDataAt(fileListInfo, i));
|
||||
strcpy(pFileNames, GetFileNameAt(fileListInfo, i));
|
||||
|
||||
if(i+1 < fileListInfo.numEntries)
|
||||
pFileNames += strlen(pFileNames) + 1;
|
||||
}
|
||||
|
||||
fileListMsg.data = data;
|
||||
fileListMsg.length = length;
|
||||
|
||||
return fileListMsg;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Methods to handle File Download Request.
|
||||
******************************************************************************/
|
||||
|
||||
FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
|
||||
FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime);
|
||||
FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
|
||||
|
||||
FileTransferMsg
|
||||
GetFileDownLoadErrMsg()
|
||||
{
|
||||
FileTransferMsg fileDownloadErrMsg;
|
||||
|
||||
char reason[] = "An internal error on the server caused download failure";
|
||||
int reasonLen = strlen(reason);
|
||||
|
||||
memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
|
||||
|
||||
fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen);
|
||||
|
||||
return fileDownloadErrMsg;
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
GetFileDownloadReadDataErrMsg()
|
||||
{
|
||||
char reason[] = "Cannot open file, perhaps it is absent or is a directory";
|
||||
int reasonLen = strlen(reason);
|
||||
|
||||
return CreateFileDownloadErrMsg(reason, reasonLen);
|
||||
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
GetFileDownloadLengthErrResponseMsg()
|
||||
{
|
||||
char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
|
||||
int reasonLen = strlen(reason);
|
||||
|
||||
return CreateFileDownloadErrMsg(reason, reasonLen);
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp)
|
||||
{
|
||||
/* const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE; */
|
||||
int numOfBytesRead = 0;
|
||||
char pBuf[SZ_RFBBLOCKSIZE];
|
||||
char* path = rtcp->rcft.rcfd.fName;
|
||||
|
||||
memset(pBuf, 0, SZ_RFBBLOCKSIZE);
|
||||
|
||||
if((rtcp->rcft.rcfd.downloadInProgress == FALSE) && (rtcp->rcft.rcfd.downloadFD == -1)) {
|
||||
if((rtcp->rcft.rcfd.downloadFD = open(path, O_RDONLY)) == -1) {
|
||||
rfbLog("File [%s]: Method [%s]: Error: Couldn't open file\n",
|
||||
__FILE__, __FUNCTION__);
|
||||
return GetFileDownloadReadDataErrMsg();
|
||||
}
|
||||
rtcp->rcft.rcfd.downloadInProgress = TRUE;
|
||||
}
|
||||
if((rtcp->rcft.rcfd.downloadInProgress == TRUE) && (rtcp->rcft.rcfd.downloadFD != -1)) {
|
||||
if( (numOfBytesRead = read(rtcp->rcft.rcfd.downloadFD, pBuf, SZ_RFBBLOCKSIZE)) <= 0) {
|
||||
close(rtcp->rcft.rcfd.downloadFD);
|
||||
rtcp->rcft.rcfd.downloadFD = -1;
|
||||
rtcp->rcft.rcfd.downloadInProgress = FALSE;
|
||||
if(numOfBytesRead == 0) {
|
||||
return CreateFileDownloadZeroSizeDataMsg(rtcp->rcft.rcfd.mTime);
|
||||
}
|
||||
return GetFileDownloadReadDataErrMsg();
|
||||
}
|
||||
return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf);
|
||||
}
|
||||
return GetFileDownLoadErrMsg();
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
|
||||
{
|
||||
FileTransferMsg fileDownloadMsg;
|
||||
struct stat stat_buf;
|
||||
int sz_rfbFileSize = 0;
|
||||
char* path = rtcp->rcft.rcfd.fName;
|
||||
|
||||
memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
|
||||
|
||||
if( (path == NULL) || (strlen(path) == 0) ||
|
||||
(stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) {
|
||||
|
||||
char reason[] = "Cannot open file, perhaps it is absent or is not a regular file";
|
||||
int reasonLen = strlen(reason);
|
||||
|
||||
rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n",
|
||||
__FILE__, __FUNCTION__, path);
|
||||
|
||||
fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen);
|
||||
}
|
||||
else {
|
||||
rtcp->rcft.rcfd.mTime = stat_buf.st_mtime;
|
||||
sz_rfbFileSize = stat_buf.st_size;
|
||||
if(sz_rfbFileSize <= 0) {
|
||||
fileDownloadMsg = CreateFileDownloadZeroSizeDataMsg(stat_buf.st_mtime);
|
||||
}
|
||||
|
||||
}
|
||||
return fileDownloadMsg;
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen)
|
||||
{
|
||||
FileTransferMsg fileDownloadErrMsg;
|
||||
int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1;
|
||||
rfbFileDownloadFailedMsg *pFDF = NULL;
|
||||
char *pFollow = NULL;
|
||||
|
||||
char *pData = (char*) calloc(length, sizeof(char));
|
||||
memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
|
||||
if(pData == NULL) {
|
||||
rfbLog("File [%s]: Method [%s]: pData is NULL\n",
|
||||
__FILE__, __FUNCTION__);
|
||||
return fileDownloadErrMsg;
|
||||
}
|
||||
|
||||
pFDF = (rfbFileDownloadFailedMsg *) pData;
|
||||
pFollow = &pData[sz_rfbFileDownloadFailedMsg];
|
||||
|
||||
pFDF->type = rfbFileDownloadFailed;
|
||||
pFDF->reasonLen = Swap16IfLE(reasonLen);
|
||||
memcpy(pFollow, reason, reasonLen);
|
||||
|
||||
fileDownloadErrMsg.data = pData;
|
||||
fileDownloadErrMsg.length = length;
|
||||
|
||||
return fileDownloadErrMsg;
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
CreateFileDownloadZeroSizeDataMsg(unsigned long mTime)
|
||||
{
|
||||
FileTransferMsg fileDownloadZeroSizeDataMsg;
|
||||
int length = sz_rfbFileDownloadDataMsg + sizeof(uint32_t);
|
||||
rfbFileDownloadDataMsg *pFDD = NULL;
|
||||
char *pFollow = NULL;
|
||||
|
||||
char *pData = (char*) calloc(length, sizeof(char));
|
||||
memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg));
|
||||
if(pData == NULL) {
|
||||
rfbLog("File [%s]: Method [%s]: pData is NULL\n",
|
||||
__FILE__, __FUNCTION__);
|
||||
return fileDownloadZeroSizeDataMsg;
|
||||
}
|
||||
|
||||
pFDD = (rfbFileDownloadDataMsg *) pData;
|
||||
pFollow = &pData[sz_rfbFileDownloadDataMsg];
|
||||
|
||||
pFDD->type = rfbFileDownloadData;
|
||||
pFDD->compressLevel = 0;
|
||||
pFDD->compressedSize = Swap16IfLE(0);
|
||||
pFDD->realSize = Swap16IfLE(0);
|
||||
|
||||
memcpy(pFollow, &mTime, sizeof(uint32_t));
|
||||
|
||||
fileDownloadZeroSizeDataMsg.data = pData;
|
||||
fileDownloadZeroSizeDataMsg.length = length;
|
||||
|
||||
return fileDownloadZeroSizeDataMsg;
|
||||
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile)
|
||||
{
|
||||
FileTransferMsg fileDownloadBlockSizeDataMsg;
|
||||
int length = sz_rfbFileDownloadDataMsg + sizeFile;
|
||||
rfbFileDownloadDataMsg *pFDD = NULL;
|
||||
char *pFollow = NULL;
|
||||
|
||||
char *pData = (char*) calloc(length, sizeof(char));
|
||||
memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg));
|
||||
if(NULL == pData) {
|
||||
rfbLog("File [%s]: Method [%s]: pData is NULL\n",
|
||||
__FILE__, __FUNCTION__);
|
||||
return fileDownloadBlockSizeDataMsg;
|
||||
}
|
||||
|
||||
pFDD = (rfbFileDownloadDataMsg *) pData;
|
||||
pFollow = &pData[sz_rfbFileDownloadDataMsg];
|
||||
|
||||
pFDD->type = rfbFileDownloadData;
|
||||
pFDD->compressLevel = 0;
|
||||
pFDD->compressedSize = Swap16IfLE(sizeFile);
|
||||
pFDD->realSize = Swap16IfLE(sizeFile);
|
||||
|
||||
memcpy(pFollow, pFile, sizeFile);
|
||||
|
||||
fileDownloadBlockSizeDataMsg.data = pData;
|
||||
fileDownloadBlockSizeDataMsg.length = length;
|
||||
|
||||
return fileDownloadBlockSizeDataMsg;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Methods to handle file upload request
|
||||
******************************************************************************/
|
||||
|
||||
FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
|
||||
|
||||
FileTransferMsg
|
||||
GetFileUploadLengthErrResponseMsg()
|
||||
{
|
||||
char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
|
||||
int reasonLen = strlen(reason);
|
||||
|
||||
return CreateFileUploadErrMsg(reason, reasonLen);
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
|
||||
{
|
||||
FileTransferMsg fileUploadErrMsg;
|
||||
|
||||
memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
|
||||
if((strlen(rtcp->rcft.rcfu.fName) == 0) ||
|
||||
((rtcp->rcft.rcfu.uploadFD = creat(rtcp->rcft.rcfu.fName,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)) {
|
||||
|
||||
char reason[] = "Could not create file";
|
||||
int reasonLen = strlen(reason);
|
||||
fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen);
|
||||
}
|
||||
else
|
||||
rtcp->rcft.rcfu.uploadInProgress = TRUE;
|
||||
|
||||
return fileUploadErrMsg;
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
GetFileUploadCompressedLevelErrMsg()
|
||||
{
|
||||
char reason[] = "Server does not support data compression on upload";
|
||||
int reasonLen = strlen(reason);
|
||||
|
||||
return CreateFileUploadErrMsg(reason, reasonLen);
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
|
||||
{
|
||||
FileTransferMsg ftm;
|
||||
unsigned long numOfBytesWritten = 0;
|
||||
|
||||
memset(&ftm, 0, sizeof(FileTransferMsg));
|
||||
|
||||
numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize);
|
||||
|
||||
if(numOfBytesWritten != rtcp->rcft.rcfu.fSize) {
|
||||
char reason[] = "Error writing file data";
|
||||
int reasonLen = strlen(reason);
|
||||
ftm = CreateFileUploadErrMsg(reason, reasonLen);
|
||||
CloseUndoneFileUpload(cl, rtcp);
|
||||
}
|
||||
return ftm;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp)
|
||||
{
|
||||
/* Here we are settimg the modification and access time of the file */
|
||||
/* Windows code stes mod/access/creation time of the file */
|
||||
struct utimbuf utb;
|
||||
|
||||
utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime;
|
||||
if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) {
|
||||
rfbLog("File [%s]: Method [%s]: Setting the modification/access"
|
||||
" time for the file <%s> failed\n", __FILE__,
|
||||
__FUNCTION__, rtcp->rcft.rcfu.fName);
|
||||
}
|
||||
|
||||
if(rtcp->rcft.rcfu.uploadFD != -1) {
|
||||
close(rtcp->rcft.rcfu.uploadFD);
|
||||
rtcp->rcft.rcfu.uploadFD = -1;
|
||||
rtcp->rcft.rcfu.uploadInProgress = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FileTransferMsg
|
||||
CreateFileUploadErrMsg(char* reason, unsigned int reasonLen)
|
||||
{
|
||||
FileTransferMsg fileUploadErrMsg;
|
||||
int length = sz_rfbFileUploadCancelMsg + reasonLen;
|
||||
rfbFileUploadCancelMsg *pFDF = NULL;
|
||||
char *pFollow = NULL;
|
||||
|
||||
char *pData = (char*) calloc(length, sizeof(char));
|
||||
memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
|
||||
if(pData == NULL) {
|
||||
rfbLog("File [%s]: Method [%s]: pData is NULL\n",
|
||||
__FILE__, __FUNCTION__);
|
||||
return fileUploadErrMsg;
|
||||
}
|
||||
|
||||
pFDF = (rfbFileUploadCancelMsg *) pData;
|
||||
pFollow = &pData[sz_rfbFileUploadCancelMsg];
|
||||
|
||||
pFDF->type = rfbFileUploadCancel;
|
||||
pFDF->reasonLen = Swap16IfLE(reasonLen);
|
||||
memcpy(pFollow, reason, reasonLen);
|
||||
|
||||
fileUploadErrMsg.data = pData;
|
||||
fileUploadErrMsg.length = length;
|
||||
|
||||
return fileUploadErrMsg;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Method to cancel File Transfer operation.
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
CloseUndoneFileUpload(rfbClientPtr cl, rfbTightClientPtr rtcp)
|
||||
{
|
||||
/* TODO :: File Upload case is not handled currently */
|
||||
/* TODO :: In case of concurrency we need to use Critical Section */
|
||||
|
||||
if(cl == NULL)
|
||||
return;
|
||||
|
||||
|
||||
if(rtcp->rcft.rcfu.uploadInProgress == TRUE) {
|
||||
rtcp->rcft.rcfu.uploadInProgress = FALSE;
|
||||
|
||||
if(rtcp->rcft.rcfu.uploadFD != -1) {
|
||||
close(rtcp->rcft.rcfu.uploadFD);
|
||||
rtcp->rcft.rcfu.uploadFD = -1;
|
||||
}
|
||||
|
||||
if(unlink(rtcp->rcft.rcfu.fName) == -1) {
|
||||
rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n",
|
||||
__FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName);
|
||||
}
|
||||
|
||||
memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CloseUndoneFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp)
|
||||
{
|
||||
if(cl == NULL)
|
||||
return;
|
||||
|
||||
if(rtcp->rcft.rcfd.downloadInProgress == TRUE) {
|
||||
rtcp->rcft.rcfd.downloadInProgress = FALSE;
|
||||
/* the thread will return if downloadInProgress is FALSE */
|
||||
pthread_join(rtcp->rcft.rcfd.downloadThread, NULL);
|
||||
|
||||
if(rtcp->rcft.rcfd.downloadFD != -1) {
|
||||
close(rtcp->rcft.rcfd.downloadFD);
|
||||
rtcp->rcft.rcfd.downloadFD = -1;
|
||||
}
|
||||
memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Method to handle create directory request.
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#undef CreateDirectory /* Prevent macro clashes under Windows */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
void
|
||||
CreateDirectory(char* dirName)
|
||||
{
|
||||
if(dirName == NULL) return;
|
||||
|
||||
if(mkdir(dirName, 0700) == -1) {
|
||||
rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n",
|
||||
__FILE__, __FUNCTION__, dirName);
|
||||
}
|
||||
}
|
||||
64
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/filetransfermsg.h
vendored
Normal file
64
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/filetransfermsg.h
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Novell, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail,
|
||||
* you may find current contact information at www.novell.com
|
||||
*
|
||||
* Author : Rohit Kumar
|
||||
* Email ID : rokumar@novell.com
|
||||
* Date : 14th July 2005
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FILE_TRANSFER_MSG_H
|
||||
#define FILE_TRANSFER_MSG_H
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma push_macro("CreateDirectory")
|
||||
#undef CreateDirectory /* Prevent macro clashes under Windows */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
typedef struct _FileTransferMsg {
|
||||
char* data;
|
||||
unsigned int length;
|
||||
} FileTransferMsg;
|
||||
|
||||
FileTransferMsg GetFileListResponseMsg(char* path, char flag);
|
||||
|
||||
FileTransferMsg GetFileDownloadResponseMsg(char* path);
|
||||
FileTransferMsg GetFileDownloadLengthErrResponseMsg();
|
||||
FileTransferMsg GetFileDownLoadErrMsg();
|
||||
FileTransferMsg GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr data);
|
||||
FileTransferMsg ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr data);
|
||||
|
||||
FileTransferMsg GetFileUploadLengthErrResponseMsg();
|
||||
FileTransferMsg GetFileUploadCompressedLevelErrMsg();
|
||||
FileTransferMsg ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr data);
|
||||
FileTransferMsg ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr data, char* pBuf);
|
||||
|
||||
void CreateDirectory(char* dirName);
|
||||
void FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr data);
|
||||
void CloseUndoneFileUpload(rfbClientPtr cl, rfbTightClientPtr data);
|
||||
void CloseUndoneFileDownload(rfbClientPtr cl, rfbTightClientPtr data);
|
||||
|
||||
void FreeFileTransferMsg(FileTransferMsg ftm);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma pop_macro("CreateDirectory") /* Restore original macro */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#endif
|
||||
|
||||
1051
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c
vendored
Normal file
1051
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
47
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.h
vendored
Normal file
47
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Novell, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail,
|
||||
* you may find current contact information at www.novell.com
|
||||
*
|
||||
* Author : Rohit Kumar
|
||||
* Email ID : rokumar@novell.com
|
||||
* Date : 14th July 2005
|
||||
*/
|
||||
|
||||
#ifndef HANDLE_FILE_TRANSFER_REQUEST_H
|
||||
#define HANDLE_FILE_TRANSFER_REQUEST_H
|
||||
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
|
||||
void InitFileTransfer();
|
||||
int SetFtpRoot(char* path);
|
||||
void EnableFileTransfer(rfbBool enable);
|
||||
rfbBool IsFileTransferEnabled();
|
||||
char* GetFtpRoot();
|
||||
|
||||
void HandleFileListRequest(rfbClientPtr cl, rfbTightClientRec* data);
|
||||
void HandleFileDownloadRequest(rfbClientPtr cl, rfbTightClientRec* data);
|
||||
void HandleFileDownloadCancelRequest(rfbClientPtr cl, rfbTightClientRec* data);
|
||||
void HandleFileUploadRequest(rfbClientPtr cl, rfbTightClientRec* data);
|
||||
void HandleFileUploadDataRequest(rfbClientPtr cl, rfbTightClientRec* data);
|
||||
void HandleFileUploadFailedRequest(rfbClientPtr cl, rfbTightClientRec* data);
|
||||
void HandleFileCreateDirRequest(rfbClientPtr cl, rfbTightClientRec* data);
|
||||
|
||||
#endif
|
||||
|
||||
457
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/rfbtightproto.h
vendored
Normal file
457
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/rfbtightproto.h
vendored
Normal file
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Novell, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail,
|
||||
* you may find current contact information at www.novell.com
|
||||
*
|
||||
* Author : Rohit Kumar
|
||||
* Email ID : rokumar@novell.com
|
||||
* Date : 25th August 2005
|
||||
*/
|
||||
|
||||
#ifndef RFBTIGHTPROTO_H
|
||||
#define RFBTIGHTPROTO_H
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* PATH_MAX is not defined in limits.h on some platforms */
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
|
||||
#define rfbSecTypeTight 16
|
||||
|
||||
void rfbTightUsage(void);
|
||||
int rfbTightProcessArgs(int argc, char *argv[]);
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Negotiation of Tunneling Capabilities (protocol version 3.7t)
|
||||
*
|
||||
* If the chosen security type is rfbSecTypeTight, the server sends a list of
|
||||
* supported tunneling methods ("tunneling" refers to any additional layer of
|
||||
* data transformation, such as encryption or external compression.)
|
||||
*
|
||||
* nTunnelTypes specifies the number of following rfbCapabilityInfo structures
|
||||
* that list all supported tunneling methods in the order of preference.
|
||||
*
|
||||
* NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be
|
||||
* used, and the client should not send a response requesting a tunneling
|
||||
* method.
|
||||
*/
|
||||
|
||||
typedef struct _rfbTunnelingCapsMsg {
|
||||
uint32_t nTunnelTypes;
|
||||
/* followed by nTunnelTypes * rfbCapabilityInfo structures */
|
||||
} rfbTunnelingCapsMsg;
|
||||
|
||||
#define sz_rfbTunnelingCapsMsg 4
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Tunneling Method Request (protocol version 3.7t)
|
||||
*
|
||||
* If the list of tunneling capabilities sent by the server was not empty, the
|
||||
* client should reply with a 32-bit code specifying a particular tunneling
|
||||
* method. The following code should be used for no tunneling.
|
||||
*/
|
||||
|
||||
#define rfbNoTunneling 0
|
||||
#define sig_rfbNoTunneling "NOTUNNEL"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Negotiation of Authentication Capabilities (protocol version 3.7t)
|
||||
*
|
||||
* After setting up tunneling, the server sends a list of supported
|
||||
* authentication schemes.
|
||||
*
|
||||
* nAuthTypes specifies the number of following rfbCapabilityInfo structures
|
||||
* that list all supported authentication schemes in the order of preference.
|
||||
*
|
||||
* NOTE: If nAuthTypes is 0, that tells the client that no authentication is
|
||||
* necessary, and the client should not send a response requesting an
|
||||
* authentication scheme.
|
||||
*/
|
||||
|
||||
typedef struct _rfbAuthenticationCapsMsg {
|
||||
uint32_t nAuthTypes;
|
||||
/* followed by nAuthTypes * rfbCapabilityInfo structures */
|
||||
} rfbAuthenticationCapsMsg;
|
||||
|
||||
#define sz_rfbAuthenticationCapsMsg 4
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Authentication Scheme Request (protocol version 3.7t)
|
||||
*
|
||||
* If the list of authentication capabilities sent by the server was not empty,
|
||||
* the client should reply with a 32-bit code specifying a particular
|
||||
* authentication scheme. The following codes are supported.
|
||||
*/
|
||||
|
||||
#define rfbAuthNone 1
|
||||
#define rfbAuthVNC 2
|
||||
#define rfbAuthUnixLogin 129
|
||||
#define rfbAuthExternal 130
|
||||
|
||||
#define sig_rfbAuthNone "NOAUTH__"
|
||||
#define sig_rfbAuthVNC "VNCAUTH_"
|
||||
#define sig_rfbAuthUnixLogin "ULGNAUTH"
|
||||
#define sig_rfbAuthExternal "XTRNAUTH"
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Structure used to describe protocol options such as tunneling methods,
|
||||
* authentication schemes and message types (protocol version 3.7t).
|
||||
*/
|
||||
|
||||
typedef struct _rfbCapabilityInfo {
|
||||
|
||||
uint32_t code; /* numeric identifier */
|
||||
uint8_t vendorSignature[4]; /* vendor identification */
|
||||
uint8_t nameSignature[8]; /* abbreviated option name */
|
||||
|
||||
} rfbCapabilityInfo;
|
||||
|
||||
#define sz_rfbCapabilityInfoVendor 4
|
||||
#define sz_rfbCapabilityInfoName 8
|
||||
#define sz_rfbCapabilityInfo 16
|
||||
|
||||
/*
|
||||
* Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
|
||||
*/
|
||||
|
||||
#define rfbStandardVendor "STDV"
|
||||
#define rfbTridiaVncVendor "TRDV"
|
||||
#define rfbTightVncVendor "TGHT"
|
||||
|
||||
|
||||
/* It's a good idea to keep these values a bit greater than required. */
|
||||
#define MAX_TIGHT_ENCODINGS 10
|
||||
#define MAX_TUNNELING_CAPS 16
|
||||
#define MAX_AUTH_CAPS 16
|
||||
|
||||
typedef struct _rfbClientFileDownload {
|
||||
char fName[PATH_MAX];
|
||||
int downloadInProgress;
|
||||
unsigned long mTime;
|
||||
int downloadFD;
|
||||
pthread_t downloadThread;
|
||||
} rfbClientFileDownload ;
|
||||
|
||||
typedef struct _rfbClientFileUpload {
|
||||
char fName[PATH_MAX];
|
||||
int uploadInProgress;
|
||||
unsigned long mTime;
|
||||
unsigned long fSize;
|
||||
int uploadFD;
|
||||
} rfbClientFileUpload ;
|
||||
|
||||
typedef struct _rfbClientFileTransfer {
|
||||
rfbClientFileDownload rcfd;
|
||||
rfbClientFileUpload rcfu;
|
||||
} rfbClientFileTransfer;
|
||||
|
||||
|
||||
typedef struct _rfbTightClientRec {
|
||||
|
||||
/* Lists of capability codes sent to clients. We remember these
|
||||
lists to restrict clients from choosing those tunneling and
|
||||
authentication types that were not advertised. */
|
||||
|
||||
int nAuthCaps;
|
||||
uint32_t authCaps[MAX_AUTH_CAPS];
|
||||
|
||||
/* This is not useful while we don't support tunneling:
|
||||
int nTunnelingCaps;
|
||||
uint32_t tunnelingCaps[MAX_TUNNELING_CAPS]; */
|
||||
|
||||
rfbClientFileTransfer rcft;
|
||||
|
||||
} rfbTightClientRec, *rfbTightClientPtr;
|
||||
|
||||
/*
|
||||
* Macro to fill in an rfbCapabilityInfo structure (protocol 3.7t).
|
||||
* Normally, using macros is no good, but this macro saves us from
|
||||
* writing constants twice -- it constructs signature names from codes.
|
||||
* Note that "code_sym" argument should be a single symbol, not an expression.
|
||||
*/
|
||||
|
||||
#define SetCapInfo(cap_ptr, code_sym, vendor) \
|
||||
{ \
|
||||
rfbCapabilityInfo *pcap; \
|
||||
pcap = (cap_ptr); \
|
||||
pcap->code = Swap32IfLE(code_sym); \
|
||||
memcpy(pcap->vendorSignature, (vendor), \
|
||||
sz_rfbCapabilityInfoVendor); \
|
||||
memcpy(pcap->nameSignature, sig_##code_sym, \
|
||||
sz_rfbCapabilityInfoName); \
|
||||
}
|
||||
|
||||
void rfbHandleSecTypeTight(rfbClientPtr cl);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Server Interaction Capabilities Message (protocol version 3.7t)
|
||||
*
|
||||
* In the protocol version 3.7t, the server informs the client what message
|
||||
* types it supports in addition to ones defined in the protocol version 3.7.
|
||||
* Also, the server sends the list of all supported encodings (note that it's
|
||||
* not necessary to advertise the "raw" encoding since it MUST be supported in
|
||||
* RFB 3.x protocols).
|
||||
*
|
||||
* This data immediately follows the server initialisation message.
|
||||
*/
|
||||
|
||||
typedef struct _rfbInteractionCapsMsg {
|
||||
uint16_t nServerMessageTypes;
|
||||
uint16_t nClientMessageTypes;
|
||||
uint16_t nEncodingTypes;
|
||||
uint16_t pad; /* reserved, must be 0 */
|
||||
/* followed by nServerMessageTypes * rfbCapabilityInfo structures */
|
||||
/* followed by nClientMessageTypes * rfbCapabilityInfo structures */
|
||||
} rfbInteractionCapsMsg;
|
||||
|
||||
#define sz_rfbInteractionCapsMsg 8
|
||||
|
||||
#define rfbFileListData 130
|
||||
#define rfbFileDownloadData 131
|
||||
#define rfbFileUploadCancel 132
|
||||
#define rfbFileDownloadFailed 133
|
||||
|
||||
/* signatures for non-standard messages */
|
||||
#define sig_rfbFileListData "FTS_LSDT"
|
||||
#define sig_rfbFileDownloadData "FTS_DNDT"
|
||||
#define sig_rfbFileUploadCancel "FTS_UPCN"
|
||||
#define sig_rfbFileDownloadFailed "FTS_DNFL"
|
||||
|
||||
|
||||
|
||||
#define rfbFileListRequest 130
|
||||
#define rfbFileDownloadRequest 131
|
||||
#define rfbFileUploadRequest 132
|
||||
#define rfbFileUploadData 133
|
||||
#define rfbFileDownloadCancel 134
|
||||
#define rfbFileUploadFailed 135
|
||||
#define rfbFileCreateDirRequest 136
|
||||
|
||||
/* signatures for non-standard messages */
|
||||
#define sig_rfbFileListRequest "FTC_LSRQ"
|
||||
#define sig_rfbFileDownloadRequest "FTC_DNRQ"
|
||||
#define sig_rfbFileUploadRequest "FTC_UPRQ"
|
||||
#define sig_rfbFileUploadData "FTC_UPDT"
|
||||
#define sig_rfbFileDownloadCancel "FTC_DNCN"
|
||||
#define sig_rfbFileUploadFailed "FTC_UPFL"
|
||||
#define sig_rfbFileCreateDirRequest "FTC_FCDR"
|
||||
|
||||
|
||||
/* signatures for basic encoding types */
|
||||
#define sig_rfbEncodingRaw "RAW_____"
|
||||
#define sig_rfbEncodingCopyRect "COPYRECT"
|
||||
#define sig_rfbEncodingRRE "RRE_____"
|
||||
#define sig_rfbEncodingCoRRE "CORRE___"
|
||||
#define sig_rfbEncodingHextile "HEXTILE_"
|
||||
#define sig_rfbEncodingZlib "ZLIB____"
|
||||
#define sig_rfbEncodingTight "TIGHT___"
|
||||
#define sig_rfbEncodingZlibHex "ZLIBHEX_"
|
||||
|
||||
|
||||
/* signatures for "fake" encoding types */
|
||||
#define sig_rfbEncodingCompressLevel0 "COMPRLVL"
|
||||
#define sig_rfbEncodingXCursor "X11CURSR"
|
||||
#define sig_rfbEncodingRichCursor "RCHCURSR"
|
||||
#define sig_rfbEncodingPointerPos "POINTPOS"
|
||||
#define sig_rfbEncodingLastRect "LASTRECT"
|
||||
#define sig_rfbEncodingNewFBSize "NEWFBSIZ"
|
||||
#define sig_rfbEncodingQualityLevel0 "JPEGQLVL"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileListRequest
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileListRequestMsg {
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint16_t dirNameSize;
|
||||
/* Followed by char Dirname[dirNameSize] */
|
||||
} rfbFileListRequestMsg;
|
||||
|
||||
#define sz_rfbFileListRequestMsg 4
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileDownloadRequest
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileDownloadRequestMsg {
|
||||
uint8_t type;
|
||||
uint8_t compressedLevel;
|
||||
uint16_t fNameSize;
|
||||
uint32_t position;
|
||||
/* Followed by char Filename[fNameSize] */
|
||||
} rfbFileDownloadRequestMsg;
|
||||
|
||||
#define sz_rfbFileDownloadRequestMsg 8
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileUploadRequest
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileUploadRequestMsg {
|
||||
uint8_t type;
|
||||
uint8_t compressedLevel;
|
||||
uint16_t fNameSize;
|
||||
uint32_t position;
|
||||
/* Followed by char Filename[fNameSize] */
|
||||
} rfbFileUploadRequestMsg;
|
||||
|
||||
#define sz_rfbFileUploadRequestMsg 8
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileUploadData
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileUploadDataMsg {
|
||||
uint8_t type;
|
||||
uint8_t compressedLevel;
|
||||
uint16_t realSize;
|
||||
uint16_t compressedSize;
|
||||
/* Followed by File[compressedSize],
|
||||
but if (realSize = compressedSize = 0) followed by uint32_t modTime */
|
||||
} rfbFileUploadDataMsg;
|
||||
|
||||
#define sz_rfbFileUploadDataMsg 6
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileDownloadCancel
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileDownloadCancelMsg {
|
||||
uint8_t type;
|
||||
uint8_t unused;
|
||||
uint16_t reasonLen;
|
||||
/* Followed by reason[reasonLen] */
|
||||
} rfbFileDownloadCancelMsg;
|
||||
|
||||
#define sz_rfbFileDownloadCancelMsg 4
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileUploadFailed
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileUploadFailedMsg {
|
||||
uint8_t type;
|
||||
uint8_t unused;
|
||||
uint16_t reasonLen;
|
||||
/* Followed by reason[reasonLen] */
|
||||
} rfbFileUploadFailedMsg;
|
||||
|
||||
#define sz_rfbFileUploadFailedMsg 4
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileCreateDirRequest
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileCreateDirRequestMsg {
|
||||
uint8_t type;
|
||||
uint8_t unused;
|
||||
uint16_t dNameLen;
|
||||
/* Followed by dName[dNameLen] */
|
||||
} rfbFileCreateDirRequestMsg;
|
||||
|
||||
#define sz_rfbFileCreateDirRequestMsg 4
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Union of all client->server messages.
|
||||
*/
|
||||
|
||||
typedef union _rfbClientToServerTightMsg {
|
||||
rfbFileListRequestMsg flr;
|
||||
rfbFileDownloadRequestMsg fdr;
|
||||
rfbFileUploadRequestMsg fupr;
|
||||
rfbFileUploadDataMsg fud;
|
||||
rfbFileDownloadCancelMsg fdc;
|
||||
rfbFileUploadFailedMsg fuf;
|
||||
rfbFileCreateDirRequestMsg fcdr;
|
||||
} rfbClientToServerTightMsg;
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileListData
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileListDataMsg {
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint16_t numFiles;
|
||||
uint16_t dataSize;
|
||||
uint16_t compressedSize;
|
||||
/* Followed by SizeData[numFiles] */
|
||||
/* Followed by Filenames[compressedSize] */
|
||||
} rfbFileListDataMsg;
|
||||
|
||||
#define sz_rfbFileListDataMsg 8
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileDownloadData
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileDownloadDataMsg {
|
||||
uint8_t type;
|
||||
uint8_t compressLevel;
|
||||
uint16_t realSize;
|
||||
uint16_t compressedSize;
|
||||
/* Followed by File[copressedSize],
|
||||
but if (realSize = compressedSize = 0) followed by uint32_t modTime */
|
||||
} rfbFileDownloadDataMsg;
|
||||
|
||||
#define sz_rfbFileDownloadDataMsg 6
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileUploadCancel
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileUploadCancelMsg {
|
||||
uint8_t type;
|
||||
uint8_t unused;
|
||||
uint16_t reasonLen;
|
||||
/* Followed by reason[reasonLen] */
|
||||
} rfbFileUploadCancelMsg;
|
||||
|
||||
#define sz_rfbFileUploadCancelMsg 4
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FileDownloadFailed
|
||||
*/
|
||||
|
||||
typedef struct _rfbFileDownloadFailedMsg {
|
||||
uint8_t type;
|
||||
uint8_t unused;
|
||||
uint16_t reasonLen;
|
||||
/* Followed by reason[reasonLen] */
|
||||
} rfbFileDownloadFailedMsg;
|
||||
|
||||
#define sz_rfbFileDownloadFailedMsg 4
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
554
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/rfbtightserver.c
vendored
Normal file
554
android/extern/libvncserver/src/libvncserver/tightvnc-filetransfer/rfbtightserver.c
vendored
Normal file
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Novell, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail,
|
||||
* you may find current contact information at www.novell.com
|
||||
*
|
||||
* Author : Rohit Kumar
|
||||
* Email ID : rokumar@novell.com
|
||||
* Date : 25th August 2005
|
||||
*/
|
||||
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#include "rfbtightproto.h"
|
||||
#include "handlefiletransferrequest.h"
|
||||
#include "filetransfermsg.h"
|
||||
|
||||
/*
|
||||
* Get my data!
|
||||
*
|
||||
* This gets the extension specific data from the client structure. If
|
||||
* the data is not found, the client connection is closed, a complaint
|
||||
* is logged, and NULL is returned.
|
||||
*/
|
||||
|
||||
extern rfbProtocolExtension tightVncFileTransferExtension;
|
||||
|
||||
rfbTightClientPtr
|
||||
rfbGetTightClientData(rfbClientPtr cl)
|
||||
{
|
||||
rfbTightClientPtr rtcp = (rfbTightClientPtr)
|
||||
rfbGetExtensionClientData(cl,
|
||||
&tightVncFileTransferExtension);
|
||||
if(rtcp == NULL) {
|
||||
rfbLog("Extension client data is null, closing the connection !\n");
|
||||
rfbCloseClient(cl);
|
||||
}
|
||||
|
||||
return rtcp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the authentication challenge.
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbVncAuthSendChallenge(rfbClientPtr cl)
|
||||
{
|
||||
|
||||
rfbLog("tightvnc-filetransfer/rfbVncAuthSendChallenge\n");
|
||||
/* 4 byte header is alreay sent. Which is rfbSecTypeVncAuth (same as rfbVncAuth). Just send the challenge. */
|
||||
rfbRandomBytes(cl->authChallenge);
|
||||
if (rfbWriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
|
||||
rfbLogPerror("rfbAuthNewClient: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dispatch client input to rfbVncAuthProcessResponse. */
|
||||
/* This methos is defined in auth.c file */
|
||||
rfbAuthProcessClientMessage(cl);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* LibVNCServer has a bug WRT Tight SecurityType and RFB 3.8
|
||||
* It should send auth result even for rfbAuthNone.
|
||||
* See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=517422
|
||||
* For testing set USE_SECTYPE_TIGHT_FOR_RFB_3_8 when compiling
|
||||
* or set it here.
|
||||
*/
|
||||
#define SECTYPE_TIGHT_FOR_RFB_3_8 \
|
||||
if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7) { \
|
||||
uint32_t authResult; \
|
||||
rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n"); \
|
||||
authResult = Swap32IfLE(rfbVncAuthOK); \
|
||||
if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { \
|
||||
rfbLogPerror("rfbAuthProcessClientMessage: write"); \
|
||||
rfbCloseClient(cl); \
|
||||
return; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
Enabled by runge on 2010/01/02
|
||||
*/
|
||||
#define USE_SECTYPE_TIGHT_FOR_RFB_3_8
|
||||
|
||||
/*
|
||||
* Read client's preferred authentication type (protocol 3.7t).
|
||||
*/
|
||||
|
||||
void
|
||||
rfbProcessClientAuthType(rfbClientPtr cl)
|
||||
{
|
||||
uint32_t auth_type;
|
||||
int n, i;
|
||||
rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
|
||||
|
||||
rfbLog("tightvnc-filetransfer/rfbProcessClientAuthType\n");
|
||||
|
||||
if(rtcp == NULL)
|
||||
return;
|
||||
|
||||
/* Read authentication type selected by the client. */
|
||||
n = rfbReadExact(cl, (char *)&auth_type, sizeof(auth_type));
|
||||
if (n <= 0) {
|
||||
if (n == 0)
|
||||
rfbLog("rfbProcessClientAuthType: client gone\n");
|
||||
else
|
||||
rfbLogPerror("rfbProcessClientAuthType: read");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
auth_type = Swap32IfLE(auth_type);
|
||||
|
||||
/* Make sure it was present in the list sent by the server. */
|
||||
for (i = 0; i < rtcp->nAuthCaps; i++) {
|
||||
if (auth_type == rtcp->authCaps[i])
|
||||
break;
|
||||
}
|
||||
if (i >= rtcp->nAuthCaps) {
|
||||
rfbLog("rfbProcessClientAuthType: "
|
||||
"wrong authentication type requested\n");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (auth_type) {
|
||||
case rfbAuthNone:
|
||||
/* Dispatch client input to rfbProcessClientInitMessage. */
|
||||
#ifdef USE_SECTYPE_TIGHT_FOR_RFB_3_8
|
||||
SECTYPE_TIGHT_FOR_RFB_3_8
|
||||
#endif
|
||||
cl->state = RFB_INITIALISATION;
|
||||
break;
|
||||
case rfbAuthVNC:
|
||||
rfbVncAuthSendChallenge(cl);
|
||||
break;
|
||||
default:
|
||||
rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n");
|
||||
rfbCloseClient(cl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read tunneling type requested by the client (protocol 3.7t).
|
||||
* NOTE: Currently, we don't support tunneling, and this function
|
||||
* can never be called.
|
||||
*/
|
||||
|
||||
void
|
||||
rfbProcessClientTunnelingType(rfbClientPtr cl)
|
||||
{
|
||||
/* If we were called, then something's really wrong. */
|
||||
rfbLog("rfbProcessClientTunnelingType: not implemented\n");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send the list of our authentication capabilities to the client
|
||||
* (protocol 3.7t).
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbSendAuthCaps(rfbClientPtr cl)
|
||||
{
|
||||
rfbAuthenticationCapsMsg caps;
|
||||
rfbCapabilityInfo caplist[MAX_AUTH_CAPS];
|
||||
int count = 0;
|
||||
rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
|
||||
|
||||
rfbLog("tightvnc-filetransfer/rfbSendAuthCaps\n");
|
||||
|
||||
if(rtcp == NULL)
|
||||
return;
|
||||
|
||||
if (cl->screen->authPasswdData && !cl->reverseConnection) {
|
||||
/* chk if this condition is valid or not. */
|
||||
SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor);
|
||||
rtcp->authCaps[count++] = rfbAuthVNC;
|
||||
}
|
||||
|
||||
rtcp->nAuthCaps = count;
|
||||
caps.nAuthTypes = Swap32IfLE((uint32_t)count);
|
||||
if (rfbWriteExact(cl, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) {
|
||||
rfbLogPerror("rfbSendAuthCaps: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count) {
|
||||
if (rfbWriteExact(cl, (char *)&caplist[0],
|
||||
count * sz_rfbCapabilityInfo) < 0) {
|
||||
rfbLogPerror("rfbSendAuthCaps: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
/* Dispatch client input to rfbProcessClientAuthType. */
|
||||
/* Call the function for authentication from here */
|
||||
rfbProcessClientAuthType(cl);
|
||||
} else {
|
||||
#ifdef USE_SECTYPE_TIGHT_FOR_RFB_3_8
|
||||
SECTYPE_TIGHT_FOR_RFB_3_8
|
||||
#endif
|
||||
/* Dispatch client input to rfbProcessClientInitMessage. */
|
||||
cl->state = RFB_INITIALISATION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send the list of our tunneling capabilities (protocol 3.7t).
|
||||
*/
|
||||
|
||||
static void
|
||||
rfbSendTunnelingCaps(rfbClientPtr cl)
|
||||
{
|
||||
rfbTunnelingCapsMsg caps;
|
||||
uint32_t nTypes = 0; /* we don't support tunneling yet */
|
||||
|
||||
rfbLog("tightvnc-filetransfer/rfbSendTunnelingCaps\n");
|
||||
|
||||
caps.nTunnelTypes = Swap32IfLE(nTypes);
|
||||
if (rfbWriteExact(cl, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) {
|
||||
rfbLogPerror("rfbSendTunnelingCaps: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nTypes) {
|
||||
/* Dispatch client input to rfbProcessClientTunnelingType(). */
|
||||
/* The flow should not reach here as tunneling is not implemented. */
|
||||
rfbProcessClientTunnelingType(cl);
|
||||
} else {
|
||||
rfbSendAuthCaps(cl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* rfbSendInteractionCaps is called after sending the server
|
||||
* initialisation message, only if TightVNC protocol extensions were
|
||||
* enabled (protocol 3.7t). In this function, we send the lists of
|
||||
* supported protocol messages and encodings.
|
||||
*/
|
||||
|
||||
/* Update these constants on changing capability lists below! */
|
||||
/* Values updated for FTP */
|
||||
#define N_SMSG_CAPS 4
|
||||
#define N_CMSG_CAPS 6
|
||||
#define N_ENC_CAPS 12
|
||||
|
||||
void
|
||||
rfbSendInteractionCaps(rfbClientPtr cl)
|
||||
{
|
||||
rfbInteractionCapsMsg intr_caps;
|
||||
rfbCapabilityInfo smsg_list[N_SMSG_CAPS];
|
||||
rfbCapabilityInfo cmsg_list[N_CMSG_CAPS];
|
||||
rfbCapabilityInfo enc_list[N_ENC_CAPS];
|
||||
int i, n_enc_caps = N_ENC_CAPS;
|
||||
|
||||
/* Fill in the header structure sent prior to capability lists. */
|
||||
intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS);
|
||||
intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS);
|
||||
intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS);
|
||||
intr_caps.pad = 0;
|
||||
|
||||
rfbLog("tightvnc-filetransfer/rfbSendInteractionCaps\n");
|
||||
|
||||
/* Supported server->client message types. */
|
||||
/* For file transfer support: */
|
||||
i = 0;
|
||||
if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) {
|
||||
SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor);
|
||||
SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor);
|
||||
SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor);
|
||||
SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor);
|
||||
if (i != N_SMSG_CAPS) {
|
||||
rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Supported client->server message types. */
|
||||
/* For file transfer support: */
|
||||
i = 0;
|
||||
if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) {
|
||||
SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor);
|
||||
SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest, rfbTightVncVendor);
|
||||
SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor);
|
||||
SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor);
|
||||
SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor);
|
||||
SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor);
|
||||
if (i != N_CMSG_CAPS) {
|
||||
rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encoding types. */
|
||||
i = 0;
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingCopyRect, rfbStandardVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingCoRRE, rfbStandardVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingHextile, rfbStandardVendor);
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor);
|
||||
#else
|
||||
n_enc_caps -= 2;
|
||||
#endif
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingCompressLevel0, rfbTightVncVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingQualityLevel0, rfbTightVncVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingXCursor, rfbTightVncVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingRichCursor, rfbTightVncVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingPointerPos, rfbTightVncVendor);
|
||||
SetCapInfo(&enc_list[i++], rfbEncodingLastRect, rfbTightVncVendor);
|
||||
if (i != n_enc_caps) {
|
||||
rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send header and capability lists */
|
||||
if (rfbWriteExact(cl, (char *)&intr_caps,
|
||||
sz_rfbInteractionCapsMsg) < 0 ||
|
||||
rfbWriteExact(cl, (char *)&smsg_list[0],
|
||||
sz_rfbCapabilityInfo * N_SMSG_CAPS) < 0 ||
|
||||
rfbWriteExact(cl, (char *)&cmsg_list[0],
|
||||
sz_rfbCapabilityInfo * N_CMSG_CAPS) < 0 ||
|
||||
rfbWriteExact(cl, (char *)&enc_list[0],
|
||||
sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) {
|
||||
rfbLogPerror("rfbSendInteractionCaps: write");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dispatch client input to rfbProcessClientNormalMessage(). */
|
||||
cl->state = RFB_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rfbBool
|
||||
rfbTightExtensionInit(rfbClientPtr cl, void* data)
|
||||
{
|
||||
|
||||
rfbSendInteractionCaps(cl);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
handleMessage(rfbClientPtr cl,
|
||||
const char* messageName,
|
||||
void (*handler)(rfbClientPtr cl, rfbTightClientPtr data))
|
||||
{
|
||||
rfbTightClientPtr data;
|
||||
|
||||
rfbLog("tightvnc-filetransfer: %s message received\n", messageName);
|
||||
|
||||
if((IsFileTransferEnabled() == FALSE) || ( cl->viewOnly == TRUE)) {
|
||||
rfbCloseClient(cl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data = rfbGetTightClientData(cl);
|
||||
if(data == NULL)
|
||||
return FALSE;
|
||||
|
||||
handler(cl, data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rfbBool
|
||||
rfbTightExtensionMsgHandler(struct _rfbClientRec* cl, void* data,
|
||||
const rfbClientToServerMsg* msg)
|
||||
{
|
||||
switch (msg->type) {
|
||||
|
||||
case rfbFileListRequest:
|
||||
|
||||
return handleMessage(cl, "rfbFileListRequest", HandleFileListRequest);
|
||||
|
||||
case rfbFileDownloadRequest:
|
||||
|
||||
return handleMessage(cl, "rfbFileDownloadRequest", HandleFileDownloadRequest);
|
||||
|
||||
case rfbFileUploadRequest:
|
||||
|
||||
return handleMessage(cl, "rfbFileUploadRequest", HandleFileUploadRequest);
|
||||
|
||||
case rfbFileUploadData:
|
||||
|
||||
return handleMessage(cl, "rfbFileUploadDataRequest", HandleFileUploadDataRequest);
|
||||
|
||||
case rfbFileDownloadCancel:
|
||||
|
||||
return handleMessage(cl, "rfbFileDownloadCancelRequest", HandleFileDownloadCancelRequest);
|
||||
|
||||
case rfbFileUploadFailed:
|
||||
|
||||
return handleMessage(cl, "rfbFileUploadFailedRequest", HandleFileUploadFailedRequest);
|
||||
|
||||
case rfbFileCreateDirRequest:
|
||||
|
||||
return handleMessage(cl, "rfbFileCreateDirRequest", HandleFileCreateDirRequest);
|
||||
|
||||
default:
|
||||
|
||||
rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
|
||||
msg->type);
|
||||
|
||||
/*
|
||||
|
||||
We shouldn't close the connection here for unhandled msg,
|
||||
it should be left to libvncserver.
|
||||
rfbLog(" ... closing connection\n");
|
||||
rfbCloseClient(cl);
|
||||
|
||||
*/
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rfbTightExtensionClientClose(rfbClientPtr cl, void* data) {
|
||||
|
||||
if(data != NULL) {
|
||||
CloseUndoneFileUpload(cl, data);
|
||||
CloseUndoneFileDownload(cl, data);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rfbTightUsage(void) {
|
||||
fprintf(stderr, "\nlibvncserver-tight-extension options:\n");
|
||||
fprintf(stderr, "-disablefiletransfer disable file transfer\n");
|
||||
fprintf(stderr, "-ftproot string set ftp root\n");
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
|
||||
int
|
||||
rfbTightProcessArg(int argc, char *argv[]) {
|
||||
|
||||
rfbLog("tightvnc-filetransfer/rfbTightProcessArg\n");
|
||||
|
||||
InitFileTransfer();
|
||||
|
||||
if(argc<1)
|
||||
return 0;
|
||||
|
||||
if (strcmp(argv[0], "-ftproot") == 0) { /* -ftproot string */
|
||||
if (2 > argc) {
|
||||
return 0;
|
||||
}
|
||||
rfbLog("ftproot is set to <%s>\n", argv[1]);
|
||||
if(SetFtpRoot(argv[1]) == FALSE) {
|
||||
rfbLog("ERROR:: Path specified for ftproot in invalid\n");
|
||||
return 0;
|
||||
}
|
||||
return 2;
|
||||
} else if (strcmp(argv[0], "-disablefiletransfer") == 0) {
|
||||
EnableFileTransfer(FALSE);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method should be registered to libvncserver to handle rfbSecTypeTight security type.
|
||||
*/
|
||||
void
|
||||
rfbHandleSecTypeTight(rfbClientPtr cl) {
|
||||
|
||||
rfbTightClientPtr rtcp = (rfbTightClientPtr) malloc(sizeof(rfbTightClientRec));
|
||||
|
||||
rfbLog("tightvnc-filetransfer/rfbHandleSecTypeTight\n");
|
||||
|
||||
if(rtcp == NULL) {
|
||||
/* Error condition close socket */
|
||||
rfbLog("Memory error has occurred while handling "
|
||||
"Tight security type... closing connection.\n");
|
||||
rfbCloseClient(cl);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(rtcp, 0, sizeof(rfbTightClientRec));
|
||||
rtcp->rcft.rcfd.downloadFD = -1;
|
||||
rtcp->rcft.rcfu.uploadFD = -1;
|
||||
rfbEnableExtension(cl, &tightVncFileTransferExtension, rtcp);
|
||||
|
||||
rfbSendTunnelingCaps(cl);
|
||||
|
||||
}
|
||||
|
||||
rfbProtocolExtension tightVncFileTransferExtension = {
|
||||
NULL,
|
||||
rfbTightExtensionInit,
|
||||
NULL,
|
||||
NULL,
|
||||
rfbTightExtensionMsgHandler,
|
||||
rfbTightExtensionClientClose,
|
||||
rfbTightUsage,
|
||||
rfbTightProcessArg,
|
||||
NULL
|
||||
};
|
||||
|
||||
static rfbSecurityHandler tightVncSecurityHandler = {
|
||||
rfbSecTypeTight,
|
||||
rfbHandleSecTypeTight,
|
||||
NULL
|
||||
};
|
||||
|
||||
void rfbRegisterTightVNCFileTransferExtension(void) {
|
||||
rfbRegisterProtocolExtension(&tightVncFileTransferExtension);
|
||||
rfbRegisterSecurityHandler(&tightVncSecurityHandler);
|
||||
/*
|
||||
Called as well from rfbTightProcessArg(), but only if there are non
|
||||
handled cmdline args. Thus, init file transfer here as well.
|
||||
*/
|
||||
InitFileTransfer();
|
||||
}
|
||||
|
||||
void
|
||||
rfbUnregisterTightVNCFileTransferExtension(void) {
|
||||
rfbUnregisterProtocolExtension(&tightVncFileTransferExtension);
|
||||
rfbUnregisterSecurityHandler(&tightVncSecurityHandler);
|
||||
}
|
||||
|
||||
480
android/extern/libvncserver/src/libvncserver/translate.c
vendored
Normal file
480
android/extern/libvncserver/src/libvncserver/translate.c
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* translate.c - translate between different pixel formats
|
||||
*/
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/rfbregion.h>
|
||||
|
||||
static void PrintPixelFormat(rfbPixelFormat *pf);
|
||||
static rfbBool rfbSetClientColourMapBGR233(rfbClientPtr cl);
|
||||
|
||||
rfbBool rfbEconomicTranslate = FALSE;
|
||||
|
||||
/*
|
||||
* Some standard pixel formats.
|
||||
*/
|
||||
|
||||
static const rfbPixelFormat BGR233Format = {
|
||||
8, 8, 0, 1, 7, 7, 3, 0, 3, 6, 0, 0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Macro to compare pixel formats.
|
||||
*/
|
||||
|
||||
#define PF_EQ(x,y) \
|
||||
((x.bitsPerPixel == y.bitsPerPixel) && \
|
||||
(x.depth == y.depth) && \
|
||||
((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \
|
||||
(!x.trueColour == !y.trueColour) && \
|
||||
(!x.trueColour || ((x.redMax == y.redMax) && \
|
||||
(x.greenMax == y.greenMax) && \
|
||||
(x.blueMax == y.blueMax) && \
|
||||
(x.redShift == y.redShift) && \
|
||||
(x.greenShift == y.greenShift) && \
|
||||
(x.blueShift == y.blueShift))))
|
||||
|
||||
#define CONCAT2(a,b) a##b
|
||||
#define CONCAT2E(a,b) CONCAT2(a,b)
|
||||
#define CONCAT3(a,b,c) a##b##c
|
||||
#define CONCAT3E(a,b,c) CONCAT3(a,b,c)
|
||||
#define CONCAT4(a,b,c,d) a##b##c##d
|
||||
#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
|
||||
|
||||
#undef OUT
|
||||
#undef IN
|
||||
|
||||
#define OUT 8
|
||||
#include "tableinitcmtemplate.c"
|
||||
#include "tableinittctemplate.c"
|
||||
#define IN 8
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#define IN 16
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#define IN 32
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#undef OUT
|
||||
|
||||
#define OUT 16
|
||||
#include "tableinitcmtemplate.c"
|
||||
#include "tableinittctemplate.c"
|
||||
#define IN 8
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#define IN 16
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#define IN 32
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#undef OUT
|
||||
|
||||
#define OUT 32
|
||||
#include "tableinitcmtemplate.c"
|
||||
#include "tableinittctemplate.c"
|
||||
#define IN 8
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#define IN 16
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#define IN 32
|
||||
#include "tabletranstemplate.c"
|
||||
#undef IN
|
||||
#undef OUT
|
||||
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
#define COUNT_OFFSETS 4
|
||||
#define BPP2OFFSET(bpp) ((bpp)/8-1)
|
||||
#include "tableinit24.c"
|
||||
#define BPP 8
|
||||
#include "tabletrans24template.c"
|
||||
#undef BPP
|
||||
#define BPP 16
|
||||
#include "tabletrans24template.c"
|
||||
#undef BPP
|
||||
#define BPP 24
|
||||
#include "tabletrans24template.c"
|
||||
#undef BPP
|
||||
#define BPP 32
|
||||
#include "tabletrans24template.c"
|
||||
#undef BPP
|
||||
#else
|
||||
#define COUNT_OFFSETS 3
|
||||
#define BPP2OFFSET(bpp) ((int)(bpp)/16)
|
||||
#endif
|
||||
|
||||
typedef void (*rfbInitCMTableFnType)(char **table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out,rfbColourMap* cm);
|
||||
typedef void (*rfbInitTableFnType)(char **table, rfbPixelFormat *in,
|
||||
rfbPixelFormat *out);
|
||||
|
||||
static rfbInitCMTableFnType rfbInitColourMapSingleTableFns[COUNT_OFFSETS] = {
|
||||
rfbInitColourMapSingleTable8,
|
||||
rfbInitColourMapSingleTable16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbInitColourMapSingleTable24,
|
||||
#endif
|
||||
rfbInitColourMapSingleTable32
|
||||
};
|
||||
|
||||
static rfbInitTableFnType rfbInitTrueColourSingleTableFns[COUNT_OFFSETS] = {
|
||||
rfbInitTrueColourSingleTable8,
|
||||
rfbInitTrueColourSingleTable16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbInitTrueColourSingleTable24,
|
||||
#endif
|
||||
rfbInitTrueColourSingleTable32
|
||||
};
|
||||
|
||||
static rfbInitTableFnType rfbInitTrueColourRGBTablesFns[COUNT_OFFSETS] = {
|
||||
rfbInitTrueColourRGBTables8,
|
||||
rfbInitTrueColourRGBTables16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbInitTrueColourRGBTables24,
|
||||
#endif
|
||||
rfbInitTrueColourRGBTables32
|
||||
};
|
||||
|
||||
static rfbTranslateFnType rfbTranslateWithSingleTableFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
|
||||
{ rfbTranslateWithSingleTable8to8,
|
||||
rfbTranslateWithSingleTable8to16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbTranslateWithSingleTable8to24,
|
||||
#endif
|
||||
rfbTranslateWithSingleTable8to32 },
|
||||
{ rfbTranslateWithSingleTable16to8,
|
||||
rfbTranslateWithSingleTable16to16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbTranslateWithSingleTable16to24,
|
||||
#endif
|
||||
rfbTranslateWithSingleTable16to32 },
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
{ rfbTranslateWithSingleTable24to8,
|
||||
rfbTranslateWithSingleTable24to16,
|
||||
rfbTranslateWithSingleTable24to24,
|
||||
rfbTranslateWithSingleTable24to32 },
|
||||
#endif
|
||||
{ rfbTranslateWithSingleTable32to8,
|
||||
rfbTranslateWithSingleTable32to16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbTranslateWithSingleTable32to24,
|
||||
#endif
|
||||
rfbTranslateWithSingleTable32to32 }
|
||||
};
|
||||
|
||||
static rfbTranslateFnType rfbTranslateWithRGBTablesFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
|
||||
{ rfbTranslateWithRGBTables8to8,
|
||||
rfbTranslateWithRGBTables8to16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbTranslateWithRGBTables8to24,
|
||||
#endif
|
||||
rfbTranslateWithRGBTables8to32 },
|
||||
{ rfbTranslateWithRGBTables16to8,
|
||||
rfbTranslateWithRGBTables16to16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbTranslateWithRGBTables16to24,
|
||||
#endif
|
||||
rfbTranslateWithRGBTables16to32 },
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
{ rfbTranslateWithRGBTables24to8,
|
||||
rfbTranslateWithRGBTables24to16,
|
||||
rfbTranslateWithRGBTables24to24,
|
||||
rfbTranslateWithRGBTables24to32 },
|
||||
#endif
|
||||
{ rfbTranslateWithRGBTables32to8,
|
||||
rfbTranslateWithRGBTables32to16,
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
rfbTranslateWithRGBTables32to24,
|
||||
#endif
|
||||
rfbTranslateWithRGBTables32to32 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* rfbTranslateNone is used when no translation is required.
|
||||
*/
|
||||
|
||||
void
|
||||
rfbTranslateNone(char *table, rfbPixelFormat *in, rfbPixelFormat *out,
|
||||
char *iptr, char *optr, int bytesBetweenInputLines,
|
||||
int width, int height)
|
||||
{
|
||||
int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
|
||||
|
||||
while (height > 0) {
|
||||
memcpy(optr, iptr, bytesPerOutputLine);
|
||||
iptr += bytesBetweenInputLines;
|
||||
optr += bytesPerOutputLine;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rfbSetTranslateFunction sets the translation function.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSetTranslateFunction(rfbClientPtr cl)
|
||||
{
|
||||
rfbLog("Pixel format for client %s:\n",cl->host);
|
||||
PrintPixelFormat(&cl->format);
|
||||
|
||||
/*
|
||||
* Check that bits per pixel values are valid
|
||||
*/
|
||||
|
||||
if ((cl->screen->serverFormat.bitsPerPixel != 8) &&
|
||||
(cl->screen->serverFormat.bitsPerPixel != 16) &&
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
(cl->screen->serverFormat.bitsPerPixel != 24) &&
|
||||
#endif
|
||||
(cl->screen->serverFormat.bitsPerPixel != 32))
|
||||
{
|
||||
rfbErr("%s: server bits per pixel not 8, 16 or 32 (is %d)\n",
|
||||
"rfbSetTranslateFunction",
|
||||
cl->screen->serverFormat.bitsPerPixel);
|
||||
rfbCloseClient(cl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((cl->format.bitsPerPixel != 8) &&
|
||||
(cl->format.bitsPerPixel != 16) &&
|
||||
#ifdef LIBVNCSERVER_ALLOW24BPP
|
||||
(cl->format.bitsPerPixel != 24) &&
|
||||
#endif
|
||||
(cl->format.bitsPerPixel != 32))
|
||||
{
|
||||
rfbErr("%s: client bits per pixel not 8, 16 or 32\n",
|
||||
"rfbSetTranslateFunction");
|
||||
rfbCloseClient(cl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) {
|
||||
rfbErr("rfbSetTranslateFunction: client has colour map "
|
||||
"but %d-bit - can only cope with 8-bit colour maps\n",
|
||||
cl->format.bitsPerPixel);
|
||||
rfbCloseClient(cl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* bpp is valid, now work out how to translate
|
||||
*/
|
||||
|
||||
if (!cl->format.trueColour) {
|
||||
/*
|
||||
* truecolour -> colour map
|
||||
*
|
||||
* Set client's colour map to BGR233, then effectively it's
|
||||
* truecolour as well
|
||||
*/
|
||||
|
||||
if (!rfbSetClientColourMapBGR233(cl))
|
||||
return FALSE;
|
||||
|
||||
cl->format = BGR233Format;
|
||||
}
|
||||
|
||||
/* truecolour -> truecolour */
|
||||
|
||||
if (PF_EQ(cl->format,cl->screen->serverFormat)) {
|
||||
|
||||
/* client & server the same */
|
||||
|
||||
rfbLog("no translation needed\n");
|
||||
cl->translateFn = rfbTranslateNone;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ((cl->screen->serverFormat.bitsPerPixel < 16) ||
|
||||
((!cl->screen->serverFormat.trueColour || !rfbEconomicTranslate) &&
|
||||
(cl->screen->serverFormat.bitsPerPixel == 16))) {
|
||||
|
||||
/* we can use a single lookup table for <= 16 bpp */
|
||||
|
||||
cl->translateFn = rfbTranslateWithSingleTableFns
|
||||
[BPP2OFFSET(cl->screen->serverFormat.bitsPerPixel)]
|
||||
[BPP2OFFSET(cl->format.bitsPerPixel)];
|
||||
|
||||
if(cl->screen->serverFormat.trueColour)
|
||||
(*rfbInitTrueColourSingleTableFns
|
||||
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
|
||||
&(cl->screen->serverFormat), &cl->format);
|
||||
else
|
||||
(*rfbInitColourMapSingleTableFns
|
||||
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
|
||||
&(cl->screen->serverFormat), &cl->format,&cl->screen->colourMap);
|
||||
|
||||
} else {
|
||||
|
||||
/* otherwise we use three separate tables for red, green and blue */
|
||||
|
||||
cl->translateFn = rfbTranslateWithRGBTablesFns
|
||||
[BPP2OFFSET(cl->screen->serverFormat.bitsPerPixel)]
|
||||
[BPP2OFFSET(cl->format.bitsPerPixel)];
|
||||
|
||||
(*rfbInitTrueColourRGBTablesFns
|
||||
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
|
||||
&(cl->screen->serverFormat), &cl->format);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* rfbSetClientColourMapBGR233 sets the client's colour map so that it's
|
||||
* just like an 8-bit BGR233 true colour client.
|
||||
*/
|
||||
|
||||
static rfbBool
|
||||
rfbSetClientColourMapBGR233(rfbClientPtr cl)
|
||||
{
|
||||
union {
|
||||
char bytes[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
|
||||
rfbSetColourMapEntriesMsg msg;
|
||||
} buf;
|
||||
rfbSetColourMapEntriesMsg *scme = &buf.msg;
|
||||
uint16_t *rgb = (uint16_t *)(&buf.bytes[sz_rfbSetColourMapEntriesMsg]);
|
||||
int i, len;
|
||||
int r, g, b;
|
||||
|
||||
if (cl->format.bitsPerPixel != 8 ) {
|
||||
rfbErr("%s: client not 8 bits per pixel\n",
|
||||
"rfbSetClientColourMapBGR233");
|
||||
rfbCloseClient(cl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
scme->type = rfbSetColourMapEntries;
|
||||
|
||||
scme->firstColour = Swap16IfLE(0);
|
||||
scme->nColours = Swap16IfLE(256);
|
||||
|
||||
len = sz_rfbSetColourMapEntriesMsg;
|
||||
|
||||
i = 0;
|
||||
|
||||
for (b = 0; b < 4; b++) {
|
||||
for (g = 0; g < 8; g++) {
|
||||
for (r = 0; r < 8; r++) {
|
||||
rgb[i++] = Swap16IfLE(r * 65535 / 7);
|
||||
rgb[i++] = Swap16IfLE(g * 65535 / 7);
|
||||
rgb[i++] = Swap16IfLE(b * 65535 / 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len += 256 * 3 * 2;
|
||||
|
||||
if (rfbWriteExact(cl, buf.bytes, len) < 0) {
|
||||
rfbLogPerror("rfbSetClientColourMapBGR233: write");
|
||||
rfbCloseClient(cl);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* this function is not called very often, so it needn't be
|
||||
efficient. */
|
||||
|
||||
/*
|
||||
* rfbSetClientColourMap is called to set the client's colour map. If the
|
||||
* client is a true colour client, we simply update our own translation table
|
||||
* and mark the whole screen as having been modified.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSetClientColourMap(rfbClientPtr cl, int firstColour, int nColours)
|
||||
{
|
||||
if (cl->screen->serverFormat.trueColour || !cl->readyForSetColourMapEntries) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (nColours == 0) {
|
||||
nColours = cl->screen->colourMap.count;
|
||||
}
|
||||
|
||||
if (cl->format.trueColour) {
|
||||
LOCK(cl->updateMutex);
|
||||
(*rfbInitColourMapSingleTableFns
|
||||
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
|
||||
&cl->screen->serverFormat, &cl->format,&cl->screen->colourMap);
|
||||
|
||||
sraRgnDestroy(cl->modifiedRegion);
|
||||
cl->modifiedRegion =
|
||||
sraRgnCreateRect(0,0,cl->screen->width,cl->screen->height);
|
||||
UNLOCK(cl->updateMutex);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return rfbSendSetColourMapEntries(cl, firstColour, nColours);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rfbSetClientColourMaps sets the colour map for each RFB client.
|
||||
*/
|
||||
|
||||
void
|
||||
rfbSetClientColourMaps(rfbScreenInfoPtr rfbScreen, int firstColour, int nColours)
|
||||
{
|
||||
rfbClientIteratorPtr i;
|
||||
rfbClientPtr cl;
|
||||
|
||||
i = rfbGetClientIterator(rfbScreen);
|
||||
while((cl = rfbClientIteratorNext(i)))
|
||||
rfbSetClientColourMap(cl, firstColour, nColours);
|
||||
rfbReleaseClientIterator(i);
|
||||
}
|
||||
|
||||
static void
|
||||
PrintPixelFormat(rfbPixelFormat *pf)
|
||||
{
|
||||
if (pf->bitsPerPixel == 1) {
|
||||
rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
|
||||
(pf->bigEndian ? "most" : "least"));
|
||||
} else {
|
||||
rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
|
||||
((pf->bitsPerPixel == 8) ? ""
|
||||
: (pf->bigEndian ? ", big endian" : ", little endian")));
|
||||
if (pf->trueColour) {
|
||||
rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
|
||||
pf->redMax, pf->greenMax, pf->blueMax,
|
||||
pf->redShift, pf->greenShift, pf->blueShift);
|
||||
} else {
|
||||
rfbLog(" uses a colour map (not true colour).\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
249
android/extern/libvncserver/src/libvncserver/ultra.c
vendored
Normal file
249
android/extern/libvncserver/src/libvncserver/ultra.c
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* ultra.c
|
||||
*
|
||||
* Routines to implement ultra based encoding (minilzo).
|
||||
* ultrazip supports packed rectangles if the rects are tiny...
|
||||
* This improves performance as lzo has more data to work with at once
|
||||
* This is 'UltraZip' and is currently not implemented.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#ifdef LIBVNCSERVER_HAVE_LZO
|
||||
#include <lzo/lzo1x.h>
|
||||
#else
|
||||
#include "minilzo.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cl->beforeEncBuf contains pixel data in the client's format.
|
||||
* cl->afterEncBuf contains the lzo (deflated) encoding version.
|
||||
* If the lzo compressed/encoded version is
|
||||
* larger than the raw data or if it exceeds cl->afterEncBufSize then
|
||||
* raw encoding is used instead.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
|
||||
* rectangle encoding.
|
||||
*/
|
||||
|
||||
#define MAX_WRKMEM ((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)
|
||||
|
||||
|
||||
void rfbFreeUltraData(rfbClientPtr cl) {
|
||||
if (cl->compStreamInitedLZO) {
|
||||
free(cl->lzoWrkMem);
|
||||
cl->compStreamInitedLZO=FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static rfbBool
|
||||
rfbSendOneRectEncodingUltra(rfbClientPtr cl,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
rfbZlibHeader hdr;
|
||||
int deflateResult;
|
||||
int i;
|
||||
char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
|
||||
+ (x * (cl->scaledScreen->bitsPerPixel / 8)));
|
||||
|
||||
int maxRawSize;
|
||||
lzo_uint maxCompSize;
|
||||
|
||||
maxRawSize = (w * h * (cl->format.bitsPerPixel / 8));
|
||||
|
||||
if (!cl->beforeEncBuf || cl->beforeEncBufSize < maxRawSize) {
|
||||
if (cl->beforeEncBuf == NULL)
|
||||
cl->beforeEncBuf = (char *)malloc(maxRawSize);
|
||||
else {
|
||||
char *reallocedBeforeEncBuf = (char *)realloc(cl->beforeEncBuf, maxRawSize);
|
||||
if (!reallocedBeforeEncBuf) return FALSE;
|
||||
cl->beforeEncBuf = reallocedBeforeEncBuf;
|
||||
}
|
||||
if(cl->beforeEncBuf)
|
||||
cl->beforeEncBufSize = maxRawSize;
|
||||
}
|
||||
|
||||
/*
|
||||
* lzo requires output buffer to be slightly larger than the input
|
||||
* buffer, in the worst case.
|
||||
*/
|
||||
maxCompSize = (maxRawSize + maxRawSize / 16 + 64 + 3);
|
||||
|
||||
if (!cl->afterEncBuf || cl->afterEncBufSize < (int)maxCompSize) {
|
||||
if (cl->afterEncBuf == NULL)
|
||||
cl->afterEncBuf = (char *)malloc(maxCompSize);
|
||||
else {
|
||||
char *reallocedAfterEncBuf = (char *)realloc(cl->afterEncBuf, maxCompSize);
|
||||
if (!reallocedAfterEncBuf) return FALSE;
|
||||
cl->afterEncBuf = reallocedAfterEncBuf;
|
||||
}
|
||||
if(cl->afterEncBuf)
|
||||
cl->afterEncBufSize = maxCompSize;
|
||||
}
|
||||
|
||||
if (!cl->beforeEncBuf || !cl->afterEncBuf)
|
||||
{
|
||||
rfbLog("rfbSendOneRectEncodingUltra: failed to allocate memory\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert pixel data to client format.
|
||||
*/
|
||||
(*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
|
||||
&cl->format, fbptr, cl->beforeEncBuf,
|
||||
cl->scaledScreen->paddedWidthInBytes, w, h);
|
||||
|
||||
if ( cl->compStreamInitedLZO == FALSE ) {
|
||||
cl->compStreamInitedLZO = TRUE;
|
||||
/* Work-memory needed for compression. Allocate memory in units
|
||||
* of `lzo_align_t' (instead of `char') to make sure it is properly aligned.
|
||||
*/
|
||||
cl->lzoWrkMem = malloc(sizeof(lzo_align_t) * (((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)));
|
||||
}
|
||||
|
||||
/* Perform the compression here. */
|
||||
deflateResult = lzo1x_1_compress((unsigned char *)cl->beforeEncBuf, (lzo_uint)w * h * (cl->format.bitsPerPixel / 8), (unsigned char *)cl->afterEncBuf, &maxCompSize, cl->lzoWrkMem);
|
||||
/* maxCompSize now contains the compressed size */
|
||||
|
||||
/* Find the total size of the resulting compressed data. */
|
||||
cl->afterEncBufLen = maxCompSize;
|
||||
|
||||
if ( deflateResult != LZO_E_OK ) {
|
||||
rfbErr("lzo deflation error: %d\n", deflateResult);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Update statics */
|
||||
rfbStatRecordEncodingSent(cl, rfbEncodingUltra, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + cl->afterEncBufLen, maxRawSize);
|
||||
|
||||
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
|
||||
> UPDATE_BUF_SIZE)
|
||||
{
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rect.r.x = Swap16IfLE(x);
|
||||
rect.r.y = Swap16IfLE(y);
|
||||
rect.r.w = Swap16IfLE(w);
|
||||
rect.r.h = Swap16IfLE(h);
|
||||
rect.encoding = Swap32IfLE(rfbEncodingUltra);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
|
||||
sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
hdr.nBytes = Swap32IfLE(cl->afterEncBufLen);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
|
||||
cl->ublen += sz_rfbZlibHeader;
|
||||
|
||||
/* We might want to try sending the data directly... */
|
||||
for (i = 0; i < cl->afterEncBufLen;) {
|
||||
|
||||
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
|
||||
|
||||
if (i + bytesToCopy > cl->afterEncBufLen) {
|
||||
bytesToCopy = cl->afterEncBufLen - i;
|
||||
}
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], &cl->afterEncBuf[i], bytesToCopy);
|
||||
|
||||
cl->ublen += bytesToCopy;
|
||||
i += bytesToCopy;
|
||||
|
||||
if (cl->ublen == UPDATE_BUF_SIZE) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* rfbSendRectEncodingUltra - send a given rectangle using one or more
|
||||
* LZO encoding rectangles.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSendRectEncodingUltra(rfbClientPtr cl,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
int maxLines;
|
||||
int linesRemaining;
|
||||
rfbRectangle partialRect;
|
||||
|
||||
partialRect.x = x;
|
||||
partialRect.y = y;
|
||||
partialRect.w = w;
|
||||
partialRect.h = h;
|
||||
|
||||
/* Determine maximum pixel/scan lines allowed per rectangle. */
|
||||
maxLines = ( ULTRA_MAX_SIZE(w) / w );
|
||||
|
||||
/* Initialize number of scan lines left to do. */
|
||||
linesRemaining = h;
|
||||
|
||||
/* Loop until all work is done. */
|
||||
while ( linesRemaining > 0 ) {
|
||||
|
||||
int linesToComp;
|
||||
|
||||
if ( maxLines < linesRemaining )
|
||||
linesToComp = maxLines;
|
||||
else
|
||||
linesToComp = linesRemaining;
|
||||
|
||||
partialRect.h = linesToComp;
|
||||
|
||||
/* Encode (compress) and send the next rectangle. */
|
||||
if ( ! rfbSendOneRectEncodingUltra( cl,
|
||||
partialRect.x,
|
||||
partialRect.y,
|
||||
partialRect.w,
|
||||
partialRect.h )) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Technically, flushing the buffer here is not extremely
|
||||
* efficient. However, this improves the overall throughput
|
||||
* of the system over very slow networks. By flushing
|
||||
* the buffer with every maximum size lzo rectangle, we
|
||||
* improve the pipelining usage of the server CPU, network,
|
||||
* and viewer CPU components. Insuring that these components
|
||||
* are working in parallel actually improves the performance
|
||||
* seen by the user.
|
||||
* Since, lzo is most useful for slow networks, this flush
|
||||
* is appropriate for the desired behavior of the lzo encoding.
|
||||
*/
|
||||
if (( cl->ublen > 0 ) &&
|
||||
( linesToComp == maxLines )) {
|
||||
if (!rfbSendUpdateBuf(cl)) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update remaining and incremental rectangle location. */
|
||||
linesRemaining -= linesToComp;
|
||||
partialRect.y += linesToComp;
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
464
android/extern/libvncserver/src/libvncserver/websockets.c
vendored
Normal file
464
android/extern/libvncserver/src/libvncserver/websockets.c
vendored
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* websockets.c - deal with WebSockets clients.
|
||||
*
|
||||
* This code should be independent of any changes in the RFB protocol. It is
|
||||
* an additional handshake and framing of normal sockets:
|
||||
* http://www.whatwg.org/specs/web-socket-protocol/
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010 Joel Martin
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
/* errno */
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#if LIBVNCSERVER_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "rfb/rfbconfig.h"
|
||||
#include "rfbssl.h"
|
||||
#include "crypto.h"
|
||||
#include "ws_decode.h"
|
||||
#include "base64.h"
|
||||
|
||||
#if 0
|
||||
#include <sys/syscall.h>
|
||||
static int gettid() {
|
||||
return (int)syscall(SYS_gettid);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* draft-ietf-hybi-thewebsocketprotocol-10
|
||||
* 5.2.2. Sending the Server's Opening Handshake
|
||||
*/
|
||||
#define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
|
||||
#define SERVER_HANDSHAKE_HYBI "HTTP/1.1 101 Switching Protocols\r\n\
|
||||
Upgrade: websocket\r\n\
|
||||
Connection: Upgrade\r\n\
|
||||
Sec-WebSocket-Accept: %s\r\n\
|
||||
Sec-WebSocket-Protocol: %s\r\n\
|
||||
\r\n"
|
||||
|
||||
#define SERVER_HANDSHAKE_HYBI_NO_PROTOCOL "HTTP/1.1 101 Switching Protocols\r\n\
|
||||
Upgrade: websocket\r\n\
|
||||
Connection: Upgrade\r\n\
|
||||
Sec-WebSocket-Accept: %s\r\n\
|
||||
\r\n"
|
||||
|
||||
#define WEBSOCKETS_CLIENT_CONNECT_WAIT_MS 100
|
||||
#define WEBSOCKETS_CLIENT_SEND_WAIT_MS 100
|
||||
#define WEBSOCKETS_MAX_HANDSHAKE_LEN 4096
|
||||
|
||||
#if defined(__linux__) && defined(NEED_TIMEVAL)
|
||||
struct timeval
|
||||
{
|
||||
long int tv_sec,tv_usec;
|
||||
}
|
||||
;
|
||||
#endif
|
||||
|
||||
static rfbBool webSocketsHandshake(rfbClientPtr cl, char *scheme);
|
||||
|
||||
static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst);
|
||||
|
||||
static int ws_read(void *cl, char *buf, size_t len);
|
||||
|
||||
|
||||
static int
|
||||
min (int a, int b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static void webSocketsGenSha1Key(char *target, int size, char *key)
|
||||
{
|
||||
unsigned char hash[SHA1_HASH_SIZE];
|
||||
char tmp[strlen(key) + sizeof(GUID) - 1];
|
||||
memcpy(tmp, key, strlen(key));
|
||||
memcpy(tmp + strlen(key), GUID, sizeof(GUID) - 1);
|
||||
hash_sha1(hash, tmp, sizeof(tmp));
|
||||
if (-1 == rfbBase64NtoP(hash, sizeof(hash), target, size))
|
||||
rfbErr("rfbBase64NtoP failed\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* rfbWebSocketsHandshake is called to handle new WebSockets connections
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
webSocketsCheck (rfbClientPtr cl)
|
||||
{
|
||||
char bbuf[4], *scheme;
|
||||
int ret;
|
||||
|
||||
ret = rfbPeekExactTimeout(cl, bbuf, 4,
|
||||
WEBSOCKETS_CLIENT_CONNECT_WAIT_MS);
|
||||
if ((ret < 0) && (errno == ETIMEDOUT)) {
|
||||
rfbLog("Normal socket connection\n");
|
||||
return TRUE;
|
||||
} else if (ret <= 0) {
|
||||
rfbErr("webSocketsHandshake: unknown connection error\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (strncmp(bbuf, "RFB ", 4) == 0) {
|
||||
rfbLog("Normal socket connection\n");
|
||||
return TRUE;
|
||||
} else if (strncmp(bbuf, "\x16", 1) == 0 || strncmp(bbuf, "\x80", 1) == 0) {
|
||||
rfbLog("Got TLS/SSL WebSockets connection\n");
|
||||
if (-1 == rfbssl_init(cl)) {
|
||||
rfbErr("webSocketsHandshake: rfbssl_init failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
ret = rfbPeekExactTimeout(cl, bbuf, 4, WEBSOCKETS_CLIENT_CONNECT_WAIT_MS);
|
||||
scheme = "wss";
|
||||
} else {
|
||||
scheme = "ws";
|
||||
}
|
||||
|
||||
if (strncmp(bbuf, "GET ", 4) != 0) {
|
||||
rfbErr("webSocketsHandshake: invalid client header\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rfbLog("Got '%s' WebSockets handshake\n", scheme);
|
||||
|
||||
if (!webSocketsHandshake(cl, scheme)) {
|
||||
return FALSE;
|
||||
}
|
||||
/* Start WebSockets framing */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static rfbBool
|
||||
webSocketsHandshake(rfbClientPtr cl, char *scheme)
|
||||
{
|
||||
char *buf, *response, *line;
|
||||
int n, linestart = 0, len = 0, llen, base64 = FALSE;
|
||||
char *path = NULL, *host = NULL, *origin = NULL, *protocol = NULL;
|
||||
char *key1 = NULL, *key2 = NULL;
|
||||
char *sec_ws_origin = NULL;
|
||||
char *sec_ws_key = NULL;
|
||||
char sec_ws_version = 0;
|
||||
ws_ctx_t *wsctx = NULL;
|
||||
|
||||
buf = (char *) malloc(WEBSOCKETS_MAX_HANDSHAKE_LEN);
|
||||
if (!buf) {
|
||||
rfbLogPerror("webSocketsHandshake: malloc");
|
||||
return FALSE;
|
||||
}
|
||||
response = (char *) malloc(WEBSOCKETS_MAX_HANDSHAKE_LEN);
|
||||
if (!response) {
|
||||
free(buf);
|
||||
rfbLogPerror("webSocketsHandshake: malloc");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (len < WEBSOCKETS_MAX_HANDSHAKE_LEN-1) {
|
||||
if ((n = rfbReadExactTimeout(cl, buf+len, 1,
|
||||
WEBSOCKETS_CLIENT_SEND_WAIT_MS)) <= 0) {
|
||||
if ((n < 0) && (errno == ETIMEDOUT)) {
|
||||
break;
|
||||
}
|
||||
if (n == 0) {
|
||||
rfbLog("webSocketsHandshake: client gone\n");
|
||||
}
|
||||
else {
|
||||
rfbLogPerror("webSocketsHandshake: read");
|
||||
}
|
||||
|
||||
free(response);
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
len += 1;
|
||||
llen = len - linestart;
|
||||
if (((llen >= 2)) && (buf[len-1] == '\n')) {
|
||||
line = buf+linestart;
|
||||
if ((llen == 2) && (strncmp("\r\n", line, 2) == 0)) {
|
||||
if (key1 && key2 && len+8 < WEBSOCKETS_MAX_HANDSHAKE_LEN) {
|
||||
if ((n = rfbReadExact(cl, buf+len, 8)) <= 0) {
|
||||
if ((n < 0) && (errno == ETIMEDOUT)) {
|
||||
break;
|
||||
}
|
||||
if (n == 0)
|
||||
rfbLog("webSocketsHandshake: client gone\n");
|
||||
else
|
||||
rfbLogPerror("webSocketsHandshake: read");
|
||||
free(response);
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
len += 8;
|
||||
} else {
|
||||
buf[len] = '\0';
|
||||
}
|
||||
break;
|
||||
} else if ((llen >= 16) && ((strncmp("GET ", line, min(llen,4))) == 0)) {
|
||||
/* 16 = 4 ("GET ") + 1 ("/.*") + 11 (" HTTP/1.1\r\n") */
|
||||
path = line+4;
|
||||
buf[len-11] = '\0'; /* Trim trailing " HTTP/1.1\r\n" */
|
||||
cl->wspath = strdup(path);
|
||||
/* rfbLog("Got path: %s\n", path); */
|
||||
} else if ((strncasecmp("host: ", line, min(llen,6))) == 0) {
|
||||
host = line+6;
|
||||
buf[len-2] = '\0';
|
||||
/* rfbLog("Got host: %s\n", host); */
|
||||
} else if ((strncasecmp("origin: ", line, min(llen,8))) == 0) {
|
||||
origin = line+8;
|
||||
buf[len-2] = '\0';
|
||||
/* rfbLog("Got origin: %s\n", origin); */
|
||||
} else if ((strncasecmp("sec-websocket-key1: ", line, min(llen,20))) == 0) {
|
||||
key1 = line+20;
|
||||
buf[len-2] = '\0';
|
||||
/* rfbLog("Got key1: %s\n", key1); */
|
||||
} else if ((strncasecmp("sec-websocket-key2: ", line, min(llen,20))) == 0) {
|
||||
key2 = line+20;
|
||||
buf[len-2] = '\0';
|
||||
/* rfbLog("Got key2: %s\n", key2); */
|
||||
/* HyBI */
|
||||
|
||||
} else if ((strncasecmp("sec-websocket-protocol: ", line, min(llen,24))) == 0) {
|
||||
protocol = line+24;
|
||||
buf[len-2] = '\0';
|
||||
rfbLog("Got protocol: %s\n", protocol);
|
||||
} else if ((strncasecmp("sec-websocket-origin: ", line, min(llen,22))) == 0) {
|
||||
sec_ws_origin = line+22;
|
||||
buf[len-2] = '\0';
|
||||
} else if ((strncasecmp("sec-websocket-key: ", line, min(llen,19))) == 0) {
|
||||
sec_ws_key = line+19;
|
||||
buf[len-2] = '\0';
|
||||
} else if ((strncasecmp("sec-websocket-version: ", line, min(llen,23))) == 0) {
|
||||
sec_ws_version = strtol(line+23, NULL, 10);
|
||||
buf[len-2] = '\0';
|
||||
}
|
||||
|
||||
linestart = len;
|
||||
}
|
||||
}
|
||||
|
||||
/* older hixie handshake, this could be removed if
|
||||
* a final standard is established -- removed now */
|
||||
if (!sec_ws_version) {
|
||||
rfbErr("Hixie no longer supported\n");
|
||||
free(response);
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!sec_ws_key) {
|
||||
rfbErr("webSocketsHandshake: sec-websocket-key is missing\n");
|
||||
free(response);
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(path && host && (origin || sec_ws_origin))) {
|
||||
rfbErr("webSocketsHandshake: incomplete client handshake\n");
|
||||
free(response);
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((protocol) && (strstr(protocol, "base64"))) {
|
||||
rfbLog(" - webSocketsHandshake: using base64 encoding\n");
|
||||
base64 = TRUE;
|
||||
protocol = "base64";
|
||||
} else {
|
||||
rfbLog(" - webSocketsHandshake: using binary/raw encoding\n");
|
||||
if ((protocol) && (strstr(protocol, "binary"))) {
|
||||
protocol = "binary";
|
||||
} else {
|
||||
protocol = "";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the WebSockets server response based on the the headers sent
|
||||
* by the client.
|
||||
*/
|
||||
char accept[B64LEN(SHA1_HASH_SIZE) + 1];
|
||||
rfbLog(" - WebSockets client version hybi-%02d\n", sec_ws_version);
|
||||
webSocketsGenSha1Key(accept, sizeof(accept), sec_ws_key);
|
||||
|
||||
if(strlen(protocol) > 0) {
|
||||
len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN,
|
||||
SERVER_HANDSHAKE_HYBI, accept, protocol);
|
||||
} else {
|
||||
len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN,
|
||||
SERVER_HANDSHAKE_HYBI_NO_PROTOCOL, accept);
|
||||
}
|
||||
|
||||
if (rfbWriteExact(cl, response, len) < 0) {
|
||||
rfbErr("webSocketsHandshake: failed sending WebSockets response\n");
|
||||
free(response);
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
/* rfbLog("webSocketsHandshake: %s\n", response); */
|
||||
free(response);
|
||||
free(buf);
|
||||
|
||||
wsctx = calloc(1, sizeof(ws_ctx_t));
|
||||
if (!wsctx) {
|
||||
rfbErr("webSocketsHandshake: could not allocate memory for context\n");
|
||||
return FALSE;
|
||||
}
|
||||
wsctx->encode = webSocketsEncodeHybi;
|
||||
wsctx->decode = webSocketsDecodeHybi;
|
||||
wsctx->ctxInfo.readFunc = ws_read;
|
||||
wsctx->base64 = base64;
|
||||
hybiDecodeCleanupComplete(wsctx);
|
||||
cl->wsctx = (wsCtx *)wsctx;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
ws_read(void *ctxPtr, char *buf, size_t len)
|
||||
{
|
||||
int n;
|
||||
rfbClientPtr cl = ctxPtr;
|
||||
if (cl->sslctx) {
|
||||
n = rfbssl_read(cl, buf, len);
|
||||
} else {
|
||||
n = read(cl->sock, buf, len);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst)
|
||||
{
|
||||
int blen, ret = -1, sz = 0;
|
||||
unsigned char opcode = '\0'; /* TODO: option! */
|
||||
ws_header_t *header;
|
||||
ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
|
||||
|
||||
|
||||
/* Optional opcode:
|
||||
* 0x0 - continuation
|
||||
* 0x1 - text frame (base64 encode buf)
|
||||
* 0x2 - binary frame (use raw buf)
|
||||
* 0x8 - connection close
|
||||
* 0x9 - ping
|
||||
* 0xA - pong
|
||||
**/
|
||||
if (!len) {
|
||||
/* nothing to encode */
|
||||
return 0;
|
||||
}
|
||||
if (len > UPDATE_BUF_SIZE) {
|
||||
rfbErr("%s: Data length %d larger than maximum of %d bytes\n", __func__, len, UPDATE_BUF_SIZE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
header = (ws_header_t *)wsctx->codeBufEncode;
|
||||
|
||||
if (wsctx->base64) {
|
||||
opcode = WS_OPCODE_TEXT_FRAME;
|
||||
/* calculate the resulting size */
|
||||
blen = B64LEN(len);
|
||||
} else {
|
||||
opcode = WS_OPCODE_BINARY_FRAME;
|
||||
blen = len;
|
||||
}
|
||||
|
||||
header->b0 = 0x80 | (opcode & 0x0f);
|
||||
if (blen <= 125) {
|
||||
header->b1 = (uint8_t)blen;
|
||||
sz = 2;
|
||||
} else if (blen <= 65536) {
|
||||
header->b1 = 0x7e;
|
||||
header->u.s16.l16 = WS_HTON16((uint16_t)blen);
|
||||
sz = 4;
|
||||
} else {
|
||||
header->b1 = 0x7f;
|
||||
header->u.s64.l64 = WS_HTON64(blen);
|
||||
sz = 10;
|
||||
}
|
||||
|
||||
if (wsctx->base64) {
|
||||
if (-1 == (ret = rfbBase64NtoP((unsigned char *)src, len, wsctx->codeBufEncode + sz, sizeof(wsctx->codeBufEncode) - sz))) {
|
||||
rfbErr("%s: Base 64 encode failed\n", __func__);
|
||||
} else {
|
||||
if (ret != blen)
|
||||
rfbErr("%s: Base 64 encode; something weird happened\n", __func__);
|
||||
ret += sz;
|
||||
}
|
||||
} else {
|
||||
memcpy(wsctx->codeBufEncode + sz, src, len);
|
||||
ret = sz + len;
|
||||
}
|
||||
|
||||
*dst = wsctx->codeBufEncode;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst)
|
||||
{
|
||||
return webSocketsEncodeHybi(cl, src, len, dst);
|
||||
}
|
||||
|
||||
int
|
||||
webSocketsDecode(rfbClientPtr cl, char *dst, int len)
|
||||
{
|
||||
ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
|
||||
wsctx->ctxInfo.ctxPtr = cl;
|
||||
return webSocketsDecodeHybi(wsctx, dst, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a stub function that was once used for Hixie-encoding.
|
||||
* We keep it for API compatibility.
|
||||
*/
|
||||
rfbBool
|
||||
webSocketCheckDisconnect(rfbClientPtr cl)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* returns TRUE if there is data waiting to be read in our internal buffer
|
||||
* or if is there any pending data in the buffer of the SSL implementation
|
||||
*/
|
||||
rfbBool
|
||||
webSocketsHasDataInBuffer(rfbClientPtr cl)
|
||||
{
|
||||
ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
|
||||
|
||||
if (wsctx && wsctx->readlen)
|
||||
return TRUE;
|
||||
|
||||
return (cl->sslctx && rfbssl_pending(cl) > 0);
|
||||
}
|
||||
586
android/extern/libvncserver/src/libvncserver/ws_decode.c
vendored
Normal file
586
android/extern/libvncserver/src/libvncserver/ws_decode.c
vendored
Normal file
@@ -0,0 +1,586 @@
|
||||
#include "ws_decode.h"
|
||||
#include "base64.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define WS_HYBI_MASK_LEN 4
|
||||
#define WS_HYBI_HEADER_LEN_SHORT 2 + WS_HYBI_MASK_LEN
|
||||
#define WS_HYBI_HEADER_LEN_EXTENDED 4 + WS_HYBI_MASK_LEN
|
||||
#define WS_HYBI_HEADER_LEN_LONG 10 + WS_HYBI_MASK_LEN
|
||||
|
||||
#undef WS_DECODE_DEBUG
|
||||
/* set to 1 to produce very fine debugging output */
|
||||
#define WS_DECODE_DEBUG 0
|
||||
|
||||
#if WS_DECODE_DEBUG == 1
|
||||
#define ws_dbg(fmt, ...) rfbLog((fmt), ##__VA_ARGS)
|
||||
#else
|
||||
#define ws_dbg(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
static inline int
|
||||
isControlFrame(ws_ctx_t *wsctx)
|
||||
{
|
||||
return 0 != (wsctx->header.opcode & 0x08);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
hybiRemaining(ws_ctx_t *wsctx)
|
||||
{
|
||||
return wsctx->header.payloadLen - wsctx->nReadPayload;
|
||||
}
|
||||
|
||||
static void
|
||||
hybiDecodeCleanupBasics(ws_ctx_t *wsctx)
|
||||
{
|
||||
/* keep opcode, cleanup rest */
|
||||
wsctx->header.opcode = WS_OPCODE_INVALID;
|
||||
wsctx->header.payloadLen = 0;
|
||||
wsctx->header.mask.u = 0;
|
||||
wsctx->header.headerLen = 0;
|
||||
wsctx->header.data = NULL;
|
||||
wsctx->header.nRead = 0;
|
||||
wsctx->nReadPayload = 0;
|
||||
wsctx->carrylen = 0;
|
||||
wsctx->readPos = (unsigned char *)wsctx->codeBufDecode;
|
||||
wsctx->readlen = 0;
|
||||
wsctx->hybiDecodeState = WS_HYBI_STATE_HEADER_PENDING;
|
||||
wsctx->writePos = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
hybiDecodeCleanupForContinuation(ws_ctx_t *wsctx)
|
||||
{
|
||||
hybiDecodeCleanupBasics(wsctx);
|
||||
ws_dbg("clean up frame, but expect continuation with opcode %d\n", wsctx->continuation_opcode);
|
||||
}
|
||||
|
||||
void
|
||||
hybiDecodeCleanupComplete(ws_ctx_t *wsctx)
|
||||
{
|
||||
hybiDecodeCleanupBasics(wsctx);
|
||||
wsctx->continuation_opcode = WS_OPCODE_INVALID;
|
||||
ws_dbg("cleaned up wsctx completely\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return payload data that has been decoded/unmasked from
|
||||
* a websocket frame.
|
||||
*
|
||||
* @param[out] dst destination buffer
|
||||
* @param[in] len bytes to copy to destination buffer
|
||||
* @param[in,out] wsctx internal state of decoding procedure
|
||||
* @param[out] number of bytes actually written to dst buffer
|
||||
* @return next hybi decoding state
|
||||
*/
|
||||
static int
|
||||
hybiReturnData(char *dst, int len, ws_ctx_t *wsctx, int *nWritten)
|
||||
{
|
||||
int nextState = WS_HYBI_STATE_ERR;
|
||||
|
||||
/* if we have something already decoded copy and return */
|
||||
if (wsctx->readlen > 0) {
|
||||
/* simply return what we have */
|
||||
if (wsctx->readlen > len) {
|
||||
ws_dbg("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", len, wsctx->readPos, wsctx->readlen);
|
||||
memcpy(dst, wsctx->readPos, len);
|
||||
*nWritten = len;
|
||||
wsctx->readlen -= len;
|
||||
wsctx->readPos += len;
|
||||
nextState = WS_HYBI_STATE_DATA_AVAILABLE;
|
||||
} else {
|
||||
ws_dbg("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", wsctx->readlen, wsctx->readPos, wsctx->readlen);
|
||||
memcpy(dst, wsctx->readPos, wsctx->readlen);
|
||||
*nWritten = wsctx->readlen;
|
||||
wsctx->readlen = 0;
|
||||
wsctx->readPos = NULL;
|
||||
if (hybiRemaining(wsctx) == 0) {
|
||||
nextState = WS_HYBI_STATE_FRAME_COMPLETE;
|
||||
} else {
|
||||
nextState = WS_HYBI_STATE_DATA_NEEDED;
|
||||
}
|
||||
}
|
||||
ws_dbg("after copy: readPos=%p, readLen=%d\n", wsctx->readPos, wsctx->readlen);
|
||||
} else {
|
||||
/* it may happen that we read some bytes but could not decode them,
|
||||
* in that case, set errno to EAGAIN and return -1 */
|
||||
nextState = wsctx->hybiDecodeState;
|
||||
errno = EAGAIN;
|
||||
*nWritten = -1;
|
||||
}
|
||||
return nextState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an RFC 6455 websocket frame (IETF hybi working group).
|
||||
*
|
||||
* Internal state is updated according to bytes received and the
|
||||
* decoding of header information.
|
||||
*
|
||||
* @param[in] cl client ptr with ptr to raw socket and ws_ctx_t ptr
|
||||
* @param[out] sockRet emulated recv return value
|
||||
* @param[out] nPayload number of payload bytes already read
|
||||
* @return next hybi decoding state; WS_HYBI_STATE_HEADER_PENDING indicates
|
||||
* that the header was not received completely.
|
||||
*/
|
||||
static int
|
||||
hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload)
|
||||
{
|
||||
int ret;
|
||||
char *headerDst = wsctx->codeBufDecode + wsctx->header.nRead;
|
||||
int n = ((uint64_t)WS_HYBI_HEADER_LEN_SHORT) - wsctx->header.nRead;
|
||||
|
||||
|
||||
ws_dbg("header_read to %p with len=%d\n", headerDst, n);
|
||||
ret = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, headerDst, n);
|
||||
ws_dbg("read %d bytes from socket\n", ret);
|
||||
if (ret <= 0) {
|
||||
if (-1 == ret) {
|
||||
/* save errno because rfbErr() will tamper it */
|
||||
int olderrno = errno;
|
||||
rfbErr("%s: read; %s\n", __func__, strerror(errno));
|
||||
errno = olderrno;
|
||||
goto err_cleanup_state;
|
||||
} else {
|
||||
*sockRet = 0;
|
||||
goto err_cleanup_state_sock_closed;
|
||||
}
|
||||
}
|
||||
|
||||
wsctx->header.nRead += ret;
|
||||
if (wsctx->header.nRead < 2) {
|
||||
/* cannot decode header with less than two bytes */
|
||||
goto ret_header_pending;
|
||||
}
|
||||
|
||||
/* first two header bytes received; interpret header data and get rest */
|
||||
wsctx->header.data = (ws_header_t *)wsctx->codeBufDecode;
|
||||
|
||||
wsctx->header.opcode = wsctx->header.data->b0 & 0x0f;
|
||||
wsctx->header.fin = (wsctx->header.data->b0 & 0x80) >> 7;
|
||||
if (isControlFrame(wsctx)) {
|
||||
ws_dbg("is control frame\n");
|
||||
/* is a control frame, leave remembered continuation opcode unchanged;
|
||||
* just check if there is a wrong fragmentation */
|
||||
if (wsctx->header.fin == 0) {
|
||||
|
||||
/* we only accept text/binary continuation frames; RFC6455:
|
||||
* Control frames (see Section 5.5) MAY be injected in the middle of
|
||||
* a fragmented message. Control frames themselves MUST NOT be
|
||||
* fragmented. */
|
||||
rfbErr("control frame with FIN bit cleared received, aborting\n");
|
||||
errno = EPROTO;
|
||||
goto err_cleanup_state;
|
||||
}
|
||||
} else {
|
||||
ws_dbg("not a control frame\n");
|
||||
/* not a control frame, check for continuation opcode */
|
||||
if (wsctx->header.opcode == WS_OPCODE_CONTINUATION) {
|
||||
ws_dbg("cont_frame\n");
|
||||
/* do we have state (i.e., opcode) for continuation frame? */
|
||||
if (wsctx->continuation_opcode == WS_OPCODE_INVALID) {
|
||||
rfbErr("no continuation state\n");
|
||||
errno = EPROTO;
|
||||
goto err_cleanup_state;
|
||||
}
|
||||
|
||||
/* otherwise, set opcode = continuation_opcode */
|
||||
wsctx->header.opcode = wsctx->continuation_opcode;
|
||||
ws_dbg("set opcode to continuation_opcode: %d\n", wsctx->header.opcode);
|
||||
} else {
|
||||
if (wsctx->header.fin == 0) {
|
||||
wsctx->continuation_opcode = wsctx->header.opcode;
|
||||
} else {
|
||||
wsctx->continuation_opcode = WS_OPCODE_INVALID;
|
||||
}
|
||||
ws_dbg("set continuation_opcode to %d\n", wsctx->continuation_opcode);
|
||||
}
|
||||
}
|
||||
|
||||
wsctx->header.payloadLen = (uint64_t)(wsctx->header.data->b1 & 0x7f);
|
||||
ws_dbg("first header bytes received; opcode=%d lenbyte=%d fin=%d\n", wsctx->header.opcode, wsctx->header.payloadLen, wsctx->header.fin);
|
||||
|
||||
/*
|
||||
* 4.3. Client-to-Server Masking
|
||||
*
|
||||
* The client MUST mask all frames sent to the server. A server MUST
|
||||
* close the connection upon receiving a frame with the MASK bit set to 0.
|
||||
**/
|
||||
if (!(wsctx->header.data->b1 & 0x80)) {
|
||||
rfbErr("%s: got frame without mask; ret=%d\n", __func__, ret);
|
||||
errno = EPROTO;
|
||||
goto err_cleanup_state;
|
||||
}
|
||||
|
||||
/* Read now the rest of the frame header, if it is longer as the minimum */
|
||||
if ((wsctx->header.payloadLen == 126) || (wsctx->header.payloadLen == 127)) {
|
||||
headerDst = wsctx->codeBufDecode + wsctx->header.nRead;
|
||||
if (wsctx->header.payloadLen == 126) {
|
||||
n = ((uint64_t)WS_HYBI_HEADER_LEN_EXTENDED) - wsctx->header.nRead;
|
||||
} else if (wsctx->header.payloadLen == 127) {
|
||||
n = ((uint64_t)WS_HYBI_HEADER_LEN_LONG) - wsctx->header.nRead;
|
||||
}
|
||||
ret = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, headerDst, n);
|
||||
if (ret <= 0) {
|
||||
if (-1 == ret) {
|
||||
/* save errno because rfbErr() will tamper it */
|
||||
int olderrno = errno;
|
||||
rfbErr("%s: read; %s\n", __func__, strerror(errno));
|
||||
errno = olderrno;
|
||||
goto err_cleanup_state;
|
||||
} else {
|
||||
*sockRet = 0;
|
||||
goto err_cleanup_state_sock_closed;
|
||||
}
|
||||
}
|
||||
|
||||
/* if more header data was read, account for it */
|
||||
wsctx->header.nRead += ret;
|
||||
}
|
||||
|
||||
if (wsctx->header.payloadLen < 126 && wsctx->header.nRead >= 6) {
|
||||
wsctx->header.headerLen = WS_HYBI_HEADER_LEN_SHORT;
|
||||
wsctx->header.mask = wsctx->header.data->u.m;
|
||||
} else if (wsctx->header.payloadLen == 126 && 8 <= wsctx->header.nRead) {
|
||||
wsctx->header.headerLen = WS_HYBI_HEADER_LEN_EXTENDED;
|
||||
wsctx->header.payloadLen = WS_NTOH16(wsctx->header.data->u.s16.l16);
|
||||
wsctx->header.mask = wsctx->header.data->u.s16.m16;
|
||||
} else if (wsctx->header.payloadLen == 127 && 14 <= wsctx->header.nRead) {
|
||||
wsctx->header.headerLen = WS_HYBI_HEADER_LEN_LONG;
|
||||
wsctx->header.payloadLen = WS_NTOH64(wsctx->header.data->u.s64.l64);
|
||||
wsctx->header.mask = wsctx->header.data->u.s64.m64;
|
||||
} else {
|
||||
/* Incomplete frame header, try again */
|
||||
rfbErr("%s: incomplete frame header; ret=%d\n", __func__, ret);
|
||||
goto ret_header_pending;
|
||||
}
|
||||
|
||||
int i;
|
||||
ws_dbg("Header:\n");
|
||||
for (i=0; i <10; i++) {
|
||||
ws_dbg("0x%02X\n", (unsigned char)wsctx->codeBufDecode[i]);
|
||||
}
|
||||
ws_dbg("\n");
|
||||
|
||||
/* while RFC 6455 mandates that lengths MUST be encoded with the minimum
|
||||
* number of bytes, it does not specify for the server how to react on
|
||||
* 'wrongly' encoded frames --- this implementation rejects them*/
|
||||
if ((wsctx->header.headerLen > WS_HYBI_HEADER_LEN_SHORT
|
||||
&& wsctx->header.payloadLen < (uint64_t)126)
|
||||
|| (wsctx->header.headerLen > WS_HYBI_HEADER_LEN_EXTENDED
|
||||
&& wsctx->header.payloadLen < (uint64_t)65536)) {
|
||||
rfbErr("%s: invalid length field; headerLen=%d payloadLen=%llu\n", __func__, wsctx->header.headerLen, wsctx->header.payloadLen);
|
||||
errno = EPROTO;
|
||||
goto err_cleanup_state;
|
||||
}
|
||||
|
||||
/* update write position for next bytes */
|
||||
wsctx->writePos = wsctx->codeBufDecode + wsctx->header.nRead;
|
||||
|
||||
/* set payload pointer just after header */
|
||||
wsctx->readPos = (unsigned char *)(wsctx->codeBufDecode + wsctx->header.headerLen);
|
||||
|
||||
*nPayload = wsctx->header.nRead - wsctx->header.headerLen;
|
||||
wsctx->nReadPayload = *nPayload;
|
||||
|
||||
ws_dbg("header complete: state=%d headerlen=%d payloadlen=%llu writeTo=%p nPayload=%d\n", wsctx->hybiDecodeState, wsctx->header.headerLen, wsctx->header.payloadLen, wsctx->writePos, *nPayload);
|
||||
|
||||
return WS_HYBI_STATE_DATA_NEEDED;
|
||||
|
||||
ret_header_pending:
|
||||
errno = EAGAIN;
|
||||
*sockRet = -1;
|
||||
return WS_HYBI_STATE_HEADER_PENDING;
|
||||
|
||||
err_cleanup_state:
|
||||
*sockRet = -1;
|
||||
err_cleanup_state_sock_closed:
|
||||
hybiDecodeCleanupComplete(wsctx);
|
||||
return WS_HYBI_STATE_ERR;
|
||||
}
|
||||
|
||||
static int
|
||||
hybiWsFrameComplete(ws_ctx_t *wsctx)
|
||||
{
|
||||
return wsctx != NULL && hybiRemaining(wsctx) == 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
hybiPayloadStart(ws_ctx_t *wsctx)
|
||||
{
|
||||
return wsctx->codeBufDecode + wsctx->header.headerLen;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the remaining payload bytes from associated raw socket.
|
||||
*
|
||||
* - try to read remaining bytes from socket
|
||||
* - unmask all multiples of 4
|
||||
* - if frame incomplete but some bytes are left, these are copied to
|
||||
* the carry buffer
|
||||
* - if opcode is TEXT: Base64-decode all unmasked received bytes
|
||||
* - set state for reading decoded data
|
||||
* - reset write position to begin of buffer (+ header)
|
||||
* --> before we retrieve more data we let the caller clear all bytes
|
||||
* from the reception buffer
|
||||
* - execute return data routine
|
||||
*
|
||||
* Sets errno corresponding to what it gets from the underlying
|
||||
* socket or EPROTO if some invalid data is in the received frame
|
||||
* or ECONNRESET if a close reason + message is received. EIO is used if
|
||||
* an internal sanity check fails.
|
||||
*
|
||||
* @param[in] cl client ptr with raw socket reference
|
||||
* @param[out] dst destination buffer
|
||||
* @param[in] len size of destination buffer
|
||||
* @param[out] sockRet emulated recv return value
|
||||
* @param[in] nInBuf number of undecoded bytes before writePos from header read
|
||||
* @return next hybi decode state
|
||||
*/
|
||||
static int
|
||||
hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf)
|
||||
{
|
||||
int n;
|
||||
int i;
|
||||
int toReturn; /* number of data bytes to return */
|
||||
int toDecode; /* number of bytes to decode starting at wsctx->writePos */
|
||||
int bufsize;
|
||||
int nextRead;
|
||||
unsigned char *data;
|
||||
|
||||
/* if data was carried over, copy to start of buffer */
|
||||
memcpy(wsctx->writePos, wsctx->carryBuf, wsctx->carrylen);
|
||||
wsctx->writePos += wsctx->carrylen;
|
||||
|
||||
/* -1 accounts for potential '\0' terminator for base64 decoding */
|
||||
bufsize = wsctx->codeBufDecode + ARRAYSIZE(wsctx->codeBufDecode) - wsctx->writePos - 1;
|
||||
ws_dbg("bufsize=%d\n", bufsize);
|
||||
if (hybiRemaining(wsctx) > bufsize) {
|
||||
nextRead = bufsize;
|
||||
} else {
|
||||
nextRead = hybiRemaining(wsctx);
|
||||
}
|
||||
|
||||
ws_dbg("calling read with buf=%p and len=%d (decodebuf=%p headerLen=%d)\n", wsctx->writePos, nextRead, wsctx->codeBufDecode, wsctx->header.headerLen);
|
||||
|
||||
if (nextRead > 0) {
|
||||
/* decode more data */
|
||||
if (-1 == (n = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, wsctx->writePos, nextRead))) {
|
||||
int olderrno = errno;
|
||||
rfbErr("%s: read; %s", __func__, strerror(errno));
|
||||
errno = olderrno;
|
||||
*sockRet = -1;
|
||||
return WS_HYBI_STATE_ERR;
|
||||
} else if (n == 0) {
|
||||
*sockRet = 0;
|
||||
return WS_HYBI_STATE_ERR;
|
||||
} else {
|
||||
ws_dbg("read %d bytes from socket; nRead=%d\n", n, wsctx->nReadPayload);
|
||||
}
|
||||
} else {
|
||||
n = 0;
|
||||
}
|
||||
|
||||
wsctx->nReadPayload += n;
|
||||
wsctx->writePos += n;
|
||||
|
||||
if (hybiRemaining(wsctx) == 0) {
|
||||
wsctx->hybiDecodeState = WS_HYBI_STATE_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
/* number of not yet unmasked payload bytes: what we read here + what was
|
||||
* carried over + what was read with the header */
|
||||
toDecode = n + wsctx->carrylen + nInBuf;
|
||||
ws_dbg("toDecode=%d from n=%d carrylen=%d headerLen=%d\n", toDecode, n, wsctx->carrylen, wsctx->header.headerLen);
|
||||
if (toDecode < 0) {
|
||||
rfbErr("%s: internal error; negative number of bytes to decode: %d", __func__, toDecode);
|
||||
errno=EIO;
|
||||
*sockRet = -1;
|
||||
return WS_HYBI_STATE_ERR;
|
||||
}
|
||||
|
||||
/* for a possible base64 decoding, we decode multiples of 4 bytes until
|
||||
* the whole frame is received and carry over any remaining bytes in the carry buf*/
|
||||
data = (unsigned char *)(wsctx->writePos - toDecode);
|
||||
|
||||
for (i = 0; i < (toDecode >> 2); i++) {
|
||||
uint32_t tmp;
|
||||
memcpy(&tmp, data + i * sizeof(tmp), sizeof(tmp));
|
||||
tmp ^= wsctx->header.mask.u;
|
||||
memcpy(data + i * sizeof(tmp), &tmp, sizeof(tmp));
|
||||
}
|
||||
ws_dbg("mask decoding; i=%d toDecode=%d\n", i, toDecode);
|
||||
|
||||
if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) {
|
||||
/* process the remaining bytes (if any) */
|
||||
for (i*=4; i < toDecode; i++) {
|
||||
data[i] ^= wsctx->header.mask.c[i % 4];
|
||||
}
|
||||
|
||||
/* all data is here, no carrying */
|
||||
wsctx->carrylen = 0;
|
||||
} else {
|
||||
/* carry over remaining, non-multiple-of-four bytes */
|
||||
wsctx->carrylen = toDecode - (i * 4);
|
||||
if (wsctx->carrylen < 0 || wsctx->carrylen > ARRAYSIZE(wsctx->carryBuf)) {
|
||||
rfbErr("%s: internal error, invalid carry over size: carrylen=%d, toDecode=%d, i=%d", __func__, wsctx->carrylen, toDecode, i);
|
||||
*sockRet = -1;
|
||||
errno = EIO;
|
||||
return WS_HYBI_STATE_ERR;
|
||||
}
|
||||
ws_dbg("carrying over %d bytes from %p to %p\n", wsctx->carrylen, wsctx->writePos + (i * 4), wsctx->carryBuf);
|
||||
memcpy(wsctx->carryBuf, data + (i * 4), wsctx->carrylen);
|
||||
wsctx->writePos -= wsctx->carrylen;
|
||||
}
|
||||
|
||||
toReturn = toDecode - wsctx->carrylen;
|
||||
|
||||
switch (wsctx->header.opcode) {
|
||||
case WS_OPCODE_CLOSE:
|
||||
/* this data is not returned as payload data */
|
||||
if (hybiWsFrameComplete(wsctx)) {
|
||||
*(wsctx->writePos) = '\0';
|
||||
ws_dbg("got close cmd %d, reason %d: %s\n", (int)(wsctx->writePos - hybiPayloadStart(wsctx)), WS_NTOH16(((uint16_t *)hybiPayloadStart(wsctx))[0]), &hybiPayloadStart(wsctx)[2]);
|
||||
errno = ECONNRESET;
|
||||
*sockRet = -1;
|
||||
return WS_HYBI_STATE_FRAME_COMPLETE;
|
||||
} else {
|
||||
ws_dbg("got close cmd; waiting for %d more bytes to arrive\n", hybiRemaining(wsctx));
|
||||
*sockRet = -1;
|
||||
errno = EAGAIN;
|
||||
return WS_HYBI_STATE_CLOSE_REASON_PENDING;
|
||||
}
|
||||
break;
|
||||
case WS_OPCODE_TEXT_FRAME:
|
||||
data[toReturn] = '\0';
|
||||
ws_dbg("Initiate Base64 decoding in %p with max size %d and '\\0' at %p\n", data, bufsize, data + toReturn);
|
||||
if (-1 == (wsctx->readlen = rfbBase64PtoN((char *)data, data, bufsize))) {
|
||||
rfbErr("%s: Base64 decode error; %s\n", __func__, strerror(errno));
|
||||
}
|
||||
wsctx->writePos = hybiPayloadStart(wsctx);
|
||||
break;
|
||||
case WS_OPCODE_BINARY_FRAME:
|
||||
wsctx->readlen = toReturn;
|
||||
wsctx->writePos = hybiPayloadStart(wsctx);
|
||||
ws_dbg("set readlen=%d writePos=%p\n", wsctx->readlen, wsctx->writePos);
|
||||
break;
|
||||
default:
|
||||
rfbErr("%s: unhandled opcode %d, b0: %02x, b1: %02x\n", __func__, (int)wsctx->header.opcode, wsctx->header.data->b0, wsctx->header.data->b1);
|
||||
}
|
||||
wsctx->readPos = data;
|
||||
|
||||
return hybiReturnData(dst, len, wsctx, sockRet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read function for websocket-socket emulation.
|
||||
*
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-------+-+-------------+-------------------------------+
|
||||
* |F|R|R|R| opcode|M| Payload len | Extended payload length |
|
||||
* |I|S|S|S| (4) |A| (7) | (16/64) |
|
||||
* |N|V|V|V| |S| | (if payload len==126/127) |
|
||||
* | |1|2|3| |K| | |
|
||||
* +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
||||
* | Extended payload length continued, if payload len == 127 |
|
||||
* + - - - - - - - - - - - - - - - +-------------------------------+
|
||||
* | |Masking-key, if MASK set to 1 |
|
||||
* +-------------------------------+-------------------------------+
|
||||
* | Masking-key (continued) | Payload Data |
|
||||
* +-------------------------------- - - - - - - - - - - - - - - - +
|
||||
* : Payload Data continued ... :
|
||||
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|
||||
* | Payload Data continued ... |
|
||||
* +---------------------------------------------------------------+
|
||||
*
|
||||
* Using the decode buffer, this function:
|
||||
* - reads the complete header from the underlying socket
|
||||
* - reads any remaining data bytes
|
||||
* - unmasks the payload data using the provided mask
|
||||
* - decodes Base64 encoded text data
|
||||
* - copies len bytes of decoded payload data into dst
|
||||
*
|
||||
* Emulates a read call on a socket.
|
||||
*/
|
||||
int
|
||||
webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len)
|
||||
{
|
||||
int result = -1;
|
||||
/* int fin; */ /* not used atm */
|
||||
|
||||
ws_dbg("%s_enter: len=%d; "
|
||||
"CTX: readlen=%d readPos=%p "
|
||||
"writeTo=%p "
|
||||
"state=%d payloadtoRead=%d payloadRemaining=%llu "
|
||||
" nReadPayload=%d carrylen=%d carryBuf=%p\n",
|
||||
__func__, len,
|
||||
wsctx->readlen, wsctx->readPos,
|
||||
wsctx->writePos,
|
||||
wsctx->hybiDecodeState, wsctx->header.payloadLen, hybiRemaining(wsctx),
|
||||
wsctx->nReadPayload, wsctx->carrylen, wsctx->carryBuf);
|
||||
|
||||
switch (wsctx->hybiDecodeState){
|
||||
int nInBuf;
|
||||
case WS_HYBI_STATE_HEADER_PENDING:
|
||||
wsctx->hybiDecodeState = hybiReadHeader(wsctx, &result, &nInBuf);
|
||||
if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) {
|
||||
goto spor;
|
||||
}
|
||||
if (wsctx->hybiDecodeState != WS_HYBI_STATE_HEADER_PENDING) {
|
||||
|
||||
/* when header is complete, try to read some more data */
|
||||
wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result, nInBuf);
|
||||
}
|
||||
break;
|
||||
case WS_HYBI_STATE_DATA_AVAILABLE:
|
||||
wsctx->hybiDecodeState = hybiReturnData(dst, len, wsctx, &result);
|
||||
break;
|
||||
case WS_HYBI_STATE_DATA_NEEDED:
|
||||
case WS_HYBI_STATE_CLOSE_REASON_PENDING:
|
||||
wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result, 0);
|
||||
break;
|
||||
default:
|
||||
/* invalid state */
|
||||
rfbErr("%s: called with invalid state %d\n", wsctx->hybiDecodeState);
|
||||
result = -1;
|
||||
errno = EIO;
|
||||
wsctx->hybiDecodeState = WS_HYBI_STATE_ERR;
|
||||
}
|
||||
|
||||
/* single point of return, if someone has questions :-) */
|
||||
spor:
|
||||
if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) {
|
||||
ws_dbg("frame received successfully, cleaning up: read=%d hlen=%d plen=%d\n", wsctx->header.nRead, wsctx->header.headerLen, wsctx->header.payloadLen);
|
||||
if (wsctx->header.fin && !isControlFrame(wsctx)) {
|
||||
/* frame finished, cleanup state */
|
||||
hybiDecodeCleanupComplete(wsctx);
|
||||
} else {
|
||||
/* always retain continuation opcode for unfinished data frames
|
||||
* or control frames, which may interleave with data frames */
|
||||
hybiDecodeCleanupForContinuation(wsctx);
|
||||
}
|
||||
} else if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) {
|
||||
hybiDecodeCleanupComplete(wsctx);
|
||||
}
|
||||
|
||||
ws_dbg("%s_exit: len=%d; "
|
||||
"CTX: readlen=%d readPos=%p "
|
||||
"writePos=%p "
|
||||
"state=%d payloadtoRead=%d payloadRemaining=%d "
|
||||
"nRead=%d carrylen=%d carryBuf=%p "
|
||||
"result=%d "
|
||||
"errno=%d\n",
|
||||
__func__, len,
|
||||
wsctx->readlen, wsctx->readPos,
|
||||
wsctx->writePos,
|
||||
wsctx->hybiDecodeState, wsctx->header.payloadLen, hybiRemaining(wsctx),
|
||||
wsctx->nReadPayload, wsctx->carrylen, wsctx->carryBuf,
|
||||
result,
|
||||
errno);
|
||||
return result;
|
||||
}
|
||||
151
android/extern/libvncserver/src/libvncserver/ws_decode.h
vendored
Normal file
151
android/extern/libvncserver/src/libvncserver/ws_decode.h
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
#ifndef _WS_DECODE_H_
|
||||
#define _WS_DECODE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define WS_NTOH64(n) OSSwapBigToHostInt64(n)
|
||||
#define WS_NTOH32(n) OSSwapBigToHostInt32(n)
|
||||
#define WS_NTOH16(n) OSSwapBigToHostInt16(n)
|
||||
#define WS_HTON64(n) OSSwapHostToBigInt64(n)
|
||||
#define WS_HTON16(n) OSSwapHostToBigInt16(n)
|
||||
|
||||
#else
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_ENDIAN_H
|
||||
#include <endian.h>
|
||||
#elif LIBVNCSERVER_HAVE_SYS_ENDIAN_H
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#define WS_NTOH64(n) htobe64(n)
|
||||
#define WS_NTOH32(n) htobe32(n)
|
||||
#define WS_NTOH16(n) htobe16(n)
|
||||
#define WS_HTON64(n) htobe64(n)
|
||||
#define WS_HTON16(n) htobe16(n)
|
||||
|
||||
#endif
|
||||
|
||||
#define B64LEN(__x) (((__x + 2) / 3) * 12 / 3)
|
||||
#define WSHLENMAX 14LL /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */
|
||||
#define WS_HYBI_MASK_LEN 4
|
||||
|
||||
#define ARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))) / (size_t)(!(sizeof(a) % sizeof((a[0])))))
|
||||
|
||||
struct ws_ctx_s;
|
||||
typedef struct ws_ctx_s ws_ctx_t;
|
||||
|
||||
typedef int (*wsEncodeFunc)(rfbClientPtr cl, const char *src, int len, char **dst);
|
||||
typedef int (*wsDecodeFunc)(ws_ctx_t *wsctx, char *dst, int len);
|
||||
|
||||
typedef int (*wsReadFunc)(void *ctx, char *dst, size_t len);
|
||||
|
||||
typedef struct ctxInfo_s{
|
||||
void *ctxPtr;
|
||||
wsReadFunc readFunc;
|
||||
} ctxInfo_t;
|
||||
|
||||
enum {
|
||||
/* header not yet received completely */
|
||||
WS_HYBI_STATE_HEADER_PENDING,
|
||||
/* data available */
|
||||
WS_HYBI_STATE_DATA_AVAILABLE,
|
||||
WS_HYBI_STATE_DATA_NEEDED,
|
||||
/* received a complete frame */
|
||||
WS_HYBI_STATE_FRAME_COMPLETE,
|
||||
/* received part of a 'close' frame */
|
||||
WS_HYBI_STATE_CLOSE_REASON_PENDING,
|
||||
/* */
|
||||
WS_HYBI_STATE_ERR
|
||||
};
|
||||
|
||||
typedef union ws_mask_s {
|
||||
char c[4];
|
||||
uint32_t u;
|
||||
} ws_mask_t;
|
||||
|
||||
/* XXX: The union and the structs do not need to be named.
|
||||
* We are working around a bug present in GCC < 4.6 which prevented
|
||||
* it from recognizing anonymous structs and unions.
|
||||
* See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=4784
|
||||
*/
|
||||
typedef struct
|
||||
#if __GNUC__
|
||||
__attribute__ ((__packed__))
|
||||
#endif
|
||||
ws_header_s {
|
||||
unsigned char b0;
|
||||
unsigned char b1;
|
||||
union {
|
||||
struct
|
||||
#if __GNUC__
|
||||
__attribute__ ((__packed__))
|
||||
#endif
|
||||
{
|
||||
uint16_t l16;
|
||||
ws_mask_t m16;
|
||||
} s16;
|
||||
struct
|
||||
#if __GNUC__
|
||||
__attribute__ ((__packed__))
|
||||
#endif
|
||||
{
|
||||
uint64_t l64;
|
||||
ws_mask_t m64;
|
||||
} s64;
|
||||
ws_mask_t m;
|
||||
} u;
|
||||
} ws_header_t;
|
||||
|
||||
typedef struct ws_header_data_s {
|
||||
ws_header_t *data;
|
||||
/** bytes read */
|
||||
int nRead;
|
||||
/** mask value */
|
||||
ws_mask_t mask;
|
||||
/** length of frame header including payload len, but without mask */
|
||||
int headerLen;
|
||||
/** length of the payload data */
|
||||
uint64_t payloadLen;
|
||||
/** opcode */
|
||||
unsigned char opcode;
|
||||
/** fin bit */
|
||||
unsigned char fin;
|
||||
} ws_header_data_t;
|
||||
|
||||
struct ws_ctx_s {
|
||||
char codeBufDecode[2048 + WSHLENMAX]; /* base64 + maximum frame header length */
|
||||
char codeBufEncode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */
|
||||
char *writePos;
|
||||
unsigned char *readPos;
|
||||
int readlen;
|
||||
int hybiDecodeState;
|
||||
char carryBuf[3]; /* For base64 carry-over */
|
||||
int carrylen;
|
||||
int base64;
|
||||
ws_header_data_t header;
|
||||
uint64_t nReadPayload;
|
||||
unsigned char continuation_opcode;
|
||||
wsEncodeFunc encode;
|
||||
wsDecodeFunc decode;
|
||||
ctxInfo_t ctxInfo;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WS_OPCODE_CONTINUATION = 0x00,
|
||||
WS_OPCODE_TEXT_FRAME = 0x01,
|
||||
WS_OPCODE_BINARY_FRAME = 0x02,
|
||||
WS_OPCODE_CLOSE = 0x08,
|
||||
WS_OPCODE_PING = 0x09,
|
||||
WS_OPCODE_PONG = 0x0A,
|
||||
WS_OPCODE_INVALID = 0xFF
|
||||
};
|
||||
|
||||
int webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len);
|
||||
|
||||
void hybiDecodeCleanupComplete(ws_ctx_t *wsctx);
|
||||
#endif
|
||||
312
android/extern/libvncserver/src/libvncserver/zlib.c
vendored
Normal file
312
android/extern/libvncserver/src/libvncserver/zlib.c
vendored
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* zlib.c
|
||||
*
|
||||
* Routines to implement zlib based encoding (deflate).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*
|
||||
* For the latest source code, please check:
|
||||
*
|
||||
* http://www.developVNC.org/
|
||||
*
|
||||
* or send email to feedback@developvnc.org.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
/*
|
||||
* cl->beforeEncBuf contains pixel data in the client's format.
|
||||
* cl->afterEncBuf contains the zlib (deflated) encoding version.
|
||||
* If the zlib compressed/encoded version is
|
||||
* larger than the raw data or if it exceeds cl->afterEncBufSize then
|
||||
* raw encoding is used instead.
|
||||
*/
|
||||
|
||||
/*
|
||||
* rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
|
||||
* rectangle encoding.
|
||||
*/
|
||||
|
||||
static rfbBool
|
||||
rfbSendOneRectEncodingZlib(rfbClientPtr cl,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
rfbZlibHeader hdr;
|
||||
int deflateResult;
|
||||
int previousOut;
|
||||
int i;
|
||||
char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
|
||||
+ (x * (cl->scaledScreen->bitsPerPixel / 8)));
|
||||
|
||||
int maxRawSize;
|
||||
int maxCompSize;
|
||||
|
||||
maxRawSize = (cl->scaledScreen->width * cl->scaledScreen->height
|
||||
* (cl->format.bitsPerPixel / 8));
|
||||
|
||||
if (!cl->beforeEncBuf || cl->beforeEncBufSize < maxRawSize) {
|
||||
if (cl->beforeEncBuf == NULL)
|
||||
cl->beforeEncBuf = (char *)malloc(maxRawSize);
|
||||
else {
|
||||
char *reallocedBeforeEncBuf = (char *)realloc(cl->beforeEncBuf, maxRawSize);
|
||||
if (!reallocedBeforeEncBuf) return FALSE;
|
||||
cl->beforeEncBuf = reallocedBeforeEncBuf;
|
||||
}
|
||||
if(cl->beforeEncBuf)
|
||||
cl->beforeEncBufSize = maxRawSize;
|
||||
}
|
||||
|
||||
/* zlib compression is not useful for very small data sets.
|
||||
* So, we just send these raw without any compression.
|
||||
*/
|
||||
if (( w * h * (cl->scaledScreen->bitsPerPixel / 8)) <
|
||||
VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) {
|
||||
|
||||
int result;
|
||||
|
||||
/* The translation function (used also by the in raw encoding)
|
||||
* requires 4/2/1 byte alignment in the output buffer (which is
|
||||
* updateBuf for the raw encoding) based on the bitsPerPixel of
|
||||
* the viewer/client. This prevents SIGBUS errors on some
|
||||
* architectures like SPARC, PARISC...
|
||||
*/
|
||||
if (( cl->format.bitsPerPixel > 8 ) &&
|
||||
( cl->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = rfbSendRectEncodingRaw(cl, x, y, w, h);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* zlib requires output buffer to be slightly larger than the input
|
||||
* buffer, in the worst case.
|
||||
*/
|
||||
maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12;
|
||||
|
||||
if (!cl->afterEncBuf || cl->afterEncBufSize < maxCompSize) {
|
||||
if (cl->afterEncBuf == NULL)
|
||||
cl->afterEncBuf = (char *)malloc(maxCompSize);
|
||||
else {
|
||||
char *reallocedAfterEncBuf = (char *)realloc(cl->afterEncBuf, maxCompSize);
|
||||
if (!reallocedAfterEncBuf) return FALSE;
|
||||
cl->afterEncBuf = reallocedAfterEncBuf;
|
||||
}
|
||||
if(cl->afterEncBuf)
|
||||
cl->afterEncBufSize = maxCompSize;
|
||||
}
|
||||
|
||||
if (!cl->beforeEncBuf || !cl->afterEncBuf)
|
||||
{
|
||||
rfbLog("rfbSendOneRectEncodingZlib: failed to allocate memory\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert pixel data to client format.
|
||||
*/
|
||||
(*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
|
||||
&cl->format, fbptr, cl->beforeEncBuf,
|
||||
cl->scaledScreen->paddedWidthInBytes, w, h);
|
||||
|
||||
cl->compStream.next_in = ( Bytef * )cl->beforeEncBuf;
|
||||
cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8);
|
||||
cl->compStream.next_out = ( Bytef * )cl->afterEncBuf;
|
||||
cl->compStream.avail_out = maxCompSize;
|
||||
cl->compStream.data_type = Z_BINARY;
|
||||
|
||||
/* Initialize the deflation state. */
|
||||
if ( cl->compStreamInited == FALSE ) {
|
||||
|
||||
cl->compStream.total_in = 0;
|
||||
cl->compStream.total_out = 0;
|
||||
cl->compStream.zalloc = Z_NULL;
|
||||
cl->compStream.zfree = Z_NULL;
|
||||
cl->compStream.opaque = Z_NULL;
|
||||
|
||||
deflateInit2( &(cl->compStream),
|
||||
cl->zlibCompressLevel,
|
||||
Z_DEFLATED,
|
||||
MAX_WBITS,
|
||||
MAX_MEM_LEVEL,
|
||||
Z_DEFAULT_STRATEGY );
|
||||
/* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */
|
||||
/* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */
|
||||
cl->compStreamInited = TRUE;
|
||||
|
||||
}
|
||||
|
||||
previousOut = cl->compStream.total_out;
|
||||
|
||||
/* Perform the compression here. */
|
||||
deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH );
|
||||
|
||||
/* Find the total size of the resulting compressed data. */
|
||||
cl->afterEncBufLen = cl->compStream.total_out - previousOut;
|
||||
|
||||
if ( deflateResult != Z_OK ) {
|
||||
rfbErr("zlib deflation error: %s\n", cl->compStream.msg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Note that it is not possible to switch zlib parameters based on
|
||||
* the results of the compression pass. The reason is
|
||||
* that we rely on the compressor and decompressor states being
|
||||
* in sync. Compressing and then discarding the results would
|
||||
* cause lose of synchronization.
|
||||
*/
|
||||
|
||||
/* Update statics */
|
||||
rfbStatRecordEncodingSent(cl, rfbEncodingZlib, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + cl->afterEncBufLen,
|
||||
+ w * (cl->format.bitsPerPixel / 8) * h);
|
||||
|
||||
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
|
||||
> UPDATE_BUF_SIZE)
|
||||
{
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rect.r.x = Swap16IfLE(x);
|
||||
rect.r.y = Swap16IfLE(y);
|
||||
rect.r.w = Swap16IfLE(w);
|
||||
rect.r.h = Swap16IfLE(h);
|
||||
rect.encoding = Swap32IfLE(rfbEncodingZlib);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
|
||||
sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
hdr.nBytes = Swap32IfLE(cl->afterEncBufLen);
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
|
||||
cl->ublen += sz_rfbZlibHeader;
|
||||
|
||||
for (i = 0; i < cl->afterEncBufLen;) {
|
||||
|
||||
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
|
||||
|
||||
if (i + bytesToCopy > cl->afterEncBufLen) {
|
||||
bytesToCopy = cl->afterEncBufLen - i;
|
||||
}
|
||||
|
||||
memcpy(&cl->updateBuf[cl->ublen], &cl->afterEncBuf[i], bytesToCopy);
|
||||
|
||||
cl->ublen += bytesToCopy;
|
||||
i += bytesToCopy;
|
||||
|
||||
if (cl->ublen == UPDATE_BUF_SIZE) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rfbSendRectEncodingZlib - send a given rectangle using one or more
|
||||
* Zlib encoding rectangles.
|
||||
*/
|
||||
|
||||
rfbBool
|
||||
rfbSendRectEncodingZlib(rfbClientPtr cl,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
int maxLines;
|
||||
int linesRemaining;
|
||||
rfbRectangle partialRect;
|
||||
|
||||
partialRect.x = x;
|
||||
partialRect.y = y;
|
||||
partialRect.w = w;
|
||||
partialRect.h = h;
|
||||
|
||||
/* Determine maximum pixel/scan lines allowed per rectangle. */
|
||||
maxLines = ( ZLIB_MAX_SIZE(w) / w );
|
||||
|
||||
/* Initialize number of scan lines left to do. */
|
||||
linesRemaining = h;
|
||||
|
||||
/* Loop until all work is done. */
|
||||
while ( linesRemaining > 0 ) {
|
||||
|
||||
int linesToComp;
|
||||
|
||||
if ( maxLines < linesRemaining )
|
||||
linesToComp = maxLines;
|
||||
else
|
||||
linesToComp = linesRemaining;
|
||||
|
||||
partialRect.h = linesToComp;
|
||||
|
||||
/* Encode (compress) and send the next rectangle. */
|
||||
if ( ! rfbSendOneRectEncodingZlib( cl,
|
||||
partialRect.x,
|
||||
partialRect.y,
|
||||
partialRect.w,
|
||||
partialRect.h )) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Technically, flushing the buffer here is not extremely
|
||||
* efficient. However, this improves the overall throughput
|
||||
* of the system over very slow networks. By flushing
|
||||
* the buffer with every maximum size zlib rectangle, we
|
||||
* improve the pipelining usage of the server CPU, network,
|
||||
* and viewer CPU components. Insuring that these components
|
||||
* are working in parallel actually improves the performance
|
||||
* seen by the user.
|
||||
* Since, zlib is most useful for slow networks, this flush
|
||||
* is appropriate for the desired behavior of the zlib encoding.
|
||||
*/
|
||||
if (( cl->ublen > 0 ) &&
|
||||
( linesToComp == maxLines )) {
|
||||
if (!rfbSendUpdateBuf(cl)) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update remaining and incremental rectangle location. */
|
||||
linesRemaining -= linesToComp;
|
||||
partialRect.y += linesToComp;
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
257
android/extern/libvncserver/src/libvncserver/zrle.c
vendored
Normal file
257
android/extern/libvncserver/src/libvncserver/zrle.c
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* zrle.c
|
||||
*
|
||||
* Routines to implement Zlib Run-length Encoding (ZRLE).
|
||||
*/
|
||||
|
||||
#include "rfb/rfb.h"
|
||||
#include "private.h"
|
||||
#include "zrleoutstream.h"
|
||||
|
||||
|
||||
#define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf) \
|
||||
{ char *fbptr = (cl->scaledScreen->frameBuffer \
|
||||
+ (cl->scaledScreen->paddedWidthInBytes * ty) \
|
||||
+ (tx * (cl->scaledScreen->bitsPerPixel / 8))); \
|
||||
\
|
||||
(*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,\
|
||||
&cl->format, fbptr, (char*)buf, \
|
||||
cl->scaledScreen->paddedWidthInBytes, tw, th); }
|
||||
|
||||
#define EXTRA_ARGS , rfbClientPtr cl
|
||||
|
||||
#define ENDIAN_LITTLE 0
|
||||
#define ENDIAN_BIG 1
|
||||
#define ENDIAN_NO 2
|
||||
#define BPP 8
|
||||
#define ZYWRLE_ENDIAN ENDIAN_NO
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef BPP
|
||||
#define BPP 15
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef BPP
|
||||
#define BPP 16
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef BPP
|
||||
#define BPP 32
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "zrleencodetemplate.c"
|
||||
#define CPIXEL 24A
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef CPIXEL
|
||||
#define CPIXEL 24B
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "zrleencodetemplate.c"
|
||||
#undef CPIXEL
|
||||
#undef BPP
|
||||
|
||||
|
||||
/*
|
||||
* zrleBeforeBuf contains pixel data in the client's format. It must be at
|
||||
* least one pixel bigger than the largest tile of pixel data, since the
|
||||
* ZRLE encoding algorithm writes to the position one past the end of the pixel
|
||||
* data.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding.
|
||||
*/
|
||||
|
||||
rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
|
||||
{
|
||||
zrleOutStream* zos;
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
rfbZRLEHeader hdr;
|
||||
int i;
|
||||
char *zrleBeforeBuf;
|
||||
|
||||
if (cl->zrleBeforeBuf == NULL) {
|
||||
cl->zrleBeforeBuf = (char *) malloc(rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4);
|
||||
}
|
||||
zrleBeforeBuf = cl->zrleBeforeBuf;
|
||||
|
||||
if (cl->preferredEncoding == rfbEncodingZYWRLE) {
|
||||
if (cl->tightQualityLevel < 0) {
|
||||
cl->zywrleLevel = 1;
|
||||
} else if (cl->tightQualityLevel < 3) {
|
||||
cl->zywrleLevel = 3;
|
||||
} else if (cl->tightQualityLevel < 6) {
|
||||
cl->zywrleLevel = 2;
|
||||
} else {
|
||||
cl->zywrleLevel = 1;
|
||||
}
|
||||
} else
|
||||
cl->zywrleLevel = 0;
|
||||
|
||||
if (!cl->zrleData)
|
||||
cl->zrleData = zrleOutStreamNew();
|
||||
zos = cl->zrleData;
|
||||
zos->in.ptr = zos->in.start;
|
||||
zos->out.ptr = zos->out.start;
|
||||
|
||||
switch (cl->format.bitsPerPixel) {
|
||||
|
||||
case 8:
|
||||
zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
if (cl->format.greenMax > 0x1F) {
|
||||
if (cl->format.bigEndian)
|
||||
zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
else
|
||||
zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
} else {
|
||||
if (cl->format.bigEndian)
|
||||
zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
else
|
||||
zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
}
|
||||
break;
|
||||
|
||||
case 32: {
|
||||
rfbBool fitsInLS3Bytes
|
||||
= ((cl->format.redMax << cl->format.redShift) < (1<<24) &&
|
||||
(cl->format.greenMax << cl->format.greenShift) < (1<<24) &&
|
||||
(cl->format.blueMax << cl->format.blueShift) < (1<<24));
|
||||
|
||||
rfbBool fitsInMS3Bytes = (cl->format.redShift > 7 &&
|
||||
cl->format.greenShift > 7 &&
|
||||
cl->format.blueShift > 7);
|
||||
|
||||
if ((fitsInLS3Bytes && !cl->format.bigEndian) ||
|
||||
(fitsInMS3Bytes && cl->format.bigEndian)) {
|
||||
if (cl->format.bigEndian)
|
||||
zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
else
|
||||
zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
}
|
||||
else if ((fitsInLS3Bytes && cl->format.bigEndian) ||
|
||||
(fitsInMS3Bytes && !cl->format.bigEndian)) {
|
||||
if (cl->format.bigEndian)
|
||||
zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
else
|
||||
zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
}
|
||||
else {
|
||||
if (cl->format.bigEndian)
|
||||
zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
else
|
||||
zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out),
|
||||
+ w * (cl->format.bitsPerPixel / 8) * h);
|
||||
|
||||
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
|
||||
> UPDATE_BUF_SIZE)
|
||||
{
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rect.r.x = Swap16IfLE(x);
|
||||
rect.r.y = Swap16IfLE(y);
|
||||
rect.r.w = Swap16IfLE(w);
|
||||
rect.r.h = Swap16IfLE(h);
|
||||
rect.encoding = Swap32IfLE(cl->preferredEncoding);
|
||||
|
||||
memcpy(cl->updateBuf+cl->ublen, (char *)&rect,
|
||||
sz_rfbFramebufferUpdateRectHeader);
|
||||
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
|
||||
|
||||
hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out));
|
||||
|
||||
memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader);
|
||||
cl->ublen += sz_rfbZRLEHeader;
|
||||
|
||||
/* copy into updateBuf and send from there. Maybe should send directly? */
|
||||
|
||||
for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) {
|
||||
|
||||
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
|
||||
|
||||
if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) {
|
||||
bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i;
|
||||
}
|
||||
|
||||
memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy);
|
||||
|
||||
cl->ublen += bytesToCopy;
|
||||
i += bytesToCopy;
|
||||
|
||||
if (cl->ublen == UPDATE_BUF_SIZE) {
|
||||
if (!rfbSendUpdateBuf(cl))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void rfbFreeZrleData(rfbClientPtr cl)
|
||||
{
|
||||
if (cl->zrleData) {
|
||||
zrleOutStreamFree(cl->zrleData);
|
||||
}
|
||||
cl->zrleData = NULL;
|
||||
|
||||
if (cl->zrleBeforeBuf) {
|
||||
free(cl->zrleBeforeBuf);
|
||||
}
|
||||
cl->zrleBeforeBuf = NULL;
|
||||
|
||||
if (cl->paletteHelper) {
|
||||
free(cl->paletteHelper);
|
||||
}
|
||||
cl->paletteHelper = NULL;
|
||||
}
|
||||
|
||||
316
android/extern/libvncserver/src/libvncserver/zrleencodetemplate.c
vendored
Normal file
316
android/extern/libvncserver/src/libvncserver/zrleencodetemplate.c
vendored
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Before including this file, you must define a number of CPP macros.
|
||||
*
|
||||
* BPP should be 8, 16 or 32 depending on the bits per pixel.
|
||||
* GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
|
||||
* into the given buffer. EXTRA_ARGS can be defined to pass any other
|
||||
* arguments needed by GET_IMAGE_INTO_BUF.
|
||||
*
|
||||
* Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
|
||||
* bigger than the largest tile of pixel data, since the ZRLE encoding
|
||||
* algorithm writes to the position one past the end of the pixel data.
|
||||
*/
|
||||
|
||||
#include "zrleoutstream.h"
|
||||
#include "zrlepalettehelper.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* __RFB_CONCAT2 concatenates its two arguments. __RFB_CONCAT2E does the same
|
||||
but also expands its arguments if they are macros */
|
||||
|
||||
#ifndef __RFB_CONCAT2E
|
||||
#define __RFB_CONCAT2(a,b) a##b
|
||||
#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
|
||||
#endif
|
||||
|
||||
#ifndef __RFB_CONCAT3E
|
||||
#define __RFB_CONCAT3(a,b,c) a##b##c
|
||||
#define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c)
|
||||
#endif
|
||||
|
||||
#undef END_FIX
|
||||
#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
|
||||
# define END_FIX LE
|
||||
#elif ZYWRLE_ENDIAN == ENDIAN_BIG
|
||||
# define END_FIX BE
|
||||
#else
|
||||
# define END_FIX NE
|
||||
#endif
|
||||
|
||||
#ifdef CPIXEL
|
||||
#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
|
||||
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
|
||||
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX)
|
||||
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX)
|
||||
#define BPPOUT 24
|
||||
#elif BPP==15
|
||||
#define PIXEL_T __RFB_CONCAT2E(zrle_U,16)
|
||||
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16)
|
||||
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
|
||||
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
|
||||
#define BPPOUT 16
|
||||
#else
|
||||
#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
|
||||
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
|
||||
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
|
||||
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
|
||||
#define BPPOUT BPP
|
||||
#endif
|
||||
|
||||
#ifndef ZRLE_ONCE
|
||||
#define ZRLE_ONCE
|
||||
|
||||
static const int bitsPerPackedPixel[] = {
|
||||
0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
||||
};
|
||||
|
||||
#endif /* ZRLE_ONCE */
|
||||
|
||||
void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os,
|
||||
int zywrle_level, int *zywrleBuf, void *paletteHelper);
|
||||
|
||||
#if BPP!=8
|
||||
#define ZYWRLE_ENCODE
|
||||
#include "zywrletemplate.c"
|
||||
#endif
|
||||
|
||||
static void ZRLE_ENCODE (int x, int y, int w, int h,
|
||||
zrleOutStream* os, void* buf
|
||||
EXTRA_ARGS
|
||||
)
|
||||
{
|
||||
int ty;
|
||||
for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
|
||||
int tx, th = rfbZRLETileHeight;
|
||||
if (th > y+h-ty) th = y+h-ty;
|
||||
for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
|
||||
int tw = rfbZRLETileWidth;
|
||||
if (tw > x+w-tx) tw = x+w-tx;
|
||||
|
||||
GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
|
||||
|
||||
if (cl->paletteHelper == NULL) {
|
||||
cl->paletteHelper = (void *) calloc(sizeof(zrlePaletteHelper), 1);
|
||||
}
|
||||
|
||||
ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os,
|
||||
cl->zywrleLevel, cl->zywrleBuf, cl->paletteHelper);
|
||||
}
|
||||
}
|
||||
zrleOutStreamFlush(os);
|
||||
}
|
||||
|
||||
|
||||
void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
|
||||
int zywrle_level, int *zywrleBuf, void *paletteHelper)
|
||||
{
|
||||
/* First find the palette and the number of runs */
|
||||
|
||||
zrlePaletteHelper *ph;
|
||||
|
||||
int runs = 0;
|
||||
int singlePixels = 0;
|
||||
|
||||
rfbBool useRle;
|
||||
rfbBool usePalette;
|
||||
|
||||
int estimatedBytes;
|
||||
int plainRleBytes;
|
||||
int i;
|
||||
|
||||
PIXEL_T* ptr = data;
|
||||
PIXEL_T* end = ptr + h * w;
|
||||
*end = ~*(end-1); /* one past the end is different so the while loop ends */
|
||||
|
||||
ph = (zrlePaletteHelper *) paletteHelper;
|
||||
zrlePaletteHelperInit(ph);
|
||||
|
||||
while (ptr < end) {
|
||||
PIXEL_T pix = *ptr;
|
||||
if (*++ptr != pix) {
|
||||
singlePixels++;
|
||||
} else {
|
||||
while (*++ptr == pix) ;
|
||||
runs++;
|
||||
}
|
||||
zrlePaletteHelperInsert(ph, pix);
|
||||
}
|
||||
|
||||
/* Solid tile is a special case */
|
||||
|
||||
if (ph->size == 1) {
|
||||
zrleOutStreamWriteU8(os, 1);
|
||||
zrleOutStreamWRITE_PIXEL(os, ph->palette[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to work out whether to use RLE and/or a palette. We do this by
|
||||
estimating the number of bytes which will be generated and picking the
|
||||
method which results in the fewest bytes. Of course this may not result
|
||||
in the fewest bytes after compression... */
|
||||
|
||||
useRle = FALSE;
|
||||
usePalette = FALSE;
|
||||
|
||||
estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */
|
||||
|
||||
#if BPP!=8
|
||||
if (zywrle_level > 0 && !(zywrle_level & 0x80))
|
||||
estimatedBytes >>= zywrle_level;
|
||||
#endif
|
||||
|
||||
plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
|
||||
|
||||
if (plainRleBytes < estimatedBytes) {
|
||||
useRle = TRUE;
|
||||
estimatedBytes = plainRleBytes;
|
||||
}
|
||||
|
||||
if (ph->size < 128) {
|
||||
int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels;
|
||||
|
||||
if (paletteRleBytes < estimatedBytes) {
|
||||
useRle = TRUE;
|
||||
usePalette = TRUE;
|
||||
estimatedBytes = paletteRleBytes;
|
||||
}
|
||||
|
||||
if (ph->size < 17) {
|
||||
int packedBytes = ((BPPOUT/8) * ph->size +
|
||||
w * h * bitsPerPackedPixel[ph->size-1] / 8);
|
||||
|
||||
if (packedBytes < estimatedBytes) {
|
||||
useRle = FALSE;
|
||||
usePalette = TRUE;
|
||||
estimatedBytes = packedBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!usePalette) ph->size = 0;
|
||||
|
||||
zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
|
||||
|
||||
for (i = 0; i < ph->size; i++) {
|
||||
zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
|
||||
}
|
||||
|
||||
if (useRle) {
|
||||
|
||||
PIXEL_T* ptr = data;
|
||||
PIXEL_T* end = ptr + w * h;
|
||||
PIXEL_T* runStart;
|
||||
PIXEL_T pix;
|
||||
while (ptr < end) {
|
||||
int len;
|
||||
runStart = ptr;
|
||||
pix = *ptr++;
|
||||
while (*ptr == pix && ptr < end)
|
||||
ptr++;
|
||||
len = ptr - runStart;
|
||||
if (len <= 2 && usePalette) {
|
||||
int index = zrlePaletteHelperLookup(ph, pix);
|
||||
if (len == 2)
|
||||
zrleOutStreamWriteU8(os, index);
|
||||
zrleOutStreamWriteU8(os, index);
|
||||
continue;
|
||||
}
|
||||
if (usePalette) {
|
||||
int index = zrlePaletteHelperLookup(ph, pix);
|
||||
zrleOutStreamWriteU8(os, index | 128);
|
||||
} else {
|
||||
zrleOutStreamWRITE_PIXEL(os, pix);
|
||||
}
|
||||
len -= 1;
|
||||
while (len >= 255) {
|
||||
zrleOutStreamWriteU8(os, 255);
|
||||
len -= 255;
|
||||
}
|
||||
zrleOutStreamWriteU8(os, len);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* no RLE */
|
||||
|
||||
if (usePalette) {
|
||||
int bppp;
|
||||
PIXEL_T* ptr = data;
|
||||
|
||||
/* packed pixels */
|
||||
|
||||
assert (ph->size < 17);
|
||||
|
||||
bppp = bitsPerPackedPixel[ph->size-1];
|
||||
|
||||
for (i = 0; i < h; i++) {
|
||||
zrle_U8 nbits = 0;
|
||||
zrle_U8 byte = 0;
|
||||
|
||||
PIXEL_T* eol = ptr + w;
|
||||
|
||||
while (ptr < eol) {
|
||||
PIXEL_T pix = *ptr++;
|
||||
zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
|
||||
byte = (byte << bppp) | index;
|
||||
nbits += bppp;
|
||||
if (nbits >= 8) {
|
||||
zrleOutStreamWriteU8(os, byte);
|
||||
nbits = 0;
|
||||
}
|
||||
}
|
||||
if (nbits > 0) {
|
||||
byte <<= 8 - nbits;
|
||||
zrleOutStreamWriteU8(os, byte);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
/* raw */
|
||||
|
||||
#if BPP!=8
|
||||
if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
|
||||
ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf);
|
||||
ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf, paletteHelper);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef CPIXEL
|
||||
PIXEL_T *ptr;
|
||||
for (ptr = data; ptr < data+w*h; ptr++)
|
||||
zrleOutStreamWRITE_PIXEL(os, *ptr);
|
||||
#else
|
||||
zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef PIXEL_T
|
||||
#undef zrleOutStreamWRITE_PIXEL
|
||||
#undef ZRLE_ENCODE
|
||||
#undef ZRLE_ENCODE_TILE
|
||||
#undef ZYWRLE_ENCODE_TILE
|
||||
#undef BPPOUT
|
||||
278
android/extern/libvncserver/src/libvncserver/zrleoutstream.c
vendored
Normal file
278
android/extern/libvncserver/src/libvncserver/zrleoutstream.c
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include "zrleoutstream.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ZRLE_IN_BUFFER_SIZE 16384
|
||||
#define ZRLE_OUT_BUFFER_SIZE 1024
|
||||
#undef ZRLE_DEBUG
|
||||
|
||||
static rfbBool zrleBufferAlloc(zrleBuffer *buffer, int size)
|
||||
{
|
||||
buffer->ptr = buffer->start = malloc(size);
|
||||
if (buffer->start == NULL) {
|
||||
buffer->end = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
buffer->end = buffer->start + size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void zrleBufferFree(zrleBuffer *buffer)
|
||||
{
|
||||
if (buffer->start)
|
||||
free(buffer->start);
|
||||
buffer->start = buffer->ptr = buffer->end = NULL;
|
||||
}
|
||||
|
||||
static rfbBool zrleBufferGrow(zrleBuffer *buffer, int size)
|
||||
{
|
||||
int offset;
|
||||
void *new_buffer;
|
||||
|
||||
size += buffer->end - buffer->start;
|
||||
offset = ZRLE_BUFFER_LENGTH (buffer);
|
||||
|
||||
new_buffer = realloc(buffer->start, size);
|
||||
if (!new_buffer) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
buffer->start = new_buffer;
|
||||
|
||||
buffer->end = buffer->start + size;
|
||||
buffer->ptr = buffer->start + offset;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
zrleOutStream *zrleOutStreamNew(void)
|
||||
{
|
||||
zrleOutStream *os;
|
||||
|
||||
os = malloc(sizeof(zrleOutStream));
|
||||
if (os == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!zrleBufferAlloc(&os->in, ZRLE_IN_BUFFER_SIZE)) {
|
||||
free(os);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!zrleBufferAlloc(&os->out, ZRLE_OUT_BUFFER_SIZE)) {
|
||||
zrleBufferFree(&os->in);
|
||||
free(os);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os->zs.zalloc = Z_NULL;
|
||||
os->zs.zfree = Z_NULL;
|
||||
os->zs.opaque = Z_NULL;
|
||||
if (deflateInit(&os->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
|
||||
zrleBufferFree(&os->in);
|
||||
free(os);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
void zrleOutStreamFree (zrleOutStream *os)
|
||||
{
|
||||
deflateEnd(&os->zs);
|
||||
zrleBufferFree(&os->in);
|
||||
zrleBufferFree(&os->out);
|
||||
free(os);
|
||||
}
|
||||
|
||||
rfbBool zrleOutStreamFlush(zrleOutStream *os)
|
||||
{
|
||||
os->zs.next_in = os->in.start;
|
||||
os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in);
|
||||
|
||||
#ifdef ZRLE_DEBUG
|
||||
rfbLog("zrleOutStreamFlush: avail_in %d\n", os->zs.avail_in);
|
||||
#endif
|
||||
|
||||
while (os->zs.avail_in != 0) {
|
||||
do {
|
||||
int ret;
|
||||
|
||||
if (os->out.ptr >= os->out.end &&
|
||||
!zrleBufferGrow(&os->out, os->out.end - os->out.start)) {
|
||||
rfbLog("zrleOutStreamFlush: failed to grow output buffer\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
os->zs.next_out = os->out.ptr;
|
||||
os->zs.avail_out = os->out.end - os->out.ptr;
|
||||
|
||||
#ifdef ZRLE_DEBUG
|
||||
rfbLog("zrleOutStreamFlush: calling deflate, avail_in %d, avail_out %d\n",
|
||||
os->zs.avail_in, os->zs.avail_out);
|
||||
#endif
|
||||
|
||||
if ((ret = deflate(&os->zs, Z_SYNC_FLUSH)) != Z_OK) {
|
||||
rfbLog("zrleOutStreamFlush: deflate failed with error code %d\n", ret);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef ZRLE_DEBUG
|
||||
rfbLog("zrleOutStreamFlush: after deflate: %d bytes\n",
|
||||
os->zs.next_out - os->out.ptr);
|
||||
#endif
|
||||
|
||||
os->out.ptr = os->zs.next_out;
|
||||
} while (os->zs.avail_out == 0);
|
||||
}
|
||||
|
||||
os->in.ptr = os->in.start;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int zrleOutStreamOverrun(zrleOutStream *os,
|
||||
int size)
|
||||
{
|
||||
#ifdef ZRLE_DEBUG
|
||||
rfbLog("zrleOutStreamOverrun\n");
|
||||
#endif
|
||||
|
||||
while (os->in.end - os->in.ptr < size && os->in.ptr > os->in.start) {
|
||||
os->zs.next_in = os->in.start;
|
||||
os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in);
|
||||
|
||||
do {
|
||||
int ret;
|
||||
|
||||
if (os->out.ptr >= os->out.end &&
|
||||
!zrleBufferGrow(&os->out, os->out.end - os->out.start)) {
|
||||
rfbLog("zrleOutStreamOverrun: failed to grow output buffer\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
os->zs.next_out = os->out.ptr;
|
||||
os->zs.avail_out = os->out.end - os->out.ptr;
|
||||
|
||||
#ifdef ZRLE_DEBUG
|
||||
rfbLog("zrleOutStreamOverrun: calling deflate, avail_in %d, avail_out %d\n",
|
||||
os->zs.avail_in, os->zs.avail_out);
|
||||
#endif
|
||||
|
||||
if ((ret = deflate(&os->zs, 0)) != Z_OK) {
|
||||
rfbLog("zrleOutStreamOverrun: deflate failed with error code %d\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ZRLE_DEBUG
|
||||
rfbLog("zrleOutStreamOverrun: after deflate: %d bytes\n",
|
||||
os->zs.next_out - os->out.ptr);
|
||||
#endif
|
||||
|
||||
os->out.ptr = os->zs.next_out;
|
||||
} while (os->zs.avail_out == 0);
|
||||
|
||||
/* output buffer not full */
|
||||
|
||||
if (os->zs.avail_in == 0) {
|
||||
os->in.ptr = os->in.start;
|
||||
} else {
|
||||
/* but didn't consume all the data? try shifting what's left to the
|
||||
* start of the buffer.
|
||||
*/
|
||||
rfbLog("zrleOutStreamOverrun: out buf not full, but in data not consumed\n");
|
||||
memmove(os->in.start, os->zs.next_in, os->in.ptr - os->zs.next_in);
|
||||
os->in.ptr -= os->zs.next_in - os->in.start;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > os->in.end - os->in.ptr)
|
||||
size = os->in.end - os->in.ptr;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int zrleOutStreamCheck(zrleOutStream *os, int size)
|
||||
{
|
||||
if (os->in.ptr + size > os->in.end) {
|
||||
return zrleOutStreamOverrun(os, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void zrleOutStreamWriteBytes(zrleOutStream *os,
|
||||
const zrle_U8 *data,
|
||||
int length)
|
||||
{
|
||||
const zrle_U8* dataEnd = data + length;
|
||||
while (data < dataEnd) {
|
||||
int n = zrleOutStreamCheck(os, dataEnd - data);
|
||||
memcpy(os->in.ptr, data, n);
|
||||
os->in.ptr += n;
|
||||
data += n;
|
||||
}
|
||||
}
|
||||
|
||||
void zrleOutStreamWriteU8(zrleOutStream *os, zrle_U8 u)
|
||||
{
|
||||
zrleOutStreamCheck(os, 1);
|
||||
*os->in.ptr++ = u;
|
||||
}
|
||||
|
||||
void zrleOutStreamWriteOpaque8(zrleOutStream *os, zrle_U8 u)
|
||||
{
|
||||
zrleOutStreamCheck(os, 1);
|
||||
*os->in.ptr++ = u;
|
||||
}
|
||||
|
||||
void zrleOutStreamWriteOpaque16 (zrleOutStream *os, zrle_U16 u)
|
||||
{
|
||||
zrleOutStreamCheck(os, 2);
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[0];
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[1];
|
||||
}
|
||||
|
||||
void zrleOutStreamWriteOpaque32 (zrleOutStream *os, zrle_U32 u)
|
||||
{
|
||||
zrleOutStreamCheck(os, 4);
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[0];
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[1];
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[2];
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[3];
|
||||
}
|
||||
|
||||
void zrleOutStreamWriteOpaque24A(zrleOutStream *os, zrle_U32 u)
|
||||
{
|
||||
zrleOutStreamCheck(os, 3);
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[0];
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[1];
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[2];
|
||||
}
|
||||
|
||||
void zrleOutStreamWriteOpaque24B(zrleOutStream *os, zrle_U32 u)
|
||||
{
|
||||
zrleOutStreamCheck(os, 3);
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[1];
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[2];
|
||||
*os->in.ptr++ = ((zrle_U8*)&u)[3];
|
||||
}
|
||||
62
android/extern/libvncserver/src/libvncserver/zrleoutstream.h
vendored
Normal file
62
android/extern/libvncserver/src/libvncserver/zrleoutstream.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifndef __ZRLE_OUT_STREAM_H__
|
||||
#define __ZRLE_OUT_STREAM_H__
|
||||
|
||||
#include <zlib.h>
|
||||
#include "zrletypes.h"
|
||||
#include "rfb/rfb.h"
|
||||
|
||||
typedef struct {
|
||||
zrle_U8 *start;
|
||||
zrle_U8 *ptr;
|
||||
zrle_U8 *end;
|
||||
} zrleBuffer;
|
||||
|
||||
typedef struct {
|
||||
zrleBuffer in;
|
||||
zrleBuffer out;
|
||||
|
||||
z_stream zs;
|
||||
} zrleOutStream;
|
||||
|
||||
#define ZRLE_BUFFER_LENGTH(b) ((b)->ptr - (b)->start)
|
||||
|
||||
zrleOutStream *zrleOutStreamNew (void);
|
||||
void zrleOutStreamFree (zrleOutStream *os);
|
||||
rfbBool zrleOutStreamFlush (zrleOutStream *os);
|
||||
void zrleOutStreamWriteBytes (zrleOutStream *os,
|
||||
const zrle_U8 *data,
|
||||
int length);
|
||||
void zrleOutStreamWriteU8 (zrleOutStream *os,
|
||||
zrle_U8 u);
|
||||
void zrleOutStreamWriteOpaque8 (zrleOutStream *os,
|
||||
zrle_U8 u);
|
||||
void zrleOutStreamWriteOpaque16 (zrleOutStream *os,
|
||||
zrle_U16 u);
|
||||
void zrleOutStreamWriteOpaque32 (zrleOutStream *os,
|
||||
zrle_U32 u);
|
||||
void zrleOutStreamWriteOpaque24A(zrleOutStream *os,
|
||||
zrle_U32 u);
|
||||
void zrleOutStreamWriteOpaque24B(zrleOutStream *os,
|
||||
zrle_U32 u);
|
||||
|
||||
#endif /* __ZRLE_OUT_STREAM_H__ */
|
||||
62
android/extern/libvncserver/src/libvncserver/zrlepalettehelper.c
vendored
Normal file
62
android/extern/libvncserver/src/libvncserver/zrlepalettehelper.c
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include "zrlepalettehelper.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ZRLE_HASH(pix) (((pix) ^ ((pix) >> 17)) & 4095)
|
||||
|
||||
void zrlePaletteHelperInit(zrlePaletteHelper *helper)
|
||||
{
|
||||
memset(helper->palette, 0, sizeof(helper->palette));
|
||||
memset(helper->index, 255, sizeof(helper->index));
|
||||
memset(helper->key, 0, sizeof(helper->key));
|
||||
helper->size = 0;
|
||||
}
|
||||
|
||||
void zrlePaletteHelperInsert(zrlePaletteHelper *helper, zrle_U32 pix)
|
||||
{
|
||||
if (helper->size < ZRLE_PALETTE_MAX_SIZE) {
|
||||
int i = ZRLE_HASH(pix);
|
||||
|
||||
while (helper->index[i] != 255 && helper->key[i] != pix)
|
||||
i++;
|
||||
if (helper->index[i] != 255) return;
|
||||
|
||||
helper->index[i] = helper->size;
|
||||
helper->key[i] = pix;
|
||||
helper->palette[helper->size] = pix;
|
||||
}
|
||||
helper->size++;
|
||||
}
|
||||
|
||||
int zrlePaletteHelperLookup(zrlePaletteHelper *helper, zrle_U32 pix)
|
||||
{
|
||||
int i = ZRLE_HASH(pix);
|
||||
|
||||
assert(helper->size <= ZRLE_PALETTE_MAX_SIZE);
|
||||
|
||||
while (helper->index[i] != 255 && helper->key[i] != pix)
|
||||
i++;
|
||||
if (helper->index[i] != 255) return helper->index[i];
|
||||
|
||||
return -1;
|
||||
}
|
||||
46
android/extern/libvncserver/src/libvncserver/zrlepalettehelper.h
vendored
Normal file
46
android/extern/libvncserver/src/libvncserver/zrlepalettehelper.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The PaletteHelper class helps us build up the palette from pixel data by
|
||||
* storing a reverse index using a simple hash-table
|
||||
*/
|
||||
|
||||
#ifndef __ZRLE_PALETTE_HELPER_H__
|
||||
#define __ZRLE_PALETTE_HELPER_H__
|
||||
|
||||
#include "zrletypes.h"
|
||||
|
||||
#define ZRLE_PALETTE_MAX_SIZE 127
|
||||
|
||||
typedef struct {
|
||||
zrle_U32 palette[ZRLE_PALETTE_MAX_SIZE];
|
||||
zrle_U8 index[ZRLE_PALETTE_MAX_SIZE + 4096];
|
||||
zrle_U32 key[ZRLE_PALETTE_MAX_SIZE + 4096];
|
||||
int size;
|
||||
} zrlePaletteHelper;
|
||||
|
||||
void zrlePaletteHelperInit (zrlePaletteHelper *helper);
|
||||
void zrlePaletteHelperInsert(zrlePaletteHelper *helper,
|
||||
zrle_U32 pix);
|
||||
int zrlePaletteHelperLookup(zrlePaletteHelper *helper,
|
||||
zrle_U32 pix);
|
||||
|
||||
#endif /* __ZRLE_PALETTE_HELPER_H__ */
|
||||
30
android/extern/libvncserver/src/libvncserver/zrletypes.h
vendored
Normal file
30
android/extern/libvncserver/src/libvncserver/zrletypes.h
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifndef __ZRLE_TYPES_H__
|
||||
#define __ZRLE_TYPES_H__
|
||||
|
||||
typedef unsigned char zrle_U8;
|
||||
typedef unsigned short zrle_U16;
|
||||
typedef unsigned int zrle_U32;
|
||||
typedef signed char zrle_S8;
|
||||
typedef signed short zrle_S16;
|
||||
typedef signed int zrle_S32;
|
||||
|
||||
#endif /* __ZRLE_TYPES_H__ */
|
||||
Reference in New Issue
Block a user