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