Coverage Report

Created: 2026-09-01 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/clipboard/synthetic.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Clipboard Functions
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include <errno.h>
23
#include <winpr/crt.h>
24
#include <winpr/user.h>
25
#include <winpr/image.h>
26
27
#include "../utils/image.h"
28
#include "clipboard.h"
29
30
#include "../log.h"
31
#define TAG WINPR_TAG("clipboard.synthetic")
32
33
static const char mime_html[] = "text/html";
34
static const char mime_ms_html[] = "HTML Format";
35
static const char* mime_bitmap[] = { "image/bmp", "image/x-bmp", "image/x-MS-bmp",
36
                                   "image/x-win-bitmap" };
37
38
static const char mime_webp[] = "image/webp";
39
static const char mime_png[] = "image/png";
40
static const char mime_jpeg[] = "image/jpeg";
41
static const char mime_tiff[] = "image/tiff";
42
43
static const BYTE enc_base64url[] =
44
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45
46
WINPR_ATTR_NODISCARD static inline char* b64_encode(const BYTE* WINPR_RESTRICT data, size_t length,
47
                                                    size_t* plen)
48
168
{
49
168
  WINPR_ASSERT(plen);
50
168
  const BYTE* WINPR_RESTRICT alphabet = enc_base64url;
51
168
  int c = 0;
52
168
  size_t blocks = 0;
53
168
  size_t outLen = (length + 3) * 4 / 3;
54
168
  size_t extra = 0;
55
56
168
  const BYTE* q = data;
57
168
  const size_t alen = outLen + extra + 1ull;
58
168
  BYTE* p = malloc(alen);
59
168
  if (!p)
60
0
    return nullptr;
61
62
168
  BYTE* ret = p;
63
64
  /* b1, b2, b3 are input bytes
65
   *
66
   * 0         1         2
67
   * 012345678901234567890123
68
   * |  b1  |  b2   |  b3   |
69
   *
70
   * [ c1 ]     [  c3 ]
71
   *      [  c2 ]     [  c4 ]
72
   *
73
   * c1, c2, c3, c4 are output chars in base64
74
   */
75
76
  /* first treat complete blocks */
77
168
  blocks = length - (length % 3);
78
538k
  for (size_t i = 0; i < blocks; i += 3, q += 3)
79
538k
  {
80
538k
    c = (q[0] << 16) + (q[1] << 8) + q[2];
81
82
538k
    *p++ = alphabet[(c & 0x00FC0000) >> 18];
83
538k
    *p++ = alphabet[(c & 0x0003F000) >> 12];
84
538k
    *p++ = alphabet[(c & 0x00000FC0) >> 6];
85
538k
    *p++ = alphabet[c & 0x0000003F];
86
538k
  }
87
88
  /* then remainder */
89
168
  switch (length % 3)
90
168
  {
91
55
    case 0:
92
55
      break;
93
46
    case 1:
94
46
      c = (q[0] << 16);
95
46
      *p++ = alphabet[(c & 0x00FC0000) >> 18];
96
46
      *p++ = alphabet[(c & 0x0003F000) >> 12];
97
46
      break;
98
67
    case 2:
99
67
      c = (q[0] << 16) + (q[1] << 8);
100
67
      *p++ = alphabet[(c & 0x00FC0000) >> 18];
101
67
      *p++ = alphabet[(c & 0x0003F000) >> 12];
102
67
      *p++ = alphabet[(c & 0x00000FC0) >> 6];
103
67
      break;
104
0
    default:
105
0
      break;
106
168
  }
107
108
168
  *p = 0;
109
168
  *plen = WINPR_ASSERTING_INT_CAST(size_t, p - ret);
110
111
168
  return (char*)ret;
112
168
}
113
114
/**
115
 * Standard Clipboard Formats:
116
 * http://msdn.microsoft.com/en-us/library/windows/desktop/ff729168/
117
 */
118
119
/**
120
 * "CF_TEXT":
121
 *
122
 * Null-terminated ANSI text with CR/LF line endings.
123
 */
124
125
static void* clipboard_synthesize_cf_text(wClipboard* clipboard, UINT32 formatId, const void* data,
126
                                          UINT32* pSize)
127
618
{
128
618
  size_t size = 0;
129
618
  char* pDstData = nullptr;
130
131
618
  if (formatId == CF_UNICODETEXT)
132
362
  {
133
362
    char* str = ConvertWCharNToUtf8Alloc(data, *pSize / sizeof(WCHAR), &size);
134
135
362
    if (!str || (size > UINT32_MAX))
136
90
    {
137
90
      free(str);
138
90
      return nullptr;
139
90
    }
140
141
272
    pDstData = ConvertLineEndingToCRLF(str, &size);
142
272
    free(str);
143
272
    *pSize = (UINT32)size;
144
272
    return pDstData;
145
362
  }
146
256
  else if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) ||
147
0
           (formatId == ClipboardGetFormatId(clipboard, mime_text_plain)))
148
256
  {
149
256
    size = *pSize;
150
256
    pDstData = ConvertLineEndingToCRLF(data, &size);
151
152
256
    if (!pDstData || (size > *pSize))
153
108
    {
154
108
      free(pDstData);
155
108
      return nullptr;
156
108
    }
157
158
148
    *pSize = (UINT32)size;
159
148
    return pDstData;
160
256
  }
161
162
0
  return nullptr;
163
618
}
164
165
/**
166
 * "CF_OEMTEXT":
167
 *
168
 * Null-terminated OEM text with CR/LF line endings.
169
 */
170
171
static void* clipboard_synthesize_cf_oemtext(wClipboard* clipboard, UINT32 formatId,
172
                                             const void* data, UINT32* pSize)
173
274
{
174
274
  return clipboard_synthesize_cf_text(clipboard, formatId, data, pSize);
175
274
}
176
177
/**
178
 * "CF_LOCALE":
179
 *
180
 * System locale identifier associated with CF_TEXT
181
 */
182
183
static void* clipboard_synthesize_cf_locale(WINPR_ATTR_UNUSED wClipboard* clipboard,
184
                                            WINPR_ATTR_UNUSED UINT32 formatId,
185
                                            WINPR_ATTR_UNUSED const void* data,
186
                                            WINPR_ATTR_UNUSED UINT32* pSize)
