Coverage Report

Created: 2024-09-08 06:16

/src/FreeRDP/libfreerdp/codec/bitmap.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Bitmap Compression
4
 *
5
 * Copyright 2004-2012 Jay Sorg <jay.sorg@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <freerdp/config.h>
21
22
#include <freerdp/codec/bitmap.h>
23
#include <freerdp/codec/planar.h>
24
25
static INLINE UINT16 GETPIXEL16(const void* WINPR_RESTRICT d, UINT32 x, UINT32 y, UINT32 w)
26
0
{
27
0
  const BYTE* WINPR_RESTRICT src = (const BYTE*)d + ((y * w + x) * sizeof(UINT16));
28
0
  return (UINT16)(((UINT16)src[1] << 8) | (UINT16)src[0]);
29
0
}
30
31
static INLINE UINT32 GETPIXEL32(const void* WINPR_RESTRICT d, UINT32 x, UINT32 y, UINT32 w)
32
0
{
33
0
  const BYTE* WINPR_RESTRICT src = (const BYTE*)d + ((y * w + x) * sizeof(UINT32));
34
0
  return (((UINT32)src[3]) << 24) | (((UINT32)src[2]) << 16) | (((UINT32)src[1]) << 8) |
35
0
         (src[0] & 0xFF);
36
0
}
37
38
/*****************************************************************************/
39
static INLINE UINT16 IN_PIXEL16(const void* WINPR_RESTRICT in_ptr, UINT32 in_x, UINT32 in_y,
40
                                UINT32 in_w, UINT16 in_last_pixel)
41
0
{
42
0
  if (in_ptr == 0)
43
0
    return 0;
44
0
  else if (in_x < in_w)
45
0
    return GETPIXEL16(in_ptr, in_x, in_y, in_w);
46
0
  else
47
0
    return in_last_pixel;
48
0
}
49
50
/*****************************************************************************/
51
static INLINE UINT32 IN_PIXEL32(const void* WINPR_RESTRICT in_ptr, UINT32 in_x, UINT32 in_y,
52
                                UINT32 in_w, UINT32 in_last_pixel)
53
0
{
54
0
  if (in_ptr == 0)
55
0
    return 0;
56
0
  else if (in_x < in_w)
57
0
    return GETPIXEL32(in_ptr, in_x, in_y, in_w);
58
0
  else
59
0
    return in_last_pixel;
60
0
}
61
62
/*****************************************************************************/
63
/* color */
64
static INLINE UINT16 out_color_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
65
                                       UINT16 in_data)
66
0
{
67
0
  if (in_count > 0)
68
0
  {
69
0
    if (in_count < 32)
70
0
    {
71
0
      const BYTE temp = ((0x3 << 5) | in_count) & 0xFF;
72
0
      Stream_Write_UINT8(in_s, temp);
73
0
    }
74
0
    else if (in_count < 256 + 32)
75
0
    {
76
0
      const BYTE temp = (in_count - 32) & 0xFF;
77
0
      Stream_Write_UINT8(in_s, 0x60);
78
0
      Stream_Write_UINT8(in_s, temp);
79
0
    }
80
0
    else
81
0
    {
82
0
      Stream_Write_UINT8(in_s, 0xf3);
83
0
      Stream_Write_UINT16(in_s, in_count);
84
0
    }
85
86
0
    Stream_Write_UINT16(in_s, in_data);
87
0
  }
88
89
0
  return 0;
90
0
}
91
#define OUT_COLOR_COUNT2(in_count, in_s, in_data) \
92
0
  in_count = out_color_count_2(in_count, in_s, in_data)
93
94
/*****************************************************************************/
95
/* color */
96
static INLINE UINT16 out_color_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
97
                                       UINT32 in_data)
98
0
{
99
0
  if (in_count > 0)
100
0
  {
101
0
    if (in_count < 32)
102
0
    {
103
0
      const BYTE temp = ((0x3 << 5) | in_count) & 0xFF;
104
0
      Stream_Write_UINT8(in_s, temp);
105
0
    }
106
0
    else if (in_count < 256 + 32)
107
0
    {
108
0
      const BYTE temp = (in_count - 32) & 0xFF;
109
0
      Stream_Write_UINT8(in_s, 0x60);
110
0
      Stream_Write_UINT8(in_s, temp);
111
0
    }
112
0
    else
113
0
    {
114
0
      Stream_Write_UINT8(in_s, 0xf3);
115
0
      Stream_Write_UINT16(in_s, in_count);
116
0
    }
117
118
0
    Stream_Write_UINT8(in_s, in_data & 0xFF);
119
120
0
    Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF);
121
0
    Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF);
122
0
  }
123
124
0
  return 0;
125
0
}
126
127
#define OUT_COLOR_COUNT3(in_count, in_s, in_data) \
128
0
  in_count = out_color_count_3(in_count, in_s, in_data)
129
130
/*****************************************************************************/
131
/* copy */
132
static INLINE UINT16 out_copy_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
133
                                      wStream* WINPR_RESTRICT in_data)
