Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

bitmap.cpp

Go to the documentation of this file.
00001 /*
00002    rdesktop: A Remote Desktop Protocol client.
00003    Bitmap decompression routines
00004    Copyright (C) Matthew Chapman 1999-2002
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 */
00020 
00021 #include "rdesktop.h"
00022 
00023 #define CVAL(p)   (*(p++))
00024 
00025 static uint32
00026 cvalx(unsigned char **input, int Bpp)
00027 {
00028         uint32 rv = 0;
00029         memcpy(&rv, *input, Bpp);
00030         *input += Bpp;
00031         return rv;
00032 }
00033 
00034 static void
00035 setli(unsigned char *input, int offset, uint32 value, int Bpp)
00036 {
00037         input += offset * Bpp;
00038         memcpy(input, &value, Bpp);
00039 }
00040 
00041 static uint32
00042 getli(unsigned char *input, int offset, int Bpp)
00043 {
00044         uint32 rv = 0;
00045         input += offset * Bpp;
00046         memcpy(&rv, input, Bpp);
00047         return rv;
00048 }
00049 
00050 #define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
00051 
00052 #define REPEAT(statement) \
00053 { \
00054         while((count & ~0x7) && ((x+8) < width)) \
00055                 UNROLL8( statement; count--; x++; ); \
00056         \
00057         while((count > 0) && (x < width)) { statement; count--; x++; } \
00058 }
00059 
00060 #define MASK_UPDATE() \
00061 { \
00062         mixmask <<= 1; \
00063         if (mixmask == 0) \
00064         { \
00065                 mask = fom_mask ? fom_mask : CVAL(input); \
00066                 mixmask = 1; \
00067         } \
00068 }
00069 
00070 BOOL
00071 bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size,
00072                   int Bpp)
00073 {
00074         unsigned char *end = input + size;
00075         unsigned char *prevline = NULL, *line = NULL;
00076         int opcode, count, offset, isfillormix, x = width;
00077         int lastopcode = -1, insertmix = False, bicolour = False;
00078         uint8 code;
00079         uint32 colour1 = 0, colour2 = 0;
00080         uint8 mixmask, mask = 0;
00081         uint32 mix = 0xffffffff;
00082         int fom_mask = 0;
00083 
00084         while (input < end)
00085         {
00086                 fom_mask = 0;
00087                 code = CVAL(input);
00088                 opcode = code >> 4;
00089 
00090                 /* Handle different opcode forms */
00091                 switch (opcode)
00092                 {
00093                         case 0xc:
00094                         case 0xd:
00095                         case 0xe:
00096                                 opcode -= 6;
00097                                 count = code & 0xf;
00098                                 offset = 16;
00099                                 break;
00100 
00101                         case 0xf:
00102                                 opcode = code & 0xf;
00103                                 if (opcode < 9)
00104                                 {
00105                                         count = CVAL(input);
00106                                         count |= CVAL(input) << 8;
00107                                 }
00108                                 else
00109                                 {
00110                                         count = (opcode < 0xb) ? 8 : 1;
00111                                 }
00112                                 offset = 0;
00113                                 break;
00114 
00115                         default:
00116                                 opcode >>= 1;
00117                                 count = code & 0x1f;
00118                                 offset = 32;
00119                                 break;
00120                 }
00121 
00122                 /* Handle strange cases for counts */
00123                 if (offset != 0)
00124                 {
00125                         isfillormix = ((opcode == 2) || (opcode == 7));
00126 
00127                         if (count == 0)
00128                         {
00129                                 if (isfillormix)
00130                                         count = CVAL(input) + 1;
00131                                 else
00132                                         count = CVAL(input) + offset;
00133                         }
00134                         else if (isfillormix)
00135                         {
00136                                 count <<= 3;
00137                         }
00138                 }
00139 
00140                 /* Read preliminary data */
00141                 switch (opcode)
00142                 {
00143                         case 0: /* Fill */
00144                                 if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
00145                                         insertmix = True;
00146                                 break;
00147                         case 8: /* Bicolour */
00148                                 colour1 = cvalx(&input, Bpp);
00149                         case 3: /* Colour */
00150                                 colour2 = cvalx(&input, Bpp);
00151                                 break;
00152                         case 6: /* SetMix/Mix */
00153                         case 7: /* SetMix/FillOrMix */
00154                                 mix = cvalx(&input, Bpp);
00155                                 opcode -= 5;
00156                                 break;
00157                         case 9: /* FillOrMix_1 */
00158                                 mask = 0x03;
00159                                 opcode = 0x02;
00160                                 fom_mask = 3;
00161                                 break;
00162                         case 0x0a:      /* FillOrMix_2 */
00163                                 mask = 0x05;
00164                                 opcode = 0x02;
00165                                 fom_mask = 5;
00166                                 break;
00167 
00168                 }
00169 
00170                 lastopcode = opcode;
00171                 mixmask = 0;
00172 
00173                 /* Output body */
00174                 while (count > 0)
00175                 {
00176                         if (x >= width)
00177                         {
00178                                 if (height <= 0)
00179                                         return False;
00180 
00181                                 x = 0;
00182                                 height--;
00183 
00184                                 prevline = line;
00185                                 line = output + height * width * Bpp;
00186                         }
00187 
00188                         switch (opcode)
00189                         {
00190                                 case 0: /* Fill */
00191                                         if (insertmix)
00192                                         {
00193                                                 if (prevline == NULL)
00194                                                         setli(line, x, mix, Bpp);
00195                                                 else
00196                                                         setli(line, x,
00197                                                               getli(prevline, x, Bpp) ^ mix, Bpp);
00198 
00199                                                 insertmix = False;
00200                                                 count--;
00201                                                 x++;
00202                                         }
00203 
00204                                         if (prevline == NULL)
00205                                         {
00206                                         REPEAT(setli(line, x, 0, Bpp))}
00207                                         else
00208                                         {
00209                                                 REPEAT(setli
00210                                                        (line, x, getli(prevline, x, Bpp), Bpp));
00211                                         }
00212                                         break;
00213 
00214                                 case 1: /* Mix */
00215                                         if (prevline == NULL)
00216                                         {
00217                                                 REPEAT(setli(line, x, mix, Bpp));
00218                                         }
00219                                         else
00220                                         {
00221                                                 REPEAT(setli
00222                                                        (line, x, getli(prevline, x, Bpp) ^ mix,
00223                                                         Bpp));
00224                                         }
00225                                         break;
00226 
00227                                 case 2: /* Fill or Mix */
00228                                         if (prevline == NULL)
00229                                         {
00230                                                 REPEAT(MASK_UPDATE();
00231                                                        if (mask & mixmask) setli(line, x, mix, Bpp);
00232                                                        else
00233                                                        setli(line, x, 0, Bpp););
00234                                         }
00235                                         else
00236                                         {
00237                                                 REPEAT(MASK_UPDATE();
00238                                                        if (mask & mixmask)
00239                                                        setli(line, x, getli(prevline, x, Bpp) ^ mix,
00240                                                              Bpp);
00241                                                        else
00242                                                        setli(line, x, getli(prevline, x, Bpp),
00243                                                              Bpp););
00244                                         }
00245                                         break;
00246 
00247                                 case 3: /* Colour */
00248                                         REPEAT(setli(line, x, colour2, Bpp));
00249                                         break;
00250 
00251                                 case 4: /* Copy */
00252                                         REPEAT(setli(line, x, cvalx(&input, Bpp), Bpp));
00253                                         break;
00254 
00255                                 case 8: /* Bicolour */
00256                                         REPEAT(if (bicolour)
00257                                                {
00258                                                setli(line, x, colour2, Bpp); bicolour = False;}
00259                                                else
00260                                                {
00261                                                setli(line, x, colour1, Bpp); bicolour = True;
00262                                                count++;}
00263                                         );
00264                                         break;
00265 
00266                                 case 0xd:       /* White */
00267                                         REPEAT(setli(line, x, 0xffffffff, Bpp));
00268                                         break;
00269 
00270                                 case 0xe:       /* Black */
00271                                         REPEAT(setli(line, x, 0, Bpp));
00272                                         break;
00273 
00274                                 default:
00275                                         unimpl("bitmap opcode 0x%x\n", opcode);
00276                                         return False;
00277                         }
00278                 }
00279         }
00280 
00281         return True;
00282 }

Generated on Sat Nov 5 16:17:41 2005 for OPIE by  doxygen 1.4.2