Compare commits
10 Commits
a646a5cce2
...
1fb029cde7
Author | SHA1 | Date | |
---|---|---|---|
1fb029cde7 | |||
|
4716f1e016 | ||
|
da36432c31 | ||
|
3986164464 | ||
|
134262fc03 | ||
|
1620a263bf | ||
|
53ba87dc17 | ||
|
50f607ee61 | ||
|
5ce283806c | ||
|
fdb2da450a |
39
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
39
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
name: Bug Report
|
||||||
|
about: Follow this template to report a bug
|
||||||
|
title: "[BUG] "
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
PLEASE, FOLLOW AS CLOSELY AS POSSIBLE THE FOLLOWING SCRIPT TO FILL A BUG REPORT (and remove hints and instructions)
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**Reproduction Steps**
|
||||||
|
Explain in detailed steps how to reproduce the bug
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Important Information:**
|
||||||
|
- rdesktop Version (*): [e.g. 1.9.0]
|
||||||
|
- Client OS (*): [e.g. Fedora Core 35]
|
||||||
|
- Server OS: [e.g. Windows 10]
|
||||||
|
- Server Software: [e.g. xrdp]
|
||||||
|
- Server Software Version: [e.g. 1.5.1]
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
- [ ] This bug prevents me from using rdesktop
|
||||||
|
- [ ] This bug is a security issue
|
||||||
|
- [ ] This bug causes a bad experience with rdesktop
|
||||||
|
- [ ] I have supplied all possible sections of the bug report template
|
||||||
|
|
||||||
|
**Additional Information**
|
||||||
|
Add any relevant contextual information or other details about the problem here, like command line arguments, output, environment variables, gdb output, screenshots, etc.
|
||||||
|
HINT: the output is often useful, run `rdesktop` with the `-v` argument (verbose) to produce a more detailed output.
|
29
.github/ISSUE_TEMPLATE/feature-suggestion.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/feature-suggestion.md
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
name: Feature Suggestion
|
||||||
|
about: Suggest a feature for rdesktop
|
||||||
|
title: "[FS]"
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
PLEASE, TAKE THIS TEMPLATE AS A SCRIPT TO HELP YOU TO THINK AS CONCRETELY AS POSSIBLE ABOUT THE PROPOSED FEATURE THAT DON'T NEED TO BE STRICTLY FOLLOWED. (remove this message before posting)
|
||||||
|
|
||||||
|
**Brief Description**
|
||||||
|
Shortly describe the feature you are proposing (1-3 phrases).
|
||||||
|
|
||||||
|
**Needs or Improvements**
|
||||||
|
The user needs your feature suggestion are intended to satisfy and/or to satisfy in a better way (i.e. know when the connection is decreasing in quality).
|
||||||
|
|
||||||
|
**The proposed feature is**
|
||||||
|
- [ ] A feature to satisfy a new need that is not currently satisfied
|
||||||
|
- [ ] A feature to improve the way an already met need is satisfied
|
||||||
|
|
||||||
|
**Detailed Solution**
|
||||||
|
Describe how the proposed feature would work, how it would be used, etc
|
||||||
|
|
||||||
|
**Expected Interface**
|
||||||
|
Describe how the interface for this feature would be (i.e. a `-f FILENAME` argument to the command line).
|
||||||
|
|
||||||
|
**Requirements**
|
||||||
|
Optionally, add a list of specific requirements for this feature
|
17
.github/ISSUE_TEMPLATE/getting-help.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/getting-help.md
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: Getting Help
|
||||||
|
about: Get help with some usage related problem
|
||||||
|
title: "[SUP]"
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**What do you need help with?**
|
||||||
|
Describe what you would like to achieve with rdesktop
|
||||||
|
|
||||||
|
**Have you tried anything so far?**
|
||||||
|
If you tried to do it in some way and it didn't work, please describe how you tried to do and what went wrong (i.e. an error message)
|
||||||
|
|
||||||
|
**Have you tried the docs?**
|
||||||
|
- [ ] Yes, I have tried to read the appropriate docs but haven't found a solution
|
190
asn.c
190
asn.c
@ -31,126 +31,109 @@
|
|||||||
static asn1_node *asn_defs = NULL;
|
static asn1_node *asn_defs = NULL;
|
||||||
|
|
||||||
#define MAX_ERROR_DESCRIPTION_SIZE 1024
|
#define MAX_ERROR_DESCRIPTION_SIZE 1024
|
||||||
char errstr[MAX_ERROR_DESCRIPTION_SIZE];
|
static char errstr[MAX_ERROR_DESCRIPTION_SIZE];
|
||||||
|
|
||||||
/* Parse an ASN.1 BER header */
|
/* Parse an ASN.1 BER header */
|
||||||
RD_BOOL
|
static int ber_parse_header(STREAM s, int tagval, uint32 *length)
|
||||||
ber_parse_header(STREAM s, int tagval, uint32 *length)
|
|
||||||
{
|
{
|
||||||
int tag, len;
|
int tag, len;
|
||||||
|
|
||||||
if (tagval > 0xff)
|
if (tagval > 0xff) {
|
||||||
{
|
|
||||||
if (!s_check_rem(s, 2)) {
|
if (!s_check_rem(s, 2)) {
|
||||||
return False;
|
return ASN_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
in_uint16_be(s, tag);
|
in_uint16_be(s, tag);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!s_check_rem(s, 1)) {
|
if (!s_check_rem(s, 1)) {
|
||||||
return False;
|
return ASN_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
in_uint8(s, tag);
|
in_uint8(s, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag != tagval)
|
if (tag != tagval) {
|
||||||
{
|
|
||||||
logger(Core, Error, "ber_parse_header(), expected tag %d, got %d", tagval, tag);
|
logger(Core, Error, "ber_parse_header(), expected tag %d, got %d", tagval, tag);
|
||||||
return False;
|
return ASN_TAG_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s_check_rem(s, 1)) {
|
if (!s_check_rem(s, 1)) {
|
||||||
return False;
|
return ASN_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
in_uint8(s, len);
|
in_uint8(s, len);
|
||||||
|
|
||||||
if (len & 0x80)
|
if (len & 0x80) {
|
||||||
{
|
|
||||||
len &= ~0x80;
|
len &= ~0x80;
|
||||||
if (!s_check_rem(s, len)) {
|
if (!s_check_rem(s, len)) {
|
||||||
return False;
|
return ASN_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
*length = 0;
|
*length = 0;
|
||||||
while (len--)
|
while (len--) {
|
||||||
next_be(s, *length);
|
next_be(s, *length);
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
*length = len;
|
*length = len;
|
||||||
|
}
|
||||||
|
|
||||||
return True;
|
return ASN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void ber_out_sequence(STREAM out, STREAM content)
|
||||||
ber_out_sequence(STREAM out, STREAM content)
|
|
||||||
{
|
{
|
||||||
size_t length;
|
size_t length;
|
||||||
length = (content ? s_length(content) : 0);
|
length = (content ? s_length(content) : 0);
|
||||||
ber_out_header(out, BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, length);
|
ber_out_header(out, BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, length);
|
||||||
if (content)
|
if (content) {
|
||||||
out_stream(out, content);
|
out_stream(out, content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Output an ASN.1 BER header */
|
/* Output an ASN.1 BER header */
|
||||||
void
|
static void ber_out_header(STREAM s, int tagval, int length)
|
||||||
ber_out_header(STREAM s, int tagval, int length)
|
|
||||||
{
|
{
|
||||||
if (tagval > 0xff)
|
if (tagval > 0xff) {
|
||||||
{
|
|
||||||
out_uint16_be(s, tagval);
|
out_uint16_be(s, tagval);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
out_uint8(s, tagval);
|
out_uint8(s, tagval);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length >= 0x80)
|
if (length >= 0x80) {
|
||||||
{
|
|
||||||
out_uint8(s, 0x82);
|
out_uint8(s, 0x82);
|
||||||
out_uint16_be(s, length);
|
out_uint16_be(s, length);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
out_uint8(s, length);
|
out_uint8(s, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output an ASN.1 BER integer */
|
/* Output an ASN.1 BER integer */
|
||||||
void
|
static void ber_out_integer(STREAM s, int value)
|
||||||
ber_out_integer(STREAM s, int value)
|
|
||||||
{
|
{
|
||||||
ber_out_header(s, BER_TAG_INTEGER, 2);
|
ber_out_header(s, BER_TAG_INTEGER, 2);
|
||||||
out_uint16_be(s, value);
|
out_uint16_be(s, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
static int ber_in_header(STREAM s, int *tagval, int *decoded_len)
|
||||||
ber_in_header(STREAM s, int *tagval, int *decoded_len)
|
|
||||||
{
|
{
|
||||||
in_uint8(s, *tagval);
|
in_uint8(s, *tagval);
|
||||||
in_uint8(s, *decoded_len);
|
in_uint8(s, *decoded_len);
|
||||||
|
|
||||||
if (*decoded_len < 0x80)
|
if (*decoded_len < 0x80) {
|
||||||
return True;
|
return ASN_SUCCESS;
|
||||||
else if (*decoded_len == 0x81)
|
} else if (*decoded_len == 0x81) {
|
||||||
{
|
|
||||||
in_uint8(s, *decoded_len);
|
in_uint8(s, *decoded_len);
|
||||||
return True;
|
return ASN_SUCCESS;
|
||||||
}
|
} else if (*decoded_len == 0x82) {
|
||||||
else if (*decoded_len == 0x82)
|
|
||||||
{
|
|
||||||
in_uint16_be(s, *decoded_len);
|
in_uint16_be(s, *decoded_len);
|
||||||
return True;
|
return ASN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return False;
|
return ASN_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int init_asn1_lib(void)
|
||||||
int init_asn1_lib(void)
|
|
||||||
{
|
{
|
||||||
int asn1_rv;
|
int asn1_rv;
|
||||||
|
|
||||||
if (asn_defs) {
|
if (asn_defs) {
|
||||||
return 0;
|
return ASN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
asn_defs = malloc(sizeof(*asn_defs));
|
asn_defs = malloc(sizeof(*asn_defs));
|
||||||
@ -158,7 +141,7 @@ int init_asn1_lib(void)
|
|||||||
if (!asn_defs) {
|
if (!asn_defs) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to allocate memory for ASN.1 parser\n",
|
logger(Core, Error, "%s:%s:%d Failed to allocate memory for ASN.1 parser\n",
|
||||||
__FILE__, __func__, __LINE__);
|
__FILE__, __func__, __LINE__);
|
||||||
return 1;
|
return ASN_MEM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
*asn_defs = NULL;
|
*asn_defs = NULL;
|
||||||
@ -167,98 +150,90 @@ int init_asn1_lib(void)
|
|||||||
logger(Core, Error, "%s:%s:%d Failed to init ASN.1 parser. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to init ASN.1 parser. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
|
|
||||||
return 1;
|
free(asn_defs);
|
||||||
|
asn_defs = NULL;
|
||||||
|
return asn1_rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ASN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encode RSA public key into DER PKCS#1 */
|
/* Encode RSA public key into DER PKCS#1 */
|
||||||
/* Returns; 0 - success, 1 - fatal error, 2 - insufficient space in buffer */
|
static int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len)
|
||||||
int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len)
|
|
||||||
{
|
{
|
||||||
int asn1_rv;
|
int asn1_rv;
|
||||||
asn1_node asn_cert;
|
asn1_node asn_cert;
|
||||||
|
|
||||||
if (!asn_defs) {
|
if (!asn_defs) {
|
||||||
if (init_asn1_lib() != 0) {
|
if (init_asn1_lib() != ASN_SUCCESS) {
|
||||||
return 1;
|
return ASN_INIT_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_cert))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_cert))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element for RSAPublicKey. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element for RSAPublicKey. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_CREATE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "modulus", m->data, m->size))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "modulus", m->data, m->size))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to write modulus. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to write modulus. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
|
|
||||||
return 1;
|
return ASN_WRITE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "publicExponent", e->data, e->size))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "publicExponent", e->data, e->size))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to write publicExponent. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to write publicExponent. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_WRITE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_der_coding(asn_cert, "", out, out_len, errstr))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_der_coding(asn_cert, "", out, out_len, errstr))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to encode PKIX1Implicit88.RSAPublicKey. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to encode PKIX1Implicit88.RSAPublicKey. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
|
|
||||||
if (asn1_rv == ASN1_MEM_ERROR) {
|
return ASN_ENCODE_ERROR;
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return ASN_SUCCESS;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size)
|
static int libtasn_read_cert_pk(uint8_t *data, size_t len, char *oid, size_t *oid_size, gnutls_datum_t *m, gnutls_datum_t *e)
|
||||||
{
|
{
|
||||||
int asn1_rv;
|
int asn1_rv;
|
||||||
asn1_node asn_cert;
|
asn1_node asn_cert;
|
||||||
|
|
||||||
/* Parse DER encoded x.509 certificate */
|
/* Parse DER encoded x.509 certificate */
|
||||||
if (!asn_defs) {
|
if (!asn_defs) {
|
||||||
if (init_asn1_lib() != 0) {
|
if (init_asn1_lib() != ASN_SUCCESS) {
|
||||||
return 1;
|
return ASN_INIT_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.Certificate", &asn_cert))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.Certificate", &asn_cert))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_CREATE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_cert, data, len, errstr))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_cert, data, len, errstr))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to decode certificate object. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to decode certificate object. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_DECODE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oid && oid_size) {
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm",
|
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm",
|
||||||
oid, (int *)oid_size)))
|
oid, (int *)oid_size)))
|
||||||
{
|
{
|
||||||
logger(Core, Error, "%s:%s:%d Failed to get cert's public key algorithm. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to get cert's public key algorithm. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_READ_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if (m && e) {
|
||||||
}
|
|
||||||
|
|
||||||
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e)
|
|
||||||
{
|
|
||||||
int asn1_rv;
|
|
||||||
asn1_node asn_cert;
|
|
||||||
|
|
||||||
int buflen;
|
int buflen;
|
||||||
uint8_t buf[16384];
|
uint8_t buf[16384];
|
||||||
|
|
||||||
@ -266,39 +241,24 @@ int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m
|
|||||||
int nblen;
|
int nblen;
|
||||||
uint8_t newbuf[16384];
|
uint8_t newbuf[16384];
|
||||||
|
|
||||||
/* Parse DER encoded x.509 certificate */
|
|
||||||
init_asn1_lib();
|
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.Certificate", &asn_cert))) {
|
|
||||||
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
|
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_cert, data, len, errstr))) {
|
|
||||||
logger(Core, Error, "%s:%s:%d Failed to decode certificate object. Error = 0x%x (%s)\n",
|
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
buflen = sizeof(buf) - 1;
|
buflen = sizeof(buf) - 1;
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", buf, &buflen))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", buf, &buflen))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to get cert's public key. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to get cert's public key. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_READ_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_key))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_key))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_CREATE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// As it' a BIT STRING the len constitutes the number of BITS, not BYTES
|
// As it' a BIT STRING the len constitutes the number of BITS, not BYTES
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_key, buf, buflen / 8, errstr))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_key, buf, buflen / 8, errstr))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to decode public key object. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to decode public key object. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_DECODE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get RSA public key's modulus and exponent */
|
/* Get RSA public key's modulus and exponent */
|
||||||
@ -307,14 +267,15 @@ int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m
|
|||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "modulus", newbuf, &nblen))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "modulus", newbuf, &nblen))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to get RSA public key's modulus. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to get RSA public key's modulus. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
return ASN_READ_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
m->size = nblen;
|
m->size = nblen;
|
||||||
|
|
||||||
if (!(m->data = malloc(m->size))) {
|
m->data = malloc(m->size);
|
||||||
|
if (!m->data) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to allocate memory for modulus.\n", __FILE__, __func__, __LINE__);
|
logger(Core, Error, "%s:%s:%d Failed to allocate memory for modulus.\n", __FILE__, __func__, __LINE__);
|
||||||
return 1;
|
return ASN_MEM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy((void *)m->data, newbuf, m->size);
|
memcpy((void *)m->data, newbuf, m->size);
|
||||||
@ -324,20 +285,31 @@ int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m
|
|||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "publicExponent", newbuf, &nblen))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "publicExponent", newbuf, &nblen))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to get RSA public key's exponent. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to get RSA public key's exponent. Error = 0x%x (%s)\n",
|
||||||
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
return 1;
|
free(m->data);
|
||||||
|
return ASN_READ_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
e->size = nblen;
|
e->size = nblen;
|
||||||
|
|
||||||
if (!(e->data = malloc(e->size))) {
|
e->data = malloc(e->size);
|
||||||
|
if (!e->data) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to allocate memory for exponent.\n", __FILE__, __func__, __LINE__);
|
logger(Core, Error, "%s:%s:%d Failed to allocate memory for exponent.\n", __FILE__, __func__, __LINE__);
|
||||||
if (m->data) {
|
|
||||||
free(m->data);
|
free(m->data);
|
||||||
}
|
return ASN_MEM_ERROR;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy((void *)e->data, newbuf, e->size);
|
memcpy((void *)e->data, newbuf, e->size);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return ASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size)
|
||||||
|
{
|
||||||
|
return libtasn_read_cert_pk(data, len, oid, oid_size, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e)
|
||||||
|
{
|
||||||
|
return libtasn_read_cert_pk(data, len, NULL, NULL, m, e);
|
||||||
}
|
}
|
||||||
|
65
asn.h
65
asn.h
@ -16,8 +16,8 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifndef _RDASN_H
|
#ifndef RDASN_H
|
||||||
#define _RDASN_H
|
#define RDASN_H
|
||||||
|
|
||||||
#include <gnutls/gnutls.h>
|
#include <gnutls/gnutls.h>
|
||||||
#include <libtasn1.h>
|
#include <libtasn1.h>
|
||||||
@ -32,14 +32,65 @@ extern "C" {
|
|||||||
#define OID_SHA_WITH_RSA_SIGNATURE "1.3.14.3.2.15"
|
#define OID_SHA_WITH_RSA_SIGNATURE "1.3.14.3.2.15"
|
||||||
#define OID_MD5_WITH_RSA_SIGNATURE "1.3.14.3.2.25"
|
#define OID_MD5_WITH_RSA_SIGNATURE "1.3.14.3.2.25"
|
||||||
|
|
||||||
int init_asn1_lib(void);
|
/**
|
||||||
int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len);
|
* Initialize the ASN.1 library.
|
||||||
|
*
|
||||||
|
* This function initializes the ASN.1 library and should be called before any other ASN.1 functions.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, or a non-zero error code on failure.
|
||||||
|
*/
|
||||||
|
extern int init_asn1_lib(void);
|
||||||
|
|
||||||
int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size);
|
/**
|
||||||
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e);
|
* Encode an RSA public key into DER PKCS#1 format.
|
||||||
|
*
|
||||||
|
* This function encodes an RSA public key into DER PKCS#1 format. The modulus and exponent of the public key are
|
||||||
|
* provided as input, and the encoded key is returned in the output buffer.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* - m: A pointer to a gnutls_datum_t structure that contains the modulus of the public key.
|
||||||
|
* - e: A pointer to a gnutls_datum_t structure that contains the exponent of the public key.
|
||||||
|
* - out: A pointer to the output buffer where the encoded key will be stored.
|
||||||
|
* - out_len: A pointer to an integer that will be set to the length of the encoded key.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, or a non-zero error code on failure.
|
||||||
|
*/
|
||||||
|
extern int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the public key algorithm OID from a DER encoded x.509 certificate.
|
||||||
|
*
|
||||||
|
* This function reads the public key algorithm OID from a DER encoded x.509 certificate. The certificate is provided
|
||||||
|
* as input, and the OID is returned in the output buffer.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* - data: A pointer to the input buffer that contains the DER encoded x.509 certificate.
|
||||||
|
* - len: The length of the input buffer.
|
||||||
|
* - oid: A pointer to the output buffer where the OID will be stored.
|
||||||
|
* - oid_size: A pointer to an integer that will be set to the length of the OID.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, or a non-zero error code on failure.
|
||||||
|
*/
|
||||||
|
extern int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the public key parameters from a DER encoded x.509 certificate.
|
||||||
|
*
|
||||||
|
* This function reads the public key parameters (modulus and exponent) from a DER encoded x.509 certificate. The
|
||||||
|
* certificate is provided as input, and the parameters are returned in the output buffers.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* - data: A pointer to the input buffer that contains the DER encoded x.509 certificate.
|
||||||
|
* - len: The length of the input buffer.
|
||||||
|
* - m: A pointer to a gnutls_datum_t structure that will be set to the modulus of the public key.
|
||||||
|
* - e: A pointer to a gnutls_datum_t structure that will be set to the exponent of the public key.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, or a non-zero error code on failure.
|
||||||
|
*/
|
||||||
|
extern int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _RDASN_H */
|
#endif /* RDASN_H */
|
||||||
|
775
bitmap.c
775
bitmap.c
@ -17,10 +17,6 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* three separate function for speed when decompressing the bitmaps
|
|
||||||
when modifying one function make the change in the others
|
|
||||||
jay.sorg@gmail.com */
|
|
||||||
|
|
||||||
/* indent is confused by this file */
|
/* indent is confused by this file */
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
|
|
||||||
@ -62,410 +58,20 @@
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 1 byte bitmap decompress */
|
#define OPCODE_FILL 0
|
||||||
|
#define OPCODE_MIX 1
|
||||||
|
#define OPCODE_FILL_OR_MIX 2
|
||||||
|
#define OPCODE_COLOUR 3
|
||||||
|
#define OPCODE_COPY 4
|
||||||
|
#define OPCODE_BICOLOUR 8
|
||||||
|
#define OPCODE_WHITE 0xd
|
||||||
|
#define OPCODE_BLACK 0xe
|
||||||
|
|
||||||
|
#define WHITE_PIXEL 0xff
|
||||||
|
#define BLACK_PIXEL 0
|
||||||
|
|
||||||
static RD_BOOL
|
static RD_BOOL
|
||||||
bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size)
|
bitmap_decompress_n(uint8 *output, int width, int height, uint8 *input, int size, int bytes_per_pixel)
|
||||||
{
|
|
||||||
uint8 *end = input + size;
|
|
||||||
uint8 *prevline = NULL, *line = NULL;
|
|
||||||
int opcode, count, offset, isfillormix, x = width;
|
|
||||||
int lastopcode = -1, insertmix = False, bicolour = False;
|
|
||||||
uint8 code;
|
|
||||||
uint8 colour1 = 0, colour2 = 0;
|
|
||||||
uint8 mixmask, mask = 0;
|
|
||||||
uint8 mix = 0xff;
|
|
||||||
int fom_mask = 0;
|
|
||||||
|
|
||||||
while (input < end)
|
|
||||||
{
|
|
||||||
fom_mask = 0;
|
|
||||||
code = CVAL(input);
|
|
||||||
opcode = code >> 4;
|
|
||||||
/* Handle different opcode forms */
|
|
||||||
switch (opcode)
|
|
||||||
{
|
|
||||||
case 0xc:
|
|
||||||
case 0xd:
|
|
||||||
case 0xe:
|
|
||||||
opcode -= 6;
|
|
||||||
count = code & 0xf;
|
|
||||||
offset = 16;
|
|
||||||
break;
|
|
||||||
case 0xf:
|
|
||||||
opcode = code & 0xf;
|
|
||||||
if (opcode < 9)
|
|
||||||
{
|
|
||||||
count = CVAL(input);
|
|
||||||
count |= CVAL(input) << 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = (opcode < 0xb) ? 8 : 1;
|
|
||||||
}
|
|
||||||
offset = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
opcode >>= 1;
|
|
||||||
count = code & 0x1f;
|
|
||||||
offset = 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Handle strange cases for counts */
|
|
||||||
if (offset != 0)
|
|
||||||
{
|
|
||||||
isfillormix = ((opcode == 2) || (opcode == 7));
|
|
||||||
if (count == 0)
|
|
||||||
{
|
|
||||||
if (isfillormix)
|
|
||||||
count = CVAL(input) + 1;
|
|
||||||
else
|
|
||||||
count = CVAL(input) + offset;
|
|
||||||
}
|
|
||||||
else if (isfillormix)
|
|
||||||
{
|
|
||||||
count <<= 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Read preliminary data */
|
|
||||||
switch (opcode)
|
|
||||||
{
|
|
||||||
case 0: /* Fill */
|
|
||||||
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
|
||||||
insertmix = True;
|
|
||||||
break;
|
|
||||||
case 8: /* Bicolour */
|
|
||||||
colour1 = CVAL(input);
|
|
||||||
colour2 = CVAL(input);
|
|
||||||
break;
|
|
||||||
case 3: /* Colour */
|
|
||||||
colour2 = CVAL(input);
|
|
||||||
break;
|
|
||||||
case 6: /* SetMix/Mix */
|
|
||||||
case 7: /* SetMix/FillOrMix */
|
|
||||||
mix = CVAL(input);
|
|
||||||
opcode -= 5;
|
|
||||||
break;
|
|
||||||
case 9: /* FillOrMix_1 */
|
|
||||||
mask = 0x03;
|
|
||||||
opcode = 0x02;
|
|
||||||
fom_mask = 3;
|
|
||||||
break;
|
|
||||||
case 0x0a: /* FillOrMix_2 */
|
|
||||||
mask = 0x05;
|
|
||||||
opcode = 0x02;
|
|
||||||
fom_mask = 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lastopcode = opcode;
|
|
||||||
mixmask = 0;
|
|
||||||
/* Output body */
|
|
||||||
while (count > 0)
|
|
||||||
{
|
|
||||||
if (x >= width)
|
|
||||||
{
|
|
||||||
if (height <= 0)
|
|
||||||
return False;
|
|
||||||
x = 0;
|
|
||||||
height--;
|
|
||||||
prevline = line;
|
|
||||||
line = output + height * width;
|
|
||||||
}
|
|
||||||
switch (opcode)
|
|
||||||
{
|
|
||||||
case 0: /* Fill */
|
|
||||||
if (insertmix)
|
|
||||||
{
|
|
||||||
if (prevline == NULL)
|
|
||||||
line[x] = mix;
|
|
||||||
else
|
|
||||||
line[x] = prevline[x] ^ mix;
|
|
||||||
insertmix = False;
|
|
||||||
count--;
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
if (prevline == NULL)
|
|
||||||
{
|
|
||||||
REPEAT(line[x] = 0)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
REPEAT(line[x] = prevline[x])
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1: /* Mix */
|
|
||||||
if (prevline == NULL)
|
|
||||||
{
|
|
||||||
REPEAT(line[x] = mix)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
REPEAT(line[x] = prevline[x] ^ mix)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2: /* Fill or Mix */
|
|
||||||
if (prevline == NULL)
|
|
||||||
{
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
MASK_UPDATE();
|
|
||||||
if (mask & mixmask)
|
|
||||||
line[x] = mix;
|
|
||||||
else
|
|
||||||
line[x] = 0;
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
MASK_UPDATE();
|
|
||||||
if (mask & mixmask)
|
|
||||||
line[x] = prevline[x] ^ mix;
|
|
||||||
else
|
|
||||||
line[x] = prevline[x];
|
|
||||||
)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3: /* Colour */
|
|
||||||
REPEAT(line[x] = colour2)
|
|
||||||
break;
|
|
||||||
case 4: /* Copy */
|
|
||||||
REPEAT(line[x] = CVAL(input))
|
|
||||||
break;
|
|
||||||
case 8: /* Bicolour */
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
if (bicolour)
|
|
||||||
{
|
|
||||||
line[x] = colour2;
|
|
||||||
bicolour = False;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
line[x] = colour1;
|
|
||||||
bicolour = True; count++;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
break;
|
|
||||||
case 0xd: /* White */
|
|
||||||
REPEAT(line[x] = 0xff)
|
|
||||||
break;
|
|
||||||
case 0xe: /* Black */
|
|
||||||
REPEAT(line[x] = 0)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logger(Core, Warning, "bitmap_decompress(), unhandled bitmap opcode 0x%x", opcode);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 2 byte bitmap decompress */
|
|
||||||
static RD_BOOL
|
|
||||||
bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size)
|
|
||||||
{
|
|
||||||
uint8 *end = input + size;
|
|
||||||
uint16 *prevline = NULL, *line = NULL;
|
|
||||||
int opcode, count, offset, isfillormix, x = width;
|
|
||||||
int lastopcode = -1, insertmix = False, bicolour = False;
|
|
||||||
uint8 code;
|
|
||||||
uint16 colour1 = 0, colour2 = 0;
|
|
||||||
uint8 mixmask, mask = 0;
|
|
||||||
uint16 mix = 0xffff;
|
|
||||||
int fom_mask = 0;
|
|
||||||
|
|
||||||
while (input < end)
|
|
||||||
{
|
|
||||||
fom_mask = 0;
|
|
||||||
code = CVAL(input);
|
|
||||||
opcode = code >> 4;
|
|
||||||
/* Handle different opcode forms */
|
|
||||||
switch (opcode)
|
|
||||||
{
|
|
||||||
case 0xc:
|
|
||||||
case 0xd:
|
|
||||||
case 0xe:
|
|
||||||
opcode -= 6;
|
|
||||||
count = code & 0xf;
|
|
||||||
offset = 16;
|
|
||||||
break;
|
|
||||||
case 0xf:
|
|
||||||
opcode = code & 0xf;
|
|
||||||
if (opcode < 9)
|
|
||||||
{
|
|
||||||
count = CVAL(input);
|
|
||||||
count |= CVAL(input) << 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = (opcode < 0xb) ? 8 : 1;
|
|
||||||
}
|
|
||||||
offset = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
opcode >>= 1;
|
|
||||||
count = code & 0x1f;
|
|
||||||
offset = 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Handle strange cases for counts */
|
|
||||||
if (offset != 0)
|
|
||||||
{
|
|
||||||
isfillormix = ((opcode == 2) || (opcode == 7));
|
|
||||||
if (count == 0)
|
|
||||||
{
|
|
||||||
if (isfillormix)
|
|
||||||
count = CVAL(input) + 1;
|
|
||||||
else
|
|
||||||
count = CVAL(input) + offset;
|
|
||||||
}
|
|
||||||
else if (isfillormix)
|
|
||||||
{
|
|
||||||
count <<= 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Read preliminary data */
|
|
||||||
switch (opcode)
|
|
||||||
{
|
|
||||||
case 0: /* Fill */
|
|
||||||
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
|
||||||
insertmix = True;
|
|
||||||
break;
|
|
||||||
case 8: /* Bicolour */
|
|
||||||
CVAL2(input, colour1);
|
|
||||||
CVAL2(input, colour2);
|
|
||||||
break;
|
|
||||||
case 3: /* Colour */
|
|
||||||
CVAL2(input, colour2);
|
|
||||||
break;
|
|
||||||
case 6: /* SetMix/Mix */
|
|
||||||
case 7: /* SetMix/FillOrMix */
|
|
||||||
CVAL2(input, mix);
|
|
||||||
opcode -= 5;
|
|
||||||
break;
|
|
||||||
case 9: /* FillOrMix_1 */
|
|
||||||
mask = 0x03;
|
|
||||||
opcode = 0x02;
|
|
||||||
fom_mask = 3;
|
|
||||||
break;
|
|
||||||
case 0x0a: /* FillOrMix_2 */
|
|
||||||
mask = 0x05;
|
|
||||||
opcode = 0x02;
|
|
||||||
fom_mask = 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lastopcode = opcode;
|
|
||||||
mixmask = 0;
|
|
||||||
/* Output body */
|
|
||||||
while (count > 0)
|
|
||||||
{
|
|
||||||
if (x >= width)
|
|
||||||
{
|
|
||||||
if (height <= 0)
|
|
||||||
return False;
|
|
||||||
x = 0;
|
|
||||||
height--;
|
|
||||||
prevline = line;
|
|
||||||
line = ((uint16 *) output) + height * width;
|
|
||||||
}
|
|
||||||
switch (opcode)
|
|
||||||
{
|
|
||||||
case 0: /* Fill */
|
|
||||||
if (insertmix)
|
|
||||||
{
|
|
||||||
if (prevline == NULL)
|
|
||||||
line[x] = mix;
|
|
||||||
else
|
|
||||||
line[x] = prevline[x] ^ mix;
|
|
||||||
insertmix = False;
|
|
||||||
count--;
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
if (prevline == NULL)
|
|
||||||
{
|
|
||||||
REPEAT(line[x] = 0)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
REPEAT(line[x] = prevline[x])
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1: /* Mix */
|
|
||||||
if (prevline == NULL)
|
|
||||||
{
|
|
||||||
REPEAT(line[x] = mix)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
REPEAT(line[x] = prevline[x] ^ mix)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2: /* Fill or Mix */
|
|
||||||
if (prevline == NULL)
|
|
||||||
{
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
MASK_UPDATE();
|
|
||||||
if (mask & mixmask)
|
|
||||||
line[x] = mix;
|
|
||||||
else
|
|
||||||
line[x] = 0;
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
MASK_UPDATE();
|
|
||||||
if (mask & mixmask)
|
|
||||||
line[x] = prevline[x] ^ mix;
|
|
||||||
else
|
|
||||||
line[x] = prevline[x];
|
|
||||||
)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3: /* Colour */
|
|
||||||
REPEAT(line[x] = colour2)
|
|
||||||
break;
|
|
||||||
case 4: /* Copy */
|
|
||||||
REPEAT(CVAL2(input, line[x]))
|
|
||||||
break;
|
|
||||||
case 8: /* Bicolour */
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
if (bicolour)
|
|
||||||
{
|
|
||||||
line[x] = colour2;
|
|
||||||
bicolour = False;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
line[x] = colour1;
|
|
||||||
bicolour = True;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
break;
|
|
||||||
case 0xd: /* White */
|
|
||||||
REPEAT(line[x] = 0xffff)
|
|
||||||
break;
|
|
||||||
case 0xe: /* Black */
|
|
||||||
REPEAT(line[x] = 0)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logger(Core, Warning, "bitmap_decompress2(), unhandled bitmap opcode 0x%x", opcode);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3 byte bitmap decompress */
|
|
||||||
static RD_BOOL
|
|
||||||
bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)
|
|
||||||
{
|
{
|
||||||
uint8 *end = input + size;
|
uint8 *end = input + size;
|
||||||
uint8 *prevline = NULL, *line = NULL;
|
uint8 *prevline = NULL, *line = NULL;
|
||||||
@ -477,14 +83,12 @@ bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int siz
|
|||||||
uint8 mix[3] = {0xff, 0xff, 0xff};
|
uint8 mix[3] = {0xff, 0xff, 0xff};
|
||||||
int fom_mask = 0;
|
int fom_mask = 0;
|
||||||
|
|
||||||
while (input < end)
|
while (input < end) {
|
||||||
{
|
|
||||||
fom_mask = 0;
|
fom_mask = 0;
|
||||||
code = CVAL(input);
|
code = CVAL(input);
|
||||||
opcode = code >> 4;
|
opcode = code >> 4;
|
||||||
/* Handle different opcode forms */
|
/* Handle different opcode forms */
|
||||||
switch (opcode)
|
switch (opcode) {
|
||||||
{
|
|
||||||
case 0xc:
|
case 0xc:
|
||||||
case 0xd:
|
case 0xd:
|
||||||
case 0xe:
|
case 0xe:
|
||||||
@ -494,15 +98,11 @@ bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int siz
|
|||||||
break;
|
break;
|
||||||
case 0xf:
|
case 0xf:
|
||||||
opcode = code & 0xf;
|
opcode = code & 0xf;
|
||||||
if (opcode < 9)
|
if (opcode < 9) {
|
||||||
{
|
|
||||||
count = CVAL(input);
|
count = CVAL(input);
|
||||||
count |= CVAL(input) << 8;
|
count |= CVAL(input) << 8;
|
||||||
}
|
} else {
|
||||||
else
|
count = (opcode < 0xb) ? 8 : 1;
|
||||||
{
|
|
||||||
count = (opcode <
|
|
||||||
0xb) ? 8 : 1;
|
|
||||||
}
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
break;
|
break;
|
||||||
@ -513,239 +113,187 @@ bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int siz
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Handle strange cases for counts */
|
/* Handle strange cases for counts */
|
||||||
if (offset != 0)
|
if (offset != 0) {
|
||||||
{
|
isfillormix = ((opcode == OPCODE_FILL_OR_MIX) || (opcode == 7));
|
||||||
isfillormix = ((opcode == 2) || (opcode == 7));
|
if (count == 0) {
|
||||||
if (count == 0)
|
if (isfillormix) {
|
||||||
{
|
|
||||||
if (isfillormix)
|
|
||||||
count = CVAL(input) + 1;
|
count = CVAL(input) + 1;
|
||||||
else
|
} else {
|
||||||
count = CVAL(input) + offset;
|
count = CVAL(input) + offset;
|
||||||
}
|
}
|
||||||
else if (isfillormix)
|
} else if (isfillormix) {
|
||||||
{
|
|
||||||
count <<= 3;
|
count <<= 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Read preliminary data */
|
/* Read preliminary data */
|
||||||
switch (opcode)
|
switch (opcode) {
|
||||||
{
|
case OPCODE_FILL:
|
||||||
case 0: /* Fill */
|
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL))) {
|
||||||
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
|
||||||
insertmix = True;
|
insertmix = True;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 8: /* Bicolour */
|
case OPCODE_BICOLOUR:
|
||||||
colour1[0] = CVAL(input);
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
colour1[1] = CVAL(input);
|
colour1[i] = CVAL(input);
|
||||||
colour1[2] = CVAL(input);
|
colour2[i] = CVAL(input);
|
||||||
colour2[0] = CVAL(input);
|
}
|
||||||
colour2[1] = CVAL(input);
|
|
||||||
colour2[2] = CVAL(input);
|
|
||||||
break;
|
break;
|
||||||
case 3: /* Colour */
|
case OPCODE_COLOUR:
|
||||||
colour2[0] = CVAL(input);
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
colour2[1] = CVAL(input);
|
colour2[i] = CVAL(input);
|
||||||
colour2[2] = CVAL(input);
|
}
|
||||||
break;
|
break;
|
||||||
case 6: /* SetMix/Mix */
|
case 6: /* SetMix/Mix */
|
||||||
case 7: /* SetMix/FillOrMix */
|
case 7: /* SetMix/FillOrMix */
|
||||||
mix[0] = CVAL(input);
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
mix[1] = CVAL(input);
|
mix[i] = CVAL(input);
|
||||||
mix[2] = CVAL(input);
|
}
|
||||||
opcode -= 5;
|
opcode -= 5;
|
||||||
break;
|
break;
|
||||||
case 9: /* FillOrMix_1 */
|
case 9: /* FillOrMix_1 */
|
||||||
mask = 0x03;
|
mask = 0x03;
|
||||||
opcode = 0x02;
|
opcode = OPCODE_FILL_OR_MIX;
|
||||||
fom_mask = 3;
|
fom_mask = 3;
|
||||||
break;
|
break;
|
||||||
case 0x0a: /* FillOrMix_2 */
|
case 0x0a: /* FillOrMix_2 */
|
||||||
mask = 0x05;
|
mask = 0x05;
|
||||||
opcode = 0x02;
|
opcode = OPCODE_FILL_OR_MIX;
|
||||||
fom_mask = 5;
|
fom_mask = 5;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lastopcode = opcode;
|
lastopcode = opcode;
|
||||||
mixmask = 0;
|
mixmask = 0;
|
||||||
/* Output body */
|
/* Output body */
|
||||||
while (count > 0)
|
while (count > 0) {
|
||||||
{
|
if (x >= width) {
|
||||||
if (x >= width)
|
if (height <= 0) {
|
||||||
{
|
|
||||||
if (height <= 0)
|
|
||||||
return False;
|
return False;
|
||||||
|
}
|
||||||
x = 0;
|
x = 0;
|
||||||
height--;
|
height--;
|
||||||
prevline = line;
|
prevline = line;
|
||||||
line = output + height * (width * 3);
|
line = output + height * (width * bytes_per_pixel);
|
||||||
}
|
}
|
||||||
switch (opcode)
|
switch (opcode) {
|
||||||
{
|
case OPCODE_FILL:
|
||||||
case 0: /* Fill */
|
if (insertmix) {
|
||||||
if (insertmix)
|
if (prevline == NULL) {
|
||||||
{
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
if (prevline == NULL)
|
line[x * bytes_per_pixel + i] = mix[i];
|
||||||
{
|
}
|
||||||
line[x * 3] = mix[0];
|
} else {
|
||||||
line[x * 3 + 1] = mix[1];
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
line[x * 3 + 2] = mix[2];
|
line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i] ^ mix[i];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
line[x * 3] =
|
|
||||||
prevline[x * 3] ^ mix[0];
|
|
||||||
line[x * 3 + 1] =
|
|
||||||
prevline[x * 3 + 1] ^ mix[1];
|
|
||||||
line[x * 3 + 2] =
|
|
||||||
prevline[x * 3 + 2] ^ mix[2];
|
|
||||||
}
|
}
|
||||||
insertmix = False;
|
insertmix = False;
|
||||||
count--;
|
count--;
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
if (prevline == NULL)
|
if (prevline == NULL) {
|
||||||
{
|
REPEAT(
|
||||||
REPEAT
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
(
|
line[x * bytes_per_pixel + i] = 0;
|
||||||
line[x * 3] = 0;
|
}
|
||||||
line[x * 3 + 1] = 0;
|
)
|
||||||
line[x * 3 + 2] = 0;
|
} else {
|
||||||
)
|
REPEAT(
|
||||||
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
|
line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
line[x * 3] = prevline[x * 3];
|
|
||||||
line[x * 3 + 1] = prevline[x * 3 + 1];
|
|
||||||
line[x * 3 + 2] = prevline[x * 3 + 2];
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1: /* Mix */
|
case OPCODE_MIX:
|
||||||
if (prevline == NULL)
|
if (prevline == NULL) {
|
||||||
{
|
REPEAT(
|
||||||
REPEAT
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
(
|
line[x * bytes_per_pixel + i] = mix[i];
|
||||||
line[x * 3] = mix[0];
|
}
|
||||||
line[x * 3 + 1] = mix[1];
|
)
|
||||||
line[x * 3 + 2] = mix[2];
|
} else {
|
||||||
)
|
REPEAT(
|
||||||
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
|
line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i] ^ mix[i];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
line[x * 3] =
|
|
||||||
prevline[x * 3] ^ mix[0];
|
|
||||||
line[x * 3 + 1] =
|
|
||||||
prevline[x * 3 + 1] ^ mix[1];
|
|
||||||
line[x * 3 + 2] =
|
|
||||||
prevline[x * 3 + 2] ^ mix[2];
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2: /* Fill or Mix */
|
case OPCODE_FILL_OR_MIX:
|
||||||
if (prevline == NULL)
|
if (prevline == NULL) {
|
||||||
{
|
REPEAT(
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
MASK_UPDATE();
|
MASK_UPDATE();
|
||||||
if (mask & mixmask)
|
if (mask & mixmask) {
|
||||||
{
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
line[x * 3] = mix[0];
|
line[x * bytes_per_pixel + i] = mix[i];
|
||||||
line[x * 3 + 1] = mix[1];
|
}
|
||||||
line[x * 3 + 2] = mix[2];
|
} else {
|
||||||
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
|
line[x * bytes_per_pixel + i] = 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
line[x * 3] = 0;
|
|
||||||
line[x * 3 + 1] = 0;
|
|
||||||
line[x * 3 + 2] = 0;
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else
|
REPEAT(
|
||||||
{
|
|
||||||
REPEAT
|
|
||||||
(
|
|
||||||
MASK_UPDATE();
|
MASK_UPDATE();
|
||||||
if (mask & mixmask)
|
if (mask & mixmask) {
|
||||||
{
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
line[x * 3] =
|
line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i] ^ mix[i];
|
||||||
prevline[x * 3] ^ mix [0];
|
}
|
||||||
line[x * 3 + 1] =
|
} else {
|
||||||
prevline[x * 3 + 1] ^ mix [1];
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
line[x * 3 + 2] =
|
line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i];
|
||||||
prevline[x * 3 + 2] ^ mix [2];
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
line[x * 3] =
|
|
||||||
prevline[x * 3];
|
|
||||||
line[x * 3 + 1] =
|
|
||||||
prevline[x * 3 + 1];
|
|
||||||
line[x * 3 + 2] =
|
|
||||||
prevline[x * 3 + 2];
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: /* Colour */
|
case OPCODE_COLOUR:
|
||||||
REPEAT
|
REPEAT(
|
||||||
(
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
line[x * 3] = colour2 [0];
|
line[x * bytes_per_pixel + i] = colour2[i];
|
||||||
line[x * 3 + 1] = colour2 [1];
|
}
|
||||||
line[x * 3 + 2] = colour2 [2];
|
|
||||||
)
|
)
|
||||||
break;
|
break;
|
||||||
case 4: /* Copy */
|
case OPCODE_COPY:
|
||||||
REPEAT
|
REPEAT(
|
||||||
(
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
line[x * 3] = CVAL(input);
|
line[x * bytes_per_pixel + i] = CVAL(input);
|
||||||
line[x * 3 + 1] = CVAL(input);
|
}
|
||||||
line[x * 3 + 2] = CVAL(input);
|
|
||||||
)
|
)
|
||||||
break;
|
break;
|
||||||
case 8: /* Bicolour */
|
case OPCODE_BICOLOUR:
|
||||||
REPEAT
|
REPEAT(
|
||||||
(
|
if (bicolour) {
|
||||||
if (bicolour)
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
{
|
line[x * bytes_per_pixel + i] = colour2[i];
|
||||||
line[x * 3] = colour2[0];
|
}
|
||||||
line[x * 3 + 1] = colour2[1];
|
|
||||||
line[x * 3 + 2] = colour2[2];
|
|
||||||
bicolour = False;
|
bicolour = False;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
|
line[x * bytes_per_pixel + i] = colour1[i];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
line[x * 3] = colour1[0];
|
|
||||||
line[x * 3 + 1] = colour1[1];
|
|
||||||
line[x * 3 + 2] = colour1[2];
|
|
||||||
bicolour = True;
|
bicolour = True;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
break;
|
break;
|
||||||
case 0xd: /* White */
|
case OPCODE_WHITE:
|
||||||
REPEAT
|
REPEAT(
|
||||||
(
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
line[x * 3] = 0xff;
|
line[x * bytes_per_pixel + i] = WHITE_PIXEL;
|
||||||
line[x * 3 + 1] = 0xff;
|
}
|
||||||
line[x * 3 + 2] = 0xff;
|
|
||||||
)
|
)
|
||||||
break;
|
break;
|
||||||
case 0xe: /* Black */
|
case OPCODE_BLACK:
|
||||||
REPEAT
|
REPEAT(
|
||||||
(
|
for (int i = 0; i < bytes_per_pixel; i++) {
|
||||||
line[x * 3] = 0;
|
line[x * bytes_per_pixel + i] = BLACK_PIXEL;
|
||||||
line[x * 3 + 1] = 0;
|
}
|
||||||
line[x * 3 + 2] = 0;
|
|
||||||
)
|
)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger(Core, Warning, "bitmap_decompress3(), unhandled bitmap opcode 0x%x", opcode);
|
logger(Core, Warning, "bitmap_decompress_n(), unhandled bitmap opcode 0x%x", opcode);
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -755,7 +303,7 @@ bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int siz
|
|||||||
|
|
||||||
/* decompress a colour plane */
|
/* decompress a colour plane */
|
||||||
static int
|
static int
|
||||||
process_plane(uint8 * in, int width, int height, uint8 * out, int size)
|
process_plane(uint8 *in, int width, int height, uint8 *out, int size)
|
||||||
{
|
{
|
||||||
UNUSED(size);
|
UNUSED(size);
|
||||||
int indexw;
|
int indexw;
|
||||||
@ -766,75 +314,61 @@ process_plane(uint8 * in, int width, int height, uint8 * out, int size)
|
|||||||
int color;
|
int color;
|
||||||
int x;
|
int x;
|
||||||
int revcode;
|
int revcode;
|
||||||
uint8 * last_line;
|
uint8 *last_line;
|
||||||
uint8 * this_line;
|
uint8 *this_line;
|
||||||
uint8 * org_in;
|
uint8 *org_in;
|
||||||
uint8 * org_out;
|
uint8 *org_out;
|
||||||
|
|
||||||
org_in = in;
|
org_in = in;
|
||||||
org_out = out;
|
org_out = out;
|
||||||
last_line = 0;
|
last_line = 0;
|
||||||
indexh = 0;
|
indexh = 0;
|
||||||
while (indexh < height)
|
while (indexh < height) {
|
||||||
{
|
|
||||||
out = (org_out + width * height * 4) - ((indexh + 1) * width * 4);
|
out = (org_out + width * height * 4) - ((indexh + 1) * width * 4);
|
||||||
color = 0;
|
color = 0;
|
||||||
this_line = out;
|
this_line = out;
|
||||||
indexw = 0;
|
indexw = 0;
|
||||||
if (last_line == 0)
|
if (last_line == 0) {
|
||||||
{
|
while (indexw < width) {
|
||||||
while (indexw < width)
|
|
||||||
{
|
|
||||||
code = CVAL(in);
|
code = CVAL(in);
|
||||||
replen = code & 0xf;
|
replen = code & 0xf;
|
||||||
collen = (code >> 4) & 0xf;
|
collen = (code >> 4) & 0xf;
|
||||||
revcode = (replen << 4) | collen;
|
revcode = (replen << 4) | collen;
|
||||||
if ((revcode <= 47) && (revcode >= 16))
|
if ((revcode <= 47) && (revcode >= 16)) {
|
||||||
{
|
|
||||||
replen = revcode;
|
replen = revcode;
|
||||||
collen = 0;
|
collen = 0;
|
||||||
}
|
}
|
||||||
while (indexw < width && collen > 0)
|
while (indexw < width && collen > 0) {
|
||||||
{
|
|
||||||
color = CVAL(in);
|
color = CVAL(in);
|
||||||
*out = color;
|
*out = color;
|
||||||
out += 4;
|
out += 4;
|
||||||
indexw++;
|
indexw++;
|
||||||
collen--;
|
collen--;
|
||||||
}
|
}
|
||||||
while (indexw < width && replen > 0)
|
while (indexw < width && replen > 0) {
|
||||||
{
|
|
||||||
*out = color;
|
*out = color;
|
||||||
out += 4;
|
out += 4;
|
||||||
indexw++;
|
indexw++;
|
||||||
replen--;
|
replen--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
while (indexw < width) {
|
||||||
{
|
|
||||||
while (indexw < width)
|
|
||||||
{
|
|
||||||
code = CVAL(in);
|
code = CVAL(in);
|
||||||
replen = code & 0xf;
|
replen = code & 0xf;
|
||||||
collen = (code >> 4) & 0xf;
|
collen = (code >> 4) & 0xf;
|
||||||
revcode = (replen << 4) | collen;
|
revcode = (replen << 4) | collen;
|
||||||
if ((revcode <= 47) && (revcode >= 16))
|
if ((revcode <= 47) && (revcode >= 16)) {
|
||||||
{
|
|
||||||
replen = revcode;
|
replen = revcode;
|
||||||
collen = 0;
|
collen = 0;
|
||||||
}
|
}
|
||||||
while (indexw < width && collen > 0)
|
while (indexw < width && collen > 0) {
|
||||||
{
|
|
||||||
x = CVAL(in);
|
x = CVAL(in);
|
||||||
if (x & 1)
|
if (x & 1) {
|
||||||
{
|
|
||||||
x = x >> 1;
|
x = x >> 1;
|
||||||
x = x + 1;
|
x = x + 1;
|
||||||
color = -x;
|
color = -x;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
x = x >> 1;
|
x = x >> 1;
|
||||||
color = x;
|
color = x;
|
||||||
}
|
}
|
||||||
@ -844,8 +378,7 @@ process_plane(uint8 * in, int width, int height, uint8 * out, int size)
|
|||||||
indexw++;
|
indexw++;
|
||||||
collen--;
|
collen--;
|
||||||
}
|
}
|
||||||
while (indexw < width && replen > 0)
|
while (indexw < width && replen > 0) {
|
||||||
{
|
|
||||||
x = last_line[indexw * 4] + color;
|
x = last_line[indexw * 4] + color;
|
||||||
*out = x;
|
*out = x;
|
||||||
out += 4;
|
out += 4;
|
||||||
@ -857,20 +390,19 @@ process_plane(uint8 * in, int width, int height, uint8 * out, int size)
|
|||||||
indexh++;
|
indexh++;
|
||||||
last_line = this_line;
|
last_line = this_line;
|
||||||
}
|
}
|
||||||
return (int) (in - org_in);
|
return (int)(in - org_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4 byte bitmap decompress */
|
/* 4 byte bitmap decompress */
|
||||||
static RD_BOOL
|
static RD_BOOL
|
||||||
bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size)
|
bitmap_decompress4(uint8 *output, int width, int height, uint8 *input, int size)
|
||||||
{
|
{
|
||||||
int code;
|
int code;
|
||||||
int bytes_pro;
|
int bytes_pro;
|
||||||
int total_pro;
|
int total_pro;
|
||||||
|
|
||||||
code = CVAL(input);
|
code = CVAL(input);
|
||||||
if (code != 0x10)
|
if (code != 0x10) {
|
||||||
{
|
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
total_pro = 1;
|
total_pro = 1;
|
||||||
@ -890,20 +422,15 @@ bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int siz
|
|||||||
|
|
||||||
/* main decompress function */
|
/* main decompress function */
|
||||||
RD_BOOL
|
RD_BOOL
|
||||||
bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp)
|
bitmap_decompress(uint8 *output, int width, int height, uint8 *input, int size, int Bpp)
|
||||||
{
|
{
|
||||||
RD_BOOL rv = False;
|
RD_BOOL rv = False;
|
||||||
|
|
||||||
switch (Bpp)
|
switch (Bpp) {
|
||||||
{
|
|
||||||
case 1:
|
case 1:
|
||||||
rv = bitmap_decompress1(output, width, height, input, size);
|
|
||||||
break;
|
|
||||||
case 2:
|
case 2:
|
||||||
rv = bitmap_decompress2(output, width, height, input, size);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
rv = bitmap_decompress3(output, width, height, input, size);
|
rv = bitmap_decompress_n(output, width, height, input, size, Bpp);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
rv = bitmap_decompress4(output, width, height, input, size);
|
rv = bitmap_decompress4(output, width, height, input, size);
|
||||||
|
235
cache.c
235
cache.c
@ -20,6 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rdesktop.h"
|
#include "rdesktop.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/* BITMAP CACHE */
|
/* BITMAP CACHE */
|
||||||
extern int g_pstcache_fd[];
|
extern int g_pstcache_fd[];
|
||||||
@ -30,22 +33,15 @@ extern int g_pstcache_fd[];
|
|||||||
#define NOT_SET -1
|
#define NOT_SET -1
|
||||||
#define IS_SET(idx) (idx >= 0)
|
#define IS_SET(idx) (idx >= 0)
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest CPU utilisation but using
|
|
||||||
* a positive value will hopefully result in less frequently used bitmaps having a greater chance
|
|
||||||
* of being evicted from the cache, and thereby reducing the need to load bitmaps from disk.
|
|
||||||
* (Jeroen)
|
|
||||||
*/
|
|
||||||
#define BUMP_COUNT 40
|
#define BUMP_COUNT 40
|
||||||
|
|
||||||
struct bmpcache_entry
|
typedef struct bmpcache_entry {
|
||||||
{
|
|
||||||
RD_HBITMAP bitmap;
|
RD_HBITMAP bitmap;
|
||||||
sint16 previous;
|
int16_t previous;
|
||||||
sint16 next;
|
int16_t next;
|
||||||
};
|
} bmpcache_entry_t;
|
||||||
|
|
||||||
static struct bmpcache_entry g_bmpcache[3][0xa00];
|
static bmpcache_entry_t g_bmpcache[3][0xa00];
|
||||||
static RD_HBITMAP g_volatile_bc[3];
|
static RD_HBITMAP g_volatile_bc[3];
|
||||||
|
|
||||||
static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
|
static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
|
||||||
@ -54,16 +50,13 @@ static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET };
|
|||||||
static int g_bmpcache_count[3];
|
static int g_bmpcache_count[3];
|
||||||
|
|
||||||
/* Setup the bitmap cache lru/mru linked list */
|
/* Setup the bitmap cache lru/mru linked list */
|
||||||
void
|
void cache_rebuild_bmpcache_linked_list(uint8_t id, int16_t *idx, int count) {
|
||||||
cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
|
|
||||||
{
|
|
||||||
int n = count, c = 0;
|
int n = count, c = 0;
|
||||||
sint16 n_idx;
|
int16_t n_idx;
|
||||||
|
|
||||||
/* find top, skip evicted bitmaps */
|
/* find top, skip evicted bitmaps */
|
||||||
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
|
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
|
||||||
if (n < 0)
|
if (n < 0) {
|
||||||
{
|
|
||||||
g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET;
|
g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -74,8 +67,7 @@ cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
|
|||||||
c++;
|
c++;
|
||||||
|
|
||||||
/* link list */
|
/* link list */
|
||||||
while (n >= 0)
|
while (n >= 0) {
|
||||||
{
|
|
||||||
/* skip evicted bitmaps */
|
/* skip evicted bitmaps */
|
||||||
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
|
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
|
||||||
|
|
||||||
@ -91,19 +83,16 @@ cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
|
|||||||
g_bmpcache[id][n_idx].previous = NOT_SET;
|
g_bmpcache[id][n_idx].previous = NOT_SET;
|
||||||
g_bmpcache_lru[id] = n_idx;
|
g_bmpcache_lru[id] = n_idx;
|
||||||
|
|
||||||
if (c != g_bmpcache_count[id])
|
if (c != g_bmpcache_count[id]) {
|
||||||
{
|
|
||||||
logger(Core, Error,
|
logger(Core, Error,
|
||||||
"cache_rebuild_bmpcache_linked_list(), %d in bitmap cache linked list, %d in ui cache...",
|
"cache_rebuild_bmpcache_linked_list(), %d in bitmap cache linked list, %d in ui cache...",
|
||||||
c, g_bmpcache_count[id]);
|
c, g_bmpcache_count[id]);
|
||||||
exit(EX_SOFTWARE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move a bitmap to a new position in the linked list. */
|
/* Move a bitmap to a new position in the linked list. */
|
||||||
void
|
void cache_bump_bitmap(uint8_t id, uint16_t idx, int bump) {
|
||||||
cache_bump_bitmap(uint8 id, uint16 idx, int bump)
|
|
||||||
{
|
|
||||||
int p_idx, n_idx, n;
|
int p_idx, n_idx, n;
|
||||||
|
|
||||||
if (!IS_PERSISTENT(id))
|
if (!IS_PERSISTENT(id))
|
||||||
@ -117,8 +106,7 @@ cache_bump_bitmap(uint8 id, uint16 idx, int bump)
|
|||||||
n_idx = g_bmpcache[id][idx].next;
|
n_idx = g_bmpcache[id][idx].next;
|
||||||
p_idx = g_bmpcache[id][idx].previous;
|
p_idx = g_bmpcache[id][idx].previous;
|
||||||
|
|
||||||
if (IS_SET(n_idx))
|
if (IS_SET(n_idx)) {
|
||||||
{
|
|
||||||
/* remove */
|
/* remove */
|
||||||
--g_bmpcache_count[id];
|
--g_bmpcache_count[id];
|
||||||
if (IS_SET(p_idx))
|
if (IS_SET(p_idx))
|
||||||
@ -129,23 +117,17 @@ cache_bump_bitmap(uint8 id, uint16 idx, int bump)
|
|||||||
g_bmpcache[id][n_idx].previous = p_idx;
|
g_bmpcache[id][n_idx].previous = p_idx;
|
||||||
else
|
else
|
||||||
g_bmpcache_mru[id] = p_idx;
|
g_bmpcache_mru[id] = p_idx;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
p_idx = NOT_SET;
|
p_idx = NOT_SET;
|
||||||
n_idx = g_bmpcache_lru[id];
|
n_idx = g_bmpcache_lru[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bump >= 0)
|
if (bump >= 0) {
|
||||||
{
|
for (n = 0; n < bump && IS_SET(n_idx); n++) {
|
||||||
for (n = 0; n < bump && IS_SET(n_idx); n++)
|
|
||||||
{
|
|
||||||
p_idx = n_idx;
|
p_idx = n_idx;
|
||||||
n_idx = g_bmpcache[id][p_idx].next;
|
n_idx = g_bmpcache[id][p_idx].next;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
p_idx = g_bmpcache_mru[id];
|
p_idx = g_bmpcache_mru[id];
|
||||||
n_idx = NOT_SET;
|
n_idx = NOT_SET;
|
||||||
}
|
}
|
||||||
@ -167,10 +149,8 @@ cache_bump_bitmap(uint8 id, uint16 idx, int bump)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Evict the least-recently used bitmap from the cache */
|
/* Evict the least-recently used bitmap from the cache */
|
||||||
void
|
void cache_evict_bitmap(uint8_t id) {
|
||||||
cache_evict_bitmap(uint8 id)
|
uint16_t idx;
|
||||||
{
|
|
||||||
uint16 idx;
|
|
||||||
int n_idx;
|
int n_idx;
|
||||||
|
|
||||||
if (!IS_PERSISTENT(id))
|
if (!IS_PERSISTENT(id))
|
||||||
@ -193,21 +173,15 @@ cache_evict_bitmap(uint8 id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve a bitmap from the cache */
|
/* Retrieve a bitmap from the cache */
|
||||||
RD_HBITMAP
|
RD_HBITMAP cache_get_bitmap(uint8_t id, uint16_t idx) {
|
||||||
cache_get_bitmap(uint8 id, uint16 idx)
|
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0]))) {
|
||||||
{
|
if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx)) {
|
||||||
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
|
|
||||||
{
|
|
||||||
if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx))
|
|
||||||
{
|
|
||||||
if (IS_PERSISTENT(id))
|
if (IS_PERSISTENT(id))
|
||||||
cache_bump_bitmap(id, idx, BUMP_COUNT);
|
cache_bump_bitmap(id, idx, BUMP_COUNT);
|
||||||
|
|
||||||
return g_bmpcache[id][idx].bitmap;
|
return g_bmpcache[id][idx].bitmap;
|
||||||
}
|
}
|
||||||
}
|
} else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff)) {
|
||||||
else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
|
|
||||||
{
|
|
||||||
return g_volatile_bc[id];
|
return g_volatile_bc[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,20 +191,16 @@ cache_get_bitmap(uint8 id, uint16 idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Store a bitmap in the cache */
|
/* Store a bitmap in the cache */
|
||||||
void
|
void cache_put_bitmap(uint8_t id, uint16_t idx, RD_HBITMAP bitmap) {
|
||||||
cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
|
|
||||||
{
|
|
||||||
RD_HBITMAP old;
|
RD_HBITMAP old;
|
||||||
|
|
||||||
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
|
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0]))) {
|
||||||
{
|
|
||||||
old = g_bmpcache[id][idx].bitmap;
|
old = g_bmpcache[id][idx].bitmap;
|
||||||
if (old != NULL)
|
if (old != NULL)
|
||||||
ui_destroy_bitmap(old);
|
ui_destroy_bitmap(old);
|
||||||
g_bmpcache[id][idx].bitmap = bitmap;
|
g_bmpcache[id][idx].bitmap = bitmap;
|
||||||
|
|
||||||
if (IS_PERSISTENT(id))
|
if (IS_PERSISTENT(id)) {
|
||||||
{
|
|
||||||
if (old == NULL)
|
if (old == NULL)
|
||||||
g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
|
g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
|
||||||
|
|
||||||
@ -238,35 +208,27 @@ cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
|
|||||||
if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS)
|
if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS)
|
||||||
cache_evict_bitmap(id);
|
cache_evict_bitmap(id);
|
||||||
}
|
}
|
||||||
}
|
} else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff)) {
|
||||||
else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
|
|
||||||
{
|
|
||||||
old = g_volatile_bc[id];
|
old = g_volatile_bc[id];
|
||||||
if (old != NULL)
|
if (old != NULL)
|
||||||
ui_destroy_bitmap(old);
|
ui_destroy_bitmap(old);
|
||||||
g_volatile_bc[id] = bitmap;
|
g_volatile_bc[id] = bitmap;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
logger(Core, Error, "cache_put_bitmap(), failed, id=%d, idx=%d\n", id, idx);
|
logger(Core, Error, "cache_put_bitmap(), failed, id=%d, idx=%d\n", id, idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Updates the persistent bitmap cache MRU information on exit */
|
/* Updates the persistent bitmap cache MRU information on exit */
|
||||||
void
|
void cache_save_state(void) {
|
||||||
cache_save_state(void)
|
uint32_t id = 0, t = 0;
|
||||||
{
|
|
||||||
uint32 id = 0, t = 0;
|
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
|
for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
|
||||||
if (IS_PERSISTENT(id))
|
if (IS_PERSISTENT(id)) {
|
||||||
{
|
|
||||||
logger(Core, Debug,
|
logger(Core, Debug,
|
||||||
"cache_save_state(), saving cache state for bitmap cache %d", id);
|
"cache_save_state(), saving cache state for bitmap cache %d", id);
|
||||||
idx = g_bmpcache_lru[id];
|
idx = g_bmpcache_lru[id];
|
||||||
while (idx >= 0)
|
while (idx >= 0) {
|
||||||
{
|
|
||||||
pstcache_touch_bitmap(id, idx, ++t);
|
pstcache_touch_bitmap(id, idx, ++t);
|
||||||
idx = g_bmpcache[id][idx].next;
|
idx = g_bmpcache[id][idx].next;
|
||||||
}
|
}
|
||||||
@ -274,19 +236,13 @@ cache_save_state(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* FONT CACHE */
|
/* FONT CACHE */
|
||||||
static FONTGLYPH g_fontcache[12][256];
|
static FONTGLYPH g_fontcache[12][256];
|
||||||
|
|
||||||
/* Retrieve a glyph from the font cache */
|
/* Retrieve a glyph from the font cache */
|
||||||
FONTGLYPH *
|
FONTGLYPH *cache_get_font(uint8_t font, uint16_t character) {
|
||||||
cache_get_font(uint8 font, uint16 character)
|
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0]))) {
|
||||||
{
|
FONTGLYPH *glyph = &g_fontcache[font][character];
|
||||||
FONTGLYPH *glyph;
|
|
||||||
|
|
||||||
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
|
|
||||||
{
|
|
||||||
glyph = &g_fontcache[font][character];
|
|
||||||
if (glyph->pixmap != NULL)
|
if (glyph->pixmap != NULL)
|
||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
@ -296,15 +252,10 @@ cache_get_font(uint8 font, uint16 character)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Store a glyph in the font cache */
|
/* Store a glyph in the font cache */
|
||||||
void
|
void cache_put_font(uint8_t font, uint16_t character, uint16_t offset,
|
||||||
cache_put_font(uint8 font, uint16 character, uint16 offset,
|
uint16_t baseline, uint16_t width, uint16_t height, RD_HGLYPH pixmap) {
|
||||||
uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
|
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0]))) {
|
||||||
{
|
FONTGLYPH *glyph = &g_fontcache[font][character];
|
||||||
FONTGLYPH *glyph;
|
|
||||||
|
|
||||||
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
|
|
||||||
{
|
|
||||||
glyph = &g_fontcache[font][character];
|
|
||||||
if (glyph->pixmap != NULL)
|
if (glyph->pixmap != NULL)
|
||||||
ui_destroy_glyph(glyph->pixmap);
|
ui_destroy_glyph(glyph->pixmap);
|
||||||
|
|
||||||
@ -313,56 +264,44 @@ cache_put_font(uint8 font, uint16 character, uint16 offset,
|
|||||||
glyph->width = width;
|
glyph->width = width;
|
||||||
glyph->height = height;
|
glyph->height = height;
|
||||||
glyph->pixmap = pixmap;
|
glyph->pixmap = pixmap;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
logger(Core, Error, "cache_put_font(), failed, font=%d, char=%d", font, character);
|
logger(Core, Error, "cache_put_font(), failed, font=%d, char=%d", font, character);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TEXT CACHE */
|
/* TEXT CACHE */
|
||||||
static DATABLOB g_textcache[256];
|
static DATABLOB g_textcache[256];
|
||||||
|
|
||||||
/* Retrieve a text item from the cache */
|
/* Retrieve a text item from the cache */
|
||||||
DATABLOB *
|
DATABLOB *cache_get_text(uint8_t cache_id) {
|
||||||
cache_get_text(uint8 cache_id)
|
return &g_textcache[cache_id];
|
||||||
{
|
|
||||||
DATABLOB *text;
|
|
||||||
|
|
||||||
text = &g_textcache[cache_id];
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store a text item in the cache */
|
/* Store a text item in the cache */
|
||||||
void
|
void cache_put_text(uint8_t cache_id, void *data, int length) {
|
||||||
cache_put_text(uint8 cache_id, void *data, int length)
|
if (cache_id < NUM_ELEMENTS(g_textcache)) {
|
||||||
{
|
DATABLOB *text = &g_textcache[cache_id];
|
||||||
DATABLOB *text;
|
|
||||||
|
|
||||||
text = &g_textcache[cache_id];
|
|
||||||
if (text->data != NULL)
|
if (text->data != NULL)
|
||||||
xfree(text->data);
|
xfree(text->data);
|
||||||
text->data = xmalloc(length);
|
text->data = xmalloc(length);
|
||||||
text->size = length;
|
text->size = length;
|
||||||
memcpy(text->data, data, length);
|
memcpy(text->data, data, length);
|
||||||
|
} else {
|
||||||
|
logger(Core, Error, "cache_put_text(), failed, cache_id=%d", cache_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* DESKTOP CACHE */
|
/* DESKTOP CACHE */
|
||||||
static uint8 g_deskcache[0x38400 * 4];
|
static uint8_t g_deskcache[0x38400 * 4];
|
||||||
|
|
||||||
/* Retrieve desktop data from the cache */
|
/* Retrieve desktop data from the cache */
|
||||||
uint8 *
|
uint8_t *cache_get_desktop(uint32_t offset, int cx, int cy, int bytes_per_pixel) {
|
||||||
cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
|
|
||||||
{
|
|
||||||
int length = cx * cy * bytes_per_pixel;
|
int length = cx * cy * bytes_per_pixel;
|
||||||
|
|
||||||
if (offset > sizeof(g_deskcache))
|
if (offset > sizeof(g_deskcache))
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
if ((offset + length) <= sizeof(g_deskcache))
|
if ((offset + length) <= sizeof(g_deskcache)) {
|
||||||
{
|
|
||||||
return &g_deskcache[offset];
|
return &g_deskcache[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,43 +310,31 @@ cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Store desktop data in the cache */
|
/* Store desktop data in the cache */
|
||||||
void
|
void cache_put_desktop(uint32_t offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8_t *data) {
|
||||||
cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
|
|
||||||
{
|
|
||||||
int length = cx * cy * bytes_per_pixel;
|
int length = cx * cy * bytes_per_pixel;
|
||||||
|
|
||||||
if (offset > sizeof(g_deskcache))
|
if (offset > sizeof(g_deskcache))
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
if ((offset + length) <= sizeof(g_deskcache))
|
if ((offset + length) <= sizeof(g_deskcache)) {
|
||||||
{
|
|
||||||
cx *= bytes_per_pixel;
|
cx *= bytes_per_pixel;
|
||||||
while (cy--)
|
while (cy--) {
|
||||||
{
|
|
||||||
memcpy(&g_deskcache[offset], data, cx);
|
memcpy(&g_deskcache[offset], data, cx);
|
||||||
data += scanline;
|
data += scanline;
|
||||||
offset += cx;
|
offset += cx;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
logger(Core, Error, "cache_put_desktop(), offset=%d, length=%d", offset, length);
|
logger(Core, Error, "cache_put_desktop(), offset=%d, length=%d", offset, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* CURSOR CACHE */
|
/* CURSOR CACHE */
|
||||||
static RD_HCURSOR g_cursorcache[0x20];
|
static RD_HCURSOR g_cursorcache[0x20];
|
||||||
|
|
||||||
/* Retrieve cursor from cache */
|
/* Retrieve cursor from cache */
|
||||||
RD_HCURSOR
|
RD_HCURSOR cache_get_cursor(uint16_t cache_idx) {
|
||||||
cache_get_cursor(uint16 cache_idx)
|
if (cache_idx < NUM_ELEMENTS(g_cursorcache)) {
|
||||||
{
|
RD_HCURSOR cursor = g_cursorcache[cache_idx];
|
||||||
RD_HCURSOR cursor;
|
|
||||||
|
|
||||||
if (cache_idx < NUM_ELEMENTS(g_cursorcache))
|
|
||||||
{
|
|
||||||
cursor = g_cursorcache[cache_idx];
|
|
||||||
if (cursor != NULL)
|
if (cursor != NULL)
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
@ -417,21 +344,14 @@ cache_get_cursor(uint16 cache_idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Store cursor in cache */
|
/* Store cursor in cache */
|
||||||
void
|
void cache_put_cursor(uint16_t cache_idx, RD_HCURSOR cursor) {
|
||||||
cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
|
if (cache_idx < NUM_ELEMENTS(g_cursorcache)) {
|
||||||
{
|
RD_HCURSOR old = g_cursorcache[cache_idx];
|
||||||
RD_HCURSOR old;
|
|
||||||
|
|
||||||
if (cache_idx < NUM_ELEMENTS(g_cursorcache))
|
|
||||||
{
|
|
||||||
old = g_cursorcache[cache_idx];
|
|
||||||
if (old != NULL)
|
if (old != NULL)
|
||||||
ui_destroy_cursor(old);
|
ui_destroy_cursor(old);
|
||||||
|
|
||||||
g_cursorcache[cache_idx] = cursor;
|
g_cursorcache[cache_idx] = cursor;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
logger(Core, Error, "cache_put_cursor(), failed, idx=%d", cache_idx);
|
logger(Core, Error, "cache_put_cursor(), failed, idx=%d", cache_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -441,12 +361,9 @@ cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
|
|||||||
static BRUSHDATA g_brushcache[2][64];
|
static BRUSHDATA g_brushcache[2][64];
|
||||||
|
|
||||||
/* Retrieve brush from cache */
|
/* Retrieve brush from cache */
|
||||||
BRUSHDATA *
|
BRUSHDATA *cache_get_brush_data(uint8_t colour_code, uint8_t idx) {
|
||||||
cache_get_brush_data(uint8 colour_code, uint8 idx)
|
|
||||||
{
|
|
||||||
colour_code = colour_code == 1 ? 0 : 1;
|
colour_code = colour_code == 1 ? 0 : 1;
|
||||||
if (idx < NUM_ELEMENTS(g_brushcache[0]))
|
if (idx < NUM_ELEMENTS(g_brushcache[0])) {
|
||||||
{
|
|
||||||
return &g_brushcache[colour_code][idx];
|
return &g_brushcache[colour_code][idx];
|
||||||
}
|
}
|
||||||
logger(Core, Debug, "cache_get_brush_data(), colour=%d, idx=%d", colour_code, idx);
|
logger(Core, Debug, "cache_get_brush_data(), colour=%d, idx=%d", colour_code, idx);
|
||||||
@ -455,23 +372,15 @@ cache_get_brush_data(uint8 colour_code, uint8 idx)
|
|||||||
|
|
||||||
/* Store brush in cache */
|
/* Store brush in cache */
|
||||||
/* this function takes over the data pointer in struct, e.g. caller gives it up */
|
/* this function takes over the data pointer in struct, e.g. caller gives it up */
|
||||||
void
|
void cache_put_brush_data(uint8_t colour_code, uint8_t idx, BRUSHDATA *brush_data) {
|
||||||
cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data)
|
|
||||||
{
|
|
||||||
BRUSHDATA *bd;
|
|
||||||
|
|
||||||
colour_code = colour_code == 1 ? 0 : 1;
|
colour_code = colour_code == 1 ? 0 : 1;
|
||||||
if (idx < NUM_ELEMENTS(g_brushcache[0]))
|
if (idx < NUM_ELEMENTS(g_brushcache[0])) {
|
||||||
{
|
BRUSHDATA *bd = &g_brushcache[colour_code][idx];
|
||||||
bd = &g_brushcache[colour_code][idx];
|
if (bd->data != 0) {
|
||||||
if (bd->data != 0)
|
|
||||||
{
|
|
||||||
xfree(bd->data);
|
xfree(bd->data);
|
||||||
}
|
}
|
||||||
memcpy(bd, brush_data, sizeof(BRUSHDATA));
|
memcpy(bd, brush_data, sizeof(BRUSHDATA));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
logger(Core, Error, "cache_put_brush_data(), colour=%d, idx=%d", colour_code, idx);
|
logger(Core, Error, "cache_put_brush_data(), colour=%d, idx=%d", colour_code, idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
AC_INIT(rdesktop, 1.8.99)
|
AC_INIT(rdesktop, 1.9.0)
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([rdesktop.c])
|
AC_CONFIG_SRCDIR([rdesktop.c])
|
||||||
|
|
||||||
|
@ -1,3 +1,22 @@
|
|||||||
|
rdesktop (1.9.0)
|
||||||
|
* Use GnuTLS and nettle instead of OpenSSL
|
||||||
|
* Improved certificate handling
|
||||||
|
* Add support for dynamic resize of sessions
|
||||||
|
* Add support for alpha cursors
|
||||||
|
* Add PulseAudio support
|
||||||
|
* Add Kerberos support on macOS
|
||||||
|
* Kerberos support no longer requires libgssglue
|
||||||
|
* Remove support for rdesktop's custom microphone extension
|
||||||
|
* Several fixes to improve compatibility with modern desktops
|
||||||
|
* macOS compatibility fixes
|
||||||
|
* Improved handling of redirections
|
||||||
|
* Many smart card bug fixes
|
||||||
|
* Many disk redirection bug fixes
|
||||||
|
* Improved logging
|
||||||
|
* Lots of other small bug fixes
|
||||||
|
|
||||||
|
-- Pierre Ossman <ossman@cendio.se> 2019-09-18
|
||||||
|
|
||||||
rdesktop (1.8.6)
|
rdesktop (1.8.6)
|
||||||
* Fix protocol code handling new licenses
|
* Fix protocol code handling new licenses
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
Summary: Remote Desktop Protocol client
|
Summary: Remote Desktop Protocol client
|
||||||
Name: rdesktop
|
Name: rdesktop
|
||||||
Version: 1.8.99
|
Version: 1.9.0
|
||||||
Release: 1
|
Release: 1
|
||||||
License: GPL; see COPYING
|
License: GPL; see COPYING
|
||||||
Group: Applications/Communications
|
Group: Applications/Communications
|
||||||
|
17
ssl.c
17
ssl.c
@ -90,9 +90,8 @@ rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 *
|
|||||||
mpz_init(exp);
|
mpz_init(exp);
|
||||||
mpz_init(mod);
|
mpz_init(mod);
|
||||||
|
|
||||||
mpz_import(mod, modulus_size, 1, sizeof(modulus[0]), 0, 0, modulus);
|
mpz_import(mod, modulus_size, -1, sizeof(modulus[0]), 0, 0, modulus);
|
||||||
// TODO: Need exponent size
|
mpz_import(exp, SEC_EXPONENT_SIZE, -1, sizeof(exponent[0]), 0, 0, exponent);
|
||||||
mpz_import(exp, 3, 1, sizeof(exponent[0]), 0, 0, exponent);
|
|
||||||
|
|
||||||
mpz_import(x, len, -1, sizeof(in[0]), 0, 0, in);
|
mpz_import(x, len, -1, sizeof(in[0]), 0, 0, in);
|
||||||
|
|
||||||
@ -308,9 +307,15 @@ rdssl_rkey_get_exp_mod(RDSSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len,
|
|||||||
{
|
{
|
||||||
size_t outlen;
|
size_t outlen;
|
||||||
|
|
||||||
// TODO: Check size before exporing
|
outlen = (mpz_sizeinbase(rkey->n, 2) + 7) / 8;
|
||||||
mpz_export(modulus, &outlen, 1, sizeof(uint8), 0, 0, rkey->n);
|
if (outlen > max_mod_len)
|
||||||
mpz_export(exponent, &outlen, 1, sizeof(uint8), 0, 0, rkey->e);
|
return 1;
|
||||||
|
outlen = (mpz_sizeinbase(rkey->e, 2) + 7) / 8;
|
||||||
|
if (outlen > max_exp_len)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
mpz_export(modulus, &outlen, -1, sizeof(uint8), 0, 0, rkey->n);
|
||||||
|
mpz_export(exponent, &outlen, -1, sizeof(uint8), 0, 0, rkey->e);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that gnutls_x509_crt_get_pk_rsa_raw() exports modulus with additional
|
* Note that gnutls_x509_crt_get_pk_rsa_raw() exports modulus with additional
|
||||||
|
5
tcp.c
5
tcp.c
@ -55,7 +55,10 @@
|
|||||||
#define INADDR_NONE ((unsigned long) -1)
|
#define INADDR_NONE ((unsigned long) -1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GNUTLS_PRIORITY "NORMAL"
|
/* Windows' self signed certificates omit the required Digital
|
||||||
|
Signature key usage flag, and only %COMPAT makes GnuTLS ignore
|
||||||
|
that violation. */
|
||||||
|
#define GNUTLS_PRIORITY "NORMAL:%COMPAT"
|
||||||
|
|
||||||
#ifdef IPv6
|
#ifdef IPv6
|
||||||
static struct addrinfo *g_server_address = NULL;
|
static struct addrinfo *g_server_address = NULL;
|
||||||
|
4
utils.c
4
utils.c
@ -1027,8 +1027,8 @@ utils_cert_handle_exception(gnutls_session_t session, unsigned int status,
|
|||||||
cert_invalid_reasons, sizeof(cert_invalid_reasons));
|
cert_invalid_reasons, sizeof(cert_invalid_reasons));
|
||||||
|
|
||||||
snprintf(message, sizeof(message),
|
snprintf(message, sizeof(message),
|
||||||
"ATTENTION! The server uses and invalid security certificate which can not be trusted for\n"
|
"ATTENTION! The server uses an invalid security certificate which can not be trusted for\n"
|
||||||
"the following identified reasons(s);\n\n"
|
"the following identified reason(s);\n\n"
|
||||||
"%s"
|
"%s"
|
||||||
"\n"
|
"\n"
|
||||||
REVIEW_CERT_TEXT
|
REVIEW_CERT_TEXT
|
||||||
|
Loading…
Reference in New Issue
Block a user