Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/codec/zgfx.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * ZGFX (RDP8) Bulk Data Compression
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
7
 * Copyright 2017 Thincast Technologies GmbH
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
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
33
/**
34
 * RDP8 Compressor Limits:
35
 *
36
 * Maximum number of uncompressed bytes in a single segment: 65535
37
 * Maximum match distance / minimum history size: 2500000 bytes.
38
 * Maximum number of segments: 65535
39
 * Maximum expansion of a segment (when compressed size exceeds uncompressed): 1000 bytes
40
 * Minimum match length: 3 bytes
41
 */
42
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* zgfx, UINT32 nbits)
118
49.6M
{
119
49.6M
  if (!zgfx)
120
0
    return FALSE;
121
122
75.4M
  while (zgfx->cBitsCurrent < nbits)
123
25.8M
  {
124
25.8M
    zgfx->BitsCurrent <<= 8;
125
126
25.8M
    if (zgfx->pbInputCurrent < zgfx->pbInputEnd)
127
1.69M
      zgfx->BitsCurrent += *(zgfx->pbInputCurrent)++;
128
129
25.8M
    zgfx->cBitsCurrent += 8;
130
25.8M
  }
131
132
49.6M
  zgfx->cBitsRemaining -= nbits;
133
49.6M
  zgfx->cBitsCurrent -= nbits;
134
49.6M
  zgfx->bits = zgfx->BitsCurrent >> zgfx->cBitsCurrent;
135
49.6M
  zgfx->BitsCurrent &= ((1 << zgfx->cBitsCurrent) - 1);
136
49.6M
  return TRUE;
137
49.6M
}
138
139
static void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* zgfx, const BYTE* src, size_t count)
140
44.4k
{
141
44.4k
  UINT32 front = 0;
142
143
44.4k
  if (count <= 0)
144
789
    return;
145
146
43.6k
  if (count > zgfx->HistoryBufferSize)
147
0
  {
148
0
    const size_t residue = count - zgfx->HistoryBufferSize;
149
0
    count = zgfx->HistoryBufferSize;
150
0
    src += residue;
151
0
    zgfx->HistoryIndex = (zgfx->HistoryIndex + residue) % zgfx->HistoryBufferSize;
152
0
  }
153
154
43.6k
  if (zgfx->HistoryIndex + count <= zgfx->HistoryBufferSize)
155
43.6k
  {
156
43.6k
    CopyMemory(&(zgfx->HistoryBuffer[zgfx->HistoryIndex]), src, count);
157
158
43.6k
    if ((zgfx->HistoryIndex += count) == zgfx->HistoryBufferSize)
159
0
      zgfx->HistoryIndex = 0;
160
43.6k
  }
161
0
  else
162
0
  {
163
0
    front = zgfx->HistoryBufferSize - zgfx->HistoryIndex;
164
0
    CopyMemory(&(zgfx->HistoryBuffer[zgfx->HistoryIndex]), src, front);
165
0
    CopyMemory(zgfx->HistoryBuffer, &src[front], count - front);
166
0
    zgfx->HistoryIndex = count - front;
167
0
  }
168
43.6k
}
169
170
static void zgfx_history_buffer_ring_read(ZGFX_CONTEXT* zgfx, int offset, BYTE* dst, UINT32 count)
171
43.1k
{
172
43.1k
  UINT32 front = 0;
173
43.1k
  UINT32 index = 0;
174
43.1k
  INT32 bytes = 0;
175
43.1k
  UINT32 valid = 0;
176
43.1k
  INT32 bytesLeft = 0;
177
43.1k
  BYTE* dptr = dst;
178
43.1k
  BYTE* origDst = dst;
179
180
43.1k
  if ((count <= 0) || (count > INT32_MAX))
181
267
    return;
182
183
42.9k
  bytesLeft = (INT32)count;
184
42.9k
  index = (zgfx->HistoryIndex + zgfx->HistoryBufferSize - offset) % zgfx->HistoryBufferSize;
185
42.9k
  bytes = MIN(bytesLeft, offset);
186
187
42.9k
  if ((index + bytes) <= zgfx->HistoryBufferSize)
188
42.7k
  {
189
42.7k
    CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), bytes);
190
42.7k
  }
191
110
  else
192
110
  {
193
110
    front = zgfx->HistoryBufferSize - index;
194
110
    CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), front);
195
110
    CopyMemory(&dptr[front], zgfx->HistoryBuffer, bytes - front);
196
110
  }
197
198
42.9k
  if ((bytesLeft -= bytes) == 0)
199
41.6k
    return;
