Coverage Report

Created: 2024-09-08 06:16

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