FreeRDP
Loading...
Searching...
No Matches
zgfx.c
1
22#include <freerdp/config.h>
23
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>
29
30#include <freerdp/log.h>
31#include <freerdp/codec/zgfx.h>
32
33#define TAG FREERDP_TAG("codec")
34
45typedef struct
46{
47 UINT32 prefixLength;
48 UINT32 prefixCode;
49 UINT32 valueBits;
50 UINT32 tokenType;
51 UINT32 valueBase;
52} ZGFX_TOKEN;
53
54struct S_ZGFX_CONTEXT
55{
56 BOOL Compressor;
57
58 const BYTE* pbInputCurrent;
59 const BYTE* pbInputEnd;
60
61 UINT32 bits;
62 UINT32 cBitsRemaining;
63 UINT32 BitsCurrent;
64 UINT32 cBitsCurrent;
65
66 BYTE OutputBuffer[65536];
67 UINT32 OutputCount;
68
69 BYTE HistoryBuffer[2500000];
70 UINT32 HistoryIndex;
71 UINT32 HistoryBufferSize;
72};
73
74static const ZGFX_TOKEN ZGFX_TOKEN_TABLE[] = {
75 // len code vbits type vbase
76 { 1, 0, 8, 0, 0 }, // 0
77 { 5, 17, 5, 1, 0 }, // 10001
78 { 5, 18, 7, 1, 32 }, // 10010
79 { 5, 19, 9, 1, 160 }, // 10011
80 { 5, 20, 10, 1, 672 }, // 10100
81 { 5, 21, 12, 1, 1696 }, // 10101
82 { 5, 24, 0, 0, 0x00 }, // 11000
83 { 5, 25, 0, 0, 0x01 }, // 11001
84 { 6, 44, 14, 1, 5792 }, // 101100
85 { 6, 45, 15, 1, 22176 }, // 101101
86 { 6, 52, 0, 0, 0x02 }, // 110100
87 { 6, 53, 0, 0, 0x03 }, // 110101
88 { 6, 54, 0, 0, 0xFF }, // 110110
89 { 7, 92, 18, 1, 54944 }, // 1011100
90 { 7, 93, 20, 1, 317088 }, // 1011101
91 { 7, 110, 0, 0, 0x04 }, // 1101110
92 { 7, 111, 0, 0, 0x05 }, // 1101111
93 { 7, 112, 0, 0, 0x06 }, // 1110000
94 { 7, 113, 0, 0, 0x07 }, // 1110001
95 { 7, 114, 0, 0, 0x08 }, // 1110010
96 { 7, 115, 0, 0, 0x09 }, // 1110011
97 { 7, 116, 0, 0, 0x0A }, // 1110100
98 { 7, 117, 0, 0, 0x0B }, // 1110101
99 { 7, 118, 0, 0, 0x3A }, // 1110110
100 { 7, 119, 0, 0, 0x3B }, // 1110111
101 { 7, 120, 0, 0, 0x3C }, // 1111000
102 { 7, 121, 0, 0, 0x3D }, // 1111001
103 { 7, 122, 0, 0, 0x3E }, // 1111010
104 { 7, 123, 0, 0, 0x3F }, // 1111011
105 { 7, 124, 0, 0, 0x40 }, // 1111100
106 { 7, 125, 0, 0, 0x80 }, // 1111101
107 { 8, 188, 20, 1, 1365664 }, // 10111100
108 { 8, 189, 21, 1, 2414240 }, // 10111101
109 { 8, 252, 0, 0, 0x0C }, // 11111100
110 { 8, 253, 0, 0, 0x38 }, // 11111101
111 { 8, 254, 0, 0, 0x39 }, // 11111110
112 { 8, 255, 0, 0, 0x66 }, // 11111111
113 { 9, 380, 22, 1, 4511392 }, // 101111100
114 { 9, 381, 23, 1, 8705696 }, // 101111101
115 { 9, 382, 24, 1, 17094304 }, // 101111110
116 { 0 }
117};
118
119static INLINE BOOL zgfx_GetBits(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, UINT32 nbits)
120{
121 if (!zgfx)
122 return FALSE;
123
124 while (zgfx->cBitsCurrent < nbits)
125 {
126 zgfx->BitsCurrent <<= 8;
127
128 if (zgfx->pbInputCurrent < zgfx->pbInputEnd)
129 zgfx->BitsCurrent += *(zgfx->pbInputCurrent)++;
130
131 zgfx->cBitsCurrent += 8;
132 }
133
134 zgfx->cBitsRemaining -= nbits;
135 zgfx->cBitsCurrent -= nbits;
136 zgfx->bits = zgfx->BitsCurrent >> zgfx->cBitsCurrent;
137 zgfx->BitsCurrent &= ((1 << zgfx->cBitsCurrent) - 1);
138 return TRUE;
139}
140
141static INLINE void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
142 const BYTE* WINPR_RESTRICT src, size_t count)
143{
144 if (count <= 0)
145 return;
146
147 if (count > zgfx->HistoryBufferSize)
148 {
149 const size_t residue = count - zgfx->HistoryBufferSize;
150 count = zgfx->HistoryBufferSize;
151 src += residue;
152 zgfx->HistoryIndex = (zgfx->HistoryIndex + residue) % zgfx->HistoryBufferSize;
153 }
154
155 if (zgfx->HistoryIndex + count <= zgfx->HistoryBufferSize)
156 {
157 CopyMemory(&(zgfx->HistoryBuffer[zgfx->HistoryIndex]), src, count);
158
159 zgfx->HistoryIndex += WINPR_ASSERTING_INT_CAST(uint32_t, count);
160 if (zgfx->HistoryIndex == zgfx->HistoryBufferSize)
161 zgfx->HistoryIndex = 0;
162 }
163 else
164 {
165 const UINT32 front = zgfx->HistoryBufferSize - zgfx->HistoryIndex;
166 CopyMemory(&(zgfx->HistoryBuffer[zgfx->HistoryIndex]), src, front);
167 CopyMemory(zgfx->HistoryBuffer, &src[front], count - front);
168 zgfx->HistoryIndex = (UINT32)(count - front);
169 }
170}
171
172static INLINE void zgfx_history_buffer_ring_read(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, int offset,
173 BYTE* WINPR_RESTRICT dst, UINT32 count)
174{
175 UINT32 front = 0;
176 UINT32 index = 0;
177 INT32 bytes = 0;
178 UINT32 valid = 0;
179 INT32 bytesLeft = 0;
180 BYTE* dptr = dst;
181 BYTE* origDst = dst;
182
183 if ((count <= 0) || (count > INT32_MAX))
184 return;
185
186 bytesLeft = (INT32)count;
187 index = (zgfx->HistoryIndex + zgfx->HistoryBufferSize -
188 WINPR_ASSERTING_INT_CAST(uint32_t, offset)) %
189 zgfx->HistoryBufferSize;
190 bytes = MIN(bytesLeft, offset);
191
192 if ((index + WINPR_ASSERTING_INT_CAST(uint32_t, bytes)) <= zgfx->HistoryBufferSize)
193 {
194 CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), WINPR_ASSERTING_INT_CAST(size_t, bytes));
195 }
196 else
197 {
198 front = zgfx->HistoryBufferSize - index;
199 CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), front);
200 CopyMemory(&dptr[front], zgfx->HistoryBuffer,
201 WINPR_ASSERTING_INT_CAST(uint32_t, bytes) - front);
202 }
203
204 if ((bytesLeft -= bytes) == 0)
205 return;
206
207 dptr += bytes;
208 valid = WINPR_ASSERTING_INT_CAST(uint32_t, bytes);
209
210 do
211 {
212 bytes = WINPR_ASSERTING_INT_CAST(int32_t, valid);
213
214 if (bytes > bytesLeft)
215 bytes = bytesLeft;
216
217 CopyMemory(dptr, origDst, WINPR_ASSERTING_INT_CAST(size_t, bytes));
218 dptr += bytes;
219 valid <<= 1;
220 } while ((bytesLeft -= bytes) > 0);
221}
222
223static INLINE BOOL zgfx_decompress_segment(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
224 wStream* WINPR_RESTRICT stream, size_t segmentSize)
225{
226 BYTE c = 0;
227 BYTE flags = 0;
228 UINT32 extra = 0;
229 int opIndex = 0;
230 UINT32 haveBits = 0;
231 UINT32 inPrefix = 0;
232 UINT32 count = 0;
233 UINT32 distance = 0;
234 BYTE* pbSegment = NULL;
235
236 WINPR_ASSERT(zgfx);
237 WINPR_ASSERT(stream);
238
239 if (segmentSize < 2)
240 return FALSE;
241
242 const size_t cbSegment = segmentSize - 1;
243
244 if (!Stream_CheckAndLogRequiredLength(TAG, stream, segmentSize) || (segmentSize > UINT32_MAX))
245 return FALSE;
246
247 Stream_Read_UINT8(stream, flags); /* header (1 byte) */
248 zgfx->OutputCount = 0;
249 pbSegment = Stream_Pointer(stream);
250 if (!Stream_SafeSeek(stream, cbSegment))
251 return FALSE;
252
253 if (!(flags & PACKET_COMPRESSED))
254 {
255 zgfx_history_buffer_ring_write(zgfx, pbSegment, cbSegment);
256
257 if (cbSegment > sizeof(zgfx->OutputBuffer))
258 return FALSE;
259
260 CopyMemory(zgfx->OutputBuffer, pbSegment, cbSegment);
261 zgfx->OutputCount = (UINT32)cbSegment;
262 return TRUE;
263 }
264
265 zgfx->pbInputCurrent = pbSegment;
266 zgfx->pbInputEnd = &pbSegment[cbSegment - 1];
267 /* NumberOfBitsToDecode = ((NumberOfBytesToDecode - 1) * 8) - ValueOfLastByte */
268 const size_t bits = 8u * (cbSegment - 1u);
269 if (bits > UINT32_MAX)
270 return FALSE;
271 if (bits < *zgfx->pbInputEnd)
272 return FALSE;
273
274 zgfx->cBitsRemaining = (UINT32)(bits - *zgfx->pbInputEnd);
275 zgfx->cBitsCurrent = 0;
276 zgfx->BitsCurrent = 0;
277
278 while (zgfx->cBitsRemaining)
279 {
280 haveBits = 0;
281 inPrefix = 0;
282
283 for (opIndex = 0; ZGFX_TOKEN_TABLE[opIndex].prefixLength != 0; opIndex++)
284 {
285 while (haveBits < ZGFX_TOKEN_TABLE[opIndex].prefixLength)
286 {
287 zgfx_GetBits(zgfx, 1);
288 inPrefix = (inPrefix << 1) + zgfx->bits;
289 haveBits++;
290 }
291
292 if (inPrefix == ZGFX_TOKEN_TABLE[opIndex].prefixCode)
293 {
294 if (ZGFX_TOKEN_TABLE[opIndex].tokenType == 0)
295 {
296 /* Literal */
297 zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
298 c = (BYTE)(ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits);
299 zgfx->HistoryBuffer[zgfx->HistoryIndex] = c;
300
301 if (++zgfx->HistoryIndex == zgfx->HistoryBufferSize)
302 zgfx->HistoryIndex = 0;
303
304 if (zgfx->OutputCount >= sizeof(zgfx->OutputBuffer))
305 return FALSE;
306
307 zgfx->OutputBuffer[zgfx->OutputCount++] = c;
308 }
309 else
310 {
311 zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
312 distance = ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits;
313
314 if (distance != 0)
315 {
316 /* Match */
317 zgfx_GetBits(zgfx, 1);
318
319 if (zgfx->bits == 0)
320 {
321 count = 3;
322 }
323 else
324 {
325 count = 4;
326 extra = 2;
327 zgfx_GetBits(zgfx, 1);
328
329 while (zgfx->bits == 1)
330 {
331 count *= 2;
332 extra++;
333 zgfx_GetBits(zgfx, 1);
334 }
335
336 zgfx_GetBits(zgfx, extra);
337 count += zgfx->bits;
338 }
339
340 if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
341 return FALSE;
342
343 zgfx_history_buffer_ring_read(zgfx, WINPR_ASSERTING_INT_CAST(int, distance),
344 &(zgfx->OutputBuffer[zgfx->OutputCount]),
345 count);
346 zgfx_history_buffer_ring_write(
347 zgfx, &(zgfx->OutputBuffer[zgfx->OutputCount]), count);
348 zgfx->OutputCount += count;
349 }
350 else
351 {
352 /* Unencoded */
353 zgfx_GetBits(zgfx, 15);
354 count = zgfx->bits;
355 zgfx->cBitsRemaining -= zgfx->cBitsCurrent;
356 zgfx->cBitsCurrent = 0;
357 zgfx->BitsCurrent = 0;
358
359 if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
360 return FALSE;
361 else if (count > zgfx->cBitsRemaining / 8)
362 return FALSE;
363 else if (zgfx->pbInputCurrent + count > zgfx->pbInputEnd)
364 return FALSE;
365
366 CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent,
367 count);
368 zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count);
369 zgfx->pbInputCurrent += count;
370 zgfx->cBitsRemaining -= (8 * count);
371 zgfx->OutputCount += count;
372 }
373 }
374
375 break;
376 }
377 }
378 }
379
380 return TRUE;
381}
382
383static INLINE BOOL zgfx_append(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
384 BYTE** WINPR_RESTRICT ppConcatenated, size_t uncompressedSize,
385 size_t* WINPR_RESTRICT pUsed)
386{
387 WINPR_ASSERT(zgfx);
388 WINPR_ASSERT(ppConcatenated);
389 WINPR_ASSERT(pUsed);
390
391 const size_t used = *pUsed;
392 if (zgfx->OutputCount > UINT32_MAX - used)
393 return FALSE;
394
395 if (used + zgfx->OutputCount > uncompressedSize)
396 return FALSE;
397
398 BYTE* tmp = realloc(*ppConcatenated, used + zgfx->OutputCount + 64ull);
399 if (!tmp)
400 return FALSE;
401 *ppConcatenated = tmp;
402 CopyMemory(&tmp[used], zgfx->OutputBuffer, zgfx->OutputCount);
403 *pUsed = used + zgfx->OutputCount;
404 return TRUE;
405}
406
407int zgfx_decompress(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, const BYTE* WINPR_RESTRICT pSrcData,
408 UINT32 SrcSize, BYTE** WINPR_RESTRICT ppDstData,
409 UINT32* WINPR_RESTRICT pDstSize, WINPR_ATTR_UNUSED UINT32 flags)
410{
411 int status = -1;
412 BYTE descriptor = 0;
413 wStream sbuffer = { 0 };
414 size_t used = 0;
415 BYTE* pConcatenated = NULL;
416 wStream* stream = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);
417
418 WINPR_ASSERT(zgfx);
419 WINPR_ASSERT(stream);
420 WINPR_ASSERT(ppDstData);
421 WINPR_ASSERT(pDstSize);
422
423 *ppDstData = NULL;
424 *pDstSize = 0;
425
426 if (!Stream_CheckAndLogRequiredLength(TAG, stream, 1))
427 goto fail;
428
429 Stream_Read_UINT8(stream, descriptor); /* descriptor (1 byte) */
430
431 if (descriptor == ZGFX_SEGMENTED_SINGLE)
432 {
433 if (!zgfx_decompress_segment(zgfx, stream, Stream_GetRemainingLength(stream)))
434 goto fail;
435
436 if (zgfx->OutputCount > 0)
437 {
438 if (!zgfx_append(zgfx, &pConcatenated, zgfx->OutputCount, &used))
439 goto fail;
440 if (used != zgfx->OutputCount)
441 goto fail;
442 *ppDstData = pConcatenated;
443 *pDstSize = zgfx->OutputCount;
444 }
445 }
446 else if (descriptor == ZGFX_SEGMENTED_MULTIPART)
447 {
448 UINT32 segmentSize = 0;
449 UINT16 segmentNumber = 0;
450 UINT16 segmentCount = 0;
451 UINT32 uncompressedSize = 0;
452
453 if (!Stream_CheckAndLogRequiredLength(TAG, stream, 6))
454 goto fail;
455
456 Stream_Read_UINT16(stream, segmentCount); /* segmentCount (2 bytes) */
457 Stream_Read_UINT32(stream, uncompressedSize); /* uncompressedSize (4 bytes) */
458
459 for (segmentNumber = 0; segmentNumber < segmentCount; segmentNumber++)
460 {
461 if (!Stream_CheckAndLogRequiredLength(TAG, stream, sizeof(UINT32)))
462 goto fail;
463
464 Stream_Read_UINT32(stream, segmentSize); /* segmentSize (4 bytes) */
465
466 if (!zgfx_decompress_segment(zgfx, stream, segmentSize))
467 goto fail;
468
469 if (!zgfx_append(zgfx, &pConcatenated, uncompressedSize, &used))
470 goto fail;
471 }
472
473 if (used != uncompressedSize)
474 goto fail;
475
476 *ppDstData = pConcatenated;
477 *pDstSize = uncompressedSize;
478 }
479 else
480 {
481 goto fail;
482 }
483
484 status = 1;
485fail:
486 if (status < 0)
487 free(pConcatenated);
488 return status;
489}
490
491static BOOL zgfx_compress_segment(WINPR_ATTR_UNUSED ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
492 wStream* WINPR_RESTRICT s, const BYTE* WINPR_RESTRICT pSrcData,
493 UINT32 SrcSize, UINT32* WINPR_RESTRICT pFlags)
494{
495 /* FIXME: Currently compression not implemented. Just copy the raw source */
496 if (!Stream_EnsureRemainingCapacity(s, SrcSize + 1))
497 {
498 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
499 return FALSE;
500 }
501
502 (*pFlags) |= ZGFX_PACKET_COMPR_TYPE_RDP8; /* RDP 8.0 compression format */
503 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, *pFlags)); /* header (1 byte) */
504 Stream_Write(s, pSrcData, SrcSize);
505 return TRUE;
506}
507
508int zgfx_compress_to_stream(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, wStream* WINPR_RESTRICT sDst,
509 const BYTE* WINPR_RESTRICT pUncompressed, UINT32 uncompressedSize,
510 UINT32* WINPR_RESTRICT pFlags)
511{
512 int fragment = 0;
513 UINT16 maxLength = 0;
514 UINT32 totalLength = 0;
515 size_t posSegmentCount = 0;
516 const BYTE* pSrcData = NULL;
517 int status = 0;
518 maxLength = ZGFX_SEGMENTED_MAXSIZE;
519 totalLength = uncompressedSize;
520 pSrcData = pUncompressed;
521
522 for (; (totalLength > 0) || (fragment == 0); fragment++)
523 {
524 size_t posDstSize = 0;
525 size_t posDataStart = 0;
526
527 const UINT32 SrcSize = (totalLength > maxLength) ? maxLength : totalLength;
528 posDstSize = 0;
529 totalLength -= SrcSize;
530
531 /* Ensure we have enough space for headers */
532 if (!Stream_EnsureRemainingCapacity(sDst, 12))
533 {
534 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
535 return -1;
536 }
537
538 if (fragment == 0)
539 {
540 /* First fragment */
541 /* descriptor (1 byte) */
542 Stream_Write_UINT8(sDst, (totalLength == 0) ? ZGFX_SEGMENTED_SINGLE
543 : ZGFX_SEGMENTED_MULTIPART);
544
545 if (totalLength > 0)
546 {
547 posSegmentCount = Stream_GetPosition(sDst); /* segmentCount (2 bytes) */
548 Stream_Seek(sDst, 2);
549 Stream_Write_UINT32(sDst, uncompressedSize); /* uncompressedSize (4 bytes) */
550 }
551 }
552
553 if (fragment > 0 || totalLength > 0)
554 {
555 /* Multipart */
556 posDstSize = Stream_GetPosition(sDst); /* size (4 bytes) */
557 Stream_Seek(sDst, 4);
558 }
559
560 posDataStart = Stream_GetPosition(sDst);
561
562 if (!zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags))
563 return -1;
564
565 if (posDstSize)
566 {
567 /* Fill segment data size */
568 const size_t DstSize = Stream_GetPosition(sDst) - posDataStart;
569 if (DstSize > UINT32_MAX)
570 return -1;
571 Stream_SetPosition(sDst, posDstSize);
572 Stream_Write_UINT32(sDst, (UINT32)DstSize);
573 Stream_SetPosition(sDst, posDataStart + DstSize);
574 }
575
576 pSrcData += SrcSize;
577 }
578
579 Stream_SealLength(sDst);
580
581 /* fill back segmentCount */
582 if (posSegmentCount)
583 {
584 Stream_SetPosition(sDst, posSegmentCount);
585 Stream_Write_UINT16(sDst, WINPR_ASSERTING_INT_CAST(uint16_t, fragment));
586 Stream_SetPosition(sDst, Stream_Length(sDst));
587 }
588
589 return status;
590}
591
592int zgfx_compress(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, const BYTE* WINPR_RESTRICT pSrcData,
593 UINT32 SrcSize, BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize,
594 UINT32* WINPR_RESTRICT pFlags)
595{
596 int status = 0;
597 wStream* s = Stream_New(NULL, SrcSize);
598 status = zgfx_compress_to_stream(zgfx, s, pSrcData, SrcSize, pFlags);
599 const size_t pos = Stream_GetPosition(s);
600 if (pos > UINT32_MAX)
601 status = -1;
602 else
603 {
604 (*ppDstData) = Stream_Buffer(s);
605 (*pDstSize) = (UINT32)pos;
606 }
607 Stream_Free(s, FALSE);
608 return status;
609}
610
611void zgfx_context_reset(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, WINPR_ATTR_UNUSED BOOL flush)
612{
613 zgfx->HistoryIndex = 0;
614}
615
616ZGFX_CONTEXT* zgfx_context_new(BOOL Compressor)
617{
618 ZGFX_CONTEXT* zgfx = NULL;
619 zgfx = (ZGFX_CONTEXT*)calloc(1, sizeof(ZGFX_CONTEXT));
620
621 if (zgfx)
622 {
623 zgfx->Compressor = Compressor;
624 zgfx->HistoryBufferSize = sizeof(zgfx->HistoryBuffer);
625 zgfx_context_reset(zgfx, FALSE);
626 }
627
628 return zgfx;
629}
630
631void zgfx_context_free(ZGFX_CONTEXT* zgfx)
632{
633 free(zgfx);
634}