200
201
1.21k
  dptr += bytes;
202
1.21k
  valid = bytes;
203
204
1.21k
  do
205
2.35k
  {
206
2.35k
    bytes = valid;
207
208
2.35k
    if (bytes > bytesLeft)
209
1.19k
      bytes = bytesLeft;
210
211
2.35k
    CopyMemory(dptr, origDst, bytes);
212
2.35k
    dptr += bytes;
213
2.35k
    valid <<= 1;
214
2.35k
  } while ((bytesLeft -= bytes) > 0);
215
1.21k
}
216
217
static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t segmentSize)
218
2.72k
{
219
2.72k
  BYTE c = 0;
220
2.72k
  BYTE flags = 0;
221
2.72k
  UINT32 extra = 0;
222
2.72k
  int opIndex = 0;
223
2.72k
  UINT32 haveBits = 0;
224
2.72k
  UINT32 inPrefix = 0;
225
2.72k
  UINT32 count = 0;
226
2.72k
  UINT32 distance = 0;
227
2.72k
  BYTE* pbSegment = NULL;
228
2.72k
  size_t cbSegment = 0;
229
230
2.72k
  WINPR_ASSERT(zgfx);
231
2.72k
  WINPR_ASSERT(stream);
232
233
2.72k
  if (segmentSize < 2)
234
29
    return FALSE;
235
236
2.69k
  cbSegment = segmentSize - 1;
237
238
2.69k
  if (!Stream_CheckAndLogRequiredLength(TAG, stream, segmentSize) || (segmentSize > UINT32_MAX))
239
126
    return FALSE;
240
241
2.56k
  Stream_Read_UINT8(stream, flags); /* header (1 byte) */
242
2.56k
  zgfx->OutputCount = 0;
243
2.56k
  pbSegment = Stream_Pointer(stream);
244
2.56k
  if (!Stream_SafeSeek(stream, cbSegment))
245
0
    return FALSE;
246
247
2.56k
  if (!(flags & PACKET_COMPRESSED))
248
228
  {
249
228
    zgfx_history_buffer_ring_write(zgfx, pbSegment, cbSegment);
250
251
228
    if (cbSegment > sizeof(zgfx->OutputBuffer))
252
17
      return FALSE;
253
254
211
    CopyMemory(zgfx->OutputBuffer, pbSegment, cbSegment);
255
211
    zgfx->OutputCount = cbSegment;
256
211
    return TRUE;
257
228
  }
258
259
2.33k
  zgfx->pbInputCurrent = pbSegment;
260
2.33k
  zgfx->pbInputEnd = &pbSegment[cbSegment - 1];
261
  /* NumberOfBitsToDecode = ((NumberOfBytesToDecode - 1) * 8) - ValueOfLastByte */
262
2.33k
  const UINT32 bits = 8u * (cbSegment - 1u);
263
2.33k
  if (bits < *zgfx->pbInputEnd)
264
33
    return FALSE;
265
266
2.30k
  zgfx->cBitsRemaining = bits - *zgfx->pbInputEnd;
267
2.30k
  zgfx->cBitsCurrent = 0;
268
2.30k
  zgfx->BitsCurrent = 0;
269
270
23.0M
  while (zgfx->cBitsRemaining)
271
23.0M
  {
272
23.0M
    haveBits = 0;
273
23.0M
    inPrefix = 0;
274
275
37.4M
    for (opIndex = 0; ZGFX_TOKEN_TABLE[opIndex].prefixLength != 0; opIndex++)
276
37.4M
    {
277
63.8M
      while (haveBits < ZGFX_TOKEN_TABLE[opIndex].prefixLength)
278
26.4M
      {
279
26.4M
        zgfx_GetBits(zgfx, 1);
280
26.4M
        inPrefix = (inPrefix << 1) + zgfx->bits;
281
26.4M
        haveBits++;
282
26.4M
      }
283
284
37.4M
      if (inPrefix == ZGFX_TOKEN_TABLE[opIndex].prefixCode)
285
23.0M
      {
286
23.0M
        if (ZGFX_TOKEN_TABLE[opIndex].tokenType == 0)
287
23.0M
        {
288
          /* Literal */
289
23.0M
          zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
290
23.0M
          c = (BYTE)(ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits);
291
23.0M
          zgfx->HistoryBuffer[zgfx->HistoryIndex] = c;
292
293
23.0M
          if (++zgfx->HistoryIndex == zgfx->HistoryBufferSize)
294
0
            zgfx->HistoryIndex = 0;
295
296
23.0M
          if (zgfx->OutputCount >= sizeof(zgfx->OutputBuffer))
297
401
            return FALSE;
298
299
23.0M
          zgfx->OutputBuffer[zgfx->OutputCount++] = c;
300
23.0M
        }
301
44.2k
        else
302
44.2k
        {
303
44.2k
          zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
304
44.2k
          distance = ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits;
305
306
44.2k
          if (distance != 0)
307
43.2k
          {
308
            /* Match */
309
43.2k
            zgfx_GetBits(zgfx, 1);
310
311
43.2k
            if (zgfx->bits == 0)
312
26.7k
            {
313
26.7k
              count = 3;
314
26.7k
            }
315
16.5k
            else
316
16.5k
            {
317
16.5k
              count = 4;
318
16.5k
              extra = 2;
319
16.5k
              zgfx_GetBits(zgfx, 1);
320
321
68.8k
              while (zgfx->bits == 1)
322
52.2k
              {
323
52.2k
                count *= 2;
324
52.2k
                extra++;
325
52.2k
                zgfx_GetBits(zgfx, 1);
326
52.2k
              }
327
328
16.5k
              zgfx_GetBits(zgfx, extra);
329
16.5k
              count += zgfx->bits;
330
16.5k
            }
331
332
43.2k
            if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
333
49
              return FALSE;
334
335
43.1k
            zgfx_history_buffer_ring_read(
336
43.1k
                zgfx, distance, &(zgfx->OutputBuffer[zgfx->OutputCount]), count);
337
43.1k
            zgfx_history_buffer_ring_write(
338
43.1k
                zgfx, &(zgfx->OutputBuffer[zgfx->OutputCount]), count);
339
43.1k
            zgfx->OutputCount += count;
340
43.1k
          }
341
1.07k
          else
342
1.07k
          {
343
            /* Unencoded */
344
1.07k
            zgfx_GetBits(zgfx, 15);
345
1.07k
            count = zgfx->bits;
346
1.07k
            zgfx->cBitsRemaining -= zgfx->cBitsCurrent;
347
1.07k
            zgfx->cBitsCurrent = 0;
348
1.07k
            zgfx->BitsCurrent = 0;
349
350
1.07k
            if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
351
2
              return FALSE;
352
1.07k
            else if (count > zgfx->cBitsRemaining / 8)
353
24
              return FALSE;
354
1.04k
            else if (zgfx->pbInputCurrent + count > zgfx->pbInputEnd)
355
24
              return FALSE;
356
357
1.02k
            CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent,
358
1.02k
                       count);
359
1.02k
            zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count);
360
1.02k
            zgfx->pbInputCurrent += count;
361
1.02k
            zgfx->cBitsRemaining -= (8 * count);
362
1.02k
            zgfx->OutputCount += count;
363
1.02k
          }
364
44.2k
        }
365
366
23.0M
        break;
367
23.0M
      }
368
37.4M
    }
