Coverage Report

Created: 2026-04-12 07:03

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