187
437
{
188
437
  UINT32* pDstData = nullptr;
189
437
  pDstData = (UINT32*)malloc(sizeof(UINT32));
190
191
437
  if (!pDstData)
192
0
    return nullptr;
193
194
437
  *pDstData = 0x0409; /* English - United States */
195
437
  return (void*)pDstData;
196
437
}
197
198
/**
199
 * "CF_UNICODETEXT":
200
 *
201
 * Null-terminated UTF-16 text with CR/LF line endings.
202
 */
203
204
static void* clipboard_synthesize_cf_unicodetext(wClipboard* clipboard, UINT32 formatId,
205
                                                 const void* data, UINT32* pSize)
206
256
{
207
256
  size_t size = 0;
208
256
  char* crlfStr = nullptr;
209
256
  WCHAR* pDstData = nullptr;
210
211
256
  if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) ||
212
0
      (formatId == ClipboardGetFormatId(clipboard, mime_text_plain)))
213
256
  {
214
256
    size_t len = 0;
215
256
    if (!pSize || (*pSize > INT32_MAX))
216
0
      return nullptr;
217
218
256
    size = *pSize;
219
256
    crlfStr = ConvertLineEndingToCRLF((const char*)data, &size);
220
221
256
    if (!crlfStr)
222
0
      return nullptr;
223
224
256
    pDstData = ConvertUtf8NToWCharAlloc(crlfStr, size, &len);
225
256
    free(crlfStr);
226
227
256
    if ((len < 1) || ((len + 1) > UINT32_MAX / sizeof(WCHAR)))
228
122
    {
229
122
      free(pDstData);
230
122
      return nullptr;
231
122
    }
232
233
134
    const size_t slen = (len + 1) * sizeof(WCHAR);
234
134
    *pSize = (UINT32)slen;
235
134
  }
236
237
134
  return (void*)pDstData;
238
256
}
239
240
/**
241
 * mime_utf8_string:
242
 *
243
 * Null-terminated UTF-8 string with LF line endings.
244
 */
245
246
static void* clipboard_synthesize_utf8_string(wClipboard* clipboard, UINT32 formatId,
247
                                              const void* data, UINT32* pSize)
248
437
{
249
437
  if (formatId == CF_UNICODETEXT)
250
181
  {
251
181
    size_t size = 0;
252
181
    char* pDstData = ConvertWCharNToUtf8Alloc(data, *pSize / sizeof(WCHAR), &size);
253
254
181
    if (!pDstData)
255
45
      return nullptr;
256
257
136
    const size_t rc = ConvertLineEndingToLF(pDstData, size);
258
136
    WINPR_ASSERT(rc <= UINT32_MAX);
259
136
    *pSize = (UINT32)rc;
260
136
    return pDstData;
261
181
  }
262
256
  else if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) ||
263
0
           (formatId == ClipboardGetFormatId(clipboard, mime_text_plain)))
264
256
  {
265
256
    const size_t size = *pSize;
266
256
    char* pDstData = calloc(size + 1, sizeof(char));
267
268
256
    if (!pDstData)
269
0
      return nullptr;
270
271
256
    CopyMemory(pDstData, data, size);
272
256
    const size_t rc = ConvertLineEndingToLF(pDstData, size);
273
256
    WINPR_ASSERT(rc <= UINT32_MAX);
274
256
    *pSize = (UINT32)rc;
275
256
    return pDstData;
276
256
  }
277
278
0
  return nullptr;
279
437
}
280
281
static BOOL is_format_bitmap(wClipboard* clipboard, UINT32 formatId)
282
154
{
283
154
  for (size_t x = 0; x < ARRAYSIZE(mime_bitmap); x++)
284
154
  {
285
154
    const char* mime = mime_bitmap[x];
286
154
    const UINT32 altFormatId = ClipboardGetFormatId(clipboard, mime);
287
154
    if (altFormatId == formatId)
288
154
      return TRUE;
289
154
  }
290
291
0
  return FALSE;
292
154
}
293
294
/**
295
 * "CF_DIB":
296
 *
297
 * BITMAPINFO structure followed by the bitmap bits.
298
 */
299
300
static void* clipboard_synthesize_cf_dib(wClipboard* clipboard, UINT32 formatId, const void* data,
301
                                         UINT32* pSize)
302
154
{
303
154
  UINT32 SrcSize = 0;
304
154
  UINT32 DstSize = 0;
305
154
  BYTE* pDstData = nullptr;
306
154
  SrcSize = *pSize;
307
308
#if defined(WINPR_UTILS_IMAGE_DIBv5)
309
  if (formatId == CF_DIBV5)
310
  {
311
    WLog_WARN(TAG, "[DIB] Unsupported destination format %s",
312
              ClipboardGetFormatName(clipboard, formatId));
313
  }
314
  else
315
#endif
316
154
      if (is_format_bitmap(clipboard, formatId))
317
154
  {
318
154
    WINPR_BITMAP_FILE_HEADER pFileHeader = WINPR_C_ARRAY_INIT;
319
154
    wStream sbuffer = WINPR_C_ARRAY_INIT;
320
154
    wStream* s = Stream_StaticConstInit(&sbuffer, data, SrcSize);
321
154
    if (!readBitmapFileHeader(s, &pFileHeader))
322
142
      return nullptr;
323
324
12
    DstSize = SrcSize - sizeof(BITMAPFILEHEADER);
325
12
    pDstData = (BYTE*)malloc(DstSize);
326
327
12
    if (!pDstData)
328
0
      return nullptr;
329
330
12
    data = (const void*)&((const BYTE*)data)[sizeof(BITMAPFILEHEADER)];
331
12
    CopyMemory(pDstData, data, DstSize);
332
12
    *pSize = DstSize;
333
12
    return pDstData;
334
12
  }
335
0
  else
336
0
  {
337
0
    WLog_WARN(TAG, "[DIB] Unsupported destination format %s",
338
0
              ClipboardGetFormatName(clipboard, formatId));
339
0
  }
340
341
0
  return nullptr;
342
154
}
343
344
/**
345
 * "CF_DIBV5":
346
 *
347
 * BITMAPV5HEADER structure followed by the bitmap color space information and the bitmap bits.
348
 */
