/src/FreeRDP/libfreerdp/codec/clear.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /**  | 
2  |  |  * FreeRDP: A Remote Desktop Protocol Implementation  | 
3  |  |  * ClearCodec Bitmap Compression  | 
4  |  |  *  | 
5  |  |  * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>  | 
6  |  |  * Copyright 2016 Armin Novak <armin.novak@thincast.com>  | 
7  |  |  * Copyright 2016 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/codec/color.h>  | 
29  |  | #include <freerdp/codec/clear.h>  | 
30  |  | #include <freerdp/log.h>  | 
31  |  |  | 
32  |  | #define TAG FREERDP_TAG("codec.clear") | 
33  |  |  | 
34  | 24.7k  | #define CLEARCODEC_FLAG_GLYPH_INDEX 0x01  | 
35  | 23.9k  | #define CLEARCODEC_FLAG_GLYPH_HIT 0x02  | 
36  | 17.1k  | #define CLEARCODEC_FLAG_CACHE_RESET 0x04  | 
37  |  |  | 
38  | 6.56M  | #define CLEARCODEC_VBAR_SIZE 32768  | 
39  | 1.08M  | #define CLEARCODEC_VBAR_SHORT_SIZE 16384  | 
40  |  |  | 
41  |  | typedef struct  | 
42  |  | { | 
43  |  |   UINT32 size;  | 
44  |  |   UINT32 count;  | 
45  |  |   UINT32* pixels;  | 
46  |  | } CLEAR_GLYPH_ENTRY;  | 
47  |  |  | 
48  |  | typedef struct  | 
49  |  | { | 
50  |  |   UINT32 size;  | 
51  |  |   UINT32 count;  | 
52  |  |   BYTE* pixels;  | 
53  |  | } CLEAR_VBAR_ENTRY;  | 
54  |  |  | 
55  |  | struct S_CLEAR_CONTEXT  | 
56  |  | { | 
57  |  |   BOOL Compressor;  | 
58  |  |   NSC_CONTEXT* nsc;  | 
59  |  |   UINT32 seqNumber;  | 
60  |  |   BYTE* TempBuffer;  | 
61  |  |   UINT32 TempSize;  | 
62  |  |   UINT32 nTempStep;  | 
63  |  |   UINT32 TempFormat;  | 
64  |  |   UINT32 format;  | 
65  |  |   CLEAR_GLYPH_ENTRY GlyphCache[4000];  | 
66  |  |   UINT32 VBarStorageCursor;  | 
67  |  |   CLEAR_VBAR_ENTRY VBarStorage[CLEARCODEC_VBAR_SIZE];  | 
68  |  |   UINT32 ShortVBarStorageCursor;  | 
69  |  |   CLEAR_VBAR_ENTRY ShortVBarStorage[CLEARCODEC_VBAR_SHORT_SIZE];  | 
70  |  | };  | 
71  |  |  | 
72  |  | static const UINT32 CLEAR_LOG2_FLOOR[256] = { | 
73  |  |   0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,  | 
74  |  |   5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,  | 
75  |  |   6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,  | 
76  |  |   6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,  | 
77  |  |   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,  | 
78  |  |   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,  | 
79  |  |   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,  | 
80  |  |   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7  | 
81  |  | };  | 
82  |  |  | 
83  |  | static const BYTE CLEAR_8BIT_MASKS[9] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF }; | 
84  |  |  | 
85  |  | static void clear_reset_vbar_storage(CLEAR_CONTEXT* clear, BOOL zero)  | 
86  | 21.0k  | { | 
87  | 21.0k  |   if (zero)  | 
88  | 17.1k  |   { | 
89  | 561M  |     for (size_t i = 0; i < ARRAYSIZE(clear->VBarStorage); i++)  | 
90  | 561M  |       winpr_aligned_free(clear->VBarStorage[i].pixels);  | 
91  |  |  | 
92  | 17.1k  |     ZeroMemory(clear->VBarStorage, sizeof(clear->VBarStorage));  | 
93  | 17.1k  |   }  | 
94  |  |  | 
95  | 21.0k  |   clear->VBarStorageCursor = 0;  | 
96  |  |  | 
97  | 21.0k  |   if (zero)  | 
98  | 17.1k  |   { | 
99  | 280M  |     for (size_t i = 0; i < ARRAYSIZE(clear->ShortVBarStorage); i++)  | 
100  | 280M  |       winpr_aligned_free(clear->ShortVBarStorage[i].pixels);  | 
101  |  |  | 
102  | 17.1k  |     ZeroMemory(clear->ShortVBarStorage, sizeof(clear->ShortVBarStorage));  | 
103  | 17.1k  |   }  | 
104  |  |  | 
105  | 21.0k  |   clear->ShortVBarStorageCursor = 0;  | 
106  | 21.0k  | }  | 
107  |  |  | 
108  |  | static void clear_reset_glyph_cache(CLEAR_CONTEXT* clear)  | 
109  | 17.1k  | { | 
110  | 68.5M  |   for (size_t i = 0; i < ARRAYSIZE(clear->GlyphCache); i++)  | 
111  | 68.5M  |     winpr_aligned_free(clear->GlyphCache[i].pixels);  | 
112  |  |  | 
113  | 17.1k  |   ZeroMemory(clear->GlyphCache, sizeof(clear->GlyphCache));  | 
114  | 17.1k  | }  | 
115  |  |  | 
116  |  | static BOOL convert_color(BYTE* dst, UINT32 nDstStep, UINT32 DstFormat, UINT32 nXDst, UINT32 nYDst,  | 
117  |  |                           UINT32 nWidth, UINT32 nHeight, const BYTE* src, UINT32 nSrcStep,  | 
118  |  |                           UINT32 SrcFormat, UINT32 nDstWidth, UINT32 nDstHeight,  | 
119  |  |                           const gdiPalette* palette)  | 
120  | 2.88k  | { | 
121  | 2.88k  |   if (nWidth + nXDst > nDstWidth)  | 
122  | 0  |     nWidth = nDstWidth - nXDst;  | 
123  |  |  | 
124  | 2.88k  |   if (nHeight + nYDst > nDstHeight)  | 
125  | 0  |     nHeight = nDstHeight - nYDst;  | 
126  |  |  | 
127  | 2.88k  |   return freerdp_image_copy(dst, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, src,  | 
128  | 2.88k  |                             SrcFormat, nSrcStep, 0, 0, palette, FREERDP_KEEP_DST_ALPHA);  | 
129  | 2.88k  | }  | 
130  |  |  | 
131  |  | static BOOL clear_decompress_nscodec(NSC_CONTEXT* nsc, UINT32 width, UINT32 height, wStream* s,  | 
132  |  |                                      UINT32 bitmapDataByteCount, BYTE* pDstData, UINT32 DstFormat,  | 
133  |  |                                      UINT32 nDstStep, UINT32 nXDstRel, UINT32 nYDstRel)  | 
134  | 605  | { | 
135  | 605  |   BOOL rc = 0;  | 
136  |  |  | 
137  | 605  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, bitmapDataByteCount))  | 
138  | 0  |     return FALSE;  | 
139  |  |  | 
140  | 605  |   rc = nsc_process_message(nsc, 32, width, height, Stream_Pointer(s), bitmapDataByteCount,  | 
141  | 605  |                            pDstData, DstFormat, nDstStep, nXDstRel, nYDstRel, width, height,  | 
142  | 605  |                            FREERDP_FLIP_NONE);  | 
143  | 605  |   Stream_Seek(s, bitmapDataByteCount);  | 
144  | 605  |   return rc;  | 
145  | 605  | }  | 
146  |  |  | 
147  |  | static BOOL clear_decompress_subcode_rlex(wStream* s, UINT32 bitmapDataByteCount, UINT32 width,  | 
148  |  |                                           UINT32 height, BYTE* pDstData, UINT32 DstFormat,  | 
149  |  |                                           UINT32 nDstStep, UINT32 nXDstRel, UINT32 nYDstRel,  | 
150  |  |                                           UINT32 nDstWidth, UINT32 nDstHeight)  | 
151  | 630  | { | 
152  | 630  |   UINT32 x = 0;  | 
153  | 630  |   UINT32 y = 0;  | 
154  | 630  |   UINT32 pixelCount = 0;  | 
155  | 630  |   UINT32 bitmapDataOffset = 0;  | 
156  | 630  |   size_t pixelIndex = 0;  | 
157  | 630  |   UINT32 numBits = 0;  | 
158  | 630  |   BYTE startIndex = 0;  | 
159  | 630  |   BYTE stopIndex = 0;  | 
160  | 630  |   BYTE suiteIndex = 0;  | 
161  | 630  |   BYTE suiteDepth = 0;  | 
162  | 630  |   BYTE paletteCount = 0;  | 
163  | 630  |   UINT32 palette[128] = { 0 }; | 
164  |  |  | 
165  | 630  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, bitmapDataByteCount))  | 
166  | 0  |     return FALSE;  | 
167  |  |  | 
168  | 630  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
169  | 6  |     return FALSE;  | 
170  | 624  |   Stream_Read_UINT8(s, paletteCount);  | 
171  | 624  |   bitmapDataOffset = 1 + (paletteCount * 3);  | 
172  |  |  | 
173  | 624  |   if ((paletteCount > 127) || (paletteCount < 1))  | 
174  | 12  |   { | 
175  | 12  |     WLog_ERR(TAG, "paletteCount %" PRIu8 "", paletteCount);  | 
176  | 12  |     return FALSE;  | 
177  | 12  |   }  | 
178  |  |  | 
179  | 612  |   if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, paletteCount, 3ull))  | 
180  | 6  |     return FALSE;  | 
181  |  |  | 
182  | 4.75k  |   for (UINT32 i = 0; i < paletteCount; i++)  | 
183  | 4.14k  |   { | 
184  | 4.14k  |     BYTE r = 0;  | 
185  | 4.14k  |     BYTE g = 0;  | 
186  | 4.14k  |     BYTE b = 0;  | 
187  | 4.14k  |     Stream_Read_UINT8(s, b);  | 
188  | 4.14k  |     Stream_Read_UINT8(s, g);  | 
189  | 4.14k  |     Stream_Read_UINT8(s, r);  | 
190  | 4.14k  |     palette[i] = FreeRDPGetColor(DstFormat, r, g, b, 0xFF);  | 
191  | 4.14k  |   }  | 
192  |  |  | 
193  | 606  |   pixelIndex = 0;  | 
194  | 606  |   pixelCount = width * height;  | 
195  | 606  |   numBits = CLEAR_LOG2_FLOOR[paletteCount - 1] + 1;  | 
196  |  |  | 
197  | 1.48k  |   while (bitmapDataOffset < bitmapDataByteCount)  | 
198  | 1.36k  |   { | 
199  | 1.36k  |     UINT32 tmp = 0;  | 
200  | 1.36k  |     UINT32 color = 0;  | 
201  | 1.36k  |     UINT32 runLengthFactor = 0;  | 
202  |  |  | 
203  | 1.36k  |     if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))  | 
204  | 20  |       return FALSE;  | 
205  |  |  | 
206  | 1.34k  |     Stream_Read_UINT8(s, tmp);  | 
207  | 1.34k  |     Stream_Read_UINT8(s, runLengthFactor);  | 
208  | 1.34k  |     bitmapDataOffset += 2;  | 
209  | 1.34k  |     suiteDepth = (tmp >> numBits) & CLEAR_8BIT_MASKS[(8 - numBits)];  | 
210  | 1.34k  |     stopIndex = tmp & CLEAR_8BIT_MASKS[numBits];  | 
211  | 1.34k  |     startIndex = stopIndex - suiteDepth;  | 
212  |  |  | 
213  | 1.34k  |     if (runLengthFactor >= 0xFF)  | 
214  | 327  |     { | 
215  | 327  |       if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))  | 
216  | 7  |         return FALSE;  | 
217  |  |  | 
218  | 320  |       Stream_Read_UINT16(s, runLengthFactor);  | 
219  | 320  |       bitmapDataOffset += 2;  | 
220  |  |  | 
221  | 320  |       if (runLengthFactor >= 0xFFFF)  | 
222  | 225  |       { | 
223  | 225  |         if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))  | 
224  | 9  |           return FALSE;  | 
225  |  |  | 
226  | 216  |         Stream_Read_UINT32(s, runLengthFactor);  | 
227  | 216  |         bitmapDataOffset += 4;  | 
228  | 216  |       }  | 
229  | 320  |     }  | 
230  |  |  | 
231  | 1.32k  |     if (startIndex >= paletteCount)  | 
232  | 196  |     { | 
233  | 196  |       WLog_ERR(TAG, "startIndex %" PRIu8 " > paletteCount %" PRIu8 "]", startIndex,  | 
234  | 196  |                paletteCount);  | 
235  | 196  |       return FALSE;  | 
236  | 196  |     }  | 
237  |  |  | 
238  | 1.13k  |     if (stopIndex >= paletteCount)  | 
239  | 23  |     { | 
240  | 23  |       WLog_ERR(TAG, "stopIndex %" PRIu8 " > paletteCount %" PRIu8 "]", stopIndex,  | 
241  | 23  |                paletteCount);  | 
242  | 23  |       return FALSE;  | 
243  | 23  |     }  | 
244  |  |  | 
245  | 1.10k  |     suiteIndex = startIndex;  | 
246  |  |  | 
247  | 1.10k  |     if (suiteIndex > 127)  | 
248  | 0  |     { | 
249  | 0  |       WLog_ERR(TAG, "suiteIndex %" PRIu8 " > 127]", suiteIndex);  | 
250  | 0  |       return FALSE;  | 
251  | 0  |     }  | 
252  |  |  | 
253  | 1.10k  |     color = palette[suiteIndex];  | 
254  |  |  | 
255  | 1.10k  |     if ((pixelIndex + runLengthFactor) > pixelCount)  | 
256  | 217  |     { | 
257  | 217  |       WLog_ERR(TAG,  | 
258  | 217  |                "pixelIndex %" PRIu32 " + runLengthFactor %" PRIu32 " > pixelCount %" PRIu32  | 
259  | 217  |                "",  | 
260  | 217  |                pixelIndex, runLengthFactor, pixelCount);  | 
261  | 217  |       return FALSE;  | 
262  | 217  |     }  | 
263  |  |  | 
264  | 17.4k  |     for (UINT32 i = 0; i < runLengthFactor; i++)  | 
265  | 16.5k  |     { | 
266  | 16.5k  |       BYTE* pTmpData = &pDstData[(nXDstRel + x) * FreeRDPGetBytesPerPixel(DstFormat) +  | 
267  | 16.5k  |                                  (nYDstRel + y) * nDstStep];  | 
268  |  |  | 
269  | 16.5k  |       if ((nXDstRel + x < nDstWidth) && (nYDstRel + y < nDstHeight))  | 
270  | 16.5k  |         FreeRDPWriteColor(pTmpData, DstFormat, color);  | 
271  |  |  | 
272  | 16.5k  |       if (++x >= width)  | 
273  | 439  |       { | 
274  | 439  |         y++;  | 
275  | 439  |         x = 0;  | 
276  | 439  |       }  | 
277  | 16.5k  |     }  | 
278  |  |  | 
279  | 891  |     pixelIndex += runLengthFactor;  | 
280  |  |  | 
281  | 891  |     if ((pixelIndex + (suiteDepth + 1)) > pixelCount)  | 
282  | 16  |     { | 
283  | 16  |       WLog_ERR(TAG,  | 
284  | 16  |                "pixelIndex %" PRIu32 " + suiteDepth %" PRIu8 " + 1 > pixelCount %" PRIu32 "",  | 
285  | 16  |                pixelIndex, suiteDepth, pixelCount);  | 
286  | 16  |       return FALSE;  | 
287  | 16  |     }  | 
288  |  |  | 
289  | 2.34k  |     for (UINT32 i = 0; i <= suiteDepth; i++)  | 
290  | 1.46k  |     { | 
291  | 1.46k  |       BYTE* pTmpData = &pDstData[(nXDstRel + x) * FreeRDPGetBytesPerPixel(DstFormat) +  | 
292  | 1.46k  |                                  (nYDstRel + y) * nDstStep];  | 
293  | 1.46k  |       UINT32 ccolor = palette[suiteIndex];  | 
294  |  |  | 
295  | 1.46k  |       if (suiteIndex > 127)  | 
296  | 0  |       { | 
297  | 0  |         WLog_ERR(TAG, "suiteIndex %" PRIu8 " > 127", suiteIndex);  | 
298  | 0  |         return FALSE;  | 
299  | 0  |       }  | 
300  |  |  | 
301  | 1.46k  |       suiteIndex++;  | 
302  |  |  | 
303  | 1.46k  |       if ((nXDstRel + x < nDstWidth) && (nYDstRel + y < nDstHeight))  | 
304  | 1.46k  |         FreeRDPWriteColor(pTmpData, DstFormat, ccolor);  | 
305  |  |  | 
306  | 1.46k  |       if (++x >= width)  | 
307  | 134  |       { | 
308  | 134  |         y++;  | 
309  | 134  |         x = 0;  | 
310  | 134  |       }  | 
311  | 1.46k  |     }  | 
312  |  |  | 
313  | 875  |     pixelIndex += (suiteDepth + 1);  | 
314  | 875  |   }  | 
315  |  |  | 
316  | 118  |   if (pixelIndex != pixelCount)  | 
317  | 68  |   { | 
318  | 68  |     WLog_ERR(TAG, "pixelIndex %" PRIdz " != pixelCount %" PRIu32 "", pixelIndex, pixelCount);  | 
319  | 68  |     return FALSE;  | 
320  | 68  |   }  | 
321  |  |  | 
322  | 50  |   return TRUE;  | 
323  | 118  | }  | 
324  |  |  | 
325  |  | static BOOL clear_resize_buffer(CLEAR_CONTEXT* clear, UINT32 width, UINT32 height)  | 
326  | 22.2k  | { | 
327  | 22.2k  |   UINT32 size = 0;  | 
328  |  |  | 
329  | 22.2k  |   if (!clear)  | 
330  | 0  |     return FALSE;  | 
331  |  |  | 
332  | 22.2k  |   size = ((width + 16) * (height + 16) * FreeRDPGetBytesPerPixel(clear->format));  | 
333  |  |  | 
334  | 22.2k  |   if (size > clear->TempSize)  | 
335  | 17.1k  |   { | 
336  | 17.1k  |     BYTE* tmp = (BYTE*)winpr_aligned_recalloc(clear->TempBuffer, size, sizeof(BYTE), 32);  | 
337  |  |  | 
338  | 17.1k  |     if (!tmp)  | 
339  | 0  |     { | 
340  | 0  |       WLog_ERR(TAG, "clear->TempBuffer winpr_aligned_recalloc failed for %" PRIu32 " bytes",  | 
341  | 0  |                size);  | 
342  | 0  |       return FALSE;  | 
343  | 0  |     }  | 
344  |  |  | 
345  | 17.1k  |     clear->TempSize = size;  | 
346  | 17.1k  |     clear->TempBuffer = tmp;  | 
347  | 17.1k  |   }  | 
348  |  |  | 
349  | 22.2k  |   return TRUE;  | 
350  | 22.2k  | }  | 
351  |  |  | 
352  |  | static BOOL clear_decompress_residual_data(CLEAR_CONTEXT* clear, wStream* s,  | 
353  |  |                                            UINT32 residualByteCount, UINT32 nWidth, UINT32 nHeight,  | 
354  |  |                                            BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep,  | 
355  |  |                                            UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,  | 
356  |  |                                            UINT32 nDstHeight, const gdiPalette* palette)  | 
357  | 4.42k  | { | 
358  | 4.42k  |   UINT32 nSrcStep = 0;  | 
359  | 4.42k  |   UINT32 suboffset = 0;  | 
360  | 4.42k  |   BYTE* dstBuffer = NULL;  | 
361  | 4.42k  |   UINT32 pixelIndex = 0;  | 
362  | 4.42k  |   UINT32 pixelCount = 0;  | 
363  |  |  | 
364  | 4.42k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, residualByteCount))  | 
365  | 3.47k  |     return FALSE;  | 
366  |  |  | 
367  | 945  |   suboffset = 0;  | 
368  | 945  |   pixelIndex = 0;  | 
369  | 945  |   pixelCount = nWidth * nHeight;  | 
370  |  |  | 
371  | 945  |   if (!clear_resize_buffer(clear, nWidth, nHeight))  | 
372  | 0  |     return FALSE;  | 
373  |  |  | 
374  | 945  |   dstBuffer = clear->TempBuffer;  | 
375  |  |  | 
376  | 147k  |   while (suboffset < residualByteCount)  | 
377  | 147k  |   { | 
378  | 147k  |     BYTE r = 0;  | 
379  | 147k  |     BYTE g = 0;  | 
380  | 147k  |     BYTE b = 0;  | 
381  | 147k  |     UINT32 runLengthFactor = 0;  | 
382  | 147k  |     UINT32 color = 0;  | 
383  |  |  | 
384  | 147k  |     if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))  | 
385  | 26  |       return FALSE;  | 
386  |  |  | 
387  | 147k  |     Stream_Read_UINT8(s, b);  | 
388  | 147k  |     Stream_Read_UINT8(s, g);  | 
389  | 147k  |     Stream_Read_UINT8(s, r);  | 
390  | 147k  |     Stream_Read_UINT8(s, runLengthFactor);  | 
391  | 147k  |     suboffset += 4;  | 
392  | 147k  |     color = FreeRDPGetColor(clear->format, r, g, b, 0xFF);  | 
393  |  |  | 
394  | 147k  |     if (runLengthFactor >= 0xFF)  | 
395  | 795  |     { | 
396  | 795  |       if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))  | 
397  | 12  |         return FALSE;  | 
398  |  |  | 
399  | 783  |       Stream_Read_UINT16(s, runLengthFactor);  | 
400  | 783  |       suboffset += 2;  | 
401  |  |  | 
402  | 783  |       if (runLengthFactor >= 0xFFFF)  | 
403  | 298  |       { | 
404  | 298  |         if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))  | 
405  | 9  |           return FALSE;  | 
406  |  |  | 
407  | 289  |         Stream_Read_UINT32(s, runLengthFactor);  | 
408  | 289  |         suboffset += 4;  | 
409  | 289  |       }  | 
410  | 783  |     }  | 
411  |  |  | 
412  | 147k  |     if ((pixelIndex >= pixelCount) || (runLengthFactor > (pixelCount - pixelIndex)))  | 
413  | 657  |     { | 
414  | 657  |       WLog_ERR(TAG,  | 
415  | 657  |                "pixelIndex %" PRIu32 " + runLengthFactor %" PRIu32 " > pixelCount %" PRIu32  | 
416  | 657  |                "",  | 
417  | 657  |                pixelIndex, runLengthFactor, pixelCount);  | 
418  | 657  |       return FALSE;  | 
419  | 657  |     }  | 
420  |  |  | 
421  | 423k  |     for (UINT32 i = 0; i < runLengthFactor; i++)  | 
422  | 276k  |     { | 
423  | 276k  |       FreeRDPWriteColor(dstBuffer, clear->format, color);  | 
424  | 276k  |       dstBuffer += FreeRDPGetBytesPerPixel(clear->format);  | 
425  | 276k  |     }  | 
426  |  |  | 
427  | 146k  |     pixelIndex += runLengthFactor;  | 
428  | 146k  |   }  | 
429  |  |  | 
430  | 241  |   nSrcStep = nWidth * FreeRDPGetBytesPerPixel(clear->format);  | 
431  |  |  | 
432  | 241  |   if (pixelIndex != pixelCount)  | 
433  | 226  |   { | 
434  | 226  |     WLog_ERR(TAG, "pixelIndex %" PRIu32 " != pixelCount %" PRIu32 "", pixelIndex, pixelCount);  | 
435  | 226  |     return FALSE;  | 
436  | 226  |   }  | 
437  |  |  | 
438  | 15  |   return convert_color(pDstData, nDstStep, DstFormat, nXDst, nYDst, nWidth, nHeight,  | 
439  | 15  |                        clear->TempBuffer, nSrcStep, clear->format, nDstWidth, nDstHeight,  | 
440  | 15  |                        palette);  | 
441  | 241  | }  | 
442  |  |  | 
443  |  | static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* clear, wStream* s,  | 
444  |  |                                             UINT32 subcodecByteCount, UINT32 nWidth, UINT32 nHeight,  | 
445  |  |                                             BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep,  | 
446  |  |                                             UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,  | 
447  |  |                                             UINT32 nDstHeight, const gdiPalette* palette)  | 
448  | 2.65k  | { | 
449  | 2.65k  |   UINT16 xStart = 0;  | 
450  | 2.65k  |   UINT16 yStart = 0;  | 
451  | 2.65k  |   UINT16 width = 0;  | 
452  | 2.65k  |   UINT16 height = 0;  | 
453  | 2.65k  |   UINT32 bitmapDataByteCount = 0;  | 
454  | 2.65k  |   BYTE subcodecId = 0;  | 
455  | 2.65k  |   UINT32 suboffset = 0;  | 
456  |  |  | 
457  | 2.65k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, subcodecByteCount))  | 
458  | 222  |     return FALSE;  | 
459  |  |  | 
460  | 2.43k  |   suboffset = 0;  | 
461  |  |  | 
462  | 5.61k  |   while (suboffset < subcodecByteCount)  | 
463  | 5.25k  |   { | 
464  | 5.25k  |     UINT32 nXDstRel = 0;  | 
465  | 5.25k  |     UINT32 nYDstRel = 0;  | 
466  |  |  | 
467  | 5.25k  |     if (!Stream_CheckAndLogRequiredLength(TAG, s, 13))  | 
468  | 22  |       return FALSE;  | 
469  |  |  | 
470  | 5.23k  |     Stream_Read_UINT16(s, xStart);  | 
471  | 5.23k  |     Stream_Read_UINT16(s, yStart);  | 
472  | 5.23k  |     Stream_Read_UINT16(s, width);  | 
473  | 5.23k  |     Stream_Read_UINT16(s, height);  | 
474  | 5.23k  |     Stream_Read_UINT32(s, bitmapDataByteCount);  | 
475  | 5.23k  |     Stream_Read_UINT8(s, subcodecId);  | 
476  | 5.23k  |     suboffset += 13;  | 
477  |  |  | 
478  | 5.23k  |     if (!Stream_CheckAndLogRequiredLength(TAG, s, bitmapDataByteCount))  | 
479  | 95  |       return FALSE;  | 
480  |  |  | 
481  | 5.14k  |     nXDstRel = nXDst + xStart;  | 
482  | 5.14k  |     nYDstRel = nYDst + yStart;  | 
483  |  |  | 
484  | 5.14k  |     if (1ull * xStart + width > nWidth)  | 
485  | 650  |     { | 
486  | 650  |       WLog_ERR(TAG, "xStart %" PRIu16 " + width %" PRIu16 " > nWidth %" PRIu32 "", xStart,  | 
487  | 650  |                width, nWidth);  | 
488  | 650  |       return FALSE;  | 
489  | 650  |     }  | 
490  | 4.49k  |     if (1ull * yStart + height > nHeight)  | 
491  | 301  |     { | 
492  | 301  |       WLog_ERR(TAG, "yStart %" PRIu16 " + height %" PRIu16 " > nHeight %" PRIu32 "", yStart,  | 
493  | 301  |                height, nHeight);  | 
494  | 301  |       return FALSE;  | 
495  | 301  |     }  | 
496  |  |  | 
497  | 4.18k  |     if (!clear_resize_buffer(clear, width, height))  | 
498  | 0  |       return FALSE;  | 
499  |  |  | 
500  | 4.18k  |     switch (subcodecId)  | 
501  | 4.18k  |     { | 
502  | 2.93k  |       case 0: /* Uncompressed */  | 
503  | 2.93k  |       { | 
504  | 2.93k  |         const UINT32 nSrcStep = width * FreeRDPGetBytesPerPixel(PIXEL_FORMAT_BGR24);  | 
505  | 2.93k  |         const size_t nSrcSize = 1ull * nSrcStep * height;  | 
506  |  |  | 
507  | 2.93k  |         if (bitmapDataByteCount != nSrcSize)  | 
508  | 61  |         { | 
509  | 61  |           WLog_ERR(TAG, "bitmapDataByteCount %" PRIu32 " != nSrcSize %" PRIuz "",  | 
510  | 61  |                    bitmapDataByteCount, nSrcSize);  | 
511  | 61  |           return FALSE;  | 
512  | 61  |         }  | 
513  |  |  | 
514  | 2.87k  |         if (!convert_color(pDstData, nDstStep, DstFormat, nXDstRel, nYDstRel, width, height,  | 
515  | 2.87k  |                            Stream_Pointer(s), nSrcStep, PIXEL_FORMAT_BGR24, nDstWidth,  | 
516  | 2.87k  |                            nDstHeight, palette))  | 
517  | 0  |           return FALSE;  | 
518  |  |  | 
519  | 2.87k  |         Stream_Seek(s, bitmapDataByteCount);  | 
520  | 2.87k  |       }  | 
521  | 0  |       break;  | 
522  |  |  | 
523  | 605  |       case 1: /* NSCodec */  | 
524  | 605  |         if (!clear_decompress_nscodec(clear->nsc, width, height, s, bitmapDataByteCount,  | 
525  | 605  |                                       pDstData, DstFormat, nDstStep, nXDstRel, nYDstRel))  | 
526  | 344  |           return FALSE;  | 
527  |  |  | 
528  | 261  |         break;  | 
529  |  |  | 
530  | 630  |       case 2: /* CLEARCODEC_SUBCODEC_RLEX */  | 
531  | 630  |         if (!clear_decompress_subcode_rlex(s, bitmapDataByteCount, width, height, pDstData,  | 
532  | 630  |                                            DstFormat, nDstStep, nXDstRel, nYDstRel,  | 
533  | 630  |                                            nDstWidth, nDstHeight))  | 
534  | 580  |           return FALSE;  | 
535  |  |  | 
536  | 50  |         break;  | 
537  |  |  | 
538  | 50  |       default:  | 
539  | 22  |         WLog_ERR(TAG, "Unknown subcodec ID %" PRIu8 "", subcodecId);  | 
540  | 22  |         return FALSE;  | 
541  | 4.18k  |     }  | 
542  |  |  | 
543  | 3.18k  |     suboffset += bitmapDataByteCount;  | 
544  | 3.18k  |   }  | 
545  |  |  | 
546  | 355  |   return TRUE;  | 
547  | 2.43k  | }  | 
548  |  |  | 
549  |  | static BOOL resize_vbar_entry(CLEAR_CONTEXT* clear, CLEAR_VBAR_ENTRY* vBarEntry)  | 
550  | 3.82M  | { | 
551  | 3.82M  |   if (vBarEntry->count > vBarEntry->size)  | 
552  | 3.13M  |   { | 
553  | 3.13M  |     const UINT32 bpp = FreeRDPGetBytesPerPixel(clear->format);  | 
554  | 3.13M  |     const UINT32 oldPos = vBarEntry->size * bpp;  | 
555  | 3.13M  |     const UINT32 diffSize = (vBarEntry->count - vBarEntry->size) * bpp;  | 
556  |  |  | 
557  | 3.13M  |     vBarEntry->size = vBarEntry->count;  | 
558  | 3.13M  |     BYTE* tmp =  | 
559  | 3.13M  |         (BYTE*)winpr_aligned_recalloc(vBarEntry->pixels, vBarEntry->count, 1ull * bpp, 32);  | 
560  |  |  | 
561  | 3.13M  |     if (!tmp)  | 
562  | 0  |     { | 
563  | 0  |       WLog_ERR(TAG, "vBarEntry->pixels winpr_aligned_recalloc %" PRIu32 " failed",  | 
564  | 0  |                vBarEntry->count * bpp);  | 
565  | 0  |       return FALSE;  | 
566  | 0  |     }  | 
567  |  |  | 
568  | 3.13M  |     memset(&tmp[oldPos], 0, diffSize);  | 
569  | 3.13M  |     vBarEntry->pixels = tmp;  | 
570  | 3.13M  |   }  | 
571  |  |  | 
572  | 3.82M  |   if (!vBarEntry->pixels && vBarEntry->size)  | 
573  | 0  |   { | 
574  | 0  |     WLog_ERR(TAG, "vBarEntry->pixels is NULL but vBarEntry->size is %" PRIu32 "",  | 
575  | 0  |              vBarEntry->size);  | 
576  | 0  |     return FALSE;  | 
577  | 0  |   }  | 
578  |  |  | 
579  | 3.82M  |   return TRUE;  | 
580  | 3.82M  | }  | 
581  |  |  | 
582  |  | static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 bandsByteCount,  | 
583  |  |                                         UINT32 nWidth, UINT32 nHeight, BYTE* pDstData,  | 
584  |  |                                         UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,  | 
585  |  |                                         UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight)  | 
586  | 2.56k  | { | 
587  | 2.56k  |   UINT32 suboffset = 0;  | 
588  |  |  | 
589  | 2.56k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, bandsByteCount))  | 
590  | 797  |     return FALSE;  | 
591  |  |  | 
592  | 2.75k  |   while (suboffset < bandsByteCount)  | 
593  | 2.53k  |   { | 
594  | 2.53k  |     BYTE cr = 0;  | 
595  | 2.53k  |     BYTE cg = 0;  | 
596  | 2.53k  |     BYTE cb = 0;  | 
597  | 2.53k  |     UINT16 xStart = 0;  | 
598  | 2.53k  |     UINT16 xEnd = 0;  | 
599  | 2.53k  |     UINT16 yStart = 0;  | 
600  | 2.53k  |     UINT16 yEnd = 0;  | 
601  | 2.53k  |     UINT32 colorBkg = 0;  | 
602  | 2.53k  |     UINT16 vBarHeader = 0;  | 
603  | 2.53k  |     UINT16 vBarYOn = 0;  | 
604  | 2.53k  |     UINT16 vBarYOff = 0;  | 
605  | 2.53k  |     UINT32 vBarCount = 0;  | 
606  | 2.53k  |     UINT32 vBarPixelCount = 0;  | 
607  | 2.53k  |     UINT32 vBarShortPixelCount = 0;  | 
608  |  |  | 
609  | 2.53k  |     if (!Stream_CheckAndLogRequiredLength(TAG, s, 11))  | 
610  | 20  |       return FALSE;  | 
611  |  |  | 
612  | 2.51k  |     Stream_Read_UINT16(s, xStart);  | 
613  | 2.51k  |     Stream_Read_UINT16(s, xEnd);  | 
614  | 2.51k  |     Stream_Read_UINT16(s, yStart);  | 
615  | 2.51k  |     Stream_Read_UINT16(s, yEnd);  | 
616  | 2.51k  |     Stream_Read_UINT8(s, cb);  | 
617  | 2.51k  |     Stream_Read_UINT8(s, cg);  | 
618  | 2.51k  |     Stream_Read_UINT8(s, cr);  | 
619  | 2.51k  |     suboffset += 11;  | 
620  | 2.51k  |     colorBkg = FreeRDPGetColor(clear->format, cr, cg, cb, 0xFF);  | 
621  |  |  | 
622  | 2.51k  |     if (xEnd < xStart)  | 
623  | 63  |     { | 
624  | 63  |       WLog_ERR(TAG, "xEnd %" PRIu16 " < xStart %" PRIu16 "", xEnd, xStart);  | 
625  | 63  |       return FALSE;  | 
626  | 63  |     }  | 
627  |  |  | 
628  | 2.45k  |     if (yEnd < yStart)  | 
629  | 72  |     { | 
630  | 72  |       WLog_ERR(TAG, "yEnd %" PRIu16 " < yStart %" PRIu16 "", yEnd, yStart);  | 
631  | 72  |       return FALSE;  | 
632  | 72  |     }  | 
633  |  |  | 
634  | 2.38k  |     vBarCount = (xEnd - xStart) + 1;  | 
635  |  |  | 
636  | 3.30M  |     for (UINT32 i = 0; i < vBarCount; i++)  | 
637  | 3.30M  |     { | 
638  | 3.30M  |       UINT32 vBarHeight = 0;  | 
639  | 3.30M  |       CLEAR_VBAR_ENTRY* vBarEntry = NULL;  | 
640  | 3.30M  |       CLEAR_VBAR_ENTRY* vBarShortEntry = NULL;  | 
641  | 3.30M  |       BOOL vBarUpdate = FALSE;  | 
642  | 3.30M  |       const BYTE* cpSrcPixel = NULL;  | 
643  |  |  | 
644  | 3.30M  |       if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))  | 
645  | 558  |         return FALSE;  | 
646  |  |  | 
647  | 3.30M  |       Stream_Read_UINT16(s, vBarHeader);  | 
648  | 3.30M  |       suboffset += 2;  | 
649  | 3.30M  |       vBarHeight = (yEnd - yStart + 1);  | 
650  |  |  | 
651  | 3.30M  |       if (vBarHeight > 52)  | 
652  | 51  |       { | 
653  | 51  |         WLog_ERR(TAG, "vBarHeight (%" PRIu32 ") > 52", vBarHeight);  | 
654  | 51  |         return FALSE;  | 
655  | 51  |       }  | 
656  |  |  | 
657  | 3.30M  |       if ((vBarHeader & 0xC000) == 0x4000) /* SHORT_VBAR_CACHE_HIT */  | 
658  | 2.74M  |       { | 
659  | 2.74M  |         const UINT16 vBarIndex = (vBarHeader & 0x3FFF);  | 
660  | 2.74M  |         vBarShortEntry = &(clear->ShortVBarStorage[vBarIndex]);  | 
661  |  |  | 
662  | 2.74M  |         if (!vBarShortEntry)  | 
663  | 0  |         { | 
664  | 0  |           WLog_ERR(TAG, "missing vBarShortEntry %" PRIu16 "", vBarIndex);  | 
665  | 0  |           return FALSE;  | 
666  | 0  |         }  | 
667  |  |  | 
668  | 2.74M  |         if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
669  | 45  |           return FALSE;  | 
670  |  |  | 
671  | 2.74M  |         Stream_Read_UINT8(s, vBarYOn);  | 
672  | 2.74M  |         suboffset += 1;  | 
673  | 2.74M  |         vBarShortPixelCount = vBarShortEntry->count;  | 
674  | 2.74M  |         vBarUpdate = TRUE;  | 
675  | 2.74M  |       }  | 
676  | 559k  |       else if ((vBarHeader & 0xC000) == 0x0000) /* SHORT_VBAR_CACHE_MISS */  | 
677  | 542k  |       { | 
678  | 542k  |         vBarYOn = (vBarHeader & 0xFF);  | 
679  | 542k  |         vBarYOff = ((vBarHeader >> 8) & 0x3F);  | 
680  |  |  | 
681  | 542k  |         if (vBarYOff < vBarYOn)  | 
682  | 349  |         { | 
683  | 349  |           WLog_ERR(TAG, "vBarYOff %" PRIu16 " < vBarYOn %" PRIu16 "", vBarYOff, vBarYOn);  | 
684  | 349  |           return FALSE;  | 
685  | 349  |         }  | 
686  |  |  | 
687  | 542k  |         vBarShortPixelCount = (vBarYOff - vBarYOn);  | 
688  |  |  | 
689  | 542k  |         if (vBarShortPixelCount > 52)  | 
690  | 14  |         { | 
691  | 14  |           WLog_ERR(TAG, "vBarShortPixelCount %" PRIu32 " > 52", vBarShortPixelCount);  | 
692  | 14  |           return FALSE;  | 
693  | 14  |         }  | 
694  |  |  | 
695  | 542k  |         if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, vBarShortPixelCount, 3ull))  | 
696  | 60  |           return FALSE;  | 
697  |  |  | 
698  | 541k  |         if (clear->ShortVBarStorageCursor >= CLEARCODEC_VBAR_SHORT_SIZE)  | 
699  | 0  |         { | 
700  | 0  |           WLog_ERR(TAG,  | 
701  | 0  |                    "clear->ShortVBarStorageCursor %" PRIu32  | 
702  | 0  |                    " >= CLEARCODEC_VBAR_SHORT_SIZE (%" PRIu32 ")",  | 
703  | 0  |                    clear->ShortVBarStorageCursor, CLEARCODEC_VBAR_SHORT_SIZE);  | 
704  | 0  |           return FALSE;  | 
705  | 0  |         }  | 
706  |  |  | 
707  | 541k  |         vBarShortEntry = &(clear->ShortVBarStorage[clear->ShortVBarStorageCursor]);  | 
708  | 541k  |         vBarShortEntry->count = vBarShortPixelCount;  | 
709  |  |  | 
710  | 541k  |         if (!resize_vbar_entry(clear, vBarShortEntry))  | 
711  | 0  |           return FALSE;  | 
712  |  |  | 
713  | 558k  |         for (UINT32 y = 0; y < vBarShortPixelCount; y++)  | 
714  | 16.9k  |         { | 
715  | 16.9k  |           BYTE r = 0;  | 
716  | 16.9k  |           BYTE g = 0;  | 
717  | 16.9k  |           BYTE b = 0;  | 
718  | 16.9k  |           BYTE* dstBuffer =  | 
719  | 16.9k  |               &vBarShortEntry->pixels[y * FreeRDPGetBytesPerPixel(clear->format)];  | 
720  | 16.9k  |           UINT32 color = 0;  | 
721  | 16.9k  |           Stream_Read_UINT8(s, b);  | 
722  | 16.9k  |           Stream_Read_UINT8(s, g);  | 
723  | 16.9k  |           Stream_Read_UINT8(s, r);  | 
724  | 16.9k  |           color = FreeRDPGetColor(clear->format, r, g, b, 0xFF);  | 
725  |  |  | 
726  | 16.9k  |           if (!FreeRDPWriteColor(dstBuffer, clear->format, color))  | 
727  | 0  |             return FALSE;  | 
728  | 16.9k  |         }  | 
729  |  |  | 
730  | 541k  |         suboffset += (vBarShortPixelCount * 3);  | 
731  | 541k  |         clear->ShortVBarStorageCursor =  | 
732  | 541k  |             (clear->ShortVBarStorageCursor + 1) % CLEARCODEC_VBAR_SHORT_SIZE;  | 
733  | 541k  |         vBarUpdate = TRUE;  | 
734  | 541k  |       }  | 
735  | 16.7k  |       else if ((vBarHeader & 0x8000) == 0x8000) /* VBAR_CACHE_HIT */  | 
736  | 16.7k  |       { | 
737  | 16.7k  |         const UINT16 vBarIndex = (vBarHeader & 0x7FFF);  | 
738  | 16.7k  |         vBarEntry = &(clear->VBarStorage[vBarIndex]);  | 
739  |  |  | 
740  |  |         /* If the cache was reset we need to fill in some dummy data. */  | 
741  | 16.7k  |         if (vBarEntry->size == 0)  | 
742  | 3.83k  |         { | 
743  | 3.83k  |           WLog_WARN(TAG, "Empty cache index %" PRIu16 ", filling dummy data", vBarIndex);  | 
744  | 3.83k  |           vBarEntry->count = vBarHeight;  | 
745  |  |  | 
746  | 3.83k  |           if (!resize_vbar_entry(clear, vBarEntry))  | 
747  | 0  |             return FALSE;  | 
748  | 3.83k  |         }  | 
749  | 16.7k  |       }  | 
750  | 0  |       else  | 
751  | 0  |       { | 
752  | 0  |         WLog_ERR(TAG, "invalid vBarHeader 0x%04" PRIX16 "", vBarHeader);  | 
753  | 0  |         return FALSE; /* invalid vBarHeader */  | 
754  | 0  |       }  | 
755  |  |  | 
756  | 3.30M  |       if (vBarUpdate)  | 
757  | 3.28M  |       { | 
758  | 3.28M  |         BYTE* pSrcPixel = NULL;  | 
759  | 3.28M  |         BYTE* dstBuffer = NULL;  | 
760  |  |  | 
761  | 3.28M  |         if (clear->VBarStorageCursor >= CLEARCODEC_VBAR_SIZE)  | 
762  | 0  |         { | 
763  | 0  |           WLog_ERR(TAG,  | 
764  | 0  |                    "clear->VBarStorageCursor %" PRIu32 " >= CLEARCODEC_VBAR_SIZE %" PRIu32  | 
765  | 0  |                    "",  | 
766  | 0  |                    clear->VBarStorageCursor, CLEARCODEC_VBAR_SIZE);  | 
767  | 0  |           return FALSE;  | 
768  | 0  |         }  | 
769  |  |  | 
770  | 3.28M  |         vBarEntry = &(clear->VBarStorage[clear->VBarStorageCursor]);  | 
771  | 3.28M  |         vBarPixelCount = vBarHeight;  | 
772  | 3.28M  |         vBarEntry->count = vBarPixelCount;  | 
773  |  |  | 
774  | 3.28M  |         if (!resize_vbar_entry(clear, vBarEntry))  | 
775  | 0  |           return FALSE;  | 
776  |  |  | 
777  | 3.28M  |         dstBuffer = vBarEntry->pixels;  | 
778  |  |         /* if (y < vBarYOn), use colorBkg */  | 
779  | 3.28M  |         UINT32 y = 0;  | 
780  | 3.28M  |         UINT32 count = vBarYOn;  | 
781  |  |  | 
782  | 3.28M  |         if ((y + count) > vBarPixelCount)  | 
783  | 3.24M  |           count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;  | 
784  |  |  | 
785  | 9.19M  |         while (count--)  | 
786  | 5.91M  |         { | 
787  | 5.91M  |           FreeRDPWriteColor(dstBuffer, clear->format, colorBkg);  | 
788  | 5.91M  |           dstBuffer += FreeRDPGetBytesPerPixel(clear->format);  | 
789  | 5.91M  |         }  | 
790  |  |  | 
791  |  |         /*  | 
792  |  |          * if ((y >= vBarYOn) && (y < (vBarYOn + vBarShortPixelCount))),  | 
793  |  |          * use vBarShortPixels at index (y - shortVBarYOn)  | 
794  |  |          */  | 
795  | 3.28M  |         y = vBarYOn;  | 
796  | 3.28M  |         count = vBarShortPixelCount;  | 
797  |  |  | 
798  | 3.28M  |         if ((y + count) > vBarPixelCount)  | 
799  | 3.24M  |           count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;  | 
800  |  |  | 
801  | 3.28M  |         if (count > 0)  | 
802  | 1.88k  |         { | 
803  | 1.88k  |           const size_t offset =  | 
804  | 1.88k  |               (1ull * y - vBarYOn) * FreeRDPGetBytesPerPixel(clear->format);  | 
805  | 1.88k  |           pSrcPixel = &vBarShortEntry->pixels[offset];  | 
806  | 1.88k  |           if (offset + count > vBarShortEntry->count)  | 
807  | 0  |           { | 
808  | 0  |             WLog_ERR(TAG, "offset + count > vBarShortEntry->count");  | 
809  | 0  |             return FALSE;  | 
810  | 0  |           }  | 
811  | 1.88k  |         }  | 
812  | 3.28M  |         for (UINT32 x = 0; x < count; x++)  | 
813  | 3.83k  |         { | 
814  | 3.83k  |           UINT32 color = 0;  | 
815  | 3.83k  |           color = FreeRDPReadColor(&pSrcPixel[x * FreeRDPGetBytesPerPixel(clear->format)],  | 
816  | 3.83k  |                                    clear->format);  | 
817  |  |  | 
818  | 3.83k  |           if (!FreeRDPWriteColor(dstBuffer, clear->format, color))  | 
819  | 0  |             return FALSE;  | 
820  |  |  | 
821  | 3.83k  |           dstBuffer += FreeRDPGetBytesPerPixel(clear->format);  | 
822  | 3.83k  |         }  | 
823  |  |  | 
824  |  |         /* if (y >= (vBarYOn + vBarShortPixelCount)), use colorBkg */  | 
825  | 3.28M  |         y = vBarYOn + vBarShortPixelCount;  | 
826  | 3.28M  |         count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;  | 
827  |  |  | 
828  | 3.35M  |         while (count--)  | 
829  | 69.8k  |         { | 
830  | 69.8k  |           if (!FreeRDPWriteColor(dstBuffer, clear->format, colorBkg))  | 
831  | 0  |             return FALSE;  | 
832  |  |  | 
833  | 69.8k  |           dstBuffer += FreeRDPGetBytesPerPixel(clear->format);  | 
834  | 69.8k  |         }  | 
835  |  |  | 
836  | 3.28M  |         vBarEntry->count = vBarPixelCount;  | 
837  | 3.28M  |         clear->VBarStorageCursor = (clear->VBarStorageCursor + 1) % CLEARCODEC_VBAR_SIZE;  | 
838  | 3.28M  |       }  | 
839  |  |  | 
840  | 3.30M  |       if (vBarEntry->count != vBarHeight)  | 
841  | 74  |       { | 
842  | 74  |         WLog_ERR(TAG, "vBarEntry->count %" PRIu32 " != vBarHeight %" PRIu32 "",  | 
843  | 74  |                  vBarEntry->count, vBarHeight);  | 
844  | 74  |         vBarEntry->count = vBarHeight;  | 
845  |  |  | 
846  | 74  |         if (!resize_vbar_entry(clear, vBarEntry))  | 
847  | 0  |           return FALSE;  | 
848  | 74  |       }  | 
849  |  |  | 
850  | 3.30M  |       const UINT32 nXDstRel = nXDst + xStart;  | 
851  | 3.30M  |       const UINT32 nYDstRel = nYDst + yStart;  | 
852  | 3.30M  |       cpSrcPixel = vBarEntry->pixels;  | 
853  |  |  | 
854  | 3.30M  |       if (i < nWidth)  | 
855  | 28.8k  |       { | 
856  | 28.8k  |         UINT32 count = vBarEntry->count;  | 
857  |  |  | 
858  | 28.8k  |         if (count > nHeight)  | 
859  | 2.21k  |           count = nHeight;  | 
860  |  |  | 
861  | 28.8k  |         if (nXDstRel + i > nDstWidth)  | 
862  | 246  |           return FALSE;  | 
863  |  |  | 
864  | 109k  |         for (UINT32 y = 0; y < count; y++)  | 
865  | 80.6k  |         { | 
866  | 80.6k  |           if (nYDstRel + y > nDstHeight)  | 
867  | 72  |             return FALSE;  | 
868  |  |  | 
869  | 80.5k  |           BYTE* pDstPixel8 =  | 
870  | 80.5k  |               &pDstData[((nYDstRel + y) * nDstStep) +  | 
871  | 80.5k  |                         ((nXDstRel + i) * FreeRDPGetBytesPerPixel(DstFormat))];  | 
872  | 80.5k  |           UINT32 color = FreeRDPReadColor(cpSrcPixel, clear->format);  | 
873  | 80.5k  |           color = FreeRDPConvertColor(color, clear->format, DstFormat, NULL);  | 
874  |  |  | 
875  | 80.5k  |           if (!FreeRDPWriteColor(pDstPixel8, DstFormat, color))  | 
876  | 0  |             return FALSE;  | 
877  |  |  | 
878  | 80.5k  |           cpSrcPixel += FreeRDPGetBytesPerPixel(clear->format);  | 
879  | 80.5k  |         }  | 
880  | 28.5k  |       }  | 
881  | 3.30M  |     }  | 
882  | 2.38k  |   }  | 
883  |  |  | 
884  | 218  |   return TRUE;  | 
885  | 1.76k  | }  | 
886  |  |  | 
887  |  | static BOOL clear_decompress_glyph_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 glyphFlags,  | 
888  |  |                                         UINT32 nWidth, UINT32 nHeight, BYTE* pDstData,  | 
889  |  |                                         UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,  | 
890  |  |                                         UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,  | 
891  |  |                                         const gdiPalette* palette, BYTE** ppGlyphData)  | 
892  | 17.1k  | { | 
893  | 17.1k  |   UINT16 glyphIndex = 0;  | 
894  |  |  | 
895  | 17.1k  |   if (ppGlyphData)  | 
896  | 17.1k  |     *ppGlyphData = NULL;  | 
897  |  |  | 
898  | 17.1k  |   if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT) && !(glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX))  | 
899  | 1.08k  |   { | 
900  | 1.08k  |     WLog_ERR(TAG, "Invalid glyph flags %08" PRIX32 "", glyphFlags);  | 
901  | 1.08k  |     return FALSE;  | 
902  | 1.08k  |   }  | 
903  |  |  | 
904  | 16.0k  |   if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) == 0)  | 
905  | 9.61k  |     return TRUE;  | 
906  |  |  | 
907  | 6.45k  |   if ((nWidth * nHeight) > (1024 * 1024))  | 
908  | 0  |   { | 
909  | 0  |     WLog_ERR(TAG, "glyph too large: %" PRIu32 "x%" PRIu32 "", nWidth, nHeight);  | 
910  | 0  |     return FALSE;  | 
911  | 0  |   }  | 
912  |  |  | 
913  | 6.45k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))  | 
914  | 0  |     return FALSE;  | 
915  |  |  | 
916  | 6.45k  |   Stream_Read_UINT16(s, glyphIndex);  | 
917  |  |  | 
918  | 6.45k  |   if (glyphIndex >= 4000)  | 
919  | 2.62k  |   { | 
920  | 2.62k  |     WLog_ERR(TAG, "Invalid glyphIndex %" PRIu16 "", glyphIndex);  | 
921  | 2.62k  |     return FALSE;  | 
922  | 2.62k  |   }  | 
923  |  |  | 
924  | 3.82k  |   if (glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT)  | 
925  | 987  |   { | 
926  | 987  |     UINT32 nSrcStep = 0;  | 
927  | 987  |     CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]);  | 
928  | 987  |     BYTE* glyphData = NULL;  | 
929  |  |  | 
930  | 987  |     if (!glyphEntry)  | 
931  | 0  |     { | 
932  | 0  |       WLog_ERR(TAG, "clear->GlyphCache[%" PRIu16 "]=NULL", glyphIndex);  | 
933  | 0  |       return FALSE;  | 
934  | 0  |     }  | 
935  |  |  | 
936  | 987  |     glyphData = (BYTE*)glyphEntry->pixels;  | 
937  |  |  | 
938  | 987  |     if (!glyphData)  | 
939  | 987  |     { | 
940  | 987  |       WLog_ERR(TAG, "clear->GlyphCache[%" PRIu16 "]->pixels=NULL", glyphIndex);  | 
941  | 987  |       return FALSE;  | 
942  | 987  |     }  | 
943  |  |  | 
944  | 0  |     if ((nWidth * nHeight) > glyphEntry->count)  | 
945  | 0  |     { | 
946  | 0  |       WLog_ERR(TAG,  | 
947  | 0  |                "(nWidth %" PRIu32 " * nHeight %" PRIu32 ") > glyphEntry->count %" PRIu32 "",  | 
948  | 0  |                nWidth, nHeight, glyphEntry->count);  | 
949  | 0  |       return FALSE;  | 
950  | 0  |     }  | 
951  |  |  | 
952  | 0  |     nSrcStep = nWidth * FreeRDPGetBytesPerPixel(clear->format);  | 
953  | 0  |     return convert_color(pDstData, nDstStep, DstFormat, nXDst, nYDst, nWidth, nHeight,  | 
954  | 0  |                          glyphData, nSrcStep, clear->format, nDstWidth, nDstHeight, palette);  | 
955  | 0  |   }  | 
956  |  |  | 
957  | 2.84k  |   if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX)  | 
958  | 2.84k  |   { | 
959  | 2.84k  |     const UINT32 bpp = FreeRDPGetBytesPerPixel(clear->format);  | 
960  | 2.84k  |     CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]);  | 
961  | 2.84k  |     glyphEntry->count = nWidth * nHeight;  | 
962  |  |  | 
963  | 2.84k  |     if (glyphEntry->count > glyphEntry->size)  | 
964  | 2.84k  |     { | 
965  | 2.84k  |       BYTE* tmp =  | 
966  | 2.84k  |           winpr_aligned_recalloc(glyphEntry->pixels, glyphEntry->count, 1ull * bpp, 32);  | 
967  |  |  | 
968  | 2.84k  |       if (!tmp)  | 
969  | 0  |       { | 
970  | 0  |         WLog_ERR(TAG, "glyphEntry->pixels winpr_aligned_recalloc %" PRIu32 " failed!",  | 
971  | 0  |                  glyphEntry->count * bpp);  | 
972  | 0  |         return FALSE;  | 
973  | 0  |       }  | 
974  |  |  | 
975  | 2.84k  |       glyphEntry->size = glyphEntry->count;  | 
976  | 2.84k  |       glyphEntry->pixels = (UINT32*)tmp;  | 
977  | 2.84k  |     }  | 
978  |  |  | 
979  | 2.84k  |     if (!glyphEntry->pixels)  | 
980  | 0  |     { | 
981  | 0  |       WLog_ERR(TAG, "glyphEntry->pixels=NULL");  | 
982  | 0  |       return FALSE;  | 
983  | 0  |     }  | 
984  |  |  | 
985  | 2.84k  |     if (ppGlyphData)  | 
986  | 2.84k  |       *ppGlyphData = (BYTE*)glyphEntry->pixels;  | 
987  |  |  | 
988  | 2.84k  |     return TRUE;  | 
989  | 2.84k  |   }  | 
990  |  |  | 
991  | 0  |   return TRUE;  | 
992  | 2.84k  | }  | 
993  |  |  | 
994  |  | static INLINE BOOL updateContextFormat(CLEAR_CONTEXT* clear, UINT32 DstFormat)  | 
995  | 34.2k  | { | 
996  | 34.2k  |   if (!clear || !clear->nsc)  | 
997  | 0  |     return FALSE;  | 
998  |  |  | 
999  | 34.2k  |   clear->format = DstFormat;  | 
1000  | 34.2k  |   return nsc_context_set_parameters(clear->nsc, NSC_COLOR_FORMAT, DstFormat);  | 
1001  | 34.2k  | }  | 
1002  |  |  | 
1003  |  | INT32 clear_decompress(CLEAR_CONTEXT* clear, const BYTE* pSrcData, UINT32 SrcSize, UINT32 nWidth,  | 
1004  |  |                        UINT32 nHeight, BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep,  | 
1005  |  |                        UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,  | 
1006  |  |                        const gdiPalette* palette)  | 
1007  | 17.1k  | { | 
1008  | 17.1k  |   INT32 rc = -1;  | 
1009  | 17.1k  |   BYTE seqNumber = 0;  | 
1010  | 17.1k  |   BYTE glyphFlags = 0;  | 
1011  | 17.1k  |   UINT32 residualByteCount = 0;  | 
1012  | 17.1k  |   UINT32 bandsByteCount = 0;  | 
1013  | 17.1k  |   UINT32 subcodecByteCount = 0;  | 
1014  | 17.1k  |   wStream sbuffer = { 0 }; | 
1015  | 17.1k  |   wStream* s = NULL;  | 
1016  | 17.1k  |   BYTE* glyphData = NULL;  | 
1017  |  |  | 
1018  | 17.1k  |   if (!pDstData)  | 
1019  | 0  |     return -1002;  | 
1020  |  |  | 
1021  | 17.1k  |   if ((nDstWidth == 0) || (nDstHeight == 0))  | 
1022  | 0  |     return -1022;  | 
1023  |  |  | 
1024  | 17.1k  |   if ((nWidth > 0xFFFF) || (nHeight > 0xFFFF))  | 
1025  | 0  |     return -1004;  | 
1026  |  |  | 
1027  | 17.1k  |   s = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);  | 
1028  |  |  | 
1029  | 17.1k  |   if (!s)  | 
1030  | 0  |     return -2005;  | 
1031  |  |  | 
1032  | 17.1k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))  | 
1033  | 0  |     goto fail;  | 
1034  |  |  | 
1035  | 17.1k  |   if (!updateContextFormat(clear, DstFormat))  | 
1036  | 0  |     goto fail;  | 
1037  |  |  | 
1038  | 17.1k  |   Stream_Read_UINT8(s, glyphFlags);  | 
1039  | 17.1k  |   Stream_Read_UINT8(s, seqNumber);  | 
1040  |  |  | 
1041  | 17.1k  |   if (!clear->seqNumber && seqNumber)  | 
1042  | 13.0k  |     clear->seqNumber = seqNumber;  | 
1043  |  |  | 
1044  | 17.1k  |   if (seqNumber != clear->seqNumber)  | 
1045  | 0  |   { | 
1046  | 0  |     WLog_ERR(TAG, "Sequence number unexpected %" PRIu8 " - %" PRIu32 "", seqNumber,  | 
1047  | 0  |              clear->seqNumber);  | 
1048  | 0  |     WLog_ERR(TAG, "seqNumber %" PRIu8 " != clear->seqNumber %" PRIu32 "", seqNumber,  | 
1049  | 0  |              clear->seqNumber);  | 
1050  | 0  |     goto fail;  | 
1051  | 0  |   }  | 
1052  |  |  | 
1053  | 17.1k  |   clear->seqNumber = (seqNumber + 1) % 256;  | 
1054  |  |  | 
1055  | 17.1k  |   if (glyphFlags & CLEARCODEC_FLAG_CACHE_RESET)  | 
1056  | 3.89k  |   { | 
1057  | 3.89k  |     clear_reset_vbar_storage(clear, FALSE);  | 
1058  | 3.89k  |   }  | 
1059  |  |  | 
1060  | 17.1k  |   if (!clear_decompress_glyph_data(clear, s, glyphFlags, nWidth, nHeight, pDstData, DstFormat,  | 
1061  | 17.1k  |                                    nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, palette,  | 
1062  | 17.1k  |                                    &glyphData))  | 
1063  | 4.68k  |   { | 
1064  | 4.68k  |     WLog_ERR(TAG, "clear_decompress_glyph_data failed!");  | 
1065  | 4.68k  |     goto fail;  | 
1066  | 4.68k  |   }  | 
1067  |  |  | 
1068  |  |   /* Read composition payload header parameters */  | 
1069  | 12.4k  |   if (Stream_GetRemainingLength(s) < 12)  | 
1070  | 2.94k  |   { | 
1071  | 2.94k  |     const UINT32 mask = (CLEARCODEC_FLAG_GLYPH_HIT | CLEARCODEC_FLAG_GLYPH_INDEX);  | 
1072  |  |  | 
1073  | 2.94k  |     if ((glyphFlags & mask) == mask)  | 
1074  | 0  |       goto finish;  | 
1075  |  |  | 
1076  | 2.94k  |     WLog_ERR(TAG,  | 
1077  | 2.94k  |              "invalid glyphFlags, missing flags: 0x%02" PRIx8 " & 0x%02" PRIx32  | 
1078  | 2.94k  |              " == 0x%02" PRIx32,  | 
1079  | 2.94k  |              glyphFlags, mask, glyphFlags & mask);  | 
1080  | 2.94k  |     goto fail;  | 
1081  | 2.94k  |   }  | 
1082  |  |  | 
1083  | 9.51k  |   Stream_Read_UINT32(s, residualByteCount);  | 
1084  | 9.51k  |   Stream_Read_UINT32(s, bandsByteCount);  | 
1085  | 9.51k  |   Stream_Read_UINT32(s, subcodecByteCount);  | 
1086  |  |  | 
1087  | 9.51k  |   if (residualByteCount > 0)  | 
1088  | 4.42k  |   { | 
1089  | 4.42k  |     if (!clear_decompress_residual_data(clear, s, residualByteCount, nWidth, nHeight, pDstData,  | 
1090  | 4.42k  |                                         DstFormat, nDstStep, nXDst, nYDst, nDstWidth,  | 
1091  | 4.42k  |                                         nDstHeight, palette))  | 
1092  | 4.40k  |     { | 
1093  | 4.40k  |       WLog_ERR(TAG, "clear_decompress_residual_data failed!");  | 
1094  | 4.40k  |       goto fail;  | 
1095  | 4.40k  |     }  | 
1096  | 4.42k  |   }  | 
1097  |  |  | 
1098  | 5.10k  |   if (bandsByteCount > 0)  | 
1099  | 2.56k  |   { | 
1100  | 2.56k  |     if (!clear_decompress_bands_data(clear, s, bandsByteCount, nWidth, nHeight, pDstData,  | 
1101  | 2.56k  |                                      DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight))  | 
1102  | 2.34k  |     { | 
1103  | 2.34k  |       WLog_ERR(TAG, "clear_decompress_bands_data failed!");  | 
1104  | 2.34k  |       goto fail;  | 
1105  | 2.34k  |     }  | 
1106  | 2.56k  |   }  | 
1107  |  |  | 
1108  | 2.75k  |   if (subcodecByteCount > 0)  | 
1109  | 2.65k  |   { | 
1110  | 2.65k  |     if (!clear_decompress_subcodecs_data(clear, s, subcodecByteCount, nWidth, nHeight, pDstData,  | 
1111  | 2.65k  |                                          DstFormat, nDstStep, nXDst, nYDst, nDstWidth,  | 
1112  | 2.65k  |                                          nDstHeight, palette))  | 
1113  | 2.29k  |     { | 
1114  | 2.29k  |       WLog_ERR(TAG, "clear_decompress_subcodecs_data failed!");  | 
1115  | 2.29k  |       goto fail;  | 
1116  | 2.29k  |     }  | 
1117  | 2.65k  |   }  | 
1118  |  |  | 
1119  | 462  |   if (glyphData)  | 
1120  | 204  |   { | 
1121  | 204  |     if (!freerdp_image_copy(glyphData, clear->format, 0, 0, 0, nWidth, nHeight, pDstData,  | 
1122  | 204  |                             DstFormat, nDstStep, nXDst, nYDst, palette, FREERDP_KEEP_DST_ALPHA))  | 
1123  | 0  |       goto fail;  | 
1124  | 204  |   }  | 
1125  |  |  | 
1126  | 462  | finish:  | 
1127  | 462  |   rc = 0;  | 
1128  | 17.1k  | fail:  | 
1129  | 17.1k  |   return rc;  | 
1130  | 462  | }  | 
1131  |  |  | 
1132  |  | int clear_compress(CLEAR_CONTEXT* clear, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData,  | 
1133  |  |                    UINT32* pDstSize)  | 
1134  | 0  | { | 
1135  | 0  |   WLog_ERR(TAG, "TODO: not implemented!");  | 
1136  | 0  |   return 1;  | 
1137  | 0  | }  | 
1138  |  |  | 
1139  |  | BOOL clear_context_reset(CLEAR_CONTEXT* clear)  | 
1140  | 17.1k  | { | 
1141  | 17.1k  |   if (!clear)  | 
1142  | 0  |     return FALSE;  | 
1143  |  |  | 
1144  |  |   /**  | 
1145  |  |    * The ClearCodec context is not bound to a particular surface,  | 
1146  |  |    * and its internal caches must NOT be reset on the ResetGraphics PDU.  | 
1147  |  |    */  | 
1148  | 17.1k  |   clear->seqNumber = 0;  | 
1149  | 17.1k  |   return TRUE;  | 
1150  | 17.1k  | }  | 
1151  |  |  | 
1152  |  | CLEAR_CONTEXT* clear_context_new(BOOL Compressor)  | 
1153  | 17.1k  | { | 
1154  | 17.1k  |   CLEAR_CONTEXT* clear = (CLEAR_CONTEXT*)winpr_aligned_calloc(1, sizeof(CLEAR_CONTEXT), 32);  | 
1155  |  |  | 
1156  | 17.1k  |   if (!clear)  | 
1157  | 0  |     return NULL;  | 
1158  |  |  | 
1159  | 17.1k  |   clear->Compressor = Compressor;  | 
1160  | 17.1k  |   clear->nsc = nsc_context_new();  | 
1161  |  |  | 
1162  | 17.1k  |   if (!clear->nsc)  | 
1163  | 0  |     goto error_nsc;  | 
1164  |  |  | 
1165  | 17.1k  |   if (!updateContextFormat(clear, PIXEL_FORMAT_BGRX32))  | 
1166  | 0  |     goto error_nsc;  | 
1167  |  |  | 
1168  | 17.1k  |   if (!clear_resize_buffer(clear, 512, 512))  | 
1169  | 0  |     goto error_nsc;  | 
1170  |  |  | 
1171  | 17.1k  |   if (!clear->TempBuffer)  | 
1172  | 0  |     goto error_nsc;  | 
1173  |  |  | 
1174  | 17.1k  |   if (!clear_context_reset(clear))  | 
1175  | 0  |     goto error_nsc;  | 
1176  |  |  | 
1177  | 17.1k  |   return clear;  | 
1178  | 0  | error_nsc:  | 
1179  | 0  |   WINPR_PRAGMA_DIAG_PUSH  | 
1180  | 0  |   WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC  | 
1181  | 0  |   clear_context_free(clear);  | 
1182  | 0  |   WINPR_PRAGMA_DIAG_POP  | 
1183  | 0  |   return NULL;  | 
1184  | 17.1k  | }  | 
1185  |  |  | 
1186  |  | void clear_context_free(CLEAR_CONTEXT* clear)  | 
1187  | 17.1k  | { | 
1188  | 17.1k  |   if (!clear)  | 
1189  | 0  |     return;  | 
1190  |  |  | 
1191  | 17.1k  |   nsc_context_free(clear->nsc);  | 
1192  | 17.1k  |   winpr_aligned_free(clear->TempBuffer);  | 
1193  |  |  | 
1194  | 17.1k  |   clear_reset_vbar_storage(clear, TRUE);  | 
1195  | 17.1k  |   clear_reset_glyph_cache(clear);  | 
1196  |  |  | 
1197  | 17.1k  |   winpr_aligned_free(clear);  | 
1198  | 17.1k  | }  |