Coverage Report

Created: 2026-10-15 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/codec/rfx_rlgr.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RemoteFX Codec Library - RLGR
4
 *
5
 * Copyright 2011 Vic Lee
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
/**
21
 * This implementation of RLGR refers to
22
 * [MS-RDPRFX] 3.1.8.1.7.3 RLGR1/RLGR3 Pseudocode
23
 */
24
25
#include <freerdp/config.h>
26
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
31
#include <winpr/assert.h>
32
#include <winpr/cast.h>
33
#include <winpr/crt.h>
34
#include <winpr/print.h>
35
#include <winpr/sysinfo.h>
36
#include <winpr/bitstream.h>
37
#include <winpr/intrin.h>
38
39
#include "rfx_bitstream.h"
40
#include "rfx_types.h"
41
#include "rfx_rlgr.h"
42
43
/* Constants used in RLGR1/RLGR3 algorithm */
44
0
#define KPMAX (80) /* max value for kp or krp */
45
0
#define LSGR (3)   /* shift count to convert kp to k */
46
0
#define UP_GR (4)  /* increase in kp after a zero run in RL mode */
47
0
#define DN_GR (6)  /* decrease in kp after a nonzero symbol in RL mode */
48
0
#define UQ_GR (3)  /* increase in kp after nonzero symbol in GR mode */
49
0
#define DQ_GR (3)  /* decrease in kp after zero symbol in GR mode */
50
51
/* Returns the least number of bits required to represent a given value */
52
#define GetMinBits(_val, _nbits) \
53
0
  do                           \
54
0
  {                            \
55
0
    UINT32 _v = (_val);      \
56
0
    (_nbits) = 0;            \
57
0
    while (_v)               \
58
0
    {                        \
59
0
      _v >>= 1;            \
60
0
      (_nbits)++;          \
61
0
    }                        \
62
0
  } while (0)
63
64
/*
65
 * Update the passed parameter and clamp it to the range [0, KPMAX]
66
 * Return the value of parameter right-shifted by LSGR
67
 */
68
static inline uint32_t UpdateParam(uint32_t* param, int32_t deltaP)
69
0
{
70
0
  WINPR_ASSERT(param);
71
0
  if (deltaP < 0)
72
0
  {
73
0
    const uint32_t udeltaP = WINPR_ASSERTING_INT_CAST(uint32_t, -deltaP);
74
0
    if (udeltaP > *param)
75
0
      *param = 0;
76
0
    else
77
0
      *param -= udeltaP;
78
0
  }
79
0
  else
80
0
    *param += WINPR_ASSERTING_INT_CAST(uint32_t, deltaP);
81
82
0
  if ((*param) > KPMAX)
83
0
    (*param) = KPMAX;
84
0
  return (*param) >> LSGR;
85
0
}
86
87
static BOOL g_LZCNT = FALSE;
88
89
static INIT_ONCE rfx_rlgr_init_once = INIT_ONCE_STATIC_INIT;
90
91
static BOOL CALLBACK rfx_rlgr_init(PINIT_ONCE once, PVOID param, PVOID* context)
92
0
{
93
0
  WINPR_UNUSED(once);
94
0
  WINPR_UNUSED(param);
95
0
  WINPR_UNUSED(context);
96
97
0
  g_LZCNT = IsProcessorFeaturePresentEx(PF_EX_LZCNT);
98
0
  return TRUE;
99
0
}
100
101
static inline UINT32 lzcnt_s(UINT32 x)
102
0
{
103
0
  if (!x)
104
0
    return 32;
105
106
0
  if (!g_LZCNT)
107
0
  {
108
0
    UINT32 y = 0;
109
0
    UINT32 n = 32;
110
0
    y = x >> 16;
111
0
    if (y != 0)
112
0
    {
113
0
      WINPR_ASSERT(n >= 16);
114
0
      n = n - 16;
115
0
      x = y;
116
0
    }
117
0
    y = x >> 8;
118
0
    if (y != 0)
119
0
    {
120
0
      WINPR_ASSERT(n >= 8);
121
0
      n = n - 8;
122
0
      x = y;
123
0
    }
124
0
    y = x >> 4;
125
0
    if (y != 0)
126
0
    {
127
0
      WINPR_ASSERT(n >= 4);
128
0
      n = n - 4;
129
0
      x = y;
130
0
    }
131
0
    y = x >> 2;
132
0
    if (y != 0)
133
0
    {
134
0
      WINPR_ASSERT(n >= 2);
135
0
      n = n - 2;
136
0
      x = y;
137
0
    }
138
0
    y = x >> 1;
139
0
    if (y != 0)
140
0
    {
141
0
      WINPR_ASSERT(n >= 2);
142
0
      return n - 2;
143
0
    }
144
145
0
    WINPR_ASSERT(n >= x);
146
0
    return n - x;
147
0
  }
148
149
0
  return __lzcnt(x);
150
0
}
151
152
int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
153
                    INT16* WINPR_RESTRICT pDstData, UINT32 rDstSize)