134
135
0
{
136
0
  if (in_count > 0)
137
0
  {
138
0
    if (in_count < 32)
139
0
    {
140
0
      const BYTE temp = ((0x4 << 5) | in_count) & 0xFF;
141
0
      Stream_Write_UINT8(in_s, temp);
142
0
    }
143
0
    else if (in_count < 256 + 32)
144
0
    {
145
0
      const BYTE temp = (in_count - 32) & 0xFF;
146
0
      Stream_Write_UINT8(in_s, 0x80);
147
0
      Stream_Write_UINT8(in_s, temp);
148
0
    }
149
0
    else
150
0
    {
151
0
      Stream_Write_UINT8(in_s, 0xf4);
152
0
      Stream_Write_UINT16(in_s, in_count);
153
0
    }
154
155
0
    Stream_Write(in_s, Stream_Buffer(in_data), 2ULL * in_count);
156
0
  }
157
158
0
  Stream_SetPosition(in_data, 0);
159
0
  return 0;
160
0
}
161
#define OUT_COPY_COUNT2(in_count, in_s, in_data) \
162
0
  in_count = out_copy_count_2(in_count, in_s, in_data)
163
/*****************************************************************************/
164
/* copy */
165
static INLINE UINT16 out_copy_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
166
                                      wStream* WINPR_RESTRICT in_data)
167
0
{
168
0
  if (in_count > 0)
169
0
  {
170
0
    if (in_count < 32)
171
0
    {
172
0
      const BYTE temp = ((0x4 << 5) | in_count) & 0xFF;
173
0
      Stream_Write_UINT8(in_s, temp);
174
0
    }
175
0
    else if (in_count < 256 + 32)
176
0
    {
177
0
      const BYTE temp = (in_count - 32) & 0xFF;
178
0
      Stream_Write_UINT8(in_s, 0x80);
179
0
      Stream_Write_UINT8(in_s, temp);
180
0
    }
181
0
    else
182
0
    {
183
0
      Stream_Write_UINT8(in_s, 0xf4);
184
0
      Stream_Write_UINT16(in_s, in_count);
185
0
    }
186
187
0
    Stream_Write(in_s, Stream_Pointer(in_data), 3ULL * in_count);
188
0
  }
189
190
0
  Stream_SetPosition(in_data, 0);
191
0
  return 0;
192
0
}
193
#define OUT_COPY_COUNT3(in_count, in_s, in_data) \
194
0
  in_count = out_copy_count_3(in_count, in_s, in_data)
195
196
/*****************************************************************************/
197
/* bicolor */
198
static INLINE UINT16 out_bicolor_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
199
                                         UINT16 in_color1, UINT16 in_color2)
200
0
{
201
0
  if (in_count > 0)
202
0
  {
203
0
    if (in_count / 2 < 16)
204
0
    {
205
0
      const BYTE temp = ((0xe << 4) | (in_count / 2)) & 0xFF;
206
0
      Stream_Write_UINT8(in_s, temp);
207
0
    }
208
0
    else if (in_count / 2 < 256 + 16)
209
0
    {
210
0
      const BYTE temp = (in_count / 2 - 16) & 0xFF;
211
0
      Stream_Write_UINT8(in_s, 0xe0);
212
0
      Stream_Write_UINT8(in_s, temp);
213
0
    }
214
0
    else
215
0
    {
216
0
      Stream_Write_UINT8(in_s, 0xf8);
217
0
      Stream_Write_UINT16(in_s, in_count / 2);
218
0
    }
219
220
0
    Stream_Write_UINT16(in_s, in_color1);
221
0
    Stream_Write_UINT16(in_s, in_color2);
222
0
  }
223
224
0
  return 0;
225
0
}
226
227
#define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \
228
0
  in_count = out_bicolor_count_2(in_count, in_s, in_color1, in_color2)
229
230
/*****************************************************************************/
231
/* bicolor */
232
static INLINE UINT16 out_bicolor_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
233
                                         UINT32 in_color1, UINT32 in_color2)
234
0
{
235
0
  if (in_count > 0)
236
0
  {
237
0
    if (in_count / 2 < 16)
238
0
    {
239
0
      const BYTE temp = ((0xe << 4) | (in_count / 2)) & 0xFF;
240
0
      Stream_Write_UINT8(in_s, temp);
241
0
    }
242
0
    else if (in_count / 2 < 256 + 16)
243
0
    {
244
0
      const BYTE temp = (in_count / 2 - 16) & 0xFF;
245
0
      Stream_Write_UINT8(in_s, 0xe0);
246
0
      Stream_Write_UINT8(in_s, temp);
247
0
    }
248
0
    else
249
0
    {
250
0
      Stream_Write_UINT8(in_s, 0xf8);
251
0
      Stream_Write_UINT16(in_s, in_count / 2);
252
0
    }
253
254
0
    Stream_Write_UINT8(in_s, in_color1 & 0xFF);
255
0
    Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF);
256
0
    Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF);
257
0
    Stream_Write_UINT8(in_s, in_color2 & 0xFF);
258
0
    Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF);
259
0
    Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF);
260
0
  }
261
262
0
  return 0;
263
0
}
264
265
#define OUT_BICOLOR_COUNT3(in_count, in_s, in_color1, in_color2) \
266
0
  in_count = out_bicolor_count_3(in_count, in_s, in_color1, in_color2)