349
#if defined(WINPR_UTILS_IMAGE_DIBv5)
350
static void* clipboard_synthesize_cf_dibv5(wClipboard* clipboard, UINT32 formatId,
351
                                           WINPR_ATTR_UNUSED const void* data,
352
                                           WINPR_ATTR_UNUSED UINT32* pSize)
353
{
354
  if (formatId == CF_DIB)
355
  {
356
    WLog_WARN(TAG, "[DIBv5] Unsupported destination format %s",
357
              ClipboardGetFormatName(clipboard, formatId));
358
  }
359
  else if (is_format_bitmap(clipboard, formatId))
360
  {
361
    WLog_WARN(TAG, "[DIBv5] Unsupported destination format %s",
362
              ClipboardGetFormatName(clipboard, formatId));
363
  }
364
  else
365
  {
366
    BOOL handled = FALSE;
367
#if defined(WINPR_UTILS_IMAGE_PNG)
368
    {
369
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_png);
370
      if (formatId == altFormatId)
371
      {
372
      }
373
    }
374
#endif
375
#if defined(WINPR_UTILS_IMAGE_JPEG)
376
    {
377
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_jpeg);
378
      if (formatId == altFormatId)
379
      {
380
      }
381
    }
382
#endif
383
    if (!handled)
384
    {
385
      WLog_WARN(TAG, "[DIBv5] Unsupported destination format %s",
386
                ClipboardGetFormatName(clipboard, formatId));
387
    }
388
  }
389
390
  return nullptr;
391
}
392
#endif
393
394
static void* clipboard_prepend_bmp_header(const WINPR_BITMAP_INFO_HEADER* pInfoHeader,
395
                                          size_t offset, const void* data, size_t size,
396
                                          UINT32* pSize)
397
430
{
398
430
  WINPR_ASSERT(pInfoHeader);
399
430
  WINPR_ASSERT(pSize);
400
401
430
  *pSize = 0;
402
430
  if ((pInfoHeader->biBitCount < 1) || (pInfoHeader->biBitCount > 32))
403
0
    return nullptr;
404
405
430
  if (size > (UINT32_MAX - sizeof(WINPR_BITMAP_FILE_HEADER)))
406
0
    return nullptr;
407
430
  const size_t DstSize = sizeof(WINPR_BITMAP_FILE_HEADER) + size;
408
430
  if ((pInfoHeader->biSize > size) || (offset > (size - pInfoHeader->biSize)))
409
360
    return nullptr;
410
411
70
  const size_t bitmapOffset = sizeof(WINPR_BITMAP_FILE_HEADER) + pInfoHeader->biSize + offset;
412
70
  if (bitmapOffset > DstSize)
413
0
    return nullptr;
414
415
70
  wStream* s = Stream_New(nullptr, DstSize);
416
70
  if (!s)
417
0
    return nullptr;
418
419
70
  WINPR_BITMAP_FILE_HEADER fileHeader = WINPR_C_ARRAY_INIT;
420
70
  fileHeader.bfType[0] = 'B';
421
70
  fileHeader.bfType[1] = 'M';
422
70
  fileHeader.bfSize = (UINT32)DstSize;
423
70
  fileHeader.bfOffBits = (UINT32)bitmapOffset;
424
70
  if (!writeBitmapFileHeader(s, &fileHeader))
425
0
    goto fail;
426
427
70
  if (!Stream_EnsureRemainingCapacity(s, size))
428
0
    goto fail;
429
70
  Stream_Write(s, data, size);
430
431
70
  {
432
70
    const size_t len = Stream_GetPosition(s);
433
70
    if (len != DstSize)
434
0
      goto fail;
435
70
  }
436
437
70
  *pSize = (UINT32)DstSize;
438
439
70
  {
440
70
    BYTE* dst = Stream_Buffer(s);
441
70
    Stream_Free(s, FALSE);
442
70
    return dst;
443
70
  }
444
445
0
fail:
446
0
  Stream_Free(s, TRUE);
447
0
  return nullptr;
448
70
}
449
450
/**
451
 * "image/bmp":
452
 *
453
 * Bitmap file format.
454
 */
455
456
static void* clipboard_synthesize_image_bmp(WINPR_ATTR_UNUSED wClipboard* clipboard,
457
                                            UINT32 formatId, const void* data, UINT32* pSize)
458
1.36k
{
459
1.36k
  UINT32 SrcSize = *pSize;
460
461
1.36k
  if (formatId == CF_DIB)
462
1.36k
  {
463
1.36k
    if (SrcSize < sizeof(BITMAPINFOHEADER))
464
45
      return nullptr;
465
466
1.31k
    wStream sbuffer = WINPR_C_ARRAY_INIT;
467
1.31k
    size_t offset = 0;
468
1.31k
    WINPR_BITMAP_INFO_HEADER header = WINPR_C_ARRAY_INIT;
469
1.31k
    wStream* s = Stream_StaticConstInit(&sbuffer, data, SrcSize);
470
1.31k
    if (!readBitmapInfoHeader(s, &header, &offset))
471
885
      return nullptr;
472
473
430
    return clipboard_prepend_bmp_header(&header, offset, data, SrcSize, pSize);
474
1.31k
  }
475
#if defined(WINPR_UTILS_IMAGE_DIBv5)
476
  else if (formatId == CF_DIBV5)
477
  {
478
    WLog_WARN(TAG, "[BMP] Unsupported destination format %s",
479
              ClipboardGetFormatName(clipboard, formatId));
480
  }
481
#endif
482
0
  else
483
0
  {
484
0
    WLog_WARN(TAG, "[BMP] Unsupported destination format %s",
485
0
              ClipboardGetFormatName(clipboard, formatId));
486
0
  }
487
488
0
  return nullptr;
489
1.36k
}
490
491
#if defined(WINPR_UTILS_IMAGE_PNG) || defined(WINPR_UTILS_IMAGE_WEBP) || \
492
    defined(WINPR_UTILS_IMAGE_JPEG)
