/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 | } |