Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/codec/mppc.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * MPPC Bulk Data Compression
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@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 <winpr/assert.h>
21
#include <freerdp/config.h>
22
23
#include <winpr/crt.h>
24
#include <winpr/print.h>
25
#include <winpr/stream.h>
26
#include <winpr/bitstream.h>
27
28
#include <freerdp/log.h>
29
#include "mppc.h"
30
31
#define TAG FREERDP_TAG("codec.mppc")
32
33
//#define DEBUG_MPPC  1
34
35
#define MPPC_MATCH_INDEX(_sym1, _sym2, _sym3)                             \
36
0
  ((((MPPC_MATCH_TABLE[_sym3] << 16) + (MPPC_MATCH_TABLE[_sym2] << 8) + \
37
0
     MPPC_MATCH_TABLE[_sym1]) &                                         \
38
0
    0x07FFF000) >>                                                      \
39
0
   12)
40
41
struct s_MPPC_CONTEXT
42
{
43
  ALIGN64 wBitStream* bs;
44
  ALIGN64 BOOL Compressor;
45
  ALIGN64 BYTE* HistoryPtr;
46
  ALIGN64 UINT32 HistoryOffset;
47
  ALIGN64 UINT32 HistoryBufferSize;
48
  ALIGN64 BYTE HistoryBuffer[65536];
49
  ALIGN64 UINT16 MatchBuffer[32768];
50
  ALIGN64 UINT32 CompressionLevel;
51
};
52
53
static const UINT32 MPPC_MATCH_TABLE[256] = {
54
  0x00000000, 0x009CCF93, 0x01399F26, 0x01D66EB9, 0x02733E4C, 0x03100DDF, 0x03ACDD72, 0x0449AD05,
55
  0x04E67C98, 0x05834C2B, 0x06201BBE, 0x06BCEB51, 0x0759BAE4, 0x07F68A77, 0x08935A0A, 0x0930299D,
56
  0x09CCF930, 0x0A69C8C3, 0x0B069856, 0x0BA367E9, 0x0C40377C, 0x0CDD070F, 0x0D79D6A2, 0x0E16A635,
57
  0x0EB375C8, 0x0F50455B, 0x0FED14EE, 0x1089E481, 0x1126B414, 0x11C383A7, 0x1260533A, 0x12FD22CD,
58
  0x1399F260, 0x1436C1F3, 0x14D39186, 0x15706119, 0x160D30AC, 0x16AA003F, 0x1746CFD2, 0x17E39F65,
59
  0x18806EF8, 0x191D3E8B, 0x19BA0E1E, 0x1A56DDB1, 0x1AF3AD44, 0x1B907CD7, 0x1C2D4C6A, 0x1CCA1BFD,
60
  0x1D66EB90, 0x1E03BB23, 0x1EA08AB6, 0x1F3D5A49, 0x1FDA29DC, 0x2076F96F, 0x2113C902, 0x21B09895,
61
  0x224D6828, 0x22EA37BB, 0x2387074E, 0x2423D6E1, 0x24C0A674, 0x255D7607, 0x25FA459A, 0x2697152D,
62
  0x2733E4C0, 0x27D0B453, 0x286D83E6, 0x290A5379, 0x29A7230C, 0x2A43F29F, 0x2AE0C232, 0x2B7D91C5,
63
  0x2C1A6158, 0x2CB730EB, 0x2D54007E, 0x2DF0D011, 0x2E8D9FA4, 0x2F2A6F37, 0x2FC73ECA, 0x30640E5D,
64
  0x3100DDF0, 0x319DAD83, 0x323A7D16, 0x32D74CA9, 0x33741C3C, 0x3410EBCF, 0x34ADBB62, 0x354A8AF5,
65
  0x35E75A88, 0x36842A1B, 0x3720F9AE, 0x37BDC941, 0x385A98D4, 0x38F76867, 0x399437FA, 0x3A31078D,
66
  0x3ACDD720, 0x3B6AA6B3, 0x3C077646, 0x3CA445D9, 0x3D41156C, 0x3DDDE4FF, 0x3E7AB492, 0x3F178425,
67
  0x3FB453B8, 0x4051234B, 0x40EDF2DE, 0x418AC271, 0x42279204, 0x42C46197, 0x4361312A, 0x43FE00BD,
68
  0x449AD050, 0x45379FE3, 0x45D46F76, 0x46713F09, 0x470E0E9C, 0x47AADE2F, 0x4847ADC2, 0x48E47D55,
69
  0x49814CE8, 0x4A1E1C7B, 0x4ABAEC0E, 0x4B57BBA1, 0x4BF48B34, 0x4C915AC7, 0x4D2E2A5A, 0x4DCAF9ED,
70
  0x4E67C980, 0x4F049913, 0x4FA168A6, 0x503E3839, 0x50DB07CC, 0x5177D75F, 0x5214A6F2, 0x52B17685,
71
  0x534E4618, 0x53EB15AB, 0x5487E53E, 0x5524B4D1, 0x55C18464, 0x565E53F7, 0x56FB238A, 0x5797F31D,
72
  0x5834C2B0, 0x58D19243, 0x596E61D6, 0x5A0B3169, 0x5AA800FC, 0x5B44D08F, 0x5BE1A022, 0x5C7E6FB5,
73
  0x5D1B3F48, 0x5DB80EDB, 0x5E54DE6E, 0x5EF1AE01, 0x5F8E7D94, 0x602B4D27, 0x60C81CBA, 0x6164EC4D,
74
  0x6201BBE0, 0x629E8B73, 0x633B5B06, 0x63D82A99, 0x6474FA2C, 0x6511C9BF, 0x65AE9952, 0x664B68E5,
75
  0x66E83878, 0x6785080B, 0x6821D79E, 0x68BEA731, 0x695B76C4, 0x69F84657, 0x6A9515EA, 0x6B31E57D,
76
  0x6BCEB510, 0x6C6B84A3, 0x6D085436, 0x6DA523C9, 0x6E41F35C, 0x6EDEC2EF, 0x6F7B9282, 0x70186215,
77
  0x70B531A8, 0x7152013B, 0x71EED0CE, 0x728BA061, 0x73286FF4, 0x73C53F87, 0x74620F1A, 0x74FEDEAD,
78
  0x759BAE40, 0x76387DD3, 0x76D54D66, 0x77721CF9, 0x780EEC8C, 0x78ABBC1F, 0x79488BB2, 0x79E55B45,
79
  0x7A822AD8, 0x7B1EFA6B, 0x7BBBC9FE, 0x7C589991, 0x7CF56924, 0x7D9238B7, 0x7E2F084A, 0x7ECBD7DD,
80
  0x7F68A770, 0x80057703, 0x80A24696, 0x813F1629, 0x81DBE5BC, 0x8278B54F, 0x831584E2, 0x83B25475,
81
  0x844F2408, 0x84EBF39B, 0x8588C32E, 0x862592C1, 0x86C26254, 0x875F31E7, 0x87FC017A, 0x8898D10D,
82
  0x8935A0A0, 0x89D27033, 0x8A6F3FC6, 0x8B0C0F59, 0x8BA8DEEC, 0x8C45AE7F, 0x8CE27E12, 0x8D7F4DA5,
83
  0x8E1C1D38, 0x8EB8ECCB, 0x8F55BC5E, 0x8FF28BF1, 0x908F5B84, 0x912C2B17, 0x91C8FAAA, 0x9265CA3D,
84
  0x930299D0, 0x939F6963, 0x943C38F6, 0x94D90889, 0x9575D81C, 0x9612A7AF, 0x96AF7742, 0x974C46D5,
85
  0x97E91668, 0x9885E5FB, 0x9922B58E, 0x99BF8521, 0x9A5C54B4, 0x9AF92447, 0x9B95F3DA, 0x9C32C36D
86
};
87
88
int mppc_decompress(MPPC_CONTEXT* mppc, const BYTE* pSrcData, UINT32 SrcSize,
89
                    const BYTE** ppDstData, UINT32* pDstSize, UINT32 flags)