493
static void* clipboard_synthesize_image_bmp_to_format(wClipboard* clipboard, UINT32 formatId,
494
                                                      UINT32 bmpFormat, const void* data,
495
                                                      UINT32* pSize)
496
{
497
  WINPR_ASSERT(clipboard);
498
  WINPR_ASSERT(data);
499
  WINPR_ASSERT(pSize);
500
501
  size_t dsize = 0;
502
  void* result = nullptr;
503
504
  wImage* img = winpr_image_new();
505
  void* bmp = clipboard_synthesize_image_bmp(clipboard, formatId, data, pSize);
506
  const UINT32 SrcSize = *pSize;
507
  *pSize = 0;
508
509
  if (!bmp || !img)
510
    goto fail;
511
512
  if (winpr_image_read_buffer(img, bmp, SrcSize) <= 0)
513
    goto fail;
514
515
  result = winpr_image_write_buffer(img, bmpFormat, &dsize);
516
  if (result)
517
  {
518
    if (dsize <= UINT32_MAX)
519
      *pSize = (UINT32)dsize;
520
    else
521
    {
522
      free(result);
523
      result = nullptr;
524
    }
525
  }
526
527
fail:
528
  free(bmp);
529
  winpr_image_free(img, TRUE);
530
  return result;
531
}
532
#endif
533
534
#if defined(WINPR_UTILS_IMAGE_PNG)
535
static void* clipboard_synthesize_image_bmp_to_png(wClipboard* clipboard, UINT32 formatId,
536
                                                   const void* data, UINT32* pSize)
537
{
538
  return clipboard_synthesize_image_bmp_to_format(clipboard, formatId, WINPR_IMAGE_PNG, data,
539
                                                  pSize);
540
}
541
#endif
542
543
#if defined(WINPR_UTILS_IMAGE_PNG) || defined(WINPR_UTILS_IMAGE_WEBP) || \
544
    defined(WINPR_UTILS_IMAGE_JPEG)
545
static void* clipboard_synthesize_image_format_to_bmp(WINPR_ATTR_UNUSED wClipboard* clipboard,
546
                                                      WINPR_ATTR_UNUSED UINT32 srcFormatId,
547
                                                      const void* data, UINT32* pSize)
548
{
549
  WINPR_ASSERT(clipboard);
550
  WINPR_ASSERT(data);
551
  WINPR_ASSERT(pSize);
552
553
  BYTE* dst = nullptr;
554
  const UINT32 SrcSize = *pSize;
555
  size_t size = 0;
556
  wImage* image = winpr_image_new();
557
  if (!image)
558
    goto fail;
559
560
  const int res = winpr_image_read_buffer(image, data, SrcSize);
561
  if (res <= 0)
562
    goto fail;
563
564
  dst = winpr_image_write_buffer(image, WINPR_IMAGE_BITMAP, &size);
565
  if ((size < sizeof(WINPR_BITMAP_FILE_HEADER)) || (size > UINT32_MAX))
566
  {
567
    free(dst);
568
    dst = nullptr;
569
    goto fail;
570
  }
571
  *pSize = (UINT32)size;
572
573
fail:
574
  winpr_image_free(image, TRUE);
575
576
  if (dst)
577
    memmove(dst, &dst[sizeof(WINPR_BITMAP_FILE_HEADER)],
578
            size - sizeof(WINPR_BITMAP_FILE_HEADER));
579
  return dst;
580
}
581
#endif
582
583
#if defined(WINPR_UTILS_IMAGE_PNG)
584
static void* clipboard_synthesize_image_png_to_bmp(wClipboard* clipboard, UINT32 formatId,
585
                                                   const void* data, UINT32* pSize)
586
{
587
  return clipboard_synthesize_image_format_to_bmp(clipboard, formatId, data, pSize);
588
}
589
#endif
590
591
#if defined(WINPR_UTILS_IMAGE_WEBP)
592
static void* clipboard_synthesize_image_bmp_to_webp(wClipboard* clipboard, UINT32 formatId,
593
                                                    const void* data, UINT32* pSize)
594
{
595
  return clipboard_synthesize_image_bmp_to_format(clipboard, formatId, WINPR_IMAGE_WEBP, data,
596
                                                  pSize);
597
}
598
599
static void* clipboard_synthesize_image_webp_to_bmp(wClipboard* clipboard, UINT32 formatId,
600
                                                    const void* data, UINT32* pSize)
601
{
602
  return clipboard_synthesize_image_format_to_bmp(clipboard, formatId, data, pSize);
603
}
604
#endif
605
606
#if defined(WINPR_UTILS_IMAGE_JPEG)
607
static void* clipboard_synthesize_image_bmp_to_jpeg(wClipboard* clipboard, UINT32 formatId,
608
                                                    const void* data, UINT32* pSize)
609
{
610
  return clipboard_synthesize_image_bmp_to_format(clipboard, formatId, WINPR_IMAGE_JPEG, data,
611
                                                  pSize);
612
}
613
614
static void* clipboard_synthesize_image_jpeg_to_bmp(wClipboard* clipboard, UINT32 formatId,
615
                                                    const void* data, UINT32* pSize)
616
{
617
  return clipboard_synthesize_image_format_to_bmp(clipboard, formatId, data, pSize);
618
}
619
#endif
620
621
/**
622
 * "HTML Format":
623
 *
624
 * HTML clipboard format: msdn.microsoft.com/en-us/library/windows/desktop/ms649015/
625
 */
626
627
static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 formatId,
628
                                              const void* pData, UINT32* pSize)