154
0
{
155
0
  uint32_t vk = 0;
156
0
  size_t run = 0;
157
0
  size_t cnt = 0;
158
0
  size_t size = 0;
159
0
  size_t offset = 0;
160
0
  INT16 mag = 0;
161
0
  UINT32 k = 0;
162
0
  UINT32 kp = 0;
163
0
  UINT32 kr = 0;
164
0
  UINT32 krp = 0;
165
0
  UINT16 code = 0;
166
0
  UINT32 sign = 0;
167
0
  UINT32 nIdx = 0;
168
0
  UINT32 val1 = 0;
169
0
  UINT32 val2 = 0;
170
0
  INT16* pOutput = nullptr;
171
0
  wBitStream* bs = nullptr;
172
0
  wBitStream s_bs = WINPR_C_ARRAY_INIT;
173
0
  const SSIZE_T DstSize = rDstSize;
174
175
0
  if (!InitOnceExecuteOnce(&rfx_rlgr_init_once, rfx_rlgr_init, nullptr, nullptr))
176
0
    return -1;
177
178
0
  k = 1;
179
0
  kp = k << LSGR;
180
181
0
  kr = 1;
182
0
  krp = kr << LSGR;
183
184
0
  if ((mode != RLGR1) && (mode != RLGR3))
185
0
    mode = RLGR1;
186
187
0
  if (!pSrcData || !SrcSize)
188
0
    return -1;
189
190
0
  if (!pDstData || !DstSize)
191
0
    return -1;
192
193
0
  pOutput = pDstData;
194
195
0
  bs = &s_bs;
196
197
0
  BitStream_Attach(bs, pSrcData, SrcSize);
198
0
  BitStream_Fetch(bs);
199
200
0
  while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize))
