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