90
20.3k
{
91
20.3k
  BYTE Literal = 0;
92
20.3k
  BYTE* SrcPtr = NULL;
93
20.3k
  UINT32 CopyOffset = 0;
94
20.3k
  UINT32 LengthOfMatch = 0;
95
20.3k
  UINT32 accumulator = 0;
96
20.3k
  BYTE* HistoryPtr = NULL;
97
20.3k
  BYTE* HistoryBuffer = NULL;
98
20.3k
  BYTE* HistoryBufferEnd = NULL;
99
20.3k
  UINT32 HistoryBufferSize = 0;
100
20.3k
  UINT32 CompressionLevel = 0;
101
20.3k
  wBitStream* bs = NULL;
102
103
20.3k
  WINPR_ASSERT(mppc);
104
20.3k
  WINPR_ASSERT(pSrcData);
105
20.3k
  WINPR_ASSERT(ppDstData);
106
20.3k
  WINPR_ASSERT(pDstSize);
107
108
20.3k
  bs = mppc->bs;
109
20.3k
  WINPR_ASSERT(bs);
110
111
20.3k
  HistoryBuffer = mppc->HistoryBuffer;
112
20.3k
  WINPR_ASSERT(HistoryBuffer);
113
114
20.3k
  HistoryBufferSize = mppc->HistoryBufferSize;
115
20.3k
  HistoryBufferEnd = &HistoryBuffer[HistoryBufferSize - 1];
116
20.3k
  CompressionLevel = mppc->CompressionLevel;
117
20.3k
  BitStream_Attach(bs, pSrcData, SrcSize);
118
20.3k
  BitStream_Fetch(bs);
119
120
20.3k
  if (flags & PACKET_AT_FRONT)
121
18.8k
  {
122
18.8k
    mppc->HistoryOffset = 0;
123
18.8k
    mppc->HistoryPtr = HistoryBuffer;
124
18.8k
  }
125
126
20.3k
  if (flags & PACKET_FLUSHED)
127
1.29k
  {
128
1.29k
    mppc->HistoryOffset = 0;
129
1.29k
    mppc->HistoryPtr = HistoryBuffer;
130
1.29k
    ZeroMemory(HistoryBuffer, mppc->HistoryBufferSize);
131
1.29k
  }
132
133
20.3k
  HistoryPtr = mppc->HistoryPtr;
134
135
20.3k
  if (!(flags & PACKET_COMPRESSED))
136
0
  {
137
0
    *pDstSize = SrcSize;
138
0
    *ppDstData = pSrcData;
139
0
    return 1;
140
0
  }
141
142
173M
  while ((bs->length - bs->position) >= 8)
143
173M
  {
144
173M
    accumulator = bs->accumulator;
145
146
    /**
147
     * Literal Encoding
148
     */
149
150
173M
    if (HistoryPtr > HistoryBufferEnd)
151
3.42k
    {
152
3.42k
      WLog_ERR(TAG, "history buffer index out of range");
153
3.42k
      return -1004;
154
3.42k
    }
155
156
173M
    if ((accumulator & 0x80000000) == 0x00000000)
157
173M
    {
158
      /**
159
       * Literal, less than 0x80
160
       * bit 0 followed by the lower 7 bits of the literal
161
       */
162
173M
      Literal = ((accumulator & 0x7F000000) >> 24);
163
173M
      *(HistoryPtr) = Literal;
164
173M
      HistoryPtr++;
165
173M
      BitStream_Shift(bs, 8);
166
173M
      continue;
167
173M
    }
168
446k
    else if ((accumulator & 0xC0000000) == 0x80000000)
169
182k
    {
170
      /**
171
       * Literal, greater than 0x7F
172
       * bits 10 followed by the lower 7 bits of the literal
173
       */
174
182k
      Literal = ((accumulator & 0x3F800000) >> 23) + 0x80;
175
182k
      *(HistoryPtr) = Literal;
176
182k
      HistoryPtr++;
177
182k
      BitStream_Shift(bs, 9);
178
182k
      continue;
179
182k
    }
180
181
    /**
182
     * CopyOffset Encoding
183
     */
184
264k
    if (CompressionLevel) /* RDP5 */
185
191k
    {
186
191k
      if ((accumulator & 0xF8000000) == 0xF8000000)
187
44.2k
      {
188
        /**
189
         * CopyOffset, range [0, 63]
190
         * bits 11111 + lower 6 bits of CopyOffset
191
         */
192
44.2k
        CopyOffset = ((accumulator >> 21) & 0x3F);
193
44.2k
        BitStream_Shift(bs, 11);
194
44.2k
      }
195
147k
      else if ((accumulator & 0xF8000000) == 0xF0000000)
196
16.1k
      {
197
        /**
198
         * CopyOffset, range [64, 319]
199
         * bits 11110 + lower 8 bits of (CopyOffset - 64)
200
         */
201
16.1k
        CopyOffset = ((accumulator >> 19) & 0xFF) + 64;
202
16.1k
        BitStream_Shift(bs, 13);
203
16.1k
      }
204
131k
      else if ((accumulator & 0xF0000000) == 0xE0000000)
205
63.2k
      {
206
        /**
207
         * CopyOffset, range [320, 2367]
208
         * bits 1110 + lower 11 bits of (CopyOffset - 320)
209
         */
210
63.2k
        CopyOffset = ((accumulator >> 17) & 0x7FF) + 320;
211
63.2k
        BitStream_Shift(bs, 15);
212
63.2k
      }
213
67.7k
      else if ((accumulator & 0xE0000000) == 0xC0000000)
214
67.7k
      {
215
        /**
216
         * CopyOffset, range [2368, ]
217
         * bits 110 + lower 16 bits of (CopyOffset - 2368)
218
         */
219
67.7k
        CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368;
220
67.7k
        BitStream_Shift(bs, 19);
221
67.7k
      }
222
0
      else
223
0
      {
224
        /* Invalid CopyOffset Encoding */
225
0
        return -1001;
226
0
      }
227
191k
    }
228
73.1k
    else /* RDP4 */
229
73.1k
    {
230
73.1k
      if ((accumulator & 0xF0000000) == 0xF0000000)
231
39.6k
      {
232
        /**
233
         * CopyOffset, range [0, 63]
234
         * bits 1111 + lower 6 bits of CopyOffset
235
         */
236
39.6k
        CopyOffset = ((accumulator >> 22) & 0x3F);
237
39.6k
        BitStream_Shift(bs, 10);
238
39.6k
      }
239
33.4k
      else if ((accumulator & 0xF0000000) == 0xE0000000)
240
18.6k
      {
241
        /**
242
         * CopyOffset, range [64, 319]
243
         * bits 1110 + lower 8 bits of (CopyOffset - 64)
244
         */
245
18.6k
        CopyOffset = ((accumulator >> 20) & 0xFF) + 64;
246
18.6k
        BitStream_Shift(bs, 12);
247
18.6k
      }
248
14.7k
      else if ((accumulator & 0xE0000000) == 0xC0000000)
249
14.7k
      {
250
        /**
251
         * CopyOffset, range [320, 8191]
252
         * bits 110 + lower 13 bits of (CopyOffset - 320)
253
         */
254
14.7k
        CopyOffset = ((accumulator >> 16) & 0x1FFF) + 320;
255
14.7k
        BitStream_Shift(bs, 16);
256
14.7k
      }
257
0
      else
258
0
      {
259
        /* Invalid CopyOffset Encoding */
260
0
        return -1002;
261
0
      }
262
73.1k
    }
263
264
    /**
265
     * LengthOfMatch Encoding
266
     */
267
264k
    accumulator = bs->accumulator;
268
269
264k
    if ((accumulator & 0x80000000) == 0x00000000)
270
124k
    {
271
      /**
272
       * LengthOfMatch [3]
273
       * bit 0 + 0 lower bits of LengthOfMatch
274
       */
275
124k
      LengthOfMatch = 3;
276
124k
      BitStream_Shift(bs, 1);
277
124k
    }
278
140k
    else if ((accumulator & 0xC0000000) == 0x80000000)
279
31.4k
    {
280
      /**
281
       * LengthOfMatch [4, 7]
282
       * bits 10 + 2 lower bits of LengthOfMatch
283
       */
284
31.4k
      LengthOfMatch = ((accumulator >> 28) & 0x0003) + 0x0004;
285
31.4k
      BitStream_Shift(bs, 4);
286
31.4k
    }
287
108k
    else if ((accumulator & 0xE0000000) == 0xC0000000)
288
33.4k
    {
289
      /**
290
       * LengthOfMatch [8, 15]
291
       * bits 110 + 3 lower bits of LengthOfMatch
292
       */
293
33.4k
      LengthOfMatch = ((accumulator >> 26) & 0x0007) + 0x0008;
294
33.4k
      BitStream_Shift(bs, 6);
295
33.4k
    }
296
75.4k
    else if ((accumulator & 0xF0000000) == 0xE0000000)
297
7.81k
    {
298
      /**
299
       * LengthOfMatch [16, 31]
300
       * bits 1110 + 4 lower bits of LengthOfMatch
301
       */
302
7.81k
      LengthOfMatch = ((accumulator >> 24) & 0x000F) + 0x0010;
303
7.81k
      BitStream_Shift(bs, 8);
304
7.81k
    }
305
67.6k
    else if ((accumulator & 0xF8000000) == 0xF0000000)
306
12.8k
    {
307
      /**
308
       * LengthOfMatch [32, 63]
309
       * bits 11110 + 5 lower bits of LengthOfMatch
310
       */
311
12.8k
      LengthOfMatch = ((accumulator >> 22) & 0x001F) + 0x0020;
312
12.8k
      BitStream_Shift(bs, 10);
313
12.8k
    }
314
54.7k
    else if ((accumulator & 0xFC000000) == 0xF8000000)
315
21.3k
    {
316
      /**
317
       * LengthOfMatch [64, 127]
318
       * bits 111110 + 6 lower bits of LengthOfMatch
319
       */
320
21.3k
      LengthOfMatch = ((accumulator >> 20) & 0x003F) + 0x0040;
321
21.3k
      BitStream_Shift(bs, 12);
322
21.3k
    }
323
33.4k
    else if ((accumulator & 0xFE000000) == 0xFC000000)
324
19.4k
    {
325
      /**
326
       * LengthOfMatch [128, 255]
327
       * bits 1111110 + 7 lower bits of LengthOfMatch
328
       */
329
19.4k
      LengthOfMatch = ((accumulator >> 18) & 0x007F) + 0x0080;
330
19.4k
      BitStream_Shift(bs, 14);
331
19.4k
    }
332
13.9k
    else if ((accumulator & 0xFF000000) == 0xFE000000)
333
5.16k
    {
334
      /**
335
       * LengthOfMatch [256, 511]
336
       * bits 11111110 + 8 lower bits of LengthOfMatch
337
       */
338
5.16k
      LengthOfMatch = ((accumulator >> 16) & 0x00FF) + 0x0100;
339
5.16k
      BitStream_Shift(bs, 16);
340
5.16k
    }
341
8.81k
    else if ((accumulator & 0xFF800000) == 0xFF000000)
342
907
    {
343
      /**
344
       * LengthOfMatch [512, 1023]
345
       * bits 111111110 + 9 lower bits of LengthOfMatch
346
       */
347
907
      LengthOfMatch = ((accumulator >> 14) & 0x01FF) + 0x0200;
348
907
      BitStream_Shift(bs, 18);
349
907
    }
350
7.90k
    else if ((accumulator & 0xFFC00000) == 0xFF800000)
351
791
    {
352
      /**
353
       * LengthOfMatch [1024, 2047]
354
       * bits 1111111110 + 10 lower bits of LengthOfMatch
355
       */
356
791
      LengthOfMatch = ((accumulator >> 12) & 0x03FF) + 0x0400;
357
791
      BitStream_Shift(bs, 20);
358
791
    }
359
7.11k
    else if ((accumulator & 0xFFE00000) == 0xFFC00000)
360
475
    {
361
      /**
362
       * LengthOfMatch [2048, 4095]
363
       * bits 11111111110 + 11 lower bits of LengthOfMatch
364
       */
365
475
      LengthOfMatch = ((accumulator >> 10) & 0x07FF) + 0x0800;
366
475
      BitStream_Shift(bs, 22);
367
475
    }
368
6.63k
    else if ((accumulator & 0xFFF00000) == 0xFFE00000)
369
439
    {
370
      /**
371
       * LengthOfMatch [4096, 8191]
372
       * bits 111111111110 + 12 lower bits of LengthOfMatch
373
       */
374
439
      LengthOfMatch = ((accumulator >> 8) & 0x0FFF) + 0x1000;
375
439
      BitStream_Shift(bs, 24);
376
439
    }
377
6.20k
    else if (((accumulator & 0xFFF80000) == 0xFFF00000) && CompressionLevel) /* RDP5 */
378
389
    {
379
      /**
380
       * LengthOfMatch [8192, 16383]
381
       * bits 1111111111110 + 13 lower bits of LengthOfMatch
382
       */
383
389
      LengthOfMatch = ((accumulator >> 6) & 0x1FFF) + 0x2000;
384
389
      BitStream_Shift(bs, 26);
385
389
    }
386
5.81k
    else if (((accumulator & 0xFFFC0000) == 0xFFF80000) && CompressionLevel) /* RDP5 */
387
479
    {
388
      /**
389
       * LengthOfMatch [16384, 32767]
390
       * bits 11111111111110 + 14 lower bits of LengthOfMatch
391
       */
392
479
      LengthOfMatch = ((accumulator >> 4) & 0x3FFF) + 0x4000;
393
479
      BitStream_Shift(bs, 28);
394
479
    }
395
5.33k
    else if (((accumulator & 0xFFFE0000) == 0xFFFC0000) && CompressionLevel) /* RDP5 */
396
445
    {
397
      /**
398
       * LengthOfMatch [32768, 65535]
399
       * bits 111111111111110 + 15 lower bits of LengthOfMatch
400
       */
401
445
      LengthOfMatch = ((accumulator >> 2) & 0x7FFF) + 0x8000;
402
445
      BitStream_Shift(bs, 30);
403
445
    }
404
4.88k
    else
405
4.88k
    {
406
      /* Invalid LengthOfMatch Encoding */
407
4.88k
      return -1003;
408
4.88k
    }
409
410
#if defined(DEBUG_MPPC)
411
    WLog_DBG(TAG, "<%" PRIu32 ",%" PRIu32 ">", CopyOffset, LengthOfMatch);
412
#endif
413
414
259k
    if ((HistoryPtr + LengthOfMatch - 1) > HistoryBufferEnd)
415
334
    {
416
334
      WLog_ERR(TAG, "history buffer overflow");
417
334
      return -1005;
418
334
    }
419
420
259k
    SrcPtr = &HistoryBuffer[(HistoryPtr - HistoryBuffer - CopyOffset) &
421
259k
                            (CompressionLevel ? 0xFFFF : 0x1FFF)];
422
423
259k
    do
424
46.2M
    {
425
46.2M
      *HistoryPtr++ = *SrcPtr++;
426
46.2M
    } while (--LengthOfMatch);
427
259k
  }
428
429
11.7k
  *pDstSize = (UINT32)(HistoryPtr - mppc->HistoryPtr);
430
11.7k
  *ppDstData = mppc->HistoryPtr;
431
11.7k
  mppc->HistoryPtr = HistoryPtr;
432
11.7k
  return 1;
433
20.3k
}
434
435
int mppc_compress(MPPC_CONTEXT* mppc, const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstBuffer,
436
                  const BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
437
0
{
438
0
  const BYTE* pSrcPtr = NULL;
439
0
  const BYTE* pSrcEnd = NULL;
440
0
  BYTE* MatchPtr = NULL;
441
0
  UINT32 DstSize = 0;
442
0
  BYTE* pDstData = NULL;
443
0
  UINT32 MatchIndex = 0;
444
0
  UINT32 accumulator = 0;
445
0
  BOOL PacketFlushed = 0;
446
0
  BOOL PacketAtFront = 0;
447
0
  DWORD CopyOffset = 0;
448
0
  DWORD LengthOfMatch = 0;
449
0
  BYTE* HistoryBuffer = NULL;
450
0
  BYTE* HistoryPtr = NULL;
451
0
  UINT32 HistoryOffset = 0;
452
0
  UINT32 HistoryBufferSize = 0;
453
0
  BYTE Sym1 = 0;
454
0
  BYTE Sym2 = 0;
455
0
  BYTE Sym3 = 0;
456
0
  UINT32 CompressionLevel = 0;
457
0
  wBitStream* bs = NULL;
458
459
0
  WINPR_ASSERT(mppc);
460
0
  WINPR_ASSERT(pSrcData);
461
0
  WINPR_ASSERT(pDstBuffer);
462
0
  WINPR_ASSERT(ppDstData);
463
0
  WINPR_ASSERT(pDstSize);
464
0
  WINPR_ASSERT(pFlags);
465
466
0
  bs = mppc->bs;
467
0
  WINPR_ASSERT(bs);
468
469
0
  HistoryBuffer = mppc->HistoryBuffer;
470
0
  WINPR_ASSERT(HistoryBuffer);
471
472
0
  HistoryBufferSize = mppc->HistoryBufferSize;
473
0
  CompressionLevel = mppc->CompressionLevel;
474
0
  HistoryOffset = mppc->HistoryOffset;
475
0
  *pFlags = 0;
476
0
  PacketFlushed = FALSE;
477
478
0
  if (((HistoryOffset + SrcSize) < (HistoryBufferSize - 3)) && HistoryOffset)
479
0
  {
480
0
    PacketAtFront = FALSE;
481
0
  }
482
0
  else
483
0
  {
484
0
    if (HistoryOffset == (HistoryBufferSize + 1))
485
0
      PacketFlushed = TRUE;
486
487
0
    HistoryOffset = 0;
488
0
    PacketAtFront = TRUE;
489
0
  }
490
491
0
  HistoryPtr = &(HistoryBuffer[HistoryOffset]);
492
0
  pDstData = pDstBuffer;
493
0
  *ppDstData = pDstBuffer;
494
495
0
  if (!pDstData)
496
0
    return -1;
497
498
0
  if (*pDstSize > SrcSize)
499
0
    DstSize = SrcSize;
500
0
  else
501
0
    DstSize = *pDstSize;
502
503
0
  BitStream_Attach(bs, pDstData, DstSize);
504
0
  pSrcPtr = pSrcData;
505
0
  pSrcEnd = &(pSrcData[SrcSize - 1]);
506
507
0
  while (pSrcPtr < (pSrcEnd - 2))
508
0
  {
509
0
    Sym1 = pSrcPtr[0];
510
0
    Sym2 = pSrcPtr[1];
511
0
    Sym3 = pSrcPtr[2];
512
0
    *HistoryPtr++ = *pSrcPtr++;
513
0
    MatchIndex = MPPC_MATCH_INDEX(Sym1, Sym2, Sym3);
514
0
    MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]);
515
516
0
    if (MatchPtr != (HistoryPtr - 1))
517
0
      mppc->MatchBuffer[MatchIndex] = (UINT16)(HistoryPtr - HistoryBuffer);
518
519
0
    if (mppc->HistoryPtr < HistoryPtr)
520
0
      mppc->HistoryPtr = HistoryPtr;
521
522
0
    if ((Sym1 != *(MatchPtr - 1)) || (Sym2 != MatchPtr[0]) || (Sym3 != MatchPtr[1]) ||
523
0
        (&MatchPtr[1] > mppc->HistoryPtr) || (MatchPtr == HistoryBuffer) ||
524
0
        (MatchPtr == (HistoryPtr - 1)) || (MatchPtr == HistoryPtr))
525
0
    {
526
0
      if (((bs->position / 8) + 2) > (DstSize - 1))
527
0
      {
528
0
        mppc_context_reset(mppc, TRUE);
529
0
        *pFlags |= PACKET_FLUSHED;
530
0
        *pFlags |= CompressionLevel;
531
0
        *ppDstData = pSrcData;
532
0
        *pDstSize = SrcSize;
533
0
        return 1;
534
0
      }
535
536
0
      accumulator = Sym1;
537
#if defined(DEBUG_MPPC)
538
      WLog_DBG(TAG, "%" PRIu32 "", accumulator);
539
#endif
540
541
0
      if (accumulator < 0x80)
542
0
      {
543
        /* 8 bits of literal are encoded as-is */
544
0
        BitStream_Write_Bits(bs, accumulator, 8);
545
0
      }
546
0
      else
547
0
      {
548
        /* bits 10 followed by lower 7 bits of literal */
549
0
        accumulator = 0x100 | (accumulator & 0x7F);
550
0
        BitStream_Write_Bits(bs, accumulator, 9);
551
0
      }
552
0
    }
553
0
    else
554
0
    {
555
0
      CopyOffset = (HistoryBufferSize - 1) & (HistoryPtr - MatchPtr);
556
0
      *HistoryPtr++ = Sym2;
557
0
      *HistoryPtr++ = Sym3;
558
0
      pSrcPtr += 2;
559
0
      LengthOfMatch = 3;
560
0
      MatchPtr += 2;
561
562
0
      while ((*pSrcPtr == *MatchPtr) && (pSrcPtr < pSrcEnd) && (MatchPtr <= mppc->HistoryPtr))
563
0
      {
564
0
        MatchPtr++;
565
0
        *HistoryPtr++ = *pSrcPtr++;
566
0
        LengthOfMatch++;
567
0
      }
568
569
#if defined(DEBUG_MPPC)
570
      WLog_DBG(TAG, "<%" PRIu32 ",%" PRIu32 ">", CopyOffset, LengthOfMatch);
571
#endif
572
573
      /* Encode CopyOffset */
574
575
0
      if (((bs->position / 8) + 7) > (DstSize - 1))
576
0
      {
577
0
        mppc_context_reset(mppc, TRUE);
578
0
        *pFlags |= PACKET_FLUSHED;
579
0
        *pFlags |= CompressionLevel;
580
0
        *ppDstData = pSrcData;
581
0
        *pDstSize = SrcSize;
582
0
        return 1;
583
0
      }
584
585
0
      if (CompressionLevel) /* RDP5 */
586
0
      {
587
0
        if (CopyOffset < 64)
588
0
        {
589
          /* bits 11111 + lower 6 bits of CopyOffset */
590
0
          accumulator = 0x07C0 | (CopyOffset & 0x003F);
591
0
          BitStream_Write_Bits(bs, accumulator, 11);
592
0
        }
593
0
        else if ((CopyOffset >= 64) && (CopyOffset < 320))
594
0
        {
595
          /* bits 11110 + lower 8 bits of (CopyOffset - 64) */
596
0
          accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF);
597
0
          BitStream_Write_Bits(bs, accumulator, 13);
598
0
        }
599
0
        else if ((CopyOffset >= 320) && (CopyOffset < 2368))
600
0
        {
601
          /* bits 1110 + lower 11 bits of (CopyOffset - 320) */
602
0
          accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF);
603
0
          BitStream_Write_Bits(bs, accumulator, 15);
604
0
        }
605
0
        else
606
0
        {
607
          /* bits 110 + lower 16 bits of (CopyOffset - 2368) */
608
0
          accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF);
609
0
          BitStream_Write_Bits(bs, accumulator, 19);
610
0
        }