201
0
  {
202
0
    if (k)
203
0
    {
204
      /* Run-Length (RL) Mode */
205
206
0
      run = 0;
207
208
      /* count number of leading 0s */
209
210
0
      cnt = lzcnt_s(bs->accumulator);
211
212
0
      size_t nbits = BitStream_GetRemainingLength(bs);
213
214
0
      if (cnt > nbits)
215
0
        cnt = WINPR_ASSERTING_INT_CAST(uint32_t, nbits);
216
217
0
      vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
218
219
0
      while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
220
0
      {
221
0
        BitStream_Shift32(bs);
222
223
0
        cnt = lzcnt_s(bs->accumulator);
224
225
0
        nbits = BitStream_GetRemainingLength(bs);
226
227
0
        if (cnt > nbits)
228
0
          cnt = nbits;
229
230
0
        WINPR_ASSERT(cnt + vk <= UINT32_MAX);
231
0
        vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
232
0
      }
233
234
0
      BitStream_Shift(bs, (vk % 32));
235
236
0
      if (BitStream_GetRemainingLength(bs) < 1)
237
0
        break;
238
239
0
      BitStream_Shift(bs, 1);
240
241
0
      while (vk--)
242
0
      {
243
0
        const UINT32 add = (1u << k); /* add (1u << k) to run length */
244
0
        run += add;
245
246
        /* update k, kp params */
247
248
0
        kp += UP_GR;
249
250
0
        if (kp > KPMAX)
251
0
          kp = KPMAX;
252
253
0
        k = kp >> LSGR;
254
0
      }
255
256
      /* next k bits contain run length remainder */
257
258
0
      if (BitStream_GetRemainingLength(bs) < k)
259
0
        break;
260
261
0
      bs->mask = ((1u << k) - 1);
262
0
      run += ((bs->accumulator >> (32 - k)) & bs->mask);
263
0
      BitStream_Shift(bs, k);
264
265
      /* read sign bit */
266
267
0
      if (BitStream_GetRemainingLength(bs) < 1)
268
0
        break;
269
270
0
      sign = (bs->accumulator & 0x80000000) ? 1 : 0;
271
0
      BitStream_Shift(bs, 1);
272
273
      /* count number of leading 1s */
274
275
0
      cnt = lzcnt_s(~(bs->accumulator));
276
277
0
      nbits = BitStream_GetRemainingLength(bs);
278
279
0
      if (cnt > nbits)
280
0
        cnt = nbits;
281
282
0
      vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
283
284
0
      while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
285
0
      {
286
0
        BitStream_Shift32(bs);
287
288
0
        cnt = lzcnt_s(~(bs->accumulator));
289
290
0
        nbits = BitStream_GetRemainingLength(bs);
291
292
0
        if (cnt > nbits)
293
0
          cnt = nbits;
294
295
0
        WINPR_ASSERT(cnt + vk <= UINT32_MAX);
296
0
        vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
297
0
      }
298
299
0
      BitStream_Shift(bs, (vk % 32));
300
301
0
      if (BitStream_GetRemainingLength(bs) < 1)
302
0
        break;
303
304
0
      BitStream_Shift(bs, 1);
305
306
      /* next kr bits contain code remainder */
307
308
0
      if (BitStream_GetRemainingLength(bs) < kr)
309
0
        break;
310
311
0
      bs->mask = ((1u << kr) - 1);
312
0
      if (kr > 0)
313
0
        code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
314
0
      else
315
0
        code = 0;
316
0
      BitStream_Shift(bs, kr);
317
318
      /* add (vk << kr) to code */
319
320
0
      code |= (vk << kr);
321
322
0
      if (!vk)
323
0
      {
324
        /* update kr, krp params */
325
326
0
        if (krp > 2)
327
0
          krp -= 2;
328
0
        else
329
0
          krp = 0;
330
331
0
        kr = krp >> LSGR;
332
0
      }
333
0
      else if (vk != 1)
334
0
      {
335
        /* update kr, krp params */
336
337
0
        krp += vk;
338
339
0
        if (krp > KPMAX)
340
0
          krp = KPMAX;
341
342
0
        kr = krp >> LSGR;
343
0
      }
344
345
      /* update k, kp params */
346
347
0
      if (kp > DN_GR)
348
0
        kp -= DN_GR;
349
0
      else
350
0
        kp = 0;
351
352
0
      k = kp >> LSGR;
353
354
      /* compute magnitude from code */
355
356
0
      const INT32 code1 = code + 1;
357
0
      if ((code1 > INT16_MAX) || (code1 < INT16_MIN))
358
0
      {
359
0
        WLog_ERR(RFX_TAG, "code1=%d", code1);
360
0
        return -1;
361
0
      }
362
363
0
      if (sign)
364
0
        mag = WINPR_ASSERTING_INT_CAST(int16_t, code1) * -1;
365
0
      else
366
0
        mag = WINPR_ASSERTING_INT_CAST(int16_t, code1);
367
368
      /* write to output stream */
369
370
0
      offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput)-pDstData);
371
0
      size = run;
372
373
0
      if ((offset + size) > rDstSize)
