2012-09-20 07:51:34 +04:00
|
|
|
/**
|
|
|
|
* xrdp: A Remote Desktop Protocol server.
|
|
|
|
*
|
2013-06-08 21:51:53 +04:00
|
|
|
* Copyright (C) Jay Sorg 2004-2013
|
2012-09-20 07:51:34 +04:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*
|
|
|
|
* librdp bitmap routines
|
|
|
|
*/
|
2005-11-03 05:01:50 +03:00
|
|
|
|
|
|
|
#include "rdp.h"
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
#define CVAL(p) ((unsigned char)(*(p++)))
|
|
|
|
|
2006-02-06 03:33:18 +03:00
|
|
|
#if defined(B_ENDIAN)
|
|
|
|
#define EIK0 1
|
|
|
|
#define EIK1 0
|
|
|
|
#else
|
|
|
|
#define EIK0 0
|
|
|
|
#define EIK1 1
|
|
|
|
#endif
|
|
|
|
|
2005-11-03 05:01:50 +03:00
|
|
|
/******************************************************************************/
|
|
|
|
#define REPEAT(statement) \
|
2012-09-20 07:51:34 +04:00
|
|
|
{ \
|
|
|
|
while ((count > 0) && (x < width)) \
|
|
|
|
{ \
|
|
|
|
statement; \
|
|
|
|
count--; \
|
|
|
|
x++; \
|
|
|
|
} \
|
|
|
|
}
|
2005-11-03 05:01:50 +03:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
#define MASK_UPDATE \
|
2012-09-20 07:51:34 +04:00
|
|
|
{ \
|
|
|
|
mixmask <<= 1; \
|
|
|
|
if ((mixmask & 0xff) == 0) \
|
|
|
|
{ \
|
|
|
|
mask = fom_mask ? fom_mask : CVAL(input); \
|
|
|
|
mixmask = 1; \
|
|
|
|
} \
|
|
|
|
}
|
2005-11-03 05:01:50 +03:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/* 1 byte bitmap decompress */
|
|
|
|
/* returns boolean */
|
|
|
|
static int APP_CC
|
2012-09-20 07:51:34 +04:00
|
|
|
bitmap_decompress1(char *output, int width, int height, char *input, int size)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
char *prevline;
|
|
|
|
char *line;
|
|
|
|
char *end;
|
|
|
|
char color1;
|
|
|
|
char color2;
|
|
|
|
char mix;
|
|
|
|
int code;
|
|
|
|
int mixmask;
|
|
|
|
int mask;
|
|
|
|
int opcode;
|
|
|
|
int count;
|
|
|
|
int offset;
|
|
|
|
int isfillormix;
|
|
|
|
int x;
|
|
|
|
int lastopcode;
|
|
|
|
int insertmix;
|
|
|
|
int bicolor;
|
|
|
|
int fom_mask;
|
|
|
|
|
|
|
|
end = input + size;
|
|
|
|
prevline = 0;
|
|
|
|
line = 0;
|
|
|
|
x = width;
|
|
|
|
lastopcode = -1;
|
|
|
|
insertmix = 0;
|
|
|
|
bicolor = 0;
|
|
|
|
color1 = 0;
|
|
|
|
color2 = 0;
|
|
|
|
mix = 0xff;
|
|
|
|
mask = 0;
|
2005-11-03 05:01:50 +03:00
|
|
|
fom_mask = 0;
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
while (input < end)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
fom_mask = 0;
|
|
|
|
code = CVAL(input);
|
|
|
|
opcode = code >> 4;
|
|
|
|
|
|
|
|
/* Handle different opcode forms */
|
|
|
|
switch (opcode)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
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;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
/* Handle strange cases for counts */
|
|
|
|
if (offset != 0)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
isfillormix = ((opcode == 2) || (opcode == 7));
|
|
|
|
|
|
|
|
if (count == 0)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
if (isfillormix)
|
|
|
|
{
|
|
|
|
count = CVAL(input) + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count = CVAL(input) + offset;
|
|
|
|
}
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
else if (isfillormix)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
count <<= 3;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read preliminary data */
|
|
|
|
switch (opcode)
|
|
|
|
{
|
|
|
|
case 0: /* Fill */
|
|
|
|
|
|
|
|
if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
|
|
|
|
{
|
|
|
|
insertmix = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 8: /* Bicolor */
|
|
|
|
color1 = CVAL(input);
|
|
|
|
case 3: /* Color */
|
|
|
|
color2 = 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)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
if (height <= 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
x = 0;
|
|
|
|
height--;
|
|
|
|
prevline = line;
|
|
|
|
line = output + height * width;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
switch (opcode)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
case 0: /* Fill */
|
|
|
|
|
|
|
|
if (insertmix)
|
|
|
|
{
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
line[x] = mix;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x] = prevline[x] ^ mix;
|
|
|
|
}
|
|
|
|
|
|
|
|
insertmix = 0;
|
|
|
|
count--;
|
|
|
|
x++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
REPEAT(line[x] = 0)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPEAT(line[x] = prevline[x])
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 1: /* Mix */
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
REPEAT(line[x] = mix)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPEAT(line[x] = prevline[x] ^ mix)
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 2: /* Fill or Mix */
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
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: /* Color */
|
|
|
|
REPEAT(line[x] = color2)
|
|
|
|
break;
|
|
|
|
case 4: /* Copy */
|
|
|
|
REPEAT(line[x] = CVAL(input))
|
|
|
|
break;
|
|
|
|
case 8: /* Bicolor */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
|
|
|
|
if (bicolor)
|
|
|
|
{
|
|
|
|
line[x] = color2;
|
|
|
|
bicolor = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x] = color1;
|
|
|
|
bicolor = 1;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 0xd: /* White */
|
|
|
|
REPEAT(line[x] = 0xff)
|
|
|
|
break;
|
|
|
|
case 0xe: /* Black */
|
|
|
|
REPEAT(line[x] = 0)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
break;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
}
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
return 1;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/* 2 byte bitmap decompress */
|
|
|
|
/* returns boolean */
|
|
|
|
static int APP_CC
|
2012-09-20 07:51:34 +04:00
|
|
|
bitmap_decompress2(char *output, int width, int height, char *input, int size)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
char *prevline;
|
|
|
|
char *line;
|
|
|
|
char *end;
|
|
|
|
char color1[2];
|
|
|
|
char color2[2];
|
|
|
|
char mix[2];
|
|
|
|
int code;
|
|
|
|
int mixmask;
|
|
|
|
int mask;
|
|
|
|
int opcode;
|
|
|
|
int count;
|
|
|
|
int offset;
|
|
|
|
int isfillormix;
|
|
|
|
int x;
|
|
|
|
int lastopcode;
|
|
|
|
int insertmix;
|
|
|
|
int bicolor;
|
|
|
|
int fom_mask;
|
|
|
|
|
|
|
|
end = input + size;
|
|
|
|
prevline = 0;
|
|
|
|
line = 0;
|
|
|
|
x = width;
|
|
|
|
lastopcode = -1;
|
|
|
|
insertmix = 0;
|
|
|
|
bicolor = 0;
|
|
|
|
color1[0] = 0;
|
|
|
|
color1[1] = 0;
|
|
|
|
color2[0] = 0;
|
|
|
|
color2[1] = 0;
|
|
|
|
mix[0] = 0xff;
|
|
|
|
mix[1] = 0xff;
|
|
|
|
mask = 0;
|
2005-11-03 05:01:50 +03:00
|
|
|
fom_mask = 0;
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
while (input < end)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
fom_mask = 0;
|
|
|
|
code = CVAL(input);
|
|
|
|
opcode = code >> 4;
|
|
|
|
|
|
|
|
/* Handle different opcode forms */
|
|
|
|
switch (opcode)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
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;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
/* Handle strange cases for counts */
|
|
|
|
if (offset != 0)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
isfillormix = ((opcode == 2) || (opcode == 7));
|
|
|
|
|
|
|
|
if (count == 0)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
if (isfillormix)
|
|
|
|
{
|
|
|
|
count = CVAL(input) + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count = CVAL(input) + offset;
|
|
|
|
}
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
else if (isfillormix)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
count <<= 3;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read preliminary data */
|
|
|
|
switch (opcode)
|
|
|
|
{
|
|
|
|
case 0: /* Fill */
|
|
|
|
|
|
|
|
if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
|
|
|
|
{
|
|
|
|
insertmix = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 8: /* Bicolor */
|
|
|
|
color1[EIK0] = CVAL(input);
|
|
|
|
color1[EIK1] = CVAL(input);
|
|
|
|
case 3: /* Color */
|
|
|
|
color2[EIK0] = CVAL(input);
|
|
|
|
color2[EIK1] = CVAL(input);
|
|
|
|
break;
|
|
|
|
case 6: /* SetMix/Mix */
|
|
|
|
case 7: /* SetMix/FillOrMix */
|
|
|
|
mix[EIK0] = CVAL(input);
|
|
|
|
mix[EIK1] = 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)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
if (height <= 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
x = 0;
|
|
|
|
height--;
|
|
|
|
prevline = line;
|
|
|
|
line = output + height * (width * 2);
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
switch (opcode)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
case 0: /* Fill */
|
|
|
|
|
|
|
|
if (insertmix)
|
|
|
|
{
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
line[x * 2 + 0] = mix[0];
|
|
|
|
line[x * 2 + 1] = mix[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
|
|
|
|
line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
insertmix = 0;
|
|
|
|
count--;
|
|
|
|
x++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 2 + 0] = 0;
|
|
|
|
line[x * 2 + 1] = 0;
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 2 + 0] = prevline[x * 2 + 0];
|
|
|
|
line[x * 2 + 1] = prevline[x * 2 + 1];
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 1: /* Mix */
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 2 + 0] = mix[0];
|
|
|
|
line[x * 2 + 1] = mix[1];
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
|
|
|
|
line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 2: /* Fill or Mix */
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
MASK_UPDATE;
|
|
|
|
|
|
|
|
if (mask & mixmask)
|
|
|
|
{
|
|
|
|
line[x * 2 + 0] = mix[0];
|
|
|
|
line[x * 2 + 1] = mix[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x * 2 + 0] = 0;
|
|
|
|
line[x * 2 + 1] = 0;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
MASK_UPDATE;
|
|
|
|
|
|
|
|
if (mask & mixmask)
|
|
|
|
{
|
|
|
|
line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
|
|
|
|
line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x * 2 + 0] = prevline[x * 2 + 0];
|
|
|
|
line[x * 2 + 1] = prevline[x * 2 + 1];
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 3: /* Color */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 2 + 0] = color2[0];
|
|
|
|
line[x * 2 + 1] = color2[1];
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 4: /* Copy */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 2 + EIK0] = CVAL(input);
|
|
|
|
line[x * 2 + EIK1] = CVAL(input);
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 8: /* Bicolor */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
|
|
|
|
if (bicolor)
|
|
|
|
{
|
|
|
|
line[x * 2 + 0] = color2[0];
|
|
|
|
line[x * 2 + 1] = color2[1];
|
|
|
|
bicolor = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x * 2 + 0] = color1[0];
|
|
|
|
line[x * 2 + 1] = color1[1];
|
|
|
|
bicolor = 1;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 0xd: /* White */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 2 + 0] = 0xff;
|
|
|
|
line[x * 2 + 1] = 0xff;
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 0xe: /* Black */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 2 + 0] = 0;
|
|
|
|
line[x * 2 + 1] = 0;
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
break;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
}
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
return 1;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/* 3 byte bitmap decompress */
|
|
|
|
/* returns boolean */
|
|
|
|
static int APP_CC
|
2012-09-20 07:51:34 +04:00
|
|
|
bitmap_decompress3(char *output, int width, int height, char *input, int size)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
char *prevline;
|
|
|
|
char *line;
|
|
|
|
char *end;
|
|
|
|
char color1[3];
|
|
|
|
char color2[3];
|
|
|
|
char mix[3];
|
|
|
|
int code;
|
|
|
|
int mixmask;
|
|
|
|
int mask;
|
|
|
|
int opcode;
|
|
|
|
int count;
|
|
|
|
int offset;
|
|
|
|
int isfillormix;
|
|
|
|
int x;
|
|
|
|
int lastopcode;
|
|
|
|
int insertmix;
|
|
|
|
int bicolor;
|
|
|
|
int fom_mask;
|
|
|
|
|
|
|
|
end = input + size;
|
|
|
|
prevline = 0;
|
|
|
|
line = 0;
|
|
|
|
x = width;
|
|
|
|
lastopcode = -1;
|
|
|
|
insertmix = 0;
|
|
|
|
bicolor = 0;
|
|
|
|
color1[0] = 0;
|
|
|
|
color1[1] = 0;
|
|
|
|
color1[2] = 0;
|
|
|
|
color2[0] = 0;
|
|
|
|
color2[1] = 0;
|
|
|
|
color2[2] = 0;
|
|
|
|
mix[0] = 0xff;
|
|
|
|
mix[1] = 0xff;
|
|
|
|
mix[2] = 0xff;
|
|
|
|
mask = 0;
|
2005-11-03 05:01:50 +03:00
|
|
|
fom_mask = 0;
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
while (input < end)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
fom_mask = 0;
|
|
|
|
code = CVAL(input);
|
|
|
|
opcode = code >> 4;
|
|
|
|
|
|
|
|
/* Handle different opcode forms */
|
|
|
|
switch (opcode)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
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;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
/* Handle strange cases for counts */
|
|
|
|
if (offset != 0)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
isfillormix = ((opcode == 2) || (opcode == 7));
|
|
|
|
|
|
|
|
if (count == 0)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
if (isfillormix)
|
|
|
|
{
|
|
|
|
count = CVAL(input) + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count = CVAL(input) + offset;
|
|
|
|
}
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
else if (isfillormix)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
count <<= 3;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read preliminary data */
|
|
|
|
switch (opcode)
|
|
|
|
{
|
|
|
|
case 0: /* Fill */
|
|
|
|
|
|
|
|
if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
|
|
|
|
{
|
|
|
|
insertmix = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 8: /* Bicolor */
|
|
|
|
color1[0] = CVAL(input);
|
|
|
|
color1[1] = CVAL(input);
|
|
|
|
color1[2] = CVAL(input);
|
|
|
|
case 3: /* Color */
|
|
|
|
color2[0] = CVAL(input);
|
|
|
|
color2[1] = CVAL(input);
|
|
|
|
color2[2] = CVAL(input);
|
|
|
|
break;
|
|
|
|
case 6: /* SetMix/Mix */
|
|
|
|
case 7: /* SetMix/FillOrMix */
|
|
|
|
mix[0] = CVAL(input);
|
|
|
|
mix[1] = CVAL(input);
|
|
|
|
mix[2] = 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)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
if (height <= 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
x = 0;
|
|
|
|
height--;
|
|
|
|
prevline = line;
|
|
|
|
line = output + height * (width * 3);
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
switch (opcode)
|
2005-11-03 05:01:50 +03:00
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
case 0: /* Fill */
|
|
|
|
|
|
|
|
if (insertmix)
|
|
|
|
{
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
line[x * 3 + 0] = mix[0];
|
|
|
|
line[x * 3 + 1] = mix[1];
|
|
|
|
line[x * 3 + 2] = mix[2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
|
|
|
|
line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
|
|
|
|
line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
insertmix = 0;
|
|
|
|
count--;
|
|
|
|
x++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 3 + 0] = 0;
|
|
|
|
line[x * 3 + 1] = 0;
|
|
|
|
line[x * 3 + 2] = 0;
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 3 + 0] = prevline[x * 3 + 0];
|
|
|
|
line[x * 3 + 1] = prevline[x * 3 + 1];
|
|
|
|
line[x * 3 + 2] = prevline[x * 3 + 2];
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 1: /* Mix */
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 3 + 0] = mix[0];
|
|
|
|
line[x * 3 + 1] = mix[1];
|
|
|
|
line[x * 3 + 2] = mix[2];
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
|
|
|
|
line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
|
|
|
|
line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 2: /* Fill or Mix */
|
|
|
|
|
|
|
|
if (prevline == 0)
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
MASK_UPDATE;
|
|
|
|
|
|
|
|
if (mask & mixmask)
|
|
|
|
{
|
|
|
|
line[x * 3 + 0] = mix[0];
|
|
|
|
line[x * 3 + 1] = mix[1];
|
|
|
|
line[x * 3 + 2] = mix[2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x * 3 + 0] = 0;
|
|
|
|
line[x * 3 + 1] = 0;
|
|
|
|
line[x * 3 + 2] = 0;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
MASK_UPDATE;
|
|
|
|
|
|
|
|
if (mask & mixmask)
|
|
|
|
{
|
|
|
|
line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
|
|
|
|
line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
|
|
|
|
line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x * 3 + 0] = prevline[x * 3 + 0];
|
|
|
|
line[x * 3 + 1] = prevline[x * 3 + 1];
|
|
|
|
line[x * 3 + 2] = prevline[x * 3 + 2];
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 3: /* Color */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 3 + 0] = color2[0];
|
|
|
|
line[x * 3 + 1] = color2[1];
|
|
|
|
line[x * 3 + 2] = color2[2];
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 4: /* Copy */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 3 + 0] = CVAL(input);
|
|
|
|
line[x * 3 + 1] = CVAL(input);
|
|
|
|
line[x * 3 + 2] = CVAL(input);
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 8: /* Bicolor */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
|
|
|
|
if (bicolor)
|
|
|
|
{
|
|
|
|
line[x * 3 + 0] = color2[0];
|
|
|
|
line[x * 3 + 1] = color2[1];
|
|
|
|
line[x * 3 + 2] = color2[2];
|
|
|
|
bicolor = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line[x * 3 + 0] = color1[0];
|
|
|
|
line[x * 3 + 1] = color1[1];
|
|
|
|
line[x * 3 + 2] = color1[2];
|
|
|
|
bicolor = 1;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 0xd: /* White */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 3 + 0] = 0xff;
|
|
|
|
line[x * 3 + 1] = 0xff;
|
|
|
|
line[x * 3 + 2] = 0xff;
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
case 0xe: /* Black */
|
|
|
|
REPEAT
|
|
|
|
(
|
|
|
|
line[x * 3 + 0] = 0;
|
|
|
|
line[x * 3 + 1] = 0;
|
|
|
|
line[x * 3 + 2] = 0;
|
|
|
|
)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
break;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
}
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
2012-09-20 07:51:34 +04:00
|
|
|
|
|
|
|
return 1;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* returns boolean */
|
|
|
|
int APP_CC
|
2012-09-20 07:51:34 +04:00
|
|
|
rdp_bitmap_decompress(char *output, int width, int height, char *input,
|
2005-11-03 05:01:50 +03:00
|
|
|
int size, int Bpp)
|
|
|
|
{
|
2012-09-20 07:51:34 +04:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
switch (Bpp)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
rv = bitmap_decompress1(output, width, height, input, size);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
rv = bitmap_decompress2(output, width, height, input, size);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
rv = bitmap_decompress3(output, width, height, input, size);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
2005-11-03 05:01:50 +03:00
|
|
|
}
|