611
0
      }
612
0
      else /* RDP4 */
613
0
      {
614
0
        if (CopyOffset < 64)
615
0
        {
616
          /* bits 1111 + lower 6 bits of CopyOffset */
617
0
          accumulator = 0x03C0 | (CopyOffset & 0x003F);
618
0
          BitStream_Write_Bits(bs, accumulator, 10);
619
0
        }
620
0
        else if ((CopyOffset >= 64) && (CopyOffset < 320))
621
0
        {
622
          /* bits 1110 + lower 8 bits of (CopyOffset - 64) */
623
0
          accumulator = 0x0E00 | ((CopyOffset - 64) & 0x00FF);
624
0
          BitStream_Write_Bits(bs, accumulator, 12);
625
0
        }
626
0
        else if ((CopyOffset >= 320) && (CopyOffset < 8192))
627
0
        {
628
          /* bits 110 + lower 13 bits of (CopyOffset - 320) */
629
0
          accumulator = 0xC000 | ((CopyOffset - 320) & 0x1FFF);
630
0
          BitStream_Write_Bits(bs, accumulator, 16);
631
0
        }
632
0
      }
633
634
      /* Encode LengthOfMatch */
635
636
0
      if (LengthOfMatch == 3)
637
0
      {
638
        /* 0 + 0 lower bits of LengthOfMatch */
639
0
        BitStream_Write_Bits(bs, 0, 1);
640
0
      }