374
0
        size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
375
376
0
      if (size)
377
0
      {
378
0
        ZeroMemory(pOutput, size * sizeof(INT16));
379
0
        pOutput += size;
380
0
      }
381
382
0
      if ((pOutput - pDstData) < DstSize)
383
0
      {
384
0
        *pOutput = mag;
385
0
        pOutput++;
386
0
      }
387
0
    }
388
0
    else
389
0
    {
390
      /* Golomb-Rice (GR) Mode */
391
392
      /* count number of leading 1s */
393
394
0
      cnt = lzcnt_s(~(bs->accumulator));
395
396
0
      size_t nbits = BitStream_GetRemainingLength(bs);
397
398
0
      if (cnt > nbits)
399
0
        cnt = nbits;
400
401
0
      vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
402
403
0
      while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
404
0
      {
405
0
        BitStream_Shift32(bs);
406
407
0
        cnt = lzcnt_s(~(bs->accumulator));
408
409
0
        nbits = BitStream_GetRemainingLength(bs);
410
411
0
        if (cnt > nbits)
412
0
          cnt = nbits;
413
414
0
        WINPR_ASSERT(cnt + vk <= UINT32_MAX);
415
0
        vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
416
0
      }
417
418
0
      BitStream_Shift(bs, (vk % 32));
419
420
0
      if (BitStream_GetRemainingLength(bs) < 1)
421
0
        break;
422
423
0
      BitStream_Shift(bs, 1);
424
425
      /* next kr bits contain code remainder */
426
427
0
      if (BitStream_GetRemainingLength(bs) < kr)
428
0
        break;
429
430
0
      bs->mask = ((1u << kr) - 1);
431
0
      if (kr > 0)
432
0
        code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
433
0
      else
434
0
        code = 0;
435
0
      BitStream_Shift(bs, kr);
436
437
      /* add (vk << kr) to code */
438
439
0
      code |= (vk << kr);
440
441
0
      if (!vk)
442
0
      {
443
        /* update kr, krp params */
444
445
0
        if (krp > 2)
446
0
          krp -= 2;
447
0
        else
448
0
          krp = 0;
449
450
0
        kr = (krp >> LSGR) & UINT32_MAX;
451
0
      }
452
0
      else if (vk != 1)
453
0
      {
454
        /* update kr, krp params */
455
456
0
        krp += vk;
457
458
0
        if (krp > KPMAX)
459
0
          krp = KPMAX;
460
461
0
        kr = krp >> LSGR;
462
0
      }
463
464
0
      if (mode == RLGR1) /* RLGR1 */
465
0
      {
466
0
        if (!code)
467
0
        {
468
          /* update k, kp params */
469
470
0
          kp += UQ_GR;
471
472
0
          if (kp > KPMAX)
473
0
            kp = KPMAX;
474
475
0
          k = kp >> LSGR;
476
477
0
          mag = 0;
478
0
        }
479
0
        else
480
0
        {
481
          /* update k, kp params */
482
483
0
          if (kp > DQ_GR)
484
0
            kp -= DQ_GR;
485
0
          else
486
0
            kp = 0;
487
488
0
          k = kp >> LSGR;
489
490
          /*
491
           * code = 2 * mag - sign
492
           * sign + code = 2 * mag
493
           */
494
0
          const INT32 codeShift = code >> 1;
495
0
          const INT32 code1shift = (code + 1) >> 1;
496
0
          if ((codeShift > INT16_MAX) || (codeShift < INT16_MIN))
497
0
          {
498
0
            WLog_ERR(RFX_TAG, "codeShift=%d", codeShift);
499
0
            return -1;
500
0
          }
501
0
          if ((code1shift > INT16_MAX) || (code1shift < INT16_MIN))
502
0
          {
503
0
            WLog_ERR(RFX_TAG, "code1shift=%d", code1shift);
504
0
            return -1;
505
0
          }
506
0
          if (code & 1)
507
0
            mag = WINPR_ASSERTING_INT_CAST(INT16, code1shift) * -1;
508
0
          else
509
0
            mag = WINPR_ASSERTING_INT_CAST(INT16, codeShift);
510
0
        }
511
512
0
        if ((pOutput - pDstData) < DstSize)
513
0
        {
514
0
          *pOutput = mag;
515
0
          pOutput++;
516
0
        }
517
0
      }
518
0
      else if (mode == RLGR3) /* RLGR3 */
519
0
      {
520
0
        nIdx = 0;
521
522
0
        if (code)
523
0
        {
524
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, code);
525
0
          nIdx = 32 - lzcnt_s(WINPR_ASSERTING_INT_CAST(uint32_t, mag));
526
0
        }
527
528
0
        if (BitStream_GetRemainingLength(bs) < nIdx)
529
0
          break;
530
531
0
        bs->mask = ((1u << nIdx) - 1);
532
0
        if (nIdx > 0)
533
0
          val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask);
