Coverage Report

Created: 2026-03-04 06:13

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
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 = (1 << k); /* add (1 << 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 = ((1 << 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 = ((1 << 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
      if (sign)
357
0
        mag = WINPR_ASSERTING_INT_CAST(int16_t, (code + 1)) * -1;
358
0
      else
359
0
        mag = WINPR_ASSERTING_INT_CAST(int16_t, code + 1);
360
361
      /* write to output stream */
362
363
0
      offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput)-pDstData);
364
0
      size = run;
365
366
0
      if ((offset + size) > rDstSize)
367
0
        size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
368
369
0
      if (size)
370
0
      {
371
0
        ZeroMemory(pOutput, size * sizeof(INT16));
372
0
        pOutput += size;
373
0
      }
374
375
0
      if ((pOutput - pDstData) < DstSize)
376
0
      {
377
0
        *pOutput = mag;
378
0
        pOutput++;
379
0
      }
380
0
    }
381
0
    else
382
0
    {
383
      /* Golomb-Rice (GR) Mode */
384
385
      /* count number of leading 1s */
386
387
0
      cnt = lzcnt_s(~(bs->accumulator));
388
389
0
      size_t nbits = BitStream_GetRemainingLength(bs);
390
391
0
      if (cnt > nbits)
392
0
        cnt = nbits;
393
394
0
      vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
395
396
0
      while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
397
0
      {
398
0
        BitStream_Shift32(bs);
399
400
0
        cnt = lzcnt_s(~(bs->accumulator));
401
402
0
        nbits = BitStream_GetRemainingLength(bs);
403
404
0
        if (cnt > nbits)
405
0
          cnt = nbits;
406
407
0
        WINPR_ASSERT(cnt + vk <= UINT32_MAX);
408
0
        vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
409
0
      }
410
411
0
      BitStream_Shift(bs, (vk % 32));
412
413
0
      if (BitStream_GetRemainingLength(bs) < 1)
414
0
        break;
415
416
0
      BitStream_Shift(bs, 1);
417
418
      /* next kr bits contain code remainder */
419
420
0
      if (BitStream_GetRemainingLength(bs) < kr)
421
0
        break;
422
423
0
      bs->mask = ((1 << kr) - 1);
424
0
      if (kr > 0)
425
0
        code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
426
0
      else
427
0
        code = 0;
428
0
      BitStream_Shift(bs, kr);
429
430
      /* add (vk << kr) to code */
431
432
0
      code |= (vk << kr);
433
434
0
      if (!vk)
435
0
      {
436
        /* update kr, krp params */
437
438
0
        if (krp > 2)
439
0
          krp -= 2;
440
0
        else
441
0
          krp = 0;
442
443
0
        kr = (krp >> LSGR) & UINT32_MAX;
444
0
      }
445
0
      else if (vk != 1)
446
0
      {
447
        /* update kr, krp params */
448
449
0
        krp += vk;
450
451
0
        if (krp > KPMAX)
452
0
          krp = KPMAX;
453
454
0
        kr = krp >> LSGR;
455
0
      }
456
457
0
      if (mode == RLGR1) /* RLGR1 */
458
0
      {
459
0
        if (!code)
460
0
        {
461
          /* update k, kp params */
462
463
0
          kp += UQ_GR;
464
465
0
          if (kp > KPMAX)
466
0
            kp = KPMAX;
467
468
0
          k = kp >> LSGR;
469
470
0
          mag = 0;
471
0
        }
472
0
        else
473
0
        {
474
          /* update k, kp params */
475
476
0
          if (kp > DQ_GR)
477
0
            kp -= DQ_GR;
478
0
          else
479
0
            kp = 0;
480
481
0
          k = kp >> LSGR;
482
483
          /*
484
           * code = 2 * mag - sign
485
           * sign + code = 2 * mag
486
           */
487
488
0
          if (code & 1)
489
0
            mag = WINPR_ASSERTING_INT_CAST(INT16, (code + 1) >> 1) * -1;
490
0
          else
491
0
            mag = WINPR_ASSERTING_INT_CAST(INT16, code >> 1);
492
0
        }
493
494
0
        if ((pOutput - pDstData) < DstSize)
495
0
        {
496
0
          *pOutput = mag;
497
0
          pOutput++;
498
0
        }
499
0
      }
500
0
      else if (mode == RLGR3) /* RLGR3 */
501
0
      {
502
0
        nIdx = 0;
503
504
0
        if (code)
505
0
        {
506
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, code);
507
0
          nIdx = 32 - lzcnt_s(WINPR_ASSERTING_INT_CAST(uint32_t, mag));
508
0
        }
509
510
0
        if (BitStream_GetRemainingLength(bs) < nIdx)
511
0
          break;
512
513
0
        bs->mask = ((1 << nIdx) - 1);
514
0
        if (nIdx > 0)
515
0
          val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask);
516
0
        else
517
0
          val1 = 0;
