1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * RLE Compressed Bitmap Stream
4 *
5 * Copyright 2011 Jay Sorg <jay.sorg@gmail.com>
6 * Copyright 2016 Armin Novak <armin.novak@thincast.com>
7 * Copyright 2016 Thincast Technologies GmbH
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22 /* do not compile the file directly */
23
24 /**
25 * Write a foreground/background image to a destination buffer.
26 */
WRITEFGBGIMAGE(BYTE * pbDest,const BYTE * pbDestEnd,UINT32 rowDelta,BYTE bitmask,PIXEL fgPel,INT32 cBits)27 static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 rowDelta,
28 BYTE bitmask, PIXEL fgPel, INT32 cBits)
29 {
30 PIXEL xorPixel;
31 BYTE mask = 0x01;
32
33 if (cBits > 8)
34 return NULL;
35
36 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
37 return NULL;
38
39 UNROLL(cBits, {
40 UINT32 data;
41 DESTREADPIXEL(xorPixel, pbDest - rowDelta);
42
43 if (bitmask & mask)
44 data = xorPixel ^ fgPel;
45 else
46 data = xorPixel;
47
48 DESTWRITEPIXEL(pbDest, data);
49 DESTNEXTPIXEL(pbDest);
50 mask = mask << 1;
51 });
52 return pbDest;
53 }
54
55 /**
56 * Write a foreground/background image to a destination buffer
57 * for the first line of compressed data.
58 */
WRITEFIRSTLINEFGBGIMAGE(BYTE * pbDest,const BYTE * pbDestEnd,BYTE bitmask,PIXEL fgPel,UINT32 cBits)59 static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, BYTE bitmask,
60 PIXEL fgPel, UINT32 cBits)
61 {
62 BYTE mask = 0x01;
63
64 if (cBits > 8)
65 return NULL;
66
67 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
68 return NULL;
69
70 UNROLL(cBits, {
71 UINT32 data;
72
73 if (bitmask & mask)
74 data = fgPel;
75 else
76 data = BLACK_PIXEL;
77
78 DESTWRITEPIXEL(pbDest, data);
79 DESTNEXTPIXEL(pbDest);
80 mask = mask << 1;
81 });
82 return pbDest;
83 }
84
85 /**
86 * Decompress an RLE compressed bitmap.
87 */
RLEDECOMPRESS(const BYTE * pbSrcBuffer,UINT32 cbSrcBuffer,BYTE * pbDestBuffer,UINT32 rowDelta,UINT32 width,UINT32 height)88 static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BYTE* pbDestBuffer,
89 UINT32 rowDelta, UINT32 width, UINT32 height)
90 {
91 const BYTE* pbSrc = pbSrcBuffer;
92 const BYTE* pbEnd;
93 const BYTE* pbDestEnd;
94 BYTE* pbDest = pbDestBuffer;
95 PIXEL temp;
96 PIXEL fgPel = WHITE_PIXEL;
97 BOOL fInsertFgPel = FALSE;
98 BOOL fFirstLine = TRUE;
99 BYTE bitmask;
100 PIXEL pixelA, pixelB;
101 UINT32 runLength;
102 UINT32 code;
103 UINT32 advance;
104 RLEEXTRA
105
106 if ((rowDelta == 0) || (rowDelta < width))
107 return FALSE;
108
109 if (!pbSrcBuffer || !pbDestBuffer)
110 return FALSE;
111
112 pbEnd = pbSrcBuffer + cbSrcBuffer;
113 pbDestEnd = pbDestBuffer + rowDelta * height;
114
115 while (pbSrc < pbEnd)
116 {
117 /* Watch out for the end of the first scanline. */
118 if (fFirstLine)
119 {
120 if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta)
121 {
122 fFirstLine = FALSE;
123 fInsertFgPel = FALSE;
124 }
125 }
126
127 /*
128 Extract the compression order code ID from the compression
129 order header.
130 */
131 code = ExtractCodeId(*pbSrc);
132
133 /* Handle Background Run Orders. */
134 if (code == REGULAR_BG_RUN || code == MEGA_MEGA_BG_RUN)
135 {
136 runLength = ExtractRunLength(code, pbSrc, &advance);
137 pbSrc = pbSrc + advance;
138
139 if (fFirstLine)
140 {
141 if (fInsertFgPel)
142 {
143 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
144 return FALSE;
145
146 DESTWRITEPIXEL(pbDest, fgPel);
147 DESTNEXTPIXEL(pbDest);
148 runLength = runLength - 1;
149 }
150
151 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
152 return FALSE;
153
154 UNROLL(runLength, {
155 DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
156 DESTNEXTPIXEL(pbDest);
157 });
158 }
159 else
160 {
161 if (fInsertFgPel)
162 {
163 DESTREADPIXEL(temp, pbDest - rowDelta);
164
165 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
166 return FALSE;
167
168 DESTWRITEPIXEL(pbDest, temp ^ fgPel);
169 DESTNEXTPIXEL(pbDest);
170 runLength--;
171 }
172
173 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
174 return FALSE;
175
176 UNROLL(runLength, {
177 DESTREADPIXEL(temp, pbDest - rowDelta);
178 DESTWRITEPIXEL(pbDest, temp);
179 DESTNEXTPIXEL(pbDest);
180 });
181 }
182
183 /* A follow-on background run order will need a foreground pel inserted. */
184 fInsertFgPel = TRUE;
185 continue;
186 }
187
188 /* For any of the other run-types a follow-on background run
189 order does not need a foreground pel inserted. */
190 fInsertFgPel = FALSE;
191
192 switch (code)
193 {
194 /* Handle Foreground Run Orders. */
195 case REGULAR_FG_RUN:
196 case MEGA_MEGA_FG_RUN:
197 case LITE_SET_FG_FG_RUN:
198 case MEGA_MEGA_SET_FG_RUN:
199 runLength = ExtractRunLength(code, pbSrc, &advance);
200 pbSrc = pbSrc + advance;
201
202 if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
203 {
204 if (pbSrc >= pbEnd)
205 return FALSE;
206 SRCREADPIXEL(fgPel, pbSrc);
207 SRCNEXTPIXEL(pbSrc);
208 }
209
210 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
211 return FALSE;
212
213 if (fFirstLine)
214 {
215 UNROLL(runLength, {
216 DESTWRITEPIXEL(pbDest, fgPel);
217 DESTNEXTPIXEL(pbDest);
218 });
219 }
220 else
221 {
222 UNROLL(runLength, {
223 DESTREADPIXEL(temp, pbDest - rowDelta);
224 DESTWRITEPIXEL(pbDest, temp ^ fgPel);
225 DESTNEXTPIXEL(pbDest);
226 });
227 }
228
229 break;
230
231 /* Handle Dithered Run Orders. */
232 case LITE_DITHERED_RUN:
233 case MEGA_MEGA_DITHERED_RUN:
234 runLength = ExtractRunLength(code, pbSrc, &advance);
235 pbSrc = pbSrc + advance;
236 if (pbSrc >= pbEnd)
237 return FALSE;
238 SRCREADPIXEL(pixelA, pbSrc);
239 SRCNEXTPIXEL(pbSrc);
240 if (pbSrc >= pbEnd)
241 return FALSE;
242 SRCREADPIXEL(pixelB, pbSrc);
243 SRCNEXTPIXEL(pbSrc);
244
245 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
246 return FALSE;
247
248 UNROLL(runLength, {
249 DESTWRITEPIXEL(pbDest, pixelA);
250 DESTNEXTPIXEL(pbDest);
251 DESTWRITEPIXEL(pbDest, pixelB);
252 DESTNEXTPIXEL(pbDest);
253 });
254 break;
255
256 /* Handle Color Run Orders. */
257 case REGULAR_COLOR_RUN:
258 case MEGA_MEGA_COLOR_RUN:
259 runLength = ExtractRunLength(code, pbSrc, &advance);
260 pbSrc = pbSrc + advance;
261 if (pbSrc >= pbEnd)
262 return FALSE;
263 SRCREADPIXEL(pixelA, pbSrc);
264 SRCNEXTPIXEL(pbSrc);
265
266 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
267 return FALSE;
268
269 UNROLL(runLength, {
270 DESTWRITEPIXEL(pbDest, pixelA);
271 DESTNEXTPIXEL(pbDest);
272 });
273 break;
274
275 /* Handle Foreground/Background Image Orders. */
276 case REGULAR_FGBG_IMAGE:
277 case MEGA_MEGA_FGBG_IMAGE:
278 case LITE_SET_FG_FGBG_IMAGE:
279 case MEGA_MEGA_SET_FGBG_IMAGE:
280 runLength = ExtractRunLength(code, pbSrc, &advance);
281 pbSrc = pbSrc + advance;
282
283 if (pbSrc >= pbEnd)
284 return FALSE;
285 if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
286 {
287 SRCREADPIXEL(fgPel, pbSrc);
288 SRCNEXTPIXEL(pbSrc);
289 }
290
291 if (fFirstLine)
292 {
293 while (runLength > 8)
294 {
295 bitmask = *pbSrc;
296 pbSrc = pbSrc + 1;
297 pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8);
298
299 if (!pbDest)
300 return FALSE;
301
302 runLength = runLength - 8;
303 }
304 }
305 else
306 {
307 while (runLength > 8)
308 {
309 bitmask = *pbSrc;
310 pbSrc = pbSrc + 1;
311 pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
312
313 if (!pbDest)
314 return FALSE;
315
316 runLength = runLength - 8;
317 }
318 }
319
320 if (runLength > 0)
321 {
322 bitmask = *pbSrc;
323 pbSrc = pbSrc + 1;
324
325 if (fFirstLine)
326 {
327 pbDest =
328 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength);
329 }
330 else
331 {
332 pbDest =
333 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength);
334 }
335
336 if (!pbDest)
337 return FALSE;
338 }
339
340 break;
341
342 /* Handle Color Image Orders. */
343 case REGULAR_COLOR_IMAGE:
344 case MEGA_MEGA_COLOR_IMAGE:
345 runLength = ExtractRunLength(code, pbSrc, &advance);
346 pbSrc = pbSrc + advance;
347 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
348 return FALSE;
349
350 UNROLL(runLength, {
351 if (pbSrc >= pbEnd)
352 return FALSE;
353 SRCREADPIXEL(temp, pbSrc);
354 SRCNEXTPIXEL(pbSrc);
355 DESTWRITEPIXEL(pbDest, temp);
356 DESTNEXTPIXEL(pbDest);
357 });
358 break;
359
360 /* Handle Special Order 1. */
361 case SPECIAL_FGBG_1:
362 pbSrc = pbSrc + 1;
363
364 if (fFirstLine)
365 {
366 pbDest =
367 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8);
368 }
369 else
370 {
371 pbDest =
372 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
373 }
374
375 if (!pbDest)
376 return FALSE;
377
378 break;
379
380 /* Handle Special Order 2. */
381 case SPECIAL_FGBG_2:
382 pbSrc = pbSrc + 1;
383
384 if (fFirstLine)
385 {
386 pbDest =
387 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8);
388 }
389 else
390 {
391 pbDest =
392 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
393 }
394
395 if (!pbDest)
396 return FALSE;
397
398 break;
399
400 /* Handle White Order. */
401 case SPECIAL_WHITE:
402 pbSrc = pbSrc + 1;
403
404 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
405 return FALSE;
406
407 DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
408 DESTNEXTPIXEL(pbDest);
409 break;
410
411 /* Handle Black Order. */
412 case SPECIAL_BLACK:
413 pbSrc = pbSrc + 1;
414
415 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
416 return FALSE;
417
418 DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
419 DESTNEXTPIXEL(pbDest);
420 break;
421
422 default:
423 return FALSE;
424 }
425 }
426
427 return TRUE;
428 }
429