267
268
/*****************************************************************************/
269
/* fill */
270
static INLINE UINT16 out_fill_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s)
271
0
{
272
0
  if (in_count > 0)
273
0
  {
274
0
    if (in_count < 32)
275
0
    {
276
0
      Stream_Write_UINT8(in_s, in_count & 0xFF);
277
0
    }
278
0
    else if (in_count < 256 + 32)
279
0
    {
280
0
      const BYTE temp = (in_count - 32) & 0xFF;
281
0
      Stream_Write_UINT8(in_s, 0x0);
282
0
      Stream_Write_UINT8(in_s, temp);
283
0
    }
284
0
    else
285
0
    {
286
0
      Stream_Write_UINT8(in_s, 0xf0);
287
0
      Stream_Write_UINT16(in_s, in_count);
288
0
    }
289
0
  }
290
291
0
  return 0;
292
0
}
293
294
0
#define OUT_FILL_COUNT2(in_count, in_s) in_count = out_fill_count_2(in_count, in_s)
295
296
/*****************************************************************************/
297
/* fill */
298
static INLINE UINT16 out_fill_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s)
299
0
{
300
0
  if (in_count > 0)
301
0
  {
302
0
    if (in_count < 32)
303
0
    {
304
0
      Stream_Write_UINT8(in_s, in_count & 0xFF);
305
0
    }
306
0
    else if (in_count < 256 + 32)
307
0
    {
308
0
      const BYTE temp = (in_count - 32) & 0xFF;
309
0
      Stream_Write_UINT8(in_s, 0x0);
310
0
      Stream_Write_UINT8(in_s, temp);
311
0
    }
312
0
    else
313
0
    {
314
0
      Stream_Write_UINT8(in_s, 0xf0);
315
0
      Stream_Write_UINT16(in_s, in_count);
316
0
    }
317
0
  }
318
319
0
  return 0;
320
0
}
321
0
#define OUT_FILL_COUNT3(in_count, in_s) in_count = out_fill_count_3(in_count, in_s)
322
323
/*****************************************************************************/
324
/* mix */
325
static INLINE UINT16 out_mix_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s)
326
0
{
327
0
  if (in_count > 0)
328
0
  {
329
0
    if (in_count < 32)
330
0
    {
331
0
      const BYTE temp = ((0x1 << 5) | in_count) & 0xFF;
332
0
      Stream_Write_UINT8(in_s, temp);
333
0
    }
334
0
    else if (in_count < 256 + 32)
335
0
    {
336
0
      const BYTE temp = (in_count - 32) & 0xFF;
337
0
      Stream_Write_UINT8(in_s, 0x20);
338
0
      Stream_Write_UINT8(in_s, temp);
339
0
    }
340
0
    else
341
0
    {
342
0
      Stream_Write_UINT8(in_s, 0xf1);
343
0
      Stream_Write_UINT16(in_s, in_count);
344
0
    }
345
0
  }
346
347
0
  return 0;
348
0
}
349
0
#define OUT_MIX_COUNT2(in_count, in_s) in_count = out_mix_count_2(in_count, in_s)
350
351
/*****************************************************************************/
352
/* mix */
353
static INLINE UINT16 out_mix_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s)
354
0
{
355
0
  if (in_count > 0)
356
0
  {
357
0
    if (in_count < 32)
358
0
    {
359
0
      const BYTE temp = ((0x1 << 5) | in_count) & 0xFF;
360
0
      Stream_Write_UINT8(in_s, temp);
361
0
    }
362
0
    else if (in_count < 256 + 32)
363
0
    {
364
0
      const BYTE temp = (in_count - 32) & 0xFF;
365
0
      Stream_Write_UINT8(in_s, 0x20);
366
0
      Stream_Write_UINT8(in_s, temp);
367
0
    }
368
0
    else
369
0
    {
370
0
      Stream_Write_UINT8(in_s, 0xf1);
371
0
      Stream_Write_UINT16(in_s, in_count);
372
0
    }
373
0
  }
374
375
0
  return 0;
376
0
}
377
378
0
#define OUT_MIX_COUNT3(in_count, in_s) in_count = out_mix_count_3(in_count, in_s)
379
380
/*****************************************************************************/
381
/* fom */
382
static INLINE UINT16 out_from_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
383
                                      const char* WINPR_RESTRICT in_mask, size_t in_mask_len)
384
0
{
385
0
  if (in_count > 0)
386
0
  {
387
0
    if ((in_count % 8) == 0 && in_count < 249)
388
0
    {
389
0
      const BYTE temp = ((0x2 << 5) | (in_count / 8)) & 0xFF;
390
0
      Stream_Write_UINT8(in_s, temp);
391
0
    }
392
0
    else if (in_count < 256)
393
0
    {
394
0
      const BYTE temp = (in_count - 1) & 0xFF;
395
0
      Stream_Write_UINT8(in_s, 0x40);
396
0
      Stream_Write_UINT8(in_s, temp);
397
0
    }
398
0
    else
399
0
    {
400
0
      Stream_Write_UINT8(in_s, 0xf2);
401
0
      Stream_Write_UINT16(in_s, in_count);
402
0
    }
403
404
0
    Stream_Write(in_s, in_mask, in_mask_len);
405
0
  }
406
407
0
  return 0;
408
0
}
409
#define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \
410
0
  in_count = out_from_count_2(in_count, in_s, in_mask, in_mask_len)