518
0
        BitStream_Shift(bs, nIdx);
519
520
0
        val2 = code - val1;
521
522
0
        if (val1 && val2)
523
0
        {
524
          /* update k, kp params */
525
526
0
          if (kp > 2 * DQ_GR)
527
0
            kp -= (2 * DQ_GR);
528
0
          else
529
0
            kp = 0;
530
531
0
          k = kp >> LSGR;
532
0
        }
533
0
        else if (!val1 && !val2)
534
0
        {
535
          /* update k, kp params */
536
537
0
          kp += (2 * UQ_GR);
538
539
0
          if (kp > KPMAX)
540
0
            kp = KPMAX;
541
542
0
          k = kp >> LSGR;
543
0
        }
544
545
0
        if (val1 & 1)
546
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, (val1 + 1) >> 1) * -1;
547
0
        else
548
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, val1 >> 1);
549
550
0
        if ((pOutput - pDstData) < DstSize)
551
0
        {
552
0
          *pOutput = mag;
553
0
          pOutput++;
554
0
        }
555
556
0
        if (val2 & 1)
557
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, (val2 + 1) >> 1) * -1;
558
0
        else
559
0
          mag = WINPR_ASSERTING_INT_CAST(int16_t, val2 >> 1);
560
561
0
        if ((pOutput - pDstData) < DstSize)
562
0
        {
563
0
          *pOutput = WINPR_ASSERTING_INT_CAST(int16_t, mag);
564
0
          pOutput++;
565
0
        }
566
0
      }
567
0
    }
568
0
  }
569
570
0
  offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
571
572
0
  if (offset < rDstSize)
573
0
  {
574
0
    size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
575
0
    ZeroMemory(pOutput, size * 2);
576
0
    pOutput += size;
577
0
  }
578
579
0
  offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
580
581
0
  if ((DstSize < 0) || (offset != (size_t)DstSize))
582
0
    return -1;
583
584
0
  return 1;
585
0
}
586
587
/* Returns the next coefficient (a signed int) to encode, from the input stream */
588
#define GetNextInput(_n)    \
589
0
  do                      \
590
0
  {                       \
591
0
    if (data_size > 0)  \
592
0
    {                   \
593
0
      (_n) = *data++; \
594
0
      data_size--;    \
595
0
    }                   \
596
0
    else                \
597
0
    {                   \
598
0
      (_n) = 0;       \
599
0
    }                   \
600
0
  } while (0)
601
602
/* Emit bitPattern to the output bitstream */
603
0
#define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
604
605
/* Emit a bit (0 or 1), count number of times, to the output bitstream */
606
static inline void OutputBit(RFX_BITSTREAM* bs, uint32_t count, UINT8 bit)
607
0
{
608
0
  UINT16 _b = ((bit) ? 0xFFFF : 0);
609
0
  const uint32_t rem = count % 16;
610
0
  for (uint32_t x = 0; x < count - rem; x += 16)
611
0
    rfx_bitstream_put_bits(bs, _b, 16);
612
613
0
  if (rem > 0)
614
0
    rfx_bitstream_put_bits(bs, _b, rem);
615
0
}
616
617
/* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 :
618
 * 0) and returns it */
619
static inline UINT32 Get2MagSign(INT32 input)
620
0
{
621
0
  if (input >= 0)
622
0
    return WINPR_ASSERTING_INT_CAST(UINT32, 2 * input);
623
0
  return WINPR_ASSERTING_INT_CAST(UINT32, -2 * input - 1);
624
0
}
625
626
/* Outputs the Golomb/Rice encoding of a non-negative integer */
627
0
#define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
628
629
static void rfx_rlgr_code_gr(RFX_BITSTREAM* bs, uint32_t* krp, UINT32 val)
630
0
{
631
0
  uint32_t kr = *krp >> LSGR;
632
633
  /* unary part of GR code */
634
635
0
  const uint32_t vk = val >> kr;
636
0
  OutputBit(bs, vk, 1);
637
0
  OutputBit(bs, 1, 0);
638
639
  /* remainder part of GR code, if needed */
640
0
  if (kr)
641
0
  {
642
0
    OutputBits(kr, val & ((1 << kr) - 1));
643
0
  }
644
645
  /* update krp, only if it is not equal to 1 */
646
0
  if (vk == 0)
647
0
  {
648
0
    (void)UpdateParam(krp, -2);
649
0
  }
650
0
  else if (vk > 1)
651
0
  {
652
0
    (void)UpdateParam(krp, WINPR_CXX_COMPAT_CAST(int32_t, vk));
653
0
  }
654
0
}
655
656
int rfx_rlgr_encode(RLGR_MODE mode, const INT16* WINPR_RESTRICT data, UINT32 data_size,
657
                    BYTE* WINPR_RESTRICT buffer, UINT32 buffer_size)