641
0
      else if ((LengthOfMatch >= 4) && (LengthOfMatch < 8))
642
0
      {
643
        /* 10 + 2 lower bits of LengthOfMatch */
644
0
        accumulator = 0x0008 | (LengthOfMatch & 0x0003);
645
0
        BitStream_Write_Bits(bs, accumulator, 4);
646
0
      }
647
0
      else if ((LengthOfMatch >= 8) && (LengthOfMatch < 16))
648
0
      {
649
        /* 110 + 3 lower bits of LengthOfMatch */
650
0
        accumulator = 0x0030 | (LengthOfMatch & 0x0007);
651
0
        BitStream_Write_Bits(bs, accumulator, 6);
652
0
      }
653
0
      else if ((LengthOfMatch >= 16) && (LengthOfMatch < 32))
654
0
      {
655
        /* 1110 + 4 lower bits of LengthOfMatch */
656
0
        accumulator = 0x00E0 | (LengthOfMatch & 0x000F);
657
0
        BitStream_Write_Bits(bs, accumulator, 8);
658
0
      }
659
0
      else if ((LengthOfMatch >= 32) && (LengthOfMatch < 64))
660
0
      {
661
        /* 11110 + 5 lower bits of LengthOfMatch */
662
0
        accumulator = 0x03C0 | (LengthOfMatch & 0x001F);
663
0
        BitStream_Write_Bits(bs, accumulator, 10);
664
0
      }
