FreeRDP
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 
45 typedef struct
46 {
47  UINT32 prefixLength;
48  UINT32 prefixCode;
49  UINT32 valueBits;
50  UINT32 tokenType;
51  UINT32 valueBase;
52 } ZGFX_TOKEN;
53 
54 struct 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 
74 static 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 
119 static 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 
141 static 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  if ((zgfx->HistoryIndex += count) == zgfx->HistoryBufferSize)
160  zgfx->HistoryIndex = 0;
161  }
162  else
163  {
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);
168  }
169 }
170 
171 static INLINE void zgfx_history_buffer_ring_read(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, int offset,
172  BYTE* WINPR_RESTRICT dst, UINT32 count)
173 {
174  UINT32 front = 0;
175  UINT32 index = 0;
176  INT32 bytes = 0;
177  UINT32 valid = 0;
178  INT32 bytesLeft = 0;
179  BYTE* dptr = dst;
180  BYTE* origDst = dst;
181 
182  if ((count <= 0) || (count > INT32_MAX))
183  return;
184 
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);
190 
191  if ((index + WINPR_ASSERTING_INT_CAST(uint32_t, bytes)) <= zgfx->HistoryBufferSize)
192  {
193  CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), WINPR_ASSERTING_INT_CAST(size_t, bytes));
194  }
195  else
196  {
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);
201  }
202 
203  if ((bytesLeft -= bytes) == 0)
204  return;
205 
206  dptr += bytes;
207  valid = WINPR_ASSERTING_INT_CAST(uint32_t, bytes);
208 
209  do
210  {
211  bytes = WINPR_ASSERTING_INT_CAST(int32_t, valid);
212 
213  if (bytes > bytesLeft)
214  bytes = bytesLeft;
215 
216  CopyMemory(dptr, origDst, WINPR_ASSERTING_INT_CAST(size_t, bytes));
217  dptr += bytes;
218  valid <<= 1;
219  } while ((bytesLeft -= bytes) > 0);
220 }
221 
222 static INLINE BOOL zgfx_decompress_segment(ZGFX_CONTEXT* WINPR_RESTRICT zgfx,
223  wStream* WINPR_RESTRICT stream, size_t segmentSize)
224 {
225  BYTE c = 0;
226  BYTE flags = 0;
227  UINT32 extra = 0;
228  int opIndex = 0;
229  UINT32 haveBits = 0;
230  UINT32 inPrefix = 0;
231  UINT32 count = 0;
232  UINT32 distance = 0;
233  BYTE* pbSegment = NULL;
234 
235  WINPR_ASSERT(zgfx);
236  WINPR_ASSERT(stream);
237 
238  if (segmentSize < 2)
239  return FALSE;
240 
241  const size_t cbSegment = segmentSize - 1;
242 
243  if (!Stream_CheckAndLogRequiredLength(TAG, stream, segmentSize) || (segmentSize > UINT32_MAX))
244  return FALSE;
245 
246  Stream_Read_UINT8(stream, flags); /* header (1 byte) */
247  zgfx->OutputCount = 0;
248  pbSegment = Stream_Pointer(stream);
249  if (!Stream_SafeSeek(stream, cbSegment))
250  return FALSE;
251 
252  if (!(flags & PACKET_COMPRESSED))
253  {
254  zgfx_history_buffer_ring_write(zgfx, pbSegment, cbSegment);
255 
256  if (cbSegment > sizeof(zgfx->OutputBuffer))
257  return FALSE;
258 
259  CopyMemory(zgfx->OutputBuffer, pbSegment, cbSegment);
260  zgfx->OutputCount = (UINT32)cbSegment;
261  return TRUE;
262  }
263 
264  zgfx->pbInputCurrent = pbSegment;
265  zgfx->pbInputEnd = &pbSegment[cbSegment - 1];
266  /* NumberOfBitsToDecode = ((NumberOfBytesToDecode - 1) * 8) - ValueOfLastByte */
267  const size_t bits = 8u * (cbSegment - 1u);
268  if (bits > UINT32_MAX)
269  return FALSE;
270  if (bits < *zgfx->pbInputEnd)
271  return FALSE;
272 
273  zgfx->cBitsRemaining = (UINT32)(bits - *zgfx->pbInputEnd);
274  zgfx->cBitsCurrent = 0;
275  zgfx->BitsCurrent = 0;
276 
277  while (zgfx->cBitsRemaining)
278  {
279  haveBits = 0;
280  inPrefix = 0;
281 
282  for (opIndex = 0; ZGFX_TOKEN_TABLE[opIndex].prefixLength != 0; opIndex++)
283  {
284  while (haveBits < ZGFX_TOKEN_TABLE[opIndex].prefixLength)
285  {
286  zgfx_GetBits(zgfx, 1);
287  inPrefix = (inPrefix << 1) + zgfx->bits;
288  haveBits++;
289  }
290 
291  if (inPrefix == ZGFX_TOKEN_TABLE[opIndex].prefixCode)
292  {
293  if (ZGFX_TOKEN_TABLE[opIndex].tokenType == 0)
294  {
295  /* Literal */
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;
299 
300  if (++zgfx->HistoryIndex == zgfx->HistoryBufferSize)
301  zgfx->HistoryIndex = 0;
302 
303  if (zgfx->OutputCount >= sizeof(zgfx->OutputBuffer))
304  return FALSE;
305 
306  zgfx->OutputBuffer[zgfx->OutputCount++] = c;
307  }
308  else
309  {
310  zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
311  distance = ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits;
312 
313  if (distance != 0)
314  {
315  /* Match */
316  zgfx_GetBits(zgfx, 1);
317 
318  if (zgfx->bits == 0)
319  {
320  count = 3;
321  }
322  else
323  {
324  count = 4;
325  extra = 2;
326  zgfx_GetBits(zgfx, 1);
327 
328  while (zgfx->bits == 1)
329  {
330  count *= 2;
331  extra++;
332  zgfx_GetBits(zgfx, 1);
333  }
334 
335  zgfx_GetBits(zgfx, extra);
336  count += zgfx->bits;
337  }
338 
339  if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
340  return FALSE;
341 
342  zgfx_history_buffer_ring_read(zgfx, WINPR_ASSERTING_INT_CAST(int, distance),
343  &(zgfx->OutputBuffer[zgfx->OutputCount]),
344  count);
345  zgfx_history_buffer_ring_write(
346  zgfx, &(zgfx->OutputBuffer[zgfx->OutputCount]), count);
347  zgfx->OutputCount += count;
348  }
349  else
350  {
351  /* Unencoded */
352  zgfx_GetBits(zgfx, 15);
353  count = zgfx->bits;
354  zgfx->cBitsRemaining -= zgfx->cBitsCurrent;
355  zgfx->cBitsCurrent = 0;
356  zgfx->BitsCurrent = 0;
357 
358  if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
359  return FALSE;
360  else if (count > zgfx->cBitsRemaining / 8)
361  return FALSE;
362  else if (zgfx->pbInputCurrent + count > zgfx->pbInputEnd)
363  return FALSE;
364 
365  CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent,
366  count);
367  zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count);
368  zgfx->pbInputCurrent += count;
369  zgfx->cBitsRemaining -= (8 * count);
370  zgfx->OutputCount += count;
371  }
372  }
373 
374  break;
375  }
376  }
377  }
378 
379  return TRUE;
380 }
381 
382 /* Allocate the buffers a bit larger.
383  *
384  * Due to optimizations some h264 decoders will read data beyond
385  * the actual available data, so ensure that it will never be a
386  * out of bounds read.
387  */
388 static INLINE BYTE* aligned_zgfx_malloc(size_t size)
389 {
390  return malloc(size + 64);
391 }
392 
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)
396 {
397  WINPR_ASSERT(zgfx);
398  WINPR_ASSERT(ppConcatenated);
399  WINPR_ASSERT(pUsed);
400 
401  const size_t used = *pUsed;
402  if (zgfx->OutputCount > UINT32_MAX - used)
403  return FALSE;
404 
405  if (used + zgfx->OutputCount > uncompressedSize)
406  return FALSE;
407 
408  BYTE* tmp = realloc(*ppConcatenated, used + zgfx->OutputCount + 64ull);
409  if (!tmp)
410  return FALSE;
411  *ppConcatenated = tmp;
412  CopyMemory(&tmp[used], zgfx->OutputBuffer, zgfx->OutputCount);
413  *pUsed = used + zgfx->OutputCount;
414  return TRUE;
415 }
416 
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)
420 {
421  int status = -1;
422  BYTE descriptor = 0;
423  wStream sbuffer = { 0 };
424  size_t used = 0;
425  BYTE* pConcatenated = NULL;
426  wStream* stream = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);
427 
428  WINPR_ASSERT(zgfx);
429  WINPR_ASSERT(stream);
430  WINPR_ASSERT(ppDstData);
431  WINPR_ASSERT(pDstSize);
432 
433  *ppDstData = NULL;
434  *pDstSize = 0;
435 
436  if (!Stream_CheckAndLogRequiredLength(TAG, stream, 1))
437  goto fail;
438 
439  Stream_Read_UINT8(stream, descriptor); /* descriptor (1 byte) */
440 
441  if (descriptor == ZGFX_SEGMENTED_SINGLE)
442  {
443  if (!zgfx_decompress_segment(zgfx, stream, Stream_GetRemainingLength(stream)))
444  goto fail;
445 
446  if (zgfx->OutputCount > 0)
447  {
448  if (!zgfx_append(zgfx, &pConcatenated, zgfx->OutputCount, &used))
449  goto fail;
450  if (used != zgfx->OutputCount)
451  goto fail;
452  *ppDstData = pConcatenated;
453  *pDstSize = zgfx->OutputCount;
454  }
455  }
456  else if (descriptor == ZGFX_SEGMENTED_MULTIPART)
457  {
458  UINT32 segmentSize = 0;
459  UINT16 segmentNumber = 0;
460  UINT16 segmentCount = 0;
461  UINT32 uncompressedSize = 0;
462 
463  if (!Stream_CheckAndLogRequiredLength(TAG, stream, 6))
464  goto fail;
465 
466  Stream_Read_UINT16(stream, segmentCount); /* segmentCount (2 bytes) */
467  Stream_Read_UINT32(stream, uncompressedSize); /* uncompressedSize (4 bytes) */
468 
469  for (segmentNumber = 0; segmentNumber < segmentCount; segmentNumber++)
470  {
471  if (!Stream_CheckAndLogRequiredLength(TAG, stream, sizeof(UINT32)))
472  goto fail;
473 
474  Stream_Read_UINT32(stream, segmentSize); /* segmentSize (4 bytes) */
475 
476  if (!zgfx_decompress_segment(zgfx, stream, segmentSize))
477  goto fail;
478 
479  if (!zgfx_append(zgfx, &pConcatenated, uncompressedSize, &used))
480  goto fail;
481  }
482 
483  if (used != uncompressedSize)
484  goto fail;
485 
486  *ppDstData = pConcatenated;
487  *pDstSize = uncompressedSize;
488  }
489  else
490  {
491  goto fail;
492  }
493 
494  status = 1;
495 fail:
496  if (status < 0)
497  free(pConcatenated);
498  return status;
499 }
500 
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)
504 {
505  /* FIXME: Currently compression not implemented. Just copy the raw source */
506  if (!Stream_EnsureRemainingCapacity(s, SrcSize + 1))
507  {
508  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
509  return FALSE;
510  }
511 
512  (*pFlags) |= ZGFX_PACKET_COMPR_TYPE_RDP8; /* RDP 8.0 compression format */
513  Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, *pFlags)); /* header (1 byte) */
514  Stream_Write(s, pSrcData, SrcSize);
515  return TRUE;
516 }
517 
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)
521 {
522  int fragment = 0;
523  UINT16 maxLength = 0;
524  UINT32 totalLength = 0;
525  size_t posSegmentCount = 0;
526  const BYTE* pSrcData = NULL;
527  int status = 0;
528  maxLength = ZGFX_SEGMENTED_MAXSIZE;
529  totalLength = uncompressedSize;
530  pSrcData = pUncompressed;
531 
532  for (; (totalLength > 0) || (fragment == 0); fragment++)
533  {
534  size_t posDstSize = 0;
535  size_t posDataStart = 0;
536 
537  const UINT32 SrcSize = (totalLength > maxLength) ? maxLength : totalLength;
538  posDstSize = 0;
539  totalLength -= SrcSize;
540 
541  /* Ensure we have enough space for headers */
542  if (!Stream_EnsureRemainingCapacity(sDst, 12))
543  {
544  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
545  return -1;
546  }
547 
548  if (fragment == 0)
549  {
550  /* First fragment */
551  /* descriptor (1 byte) */
552  Stream_Write_UINT8(sDst, (totalLength == 0) ? ZGFX_SEGMENTED_SINGLE
553  : ZGFX_SEGMENTED_MULTIPART);
554 
555  if (totalLength > 0)
556  {
557  posSegmentCount = Stream_GetPosition(sDst); /* segmentCount (2 bytes) */
558  Stream_Seek(sDst, 2);
559  Stream_Write_UINT32(sDst, uncompressedSize); /* uncompressedSize (4 bytes) */
560  }
561  }
562 
563  if (fragment > 0 || totalLength > 0)
564  {
565  /* Multipart */
566  posDstSize = Stream_GetPosition(sDst); /* size (4 bytes) */
567  Stream_Seek(sDst, 4);
568  }
569 
570  posDataStart = Stream_GetPosition(sDst);
571 
572  if (!zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags))
573  return -1;
574 
575  if (posDstSize)
576  {
577  /* Fill segment data size */
578  const size_t DstSize = Stream_GetPosition(sDst) - posDataStart;
579  if (DstSize > UINT32_MAX)
580  return -1;
581  Stream_SetPosition(sDst, posDstSize);
582  Stream_Write_UINT32(sDst, (UINT32)DstSize);
583  Stream_SetPosition(sDst, posDataStart + DstSize);
584  }
585 
586  pSrcData += SrcSize;
587  }
588 
589  Stream_SealLength(sDst);
590 
591  /* fill back segmentCount */
592  if (posSegmentCount)
593  {
594  Stream_SetPosition(sDst, posSegmentCount);
595  Stream_Write_UINT16(sDst, WINPR_ASSERTING_INT_CAST(uint16_t, fragment));
596  Stream_SetPosition(sDst, Stream_Length(sDst));
597  }
598 
599  return status;
600 }
601 
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)
605 {
606  int status = 0;
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)
611  status = -1;
612  else
613  {
614  (*ppDstData) = Stream_Buffer(s);
615  (*pDstSize) = (UINT32)pos;
616  }
617  Stream_Free(s, FALSE);
618  return status;
619 }
620 
621 void zgfx_context_reset(ZGFX_CONTEXT* WINPR_RESTRICT zgfx, BOOL flush)
622 {
623  zgfx->HistoryIndex = 0;
624 }
625 
626 ZGFX_CONTEXT* zgfx_context_new(BOOL Compressor)
627 {
628  ZGFX_CONTEXT* zgfx = NULL;
629  zgfx = (ZGFX_CONTEXT*)calloc(1, sizeof(ZGFX_CONTEXT));
630 
631  if (zgfx)
632  {
633  zgfx->Compressor = Compressor;
634  zgfx->HistoryBufferSize = sizeof(zgfx->HistoryBuffer);
635  zgfx_context_reset(zgfx, FALSE);
636  }
637 
638  return zgfx;
639 }
640 
641 void zgfx_context_free(ZGFX_CONTEXT* zgfx)
642 {
643  free(zgfx);
644 }