411
412
/*****************************************************************************/
413
/* fill or mix (fom) */
414
static INLINE UINT16 out_from_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
415
                                      const char* WINPR_RESTRICT in_mask, size_t in_mask_len)
416
0
{
417
0
  if (in_count > 0)
418
0
  {
419
0
    if ((in_count % 8) == 0 && in_count < 249)
420
0
    {
421
0
      const BYTE temp = ((0x2 << 5) | (in_count / 8)) & 0xFF;
422
0
      Stream_Write_UINT8(in_s, temp);
423
0
    }
424
0
    else if (in_count < 256)
425
0
    {
426
0
      const BYTE temp = (in_count - 1) & 0xFF;
427
0
      Stream_Write_UINT8(in_s, 0x40);
428
0
      Stream_Write_UINT8(in_s, temp);
429
0
    }
430
0
    else
431
0
    {
432
0
      Stream_Write_UINT8(in_s, 0xf2);
433
0
      Stream_Write_UINT16(in_s, in_count);
434
0
    }
435
436
0
    Stream_Write(in_s, in_mask, in_mask_len);
437
0
  }
438
439
0
  return 0;
440
0
}
441
#define OUT_FOM_COUNT3(in_count, in_s, in_mask, in_mask_len) \
442
0
  in_count = out_from_count_3(in_count, in_s, in_mask, in_mask_len)
443
444
0
#define TEST_FILL ((last_line == 0 && pixel == 0) || (last_line != 0 && pixel == ypixel))
445
0
#define TEST_MIX ((last_line == 0 && pixel == mix) || (last_line != 0 && pixel == (ypixel ^ mix)))
446
0
#define TEST_FOM TEST_FILL || TEST_MIX
447
0
#define TEST_COLOR pixel == last_pixel
448
#define TEST_BICOLOR                                                        \
449
0
  ((pixel != last_pixel) &&                                               \
450
0
   ((!bicolor_spin && (pixel == bicolor1) && (last_pixel == bicolor2)) || \
451
0
    (bicolor_spin && (pixel == bicolor2) && (last_pixel == bicolor1))))
452
#define RESET_COUNTS          \
453
0
  do                        \
454
0
  {                         \
455
0
    bicolor_count = 0;    \
456
0
    fill_count = 0;       \
457
0
    color_count = 0;      \
458
0
    mix_count = 0;        \
459
0
    fom_count = 0;        \
460
0
    fom_mask_len = 0;     \
461
0
    bicolor_spin = FALSE; \
462
0
  } while (0)
463
464
static INLINE SSIZE_T freerdp_bitmap_compress_24(const void* WINPR_RESTRICT srcData, UINT32 width,
465
                                                 UINT32 height, wStream* WINPR_RESTRICT s,
466
                                                 UINT32 byte_limit, UINT32 start_line,
467
                                                 wStream* WINPR_RESTRICT temp_s, UINT32 e)
