~ubuntu-branches/ubuntu/feisty/rdesktop/feisty-proposed

« back to all changes in this revision

Viewing changes to bitmap.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Johnston
  • Date: 2004-02-04 17:52:26 UTC
  • Revision ID: james.westby@ubuntu.com-20040204175226-87kz4bzs1nimji68
Tags: upstream-1.3.1
ImportĀ upstreamĀ versionĀ 1.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- c-basic-offset: 8 -*-
 
2
   rdesktop: A Remote Desktop Protocol client.
 
3
   Bitmap decompression routines
 
4
   Copyright (C) Matthew Chapman 1999-2002
 
5
 
 
6
   This program is free software; you can redistribute it and/or modify
 
7
   it under the terms of the GNU General Public License as published by
 
8
   the Free Software Foundation; either version 2 of the License, or
 
9
   (at your option) any later version.
 
10
 
 
11
   This program is distributed in the hope that it will be useful,
 
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
   GNU General Public License for more details.
 
15
 
 
16
   You should have received a copy of the GNU General Public License
 
17
   along with this program; if not, write to the Free Software
 
18
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
*/
 
20
 
 
21
#include "rdesktop.h"
 
22
 
 
23
#define CVAL(p)   (*(p++))
 
24
 
 
25
static uint32
 
26
cvalx(unsigned char **input, int Bpp)
 
27
{
 
28
        uint32 rv = 0;
 
29
        memcpy(&rv, *input, Bpp);
 
30
        *input += Bpp;
 
31
        return rv;
 
32
}
 
33
 
 
34
static void
 
35
setli(unsigned char *input, int offset, uint32 value, int Bpp)
 
36
{
 
37
        input += offset * Bpp;
 
38
        memcpy(input, &value, Bpp);
 
39
}
 
40
 
 
41
static uint32
 
42
getli(unsigned char *input, int offset, int Bpp)
 
43
{
 
44
        uint32 rv = 0;
 
45
        input += offset * Bpp;
 
46
        memcpy(&rv, input, Bpp);
 
47
        return rv;
 
48
}
 
49
 
 
50
#define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
 
51
 
 
52
#define REPEAT(statement) \
 
53
{ \
 
54
        while((count & ~0x7) && ((x+8) < width)) \
 
55
                UNROLL8( statement; count--; x++; ); \
 
56
        \
 
57
        while((count > 0) && (x < width)) { statement; count--; x++; } \
 
58
}
 
59
 
 
60
#define MASK_UPDATE() \
 
61
{ \
 
62
        mixmask <<= 1; \
 
63
        if (mixmask == 0) \
 
64
        { \
 
65
                mask = fom_mask ? fom_mask : CVAL(input); \
 
66
                mixmask = 1; \
 
67
        } \
 
68
}
 
69
 
 
70
BOOL
 
71
bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size,
 
72
                  int Bpp)
 