658
0
{
659
0
  uint32_t k = 0;
660
0
  uint32_t kp = 0;
661
0
  uint32_t krp = 0;
662
0
  RFX_BITSTREAM* bs = nullptr;
663
664
0
  if (!(bs = (RFX_BITSTREAM*)winpr_aligned_calloc(1, sizeof(RFX_BITSTREAM), 32)))
665
0
    return 0;
666
667
0
  rfx_bitstream_attach(bs, buffer, buffer_size);
668
669
  /* initialize the parameters */
670
0
  k = 1;
671
0
  kp = 1 << LSGR;
672
0
  krp = 1 << LSGR;
673
674
  /* process all the input coefficients */
675
0
  while (data_size > 0)
676
0
  {
677
0
    int input = 0;
678
679
0
    if (k)
680
0
    {
681
0
      uint32_t numZeros = 0;
682
0
      uint32_t runmax = 0;
683
0
      BYTE sign = 0;
684
685
      /* RUN-LENGTH MODE */
686
687
      /* collect the run of zeros in the input stream */
688
0
      numZeros = 0;
689
0
      GetNextInput(input);
690
0
      while (input == 0 && data_size > 0)
691
0
      {
692
0
        numZeros++;
693
0
        GetNextInput(input);
694
0
      }
695
696
      // emit output zeros
697
0
      runmax = 1 << k;
698
0
      while (numZeros >= runmax)
699
0
      {
700
0
        OutputBit(bs, 1, 0); /* output a zero bit */
701
0
        numZeros -= runmax;
702
0
        k = UpdateParam(&kp, UP_GR); /* update kp, k */
703
0
        runmax = 1 << k;
704
0
      }
705
706
      /* output a 1 to terminate runs */
707
0
      OutputBit(bs, 1, 1);
708
709
      /* output the remaining run length using k bits */
710
0
      OutputBits(k, numZeros);
711
712
      /* note: when we reach here and the last byte being encoded is 0, we still
713
         need to output the last two bits, otherwise mstsc will crash */
714
715
      /* encode the nonzero value using GR coding */
716
0
      const UINT32 mag =
717
0
          (UINT32)(input < 0 ? -input : input); /* absolute value of input coefficient */
718
0
      sign = (input < 0 ? 1 : 0);         /* sign of input coefficient */
719
720
0
      OutputBit(bs, 1, sign);          /* output the sign bit */
721
0
      CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */
722
723
0
      k = UpdateParam(&kp, -DN_GR);
724
0
    }
725
0
    else
726
0
    {
727
      /* GOLOMB-RICE MODE */
728
729
0
      if (mode == RLGR1)
730
0
      {
731
0
        UINT32 twoMs = 0;
732
733
        /* RLGR1 variant */
734
735
        /* convert input to (2*magnitude - sign), encode using GR code */
736
0
        GetNextInput(input);
737
0
        twoMs = Get2MagSign(input);
738
0
        CodeGR(&krp, twoMs);
739
740
        /* update k, kp */
741
        /* NOTE: as of Aug 2011, the algorithm is still wrongly documented
742
           and the update direction is reversed */
743
0
        if (twoMs)
744
0
        {
745
0
          k = UpdateParam(&kp, -DQ_GR);
746
0
        }
747
0
        else
748
0
        {
749
0
          k = UpdateParam(&kp, UQ_GR);
750
0
        }
751
0
      }
752
0
      else /* mode == RLGR3 */
753
0
      {
754
0
        UINT32 twoMs1 = 0;
755
0
        UINT32 twoMs2 = 0;
756
0
        UINT32 sum2Ms = 0;
757
0
        UINT32 nIdx = 0;
758
759
        /* RLGR3 variant */
760
761
        /* convert the next two input values to (2*magnitude - sign) and */
762
        /* encode their sum using GR code */
763
764
0
        GetNextInput(input);
765
0
        twoMs1 = Get2MagSign(input);
766
0
        GetNextInput(input);
767
0
        twoMs2 = Get2MagSign(input);
768
0
        sum2Ms = twoMs1 + twoMs2;
769
770
0
        CodeGR(&krp, sum2Ms);
771
772
        /* encode binary representation of the first input (twoMs1). */
773
0
        GetMinBits(sum2Ms, nIdx);
774
0
        OutputBits(nIdx, twoMs1);
775
776
        /* update k,kp for the two input values */
777
778
0
        if (twoMs1 && twoMs2)
779
0
        {
780
0
          k = UpdateParam(&kp, -2 * DQ_GR);
781
0
        }
782
0
        else if (!twoMs1 && !twoMs2)
783
0
        {
784
0
          k = UpdateParam(&kp, 2 * UQ_GR);
785
0
        }
786
0
      }
787
0
    }
788
0
  }
789
790
0
  rfx_bitstream_flush(bs);
791
0
  uint32_t processed_size = rfx_bitstream_get_processed_bytes(bs);
792
0
  winpr_aligned_free(bs);
793
794
0
  return WINPR_ASSERTING_INT_CAST(int, processed_size);
795
0
}