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