534
0
        else
535
0
          val1 = 0;
536
0
        BitStream_Shift(bs, nIdx);
537
538
0
        val2 = code - val1;
539
540
0
        if (val1 && val2)
541
0
        {
542
          /* update k, kp params */
543
544
0
          if (kp > 2 * DQ_GR)
545
0
            kp -= (2 * DQ_GR);
546
0
          else
547
0
            kp = 0;
548
549
0
          k = kp >> LSGR;
550
0
        }
551
0
        else if (!val1 && !val2)
552
0
        {
553
          /* update k, kp params */
554
555
0
          kp += (2 * UQ_GR);
556
557
0
          if (kp > KPMAX)
558
0
            kp = KPMAX;
559
560
0
          k = kp >> LSGR;
561
0
        }
562
563
0
        const UINT32 val1Shift = val1 >> 1;
564
0
        const UINT32 val11Shift = (val1 + 1) >> 1;
565
0
        if (val1Shift > INT16_MAX)
566
0
        {
567
0
          WLog_ERR(RFX_TAG, "val1Shift=%" PRIu32, val1Shift);
568
0
          return -1;
569
0
        }
570
0
        if (val11Shift > INT16_MAX)
571
0
        {
572
0
          WLog_ERR(RFX_TAG, "val11Shift=%" PRIu32, val11Shift);
573
0
          return -1;
574
0
        }
575
0
        if (val1 & 1)
576
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, val11Shift) * -1;
577
0
        else
578
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, val1Shift);
579
580
0
        if ((pOutput - pDstData) < DstSize)
581
0
        {
582
0
          *pOutput = mag;
583
0
          pOutput++;
584
0
        }
585
586
0
        const UINT32 val2Shift = val2 / 2;
587
0
        const UINT32 val21Shift = (val2 + 1) / 2;
588
0
        if (val2Shift > INT16_MAX)
589
0
        {
590
0
          WLog_ERR(RFX_TAG, "val2Shift=%" PRIu32, val2Shift);
591
0
          return -1;
592
0
        }
593
594
0
        if (val21Shift > INT16_MAX)
595
0
        {
596
0
          WLog_ERR(RFX_TAG, "val21Shift=%" PRIu32, val21Shift);
597
0
          return -1;
598
0
        }
599
0
        if (val2 & 1)
600
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, val21Shift) * -1;
601
0
        else
602
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, val2Shift);
603
604
0
        if ((pOutput - pDstData) < DstSize)
605
0
        {
606
0
          *pOutput = WINPR_ASSERTING_INT_CAST(int16_t, mag);
607
0
          pOutput++;
608
0
        }
609
0
      }
610
0
    }
611
0
  }
612
613
0
  offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
614
615
0
  if (offset < rDstSize)
616
0
  {
617
0
    size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
618
0
    ZeroMemory(pOutput, size * 2);
619
0
    pOutput += size;
620
0
  }
621
622
0
  offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
623
624
0
  if ((DstSize < 0) || (offset != (size_t)DstSize))