468
0
{
469
0
  char fom_mask[8192] = { 0 }; /* good for up to 64K bitmap */
470
0
  SSIZE_T lines_sent = 0;
471
0
  UINT16 count = 0;
472
0
  UINT16 color_count = 0;
473
0
  UINT32 last_pixel = 0;
474
0
  UINT32 last_ypixel = 0;
475
0
  UINT16 bicolor_count = 0;
476
0
  UINT32 bicolor1 = 0;
477
0
  UINT32 bicolor2 = 0;
478
0
  BOOL bicolor_spin = FALSE;
479
0
  UINT32 end = width + e;
480
0
  UINT32 out_count = end * 3;
481
0
  UINT16 fill_count = 0;
482
0
  UINT16 mix_count = 0;
483
0
  const UINT32 mix = 0xFFFFFF;
484
0
  UINT16 fom_count = 0;
485
0
  size_t fom_mask_len = 0;
486
0
  const char* start = (const char*)srcData;
487
0
  const char* line = start + 4ULL * width * start_line;
488
0
  const char* last_line = NULL;
489
490
0
  while ((line >= start) && (out_count < 32768))
491
0
  {
492
0
    size_t i = Stream_GetPosition(s) + 3ULL * count;
493
494
0
    if ((i - (3ULL * color_count) >= byte_limit) &&
495
0
        (i - (3ULL * bicolor_count) >= byte_limit) && (i - (3ULL * fill_count) >= byte_limit) &&
496
0
        (i - (3ULL * mix_count) >= byte_limit) && (i - (3ULL * fom_count) >= byte_limit))
497
0
    {
498
0
      break;
499
0
    }
500
501
0
    out_count += end * 3;
502
503
0
    for (UINT32 j = 0; j < end; j++)
504
0
    {
505
      /* read next pixel */
506
0
      const UINT32 pixel = IN_PIXEL32(line, j, 0, width, last_pixel);
507
0
      const UINT32 ypixel = IN_PIXEL32(last_line, j, 0, width, last_ypixel);
508
509
0
      if (!TEST_FILL)
510
0
      {
511
0
        if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
512
0
            fill_count >= mix_count && fill_count >= fom_count)
513
0
        {
514
0
          if (fill_count > count)
515
0
            return -1;
516
517
0
          count -= fill_count;
518
0
          OUT_COPY_COUNT3(count, s, temp_s);
519
0
          OUT_FILL_COUNT3(fill_count, s);
520
0
          RESET_COUNTS;
521
0
        }
522
523
0
        fill_count = 0;
524
0
      }
525
526
0
      if (!TEST_MIX)
527
0
      {
528
0
        if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count &&
529
0
            mix_count >= color_count && mix_count >= fom_count)
530
0
        {
531
0
          if (mix_count > count)
532
0
            return -1;
533
534
0
          count -= mix_count;
535
0
          OUT_COPY_COUNT3(count, s, temp_s);
536
0
          OUT_MIX_COUNT3(mix_count, s);
537
0
          RESET_COUNTS;
538
0
        }
539
540
0
        mix_count = 0;
541
0
      }
542
543
0
      if (!(TEST_COLOR))
544
0
      {
545
0
        if (color_count > 3 && color_count >= fill_count && color_count >= bicolor_count &&
546
0
            color_count >= mix_count && color_count >= fom_count)
547
0
        {
548
0
          if (color_count > count)
549
0
            return -1;
550
551
0
          count -= color_count;
552
0
          OUT_COPY_COUNT3(count, s, temp_s);
553
0
          OUT_COLOR_COUNT3(color_count, s, last_pixel);
554
0
          RESET_COUNTS;
555
0
        }
556
557
0
        color_count = 0;
558
0
      }
559
560
0
      if (!TEST_BICOLOR)
561
0
      {
562
0
        if (bicolor_count > 3 && bicolor_count >= fill_count &&
563
0
            bicolor_count >= color_count && bicolor_count >= mix_count &&
564
0
            bicolor_count >= fom_count)
565
0
        {
566
0
          if ((bicolor_count % 2) != 0)
567
0
            bicolor_count--;
568
569
0
          if (bicolor_count > count)
570
0
            return -1;
571
572
0
          count -= bicolor_count;
573
0
          OUT_COPY_COUNT3(count, s, temp_s);
574
0
          OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1);
575
0
          RESET_COUNTS;
576
0
        }
577
578
0
        bicolor_count = 0;
579
0
        bicolor1 = last_pixel;
580
0
        bicolor2 = pixel;
581
0
        bicolor_spin = FALSE;
582
0
      }
583
584
0
      if (!(TEST_FOM))
585
0
      {
586
0
        if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count &&
587
0
            fom_count >= mix_count && fom_count >= bicolor_count)
588
0
        {
589
0
          if (fom_count > count)
590
0
            return -1;
591
592
0
          count -= fom_count;
593
0
          OUT_COPY_COUNT3(count, s, temp_s);
594
0
          OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len);
595
0
          RESET_COUNTS;
596
0
        }
597
598
0
        fom_count = 0;
599
0
        fom_mask_len = 0;
600
0
      }
601
602
0
      if (TEST_FILL)
603
0
      {
604
0
        fill_count++;
605
0
      }
606
607
0
      if (TEST_MIX)
608
0
      {
609
0
        mix_count++;
610
0
      }
611
612
0
      if (TEST_COLOR)
613
0
      {
614
0
        color_count++;
615
0
      }
616
617
0
      if (TEST_BICOLOR)
618
0
      {
619
0
        bicolor_spin = !bicolor_spin;
620
0
        bicolor_count++;
621
0
      }
622
623
0
      if (TEST_FOM)
624
0
      {
625
0
        if ((fom_count % 8) == 0)
626
0
        {
627
0
          fom_mask[fom_mask_len] = 0;
628
0
          fom_mask_len++;
629
0
        }
630
631
0
        if (pixel == (ypixel ^ mix))
632
0
        {
633
0
          fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8));
634
0
        }
635
636
0
        fom_count++;
637
0
      }
638
639
0
      Stream_Write_UINT8(temp_s, pixel & 0xff);
640
0
      Stream_Write_UINT8(temp_s, (pixel >> 8) & 0xff);
641
0
      Stream_Write_UINT8(temp_s, (pixel >> 16) & 0xff);
642
0
      count++;
643
0
      last_pixel = pixel;
644
0
      last_ypixel = ypixel;
645
0
    }
646
647
    /* can't take fix, mix, or fom past first line */
648
0
    if (last_line == 0)
649
0
    {
650
0
      if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
651
0
          fill_count >= mix_count && fill_count >= fom_count)
652
0
      {
653
0
        if (fill_count > count)
654
0
          return -1;
655
656
0
        count -= fill_count;
657
0
        OUT_COPY_COUNT3(count, s, temp_s);
658
0
        OUT_FILL_COUNT3(fill_count, s);
659
0
        RESET_COUNTS;
660
0
      }
661
662
0
      fill_count = 0;
663
664
0
      if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count &&
665
0
          mix_count >= color_count && mix_count >= fom_count)
666
0
      {
667
0
        if (mix_count > count)
668
0
          return -1;
669
670
0
        count -= mix_count;
671
0
        OUT_COPY_COUNT3(count, s, temp_s);
672
0
        OUT_MIX_COUNT3(mix_count, s);
673
0
        RESET_COUNTS;
674
0
      }