665
0
      else if ((LengthOfMatch >= 64) && (LengthOfMatch < 128))
666
0
      {
667
        /* 111110 + 6 lower bits of LengthOfMatch */
668
0
        accumulator = 0x0F80 | (LengthOfMatch & 0x003F);
669
0
        BitStream_Write_Bits(bs, accumulator, 12);
670
0
      }
671
0
      else if ((LengthOfMatch >= 128) && (LengthOfMatch < 256))
672
0
      {
673
        /* 1111110 + 7 lower bits of LengthOfMatch */
674
0
        accumulator = 0x3F00 | (LengthOfMatch & 0x007F);
675
0
        BitStream_Write_Bits(bs, accumulator, 14);
676
0
      }
677
0
      else if ((LengthOfMatch >= 256) && (LengthOfMatch < 512))
678
0
      {
679
        /* 11111110 + 8 lower bits of LengthOfMatch */
680
0
        accumulator = 0xFE00 | (LengthOfMatch & 0x00FF);
681
0
        BitStream_Write_Bits(bs, accumulator, 16);
682
0
      }
683
0
      else if ((LengthOfMatch >= 512) && (LengthOfMatch < 1024))
684
0
      {
685
        /* 111111110 + 9 lower bits of LengthOfMatch */
686
0
        accumulator = 0x3FC00 | (LengthOfMatch & 0x01FF);
687
0
        BitStream_Write_Bits(bs, accumulator, 18);
688
0
      }
