Coverage Report

Created: 2023-09-25 06:56

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