FreeRDP
libfreerdp/codec/include/bitmap.h
1 
22 #include <winpr/assert.h>
23 #include <winpr/cast.h>
24 #include <winpr/wtypes.h>
25 
26 /* do not compile the file directly */
27 
31 static inline BYTE* WRITEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
32  const BYTE* WINPR_RESTRICT pbDestEnd, UINT32 rowDelta,
33  BYTE bitmask, PIXEL fgPel, UINT32 cBits)
34 {
35  PIXEL xorPixel = 0;
36  BYTE mask = 0x01;
37 
38  if (cBits > 8)
39  {
40  WLog_ERR(TAG, "cBits %d > 8", cBits);
41  return NULL;
42  }
43 
44  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
45  return NULL;
46 
47  UNROLL(cBits, {
48  PIXEL data = 0;
49  DESTREADPIXEL(xorPixel, pbDest - rowDelta);
50 
51  if (bitmask & mask)
52  data = xorPixel ^ fgPel;
53  else
54  data = xorPixel;
55 
56  DESTWRITEPIXEL(pbDest, data);
57  mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
58  });
59  return pbDest;
60 }
61 
66 static inline BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
67  const BYTE* WINPR_RESTRICT pbDestEnd, BYTE bitmask,
68  PIXEL fgPel, UINT32 cBits)
69 {
70  BYTE mask = 0x01;
71 
72  if (cBits > 8)
73  {
74  WLog_ERR(TAG, "cBits %d > 8", cBits);
75  return NULL;
76  }
77 
78  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
79  return NULL;
80 
81  UNROLL(cBits, {
82  PIXEL data;
83 
84  if (bitmask & mask)
85  data = fgPel;
86  else
87  data = BLACK_PIXEL;
88 
89  DESTWRITEPIXEL(pbDest, data);
90  mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
91  });
92  return pbDest;
93 }
94 
98 static inline BOOL RLEDECOMPRESS(const BYTE* WINPR_RESTRICT pbSrcBuffer, UINT32 cbSrcBuffer,
99  BYTE* WINPR_RESTRICT pbDestBuffer, UINT32 rowDelta, UINT32 width,
100  UINT32 height)
101 {
102 #if defined(WITH_DEBUG_CODECS)
103  char sbuffer[128] = { 0 };
104 #endif
105  const BYTE* pbSrc = pbSrcBuffer;
106  BYTE* pbDest = pbDestBuffer;
107  PIXEL temp = 0;
108  PIXEL fgPel = WHITE_PIXEL;
109  BOOL fInsertFgPel = FALSE;
110  BOOL fFirstLine = TRUE;
111  BYTE bitmask = 0;
112  PIXEL pixelA = 0;
113  PIXEL pixelB = 0;
114  UINT32 runLength = 0;
115  UINT32 code = 0;
116  UINT32 advance = 0;
117  RLEEXTRA
118 
119  if ((rowDelta == 0) || (rowDelta < width))
120  {
121  WLog_ERR(TAG, "Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32, rowDelta,
122  width);
123  return FALSE;
124  }
125 
126  if (!pbSrcBuffer || !pbDestBuffer)
127  {
128  WLog_ERR(TAG, "Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p", pbSrcBuffer,
129  pbDestBuffer);
130  return FALSE;
131  }
132 
133  const BYTE* pbEnd = &pbSrcBuffer[cbSrcBuffer];
134  const BYTE* pbDestEnd = &pbDestBuffer[1ULL * rowDelta * height];
135 
136  while (pbSrc < pbEnd)
137  {
138  /* Watch out for the end of the first scanline. */
139  if (fFirstLine)
140  {
141  if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta)
142  {
143  fFirstLine = FALSE;
144  fInsertFgPel = FALSE;
145  }
146  }
147 
148  /*
149  Extract the compression order code ID from the compression
150  order header.
151  */
152  code = ExtractCodeId(*pbSrc);
153 
154 #if defined(WITH_DEBUG_CODECS)
155  WLog_VRB(TAG, "pbSrc=%p code=%s, rem=%" PRIuz, pbSrc,
156  rle_code_str_buffer(code, sbuffer, sizeof(sbuffer)), pbEnd - pbSrc);
157 #endif
158 
159  /* Handle Background Run Orders. */
160  if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN))
161  {
162  runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
163  if (advance == 0)
164  return FALSE;
165  pbSrc = pbSrc + advance;
166 
167  if (fFirstLine)
168  {
169  if (fInsertFgPel)
170  {
171  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
172  return FALSE;
173 
174  DESTWRITEPIXEL(pbDest, fgPel);
175  runLength = runLength - 1;
176  }
177 
178  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
179  return FALSE;
180 
181  UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); });
182  }
183  else
184  {
185  if (fInsertFgPel)
186  {
187  DESTREADPIXEL(temp, pbDest - rowDelta);
188 
189  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
190  return FALSE;
191 
192  DESTWRITEPIXEL(pbDest, temp ^ fgPel);
193  runLength--;
194  }
195 
196  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
197  return FALSE;
198 
199  UNROLL(runLength, {
200  DESTREADPIXEL(temp, pbDest - rowDelta);
201  DESTWRITEPIXEL(pbDest, temp);
202  });
203  }
204 
205  /* A follow-on background run order will need a foreground pel inserted. */
206  fInsertFgPel = TRUE;
207  continue;
208  }
209 
210  /* For any of the other run-types a follow-on background run
211  order does not need a foreground pel inserted. */
212  fInsertFgPel = FALSE;
213 
214  switch (code)
215  {
216  /* Handle Foreground Run Orders. */
217  case REGULAR_FG_RUN:
218  case MEGA_MEGA_FG_RUN:
219  case LITE_SET_FG_FG_RUN:
220  case MEGA_MEGA_SET_FG_RUN:
221  runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
222  if (advance == 0)
223  return FALSE;
224  pbSrc = pbSrc + advance;
225 
226  if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
227  {
228  if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
229  return FALSE;
230  SRCREADPIXEL(fgPel, pbSrc);
231  }
232 
233  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
234  return FALSE;
235 
236  if (fFirstLine)
237  {
238  UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); });
239  }
240  else
241  {
242  UNROLL(runLength, {
243  DESTREADPIXEL(temp, pbDest - rowDelta);
244  DESTWRITEPIXEL(pbDest, temp ^ fgPel);
245  });
246  }
247 
248  break;
249 
250  /* Handle Dithered Run Orders. */
251  case LITE_DITHERED_RUN:
252  case MEGA_MEGA_DITHERED_RUN:
253  runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
254  if (advance == 0)
255  return FALSE;
256  pbSrc = pbSrc + advance;
257  if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
258  return FALSE;
259  SRCREADPIXEL(pixelA, pbSrc);
260  if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
261  return FALSE;
262  SRCREADPIXEL(pixelB, pbSrc);
263 
264  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
265  return FALSE;
266 
267  UNROLL(runLength, {
268  DESTWRITEPIXEL(pbDest, pixelA);
269  DESTWRITEPIXEL(pbDest, pixelB);
270  });
271  break;
272 
273  /* Handle Color Run Orders. */
274  case REGULAR_COLOR_RUN:
275  case MEGA_MEGA_COLOR_RUN:
276  runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
277  if (advance == 0)
278  return FALSE;
279  pbSrc = pbSrc + advance;
280  if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
281  return FALSE;
282  SRCREADPIXEL(pixelA, pbSrc);
283 
284  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
285  return FALSE;
286 
287  UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); });
288  break;
289 
290  /* Handle Foreground/Background Image Orders. */
291  case REGULAR_FGBG_IMAGE:
292  case MEGA_MEGA_FGBG_IMAGE:
293  case LITE_SET_FG_FGBG_IMAGE:
294  case MEGA_MEGA_SET_FGBG_IMAGE:
295  runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
296  if (advance == 0)
297  return FALSE;
298  pbSrc = pbSrc + advance;
299 
300  if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
301  {
302  if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
303  return FALSE;
304  SRCREADPIXEL(fgPel, pbSrc);
305  }
306 
307  if (!buffer_within_range(pbSrc, runLength / 8, pbEnd))
308  return FALSE;
309  if (fFirstLine)
310  {
311  while (runLength > 8)
312  {
313  bitmask = *pbSrc;
314  pbSrc = pbSrc + 1;
315  pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8);
316 
317  if (!pbDest)
318  return FALSE;
319 
320  runLength = runLength - 8;
321  }
322  }
323  else
324  {
325  while (runLength > 8)
326  {
327  bitmask = *pbSrc++;
328 
329  pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
330 
331  if (!pbDest)
332  return FALSE;
333 
334  runLength = runLength - 8;
335  }
336  }
337 
338  if (runLength > 0)
339  {
340  if (!buffer_within_range(pbSrc, 1, pbEnd))
341  return FALSE;
342  bitmask = *pbSrc++;
343 
344  if (fFirstLine)
345  {
346  pbDest =
347  WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength);
348  }
349  else
350  {
351  pbDest =
352  WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength);
353  }
354 
355  if (!pbDest)
356  return FALSE;
357  }
358 
359  break;
360 
361  /* Handle Color Image Orders. */
362  case REGULAR_COLOR_IMAGE:
363  case MEGA_MEGA_COLOR_IMAGE:
364  runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
365  if (advance == 0)
366  return FALSE;
367  pbSrc = pbSrc + advance;
368  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
369  return FALSE;
370  if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength))
371  return FALSE;
372 
373  UNROLL(runLength, {
374  SRCREADPIXEL(temp, pbSrc);
375  DESTWRITEPIXEL(pbDest, temp);
376  });
377  break;
378 
379  /* Handle Special Order 1. */
380  case SPECIAL_FGBG_1:
381  if (!buffer_within_range(pbSrc, 1, pbEnd))
382  return FALSE;
383  pbSrc = pbSrc + 1;
384 
385  if (fFirstLine)
386  {
387  pbDest =
388  WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8);
389  }
390  else
391  {
392  pbDest =
393  WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
394  }
395 
396  if (!pbDest)
397  return FALSE;
398 
399  break;
400 
401  /* Handle Special Order 2. */
402  case SPECIAL_FGBG_2:
403  if (!buffer_within_range(pbSrc, 1, pbEnd))
404  return FALSE;
405  pbSrc = pbSrc + 1;
406 
407  if (fFirstLine)
408  {
409  pbDest =
410  WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8);
411  }
412  else
413  {
414  pbDest =
415  WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
416  }
417 
418  if (!pbDest)
419  return FALSE;
420 
421  break;
422 
423  /* Handle White Order. */
424  case SPECIAL_WHITE:
425  if (!buffer_within_range(pbSrc, 1, pbEnd))
426  return FALSE;
427  pbSrc = pbSrc + 1;
428 
429  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
430  return FALSE;
431 
432  DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
433  break;
434 
435  /* Handle Black Order. */
436  case SPECIAL_BLACK:
437  if (!buffer_within_range(pbSrc, 1, pbEnd))
438  return FALSE;
439  pbSrc = pbSrc + 1;
440 
441  if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
442  return FALSE;
443 
444  DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
445  break;
446 
447  default:
448  WLog_ERR(TAG, "invalid code 0x%08" PRIx32 ", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p",
449  code, pbSrcBuffer, pbSrc, pbEnd);
450  return FALSE;
451  }
452  }
453 
454  return TRUE;
455 }