675
676
0
      mix_count = 0;
677
678
0
      if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count &&
679
0
          fom_count >= mix_count && fom_count >= bicolor_count)
680
0
      {
681
0
        if (fom_count > count)
682
0
          return -1;
683
684
0
        count -= fom_count;
685
0
        OUT_COPY_COUNT3(count, s, temp_s);
686
0
        OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len);
687
0
        RESET_COUNTS;
688
0
      }
689
690
0
      fom_count = 0;
691
0
      fom_mask_len = 0;
692
0
    }
693
694
0
    last_line = line;
695
0
    line = line - 4ULL * width;
696
0
    start_line--;
697
0
    lines_sent++;
698
0
  }
699
700
0
  Stream_SetPosition(temp_s, 0);
701
702
0
  if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
703
0
      fill_count >= mix_count && fill_count >= fom_count)
704
0
  {
705
0
    if (fill_count > count)
706
0
      return -1;
707
708
0
    count -= fill_count;
709
0
    OUT_COPY_COUNT3(count, s, temp_s);
710
0
    OUT_FILL_COUNT3(fill_count, s);
711
0
  }
712
0
  else if (mix_count > 3 && mix_count >= color_count && mix_count >= bicolor_count &&
713
0
           mix_count >= fill_count && mix_count >= fom_count)
714
0
  {
715
0
    if (mix_count > count)
716
0
      return -1;
717
718
0
    count -= mix_count;
719
0
    OUT_COPY_COUNT3(count, s, temp_s);
720
0
    OUT_MIX_COUNT3(mix_count, s);
721
0
  }
722
0
  else if (color_count > 3 && color_count >= mix_count && color_count >= bicolor_count &&
723
0
           color_count >= fill_count && color_count >= fom_count)
724
0
  {
725
0
    if (color_count > count)
726
0
      return -1;
727
728
0
    count -= color_count;
729
0
    OUT_COPY_COUNT3(count, s, temp_s);
730
0
    OUT_COLOR_COUNT3(color_count, s, last_pixel);
731
0
  }
732
0
  else if (bicolor_count > 3 && bicolor_count >= mix_count && bicolor_count >= color_count &&
733
0
           bicolor_count >= fill_count && bicolor_count >= fom_count)
734
0
  {
735
0
    if ((bicolor_count % 2) != 0)
736
0
      bicolor_count--;
737
738
0
    if (bicolor_count > count)
739
0
      return -1;
740
741
0
    count -= bicolor_count;
742
0
    OUT_COPY_COUNT3(count, s, temp_s);
743
0
    OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1);
744
745
0
    if (bicolor_count > count)
746
0
      return -1;
747
748
0
    count -= bicolor_count;
749
0
    OUT_COPY_COUNT3(count, s, temp_s);
750
0
    OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2);
751
0
  }
752
0
  else if (fom_count > 3 && fom_count >= mix_count && fom_count >= color_count &&
753
0
           fom_count >= fill_count && fom_count >= bicolor_count)
754
0
  {
755
0
    if (fom_count > count)
756
0
      return -1;
757
758
0
    count -= fom_count;
759
0
    OUT_COPY_COUNT3(count, s, temp_s);
760
0
    OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len);
761
0
  }
762
0
  else
763
0
  {
764
0
    OUT_COPY_COUNT3(count, s, temp_s);
765
0
  }
766
767
0
  return lines_sent;
768
0
}
769
770
static INLINE SSIZE_T freerdp_bitmap_compress_16(const void* WINPR_RESTRICT srcData, UINT32 width,
771
                                                 UINT32 height, wStream* WINPR_RESTRICT s,
772
                                                 UINT32 bpp, UINT32 byte_limit, UINT32 start_line,
773
                                                 wStream* WINPR_RESTRICT temp_s, UINT32 e)
