FreeRDP
mppc.c
1 
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  ((((MPPC_MATCH_TABLE[_sym3] << 16) + (MPPC_MATCH_TABLE[_sym2] << 8) + \
37  MPPC_MATCH_TABLE[_sym1]) & \
38  0x07FFF000) >> \
39  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 {
91  BYTE Literal = 0;
92  BYTE* SrcPtr = NULL;
93  UINT32 CopyOffset = 0;
94  UINT32 LengthOfMatch = 0;
95  UINT32 accumulator = 0;
96  BYTE* HistoryPtr = NULL;
97  BYTE* HistoryBuffer = NULL;
98  BYTE* HistoryBufferEnd = NULL;
99  UINT32 HistoryBufferSize = 0;
100  UINT32 CompressionLevel = 0;
101  wBitStream* bs = NULL;
102 
103  WINPR_ASSERT(mppc);
104  WINPR_ASSERT(pSrcData);
105  WINPR_ASSERT(ppDstData);
106  WINPR_ASSERT(pDstSize);
107 
108  bs = mppc->bs;
109  WINPR_ASSERT(bs);
110 
111  HistoryBuffer = mppc->HistoryBuffer;
112  WINPR_ASSERT(HistoryBuffer);
113 
114  HistoryBufferSize = mppc->HistoryBufferSize;
115  HistoryBufferEnd = &HistoryBuffer[HistoryBufferSize - 1];
116  CompressionLevel = mppc->CompressionLevel;
117  BitStream_Attach(bs, pSrcData, SrcSize);
118  BitStream_Fetch(bs);
119 
120  if (flags & PACKET_AT_FRONT)
121  {
122  mppc->HistoryOffset = 0;
123  mppc->HistoryPtr = HistoryBuffer;
124  }
125 
126  if (flags & PACKET_FLUSHED)
127  {
128  mppc->HistoryOffset = 0;
129  mppc->HistoryPtr = HistoryBuffer;
130  ZeroMemory(HistoryBuffer, mppc->HistoryBufferSize);
131  }
132 
133  HistoryPtr = mppc->HistoryPtr;
134 
135  if (!(flags & PACKET_COMPRESSED))
136  {
137  *pDstSize = SrcSize;
138  *ppDstData = pSrcData;
139  return 1;
140  }
141 
142  while ((bs->length - bs->position) >= 8)
143  {
144  accumulator = bs->accumulator;
145 
150  if (HistoryPtr > HistoryBufferEnd)
151  {
152  WLog_ERR(TAG, "history buffer index out of range");
153  return -1004;
154  }
155 
156  if ((accumulator & 0x80000000) == 0x00000000)
157  {
162  Literal = ((accumulator & 0x7F000000) >> 24);
163  *(HistoryPtr) = Literal;
164  HistoryPtr++;
165  BitStream_Shift(bs, 8);
166  continue;
167  }
168  else if ((accumulator & 0xC0000000) == 0x80000000)
169  {
174  Literal = ((accumulator & 0x3F800000) >> 23) + 0x80;
175  *(HistoryPtr) = Literal;
176  HistoryPtr++;
177  BitStream_Shift(bs, 9);
178  continue;
179  }
180 
184  if (CompressionLevel) /* RDP5 */
185  {
186  if ((accumulator & 0xF8000000) == 0xF8000000)
187  {
192  CopyOffset = ((accumulator >> 21) & 0x3F);
193  BitStream_Shift(bs, 11);
194  }
195  else if ((accumulator & 0xF8000000) == 0xF0000000)
196  {
201  CopyOffset = ((accumulator >> 19) & 0xFF) + 64;
202  BitStream_Shift(bs, 13);
203  }
204  else if ((accumulator & 0xF0000000) == 0xE0000000)
205  {
210  CopyOffset = ((accumulator >> 17) & 0x7FF) + 320;
211  BitStream_Shift(bs, 15);
212  }
213  else if ((accumulator & 0xE0000000) == 0xC0000000)
214  {
219  CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368;
220  BitStream_Shift(bs, 19);
221  }
222  else
223  {
224  /* Invalid CopyOffset Encoding */
225  return -1001;
226  }
227  }
228  else /* RDP4 */
229  {
230  if ((accumulator & 0xF0000000) == 0xF0000000)
231  {
236  CopyOffset = ((accumulator >> 22) & 0x3F);
237  BitStream_Shift(bs, 10);
238  }
239  else if ((accumulator & 0xF0000000) == 0xE0000000)
240  {
245  CopyOffset = ((accumulator >> 20) & 0xFF) + 64;
246  BitStream_Shift(bs, 12);
247  }
248  else if ((accumulator & 0xE0000000) == 0xC0000000)
249  {
254  CopyOffset = ((accumulator >> 16) & 0x1FFF) + 320;
255  BitStream_Shift(bs, 16);
256  }
257  else
258  {
259  /* Invalid CopyOffset Encoding */
260  return -1002;
261  }
262  }
263 
267  accumulator = bs->accumulator;
268 
269  if ((accumulator & 0x80000000) == 0x00000000)
270  {
275  LengthOfMatch = 3;
276  BitStream_Shift(bs, 1);
277  }
278  else if ((accumulator & 0xC0000000) == 0x80000000)
279  {
284  LengthOfMatch = ((accumulator >> 28) & 0x0003) + 0x0004;
285  BitStream_Shift(bs, 4);
286  }
287  else if ((accumulator & 0xE0000000) == 0xC0000000)
288  {
293  LengthOfMatch = ((accumulator >> 26) & 0x0007) + 0x0008;
294  BitStream_Shift(bs, 6);
295  }
296  else if ((accumulator & 0xF0000000) == 0xE0000000)
297  {
302  LengthOfMatch = ((accumulator >> 24) & 0x000F) + 0x0010;
303  BitStream_Shift(bs, 8);
304  }
305  else if ((accumulator & 0xF8000000) == 0xF0000000)
306  {
311  LengthOfMatch = ((accumulator >> 22) & 0x001F) + 0x0020;
312  BitStream_Shift(bs, 10);
313  }
314  else if ((accumulator & 0xFC000000) == 0xF8000000)
315  {
320  LengthOfMatch = ((accumulator >> 20) & 0x003F) + 0x0040;
321  BitStream_Shift(bs, 12);
322  }
323  else if ((accumulator & 0xFE000000) == 0xFC000000)
324  {
329  LengthOfMatch = ((accumulator >> 18) & 0x007F) + 0x0080;
330  BitStream_Shift(bs, 14);
331  }
332  else if ((accumulator & 0xFF000000) == 0xFE000000)
333  {
338  LengthOfMatch = ((accumulator >> 16) & 0x00FF) + 0x0100;
339  BitStream_Shift(bs, 16);
340  }
341  else if ((accumulator & 0xFF800000) == 0xFF000000)
342  {
347  LengthOfMatch = ((accumulator >> 14) & 0x01FF) + 0x0200;
348  BitStream_Shift(bs, 18);
349  }
350  else if ((accumulator & 0xFFC00000) == 0xFF800000)
351  {
356  LengthOfMatch = ((accumulator >> 12) & 0x03FF) + 0x0400;
357  BitStream_Shift(bs, 20);
358  }
359  else if ((accumulator & 0xFFE00000) == 0xFFC00000)
360  {
365  LengthOfMatch = ((accumulator >> 10) & 0x07FF) + 0x0800;
366  BitStream_Shift(bs, 22);
367  }
368  else if ((accumulator & 0xFFF00000) == 0xFFE00000)
369  {
374  LengthOfMatch = ((accumulator >> 8) & 0x0FFF) + 0x1000;
375  BitStream_Shift(bs, 24);
376  }
377  else if (((accumulator & 0xFFF80000) == 0xFFF00000) && CompressionLevel) /* RDP5 */
378  {
383  LengthOfMatch = ((accumulator >> 6) & 0x1FFF) + 0x2000;
384  BitStream_Shift(bs, 26);
385  }
386  else if (((accumulator & 0xFFFC0000) == 0xFFF80000) && CompressionLevel) /* RDP5 */
387  {
392  LengthOfMatch = ((accumulator >> 4) & 0x3FFF) + 0x4000;
393  BitStream_Shift(bs, 28);
394  }
395  else if (((accumulator & 0xFFFE0000) == 0xFFFC0000) && CompressionLevel) /* RDP5 */
396  {
401  LengthOfMatch = ((accumulator >> 2) & 0x7FFF) + 0x8000;
402  BitStream_Shift(bs, 30);
403  }
404  else
405  {
406  /* Invalid LengthOfMatch Encoding */
407  return -1003;
408  }
409 
410 #if defined(DEBUG_MPPC)
411  WLog_DBG(TAG, "<%" PRIu32 ",%" PRIu32 ">", CopyOffset, LengthOfMatch);
412 #endif
413 
414  if ((HistoryPtr + LengthOfMatch - 1) > HistoryBufferEnd)
415  {
416  WLog_ERR(TAG, "history buffer overflow");
417  return -1005;
418  }
419 
420  SrcPtr = &HistoryBuffer[(HistoryPtr - HistoryBuffer - CopyOffset) &
421  (CompressionLevel ? 0xFFFF : 0x1FFF)];
422 
423  do
424  {
425  *HistoryPtr++ = *SrcPtr++;
426  } while (--LengthOfMatch);
427  }
428 
429  *pDstSize = (UINT32)(HistoryPtr - mppc->HistoryPtr);
430  *ppDstData = mppc->HistoryPtr;
431  mppc->HistoryPtr = HistoryPtr;
432  return 1;
433 }
434 
435 int mppc_compress(MPPC_CONTEXT* mppc, const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstBuffer,
436  const BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
437 {
438  const BYTE* pSrcPtr = NULL;
439  const BYTE* pSrcEnd = NULL;
440  BYTE* MatchPtr = NULL;
441  UINT32 DstSize = 0;
442  BYTE* pDstData = NULL;
443  UINT32 MatchIndex = 0;
444  UINT32 accumulator = 0;
445  BOOL PacketFlushed = 0;
446  BOOL PacketAtFront = 0;
447  DWORD CopyOffset = 0;
448  DWORD LengthOfMatch = 0;
449  BYTE* HistoryBuffer = NULL;
450  BYTE* HistoryPtr = NULL;
451  UINT32 HistoryOffset = 0;
452  UINT32 HistoryBufferSize = 0;
453  BYTE Sym1 = 0;
454  BYTE Sym2 = 0;
455  BYTE Sym3 = 0;
456  UINT32 CompressionLevel = 0;
457  wBitStream* bs = NULL;
458 
459  WINPR_ASSERT(mppc);
460  WINPR_ASSERT(pSrcData);
461  WINPR_ASSERT(pDstBuffer);
462  WINPR_ASSERT(ppDstData);
463  WINPR_ASSERT(pDstSize);
464  WINPR_ASSERT(pFlags);
465 
466  bs = mppc->bs;
467  WINPR_ASSERT(bs);
468 
469  HistoryBuffer = mppc->HistoryBuffer;
470  WINPR_ASSERT(HistoryBuffer);
471 
472  HistoryBufferSize = mppc->HistoryBufferSize;
473  CompressionLevel = mppc->CompressionLevel;
474  HistoryOffset = mppc->HistoryOffset;
475  *pFlags = 0;
476  PacketFlushed = FALSE;
477 
478  if (((HistoryOffset + SrcSize) < (HistoryBufferSize - 3)) && HistoryOffset)
479  {
480  PacketAtFront = FALSE;
481  }
482  else
483  {
484  if (HistoryOffset == (HistoryBufferSize + 1))
485  PacketFlushed = TRUE;
486 
487  HistoryOffset = 0;
488  PacketAtFront = TRUE;
489  }
490 
491  HistoryPtr = &(HistoryBuffer[HistoryOffset]);
492  pDstData = pDstBuffer;
493  *ppDstData = pDstBuffer;
494 
495  if (!pDstData)
496  return -1;
497 
498  if (*pDstSize > SrcSize)
499  DstSize = SrcSize;
500  else
501  DstSize = *pDstSize;
502 
503  BitStream_Attach(bs, pDstData, DstSize);
504  pSrcPtr = pSrcData;
505  pSrcEnd = &(pSrcData[SrcSize - 1]);
506 
507  while (pSrcPtr < (pSrcEnd - 2))
508  {
509  Sym1 = pSrcPtr[0];
510  Sym2 = pSrcPtr[1];
511  Sym3 = pSrcPtr[2];
512  *HistoryPtr++ = *pSrcPtr++;
513  MatchIndex = MPPC_MATCH_INDEX(Sym1, Sym2, Sym3);
514  MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]);
515 
516  if (MatchPtr != (HistoryPtr - 1))
517  mppc->MatchBuffer[MatchIndex] = (UINT16)(HistoryPtr - HistoryBuffer);
518 
519  if (mppc->HistoryPtr < HistoryPtr)
520  mppc->HistoryPtr = HistoryPtr;
521 
522  if ((Sym1 != *(MatchPtr - 1)) || (Sym2 != MatchPtr[0]) || (Sym3 != MatchPtr[1]) ||
523  (&MatchPtr[1] > mppc->HistoryPtr) || (MatchPtr == HistoryBuffer) ||
524  (MatchPtr == (HistoryPtr - 1)) || (MatchPtr == HistoryPtr))
525  {
526  if (((bs->position / 8) + 2) > (DstSize - 1))
527  {
528  mppc_context_reset(mppc, TRUE);
529  *pFlags |= PACKET_FLUSHED;
530  *pFlags |= CompressionLevel;
531  *ppDstData = pSrcData;
532  *pDstSize = SrcSize;
533  return 1;
534  }
535 
536  accumulator = Sym1;
537 #if defined(DEBUG_MPPC)
538  WLog_DBG(TAG, "%" PRIu32 "", accumulator);
539 #endif
540 
541  if (accumulator < 0x80)
542  {
543  /* 8 bits of literal are encoded as-is */
544  BitStream_Write_Bits(bs, accumulator, 8);
545  }
546  else
547  {
548  /* bits 10 followed by lower 7 bits of literal */
549  accumulator = 0x100 | (accumulator & 0x7F);
550  BitStream_Write_Bits(bs, accumulator, 9);
551  }
552  }
553  else
554  {
555  CopyOffset = (HistoryBufferSize - 1) & (HistoryPtr - MatchPtr);
556  *HistoryPtr++ = Sym2;
557  *HistoryPtr++ = Sym3;
558  pSrcPtr += 2;
559  LengthOfMatch = 3;
560  MatchPtr += 2;
561 
562  while ((*pSrcPtr == *MatchPtr) && (pSrcPtr < pSrcEnd) && (MatchPtr <= mppc->HistoryPtr))
563  {
564  MatchPtr++;
565  *HistoryPtr++ = *pSrcPtr++;
566  LengthOfMatch++;
567  }
568 
569 #if defined(DEBUG_MPPC)
570  WLog_DBG(TAG, "<%" PRIu32 ",%" PRIu32 ">", CopyOffset, LengthOfMatch);
571 #endif
572 
573  /* Encode CopyOffset */
574 
575  if (((bs->position / 8) + 7) > (DstSize - 1))
576  {
577  mppc_context_reset(mppc, TRUE);
578  *pFlags |= PACKET_FLUSHED;
579  *pFlags |= CompressionLevel;
580  *ppDstData = pSrcData;
581  *pDstSize = SrcSize;
582  return 1;
583  }
584 
585  if (CompressionLevel) /* RDP5 */
586  {
587  if (CopyOffset < 64)
588  {
589  /* bits 11111 + lower 6 bits of CopyOffset */
590  accumulator = 0x07C0 | (CopyOffset & 0x003F);
591  BitStream_Write_Bits(bs, accumulator, 11);
592  }
593  else if ((CopyOffset >= 64) && (CopyOffset < 320))
594  {
595  /* bits 11110 + lower 8 bits of (CopyOffset - 64) */
596  accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF);
597  BitStream_Write_Bits(bs, accumulator, 13);
598  }
599  else if ((CopyOffset >= 320) && (CopyOffset < 2368))
600  {
601  /* bits 1110 + lower 11 bits of (CopyOffset - 320) */
602  accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF);
603  BitStream_Write_Bits(bs, accumulator, 15);
604  }
605  else
606  {
607  /* bits 110 + lower 16 bits of (CopyOffset - 2368) */
608  accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF);
609  BitStream_Write_Bits(bs, accumulator, 19);
610  }
611  }
612  else /* RDP4 */
613  {
614  if (CopyOffset < 64)
615  {
616  /* bits 1111 + lower 6 bits of CopyOffset */
617  accumulator = 0x03C0 | (CopyOffset & 0x003F);
618  BitStream_Write_Bits(bs, accumulator, 10);
619  }
620  else if ((CopyOffset >= 64) && (CopyOffset < 320))
621  {
622  /* bits 1110 + lower 8 bits of (CopyOffset - 64) */
623  accumulator = 0x0E00 | ((CopyOffset - 64) & 0x00FF);
624  BitStream_Write_Bits(bs, accumulator, 12);
625  }
626  else if ((CopyOffset >= 320) && (CopyOffset < 8192))
627  {
628  /* bits 110 + lower 13 bits of (CopyOffset - 320) */
629  accumulator = 0xC000 | ((CopyOffset - 320) & 0x1FFF);
630  BitStream_Write_Bits(bs, accumulator, 16);
631  }
632  }
633 
634  /* Encode LengthOfMatch */
635 
636  if (LengthOfMatch == 3)
637  {
638  /* 0 + 0 lower bits of LengthOfMatch */
639  BitStream_Write_Bits(bs, 0, 1);
640  }
641  else if ((LengthOfMatch >= 4) && (LengthOfMatch < 8))
642  {
643  /* 10 + 2 lower bits of LengthOfMatch */
644  accumulator = 0x0008 | (LengthOfMatch & 0x0003);
645  BitStream_Write_Bits(bs, accumulator, 4);
646  }
647  else if ((LengthOfMatch >= 8) && (LengthOfMatch < 16))
648  {
649  /* 110 + 3 lower bits of LengthOfMatch */
650  accumulator = 0x0030 | (LengthOfMatch & 0x0007);
651  BitStream_Write_Bits(bs, accumulator, 6);
652  }
653  else if ((LengthOfMatch >= 16) && (LengthOfMatch < 32))
654  {
655  /* 1110 + 4 lower bits of LengthOfMatch */
656  accumulator = 0x00E0 | (LengthOfMatch & 0x000F);
657  BitStream_Write_Bits(bs, accumulator, 8);
658  }
659  else if ((LengthOfMatch >= 32) && (LengthOfMatch < 64))
660  {
661  /* 11110 + 5 lower bits of LengthOfMatch */
662  accumulator = 0x03C0 | (LengthOfMatch & 0x001F);
663  BitStream_Write_Bits(bs, accumulator, 10);
664  }
665  else if ((LengthOfMatch >= 64) && (LengthOfMatch < 128))
666  {
667  /* 111110 + 6 lower bits of LengthOfMatch */
668  accumulator = 0x0F80 | (LengthOfMatch & 0x003F);
669  BitStream_Write_Bits(bs, accumulator, 12);
670  }
671  else if ((LengthOfMatch >= 128) && (LengthOfMatch < 256))
672  {
673  /* 1111110 + 7 lower bits of LengthOfMatch */
674  accumulator = 0x3F00 | (LengthOfMatch & 0x007F);
675  BitStream_Write_Bits(bs, accumulator, 14);
676  }
677  else if ((LengthOfMatch >= 256) && (LengthOfMatch < 512))
678  {
679  /* 11111110 + 8 lower bits of LengthOfMatch */
680  accumulator = 0xFE00 | (LengthOfMatch & 0x00FF);
681  BitStream_Write_Bits(bs, accumulator, 16);
682  }
683  else if ((LengthOfMatch >= 512) && (LengthOfMatch < 1024))
684  {
685  /* 111111110 + 9 lower bits of LengthOfMatch */
686  accumulator = 0x3FC00 | (LengthOfMatch & 0x01FF);
687  BitStream_Write_Bits(bs, accumulator, 18);
688  }
689  else if ((LengthOfMatch >= 1024) && (LengthOfMatch < 2048))
690  {
691  /* 1111111110 + 10 lower bits of LengthOfMatch */
692  accumulator = 0xFF800 | (LengthOfMatch & 0x03FF);
693  BitStream_Write_Bits(bs, accumulator, 20);
694  }
695  else if ((LengthOfMatch >= 2048) && (LengthOfMatch < 4096))
696  {
697  /* 11111111110 + 11 lower bits of LengthOfMatch */
698  accumulator = 0x3FF000 | (LengthOfMatch & 0x07FF);
699  BitStream_Write_Bits(bs, accumulator, 22);
700  }
701  else if ((LengthOfMatch >= 4096) && (LengthOfMatch < 8192))
702  {
703  /* 111111111110 + 12 lower bits of LengthOfMatch */
704  accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF);
705  BitStream_Write_Bits(bs, accumulator, 24);
706  }
707  else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) &&
708  CompressionLevel) /* RDP5 */
709  {
710  /* 1111111111110 + 13 lower bits of LengthOfMatch */
711  accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF);
712  BitStream_Write_Bits(bs, accumulator, 26);
713  }
714  else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) &&
715  CompressionLevel) /* RDP5 */
716  {
717  /* 11111111111110 + 14 lower bits of LengthOfMatch */
718  accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF);
719  BitStream_Write_Bits(bs, accumulator, 28);
720  }
721  else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) &&
722  CompressionLevel) /* RDP5 */
723  {
724  /* 111111111111110 + 15 lower bits of LengthOfMatch */
725  accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF);
726  BitStream_Write_Bits(bs, accumulator, 30);
727  }
728  }
729  }
730 
731  /* Encode trailing symbols as literals */
732 
733  while (pSrcPtr <= pSrcEnd)
734  {
735  if (((bs->position / 8) + 2) > (DstSize - 1))
736  {
737  mppc_context_reset(mppc, TRUE);
738  *pFlags |= PACKET_FLUSHED;
739  *pFlags |= CompressionLevel;
740  *ppDstData = pSrcData;
741  *pDstSize = SrcSize;
742  return 1;
743  }
744 
745  accumulator = *pSrcPtr;
746 #if defined(DEBUG_MPPC)
747  WLog_DBG(TAG, "%" PRIu32 "", accumulator);
748 #endif
749 
750  if (accumulator < 0x80)
751  {
752  /* 8 bits of literal are encoded as-is */
753  BitStream_Write_Bits(bs, accumulator, 8);
754  }
755  else
756  {
757  /* bits 10 followed by lower 7 bits of literal */
758  accumulator = 0x100 | (accumulator & 0x7F);
759  BitStream_Write_Bits(bs, accumulator, 9);
760  }
761 
762  *HistoryPtr++ = *pSrcPtr++;
763  }
764 
765  BitStream_Flush(bs);
766  *pFlags |= PACKET_COMPRESSED;
767  *pFlags |= CompressionLevel;
768 
769  if (PacketAtFront)
770  *pFlags |= PACKET_AT_FRONT;
771 
772  if (PacketFlushed)
773  *pFlags |= PACKET_FLUSHED;
774 
775  *pDstSize = ((bs->position + 7) / 8);
776  mppc->HistoryPtr = HistoryPtr;
777  const intptr_t diff = HistoryPtr - HistoryBuffer;
778  if (diff > UINT32_MAX)
779  return -1;
780  mppc->HistoryOffset = (UINT32)diff;
781  return 1;
782 }
783 
784 void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel)
785 {
786  WINPR_ASSERT(mppc);
787 
788  if (CompressionLevel < 1)
789  {
790  mppc->CompressionLevel = 0;
791  mppc->HistoryBufferSize = 8192;
792  }
793  else
794  {
795  mppc->CompressionLevel = 1;
796  mppc->HistoryBufferSize = 65536;
797  }
798 }
799 
800 void mppc_context_reset(MPPC_CONTEXT* mppc, BOOL flush)
801 {
802  WINPR_ASSERT(mppc);
803 
804  ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer));
805  ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer));
806 
807  if (flush)
808  {
809  mppc->HistoryOffset = mppc->HistoryBufferSize + 1;
810  mppc->HistoryPtr = mppc->HistoryBuffer;
811  }
812  else
813  {
814  mppc->HistoryOffset = 0;
815  mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
816  }
817 }
818 
819 MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor)
820 {
821  MPPC_CONTEXT* mppc = calloc(1, sizeof(MPPC_CONTEXT));
822 
823  if (!mppc)
824  goto fail;
825 
826  mppc->Compressor = Compressor;
827 
828  if (CompressionLevel < 1)
829  {
830  mppc->CompressionLevel = 0;
831  mppc->HistoryBufferSize = 8192;
832  }
833  else
834  {
835  mppc->CompressionLevel = 1;
836  mppc->HistoryBufferSize = 65536;
837  }
838 
839  mppc->bs = BitStream_New();
840 
841  if (!mppc->bs)
842  goto fail;
843 
844  mppc_context_reset(mppc, FALSE);
845 
846  return mppc;
847 
848 fail:
849  mppc_context_free(mppc);
850  return NULL;
851 }
852 
853 void mppc_context_free(MPPC_CONTEXT* mppc)
854 {
855  if (mppc)
856  {
857  BitStream_Free(mppc->bs);
858  free(mppc);
859  }
860 }