--- sourceforge.net/trunk/rdesktop/bitmap.c 2002/09/26 14:26:46 207 +++ sourceforge.net/trunk/rdesktop/bitmap.c 2003/02/04 05:32:13 309 @@ -2,17 +2,17 @@ rdesktop: A Remote Desktop Protocol client. Bitmap decompression routines Copyright (C) Matthew Chapman 1999-2002 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -21,6 +21,7 @@ #include "rdesktop.h" #define CVAL(p) (*(p++)) +#define CVAL16(p) (*(((uint16*)p)++)) #define UNROLL8(exp) { exp exp exp exp exp exp exp exp } @@ -43,7 +44,7 @@ } BOOL -bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size) +bitmap_decompress8(unsigned char *output, int width, int height, unsigned char *input, int size) { unsigned char *end = input + size; unsigned char *prevline = NULL, *line = NULL; @@ -246,3 +247,221 @@ return True; } + +BOOL +bitmap_decompress16(unsigned char *output, int width, int height, unsigned char *input, int size) +{ + unsigned char *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 < 0xd) ? 8 : 1; // was 0xb in 8 bit + } + 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 = CVAL16(input); + case 3: /* Colour */ + colour2 = CVAL16(input); + break; + case 6: /* SetMix/Mix */ + case 7: /* SetMix/FillOrMix */ + mix = CVAL16(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 = (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(line[x] = CVAL16(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] = 0xffff); + break; + + case 0xe: /* Black */ + REPEAT(line[x] = 0x00); + break; + + default: + unimpl("bitmap opcode 0x%x\n", opcode); + return False; + } + } + } + + return True; +} + +BOOL +bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size, int bpp) +{ + if (bpp == 8) + return bitmap_decompress8(output, width, height, input, size); + else if (bpp == 16) + return bitmap_decompress16(output, width, height, input, size); + else + return False; +}