689
0
      else if ((LengthOfMatch >= 1024) && (LengthOfMatch < 2048))
690
0
      {
691
        /* 1111111110 + 10 lower bits of LengthOfMatch */
692
0
        accumulator = 0xFF800 | (LengthOfMatch & 0x03FF);
693
0
        BitStream_Write_Bits(bs, accumulator, 20);
694
0
      }
695
0
      else if ((LengthOfMatch >= 2048) && (LengthOfMatch < 4096))
696
0
      {
697
        /* 11111111110 + 11 lower bits of LengthOfMatch */
698
0
        accumulator = 0x3FF000 | (LengthOfMatch & 0x07FF);
699
0
        BitStream_Write_Bits(bs, accumulator, 22);
700
0
      }
701
0
      else if ((LengthOfMatch >= 4096) && (LengthOfMatch < 8192))
702
0
      {
703
        /* 111111111110 + 12 lower bits of LengthOfMatch */
704
0
        accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF);
705
0
        BitStream_Write_Bits(bs, accumulator, 24);
706
0
      }
707
0
      else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) &&
708
0
               CompressionLevel) /* RDP5 */
709
0
      {
710
        /* 1111111111110 + 13 lower bits of LengthOfMatch */
711
0
        accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF);
712
0
        BitStream_Write_Bits(bs, accumulator, 26);