73
{
 
74
        unsigned char *end = input + size;
 
75
        unsigned char *prevline = NULL, *line = NULL;
 
76
        int opcode, count, offset, isfillormix, x = width;
 
77
        int lastopcode = -1, insertmix = False, bicolour = False;
 
78
        uint8 code;
 
79
        uint32 colour1 = 0, colour2 = 0;
 
80
        uint8 mixmask, mask = 0;
 
81
        uint32 mix = 0xffffffff;
 
82
        int fom_mask = 0;
 
83
 
 
84
        while (input < end)
 
85
        {
 
86
                fom_mask = 0;
 
87
                code = CVAL(input);
 
88
                opcode = code >> 4;
 
89
 
 
90
                /* Handle different opcode forms */
 
91
                switch (opcode)
 
92
                {
 
93
                        case 0xc:
 
94
                        case 0xd:
 
95
                        case 0xe:
 
96
                                opcode -= 6;
 
97
                                count = code & 0xf;
 
98
                                offset = 16;
 
99
                                break;
 
100
 
 
101
                        case 0xf:
 
102
                                opcode = code & 0xf;
 
103
                                if (opcode < 9)
 
104
                                {
 
105
                                        count = CVAL(input);
 
106
                                        count |= CVAL(input) << 8;
 
107
                                }
 
108
                                else
 
109
                                {
 
110
                                        count = (opcode < 0xb) ? 8 : 1;
 
111
                                }
 
112
                                offset = 0;
 
113
                                break;
 
114
 
 
115
                        default:
 
116
                                opcode >>= 1;
 
117
                                count = code & 0x1f;
 
118
                                offset = 32;
 
119
                                break;
 
120
                }
 
121
 
 
122
                /* Handle strange cases for counts */
 
123
                if (offset != 0)
 
124
                {
 
125
                        isfillormix = ((opcode == 2) || (opcode == 7));
 
126
 
 
127
                        if (count == 0)
 
128
                        {
 
129
                                if (isfillormix)
 
130
                                        count = CVAL(input) + 1;
 
131
                                else
 
132
                                        count = CVAL(input) + offset;
 
133
                        }
 
134
                        else if (isfillormix)
 
135
                        {
 
136
                                count <<= 3;
 
137
                        }
 
138
                }
 
139
 
 
140
                /* Read preliminary data */
 
141
                switch (opcode)
 
142
                {
 
143
                        case 0: /* Fill */
 
144
                                if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
 
145
                                        insertmix = True;
 
146
                                break;
 
147
                        case 8: /* Bicolour */
 
148
                                colour1 = cvalx(&input, Bpp);
 
149
                        case 3: /* Colour */
 
150
                                colour2 = cvalx(&input, Bpp);
 
151
                                break;
 
152
                        case 6: /* SetMix/Mix */
 
153
                        case 7: /* SetMix/FillOrMix */
 
154
                                mix = cvalx(&input, Bpp);
 
155
                                opcode -= 5;
 
156
                                break;
 
157
                        case 9: /* FillOrMix_1 */
 
158
                                mask = 0x03;
 
159
                                opcode = 0x02;
 
160
                                fom_mask = 3;
 
161
                                break;
 
162
                        case 0x0a:      /* FillOrMix_2 */
 
163
                                mask = 0x05;
 
164
                                opcode = 0x02;
 
165
                                fom_mask = 5;
 
166
                                break;
 
167
 
 
168
                }
 
169
 
 
170
                lastopcode = opcode;
 
171
                mixmask = 0;
 
172
 
 
173
                /* Output body */
 
174
                while (count > 0)
 
175
                {
 
176
                        if (x >= width)
 
177
                        {
 
178
                                if (height <= 0)
 
179
                                        return False;
 
180
 
 
181
                                x = 0;
 
182
                                height--;
 
183
 
 
184
                                prevline = line;
 
185
                                line = output + height * width * Bpp;
 
186
                        }
 
187
 
 
188
                        switch (opcode)
 
189
                        {
 
190
                                case 0: /* Fill */
 
191
                                        if (insertmix)
 
192
                                        {
 
193
                                                if (prevline == NULL)
 
194
                                                        setli(line, x, mix, Bpp);
 
195
                                                else
 
196
                                                        setli(line, x,
 
197
                                                              getli(prevline, x, Bpp) ^ mix, Bpp);
 
198
 
 
199
                                                insertmix = False;
 
200
                                                count--;
 
201
                                                x++;
 
202
                                        }
 
203
 
 
204
                                        if (prevline == NULL)
 
205
                                        {
 
206
                                        REPEAT(setli(line, x, 0, Bpp))}
 
207
                                        else
 
208
                                        {
 
209
                                                REPEAT(setli
 
210
                                                       (line, x, getli(prevline, x, Bpp), Bpp));
 
211
                                        }
 
212
                                        break;
 
213
 
 
214
                                case 1: /* Mix */
 
215
                                        if (prevline == NULL)
 
216
                                        {
 
217
                                                REPEAT(setli(line, x, mix, Bpp));
 
218
                                        }
 
219
                                        else
 
220
                                        {
 
221
                                                REPEAT(setli
 
222
                                                       (line, x, getli(prevline, x, Bpp) ^ mix,
 
223
                                                        Bpp));
 
224
                                        }
 
225
                                        break;
 
226
 
 
227
                                case 2: /* Fill or Mix */
 
228
                                        if (prevline == NULL)
 
229
                                        {
 
230
                                                REPEAT(MASK_UPDATE();
 
231
                                                       if (mask & mixmask) setli(line, x, mix, Bpp);
 
232
                                                       else
 
233
                                                       setli(line, x, 0, Bpp););
 
234
                                        }
 
235
                                        else
 
236
                                        {
 
237
                                                REPEAT(MASK_UPDATE();
 
238
                                                       if (mask & mixmask)
 
239
                                                       setli(line, x, getli(prevline, x, Bpp) ^ mix,
 
240
                                                             Bpp);
 
241
                                                       else
 
242
                                                       setli(line, x, getli(prevline, x, Bpp),
 
243
                                                             Bpp););
 
244
                                        }
 
245
                                        break;
 
246
 
 
247
                                case 3: /* Colour */
 
248
                                        REPEAT(setli(line, x, colour2, Bpp));
 
249
                                        break;
 
250
 
 
251
                                case 4: /* Copy */
 
252
                                        REPEAT(setli(line, x, cvalx(&input, Bpp), Bpp));
 
253
                                        break;
 
254
 
 
255
                                case 8: /* Bicolour */
 
256
                                        REPEAT(if (bicolour)
 
257
                                               {
 
258
                                               setli(line, x, colour2, Bpp); bicolour = False;}
 
259
                                               else
 
260
                                               {
 
261
                                               setli(line, x, colour1, Bpp); bicolour = True;
 
262
                                               count++;}
 
263
                                        );
 
264
                                        break;
 
265
 
 
266
                                case 0xd:       /* White */
 
267
                                        REPEAT(setli(line, x, 0xffffffff, Bpp));
 
268
                                        break;
 
269
 
 
270
                                case 0xe:       /* Black */
 
271
                                        REPEAT(setli(line, x, 0, Bpp));
 
272
                                        break;
 
273
 
 
274
                                default:
 
275
                                        unimpl("bitmap opcode 0x%x\n", opcode);
 
276
                                        return False;
 
277
                        }
 
278
                }
 
279
        }
 
280
 
 
281
        return True;
 
282
}