22 #include <freerdp/config.h>
24 #include <winpr/assert.h>
25 #include <winpr/cast.h>
26 #include <winpr/crt.h>
27 #include <winpr/print.h>
28 #include <winpr/bitstream.h>
30 #include <freerdp/log.h>
31 #include <freerdp/codec/zgfx.h>
33 #define TAG FREERDP_TAG("codec")
58 const BYTE* pbInputCurrent;
59 const BYTE* pbInputEnd;
62 UINT32 cBitsRemaining;
66 BYTE OutputBuffer[65536];
69 BYTE HistoryBuffer[2500000];
71 UINT32 HistoryBufferSize;
74 static const ZGFX_TOKEN ZGFX_TOKEN_TABLE[] = {
80 { 5, 20, 10, 1, 672 },
81 { 5, 21, 12, 1, 1696 },
82 { 5, 24, 0, 0, 0x00 },
83 { 5, 25, 0, 0, 0x01 },
84 { 6, 44, 14, 1, 5792 },
85 { 6, 45, 15, 1, 22176 },
86 { 6, 52, 0, 0, 0x02 },
87 { 6, 53, 0, 0, 0x03 },
88 { 6, 54, 0, 0, 0xFF },
89 { 7, 92, 18, 1, 54944 },
90 { 7, 93, 20, 1, 317088 },
91 { 7, 110, 0, 0, 0x04 },
92 { 7, 111, 0, 0, 0x05 },
93 { 7, 112, 0, 0, 0x06 },
94 { 7, 113, 0, 0, 0x07 },
95 { 7, 114, 0, 0, 0x08 },
96 { 7, 115, 0, 0, 0x09 },
97 { 7, 116, 0, 0, 0x0A },
98 { 7, 117, 0, 0, 0x0B },
99 { 7, 118, 0, 0, 0x3A },
100 { 7, 119, 0, 0, 0x3B },
101 { 7, 120, 0, 0, 0x3C },
102 { 7, 121, 0, 0, 0x3D },
103 { 7, 122, 0, 0, 0x3E },
104 { 7, 123, 0, 0, 0x3F },
105 { 7, 124, 0, 0, 0x40 },
106 { 7, 125, 0, 0, 0x80 },
107 { 8, 188, 20, 1, 1365664 },
108 { 8, 189, 21, 1, 2414240 },
109 { 8, 252, 0, 0, 0x0C },
110 { 8, 253, 0, 0, 0x38 },
111 { 8, 254, 0, 0, 0x39 },
112 { 8, 255, 0, 0, 0x66 },
113 { 9, 380, 22, 1, 4511392 },
114 { 9, 381, 23, 1, 8705696 },
115 { 9, 382, 24, 1, 17094304 },
119 static INLINE BOOL zgfx_GetBits(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, UINT32 nbits)
124 while (zgfx->cBitsCurrent < nbits)
126 zgfx->BitsCurrent <<= 8;
128 if (zgfx->pbInputCurrent < zgfx->pbInputEnd)
129 zgfx->BitsCurrent += *(zgfx->pbInputCurrent)++;
131 zgfx->cBitsCurrent += 8;
134 zgfx->cBitsRemaining -= nbits;
135 zgfx->cBitsCurrent -= nbits;
136 zgfx->bits = zgfx->BitsCurrent >> zgfx->cBitsCurrent;
137 zgfx->BitsCurrent &= ((1 << zgfx->cBitsCurrent) - 1);
141 static INLINE
void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
142 const BYTE* WINPR_RESTRICT src,
size_t count)
147 if (count > zgfx->HistoryBufferSize)
149 const size_t residue = count - zgfx->HistoryBufferSize;
150 count = zgfx->HistoryBufferSize;
152 zgfx->HistoryIndex = (zgfx->HistoryIndex + residue) % zgfx->HistoryBufferSize;
155 if (zgfx->HistoryIndex + count <= zgfx->HistoryBufferSize)
157 CopyMemory(&(zgfx->HistoryBuffer[zgfx->HistoryIndex]), src, count);
159 if ((zgfx->HistoryIndex += count) == zgfx->HistoryBufferSize)
160 zgfx->HistoryIndex = 0;
164 const UINT32 front = zgfx->HistoryBufferSize - zgfx->HistoryIndex;
165 CopyMemory(&(zgfx->HistoryBuffer[zgfx->HistoryIndex]), src, front);
166 CopyMemory(zgfx->HistoryBuffer, &src[front], count - front);
167 zgfx->HistoryIndex = (UINT32)(count - front);
171 static INLINE
void zgfx_history_buffer_ring_read(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
int offset,
172 BYTE* WINPR_RESTRICT dst, UINT32 count)
182 if ((count <= 0) || (count > INT32_MAX))
185 bytesLeft = (INT32)count;
186 index = (zgfx->HistoryIndex + zgfx->HistoryBufferSize -
187 WINPR_ASSERTING_INT_CAST(uint32_t, offset)) %
188 zgfx->HistoryBufferSize;
189 bytes = MIN(bytesLeft, offset);
191 if ((index + WINPR_ASSERTING_INT_CAST(uint32_t, bytes)) <= zgfx->HistoryBufferSize)
193 CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), WINPR_ASSERTING_INT_CAST(
size_t, bytes));
197 front = zgfx->HistoryBufferSize - index;
198 CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), front);
199 CopyMemory(&dptr[front], zgfx->HistoryBuffer,
200 WINPR_ASSERTING_INT_CAST(uint32_t, bytes) - front);
203 if ((bytesLeft -= bytes) == 0)
207 valid = WINPR_ASSERTING_INT_CAST(uint32_t, bytes);
211 bytes = WINPR_ASSERTING_INT_CAST(int32_t, valid);
213 if (bytes > bytesLeft)
216 CopyMemory(dptr, origDst, WINPR_ASSERTING_INT_CAST(
size_t, bytes));
219 }
while ((bytesLeft -= bytes) > 0);
222 static INLINE BOOL zgfx_decompress_segment(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
223 wStream* WINPR_RESTRICT stream,
size_t segmentSize)
233 BYTE* pbSegment = NULL;
236 WINPR_ASSERT(stream);
241 const size_t cbSegment = segmentSize - 1;
243 if (!Stream_CheckAndLogRequiredLength(TAG, stream, segmentSize) || (segmentSize > UINT32_MAX))
246 Stream_Read_UINT8(stream, flags);
247 zgfx->OutputCount = 0;
248 pbSegment = Stream_Pointer(stream);
249 if (!Stream_SafeSeek(stream, cbSegment))
252 if (!(flags & PACKET_COMPRESSED))
254 zgfx_history_buffer_ring_write(zgfx, pbSegment, cbSegment);
256 if (cbSegment >
sizeof(zgfx->OutputBuffer))
259 CopyMemory(zgfx->OutputBuffer, pbSegment, cbSegment);
260 zgfx->OutputCount = (UINT32)cbSegment;
264 zgfx->pbInputCurrent = pbSegment;
265 zgfx->pbInputEnd = &pbSegment[cbSegment - 1];
267 const size_t bits = 8u * (cbSegment - 1u);
268 if (bits > UINT32_MAX)
270 if (bits < *zgfx->pbInputEnd)
273 zgfx->cBitsRemaining = (UINT32)(bits - *zgfx->pbInputEnd);
274 zgfx->cBitsCurrent = 0;
275 zgfx->BitsCurrent = 0;
277 while (zgfx->cBitsRemaining)
282 for (opIndex = 0; ZGFX_TOKEN_TABLE[opIndex].prefixLength != 0; opIndex++)
284 while (haveBits < ZGFX_TOKEN_TABLE[opIndex].prefixLength)
286 zgfx_GetBits(zgfx, 1);
287 inPrefix = (inPrefix << 1) + zgfx->bits;
291 if (inPrefix == ZGFX_TOKEN_TABLE[opIndex].prefixCode)
293 if (ZGFX_TOKEN_TABLE[opIndex].tokenType == 0)
296 zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
297 c = (BYTE)(ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits);
298 zgfx->HistoryBuffer[zgfx->HistoryIndex] = c;
300 if (++zgfx->HistoryIndex == zgfx->HistoryBufferSize)
301 zgfx->HistoryIndex = 0;
303 if (zgfx->OutputCount >=
sizeof(zgfx->OutputBuffer))
306 zgfx->OutputBuffer[zgfx->OutputCount++] = c;
310 zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
311 distance = ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits;
316 zgfx_GetBits(zgfx, 1);
326 zgfx_GetBits(zgfx, 1);
328 while (zgfx->bits == 1)
332 zgfx_GetBits(zgfx, 1);
335 zgfx_GetBits(zgfx, extra);
339 if (count >
sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
342 zgfx_history_buffer_ring_read(zgfx, WINPR_ASSERTING_INT_CAST(
int, distance),
343 &(zgfx->OutputBuffer[zgfx->OutputCount]),
345 zgfx_history_buffer_ring_write(
346 zgfx, &(zgfx->OutputBuffer[zgfx->OutputCount]), count);
347 zgfx->OutputCount += count;
352 zgfx_GetBits(zgfx, 15);
354 zgfx->cBitsRemaining -= zgfx->cBitsCurrent;
355 zgfx->cBitsCurrent = 0;
356 zgfx->BitsCurrent = 0;
358 if (count >
sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
360 else if (count > zgfx->cBitsRemaining / 8)
362 else if (zgfx->pbInputCurrent + count > zgfx->pbInputEnd)
365 CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent,
367 zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count);
368 zgfx->pbInputCurrent += count;
369 zgfx->cBitsRemaining -= (8 * count);
370 zgfx->OutputCount += count;
388 static INLINE BYTE* aligned_zgfx_malloc(
size_t size)
390 return malloc(size + 64);
393 static INLINE BOOL zgfx_append(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
394 BYTE** WINPR_RESTRICT ppConcatenated,
size_t uncompressedSize,
395 size_t* WINPR_RESTRICT pUsed)
398 WINPR_ASSERT(ppConcatenated);
401 const size_t used = *pUsed;
402 if (zgfx->OutputCount > UINT32_MAX - used)
405 if (used + zgfx->OutputCount > uncompressedSize)
408 BYTE* tmp = realloc(*ppConcatenated, used + zgfx->OutputCount + 64ull);
411 *ppConcatenated = tmp;
412 CopyMemory(&tmp[used], zgfx->OutputBuffer, zgfx->OutputCount);
413 *pUsed = used + zgfx->OutputCount;
417 int zgfx_decompress(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
const BYTE* WINPR_RESTRICT pSrcData,
418 UINT32 SrcSize, BYTE** WINPR_RESTRICT ppDstData,
419 UINT32* WINPR_RESTRICT pDstSize, UINT32 flags)
425 BYTE* pConcatenated = NULL;
426 wStream* stream = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);
429 WINPR_ASSERT(stream);
430 WINPR_ASSERT(ppDstData);
431 WINPR_ASSERT(pDstSize);
436 if (!Stream_CheckAndLogRequiredLength(TAG, stream, 1))
439 Stream_Read_UINT8(stream, descriptor);
441 if (descriptor == ZGFX_SEGMENTED_SINGLE)
443 if (!zgfx_decompress_segment(zgfx, stream, Stream_GetRemainingLength(stream)))
446 if (zgfx->OutputCount > 0)
448 if (!zgfx_append(zgfx, &pConcatenated, zgfx->OutputCount, &used))
450 if (used != zgfx->OutputCount)
452 *ppDstData = pConcatenated;
453 *pDstSize = zgfx->OutputCount;
456 else if (descriptor == ZGFX_SEGMENTED_MULTIPART)
458 UINT32 segmentSize = 0;
459 UINT16 segmentNumber = 0;
460 UINT16 segmentCount = 0;
461 UINT32 uncompressedSize = 0;
463 if (!Stream_CheckAndLogRequiredLength(TAG, stream, 6))
466 Stream_Read_UINT16(stream, segmentCount);
467 Stream_Read_UINT32(stream, uncompressedSize);
469 for (segmentNumber = 0; segmentNumber < segmentCount; segmentNumber++)
471 if (!Stream_CheckAndLogRequiredLength(TAG, stream,
sizeof(UINT32)))
474 Stream_Read_UINT32(stream, segmentSize);
476 if (!zgfx_decompress_segment(zgfx, stream, segmentSize))
479 if (!zgfx_append(zgfx, &pConcatenated, uncompressedSize, &used))
483 if (used != uncompressedSize)
486 *ppDstData = pConcatenated;
487 *pDstSize = uncompressedSize;
501 static BOOL zgfx_compress_segment(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
wStream* WINPR_RESTRICT s,
502 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
503 UINT32* WINPR_RESTRICT pFlags)
506 if (!Stream_EnsureRemainingCapacity(s, SrcSize + 1))
508 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
512 (*pFlags) |= ZGFX_PACKET_COMPR_TYPE_RDP8;
513 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, *pFlags));
514 Stream_Write(s, pSrcData, SrcSize);
518 int zgfx_compress_to_stream(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
wStream* WINPR_RESTRICT sDst,
519 const BYTE* WINPR_RESTRICT pUncompressed, UINT32 uncompressedSize,
520 UINT32* WINPR_RESTRICT pFlags)
523 UINT16 maxLength = 0;
524 UINT32 totalLength = 0;
525 size_t posSegmentCount = 0;
526 const BYTE* pSrcData = NULL;
528 maxLength = ZGFX_SEGMENTED_MAXSIZE;
529 totalLength = uncompressedSize;
530 pSrcData = pUncompressed;
532 for (; (totalLength > 0) || (fragment == 0); fragment++)
534 size_t posDstSize = 0;
535 size_t posDataStart = 0;
537 const UINT32 SrcSize = (totalLength > maxLength) ? maxLength : totalLength;
539 totalLength -= SrcSize;
542 if (!Stream_EnsureRemainingCapacity(sDst, 12))
544 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
552 Stream_Write_UINT8(sDst, (totalLength == 0) ? ZGFX_SEGMENTED_SINGLE
553 : ZGFX_SEGMENTED_MULTIPART);
557 posSegmentCount = Stream_GetPosition(sDst);
558 Stream_Seek(sDst, 2);
559 Stream_Write_UINT32(sDst, uncompressedSize);
563 if (fragment > 0 || totalLength > 0)
566 posDstSize = Stream_GetPosition(sDst);
567 Stream_Seek(sDst, 4);
570 posDataStart = Stream_GetPosition(sDst);
572 if (!zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags))
578 const size_t DstSize = Stream_GetPosition(sDst) - posDataStart;
579 if (DstSize > UINT32_MAX)
581 Stream_SetPosition(sDst, posDstSize);
582 Stream_Write_UINT32(sDst, (UINT32)DstSize);
583 Stream_SetPosition(sDst, posDataStart + DstSize);
589 Stream_SealLength(sDst);
594 Stream_SetPosition(sDst, posSegmentCount);
595 Stream_Write_UINT16(sDst, WINPR_ASSERTING_INT_CAST(uint16_t, fragment));
596 Stream_SetPosition(sDst, Stream_Length(sDst));
602 int zgfx_compress(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
const BYTE* WINPR_RESTRICT pSrcData,
603 UINT32 SrcSize, BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize,
604 UINT32* WINPR_RESTRICT pFlags)
607 wStream* s = Stream_New(NULL, SrcSize);
608 status = zgfx_compress_to_stream(zgfx, s, pSrcData, SrcSize, pFlags);
609 const size_t pos = Stream_GetPosition(s);
610 if (pos > UINT32_MAX)
614 (*ppDstData) = Stream_Buffer(s);
615 (*pDstSize) = (UINT32)pos;
617 Stream_Free(s, FALSE);
621 void zgfx_context_reset(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, BOOL flush)
623 zgfx->HistoryIndex = 0;
626 ZGFX_CONTEXT* zgfx_context_new(BOOL Compressor)
628 ZGFX_CONTEXT* zgfx = NULL;
629 zgfx = (ZGFX_CONTEXT*)calloc(1,
sizeof(ZGFX_CONTEXT));
633 zgfx->Compressor = Compressor;
634 zgfx->HistoryBufferSize =
sizeof(zgfx->HistoryBuffer);
635 zgfx_context_reset(zgfx, FALSE);
641 void zgfx_context_free(ZGFX_CONTEXT* zgfx)