629
93
{
630
93
  union
631
93
  {
632
93
    const void* cpv;
633
93
    const char* cpc;
634
93
    const BYTE* cpb;
635
93
    WCHAR* pv;
636
93
  } pSrcData;
637
93
  char* pDstData = nullptr;
638
639
93
  pSrcData.cpv = nullptr;
640
641
93
  WINPR_ASSERT(clipboard);
642
93
  WINPR_ASSERT(pSize);
643
644
93
  if (formatId == ClipboardGetFormatId(clipboard, mime_html))
645
93
  {
646
93
    const size_t SrcSize = (size_t)*pSize;
647
93
    const size_t DstSize = SrcSize + 200;
648
93
    char* body = nullptr;
649
93
    char num[20] = WINPR_C_ARRAY_INIT;
650
651
    /* Create a copy, we modify the input data */
652
93
    pSrcData.pv = calloc(1, SrcSize + 1);
653
93
    if (!pSrcData.pv)
654
0
      goto fail;
655
93
    memcpy(pSrcData.pv, pData, SrcSize);
656
657
93
    if (SrcSize > 2)
658
91
    {
659
91
      if (SrcSize > INT_MAX)
660
0
        goto fail;
661
662
      /* Check the BOM (Byte Order Mark) */
663
91
      if ((pSrcData.cpb[0] == 0xFE) && (pSrcData.cpb[1] == 0xFF))
664
42
      {
665
42
        if (!ByteSwapUnicode(pSrcData.pv, (SrcSize / 2)))
666
0
          goto fail;
667
42
      }
668
669
      /* Check if we have WCHAR, convert to UTF-8 */
670
91
      if ((pSrcData.cpb[0] == 0xFF) && (pSrcData.cpb[1] == 0xFE))
671
47
      {
672
47
        char* utfString = ConvertWCharNToUtf8Alloc(&pSrcData.pv[1],
673
47
                                                   (SrcSize / sizeof(WCHAR)) - 1, nullptr);
674
47
        free(pSrcData.pv);
675
47
        pSrcData.cpc = utfString;
676
47
        if (!utfString)
677
7
          goto fail;
678
47
      }
679
91
    }
680
681
86
    pDstData = (char*)calloc(1, DstSize);
682
683
86
    if (!pDstData)
684
0
      goto fail;
685
686
86
    (void)sprintf_s(pDstData, DstSize,
687
86
                    "Version:0.9\r\n"
688
86
                    "StartHTML:0000000000\r\n"
689
86
                    "EndHTML:0000000000\r\n"
690
86
                    "StartFragment:0000000000\r\n"
691
86
                    "EndFragment:0000000000\r\n");
692
86
    body = strstr(pSrcData.cpc, "<body");
693
694
86
    if (!body)
695
82
      body = strstr(pSrcData.cpc, "<BODY");
696
697
    /* StartHTML */
698
86
    (void)sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, DstSize));
699
86
    CopyMemory(&pDstData[23], num, 10);
700
701
86
    if (!body)
702
82
    {
703
82
      if (!winpr_str_append("<HTML><BODY>", pDstData, DstSize, nullptr))
704
0
        goto fail;
705
82
    }
706
707
86
    if (!winpr_str_append("<!--StartFragment-->", pDstData, DstSize, nullptr))
708
0
      goto fail;
709
710
    /* StartFragment */
711
86
    (void)sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, SrcSize + 200));
712
86
    CopyMemory(&pDstData[69], num, 10);
713
714
86
    if (!winpr_str_append(pSrcData.cpc, pDstData, DstSize, nullptr))
715
7
      goto fail;
716
717
    /* EndFragment */
718
79
    (void)sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, SrcSize + 200));
719
79
    CopyMemory(&pDstData[93], num, 10);
720
721
79
    if (!winpr_str_append("<!--EndFragment-->", pDstData, DstSize, nullptr))
722
2
      goto fail;
723
724
77
    if (!body)
725
73
    {
726
73
      if (!winpr_str_append("</BODY></HTML>", pDstData, DstSize, nullptr))
727
3
        goto fail;
728
73
    }
729
730
    /* EndHTML */
731
74
    (void)sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, DstSize));
732
74
    CopyMemory(&pDstData[43], num, 10);
733
74
    *pSize = (UINT32)strnlen(pDstData, DstSize) + 1;
734
74
  }
735
93
fail:
736
93
  free(pSrcData.pv);
737
93
  return pDstData;
738
93
}
739
740
static char* html_pre_write(wStream* s, const char* what)
741
672
{
742
672
  const size_t len = strlen(what);
743
672
  Stream_Write(s, what, len);
744
672
  char* startHTML = Stream_PointerAs(s, char);
745
7.39k
  for (size_t x = 0; x < 10; x++)
746
6.72k
    Stream_Write_INT8(s, '0');
747
672
  Stream_Write(s, "\r\n", 2);
748
672
  return startHTML;
749
672
}
750
751
static void html_fill_number(char* pos, size_t val)
752
672
{
753
672
  char str[11] = WINPR_C_ARRAY_INIT;
754
672
  (void)_snprintf(str, sizeof(str), "%010" PRIuz, val);
755
672
  memcpy(pos, str, 10);
756
672
}
757
758
static void* clipboard_wrap_html(const char* mime, const char* idata, size_t ilength,
759
                                 uint32_t* plen)
760
168
{
761
168
  WINPR_ASSERT(mime);
762
168
  WINPR_ASSERT(plen);
763
764
168
  *plen = 0;
765
766
168
  size_t b64len = 0;
767
168
  char* b64 = b64_encode((const BYTE*)idata, ilength, &b64len);
768
168
  if (!b64)
769
0
    return nullptr;
770
771
168
  const size_t mimelen = strlen(mime);
772
168
  wStream* s = Stream_New(nullptr, b64len + 225 + mimelen);
773
168
  if (!s)
774
0
  {
775
0
    free(b64);
776
0
    return nullptr;
777
0
  }
778
779
168
  char* startHTML = html_pre_write(s, "Version:0.9\r\nStartHTML:");
780
168
  char* endHTML = html_pre_write(s, "EndHTML:");
781
168
  char* startFragment = html_pre_write(s, "StartFragment:");
782
168
  char* endFragment = html_pre_write(s, "EndFragment:");
783
784
168
  html_fill_number(startHTML, Stream_GetPosition(s));
785
168
  const char html[] = "<html><!--StartFragment-->";
786
168
  Stream_Write(s, html, strnlen(html, sizeof(html)));
787
788
168
  html_fill_number(startFragment, Stream_GetPosition(s));
789
790
168
  const char body[] = "<body><img alt=\"FreeRDP clipboard image\" src=\"data:";
791
168
  Stream_Write(s, body, strnlen(body, sizeof(body)));
792
793
168
  Stream_Write(s, mime, mimelen);
794
795
168
  const char base64[] = ";base64,";
796
168
  Stream_Write(s, base64, strnlen(base64, sizeof(base64)));
797
168
  Stream_Write(s, b64, b64len);
798
799
168
  const char end[] = "\"/></body>";
800
168
  Stream_Write(s, end, strnlen(end, sizeof(end)));
801
802
168
  html_fill_number(endFragment, Stream_GetPosition(s));
803
804
168
  const char fragend[] = "<!--EndFragment--></html>";
805
168
  Stream_Write(s, fragend, strnlen(fragend, sizeof(fragend)));
806
168
  html_fill_number(endHTML, Stream_GetPosition(s));
807
808
168
  void* res = Stream_Buffer(s);
809
168
  const size_t pos = Stream_GetPosition(s);
810
168
  *plen = WINPR_ASSERTING_INT_CAST(uint32_t, pos);
811
168
  Stream_Free(s, FALSE);
812
168
  free(b64);
813
168
  return res;
814
168
}
815
816
static void* clipboard_wrap_format_to_html(uint32_t bmpFormat, const char* idata, size_t ilength,
817
                                           uint32_t* plen)