625
0
    return -1;
626
627
0
  return 1;
628
0
}
629
630
/* Returns the next coefficient (a signed int) to encode, from the input stream */
631
#define GetNextInput(_n)    \
632
0
  do                      \
633
0
  {                       \
634
0
    if (data_size > 0)  \
635
0
    {                   \
636
0
      (_n) = *data++; \
637
0
      data_size--;    \
638
0
    }                   \
639
0
    else                \
640
0
    {                   \
641
0
      (_n) = 0;       \
642
0
    }                   \
643
0
  } while (0)
644
645
/* Emit bitPattern to the output bitstream */
646
0
#define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
647
648
/* Emit a bit (0 or 1), count number of times, to the output bitstream */
649
static inline void OutputBit(RFX_BITSTREAM* bs, uint32_t count, UINT8 bit)
650
0
{
651
0
  UINT16 _b = ((bit) ? 0xFFFF : 0);
652
0
  const uint32_t rem = count % 16;
653
0
  for (uint32_t x = 0; x < count - rem; x += 16)
654
0
    rfx_bitstream_put_bits(bs, _b, 16);
655
656
0
  if (rem > 0)
657
0
    rfx_bitstream_put_bits(bs, _b, rem);
658
0
}
659
660
/* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 :
661
 * 0) and returns it */
662
static inline UINT32 Get2MagSign(INT32 input)
663
0
{
664
0
  if (input >= 0)
665
0
    return WINPR_ASSERTING_INT_CAST(UINT32, 2 * input);
666
0
  return WINPR_ASSERTING_INT_CAST(UINT32, -2 * input - 1);
667
0
}
668
669
/* Outputs the Golomb/Rice encoding of a non-negative integer */
670
0
#define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
671
672
static void rfx_rlgr_code_gr(RFX_BITSTREAM* bs, uint32_t* krp, UINT32 val)
673
0
{
674
0
  uint32_t kr = *krp >> LSGR;
675
676
  /* unary part of GR code */
677
678
0
  const uint32_t vk = val >> kr;
679
0
  OutputBit(bs, vk, 1);
680
0
  OutputBit(bs, 1, 0);
681
682
  /* remainder part of GR code, if needed */
683
0
  if (kr)
684
0
  {
685
0
    OutputBits(kr, val & ((1u << kr) - 1));
686
0
  }
687
688
  /* update krp, only if it is not equal to 1 */
689
0
  if (vk == 0)
690
0
  {
691
0
    (void)UpdateParam(krp, -2);
692
0
  }
693
0
  else if (vk > 1)
694
0
  {
695
0
    (void)UpdateParam(krp, WINPR_CXX_COMPAT_CAST(int32_t, vk));
696
0
  }
697
0
}
698
699
int rfx_rlgr_encode(RLGR_MODE mode, const INT16* WINPR_RESTRICT data, UINT32 data_size,
700
                    BYTE* WINPR_RESTRICT buffer, UINT32 buffer_size)