713
0
      }
714
0
      else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) &&
715
0
               CompressionLevel) /* RDP5 */
716
0
      {
717
        /* 11111111111110 + 14 lower bits of LengthOfMatch */
718
0
        accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF);
719
0
        BitStream_Write_Bits(bs, accumulator, 28);
720
0
      }
721
0
      else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) &&
722
0
               CompressionLevel) /* RDP5 */
723
0
      {
724
        /* 111111111111110 + 15 lower bits of LengthOfMatch */
725
0
        accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF);
726
0
        BitStream_Write_Bits(bs, accumulator, 30);
727
0
      }
728
0
    }
729
0
  }
730
731
  /* Encode trailing symbols as literals */
732
733
0
  while (pSrcPtr <= pSrcEnd)
734
0
  {
735
0
    if (((bs->position / 8) + 2) > (DstSize - 1))
736
0
    {
737
0
      mppc_context_reset(mppc, TRUE);
738
0
      *pFlags |= PACKET_FLUSHED;
739
0
      *pFlags |= CompressionLevel;
740
0
      *ppDstData = pSrcData;
741
0
      *pDstSize = SrcSize;
742
0
      return 1;
743
0
    }
744
745
0
    accumulator = *pSrcPtr;
746
#if defined(DEBUG_MPPC)
747
    WLog_DBG(TAG, "%" PRIu32 "", accumulator);
748
#endif
749
750
0
    if (accumulator < 0x80)
751
0
    {
752
      /* 8 bits of literal are encoded as-is */
753
0
      BitStream_Write_Bits(bs, accumulator, 8);
754
0
    }
755
0
    else
756
0
    {
757
      /* bits 10 followed by lower 7 bits of literal */
758
0
      accumulator = 0x100 | (accumulator & 0x7F);
759
0
      BitStream_Write_Bits(bs, accumulator, 9);
760
0
    }
761
762
0
    *HistoryPtr++ = *pSrcPtr++;
763
0
  }
