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#include <winpr/file.h>
9#include <winpr/shell.h>
10#include <winpr/path.h>
11
12#define test_log(fmt, ...) test_log_fn(__FILE__, __func__, __LINE__, (fmt), ##__VA_ARGS__)
13static void test_log_fn(const char* file, const char* func, size_t line, const char* fmt, ...)
14{
15 va_list ap;
16 va_start(ap, fmt);
17
18 char* fstr = nullptr;
19 size_t fslen = 0;
20 winpr_vasprintf(&fstr, &fslen, fmt, ap);
21 (void)fprintf(stderr, "[%" PRIu32 ":%s]: %s\n", line, func, fstr);
22 free(fstr);
23 va_end(ap);
24}
25
26#define test_ClipboardSetData(clipboard, formatId, data, size) \
27 test_ClipboardSetDataFn(__FILE__, __func__, __LINE__, (clipboard), (formatId), (data), (size))
28
29WINPR_ATTR_NODISCARD
30static BOOL test_ClipboardSetDataFn(const char* file, const char* func, size_t line,
31 wClipboard* clipboard, UINT32 formatId, const void* data,
32 UINT32 size)
33{
34 const BOOL rc = ClipboardSetData(clipboard, formatId, data, size);
35 if (!rc)
36 {
37 test_log_fn(file, func, line, "ClipboardSetData %s[0x%04" PRIx32 "][%" PRIu32 "] failed",
38 ClipboardGetFormatName(clipboard, formatId), formatId, size);
39 }
40 return rc;
41}
42
43#define test_ClipboardGetData(clipboard, formatId, size) \
44 test_ClipboardGetDataFn(__FILE__, __func__, __LINE__, (clipboard), (formatId), (size))
45
46WINPR_ATTR_NODISCARD
47static void* test_ClipboardGetDataFn(const char* file, const char* func, size_t line,
48 wClipboard* clipboard, UINT32 formatId, UINT32* pSize)
49{
50 void* rc = ClipboardGetData(clipboard, formatId, pSize);
51 if (!rc)
52 {
53 test_log_fn(file, func, line, "ClipboardGetData %s[0x%04" PRIx32 "] failed",
54 ClipboardGetFormatName(clipboard, formatId), formatId);
55 }
56 return rc;
57}
58
59WINPR_ATTR_NODISCARD
60static BOOL test_dib_to_bmp(const BYTE* dib, size_t dibSize, size_t expectedOffset)
61{
62 BOOL rc = FALSE;
63
64 wClipboard* clipboard = ClipboardCreate();
65 if (!clipboard)
66 {
67 test_log("ClipboardCreate failed");
68 return FALSE;
69 }
70
71 const UINT32 bmpId = ClipboardRegisterFormat(clipboard, "image/bmp");
72 if (bmpId == 0)
73 {
74 test_log("bmpId == 0");
75 goto fail;
76 }
77 if (dibSize > UINT32_MAX)
78 {
79 test_log("dibSize %" PRIuz " > UINT32_MAX failed");
80 goto fail;
81 }
82 if (!test_ClipboardSetData(clipboard, CF_DIB, dib, (UINT32)dibSize))
83 goto fail;
84
85 UINT32 bmpSize = 0;
86 BYTE* bmp = test_ClipboardGetData(clipboard, bmpId, &bmpSize);
87 if (!bmp)
88 goto fail;
89
90 /* The synthesized BMP must also be readable by the image conversion code. */
91 wImage* image = winpr_image_new();
92 if (!image)
93 {
94 test_log("winpr_image_new failed");
95 goto fail_bmp;
96 }
97 rc = (winpr_image_read_buffer(image, bmp, bmpSize) > 0);
98 if (!rc)
99 test_log("winpr_image_read_buffer failed");
100 winpr_image_free(image, TRUE);
101
102fail_bmp:
103 free(bmp);
104fail:
105 ClipboardDestroy(clipboard);
106 return rc;
107}
108
109static void write_dib_info_header(wStream* s, UINT32 size, UINT16 bpp, UINT32 compression)
110{
111 WINPR_ASSERT(s);
112
113 Stream_Write_UINT32(s, size);
114 Stream_Write_INT32(s, 1); /* width */
115 Stream_Write_INT32(s, 1); /* height */
116 Stream_Write_UINT16(s, 1); /* planes */
117 Stream_Write_UINT16(s, bpp);
118 Stream_Write_UINT32(s, compression);
119 Stream_Write_UINT32(s, 4); /* image size */
120 Stream_Zero(s, 16); /* resolution and palette metadata */
121}
122
123WINPR_ATTR_NODISCARD
124static BOOL test_dib_offsets(void)
125{
126 BYTE v4[sizeof(BITMAPV4HEADER) + 4] = WINPR_C_ARRAY_INIT;
127 wStream sbuffer = WINPR_C_ARRAY_INIT;
128 wStream* s = Stream_StaticInit(&sbuffer, v4, sizeof(v4));
129 if (!s)
130 return FALSE;
131 write_dib_info_header(s, sizeof(BITMAPV4HEADER), 32, BI_BITFIELDS);
132
133 Stream_Write_UINT32(s, 0x00FF0000); /* red mask */
134 Stream_Write_UINT32(s, 0x0000FF00); /* green mask */
135 Stream_Write_UINT32(s, 0x000000FF); /* blue mask */
136 Stream_Write_UINT32(s, 0xFF000000); /* alpha mask */
137 Stream_Zero(s, sizeof(BITMAPV4HEADER) - Stream_GetPosition(s));
138 Stream_Write_UINT32(s, 0xFF123456); /* pixel */
139 if (!test_dib_to_bmp(v4, sizeof(v4), sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(BITMAPV4HEADER)))
140 return FALSE;
141
142 BYTE bitfields[sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD) + 4] = WINPR_C_ARRAY_INIT;
143 s = Stream_StaticInit(&sbuffer, bitfields, sizeof(bitfields));
144 if (!s)
145 return FALSE;
146 write_dib_info_header(s, sizeof(BITMAPINFOHEADER), 32, BI_BITFIELDS);
147 Stream_Write_UINT32(s, 0x00FF0000); /* red mask */
148 Stream_Write_UINT32(s, 0x0000FF00); /* green mask */
149 Stream_Write_UINT32(s, 0x000000FF); /* blue mask */
150 Stream_Write_UINT32(s, 0xFF123456); /* pixel */
151 if (!test_dib_to_bmp(bitfields, sizeof(bitfields),
153 3 * sizeof(DWORD)))
154 return FALSE;
155
156 BYTE paletted[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) + 4] = WINPR_C_ARRAY_INIT;
157 s = Stream_StaticInit(&sbuffer, paletted, sizeof(paletted));
158 if (!s)
159 return FALSE;
160 write_dib_info_header(s, sizeof(BITMAPINFOHEADER), 8, BI_RGB);
161 Stream_Zero(s, 256 * sizeof(RGBQUAD));
162 Stream_Write_UINT32(s, 0); /* pixel row */
163 return test_dib_to_bmp(paletted, sizeof(paletted),
165 256 * sizeof(RGBQUAD));
166}
167
168WINPR_ATTR_NODISCARD
169static BOOL test_text_leading_newline(void)
170{
171 const char* tests[][2] = { { "\nfoo", "\r\nfoo" }, { "\n", "\r\n" } };
172 BOOL rc = FALSE;
173
174 wClipboard* clipboard = ClipboardCreate();
175 if (!clipboard)
176 {
177 test_log("ClipboardCreate failed");
178 return FALSE;
179 }
180
181 const UINT32 textId = ClipboardRegisterFormat(clipboard, "text/plain");
182 for (size_t x = 0; x < ARRAYSIZE(tests); x++)
183 {
184 const char** cur = tests[x];
185 /* local text/plain is set without a terminator */
186 if (!test_ClipboardSetData(clipboard, textId, cur[0], (UINT32)strlen(cur[0])))
187 goto fail;
188
189 UINT32 size = 0;
190 WCHAR* wstr = test_ClipboardGetData(clipboard, CF_UNICODETEXT, &size);
191 char* str = ConvertWCharNToUtf8Alloc(wstr, size / sizeof(WCHAR), nullptr);
192 const BOOL match = str && (strcmp(str, cur[1]) == 0);
193 if (!match)
194 {
195 test_log("text/plain to CF_UNICODETEXT failed for case %" PRIuz "[%s (%" PRIu32
196 ") %p : expect %s (%" PRIuz ") : from %s (" PRIuz ")]",
197 x, str, size, wstr, cur[1], strlen(cur[1]), cur[0], strlen(cur[0]));
198 }
199 free(wstr);
200 free(str);
201 if (!match)
202 goto fail;
203 }
204 rc = TRUE;
205
206fail:
207 ClipboardDestroy(clipboard);
208 return rc;
209}
210
211WINPR_ATTR_NODISCARD
212static BOOL test_text_conversion(void)
213{
214 wClipboard* clipboard = ClipboardCreate();
215 if (!clipboard)
216 return FALSE;
217
218 typedef struct
219 {
220 UINT32 srcFormat;
221 UINT32 dstFormat;
222 const char* src;
223 size_t srcLen;
224 const char* expect;
225 size_t expectLen;
226 } test_case_t;
227
228 /* text/plain is UTF-8 on Windows, and ASCII with \u escapes for other characters elsewhere */
229 const test_case_t tests[] = {
230#if defined(_WIN32)
231 { ClipboardRegisterFormat(clipboard, "text/plain"),
232 ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"), "a\nb\ncሴ՞", 10,
233 "a\nb\ncሴ՞", 11 },
234 { ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"),
235 ClipboardRegisterFormat(clipboard, "text/plain"), "a\r\nb\nc՞՞", 10, "a\r\nb\nc՞՞", 11 },
236 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_UNICODETEXT, "a\nb\ncሴ՞", 10,
237 "\x61\x00\x0d\x00\x0a\x00\x62\x00\x0d\x0\x0a\x00\x63\x00\x34\x12\x5e\x05\x00\x00\x00",
238 20 },
239 { CF_UNICODETEXT, ClipboardRegisterFormat(clipboard, "text/plain"),
240 "\x61\x00\x0d\x00\x0a\x00\x62\x00\x0d\x0\x0a\x00\x63\x00\x34\x12\x5e\x05\x00\x00\x00", 18,
241 "a\nb\ncሴ՞", 11 },
242 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_TEXT, "a\nb\ncሴ՞", 10,
243 "a\nb\nc\\u1234\\u055e", 18 },
244 { CF_TEXT, ClipboardRegisterFormat(clipboard, "text/plain"), "a\nb\nc\\u1234\\u055e", 17,
245 "a\nb\ncሴ՞", 11 },
246 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_OEMTEXT, "a\nb\ncሴ՞", 10,
247 "a\nb\nc\\u1234\\u055e", 18 },
248 { CF_OEMTEXT, ClipboardRegisterFormat(clipboard, "text/plain"), "a\nb\rc\\u1234\\u055e", 17,
249 "a\nb\ncሴ՞", 11 },
250#else
251 { ClipboardRegisterFormat(clipboard, "text/plain"),
252 ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"), "a\nb\rc\\u1234\\u055e",
253 17, "a\nb\ncሴ՞", 11 },
254 { ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"),
255 ClipboardRegisterFormat(clipboard, "text/plain"), "a\r\nb\nc՞՞", 10,
256 "a\r\nb\nc\\u055e\\u055e", 19 },
257 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_UNICODETEXT, "a\nb\rc\\u1234\\u055e",
258 17, "\x61\x00\x0d\x00\x0a\x00\x62\x00\x0d\x0\x0a\x00\x63\x00\x34\x12\x5e\x05\x00\x00\x00",
259 20 },
260 { CF_UNICODETEXT, ClipboardRegisterFormat(clipboard, "text/plain"),
261 "\x61\x00\x0d\x00\x0a\x00\x62\x00\x0d\x0\x0a\x00\x63\x00\x34\x12\x5e\x05\x00\x00\x00", 18,
262 "a\nb\nc\\u1234\\u055e", 18 },
263 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_TEXT, "a\nb\rc\\u1234\\u055e", 17,
264 "a\nb\nc\\u1234\\u055e", 18 },
265 { CF_TEXT, ClipboardRegisterFormat(clipboard, "text/plain"), "a\nb\nc\\u1234\\u055e", 17,
266 "a\nb\nc\\u1234\\u055e", 18 },
267 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_OEMTEXT, "a\nb\rc\\u1234\\u055e", 17,
268 "a\nb\nc\\u1234\\u055e", 18 },
269 { CF_OEMTEXT, ClipboardRegisterFormat(clipboard, "text/plain"), "a\nb\rc\\u1234\\u055e", 17,
270 "a\nb\nc\\u1234\\u055e", 18 },
271#endif
272 /* UTF-8 set with its terminator */
273 { ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"),
274 ClipboardRegisterFormat(clipboard, "UTF8_STRING"), "ab", 3, "ab", 3 },
275 { ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"), CF_UNICODETEXT, "ab", 3,
276 "\x61\x00\x62\x00\x00\x00", 6 }
277 };
278
279 BOOL rc = FALSE;
280
281 for (size_t x = 0; x < ARRAYSIZE(tests); x++)
282 {
283 const test_case_t* cur = &tests[x];
284
285 /* local text/plain is set without a terminator */
286 if (!test_ClipboardSetData(clipboard, cur->srcFormat, cur->src, cur->srcLen))
287 goto fail;
288
289 UINT32 dstSize = 0;
290 BYTE* data = test_ClipboardGetData(clipboard, cur->dstFormat, &dstSize);
291 if (dstSize != cur->expectLen)
292 {
293 winpr_znfree(data, dstSize);
294 goto fail;
295 }
296 if (dstSize != 0)
297 {
298 if (!data)
299 {
300 winpr_znfree(data, dstSize);
301 goto fail;
302 }
303 const int rc = memcmp(cur->expect, data, cur->expectLen);
304 winpr_znfree(data, dstSize);
305 if (rc != 0)
306 goto fail;
307 }
308 else
309 winpr_znfree(data, dstSize);
310 }
311 rc = TRUE;
312
313fail:
314 ClipboardDestroy(clipboard);
315 return rc;
316}
317
318WINPR_ATTR_NODISCARD
319static BOOL set_descriptor_name(FILEDESCRIPTORW* dsc, const char* name, const char* trailing)
320{
321 BOOL rc = TRUE;
322 /* what follows the '\0' of cFileName is garbage the converter must ignore */
323 memset(dsc->cFileName, 0xff, sizeof(dsc->cFileName));
324 const size_t len = strlen(name);
325 if (ConvertUtf8NToWChar(name, len + 1, dsc->cFileName, ARRAYSIZE(dsc->cFileName)) < 0)
326 rc = FALSE;
327 else if (trailing && (ConvertUtf8NToWChar(trailing, strlen(trailing), &dsc->cFileName[len],
328 ARRAYSIZE(dsc->cFileName) - len - 1) < 0))
329 rc = FALSE;
330 if (!rc)
331 test_log("set_descriptor_name(%s, %s) failed", name, trailing);
332 return TRUE;
333}
334
335WINPR_ATTR_NODISCARD
336static BOOL test_file_descriptors_to_uri_list(void)
337{
338 BOOL rc = FALSE;
339 char* basePath = GetKnownSubPath(KNOWN_PATH_TEMP, "frdp-test");
340 if (!basePath)
341 return FALSE;
342 char* uris = nullptr;
343
344 struct
345 {
346 UINT32 count;
347 FILEDESCRIPTORW dsc[4];
348 } data = WINPR_C_ARRAY_INIT;
349
350 char* cmpdir = nullptr;
351 char* cmpa = nullptr;
352 wClipboard* clipboard = ClipboardCreate();
353 if (!clipboard)
354 goto fail;
355
356 HRESULT hr = PathCchConvertStyleA(basePath, strlen(basePath), PATH_STYLE_UNIX);
357 if (FAILED(hr))
358 goto fail;
359
360 wClipboardDelegate* delegate = ClipboardGetDelegate(clipboard);
361 if (!delegate)
362 goto fail;
363 delegate->basePath = basePath;
364
365 size_t len = 0;
366 winpr_asprintf(&cmpdir, &len, "file://%s/dir\r\n", basePath);
367 winpr_asprintf(&cmpa, &len, "file://%s/a.txt", basePath);
368 if (!cmpdir || !cmpa)
369 goto fail;
370
371 /* data must be little endian */
372 winpr_Data_Write_UINT32(&data.count, ARRAYSIZE(data.dsc));
373 winpr_Data_Write_UINT32(&data.dsc[0].dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY);
374 if (!set_descriptor_name(&data.dsc[0], "dir", nullptr))
375 goto fail;
376 if (!set_descriptor_name(&data.dsc[1], "dir\\b.txt", nullptr))
377 goto fail;
378 /* a stale '\' after the name must not make a top level file look nested */
379 if (!set_descriptor_name(&data.dsc[2], "a.txt", "old\\name"))
380 goto fail;
381 if (!set_descriptor_name(&data.dsc[3], "a.txt", "old\\"))
382 goto fail;
383
384 {
385 const UINT32 srcId = ClipboardRegisterFormat(clipboard, "FileGroupDescriptorW");
386 const UINT32 dstId = ClipboardRegisterFormat(clipboard, "text/uri-list");
387 if (!test_ClipboardSetData(clipboard, srcId, &data, sizeof(data)))
388 goto fail;
389
390 UINT32 size = 0;
391 uris = test_ClipboardGetData(clipboard, dstId, &size);
392 if (!uris)
393 goto fail;
394 test_log("text/uri-list: '%s'", uris);
395
396 if (!strstr(uris, cmpdir))
397 {
398 test_log("strstr(%s, %s) failed", uris, cmpdir);
399 goto fail;
400 }
401 if (strstr(uris, "b.txt"))
402 {
403 test_log("strstr(%s, %s) failed", uris, "b.txt");
404 goto fail;
405 }
406 }
407
408 rc = TRUE;
409fail:
410 if (!rc)
411 test_log("FileGroupDescriptorW -> text/uri-list conversion failed");
412 free(uris);
413 free(cmpdir);
414 free(cmpa);
415 free(basePath);
416 ClipboardDestroy(clipboard);
417 return rc;
418}
419
420/* image/bmp from the clipboard has a plain BITMAPINFOHEADER and is stored bottom-up */
421WINPR_ATTR_NODISCARD
422static BOOL test_is_plain_bmp(const BYTE* bmp, size_t size)
423{
424 if ((size < 54) || (bmp[0] != 'B') || (bmp[1] != 'M'))
425 return FALSE;
426
427 UINT32 biSize = 0;
428 INT32 biHeight = 0;
429 UINT32 biCompression = 0;
430 memcpy(&biSize, &bmp[14], sizeof(biSize));
431 memcpy(&biHeight, &bmp[22], sizeof(biHeight));
432 memcpy(&biCompression, &bmp[30], sizeof(biCompression));
433 if ((biSize != 40) || (biHeight <= 0) || (biCompression != BI_RGB))
434 {
435 test_log("not a plain bottom-up BMP: biSize=%" PRIu32 " biHeight=%" PRId32
436 " biCompression=%" PRIu32,
437 biSize, biHeight, biCompression);
438 return FALSE;
439 }
440 return TRUE;
441}
442
443/* convert the clipboard content to dstMime and compare the image with the expected one */
444WINPR_ATTR_NODISCARD
445static BOOL test_convert_image(wClipboard* clipboard, const char* dstMime, const wImage* expected)
446{
447 BOOL rc = FALSE;
448 UINT32 size = 0;
449 wImage* img = winpr_image_new();
450 BYTE* data =
451 test_ClipboardGetData(clipboard, ClipboardRegisterFormat(clipboard, dstMime), &size);
452 if (!img || !data)
453 goto fail;
454
455 if (winpr_image_read_buffer(img, data, size) <= 0)
456 {
457 test_log("can not read %s", dstMime);
458 goto fail;
459 }
460
461 if (!winpr_image_equal(expected, img,
462 WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
463 WINPR_IMAGE_CMP_FUZZY))
464 {
465 test_log("%s differs from the source image", dstMime);
466 goto fail;
467 }
468
469 if ((strcmp(dstMime, "image/bmp") == 0) && !test_is_plain_bmp(data, size))
470 goto fail;
471
472 rc = TRUE;
473fail:
474 free(data);
475 winpr_image_free(img, TRUE);
476 return rc;
477}
478
479/* image formats convert into each other directly, without going through CF_DIB first */
480WINPR_ATTR_NODISCARD
481static BOOL test_image_to_image(void)
482{
483 BOOL rc = FALSE;
484 void* data = nullptr;
485 size_t size = 0;
486 wClipboard* clipboard = ClipboardCreate();
487 wImage* img = winpr_image_new();
488 if (!clipboard || !img)
489 goto fail;
490
491 if (winpr_image_read(img, TEST_CLIP_BMP) <= 0)
492 goto fail;
493
494 data = winpr_image_write_buffer(img, WINPR_IMAGE_BITMAP, &size);
495 if (!data || !test_ClipboardSetData(clipboard, ClipboardRegisterFormat(clipboard, "image/bmp"),
496 data, (UINT32)size))
497 goto fail;
498 free(data);
499 data = nullptr;
500
501 if (!test_convert_image(clipboard, "image/x-bmp", img))
502 goto fail;
503#if defined(WINPR_UTILS_IMAGE_PNG)
504 if (!test_convert_image(clipboard, "image/png", img))
505 goto fail;
506
507 data = winpr_image_write_buffer(img, WINPR_IMAGE_PNG, &size);
508 if (!data || !test_ClipboardSetData(clipboard, ClipboardRegisterFormat(clipboard, "image/png"),
509 data, (UINT32)size))
510 goto fail;
511
512 if (!test_convert_image(clipboard, "image/bmp", img))
513 goto fail;
514#endif
515
516 rc = TRUE;
517fail:
518 free(data);
519 winpr_image_free(img, TRUE);
520 ClipboardDestroy(clipboard);
521 return rc;
522}
523
524/* text/plain is UTF-8 on Windows and ASCII with \u escapes elsewhere; both convert back */
525WINPR_ATTR_NODISCARD
526static BOOL test_text_plain(void)
527{
528 BOOL rc = FALSE;
529 const char utf8[] = "A\xe4\xb8\xad\xe6\x96\x87\xc3\xa9"; /* A, two CJK characters, e acute */
530 const size_t utf8len = strlen(utf8);
531 char* plain = nullptr;
532 WCHAR* wstr = nullptr;
533 char* back = nullptr;
534 UINT32 size = 0;
535
536 wClipboard* clipboard = ClipboardCreate();
537 if (!clipboard)
538 goto fail;
539
540 const UINT32 idUtf8 = ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8");
541 const UINT32 idPlain = ClipboardRegisterFormat(clipboard, "text/plain");
542 if (!test_ClipboardSetData(clipboard, idUtf8, utf8, (UINT32)utf8len))
543 goto fail;
544
545 plain = test_ClipboardGetData(clipboard, idPlain, &size);
546 if (!plain)
547 goto fail;
548
549#if defined(_WIN32)
550 if ((size < utf8len) || (memcmp(plain, utf8, utf8len) != 0))
551 {
552 test_log("text/plain is not UTF-8");
553 goto fail;
554 }
555#else
556 for (UINT32 x = 0; x < size; x++)
557 {
558 if ((BYTE)plain[x] > 0x7f)
559 {
560 test_log("text/plain is not ASCII");
561 goto fail;
562 }
563 }
564#endif
565
566 if (!test_ClipboardSetData(clipboard, idPlain, plain, size))
567 goto fail;
568
569 wstr = test_ClipboardGetData(clipboard, CF_UNICODETEXT, &size);
570 if (!wstr)
571 goto fail;
572
573 {
574 size_t backlen = 0;
575 back = ConvertWCharNToUtf8Alloc(wstr, size / sizeof(WCHAR), &backlen);
576 if (!back || (backlen < utf8len) || (memcmp(back, utf8, utf8len) != 0))
577 {
578 test_log("text/plain does not convert back to the original text");
579 goto fail;
580 }
581 }
582
583 rc = TRUE;
584fail:
585 free(back);
586 free(wstr);
587 free(plain);
588 ClipboardDestroy(clipboard);
589 return rc;
590}
591
592int TestClipboardFormats(int argc, char* argv[])
593{
594 int rc = -1;
595 UINT32 count = 0;
596 UINT32* pFormatIds = nullptr;
597 const char* formatName = nullptr;
598 UINT32 utf8StringFormatId = 0;
599
600 WINPR_UNUSED(argc);
601 WINPR_UNUSED(argv);
602
603 if (!test_text_leading_newline())
604 return -1;
605
606 if (!test_text_conversion())
607 return -1;
608
609 if (!test_file_descriptors_to_uri_list())
610 return -1;
611
612 wClipboard* clipboard = ClipboardCreate();
613 if (!clipboard)
614 return -1;
615
616 const char* mime_types[] = { "text/plain", "text/plain;charset=utf-8",
617 "text/html", "image/bmp",
618 "image/png", "image/webp",
619 "image/jpeg" };
620 for (size_t x = 0; x < ARRAYSIZE(mime_types); x++)
621 {
622 const char* mime = mime_types[x];
623 UINT32 id = ClipboardRegisterFormat(clipboard, mime);
624 test_log("ClipboardRegisterFormat(%s) -> 0x%08" PRIx32 "", mime, id);
625 if (id == 0)
626 goto fail;
627 }
628
629 utf8StringFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING");
630 pFormatIds = nullptr;
631 count = ClipboardGetRegisteredFormatIds(clipboard, &pFormatIds);
632
633 for (UINT32 index = 0; index < count; index++)
634 {
635 UINT32 formatId = pFormatIds[index];
636 formatName = ClipboardGetFormatName(clipboard, formatId);
637 test_log("Format: 0x%08" PRIX32 " %s", formatId, formatName);
638 }
639
640 free(pFormatIds);
641
642 if (1)
643 {
644 const char pSrcData[] = "this is a test string";
645 char* pDstData = nullptr;
646
647 UINT32 SrcSize = (UINT32)(strnlen(pSrcData, ARRAYSIZE(pSrcData)) + 1);
648 const BOOL bSuccess =
649 test_ClipboardSetData(clipboard, utf8StringFormatId, pSrcData, SrcSize);
650 if (!bSuccess)
651 goto fail;
652
653 UINT32 DstSize = 0;
654 pDstData = (char*)test_ClipboardGetData(clipboard, utf8StringFormatId, &DstSize);
655 const BOOL equal = (SrcSize == DstSize) && (strncmp(pSrcData, pDstData, SrcSize) == 0);
656 free(pDstData);
657 if (!equal)
658 goto fail;
659 {
660 UINT32 WDstSize = 0;
661 WCHAR* pDstData = (WCHAR*)test_ClipboardGetData(clipboard, CF_UNICODETEXT, &WDstSize);
662
663 size_t cmpSrcSize = 0;
664 char* pCmpData =
665 ConvertWCharNToUtf8Alloc(pDstData, WDstSize / sizeof(WCHAR), &cmpSrcSize);
666 const BOOL equal2 =
667 (SrcSize == cmpSrcSize + 1ull) && (strncmp(pCmpData, pSrcData, SrcSize) == 0);
668 free(pDstData);
669 free(pCmpData);
670 if (!equal2)
671 goto fail;
672 }
673 }
674
675 pFormatIds = nullptr;
676 count = ClipboardGetFormatIds(clipboard, &pFormatIds);
677
678 for (UINT32 index = 0; index < count; index++)
679 {
680 UINT32 formatId = pFormatIds[index];
681 formatName = ClipboardGetFormatName(clipboard, formatId);
682 test_log("Format: 0x%08" PRIX32 " %s", formatId, formatName);
683 }
684
685 if (1)
686 {
687 const char* name = TEST_CLIP_BMP;
688 BOOL bSuccess = FALSE;
689 UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/bmp");
690
691 wImage* img = winpr_image_new();
692 if (!img)
693 goto fail;
694
695 if (winpr_image_read(img, name) <= 0)
696 {
697 winpr_image_free(img, TRUE);
698 goto fail;
699 }
700
701 size_t bmpsize = 0;
702 void* data = winpr_image_write_buffer(img, WINPR_IMAGE_BITMAP, &bmpsize);
703 bSuccess = test_ClipboardSetData(clipboard, idBmp, data, bmpsize);
704
705 free(data);
706 winpr_image_free(img, TRUE);
707 if (!bSuccess)
708 goto fail;
709
710 {
711 UINT32 id = CF_DIB;
712
713 UINT32 DstSize = 0;
714 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
715 if (!pDstData)
716 goto fail;
717 bSuccess = test_ClipboardSetData(clipboard, id, pDstData, DstSize);
718 free(pDstData);
719 if (!bSuccess)
720 goto fail;
721 }
722 {
723 const uint32_t id = ClipboardGetFormatId(clipboard, "HTML Format");
724 UINT32 DstSize = 0;
725 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
726 if (!pDstData)
727 goto fail;
728 {
729 FILE* fp = fopen("test.html", "w");
730 if (fp)
731 {
732 (void)fwrite(pDstData, 1, DstSize, fp);
733 (void)fclose(fp);
734 }
735 }
736 free(pDstData);
737 }
738 {
739 UINT32 id = ClipboardRegisterFormat(clipboard, "image/bmp");
740
741 UINT32 DstSize = 0;
742 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
743 if (!pDstData)
744 goto fail;
745 free(pDstData);
746 if (DstSize != bmpsize)
747 goto fail;
748 }
749
750#if defined(WINPR_UTILS_IMAGE_PNG)
751 {
752 UINT32 id = ClipboardRegisterFormat(clipboard, "image/png");
753
754 UINT32 DstSize = 0;
755 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
756 if (!pDstData)
757 goto fail;
758 free(pDstData);
759 }
760 {
761 const char* name = TEST_CLIP_PNG;
762 BOOL bSuccess = FALSE;
763 UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/png");
764
765 wImage* img = winpr_image_new();
766 if (!img)
767 goto fail;
768
769 if (winpr_image_read(img, name) <= 0)
770 {
771 winpr_image_free(img, TRUE);
772 goto fail;
773 }
774
775 size_t bmpsize = 0;
776 void* data = winpr_image_write_buffer(img, WINPR_IMAGE_PNG, &bmpsize);
777 bSuccess = test_ClipboardSetData(clipboard, idBmp, data, bmpsize);
778
779 free(data);
780 winpr_image_free(img, TRUE);
781 if (!bSuccess)
782 goto fail;
783 }
784 {
785 UINT32 id = CF_DIB;
786
787 UINT32 DstSize = 0;
788 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
789 if (!pDstData)
790 goto fail;
791 bSuccess = test_ClipboardSetData(clipboard, id, pDstData, DstSize);
792 free(pDstData);
793 if (!bSuccess)
794 goto fail;
795 }
796#endif
797
798#if defined(WINPR_UTILS_IMAGE_WEBP)
799 {
800 UINT32 id = ClipboardRegisterFormat(clipboard, "image/webp");
801
802 UINT32 DstSize = 0;
803 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
804 if (!pDstData)
805 goto fail;
806 free(pDstData);
807 }
808#endif
809
810#if defined(WINPR_UTILS_IMAGE_JPEG)
811 {
812 UINT32 id = ClipboardRegisterFormat(clipboard, "image/jpeg");
813
814 UINT32 DstSize = 0;
815 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
816 if (!pDstData)
817 goto fail;
818 free(pDstData);
819 }
820#endif
821 }
822
823 if (!test_dib_offsets())
824 goto fail;
825
826 if (!test_image_to_image())
827 goto fail;
828
829 if (!test_text_plain())
830 goto fail;
831
832 rc = 0;
833
834fail:
835 free(pFormatIds);
836 ClipboardDestroy(clipboard);
837 return rc;
838}