369
23.0M
  }
370
371
1.80k
  return TRUE;
372
2.30k
}
373
374
/* Allocate the buffers a bit larger.
375
 *
376
 * Due to optimizations some h264 decoders will read data beyond
377
 * the actual available data, so ensure that it will never be a
378
 * out of bounds read.
379
 */
380
static BYTE* aligned_zgfx_malloc(size_t size)
381
0
{
382
0
  return malloc(size + 64);
383
0
}
384
385
static BOOL zgfx_append(ZGFX_CONTEXT* zgfx, BYTE** ppConcatenated, size_t uncompressedSize,
386
                        size_t* pUsed)
387
2.01k
{
388
2.01k
  WINPR_ASSERT(zgfx);
389
2.01k
  WINPR_ASSERT(ppConcatenated);
390
2.01k
  WINPR_ASSERT(pUsed);
391
392
2.01k
  const size_t used = *pUsed;
393
2.01k
  if (zgfx->OutputCount > UINT32_MAX - used)
394
0
    return FALSE;
395
396
2.01k
  if (used + zgfx->OutputCount > uncompressedSize)
397
19
    return FALSE;
398
399
1.99k
  BYTE* tmp = realloc(*ppConcatenated, used + zgfx->OutputCount + 64ull);
400
1.99k
  if (!tmp)
401
0
    return FALSE;
402
1.99k
  *ppConcatenated = tmp;
403
1.99k
  CopyMemory(&tmp[used], zgfx->OutputBuffer, zgfx->OutputCount);
404
1.99k
  *pUsed = used + zgfx->OutputCount;
405
1.99k
  return TRUE;
406
1.99k
}
407
408
int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData,
409
                    UINT32* pDstSize, UINT32 flags)
