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 const char** cur = tests[x];
178 /* local text/plain is set without a terminator */
179 if (!test_ClipboardSetData(clipboard, textId, cur[0], (UINT32)strlen(cur[0])))
180 goto fail;
181
182 UINT32 size = 0;
183 WCHAR* wstr = test_ClipboardGetData(clipboard, CF_UNICODETEXT, &size);
184 char* str = ConvertWCharNToUtf8Alloc(wstr, size / sizeof(WCHAR), nullptr);
185 const BOOL match = str && (strcmp(str, cur[1]) == 0);
186 if (!match)
187 {
188 test_log("text/plain to CF_UNICODETEXT failed for case %" PRIuz "[%s (%" PRIu32
189 ") %p : expect %s (%" PRIuz ") : from %s (" PRIuz ")]",
190 x, str, size, wstr, cur[1], strlen(cur[1]), cur[0], strlen(cur[0]));
191 }
192 free(wstr);
193 free(str);
194 if (!match)
195 goto fail;
196 }
197 rc = TRUE;
198
199fail:
200 ClipboardDestroy(clipboard);
201 return rc;
202}
203
204WINPR_ATTR_NODISCARD
205static BOOL test_text_conversion(void)
206{
207 wClipboard* clipboard = ClipboardCreate();
208 if (!clipboard)
209 return FALSE;
210
211 typedef struct
212 {
213 UINT32 srcFormat;
214 UINT32 dstFormat;
215 const char* src;
216 size_t srcLen;
217 const char* expect;
218 size_t expectLen;
219 } test_case_t;
220
221 const test_case_t tests[] = {
222 { ClipboardRegisterFormat(clipboard, "text/plain"),
223 ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"), "a\nb\rc\\u1234\\u055e",
224 17, "a\nb\ncሴ՞", 10 },
225 { ClipboardRegisterFormat(clipboard, "text/plain;charset=utf-8"),
226 ClipboardRegisterFormat(clipboard, "text/plain"), "a\r\nb\nc՞՞", 10,
227 "a\r\nb\nc\\u055e\\u055e", 18 },
228 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_UNICODETEXT, "a\nb\rc\\u1234\\u055e",
229 17, "\x61\x00\x0d\x00\x0a\x00\x62\x00\x0d\x0\x0a\x00\x63\x00\x34\x12\x5e\x05\x00\x00\x00",
230 18 },
231 { CF_UNICODETEXT, ClipboardRegisterFormat(clipboard, "text/plain"),
232 "\x61\x00\x0d\x00\x0a\x00\x62\x00\x0d\x0\x0a\x00\x63\x00\x34\x12\x5e\x05\x00\x00\x00", 18,
233 "a\nb\nc\\u1234\\u055e", 17 },
234 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_TEXT, "a\nb\rc\\u1234\\u055e", 17,
235 "a\nb\nc\\u1234\\u055e", 17 },
236 { CF_TEXT, ClipboardRegisterFormat(clipboard, "text/plain"), "a\nb\nc\\u1234\\u055e", 17,
237 "a\nb\nc\\u1234\\u055e", 17 },
238 { ClipboardRegisterFormat(clipboard, "text/plain"), CF_OEMTEXT, "a\nb\rc\\u1234\\u055e", 17,
239 "a\nb\nc\\u1234\\u055e", 17 },
240 { CF_OEMTEXT, ClipboardRegisterFormat(clipboard, "text/plain"), "a\nb\rc\\u1234\\u055e", 17,
241 "a\nb\nc\\u1234\\u055e", 17 }
242 };
243
244 BOOL rc = FALSE;
245
246 for (size_t x = 0; x < ARRAYSIZE(tests); x++)
247 {
248 const test_case_t* cur = &tests[x];
249
250 /* local text/plain is set without a terminator */
251 if (!test_ClipboardSetData(clipboard, cur->srcFormat, cur->src, cur->srcLen))
252 goto fail;
253
254 UINT32 dstSize = 0;
255 BYTE* data = test_ClipboardGetData(clipboard, cur->dstFormat, &dstSize);
256 if (dstSize != cur->expectLen)
257 {
258 winpr_znfree(data, dstSize);
259 goto fail;
260 }
261 if (dstSize != 0)
262 {
263 if (!data)
264 {
265 winpr_znfree(data, dstSize);
266 goto fail;
267 }
268 const int rc = memcmp(cur->expect, data, cur->expectLen);
269 winpr_znfree(data, dstSize);
270 if (rc != 0)
271 goto fail;
272 }
273 else
274 winpr_znfree(data, dstSize);
275 }
276 rc = TRUE;
277
278fail:
279 ClipboardDestroy(clipboard);
280 return rc;
281}
282
283int TestClipboardFormats(int argc, char* argv[])
284{
285 int rc = -1;
286 UINT32 count = 0;
287 UINT32* pFormatIds = nullptr;
288 const char* formatName = nullptr;
289 UINT32 utf8StringFormatId = 0;
290
291 WINPR_UNUSED(argc);
292 WINPR_UNUSED(argv);
293
294 if (!test_text_leading_newline())
295 return -1;
296
297 if (!test_text_conversion())
298 return -1;
299
300 wClipboard* clipboard = ClipboardCreate();
301 if (!clipboard)
302 return -1;
303
304 const char* mime_types[] = { "text/plain", "text/plain;charset=utf-8",
305 "text/html", "image/bmp",
306 "image/png", "image/webp",
307 "image/jpeg" };
308 for (size_t x = 0; x < ARRAYSIZE(mime_types); x++)
309 {
310 const char* mime = mime_types[x];
311 UINT32 id = ClipboardRegisterFormat(clipboard, mime);
312 test_log("ClipboardRegisterFormat(%s) -> 0x%08" PRIx32 "", mime, id);
313 if (id == 0)
314 goto fail;
315 }
316
317 utf8StringFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING");
318 pFormatIds = nullptr;
319 count = ClipboardGetRegisteredFormatIds(clipboard, &pFormatIds);
320
321 for (UINT32 index = 0; index < count; index++)
322 {
323 UINT32 formatId = pFormatIds[index];
324 formatName = ClipboardGetFormatName(clipboard, formatId);
325 test_log("Format: 0x%08" PRIX32 " %s", formatId, formatName);
326 }
327
328 free(pFormatIds);
329
330 if (1)
331 {
332 const char pSrcData[] = "this is a test string";
333 char* pDstData = nullptr;
334
335 UINT32 SrcSize = (UINT32)(strnlen(pSrcData, ARRAYSIZE(pSrcData)) + 1);
336 const BOOL bSuccess =
337 test_ClipboardSetData(clipboard, utf8StringFormatId, pSrcData, SrcSize);
338 if (!bSuccess)
339 goto fail;
340
341 UINT32 DstSize = 0;
342 pDstData = (char*)test_ClipboardGetData(clipboard, utf8StringFormatId, &DstSize);
343 const BOOL equal = (SrcSize == DstSize) && (strncmp(pSrcData, pDstData, SrcSize) == 0);
344 free(pDstData);
345 if (!equal)
346 goto fail;
347 {
348 UINT32 WDstSize = 0;
349 WCHAR* pDstData = (WCHAR*)test_ClipboardGetData(clipboard, CF_UNICODETEXT, &WDstSize);
350
351 size_t cmpSrcSize = 0;
352 char* pCmpData =
353 ConvertWCharNToUtf8Alloc(pDstData, WDstSize / sizeof(WCHAR), &cmpSrcSize);
354 const BOOL equal2 =
355 (SrcSize == cmpSrcSize + 1ull) && (strncmp(pCmpData, pSrcData, SrcSize) == 0);
356 free(pDstData);
357 free(pCmpData);
358 if (!equal2)
359 goto fail;
360 }
361 }
362
363 pFormatIds = nullptr;
364 count = ClipboardGetFormatIds(clipboard, &pFormatIds);
365
366 for (UINT32 index = 0; index < count; index++)
367 {
368 UINT32 formatId = pFormatIds[index];
369 formatName = ClipboardGetFormatName(clipboard, formatId);
370 test_log("Format: 0x%08" PRIX32 " %s", formatId, formatName);
371 }
372
373 if (1)
374 {
375 const char* name = TEST_CLIP_BMP;
376 BOOL bSuccess = FALSE;
377 UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/bmp");
378
379 wImage* img = winpr_image_new();
380 if (!img)
381 goto fail;
382
383 if (winpr_image_read(img, name) <= 0)
384 {
385 winpr_image_free(img, TRUE);
386 goto fail;
387 }
388
389 size_t bmpsize = 0;
390 void* data = winpr_image_write_buffer(img, WINPR_IMAGE_BITMAP, &bmpsize);
391 bSuccess = test_ClipboardSetData(clipboard, idBmp, data, bmpsize);
392
393 free(data);
394 winpr_image_free(img, TRUE);
395 if (!bSuccess)
396 goto fail;
397
398 {
399 UINT32 id = CF_DIB;
400
401 UINT32 DstSize = 0;
402 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
403 if (!pDstData)
404 goto fail;
405 bSuccess = test_ClipboardSetData(clipboard, id, pDstData, DstSize);
406 free(pDstData);
407 if (!bSuccess)
408 goto fail;
409 }
410 {
411 const uint32_t id = ClipboardGetFormatId(clipboard, "HTML Format");
412 UINT32 DstSize = 0;
413 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
414 if (!pDstData)
415 goto fail;
416 {
417 FILE* fp = fopen("test.html", "w");
418 if (fp)
419 {
420 (void)fwrite(pDstData, 1, DstSize, fp);
421 (void)fclose(fp);
422 }
423 }
424 free(pDstData);
425 }
426 {
427 UINT32 id = ClipboardRegisterFormat(clipboard, "image/bmp");
428
429 UINT32 DstSize = 0;
430 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
431 if (!pDstData)
432 goto fail;
433 free(pDstData);
434 if (DstSize != bmpsize)
435 goto fail;
436 }
437
438#if defined(WINPR_UTILS_IMAGE_PNG)
439 {
440 UINT32 id = ClipboardRegisterFormat(clipboard, "image/png");
441
442 UINT32 DstSize = 0;
443 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
444 if (!pDstData)
445 goto fail;
446 free(pDstData);
447 }
448 {
449 const char* name = TEST_CLIP_PNG;
450 BOOL bSuccess = FALSE;
451 UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/png");
452
453 wImage* img = winpr_image_new();
454 if (!img)
455 goto fail;
456
457 if (winpr_image_read(img, name) <= 0)
458 {
459 winpr_image_free(img, TRUE);
460 goto fail;
461 }
462
463 size_t bmpsize = 0;
464 void* data = winpr_image_write_buffer(img, WINPR_IMAGE_PNG, &bmpsize);
465 bSuccess = test_ClipboardSetData(clipboard, idBmp, data, bmpsize);
466
467 free(data);
468 winpr_image_free(img, TRUE);
469 if (!bSuccess)
470 goto fail;
471 }
472 {
473 UINT32 id = CF_DIB;
474
475 UINT32 DstSize = 0;
476 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
477 if (!pDstData)
478 goto fail;
479 bSuccess = test_ClipboardSetData(clipboard, id, pDstData, DstSize);
480 free(pDstData);
481 if (!bSuccess)
482 goto fail;
483 }
484#endif
485
486#if defined(WINPR_UTILS_IMAGE_WEBP)
487 {
488 UINT32 id = ClipboardRegisterFormat(clipboard, "image/webp");
489
490 UINT32 DstSize = 0;
491 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
492 if (!pDstData)
493 goto fail;
494 free(pDstData);
495 }
496#endif
497
498#if defined(WINPR_UTILS_IMAGE_JPEG)
499 {
500 UINT32 id = ClipboardRegisterFormat(clipboard, "image/jpeg");
501
502 UINT32 DstSize = 0;
503 void* pDstData = test_ClipboardGetData(clipboard, id, &DstSize);
504 if (!pDstData)
505 goto fail;
506 free(pDstData);
507 }
508#endif
509 }
510
511 if (!test_dib_offsets())
512 goto fail;
513
514 rc = 0;
515
516fail:
517 free(pFormatIds);
518 ClipboardDestroy(clipboard);
519 return rc;
520}