774
0
{
775
0
  char fom_mask[8192] = { 0 }; /* good for up to 64K bitmap */
776
0
  SSIZE_T lines_sent = 0;
777
0
  UINT16 count = 0;
778
0
  UINT16 color_count = 0;
779
0
  UINT16 last_pixel = 0;
780
0
  UINT16 last_ypixel = 0;
781
0
  UINT16 bicolor_count = 0;
782
0
  UINT16 bicolor1 = 0;
783
0
  UINT16 bicolor2 = 0;
784
0
  BOOL bicolor_spin = FALSE;
785
0
  UINT32 end = width + e;
786
0
  UINT32 out_count = end * 2;
787
0
  UINT16 fill_count = 0;
788
0
  UINT16 mix_count = 0;
789
0
  const UINT32 mix = (bpp == 15) ? 0xBA1F : 0xFFFF;
790
0
  UINT16 fom_count = 0;
791
0
  size_t fom_mask_len = 0;
792
0
  const char* start = (const char*)srcData;
793
0
  const char* line = start + 2ULL * width * start_line;
794
0
  const char* last_line = NULL;
795
796
0
  while ((line >= start) && (out_count < 32768))
797
0
  {
798
0
    size_t i = Stream_GetPosition(s) + 2ULL * count;
799
800
0
    if ((i - (2ULL * color_count) >= byte_limit) &&
801
0
        (i - (2ULL * bicolor_count) >= byte_limit) && (i - (2ULL * fill_count) >= byte_limit) &&
802
0
        (i - (2ULL * mix_count) >= byte_limit) && (i - (2ULL * fom_count) >= byte_limit))
803
0
    {
804
0
      break;
805
0
    }
806
807
0
    out_count += end * 2;
808
809
0
    for (UINT32 j = 0; j < end; j++)
810
0
    {
811
      /* read next pixel */
812
0
      const UINT16 pixel = IN_PIXEL16(line, j, 0, width, last_pixel);
813
0
      const UINT16 ypixel = IN_PIXEL16(last_line, j, 0, width, last_ypixel);
814
815
0
      if (!TEST_FILL)
816
0
      {
817
0
        if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
818
0
            fill_count >= mix_count && fill_count >= fom_count)
819
0
        {
820
0
          if (fill_count > count)
821
0
            return -1;
822
823
0
          count -= fill_count;
824
0
          OUT_COPY_COUNT2(count, s, temp_s);
825
0
          OUT_FILL_COUNT2(fill_count, s);
826
0
          RESET_COUNTS;
827
0
        }
828
829
0
        fill_count = 0;
830
0
      }
831
832
0
      if (!TEST_MIX)
833
0
      {
834
0
        if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count &&
835
0
            mix_count >= color_count && mix_count >= fom_count)
836
0
        {
837
0
          if (mix_count > count)
838
0
            return -1;
839
840
0
          count -= mix_count;
841
0
          OUT_COPY_COUNT2(count, s, temp_s);
842
0
          OUT_MIX_COUNT2(mix_count, s);
843
0
          RESET_COUNTS;
844
0
        }
845
846
0
        mix_count = 0;
847
0
      }
848
849
0
      if (!(TEST_COLOR))
850
0
      {
851
0
        if (color_count > 3 && color_count >= fill_count && color_count >= bicolor_count &&
852
0
            color_count >= mix_count && color_count >= fom_count)
853
0
        {
854
0
          if (color_count > count)
855
0
            return -1;
856
857
0
          count -= color_count;
858
0
          OUT_COPY_COUNT2(count, s, temp_s);
859
0
          OUT_COLOR_COUNT2(color_count, s, last_pixel);
860
0
          RESET_COUNTS;
861
0
        }
862
863
0
        color_count = 0;
864
0
      }
865
866
0
      if (!TEST_BICOLOR)
867
0
      {
868
0
        if ((bicolor_count > 3) && (bicolor_count >= fill_count) &&
869
0
            (bicolor_count >= color_count) && (bicolor_count >= mix_count) &&
870
0
            (bicolor_count >= fom_count))
871
0
        {
872
0
          if ((bicolor_count % 2) != 0)
873
0
            bicolor_count--;
874
875
0
          if (bicolor_count > count)
876
0
            return -1;
877
878
0
          count -= bicolor_count;
879
0
          OUT_COPY_COUNT2(count, s, temp_s);
880
0
          OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1);
881
0
          RESET_COUNTS;
882
0
        }
883
884
0
        bicolor_count = 0;
885
0
        bicolor1 = last_pixel;
886
0
        bicolor2 = pixel;
887
0
        bicolor_spin = FALSE;
888
0
      }
889
890
0
      if (!(TEST_FOM))
891
0
      {
892
0
        if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count &&
893
0
            fom_count >= mix_count && fom_count >= bicolor_count)
894
0
        {
895
0
          if (fom_count > count)
896
0
            return -1;
897
898
0
          count -= fom_count;
899
0
          OUT_COPY_COUNT2(count, s, temp_s);
900
0
          OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len);
901
0
          RESET_COUNTS;
902
0
        }
903
904
0
        fom_count = 0;
905
0
        fom_mask_len = 0;
906
0
      }
907
908
0
      if (TEST_FILL)
909
0
      {
910
0
        fill_count++;
911
0
      }
912
913
0
      if (TEST_MIX)
914
0
      {
915
0
        mix_count++;
916
0
      }
917
918
0
      if (TEST_COLOR)
919
0
      {
920
0
        color_count++;
921
0
      }
922
923
0
      if (TEST_BICOLOR)
924
0
      {
925
0
        bicolor_spin = !bicolor_spin;
926
0
        bicolor_count++;
927
0
      }
928
929
0
      if (TEST_FOM)
930
0
      {
931
0
        if ((fom_count % 8) == 0)
932
0
        {
933
0
          fom_mask[fom_mask_len] = 0;
934
0
          fom_mask_len++;
935
0
        }
936
937
0
        if (pixel == (ypixel ^ mix))
938
0
        {
939
0
          fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8));
940
0
        }
941
942
0
        fom_count++;
943
0
      }
944
945
0
      Stream_Write_UINT16(temp_s, pixel);
946
0
      count++;
947
0
      last_pixel = pixel;
948
0
      last_ypixel = ypixel;
949
0
    }
950
951
    /* can't take fix, mix, or fom past first line */
952
0
    if (last_line == 0)
953
0
    {
954
0
      if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
955
0
          fill_count >= mix_count && fill_count >= fom_count)