410
5.71k
{
411
5.71k
  int status = -1;
412
5.71k
  BYTE descriptor = 0;
413
5.71k
  wStream sbuffer = { 0 };
414
5.71k
  size_t used = 0;
415
5.71k
  BYTE* pConcatenated = NULL;
416
5.71k
  wStream* stream = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);
417
418
5.71k
  WINPR_ASSERT(zgfx);
419
5.71k
  WINPR_ASSERT(stream);
420
5.71k
  WINPR_ASSERT(ppDstData);
421
5.71k
  WINPR_ASSERT(pDstSize);
422
423
5.71k
  *ppDstData = NULL;
424
5.71k
  *pDstSize = 0;
425
426
5.71k
  if (!Stream_CheckAndLogRequiredLength(TAG, stream, 1))
427
0
    goto fail;
428
429
5.71k
  Stream_Read_UINT8(stream, descriptor); /* descriptor (1 byte) */
430
431
5.71k
  if (descriptor == ZGFX_SEGMENTED_SINGLE)
432
656
  {
433
656
    if (!zgfx_decompress_segment(zgfx, stream, Stream_GetRemainingLength(stream)))
434
533
      goto fail;
435
436
123
    if (zgfx->OutputCount > 0)
437
118
    {
438
118
      if (!zgfx_append(zgfx, &pConcatenated, zgfx->OutputCount, &used))
439
0
        goto fail;
440
118
      if (used != zgfx->OutputCount)
441
0
        goto fail;
442
118
      *ppDstData = pConcatenated;
443
118
      *pDstSize = zgfx->OutputCount;
444
118
    }
445
123
  }
446
5.05k
  else if (descriptor == ZGFX_SEGMENTED_MULTIPART)
447
344
  {
448
344
    UINT32 segmentSize = 0;
449
344
    UINT16 segmentNumber = 0;
450
344
    UINT16 segmentCount = 0;
451
344
    UINT32 uncompressedSize = 0;
452
453
344
    if (!Stream_CheckAndLogRequiredLength(TAG, stream, 6))
454
37
      goto fail;
455
456
307
    Stream_Read_UINT16(stream, segmentCount);     /* segmentCount (2 bytes) */
457
307
    Stream_Read_UINT32(stream, uncompressedSize); /* uncompressedSize (4 bytes) */
458
459
2.18k
    for (segmentNumber = 0; segmentNumber < segmentCount; segmentNumber++)
460
2.14k
    {
461
2.14k
      if (!Stream_CheckAndLogRequiredLength(TAG, stream, sizeof(UINT32)))
462
84
        goto fail;
463
464
2.06k
      Stream_Read_UINT32(stream, segmentSize); /* segmentSize (4 bytes) */
465
466
2.06k
      if (!zgfx_decompress_segment(zgfx, stream, segmentSize))
467
172
        goto fail;
468
469
1.89k
      if (!zgfx_append(zgfx, &pConcatenated, uncompressedSize, &used))
470
19
        goto fail;
471
1.89k
    }
472
473
32
    if (used != uncompressedSize)
474
31
      goto fail;
475
476
1
    *ppDstData = pConcatenated;
477
1
    *pDstSize = uncompressedSize;
478
1
  }
479
4.71k
  else
480
4.71k
  {
481
4.71k
    goto fail;
482
4.71k
  }
483
484
124
  status = 1;
485
5.71k
fail:
486
5.71k
  if (status < 0)
487
5.59k
    free(pConcatenated);
488
5.71k
  return status;
489
124
}
490
491
static BOOL zgfx_compress_segment(ZGFX_CONTEXT* zgfx, wStream* s, const BYTE* pSrcData,
492
                                  UINT32 SrcSize, UINT32* pFlags)
493
0
{
494
  /* FIXME: Currently compression not implemented. Just copy the raw source */
495
0
  if (!Stream_EnsureRemainingCapacity(s, SrcSize + 1))
496
0
  {
497
0
    WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
498
0
    return FALSE;
499
0
  }
500
501
0
  (*pFlags) |= ZGFX_PACKET_COMPR_TYPE_RDP8; /* RDP 8.0 compression format */
502
0
  Stream_Write_UINT8(s, (*pFlags));         /* header (1 byte) */
503
0
  Stream_Write(s, pSrcData, SrcSize);
504
0
  return TRUE;
505
0
}
506
507
int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, const BYTE* pUncompressed,
508
                            UINT32 uncompressedSize, UINT32* pFlags)
