Coverage Report

Created: 2026-03-04 06:17

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