00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
00141 switch (opcode)
00142 {
00143 case 0:
00144 if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
00145 insertmix = True;
00146 break;
00147 case 8:
00148 colour1 = cvalx(&input, Bpp);
00149 case 3:
00150 colour2 = cvalx(&input, Bpp);
00151 break;
00152 case 6:
00153 case 7:
00154 mix = cvalx(&input, Bpp);
00155 opcode -= 5;
00156 break;
00157 case 9:
00158 mask = 0x03;
00159 opcode = 0x02;
00160 fom_mask = 3;
00161 break;
00162 case 0x0a:
00163 mask = 0x05;
00164 opcode = 0x02;
00165 fom_mask = 5;
00166 break;
00167
00168 }
00169
00170 lastopcode = opcode;
00171 mixmask = 0;
00172
00173
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:
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:
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:
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:
00248 REPEAT(setli(line, x, colour2, Bpp));
00249 break;
00250
00251 case 4:
00252 REPEAT(setli(line, x, cvalx(&input, Bpp), Bpp));
00253 break;
00254
00255 case 8:
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:
00267 REPEAT(setli(line, x, 0xffffffff, Bpp));
00268 break;
00269
00270 case 0xe:
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 }