818
0
{
819
0
  void* res = nullptr;
820
0
  wImage* img = winpr_image_new();
821
0
  if (!img)
822
0
    goto fail;
823
824
0
  if (winpr_image_read_buffer(img, (const BYTE*)idata, ilength) <= 0)
825
0
    goto fail;
826
827
0
  {
828
0
    size_t bmpsize = 0;
829
0
    void* bmp = winpr_image_write_buffer(img, bmpFormat, &bmpsize);
830
0
    if (!bmp)
831
0
      goto fail;
832
833
0
    res = clipboard_wrap_html(winpr_image_format_mime(bmpFormat), bmp, bmpsize, plen);
834
0
    free(bmp);
835
0
  }
836
0
fail:
837
0
  winpr_image_free(img, TRUE);
838
0
  return res;
839
0
}
840
841
static void* clipboard_wrap_bmp_to_html(const char* idata, size_t ilength, uint32_t* plen)
842
168
{
843
168
  const uint32_t formats[] = { WINPR_IMAGE_WEBP, WINPR_IMAGE_PNG, WINPR_IMAGE_JPEG };
844
845
672
  for (size_t x = 0; x < ARRAYSIZE(formats); x++)
846
504
  {
847
504
    const uint32_t format = formats[x];
848
504
    if (winpr_image_format_is_supported(format))
849
0
    {
850
0
      return clipboard_wrap_format_to_html(format, idata, ilength, plen);
851
0
    }
852
504
  }
853
168
  const uint32_t bmpFormat = WINPR_IMAGE_BITMAP;
854
168
  return clipboard_wrap_html(winpr_image_format_mime(bmpFormat), idata, ilength, plen);
855
168
}
856
857
static void* clipboard_synthesize_image_html(WINPR_ATTR_UNUSED wClipboard* clipboard,
858
                                             UINT32 formatId, const void* data, UINT32* pSize)
859
426
{
860
426
  WINPR_ASSERT(pSize);
861
862
426
  const size_t datalen = *pSize;
863
864
426
  switch (formatId)
865
426
  {
866
0
    case CF_TIFF:
867
0
      return clipboard_wrap_html(mime_tiff, data, datalen, pSize);
868
272
    case CF_DIB:
869
272
    case CF_DIBV5:
870
272
    {
871
272
      uint32_t bmplen = *pSize;
872
272
      void* bmp = clipboard_synthesize_image_bmp(clipboard, formatId, data, &bmplen);
873
272
      if (!bmp)
874
258
      {
875
258
        WLog_WARN(TAG, "failed to convert formatId 0x%08" PRIx32 " [%s]", formatId,
876
258
                  ClipboardGetFormatName(clipboard, formatId));
877
258
        *pSize = 0;
878
258
        return nullptr;
879
258
      }
880
881
14
      void* res = clipboard_wrap_bmp_to_html(bmp, bmplen, pSize);
882
14
      free(bmp);
883
14
      return res;
884
272
    }
885
154
    default:
886
154
    {
887
154
      const uint32_t idWebp = ClipboardRegisterFormat(clipboard, mime_webp);
888
154
      const uint32_t idPng = ClipboardRegisterFormat(clipboard, mime_png);
889
154
      const uint32_t idJpeg = ClipboardRegisterFormat(clipboard, mime_jpeg);
890
154
      const uint32_t idTiff = ClipboardRegisterFormat(clipboard, mime_tiff);
891
154
      if (formatId == idWebp)
892
0
      {
893
0
        return clipboard_wrap_html(mime_webp, data, datalen, pSize);
894
0
      }
895
154
      else if (formatId == idPng)
896
0
      {
897
0
        return clipboard_wrap_html(mime_png, data, datalen, pSize);
898
0
      }
899
154
      else if (formatId == idJpeg)
900
0
      {
901
0
        return clipboard_wrap_html(mime_jpeg, data, datalen, pSize);
902
0
      }
903
154
      else if (formatId == idTiff)
904
0
      {
905
0
        return clipboard_wrap_html(mime_tiff, data, datalen, pSize);
906
0
      }
907
154
      else
908
154
      {
909
154
        for (size_t x = 0; x < ARRAYSIZE(mime_bitmap); x++)
910
154
        {
911
154
          const char* mime = mime_bitmap[x];
912
154
          const uint32_t id = ClipboardRegisterFormat(clipboard, mime);
913
914
154
          if (formatId == id)
915
154
            return clipboard_wrap_bmp_to_html(data, datalen, pSize);
916
154
        }
917
154
      }
918
919
0
      WLog_WARN(TAG, "Unsupported image format id 0x%08" PRIx32 " [%s]", formatId,
920
0
                ClipboardGetFormatName(clipboard, formatId));
921
0
      *pSize = 0;
922
0
      return nullptr;
923
154
    }
924
426
  }
925
426
}
926
927
/**
928
 * "text/html":
929
 *
930
 * HTML text format.
931
 */
932
933
static void* clipboard_synthesize_text_html(wClipboard* clipboard, UINT32 formatId,
934
                                            const void* data, UINT32* pSize)