701
0
{
702
0
  RFX_BITSTREAM* bs = (RFX_BITSTREAM*)winpr_aligned_calloc(1, sizeof(RFX_BITSTREAM), 32);
703
704
0
  if (!bs)
705
0
    return 0;
706
707
0
  rfx_bitstream_attach(bs, buffer, buffer_size);
708
709
  /* initialize the parameters */
710
0
  uint32_t k = 1;
711
0
  uint32_t kp = 1u << LSGR;
712
0
  uint32_t krp = 1u << LSGR;
713
714
  /* process all the input coefficients */
715
0
  while (data_size > 0)
716
0
  {
717
0
    int input = 0;
718
719
0
    if (k)
720
0
    {
721
0
      uint32_t numZeros = 0;
722
0
      uint32_t runmax = 0;
723
0
      BYTE sign = 0;
724
725
      /* RUN-LENGTH MODE */
726
727
      /* collect the run of zeros in the input stream */
728
0
      numZeros = 0;
729
0
      GetNextInput(input);
730
0
      while (input == 0 && data_size > 0)
731
0
      {
732
0
        numZeros++;
733
0
        GetNextInput(input);
734
0
      }
735
736
      // emit output zeros
737
0
      runmax = 1u << k;
738
0
      while (numZeros >= runmax)
739
0
      {
740
0
        OutputBit(bs, 1, 0); /* output a zero bit */
741
0
        numZeros -= runmax;
742
0
        k = UpdateParam(&kp, UP_GR); /* update kp, k */
743
0
        runmax = 1u << k;
744
0
      }
745
746
      /* output a 1 to terminate runs */
747
0
      OutputBit(bs, 1, 1);
748
749
      /* output the remaining run length using k bits */
750
0
      OutputBits(k, numZeros);
751
752
      /* note: when we reach here and the last byte being encoded is 0, we still
753
         need to output the last two bits, otherwise mstsc will crash */
754
755
      /* encode the nonzero value using GR coding */
756
0
      const UINT32 mag =
757
0
          (UINT32)(input < 0 ? -input : input); /* absolute value of input coefficient */
758
0
      sign = (input < 0 ? 1 : 0);         /* sign of input coefficient */
759
760
0
      OutputBit(bs, 1, sign);          /* output the sign bit */
761
0
      CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */
762
763
0
      k = UpdateParam(&kp, -DN_GR);
764
0
    }
765
0
    else
766
0
    {
767
      /* GOLOMB-RICE MODE */
768
769
0
      if (mode == RLGR1)
770
0
      {
771
0
        UINT32 twoMs = 0;
772
773
        /* RLGR1 variant */
774
775
        /* convert input to (2*magnitude - sign), encode using GR code */
776
0
        GetNextInput(input);
777
0
        twoMs = Get2MagSign(input);
778
0
        CodeGR(&krp, twoMs);
779
780
        /* update k, kp */
781
        /* NOTE: as of Aug 2011, the algorithm is still wrongly documented
782
           and the update direction is reversed */
783
0
        if (twoMs)
784
0
        {
785
0
          k = UpdateParam(&kp, -DQ_GR);
786
0
        }
787
0
        else
788
0
        {
789
0
          k = UpdateParam(&kp, UQ_GR);
790
0
        }
791
0
      }
792
0
      else /* mode == RLGR3 */
793
0
      {
794
0
        UINT32 twoMs1 = 0;
795
0
        UINT32 twoMs2 = 0;
796
0
        UINT32 sum2Ms = 0;
797
0
        UINT32 nIdx = 0;
798
799
        /* RLGR3 variant */
800
801
        /* convert the next two input values to (2*magnitude - sign) and */
802
        /* encode their sum using GR code */
803
804
0
        GetNextInput(input);
805
0
        twoMs1 = Get2MagSign(input);
806
0
        GetNextInput(input);
807
0
        twoMs2 = Get2MagSign(input);
808
0
        sum2Ms = twoMs1 + twoMs2;
809
810
0
        CodeGR(&krp, sum2Ms);
811
812
        /* encode binary representation of the first input (twoMs1). */
813
0
        GetMinBits(sum2Ms, nIdx);
814
0
        OutputBits(nIdx, twoMs1);
815
816
        /* update k,kp for the two input values */
817
818
0
        if (twoMs1 && twoMs2)
819
0
        {
820
0
          k = UpdateParam(&kp, -2 * DQ_GR);
821
0
        }
822
0
        else if (!twoMs1 && !twoMs2)
823
0
        {
824
0
          k = UpdateParam(&kp, 2 * UQ_GR);
825
0
        }
826
0
      }
827
0
    }
828
0
  }
829
830
0
  rfx_bitstream_flush(bs);
831
0
  uint32_t processed_size = rfx_bitstream_get_processed_bytes(bs);
832
0
  winpr_aligned_free(bs);
833
834
0
  return WINPR_ASSERTING_INT_CAST(int, processed_size);
835
0
}