/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 | 0 | { |
91 | 0 | BYTE Literal = 0; |
92 | 0 | BYTE* SrcPtr = NULL; |
93 | 0 | UINT32 CopyOffset = 0; |
94 | 0 | UINT32 LengthOfMatch = 0; |
95 | 0 | UINT32 accumulator = 0; |
96 | 0 | BYTE* HistoryPtr = NULL; |
97 | 0 | BYTE* HistoryBuffer = NULL; |
98 | 0 | BYTE* HistoryBufferEnd = NULL; |
99 | 0 | UINT32 HistoryBufferSize = 0; |
100 | 0 | UINT32 CompressionLevel = 0; |
101 | 0 | wBitStream* bs = NULL; |
102 | |
|
103 | 0 | WINPR_ASSERT(mppc); |
104 | 0 | WINPR_ASSERT(pSrcData); |
105 | 0 | WINPR_ASSERT(ppDstData); |
106 | 0 | WINPR_ASSERT(pDstSize); |
107 | | |
108 | 0 | bs = mppc->bs; |
109 | 0 | WINPR_ASSERT(bs); |
110 | | |
111 | 0 | HistoryBuffer = mppc->HistoryBuffer; |
112 | 0 | WINPR_ASSERT(HistoryBuffer); |
113 | | |
114 | 0 | HistoryBufferSize = mppc->HistoryBufferSize; |
115 | 0 | HistoryBufferEnd = &HistoryBuffer[HistoryBufferSize - 1]; |
116 | 0 | CompressionLevel = mppc->CompressionLevel; |
117 | 0 | BitStream_Attach(bs, pSrcData, SrcSize); |
118 | 0 | BitStream_Fetch(bs); |
119 | |
|
120 | 0 | if (flags & PACKET_AT_FRONT) |
121 | 0 | { |
122 | 0 | mppc->HistoryOffset = 0; |
123 | 0 | mppc->HistoryPtr = HistoryBuffer; |
124 | 0 | } |
125 | |
|
126 | 0 | if (flags & PACKET_FLUSHED) |
127 | 0 | { |
128 | 0 | mppc->HistoryOffset = 0; |
129 | 0 | mppc->HistoryPtr = HistoryBuffer; |
130 | 0 | ZeroMemory(HistoryBuffer, mppc->HistoryBufferSize); |
131 | 0 | } |
132 | |
|
133 | 0 | HistoryPtr = mppc->HistoryPtr; |
134 | |
|
135 | 0 | if (!(flags & PACKET_COMPRESSED)) |
136 | 0 | { |
137 | 0 | *pDstSize = SrcSize; |
138 | 0 | *ppDstData = pSrcData; |
139 | 0 | return 1; |
140 | 0 | } |
141 | | |
142 | 0 | while ((bs->length - bs->position) >= 8) |
143 | 0 | { |
144 | 0 | accumulator = bs->accumulator; |
145 | | |
146 | | /** |
147 | | * Literal Encoding |
148 | | */ |
149 | |
|
150 | 0 | if (HistoryPtr > HistoryBufferEnd) |
151 | 0 | { |
152 | 0 | WLog_ERR(TAG, "history buffer index out of range"); |
153 | 0 | return -1004; |
154 | 0 | } |
155 | | |
156 | 0 | if ((accumulator & 0x80000000) == 0x00000000) |
157 | 0 | { |
158 | | /** |
159 | | * Literal, less than 0x80 |
160 | | * bit 0 followed by the lower 7 bits of the literal |
161 | | */ |
162 | 0 | Literal = ((accumulator & 0x7F000000) >> 24); |
163 | 0 | *(HistoryPtr) = Literal; |
164 | 0 | HistoryPtr++; |
165 | 0 | BitStream_Shift(bs, 8); |
166 | 0 | continue; |
167 | 0 | } |
168 | 0 | else if ((accumulator & 0xC0000000) == 0x80000000) |
169 | 0 | { |
170 | | /** |
171 | | * Literal, greater than 0x7F |
172 | | * bits 10 followed by the lower 7 bits of the literal |
173 | | */ |
174 | 0 | Literal = ((accumulator & 0x3F800000) >> 23) + 0x80; |
175 | 0 | *(HistoryPtr) = Literal; |
176 | 0 | HistoryPtr++; |
177 | 0 | BitStream_Shift(bs, 9); |
178 | 0 | continue; |
179 | 0 | } |
180 | | |
181 | | /** |
182 | | * CopyOffset Encoding |
183 | | */ |
184 | 0 | if (CompressionLevel) /* RDP5 */ |
185 | 0 | { |
186 | 0 | if ((accumulator & 0xF8000000) == 0xF8000000) |
187 | 0 | { |
188 | | /** |
189 | | * CopyOffset, range [0, 63] |
190 | | * bits 11111 + lower 6 bits of CopyOffset |
191 | | */ |
192 | 0 | CopyOffset = ((accumulator >> 21) & 0x3F); |
193 | 0 | BitStream_Shift(bs, 11); |
194 | 0 | } |
195 | 0 | else if ((accumulator & 0xF8000000) == 0xF0000000) |
196 | 0 | { |
197 | | /** |
198 | | * CopyOffset, range [64, 319] |
199 | | * bits 11110 + lower 8 bits of (CopyOffset - 64) |
200 | | */ |
201 | 0 | CopyOffset = ((accumulator >> 19) & 0xFF) + 64; |
202 | 0 | BitStream_Shift(bs, 13); |
203 | 0 | } |
204 | 0 | else if ((accumulator & 0xF0000000) == 0xE0000000) |
205 | 0 | { |
206 | | /** |
207 | | * CopyOffset, range [320, 2367] |
208 | | * bits 1110 + lower 11 bits of (CopyOffset - 320) |
209 | | */ |
210 | 0 | CopyOffset = ((accumulator >> 17) & 0x7FF) + 320; |
211 | 0 | BitStream_Shift(bs, 15); |
212 | 0 | } |
213 | 0 | else if ((accumulator & 0xE0000000) == 0xC0000000) |
214 | 0 | { |
215 | | /** |
216 | | * CopyOffset, range [2368, ] |
217 | | * bits 110 + lower 16 bits of (CopyOffset - 2368) |
218 | | */ |
219 | 0 | CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368; |
220 | 0 | BitStream_Shift(bs, 19); |
221 | 0 | } |
222 | 0 | else |
223 | 0 | { |
224 | | /* Invalid CopyOffset Encoding */ |
225 | 0 | return -1001; |
226 | 0 | } |
227 | 0 | } |
228 | 0 | else /* RDP4 */ |
229 | 0 | { |
230 | 0 | if ((accumulator & 0xF0000000) == 0xF0000000) |
231 | 0 | { |
232 | | /** |
233 | | * CopyOffset, range [0, 63] |
234 | | * bits 1111 + lower 6 bits of CopyOffset |
235 | | */ |
236 | 0 | CopyOffset = ((accumulator >> 22) & 0x3F); |
237 | 0 | BitStream_Shift(bs, 10); |
238 | 0 | } |
239 | 0 | else if ((accumulator & 0xF0000000) == 0xE0000000) |
240 | 0 | { |
241 | | /** |
242 | | * CopyOffset, range [64, 319] |
243 | | * bits 1110 + lower 8 bits of (CopyOffset - 64) |
244 | | */ |
245 | 0 | CopyOffset = ((accumulator >> 20) & 0xFF) + 64; |
246 | 0 | BitStream_Shift(bs, 12); |
247 | 0 | } |
248 | 0 | else if ((accumulator & 0xE0000000) == 0xC0000000) |
249 | 0 | { |
250 | | /** |
251 | | * CopyOffset, range [320, 8191] |
252 | | * bits 110 + lower 13 bits of (CopyOffset - 320) |
253 | | */ |
254 | 0 | CopyOffset = ((accumulator >> 16) & 0x1FFF) + 320; |
255 | 0 | BitStream_Shift(bs, 16); |
256 | 0 | } |
257 | 0 | else |
258 | 0 | { |
259 | | /* Invalid CopyOffset Encoding */ |
260 | 0 | return -1002; |
261 | 0 | } |
262 | 0 | } |
263 | | |
264 | | /** |
265 | | * LengthOfMatch Encoding |
266 | | */ |
267 | 0 | accumulator = bs->accumulator; |
268 | |
|
269 | 0 | if ((accumulator & 0x80000000) == 0x00000000) |
270 | 0 | { |
271 | | /** |
272 | | * LengthOfMatch [3] |
273 | | * bit 0 + 0 lower bits of LengthOfMatch |
274 | | */ |
275 | 0 | LengthOfMatch = 3; |
276 | 0 | BitStream_Shift(bs, 1); |
277 | 0 | } |
278 | 0 | else if ((accumulator & 0xC0000000) == 0x80000000) |
279 | 0 | { |
280 | | /** |
281 | | * LengthOfMatch [4, 7] |
282 | | * bits 10 + 2 lower bits of LengthOfMatch |
283 | | */ |
284 | 0 | LengthOfMatch = ((accumulator >> 28) & 0x0003) + 0x0004; |
285 | 0 | BitStream_Shift(bs, 4); |
286 | 0 | } |
287 | 0 | else if ((accumulator & 0xE0000000) == 0xC0000000) |
288 | 0 | { |
289 | | /** |
290 | | * LengthOfMatch [8, 15] |
291 | | * bits 110 + 3 lower bits of LengthOfMatch |
292 | | */ |
293 | 0 | LengthOfMatch = ((accumulator >> 26) & 0x0007) + 0x0008; |
294 | 0 | BitStream_Shift(bs, 6); |
295 | 0 | } |
296 | 0 | else if ((accumulator & 0xF0000000) == 0xE0000000) |
297 | 0 | { |
298 | | /** |
299 | | * LengthOfMatch [16, 31] |
300 | | * bits 1110 + 4 lower bits of LengthOfMatch |
301 | | */ |
302 | 0 | LengthOfMatch = ((accumulator >> 24) & 0x000F) + 0x0010; |
303 | 0 | BitStream_Shift(bs, 8); |
304 | 0 | } |
305 | 0 | else if ((accumulator & 0xF8000000) == 0xF0000000) |
306 | 0 | { |
307 | | /** |
308 | | * LengthOfMatch [32, 63] |
309 | | * bits 11110 + 5 lower bits of LengthOfMatch |
310 | | */ |
311 | 0 | LengthOfMatch = ((accumulator >> 22) & 0x001F) + 0x0020; |
312 | 0 | BitStream_Shift(bs, 10); |
313 | 0 | } |
314 | 0 | else if ((accumulator & 0xFC000000) == 0xF8000000) |
315 | 0 | { |
316 | | /** |
317 | | * LengthOfMatch [64, 127] |
318 | | * bits 111110 + 6 lower bits of LengthOfMatch |
319 | | */ |
320 | 0 | LengthOfMatch = ((accumulator >> 20) & 0x003F) + 0x0040; |
321 | 0 | BitStream_Shift(bs, 12); |
322 | 0 | } |
323 | 0 | else if ((accumulator & 0xFE000000) == 0xFC000000) |
324 | 0 | { |
325 | | /** |
326 | | * LengthOfMatch [128, 255] |
327 | | * bits 1111110 + 7 lower bits of LengthOfMatch |
328 | | */ |
329 | 0 | LengthOfMatch = ((accumulator >> 18) & 0x007F) + 0x0080; |
330 | 0 | BitStream_Shift(bs, 14); |
331 | 0 | } |
332 | 0 | else if ((accumulator & 0xFF000000) == 0xFE000000) |
333 | 0 | { |
334 | | /** |
335 | | * LengthOfMatch [256, 511] |
336 | | * bits 11111110 + 8 lower bits of LengthOfMatch |
337 | | */ |
338 | 0 | LengthOfMatch = ((accumulator >> 16) & 0x00FF) + 0x0100; |
339 | 0 | BitStream_Shift(bs, 16); |
340 | 0 | } |
341 | 0 | else if ((accumulator & 0xFF800000) == 0xFF000000) |
342 | 0 | { |
343 | | /** |
344 | | * LengthOfMatch [512, 1023] |
345 | | * bits 111111110 + 9 lower bits of LengthOfMatch |
346 | | */ |
347 | 0 | LengthOfMatch = ((accumulator >> 14) & 0x01FF) + 0x0200; |
348 | 0 | BitStream_Shift(bs, 18); |
349 | 0 | } |
350 | 0 | else if ((accumulator & 0xFFC00000) == 0xFF800000) |
351 | 0 | { |
352 | | /** |
353 | | * LengthOfMatch [1024, 2047] |
354 | | * bits 1111111110 + 10 lower bits of LengthOfMatch |
355 | | */ |
356 | 0 | LengthOfMatch = ((accumulator >> 12) & 0x03FF) + 0x0400; |
357 | 0 | BitStream_Shift(bs, 20); |
358 | 0 | } |
359 | 0 | else if ((accumulator & 0xFFE00000) == 0xFFC00000) |
360 | 0 | { |
361 | | /** |
362 | | * LengthOfMatch [2048, 4095] |
363 | | * bits 11111111110 + 11 lower bits of LengthOfMatch |
364 | | */ |
365 | 0 | LengthOfMatch = ((accumulator >> 10) & 0x07FF) + 0x0800; |
366 | 0 | BitStream_Shift(bs, 22); |
367 | 0 | } |
368 | 0 | else if ((accumulator & 0xFFF00000) == 0xFFE00000) |
369 | 0 | { |
370 | | /** |
371 | | * LengthOfMatch [4096, 8191] |
372 | | * bits 111111111110 + 12 lower bits of LengthOfMatch |
373 | | */ |
374 | 0 | LengthOfMatch = ((accumulator >> 8) & 0x0FFF) + 0x1000; |
375 | 0 | BitStream_Shift(bs, 24); |
376 | 0 | } |
377 | 0 | else if (((accumulator & 0xFFF80000) == 0xFFF00000) && CompressionLevel) /* RDP5 */ |
378 | 0 | { |
379 | | /** |
380 | | * LengthOfMatch [8192, 16383] |
381 | | * bits 1111111111110 + 13 lower bits of LengthOfMatch |
382 | | */ |
383 | 0 | LengthOfMatch = ((accumulator >> 6) & 0x1FFF) + 0x2000; |
384 | 0 | BitStream_Shift(bs, 26); |
385 | 0 | } |
386 | 0 | else if (((accumulator & 0xFFFC0000) == 0xFFF80000) && CompressionLevel) /* RDP5 */ |
387 | 0 | { |
388 | | /** |
389 | | * LengthOfMatch [16384, 32767] |
390 | | * bits 11111111111110 + 14 lower bits of LengthOfMatch |
391 | | */ |
392 | 0 | LengthOfMatch = ((accumulator >> 4) & 0x3FFF) + 0x4000; |
393 | 0 | BitStream_Shift(bs, 28); |
394 | 0 | } |
395 | 0 | else if (((accumulator & 0xFFFE0000) == 0xFFFC0000) && CompressionLevel) /* RDP5 */ |
396 | 0 | { |
397 | | /** |
398 | | * LengthOfMatch [32768, 65535] |
399 | | * bits 111111111111110 + 15 lower bits of LengthOfMatch |
400 | | */ |
401 | 0 | LengthOfMatch = ((accumulator >> 2) & 0x7FFF) + 0x8000; |
402 | 0 | BitStream_Shift(bs, 30); |
403 | 0 | } |
404 | 0 | else |
405 | 0 | { |
406 | | /* Invalid LengthOfMatch Encoding */ |
407 | 0 | return -1003; |
408 | 0 | } |
409 | | |
410 | | #if defined(DEBUG_MPPC) |
411 | | WLog_DBG(TAG, "<%" PRIu32 ",%" PRIu32 ">", CopyOffset, LengthOfMatch); |
412 | | #endif |
413 | | |
414 | 0 | if ((HistoryPtr + LengthOfMatch - 1) > HistoryBufferEnd) |
415 | 0 | { |
416 | 0 | WLog_ERR(TAG, "history buffer overflow"); |
417 | 0 | return -1005; |
418 | 0 | } |
419 | | |
420 | 0 | SrcPtr = &HistoryBuffer[(HistoryPtr - HistoryBuffer - CopyOffset) & |
421 | 0 | (CompressionLevel ? 0xFFFF : 0x1FFF)]; |
422 | |
|
423 | 0 | do |
424 | 0 | { |
425 | 0 | *HistoryPtr++ = *SrcPtr++; |
426 | 0 | } while (--LengthOfMatch); |
427 | 0 | } |
428 | | |
429 | 0 | *pDstSize = (UINT32)(HistoryPtr - mppc->HistoryPtr); |
430 | 0 | *ppDstData = mppc->HistoryPtr; |
431 | 0 | mppc->HistoryPtr = HistoryPtr; |
432 | 0 | return 1; |
433 | 0 | } |
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 | const intptr_t diff = HistoryPtr - HistoryBuffer; |
778 | 0 | if (diff > UINT32_MAX) |
779 | 0 | return -1; |
780 | 0 | mppc->HistoryOffset = (UINT32)diff; |
781 | 0 | return 1; |
782 | 0 | } |
783 | | |
784 | | void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel) |
785 | 0 | { |
786 | 0 | WINPR_ASSERT(mppc); |
787 | | |
788 | 0 | if (CompressionLevel < 1) |
789 | 0 | { |
790 | 0 | mppc->CompressionLevel = 0; |
791 | 0 | mppc->HistoryBufferSize = 8192; |
792 | 0 | } |
793 | 0 | else |
794 | 0 | { |
795 | 0 | mppc->CompressionLevel = 1; |
796 | 0 | mppc->HistoryBufferSize = 65536; |
797 | 0 | } |
798 | 0 | } |
799 | | |
800 | | void mppc_context_reset(MPPC_CONTEXT* mppc, BOOL flush) |
801 | 0 | { |
802 | 0 | WINPR_ASSERT(mppc); |
803 | | |
804 | 0 | ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer)); |
805 | 0 | ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer)); |
806 | |
|
807 | 0 | if (flush) |
808 | 0 | { |
809 | 0 | mppc->HistoryOffset = mppc->HistoryBufferSize + 1; |
810 | 0 | mppc->HistoryPtr = mppc->HistoryBuffer; |
811 | 0 | } |
812 | 0 | else |
813 | 0 | { |
814 | 0 | mppc->HistoryOffset = 0; |
815 | 0 | mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]); |
816 | 0 | } |
817 | 0 | } |
818 | | |
819 | | MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor) |
820 | 0 | { |
821 | 0 | MPPC_CONTEXT* mppc = calloc(1, sizeof(MPPC_CONTEXT)); |
822 | |
|
823 | 0 | if (!mppc) |
824 | 0 | goto fail; |
825 | | |
826 | 0 | mppc->Compressor = Compressor; |
827 | |
|
828 | 0 | if (CompressionLevel < 1) |
829 | 0 | { |
830 | 0 | mppc->CompressionLevel = 0; |
831 | 0 | mppc->HistoryBufferSize = 8192; |
832 | 0 | } |
833 | 0 | else |
834 | 0 | { |
835 | 0 | mppc->CompressionLevel = 1; |
836 | 0 | mppc->HistoryBufferSize = 65536; |
837 | 0 | } |
838 | |
|
839 | 0 | mppc->bs = BitStream_New(); |
840 | |
|
841 | 0 | if (!mppc->bs) |
842 | 0 | goto fail; |
843 | | |
844 | 0 | mppc_context_reset(mppc, FALSE); |
845 | |
|
846 | 0 | return mppc; |
847 | | |
848 | 0 | fail: |
849 | 0 | mppc_context_free(mppc); |
850 | 0 | return NULL; |
851 | 0 | } |
852 | | |
853 | | void mppc_context_free(MPPC_CONTEXT* mppc) |
854 | 0 | { |
855 | 0 | if (mppc) |
856 | 0 | { |
857 | 0 | BitStream_Free(mppc->bs); |
858 | 0 | free(mppc); |
859 | 0 | } |
860 | 0 | } |