956
0
      {
957
0
        if (fill_count > count)
958
0
          return -1;
959
960
0
        count -= fill_count;
961
0
        OUT_COPY_COUNT2(count, s, temp_s);
962
0
        OUT_FILL_COUNT2(fill_count, s);
963
0
        RESET_COUNTS;
964
0
      }
965
966
0
      fill_count = 0;
967
968
0
      if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count &&
969
0
          mix_count >= color_count && mix_count >= fom_count)
970
0
      {
971
0
        if (mix_count > count)
972
0
          return -1;
973
974
0
        count -= mix_count;
975
0
        OUT_COPY_COUNT2(count, s, temp_s);
976
0
        OUT_MIX_COUNT2(mix_count, s);
977
0
        RESET_COUNTS;
978
0
      }
979
980
0
      mix_count = 0;
981
982
0
      if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count &&
983
0
          fom_count >= mix_count && fom_count >= bicolor_count)
984
0
      {
985
0
        if (fom_count > count)
986
0
          return -1;
987
988
0
        count -= fom_count;
989
0
        OUT_COPY_COUNT2(count, s, temp_s);
990
0
        OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len);
991
0
        RESET_COUNTS;
992
0
      }
993
994
0
      fom_count = 0;
995
0
      fom_mask_len = 0;
996
0
    }
997
998
0
    last_line = line;
999
0
    line = line - 2ULL * width;
1000
0
    start_line--;
1001
0
    lines_sent++;
1002
0
  }
1003
1004
0
  Stream_SetPosition(temp_s, 0);
1005
1006
0
  if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
1007
0
      fill_count >= mix_count && fill_count >= fom_count)
1008
0
  {
1009
0
    if (fill_count > count)
1010
0
      return -1;
1011
1012
0
    count -= fill_count;
1013
0
    OUT_COPY_COUNT2(count, s, temp_s);
1014
0
    OUT_FILL_COUNT2(fill_count, s);
1015
0
  }
1016
0
  else if (mix_count > 3 && mix_count >= color_count && mix_count >= bicolor_count &&
1017
0
           mix_count >= fill_count && mix_count >= fom_count)
1018
0
  {
1019
0
    if (mix_count > count)
1020
0
      return -1;
1021
1022
0
    count -= mix_count;
1023
0
    OUT_COPY_COUNT2(count, s, temp_s);
1024
0
    OUT_MIX_COUNT2(mix_count, s);
1025
0
  }
1026
0
  else if (color_count > 3 && color_count >= mix_count && color_count >= bicolor_count &&
1027
0
           color_count >= fill_count && color_count >= fom_count)
1028
0
  {
1029
0
    if (color_count > count)
1030
0
      return -1;
1031
1032
0
    count -= color_count;
1033
0
    OUT_COPY_COUNT2(count, s, temp_s);
1034
0
    OUT_COLOR_COUNT2(color_count, s, last_pixel);
1035
0
  }
1036
0
  else if (bicolor_count > 3 && bicolor_count >= mix_count && bicolor_count >= color_count &&
1037
0
           bicolor_count >= fill_count && bicolor_count >= fom_count)
1038
0
  {
1039
0
    if ((bicolor_count % 2) != 0)
1040
0
      bicolor_count--;
1041
1042
0
    if (bicolor_count > count)
1043
0
      return -1;
1044
1045
0
    count -= bicolor_count;
1046
0
    OUT_COPY_COUNT2(count, s, temp_s);
1047
0
    OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1);
1048
1049
0
    if (bicolor_count > count)
1050
0
      return -1;
1051
1052
0
    count -= bicolor_count;
1053
0
    OUT_COPY_COUNT2(count, s, temp_s);
1054
0
    OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2);
1055
0
  }
1056
0
  else if (fom_count > 3 && fom_count >= mix_count && fom_count >= color_count &&
1057
0
           fom_count >= fill_count && fom_count >= bicolor_count)
1058
0
  {
1059
0
    if (fom_count > count)
1060
0
      return -1;
1061
1062
0
    count -= fom_count;
1063
0
    OUT_COPY_COUNT2(count, s, temp_s);
1064
0
    OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len);
1065
0
  }
1066
0
  else
1067
0
  {
1068
0
    OUT_COPY_COUNT2(count, s, temp_s);
1069
0
  }
1070
1071
0
  return lines_sent;
1072
0
}
1073
1074
SSIZE_T freerdp_bitmap_compress(const void* WINPR_RESTRICT srcData, UINT32 width, UINT32 height,
1075
                                wStream* WINPR_RESTRICT s, UINT32 bpp, UINT32 byte_limit,
1076
                                UINT32 start_line, wStream* WINPR_RESTRICT temp_s, UINT32 e)
1077
0
{
1078
0
  Stream_SetPosition(temp_s, 0);
1079
1080
0
  switch (bpp)
1081
0
  {
1082
0
    case 15:
1083
0
    case 16:
1084
0
      return freerdp_bitmap_compress_16(srcData, width, height, s, bpp, byte_limit,
1085
0
                                        start_line, temp_s, e);
1086
1087
0
    case 24:
1088
0
      return freerdp_bitmap_compress_24(srcData, width, height, s, byte_limit, start_line,
1089
0
                                        temp_s, e);
1090
1091
0
    default:
1092
0
      return -1;
1093
0
  }
1094
0
}