764
765
0
  BitStream_Flush(bs);
766
0
  *pFlags |= PACKET_COMPRESSED;
767
0
  *pFlags |= CompressionLevel;
768
769
0
  if (PacketAtFront)
770
0
    *pFlags |= PACKET_AT_FRONT;
771
772
0
  if (PacketFlushed)
773
0
    *pFlags |= PACKET_FLUSHED;
774
775
0
  *pDstSize = ((bs->position + 7) / 8);
776
0
  mppc->HistoryPtr = HistoryPtr;
777
0
  mppc->HistoryOffset = HistoryPtr - HistoryBuffer;
778
0
  return 1;
779
0
}
780
781
void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel)
782
727
{
783
727
  WINPR_ASSERT(mppc);
784
785
727
  if (CompressionLevel < 1)
786
214
  {
787
214
    mppc->CompressionLevel = 0;
788
214
    mppc->HistoryBufferSize = 8192;
789
214
  }
790
513
  else
791
513
  {
792
513
    mppc->CompressionLevel = 1;
793
513
    mppc->HistoryBufferSize = 65536;
794
513
  }
795
727
}
796
797
void mppc_context_reset(MPPC_CONTEXT* mppc, BOOL flush)
798
118k
{
799
118k
  WINPR_ASSERT(mppc);
800
801
118k
  ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer));
802
118k
  ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer));
803
804
118k
  if (flush)
805
0
  {
806
0
    mppc->HistoryOffset = mppc->HistoryBufferSize + 1;
807
0
    mppc->HistoryPtr = mppc->HistoryBuffer;
808
0
  }
809
118k
  else
810
118k
  {
811
118k
    mppc->HistoryOffset = 0;
812
118k
    mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
813
118k
  }
814
118k
}
815
816
MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor)
817
82.7k
{
818
82.7k
  MPPC_CONTEXT* mppc = calloc(1, sizeof(MPPC_CONTEXT));
819
820
82.7k
  if (!mppc)
821
0
    goto fail;
822
823
82.7k
  mppc->Compressor = Compressor;
824
825
82.7k
  if (CompressionLevel < 1)
826
5.71k
  {
827
5.71k
    mppc->CompressionLevel = 0;
828
5.71k
    mppc->HistoryBufferSize = 8192;
829
5.71k
  }
830
77.0k
  else
831
77.0k
  {
832
77.0k
    mppc->CompressionLevel = 1;
833
77.0k
    mppc->HistoryBufferSize = 65536;
834
77.0k
  }
835
836
82.7k
  mppc->bs = BitStream_New();
837
838
82.7k
  if (!mppc->bs)
839
0
    goto fail;
840
841
82.7k
  mppc_context_reset(mppc, FALSE);
842
843
82.7k
  return mppc;
844
845
0
fail:
846
0
  mppc_context_free(mppc);
847
0
  return NULL;
848
82.7k
}
849
850
void mppc_context_free(MPPC_CONTEXT* mppc)
851
82.7k
{
852
82.7k
  if (mppc)
853
82.7k
  {
854
82.7k
    BitStream_Free(mppc->bs);
855
82.7k
    free(mppc);
856
82.7k
  }
857
82.7k
}