FreeRDP
Loading...
Searching...
No Matches
TestClipboardFormats.c
1
2#include <winpr/crt.h>
3#include <winpr/print.h>
4#include <winpr/image.h>
5#include <winpr/clipboard.h>
6#include <winpr/stream.h>
7#include <winpr/user.h>
8
9#define test_log(fmt, ...) test_log_fn(__FILE__, __func__, __LINE__, (fmt), ##__VA_ARGS__)
10static void test_log_fn(const char* file, const char* func, size_t line, const char* fmt, ...)
11{
12 va_list ap;
13 va_start(ap, fmt);
14
15 char* fstr = nullptr;
16 size_t fslen = 0;
17 winpr_vasprintf(&fstr, &fslen, fmt, ap);
18 (void)fprintf(stderr, "[%" PRIu32 ":%s]: %s\n", line, func, fstr);
19 free(fstr);
20 va_end(ap);
21}
22
23#define test_ClipboardSetData(clipboard, formatId, data, size) \
24 test_ClipboardSetDataFn(__FILE__, __func__, __LINE__, (clipboard), (formatId), (data), (size))
25static BOOL test_ClipboardSetDataFn(const char* file, const char* func, size_t line,
26 wClipboard* clipboard, UINT32 formatId, const void* data,
27 UINT32 size)
28{
29 const BOOL rc = ClipboardSetData(clipboard, formatId, data, size);
30 if (!rc)
31 {
32 test_log_fn(file, func, line, "ClipboardSetData %s[0x%04" PRIx32 "][%" PRIu32 "] failed",
33 ClipboardGetFormatName(clipboard, formatId), formatId, size);
34 }
35 return rc;
36}
37
38#define test_ClipboardGetData(clipboard, formatId, size) \
39 test_ClipboardGetDataFn(__FILE__, __func__, __LINE__, (clipboard), (formatId), (size))
40static void* test_ClipboardGetDataFn(const char* file, const char* func, size_t line,
41 wClipboard* clipboard, UINT32 formatId, UINT32* pSize)
42{
43 void* rc = ClipboardGetData(clipboard, formatId, pSize);
44 if (!rc)
45 {
46 test_log_fn(file, func, line, "ClipboardGetData %s[0x%04" PRIx32 "] failed",
47 ClipboardGetFormatName(clipboard, formatId), formatId);
48 }
49 return rc;
50}
51
52WINPR_ATTR_NODISCARD
53static BOOL test_dib_to_bmp(const BYTE* dib, size_t dibSize, size_t expectedOffset)
54{
55 BOOL rc = FALSE;
56
57 wClipboard* clipboard = ClipboardCreate();
58 if (!clipboard)
59 {
60 test_log("ClipboardCreate failed");
61 return FALSE;
62 }
63
64 const UINT32 bmpId = ClipboardRegisterFormat(clipboard, "image/bmp");
65 if (bmpId == 0)
66 {
67 test_log("bmpId == 0");
68 goto fail;
69 }
70 if (dibSize > UINT32_MAX)
71 {
72 test_log("dibSize %" PRIuz " > UINT32_MAX failed");
73 goto fail;
74 }
75 if (!test_ClipboardSetData(clipboard, CF_DIB, dib, (UINT32)dibSize))
76 goto fail;
77
78 UINT32 bmpSize = 0;
79 BYTE* bmp = test_ClipboardGetData(clipboard, bmpId, &bmpSize);
80 if (!bmp)
81 goto fail;
82
83 /* The synthesized BMP must also be readable by the image conversion code. */
84 wImage* image = winpr_image_new();
85 if (!image)
86 {
87 test_log("winpr_image_new failed");
88 goto fail_bmp;
89 }
90 rc = (winpr_image_read_buffer(image, bmp, bmpSize) > 0);
91 if (!rc)
92 test_log("winpr_image_read_buffer failed");
93 winpr_image_free(image, TRUE);
94
95fail_bmp:
96 free(bmp);
97fail:
98 ClipboardDestroy(clipboard);
99 return rc;
100}
101
102static void write_dib_info_header(wStream* s, UINT32 size, UINT16 bpp, UINT32 compression)
103{
104 WINPR_ASSERT(s);
105
106 Stream_Write_UINT32(s, size);
107 Stream_Write_INT32(s, 1); /* width */
108 Stream_Write_INT32(s, 1); /* height */
109 Stream_Write_UINT16(s, 1); /* planes */
110 Stream_Write_UINT16(s, bpp);
111 Stream_Write_UINT32(s, compression);
112 Stream_Write_UINT32(s, 4); /* image size */
113 Stream_Zero(s, 16); /* resolution and palette metadata */
114}
115
116WINPR_ATTR_NODISCARD
117static BOOL test_dib_offsets(void)
118{
119 BYTE v4[sizeof(BITMAPV4HEADER) + 4] = WINPR_C_ARRAY_INIT;
120 wStream sbuffer = WINPR_C_ARRAY_INIT;
121 wStream* s = Stream_StaticInit(&sbuffer, v4, sizeof(v4));
122 if (!s)
123 return FALSE;
124 write_dib_info_header(s, sizeof(BITMAPV4HEADER), 32, BI_BITFIELDS);
125
126 Stream_Write_UINT32(s, 0x00FF0000); /* red mask */
127 Stream_Write_UINT32(s, 0x0000FF00); /* green mask */
128 Stream_Write_UINT32(s, 0x000000FF); /* blue mask */
129 Stream_Write_UINT32(s, 0xFF000000); /* alpha mask */
130 Stream_Zero(s, sizeof(BITMAPV4HEADER) - Stream_GetPosition(s));
131 Stream_Write_UINT32(s, 0xFF123456); /* pixel */
132 if (!test_dib_to_bmp(v4, sizeof(v4), sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(BITMAPV4HEADER)))
133 return FALSE;
134
135 BYTE bitfields[sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD) + 4] = WINPR_C_ARRAY_INIT;
136 s = Stream_StaticInit(&sbuffer, bitfields, sizeof(bitfields));
137 if (!s)
138 return FALSE;
139 write_dib_info_header(s, sizeof(BITMAPINFOHEADER), 32, BI_BITFIELDS);
140 Stream_Write_UINT32(s, 0x00FF0000); /* red mask */
141 Stream_Write_UINT32(s, 0x0000FF00); /* green mask */
142 Stream_Write_UINT32(s, 0x000000FF); /* blue mask */
143 Stream_Write_UINT32(s, 0xFF123456); /* pixel */
144 if (!test_dib_to_bmp(bitfields, sizeof(bitfields),
146 3 * sizeof(DWORD)))
147 return FALSE;
148
149 BYTE paletted[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) + 4] = WINPR_C_ARRAY_INIT;
150 s = Stream_StaticInit(&sbuffer, paletted, sizeof(paletted));
151 if (!s)
152 return FALSE;
153 write_dib_info_header(s, sizeof(BITMAPINFOHEADER), 8, BI_RGB);
154 Stream_Zero(s, 256 * sizeof(RGBQUAD));
155 Stream_Write_UINT32(s, 0); /* pixel row */
156 return test_dib_to_bmp(paletted, sizeof(paletted),
158 256 * sizeof(RGBQUAD));
159}
160
161WINPR_ATTR_NODISCARD
162static BOOL test_text_leading_newline(void)
163{
164 const char* tests[][2] = { { "\nfoo", "\r\nfoo" }, { "\n", "\r\n" } };
165 BOOL rc = FALSE;
166
167 wClipboard* clipboard = ClipboardCreate();
168 if (!clipboard)
169 {
170 test_log("ClipboardCreate failed");
171 return FALSE;
172 }
173
174 const UINT32 textId = ClipboardRegisterFormat(clipboard, "text/plain");
175 for (size_t x = 0; x < ARRAYSIZE(tests); x++)
176 {
177 /* local text/plain is set without a terminator */
178 if (!test_ClipboardSetData(clipboard, textId, tests[x][0], (UINT32)strlen(tests[x][0])))
179 goto fail;
180
181 UINT32 size = 0;
182 WCHAR* wstr = test_ClipboardGetData(clipboard, CF_UNICODETEXT, &size);
183 char* str = ConvertWCharNToUtf8Alloc(wstr, size / sizeof(WCHAR), nullptr);
184 const BOOL match = str && (strcmp(str, tests[x][1]) == 0);
185 free(wstr);
186 free(str);
187 if (!match)
188 {
189 test_log("text/plain to CF_UNICODETEXT failed for case %" PRIuz "", x);
190 goto fail;
191 }
192 }
193 rc = TRUE;
194
195fail:
196 ClipboardDestroy(clipboard);
197 return rc;
198}
199
200WINPR_ATTR_NODISCARD
201static BOOL test_text_conversion(void)
202{
203 wClipboard* clipboard = ClipboardCreate();
204 if (!clipboard)
205 return FALSE;
206
207 typedef struct
208 {
209 UINT32 srcFormat;
210 UINT32 dstFormat;
211 const char* src;
212 size_t srcLen;
213 const char* expect;
214 size_t expectLen;
215 } test_case_t;
216
217 const test_case_t tests[] = {
218 { ClipboardRegisterFormat(clipboard, "text/plain"),
219 ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"), "a\nb\rc\\u1234\\u055e",
220 17, "a\nb\ncሴ՞", 10 },
221 { ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"),
222 ClipboardRegisterFormat(clipboard, "text/plain"), "a\r\nb\nc՞՞", 10,
223 "a\r\nb\nc\\u055e\\u055e", 18 },
224 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_UNICODETEXT, "a\nb\rc\\u1234\\u055e",
225 17, "\x61\x00\x0d\x00\x0a\x00\x62\x00\x0d\x0\x0a\x00\x63\x00\x34\x12\x5e\x05\x00\x00\x00",
226 18 },
227 { CF_UNICODETEXT, ClipboardRegisterFormat(clipboard, "text/plain"),
228 "\x61\x00\x0d\x00\x0a\x00\x62\x00\x0d\x0\x0a\x00\x63\x00\x34\x12\x5e\x05\x00\x00\x00", 18,
229 "a\nb\nc\\u1234\\u055e", 17 },
230 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_TEXT, "a\nb\rc\\u1234\\u055e", 17,
231 "a\nb\nc\\u1234\\u055e", 17 },
232 { CF_TEXT, ClipboardRegisterFormat(clipboard, "text/plain"), "a\nb\nc\\u1234\\u055e", 17,
233 "a\nb\nc\\u1234\\u055e", 17 },
234 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_OEMTEXT, "a\nb\rc\\u1234\\u055e", 17,
235 "a\nb\nc\\u1234\\u055e", 17 },
236 { CF_OEMTEXT, ClipboardRegisterFormat(clipboard, "text/plain"), "a\nb\rc\\u1234\\u055e", 17,
237 "a\nb\nc\\u1234\\u055e", 17 }
238 };
239
240 BOOL rc = FALSE;
241
242 for (size_t x = 0; x < ARRAYSIZE(tests); x++)
243 {
244 const test_case_t* cur = &tests[x];
245
246 /* local text/plain is set without a terminator */
247 if (!test_ClipboardSetData(clipboard, cur->srcFormat, cur->src, cur->srcLen))
248 goto fail;
249
250 UINT32 dstSize = 0;
251 BYTE* data = test_ClipboardGetData(clipboard, cur->dstFormat, &dstSize);
252 if (dstSize != cur->expectLen)
253 {
254 winpr_znfree(data, dstSize);
255 goto fail;
256 }
257 if (dstSize != 0)
258 {
259 if (!data)
260 {
261 winpr_znfree(data, dstSize);
262 goto fail;
263 }
264 const int rc = memcmp(cur->expect, data, cur->expectLen);
265 winpr_znfree(data, dstSize);
266 if (rc != 0)
267 goto fail;
268 }
269 else
270 winpr_znfree(data, dstSize);
271 }
272 rc = TRUE;
273
274fail:
275 ClipboardDestroy(clipboard);
276 return rc;
277}
278
279int TestClipboardFormats(int argc, char* argv[])
280{
281 int rc = -1;
282 UINT32 count = 0;
283 UINT32* pFormatIds = nullptr;
284 const char* formatName = nullptr;
285 UINT32 utf8StringFormatId = 0;
286
287 WINPR_UNUSED(argc);
288 WINPR_UNUSED(argv);
289
290 if (!test_text_leading_newline())
291 return -1;
292
293 if (!test_text_conversion())
294 return -1;
295
296 wClipboard* clipboard = ClipboardCreate();
297 if (!clipboard)
298 return -1;
299
300 const char* mime_types[] = { "text/plain", "text/plain;charset=utf-8",
301 "text/html", "image/bmp",
302 "image/png", "image/webp",
303 "image/jpeg" };
304 for (size_t x = 0; x < ARRAYSIZE(mime_types); x++)
305 {
306 const char* mime = mime_types[x];
307 UINT32 id = ClipboardRegisterFormat(clipboard, mime);
308 test_log("ClipboardRegisterFormat(%s) -> 0x%08" PRIx32 "", mime, id);
309 if (id == 0)
310 goto fail;
311 }
312
313 utf8StringFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING");
314 pFormatIds = nullptr;
315 count = ClipboardGetRegisteredFormatIds(clipboard, &pFormatIds);
316
317 for (UINT32 index = 0; index < count; index++)
318 {
319 UINT32 formatId = pFormatIds[index];
320 formatName = ClipboardGetFormatName(clipboard, formatId);
321 test_log("Format: 0x%08" PRIX32 " %s", formatId, formatName);
322 }
323
324 free(pFormatIds);
325
326 if (1)
327 {
328 UINT32 SrcSize = 0;
329 UINT32 DstSize = 0;
330 const char pSrcData[] = "this is a test string";
331 char* pDstData = nullptr;
332
333 SrcSize = (UINT32)(strnlen(pSrcData, ARRAYSIZE(pSrcData)) + 1);
334 const BOOL bSuccess =
335 test_ClipboardSetData(clipboard, utf8StringFormatId, pSrcData, SrcSize);
336 if (!bSuccess)
337 goto fail;
338
339 DstSize = 0;
340 pDstData = (char*)test_ClipboardGetData(clipboard, utf8StringFormatId, &DstSize);
341 free(pDstData);
342 }
343
344 if (1)
345 {
346 UINT32 DstSize = 0;
347 char* pSrcData = nullptr;
348 WCHAR* pDstData = nullptr;
349 DstSize = 0;
350 pDstData = (WCHAR*)test_ClipboardGetData(clipboard, CF_UNICODETEXT, &DstSize);
351 pSrcData = ConvertWCharNToUtf8Alloc(pDstData, DstSize / sizeof(WCHAR), nullptr);
352
353 free(pDstData);
354 free(pSrcData);
355 }
356
357 pFormatIds = nullptr;
358 count = ClipboardGetFormatIds(clipboard, &pFormatIds);
359
360 for (UINT32 index = 0; index < count; index++)
361 {
362 UINT32 formatId = pFormatIds[index];
363 formatName = ClipboardGetFormatName(clipboard, formatId);
364 test_log("Format: 0x%08" PRIX32 " %s", formatId, formatName);
365 }
366
367 if (1)
368 {
369 const char* name = TEST_CLIP_BMP;
370 BOOL bSuccess = FALSE;
371 UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/bmp");
372
373 wImage* img = winpr_image_new();
374 if (!img)
375 goto fail;
376
377 if (winpr_image_read(img, name) <= 0)
378 {
379 winpr_image_free(img, TRUE);
380 goto fail;
381 }
382
383 size_t bmpsize = 0;
384 void* data = winpr_image_write_buffer(img, WINPR_IMAGE_BITMAP, &bmpsize);
385 bSuccess = test_ClipboardSetData(clipboard, idBmp, data, bmpsize);
386
387 free(data);
388 winpr_image_free(img, TRUE);
389 if (!bSuccess)
390 goto fail;
391
392 {
393 UINT32 id = CF_DIB;
394
395 UINT32 DstSize = 0;
396 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
397 if (!pDstData)
398 goto fail;
399 bSuccess = test_ClipboardSetData(clipboard, id, pDstData, DstSize);
400 free(pDstData);
401 if (!bSuccess)
402 goto fail;
403 }
404 {
405 const uint32_t id = ClipboardGetFormatId(clipboard, "HTML Format");
406 UINT32 DstSize = 0;
407 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
408 if (!pDstData)
409 goto fail;
410 {
411 FILE* fp = fopen("test.html", "w");
412 if (fp)
413 {
414 (void)fwrite(pDstData, 1, DstSize, fp);
415 (void)fclose(fp);
416 }
417 }
418 free(pDstData);
419 }
420 {
421 UINT32 id = ClipboardRegisterFormat(clipboard, "image/bmp");
422
423 UINT32 DstSize = 0;
424 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
425 if (!pDstData)
426 goto fail;
427 free(pDstData);
428 if (DstSize != bmpsize)
429 goto fail;
430 }
431
432#if defined(WINPR_UTILS_IMAGE_PNG)
433 {
434 UINT32 id = ClipboardRegisterFormat(clipboard, "image/png");
435
436 UINT32 DstSize = 0;
437 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
438 if (!pDstData)
439 goto fail;
440 free(pDstData);
441 }
442 {
443 const char* name = TEST_CLIP_PNG;
444 BOOL bSuccess = FALSE;
445 UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/png");
446
447 wImage* img = winpr_image_new();
448 if (!img)
449 goto fail;
450
451 if (winpr_image_read(img, name) <= 0)
452 {
453 winpr_image_free(img, TRUE);
454 goto fail;
455 }
456
457 size_t bmpsize = 0;
458 void* data = winpr_image_write_buffer(img, WINPR_IMAGE_PNG, &bmpsize);
459 bSuccess = test_ClipboardSetData(clipboard, idBmp, data, bmpsize);
460
461 free(data);
462 winpr_image_free(img, TRUE);
463 if (!bSuccess)
464 goto fail;
465 }
466 {
467 UINT32 id = CF_DIB;
468
469 UINT32 DstSize = 0;
470 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
471 if (!pDstData)
472 goto fail;
473 bSuccess = test_ClipboardSetData(clipboard, id, pDstData, DstSize);
474 free(pDstData);
475 if (!bSuccess)
476 goto fail;
477 }
478#endif
479
480#if defined(WINPR_UTILS_IMAGE_WEBP)
481 {
482 UINT32 id = ClipboardRegisterFormat(clipboard, "image/webp");
483
484 UINT32 DstSize = 0;
485 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
486 if (!pDstData)
487 goto fail;
488 free(pDstData);
489 }
490#endif
491
492#if defined(WINPR_UTILS_IMAGE_JPEG)
493 {
494 UINT32 id = ClipboardRegisterFormat(clipboard, "image/jpeg");
495
496 UINT32 DstSize = 0;
497 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
498 if (!pDstData)
499 goto fail;
500 free(pDstData);
501 }
502#endif
503 }
504
505 if (!test_dib_offsets())
506 goto fail;
507
508 rc = 0;
509
510fail:
511 free(pFormatIds);
512 ClipboardDestroy(clipboard);
513 return rc;
514}