935
96
{
936
96
  char* pDstData = nullptr;
937
938
96
  if (formatId == ClipboardGetFormatId(clipboard, mime_ms_html))
939
96
  {
940
96
    const char* str = (const char*)data;
941
96
    const size_t SrcSize = *pSize;
942
96
    const char* begStr = strstr(str, "StartHTML:");
943
96
    const char* endStr = strstr(str, "EndHTML:");
944
945
96
    if (!begStr || !endStr)
946
2
      return nullptr;
947
948
96
    errno = 0;
949
94
    const long beg = strtol(&begStr[10], nullptr, 10);
950
951
94
    if (errno != 0)
952
1
      return nullptr;
953
954
93
    const long end = strtol(&endStr[8], nullptr, 10);
955
956
93
    if ((beg < 0) || (end < 0) || ((size_t)beg > SrcSize) || ((size_t)end > SrcSize) ||
957
6
        (beg >= end) || (errno != 0))
958
88
      return nullptr;
959
960
5
    const size_t DstSize = (size_t)(end - beg);
961
5
    pDstData = calloc(DstSize + 1, sizeof(char));
962
963
5
    if (!pDstData)
964
0
      return nullptr;
965
966
5
    CopyMemory(pDstData, &str[beg], DstSize);
967
5
    const size_t rc = ConvertLineEndingToLF(pDstData, DstSize);
968
5
    WINPR_ASSERT(rc <= UINT32_MAX);
969
5
    *pSize = (UINT32)rc;
970
5
  }
971
972
5
  return pDstData;
973
96
}
974
975
BOOL ClipboardInitSynthesizers(wClipboard* clipboard)
976
1.69k
{
977
  /**
978
   * CF_TEXT
979
   */
980
1.69k
  {
981
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_OEMTEXT,
982
1.69k
                                      clipboard_synthesize_cf_oemtext))
983
0
      return FALSE;
984
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_UNICODETEXT,
985
1.69k
                                      clipboard_synthesize_cf_unicodetext))
986
0
      return FALSE;
987
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_LOCALE,
988
1.69k
                                      clipboard_synthesize_cf_locale))
989
0
      return FALSE;
990
991
1.69k
    UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
992
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_TEXT, altFormatId,
993
1.69k
                                      clipboard_synthesize_utf8_string))
994
0
      return FALSE;
995
1.69k
  }
996
  /**
997
   * CF_OEMTEXT
998
   */
999
1.69k
  {
1000
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_TEXT,
1001
1.69k
                                      clipboard_synthesize_cf_text))
1002
0
      return FALSE;
1003
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_UNICODETEXT,
1004
1.69k
                                      clipboard_synthesize_cf_unicodetext))
1005
0
      return FALSE;
1006
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_LOCALE,
1007
1.69k
                                      clipboard_synthesize_cf_locale))
1008
0
      return FALSE;
1009
1.69k
    UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
1010
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, altFormatId,
1011
1.69k
                                      clipboard_synthesize_utf8_string))
1012
0
      return FALSE;
1013
1.69k
  }
1014
  /**
1015
   * CF_UNICODETEXT
1016
   */
1017
1.69k
  {
1018
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_TEXT,
1019
1.69k
                                      clipboard_synthesize_cf_text))
1020
0
      return FALSE;
1021
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_OEMTEXT,
1022
1.69k
                                      clipboard_synthesize_cf_oemtext))
1023
0
      return FALSE;
1024
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_LOCALE,
1025
1.69k
                                      clipboard_synthesize_cf_locale))
1026
0
      return FALSE;
1027
1.69k
    UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
1028
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, altFormatId,
1029
1.69k
                                      clipboard_synthesize_utf8_string))
1030
0
      return FALSE;
1031
1.69k
  }
1032
  /**
1033
   * UTF8_STRING
1034
   */
1035
1.69k
  {
1036
1.69k
    UINT32 formatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
1037
1038
1.69k
    if (formatId)
1039
1.69k
    {
1040
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, CF_TEXT,
1041
1.69k
                                        clipboard_synthesize_cf_text))
1042
0
        return FALSE;
1043
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, CF_OEMTEXT,
1044
1.69k
                                        clipboard_synthesize_cf_oemtext))
1045
0
        return FALSE;
1046
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, CF_UNICODETEXT,
1047
1.69k
                                        clipboard_synthesize_cf_unicodetext))
1048
0
        return FALSE;
1049
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, CF_LOCALE,
1050
1.69k
                                        clipboard_synthesize_cf_locale))
1051
0
        return FALSE;
1052
1.69k
    }
1053
1.69k
  }
1054
  /**
1055
   * text/plain
1056
   */
1057
1.69k
  {
1058
1.69k
    UINT32 formatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
1059
1060
1.69k
    if (formatId)
1061
1.69k
    {
1062
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, CF_TEXT,
1063
1.69k
                                        clipboard_synthesize_cf_text))
1064
0
        return FALSE;
1065
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, CF_OEMTEXT,
1066
1.69k
                                        clipboard_synthesize_cf_oemtext))
1067
0
        return FALSE;
1068
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, CF_UNICODETEXT,
1069
1.69k
                                        clipboard_synthesize_cf_unicodetext))
1070
0
        return FALSE;
1071
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, CF_LOCALE,
1072
1.69k
                                        clipboard_synthesize_cf_locale))
1073
0
        return FALSE;
1074
1.69k
    }
1075
1.69k
  }
1076
1077
1.69k
  const uint32_t htmlFormat = ClipboardRegisterFormat(clipboard, mime_ms_html);
1078
1.69k
  const uint32_t tiffFormat = ClipboardRegisterFormat(clipboard, mime_tiff);
1079
1080
  /**
1081
   * CF_TIFF
1082
   */
1083
1.69k
  if (!ClipboardRegisterSynthesizer(clipboard, CF_TIFF, htmlFormat,
1084
1.69k
                                    clipboard_synthesize_image_html))
1085
0
    return FALSE;
1086
1.69k
  if (!ClipboardRegisterSynthesizer(clipboard, tiffFormat, htmlFormat,
1087
1.69k
                                    clipboard_synthesize_image_html))