509
0
{
510
0
  int fragment = 0;
511
0
  UINT16 maxLength = 0;
512
0
  UINT32 totalLength = 0;
513
0
  size_t posSegmentCount = 0;
514
0
  const BYTE* pSrcData = NULL;
515
0
  int status = 0;
516
0
  maxLength = ZGFX_SEGMENTED_MAXSIZE;
517
0
  totalLength = uncompressedSize;
518
0
  pSrcData = pUncompressed;
519
520
0
  for (; (totalLength > 0) || (fragment == 0); fragment++)
521
0
  {
522
0
    UINT32 SrcSize = 0;
523
0
    size_t posDstSize = 0;
524
0
    size_t posDataStart = 0;
525
0
    UINT32 DstSize = 0;
526
0
    SrcSize = (totalLength > maxLength) ? maxLength : totalLength;
527
0
    posDstSize = 0;
528
0
    totalLength -= SrcSize;
529
530
    /* Ensure we have enough space for headers */
531
0
    if (!Stream_EnsureRemainingCapacity(sDst, 12))
532
0
    {
533
0
      WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
534
0
      return -1;
535
0
    }
536
537
0
    if (fragment == 0)
538
0
    {
539
      /* First fragment */
540
      /* descriptor (1 byte) */
541
0
      Stream_Write_UINT8(sDst, (totalLength == 0) ? ZGFX_SEGMENTED_SINGLE
542
0
                                                  : ZGFX_SEGMENTED_MULTIPART);
543
544
0
      if (totalLength > 0)
545
0
      {
546
0
        posSegmentCount = Stream_GetPosition(sDst); /* segmentCount (2 bytes) */
547
0
        Stream_Seek(sDst, 2);
548
0
        Stream_Write_UINT32(sDst, uncompressedSize); /* uncompressedSize (4 bytes) */
549
0
      }
550
0
    }
551
552
0
    if (fragment > 0 || totalLength > 0)
553
0
    {
554
      /* Multipart */
555
0
      posDstSize = Stream_GetPosition(sDst); /* size (4 bytes) */
556
0
      Stream_Seek(sDst, 4);
557
0
    }
558
559
0
    posDataStart = Stream_GetPosition(sDst);
560
561
0
    if (!zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags))
562
0
      return -1;
563
564
0
    if (posDstSize)
565
0
    {
566
      /* Fill segment data size */
567
0
      DstSize = Stream_GetPosition(sDst) - posDataStart;
568
0
      Stream_SetPosition(sDst, posDstSize);
569
0
      Stream_Write_UINT32(sDst, DstSize);
570
0
      Stream_SetPosition(sDst, posDataStart + DstSize);
571
0
    }
572
573
0
    pSrcData += SrcSize;
574
0
  }
575
576
0
  Stream_SealLength(sDst);
577
578
  /* fill back segmentCount */
579
0
  if (posSegmentCount)
580
0
  {
581
0
    Stream_SetPosition(sDst, posSegmentCount);
582
0
    Stream_Write_UINT16(sDst, fragment);
583
0
    Stream_SetPosition(sDst, Stream_Length(sDst));
584
0
  }
585
586
0
  return status;
587
0
}
588
589
int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData,
590
                  UINT32* pDstSize, UINT32* pFlags)
591
0
{
592
0
  int status = 0;
593
0
  wStream* s = Stream_New(NULL, SrcSize);
594
0
  status = zgfx_compress_to_stream(zgfx, s, pSrcData, SrcSize, pFlags);
595
0
  (*ppDstData) = Stream_Buffer(s);
596
0
  (*pDstSize) = Stream_GetPosition(s);
597
0
  Stream_Free(s, FALSE);
598
0
  return status;
599
0
}
600
601
void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush)
602
5.71k
{
603
5.71k
  zgfx->HistoryIndex = 0;
604
5.71k
}
605
606
ZGFX_CONTEXT* zgfx_context_new(BOOL Compressor)
607
5.71k
{
608
5.71k
  ZGFX_CONTEXT* zgfx = NULL;
609
5.71k
  zgfx = (ZGFX_CONTEXT*)calloc(1, sizeof(ZGFX_CONTEXT));
610
611
5.71k
  if (zgfx)
612
5.71k
  {
613
5.71k
    zgfx->Compressor = Compressor;
614
5.71k
    zgfx->HistoryBufferSize = sizeof(zgfx->HistoryBuffer);
615
5.71k
    zgfx_context_reset(zgfx, FALSE);
616
5.71k
  }
617
618
5.71k
  return zgfx;
619
5.71k
}
620
621
void zgfx_context_free(ZGFX_CONTEXT* zgfx)
622
5.71k
{
623
5.71k
  free(zgfx);
624
5.71k
}