21 #include <winpr/assert.h>
23 #include <freerdp/config.h>
25 #include "../core/settings.h"
27 #include "../codec/mppc.h"
28 #include "../codec/ncrush.h"
29 #include "../codec/xcrush.h"
31 #include <freerdp/log.h>
32 #define TAG FREERDP_TAG("core")
38 ALIGN64 rdpContext* context;
39 ALIGN64 UINT32 CompressionLevel;
40 ALIGN64 UINT32 CompressionMaxSize;
41 ALIGN64 MPPC_CONTEXT* mppcSend;
42 ALIGN64 MPPC_CONTEXT* mppcRecv;
43 ALIGN64 NCRUSH_CONTEXT* ncrushRecv;
44 ALIGN64 NCRUSH_CONTEXT* ncrushSend;
45 ALIGN64 XCRUSH_CONTEXT* xcrushRecv;
46 ALIGN64 XCRUSH_CONTEXT* xcrushSend;
47 ALIGN64 BYTE OutputBuffer[65536];
50 #if defined(WITH_BULK_DEBUG)
51 static INLINE
const char* bulk_get_compression_flags_string(UINT32 flags)
53 flags &= BULK_COMPRESSION_FLAGS_MASK;
56 return "PACKET_UNCOMPRESSED";
57 else if (flags == PACKET_COMPRESSED)
58 return "PACKET_COMPRESSED";
59 else if (flags == PACKET_AT_FRONT)
60 return "PACKET_AT_FRONT";
61 else if (flags == PACKET_FLUSHED)
62 return "PACKET_FLUSHED";
63 else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT))
64 return "PACKET_COMPRESSED | PACKET_AT_FRONT";
65 else if (flags == (PACKET_COMPRESSED | PACKET_FLUSHED))
66 return "PACKET_COMPRESSED | PACKET_FLUSHED";
67 else if (flags == (PACKET_AT_FRONT | PACKET_FLUSHED))
68 return "PACKET_AT_FRONT | PACKET_FLUSHED";
69 else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED))
70 return "PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED";
72 return "PACKET_UNKNOWN";
76 static UINT32 bulk_compression_level(rdpBulk* WINPR_RESTRICT bulk)
78 rdpSettings* settings = NULL;
80 WINPR_ASSERT(bulk->context);
81 settings = bulk->context->settings;
82 WINPR_ASSERT(settings);
83 bulk->CompressionLevel = (settings->CompressionLevel >= PACKET_COMPR_TYPE_RDP61)
84 ? PACKET_COMPR_TYPE_RDP61
85 : settings->CompressionLevel;
86 return bulk->CompressionLevel;
89 UINT32 bulk_compression_max_size(rdpBulk* WINPR_RESTRICT bulk)
92 bulk_compression_level(bulk);
93 bulk->CompressionMaxSize = (bulk->CompressionLevel < PACKET_COMPR_TYPE_64K) ? 8192 : 65536;
94 return bulk->CompressionMaxSize;
97 #if defined(WITH_BULK_DEBUG)
98 static INLINE
int bulk_compress_validate(rdpBulk* bulk,
const BYTE* pSrcData, UINT32 SrcSize,
99 const BYTE* pDstData, UINT32 DstSize, UINT32 Flags)
102 const BYTE* v_pSrcData = NULL;
103 const BYTE* v_pDstData = NULL;
104 UINT32 v_SrcSize = 0;
105 UINT32 v_DstSize = 0;
109 WINPR_ASSERT(pSrcData);
110 WINPR_ASSERT(pDstData);
112 v_pSrcData = pDstData;
114 v_Flags = Flags | bulk->CompressionLevel;
115 status = bulk_decompress(bulk, v_pSrcData, v_SrcSize, &v_pDstData, &v_DstSize, v_Flags);
119 WLog_DBG(TAG,
"compression/decompression failure");
123 if (v_DstSize != SrcSize)
126 "compression/decompression size mismatch: Actual: %" PRIu32
", Expected: %" PRIu32
132 if (memcmp(v_pDstData, pSrcData, SrcSize) != 0)
134 WLog_DBG(TAG,
"compression/decompression input/output mismatch! flags: 0x%08" PRIX32
"",
137 WLog_DBG(TAG,
"Actual:");
138 winpr_HexDump(TAG, WLOG_DEBUG, v_pDstData, SrcSize);
139 WLog_DBG(TAG,
"Expected:");
140 winpr_HexDump(TAG, WLOG_DEBUG, pSrcData, SrcSize);
149 int bulk_decompress(rdpBulk* WINPR_RESTRICT bulk,
const BYTE* WINPR_RESTRICT pSrcData,
150 UINT32 SrcSize,
const BYTE** WINPR_RESTRICT ppDstData,
151 UINT32* WINPR_RESTRICT pDstSize, UINT32 flags)
156 WINPR_ASSERT(bulk->context);
157 WINPR_ASSERT(pSrcData);
158 WINPR_ASSERT(ppDstData);
159 WINPR_ASSERT(pDstSize);
161 rdpMetrics* metrics = bulk->context->metrics;
162 WINPR_ASSERT(metrics);
164 bulk_compression_max_size(bulk);
165 const UINT32 type = flags & BULK_COMPRESSION_TYPE_MASK;
167 if (flags & BULK_COMPRESSION_FLAGS_MASK)
171 case PACKET_COMPR_TYPE_8K:
172 mppc_set_compression_level(bulk->mppcRecv, 0);
174 mppc_decompress(bulk->mppcRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags);
177 case PACKET_COMPR_TYPE_64K:
178 mppc_set_compression_level(bulk->mppcRecv, 1);
180 mppc_decompress(bulk->mppcRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags);
183 case PACKET_COMPR_TYPE_RDP6:
184 status = ncrush_decompress(bulk->ncrushRecv, pSrcData, SrcSize, ppDstData, pDstSize,
188 case PACKET_COMPR_TYPE_RDP61:
189 status = xcrush_decompress(bulk->xcrushRecv, pSrcData, SrcSize, ppDstData, pDstSize,
193 case PACKET_COMPR_TYPE_RDP8:
194 WLog_ERR(TAG,
"Unsupported bulk compression type %08" PRIx32,
195 bulk->CompressionLevel);
199 WLog_ERR(TAG,
"Unknown bulk compression type %08" PRIx32, bulk->CompressionLevel);
206 *ppDstData = pSrcData;
213 const UINT32 CompressedBytes = SrcSize;
214 const UINT32 UncompressedBytes = *pDstSize;
215 const double CompressionRatio =
216 metrics_write_bytes(metrics, UncompressedBytes, CompressedBytes);
217 #ifdef WITH_BULK_DEBUG
220 "Decompress Type: %" PRIu32
" Flags: %s (0x%08" PRIX32
221 ") Compression Ratio: %f (%" PRIu32
" / %" PRIu32
"), Total: %f (%" PRIu64
223 type, bulk_get_compression_flags_string(flags), flags, CompressionRatio,
224 CompressedBytes, UncompressedBytes, metrics->TotalCompressionRatio,
225 metrics->TotalCompressedBytes, metrics->TotalUncompressedBytes);
228 WINPR_UNUSED(CompressionRatio);
233 WLog_ERR(TAG,
"Decompression failure!");
239 int bulk_compress(rdpBulk* WINPR_RESTRICT bulk,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
240 const BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize,
241 UINT32* WINPR_RESTRICT pFlags)
246 WINPR_ASSERT(bulk->context);
247 WINPR_ASSERT(pSrcData);
248 WINPR_ASSERT(ppDstData);
249 WINPR_ASSERT(pDstSize);
251 rdpMetrics* metrics = bulk->context->metrics;
252 WINPR_ASSERT(metrics);
254 if ((SrcSize <= 50) || (SrcSize >= 16384))
256 *ppDstData = pSrcData;
261 *pDstSize =
sizeof(bulk->OutputBuffer);
262 bulk_compression_level(bulk);
263 bulk_compression_max_size(bulk);
265 switch (bulk->CompressionLevel)
267 case PACKET_COMPR_TYPE_8K:
268 case PACKET_COMPR_TYPE_64K:
269 mppc_set_compression_level(bulk->mppcSend, bulk->CompressionLevel);
270 status = mppc_compress(bulk->mppcSend, pSrcData, SrcSize, bulk->OutputBuffer, ppDstData,
273 case PACKET_COMPR_TYPE_RDP6:
274 status = ncrush_compress(bulk->ncrushSend, pSrcData, SrcSize, bulk->OutputBuffer,
275 ppDstData, pDstSize, pFlags);
277 case PACKET_COMPR_TYPE_RDP61:
278 status = xcrush_compress(bulk->xcrushSend, pSrcData, SrcSize, bulk->OutputBuffer,
279 ppDstData, pDstSize, pFlags);
281 case PACKET_COMPR_TYPE_RDP8:
282 WLog_ERR(TAG,
"Unsupported bulk compression type %08" PRIx32, bulk->CompressionLevel);
286 WLog_ERR(TAG,
"Unknown bulk compression type %08" PRIx32, bulk->CompressionLevel);
293 const UINT32 CompressedBytes = *pDstSize;
294 const UINT32 UncompressedBytes = SrcSize;
295 const double CompressionRatio =
296 metrics_write_bytes(metrics, UncompressedBytes, CompressedBytes);
297 #ifdef WITH_BULK_DEBUG
300 "Compress Type: %" PRIu32
" Flags: %s (0x%08" PRIX32
301 ") Compression Ratio: %f (%" PRIu32
" / %" PRIu32
"), Total: %f (%" PRIu64
303 bulk->CompressionLevel, bulk_get_compression_flags_string(*pFlags), *pFlags,
304 CompressionRatio, CompressedBytes, UncompressedBytes,
305 metrics->TotalCompressionRatio, metrics->TotalCompressedBytes,
306 metrics->TotalUncompressedBytes);
309 WINPR_UNUSED(CompressionRatio);
313 #if defined(WITH_BULK_DEBUG)
315 if (bulk_compress_validate(bulk, pSrcData, SrcSize, *ppDstData, *pDstSize, *pFlags) < 0)
322 void bulk_reset(rdpBulk* WINPR_RESTRICT bulk)
326 mppc_context_reset(bulk->mppcSend, FALSE);
327 mppc_context_reset(bulk->mppcRecv, FALSE);
328 ncrush_context_reset(bulk->ncrushRecv, FALSE);
329 ncrush_context_reset(bulk->ncrushSend, FALSE);
330 xcrush_context_reset(bulk->xcrushRecv, FALSE);
331 xcrush_context_reset(bulk->xcrushSend, FALSE);
334 rdpBulk* bulk_new(rdpContext* context)
336 rdpBulk* bulk = NULL;
337 WINPR_ASSERT(context);
339 bulk = (rdpBulk*)calloc(1,
sizeof(rdpBulk));
344 bulk->context = context;
345 bulk->mppcSend = mppc_context_new(1, TRUE);
348 bulk->mppcRecv = mppc_context_new(1, FALSE);
351 bulk->ncrushRecv = ncrush_context_new(FALSE);
352 if (!bulk->ncrushRecv)
354 bulk->ncrushSend = ncrush_context_new(TRUE);
355 if (!bulk->ncrushSend)
357 bulk->xcrushRecv = xcrush_context_new(FALSE);
358 if (!bulk->xcrushRecv)
360 bulk->xcrushSend = xcrush_context_new(TRUE);
361 if (!bulk->xcrushSend)
363 bulk->CompressionLevel = context->settings->CompressionLevel;
367 WINPR_PRAGMA_DIAG_PUSH
368 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
370 WINPR_PRAGMA_DIAG_POP
374 void bulk_free(rdpBulk* bulk)
379 mppc_context_free(bulk->mppcSend);
380 mppc_context_free(bulk->mppcRecv);
381 ncrush_context_free(bulk->ncrushRecv);
382 ncrush_context_free(bulk->ncrushSend);
383 xcrush_context_free(bulk->xcrushRecv);
384 xcrush_context_free(bulk->xcrushSend);