1088
0
    return FALSE;
1089
1090
  /**
1091
   * CF_DIB
1092
   */
1093
1.69k
  {
1094
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1095
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIB, CF_DIBV5,
1096
                                      clipboard_synthesize_cf_dibv5))
1097
      return FALSE;
1098
#endif
1099
8.47k
    for (size_t x = 0; x < ARRAYSIZE(mime_bitmap); x++)
1100
6.78k
    {
1101
6.78k
      const char* mime = mime_bitmap[x];
1102
6.78k
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime);
1103
6.78k
      if (altFormatId == 0)
1104
0
        continue;
1105
6.78k
      if (!ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId,
1106
6.78k
                                        clipboard_synthesize_image_bmp))
1107
0
        return FALSE;
1108
6.78k
    }
1109
1.69k
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIB, htmlFormat,
1110
1.69k
                                      clipboard_synthesize_image_html))
1111
0
      return FALSE;
1112
1.69k
  }
1113
1114
  /**
1115
   * CF_DIBV5
1116
   */
1117
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1118
  {
1119
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, CF_DIB, clipboard_synthesize_cf_dib))
1120
      return FALSE;
1121
1122
    for (size_t x = 0; x < ARRAYSIZE(mime_bitmap); x++)
1123
    {
1124
      const char* mime = mime_bitmap[x];
1125
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime);
1126
      if (altFormatId == 0)
1127
        continue;
1128
      if (!ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId,
1129
                                        clipboard_synthesize_image_bmp))
1130
        return FALSE;
1131
    }
1132
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, htmlFormat,
1133
                                      clipboard_synthesize_image_html))
1134
      return FALSE;
1135
  }
1136
#endif
1137
1138
  /**
1139
   * image/bmp
1140
   */
1141
8.47k
  for (size_t x = 0; x < ARRAYSIZE(mime_bitmap); x++)
1142
6.78k
  {
1143
6.78k
    const char* mime = mime_bitmap[x];
1144
6.78k
    const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime);
1145
6.78k
    if (altFormatId == 0)
1146
0
      continue;
1147
6.78k
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIB,
1148
6.78k
                                      clipboard_synthesize_cf_dib))
1149
0
      return FALSE;
1150
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1151
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIBV5,
1152
                                      clipboard_synthesize_cf_dibv5))
1153
      return FALSE;
1154
#endif
1155
6.78k
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, htmlFormat,
1156
6.78k
                                      clipboard_synthesize_image_html))
1157
0
      return FALSE;
1158
6.78k
  }
1159
1160
  /**
1161
   * image/png
1162
   */
1163
#if defined(WINPR_UTILS_IMAGE_PNG)
1164
  {
1165
    const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_png);
1166
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId,
1167
                                      clipboard_synthesize_image_bmp_to_png))
1168
      return FALSE;
1169
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIB,
1170
                                      clipboard_synthesize_image_png_to_bmp))
1171
      return FALSE;
1172
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, htmlFormat,
1173
                                      clipboard_synthesize_image_html))
1174
      return FALSE;
1175
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1176
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId,
1177
                                      clipboard_synthesize_image_bmp_to_png))
1178
      return FALSE;
1179
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIBV5,
1180
                                      clipboard_synthesize_image_png_to_bmp))
1181
      return FALSE;
1182
#endif
1183
  }
1184
#endif
1185
1186
  /**
1187
   * image/webp
1188
   */
1189
#if defined(WINPR_UTILS_IMAGE_WEBP)
1190
  {
1191
    const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_webp);
1192
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId,
1193
                                      clipboard_synthesize_image_bmp_to_webp))
1194
      return FALSE;
1195
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIB,
1196
                                      clipboard_synthesize_image_webp_to_bmp))
1197
      return FALSE;
1198
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, htmlFormat,
1199
                                      clipboard_synthesize_image_html))
1200
      return FALSE;
1201
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1202
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId,
1203
                                      clipboard_synthesize_image_bmp_to_webp))
1204
      return FALSE;
1205
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIBV5,
1206
                                      clipboard_synthesize_image_webp_to_bmp))
1207
      return FALSE;
1208
#endif
1209
  }
1210
#endif
1211
1212
  /**
1213
   * image/jpeg
1214
   */
1215
#if defined(WINPR_UTILS_IMAGE_JPEG)
1216
  {
1217
    const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_jpeg);
1218
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId,
1219
                                      clipboard_synthesize_image_bmp_to_jpeg))
1220
      return FALSE;
1221
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIB,
1222
                                      clipboard_synthesize_image_jpeg_to_bmp))
1223
      return FALSE;
1224
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, htmlFormat,
1225
                                      clipboard_synthesize_image_html))
1226
      return FALSE;
1227
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1228
    if (!ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIBV5,
1229
                                      clipboard_synthesize_image_jpeg_to_bmp))
1230
      return FALSE;
1231
    if (!ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId,
1232
                                      clipboard_synthesize_image_bmp_to_jpeg))
1233
      return FALSE;
1234
#endif
1235
  }
1236
#endif
1237
1238
  /**
1239
   * HTML Format
1240
   */
1241
1.69k
  {
1242
1.69k
    UINT32 formatId = ClipboardRegisterFormat(clipboard, mime_ms_html);
1243
1244
1.69k
    if (formatId)
1245
1.69k
    {
1246
1.69k
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_html);
1247
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, altFormatId,
1248
1.69k
                                        clipboard_synthesize_text_html))
1249
0
        return FALSE;
1250
1.69k
    }
1251
1.69k
  }
1252
1253
  /**
1254
   * text/html
1255
   */
1256
1.69k
  {
1257
1.69k
    UINT32 formatId = ClipboardRegisterFormat(clipboard, mime_html);
1258
1259
1.69k
    if (formatId)
1260
1.69k
    {
1261
1.69k
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_ms_html);
1262
1.69k
      if (!ClipboardRegisterSynthesizer(clipboard, formatId, altFormatId,
1263
1.69k
                                        clipboard_synthesize_html_format))
1264
0
        return FALSE;
1265
1.69k
    }
1266
1.69k
  }
1267
1268
1.69k
  return TRUE;
1269
1.69k
}