Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/winpr/libwinpr/clipboard/synthetic.c
Line
Count
Source (jump to first uncovered line)
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 NULL;
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 = NULL;
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 NULL;
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 NULL;
155
0
    }
156
157
0
    *pSize = (UINT32)size;
158
0
    return pDstData;
159
0
  }
160
161
0
  return NULL;
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 = NULL;
188
0
  pDstData = (UINT32*)malloc(sizeof(UINT32));
189
190
0
  if (!pDstData)
191
0
    return NULL;
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 = NULL;
208
0
  WCHAR* pDstData = NULL;
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 NULL;
216
217
0
    size = *pSize;
218
0
    crlfStr = ConvertLineEndingToCRLF((const char*)data, &size);
219
220
0
    if (!crlfStr)
221
0
      return NULL;
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 NULL;
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 NULL;
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 NULL;
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 NULL;
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 = NULL;
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 = { 0 };
318
0
    wStream sbuffer = { 0 };
319
0
    wStream* s = Stream_StaticConstInit(&sbuffer, data, SrcSize);
320
0
    if (!readBitmapFileHeader(s, &pFileHeader))
321
0
      return NULL;
322
323
0
    DstSize = SrcSize - sizeof(BITMAPFILEHEADER);
324
0
    pDstData = (BYTE*)malloc(DstSize);
325
326
0
    if (!pDstData)
327
0
      return NULL;
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 NULL;
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 NULL;
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 NULL;
402
403
0
  const size_t DstSize = sizeof(WINPR_BITMAP_FILE_HEADER) + size;
404
0
  if (DstSize > UINT32_MAX)
405
0
    return NULL;
406
407
0
  wStream* s = Stream_New(NULL, DstSize);
408
0
  if (!s)
409
0
    return NULL;
410
411
0
  WINPR_BITMAP_FILE_HEADER fileHeader = { 0 };
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
0
  const size_t len = Stream_GetPosition(s);
423
0
  if (len != DstSize)
424
0
    goto fail;
425
0
  *pSize = (UINT32)DstSize;
426
427
0
  BYTE* dst = Stream_Buffer(s);
428
0
  Stream_Free(s, FALSE);
429
0
  return dst;
430
431
0
fail:
432
0
  Stream_Free(s, TRUE);
433
0
  return NULL;
434
0
}
435
436
/**
437
 * "image/bmp":
438
 *
439
 * Bitmap file format.
440
 */
441
442
static void* clipboard_synthesize_image_bmp(WINPR_ATTR_UNUSED wClipboard* clipboard,
443
                                            UINT32 formatId, const void* data, UINT32* pSize)
444
0
{
445
0
  UINT32 SrcSize = *pSize;
446
447
0
  if (formatId == CF_DIB)
448
0
  {
449
0
    if (SrcSize < sizeof(BITMAPINFOHEADER))
450
0
      return NULL;
451
452
0
    wStream sbuffer = { 0 };
453
0
    size_t offset = 0;
454
0
    WINPR_BITMAP_INFO_HEADER header = { 0 };
455
0
    wStream* s = Stream_StaticConstInit(&sbuffer, data, SrcSize);
456
0
    if (!readBitmapInfoHeader(s, &header, &offset))
457
0
      return NULL;
458
459
0
    return clipboard_prepend_bmp_header(&header, data, SrcSize, pSize);
460
0
  }
461
#if defined(WINPR_UTILS_IMAGE_DIBv5)
462
  else if (formatId == CF_DIBV5)
463
  {
464
    WLog_WARN(TAG, "[BMP] Unsupported destination format %s",
465
              ClipboardGetFormatName(clipboard, formatId));
466
  }
467
#endif
468
0
  else
469
0
  {
470
0
    WLog_WARN(TAG, "[BMP] Unsupported destination format %s",
471
0
              ClipboardGetFormatName(clipboard, formatId));
472
0
  }
473
474
0
  return NULL;
475
0
}
476
477
#if defined(WINPR_UTILS_IMAGE_PNG) || defined(WINPR_UTILS_IMAGE_WEBP) || \
478
    defined(WINPR_UTILS_IMAGE_JPEG)
479
static void* clipboard_synthesize_image_bmp_to_format(wClipboard* clipboard, UINT32 formatId,
480
                                                      UINT32 bmpFormat, const void* data,
481
                                                      UINT32* pSize)
482
{
483
  WINPR_ASSERT(clipboard);
484
  WINPR_ASSERT(data);
485
  WINPR_ASSERT(pSize);
486
487
  size_t dsize = 0;
488
  void* result = NULL;
489
490
  wImage* img = winpr_image_new();
491
  void* bmp = clipboard_synthesize_image_bmp(clipboard, formatId, data, pSize);
492
  const UINT32 SrcSize = *pSize;
493
  *pSize = 0;
494
495
  if (!bmp || !img)
496
    goto fail;
497
498
  if (winpr_image_read_buffer(img, bmp, SrcSize) <= 0)
499
    goto fail;
500
501
  result = winpr_image_write_buffer(img, bmpFormat, &dsize);
502
  if (result)
503
  {
504
    if (dsize <= UINT32_MAX)
505
      *pSize = (UINT32)dsize;
506
    else
507
    {
508
      free(result);
509
      result = NULL;
510
    }
511
  }
512
513
fail:
514
  free(bmp);
515
  winpr_image_free(img, TRUE);
516
  return result;
517
}
518
#endif
519
520
#if defined(WINPR_UTILS_IMAGE_PNG)
521
static void* clipboard_synthesize_image_bmp_to_png(wClipboard* clipboard, UINT32 formatId,
522
                                                   const void* data, UINT32* pSize)
523
{
524
  return clipboard_synthesize_image_bmp_to_format(clipboard, formatId, WINPR_IMAGE_PNG, data,
525
                                                  pSize);
526
}
527
#endif
528
529
#if defined(WINPR_UTILS_IMAGE_PNG) || defined(WINPR_UTILS_IMAGE_WEBP) || \
530
    defined(WINPR_UTILS_IMAGE_JPEG)
531
static void* clipboard_synthesize_image_format_to_bmp(wClipboard* clipboard,
532
                                                      WINPR_ATTR_UNUSED UINT32 srcFormatId,
533
                                                      const void* data, UINT32* pSize)
534
{
535
  WINPR_ASSERT(clipboard);
536
  WINPR_ASSERT(data);
537
  WINPR_ASSERT(pSize);
538
539
  BYTE* dst = NULL;
540
  const UINT32 SrcSize = *pSize;
541
  size_t size = 0;
542
  wImage* image = winpr_image_new();
543
  if (!image)
544
    goto fail;
545
546
  const int res = winpr_image_read_buffer(image, data, SrcSize);
547
  if (res <= 0)
548
    goto fail;
549
550
  dst = winpr_image_write_buffer(image, WINPR_IMAGE_BITMAP, &size);
551
  if ((size < sizeof(WINPR_BITMAP_FILE_HEADER)) || (size > UINT32_MAX))
552
  {
553
    free(dst);
554
    dst = NULL;
555
    goto fail;
556
  }
557
  *pSize = (UINT32)size;
558
559
fail:
560
  winpr_image_free(image, TRUE);
561
562
  if (dst)
563
    memmove(dst, &dst[sizeof(WINPR_BITMAP_FILE_HEADER)],
564
            size - sizeof(WINPR_BITMAP_FILE_HEADER));
565
  return dst;
566
}
567
#endif
568
569
#if defined(WINPR_UTILS_IMAGE_PNG)
570
static void* clipboard_synthesize_image_png_to_bmp(wClipboard* clipboard, UINT32 formatId,
571
                                                   const void* data, UINT32* pSize)
572
{
573
  return clipboard_synthesize_image_format_to_bmp(clipboard, formatId, data, pSize);
574
}
575
#endif
576
577
#if defined(WINPR_UTILS_IMAGE_WEBP)
578
static void* clipboard_synthesize_image_bmp_to_webp(wClipboard* clipboard, UINT32 formatId,
579
                                                    const void* data, UINT32* pSize)
580
{
581
  return clipboard_synthesize_image_bmp_to_format(clipboard, formatId, WINPR_IMAGE_WEBP, data,
582
                                                  pSize);
583
}
584
585
static void* clipboard_synthesize_image_webp_to_bmp(wClipboard* clipboard, UINT32 formatId,
586
                                                    const void* data, UINT32* pSize)
587
{
588
  return clipboard_synthesize_image_format_to_bmp(clipboard, formatId, data, pSize);
589
}
590
#endif
591
592
#if defined(WINPR_UTILS_IMAGE_JPEG)
593
static void* clipboard_synthesize_image_bmp_to_jpeg(wClipboard* clipboard, UINT32 formatId,
594
                                                    const void* data, UINT32* pSize)
595
{
596
  return clipboard_synthesize_image_bmp_to_format(clipboard, formatId, WINPR_IMAGE_JPEG, data,
597
                                                  pSize);
598
}
599
600
static void* clipboard_synthesize_image_jpeg_to_bmp(wClipboard* clipboard, UINT32 formatId,
601
                                                    const void* data, UINT32* pSize)
602
{
603
  return clipboard_synthesize_image_format_to_bmp(clipboard, formatId, data, pSize);
604
}
605
#endif
606
607
/**
608
 * "HTML Format":
609
 *
610
 * HTML clipboard format: msdn.microsoft.com/en-us/library/windows/desktop/ms649015/
611
 */
612
613
static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 formatId,
614
                                              const void* pData, UINT32* pSize)
615
0
{
616
0
  union
617
0
  {
618
0
    const void* cpv;
619
0
    const char* cpc;
620
0
    const BYTE* cpb;
621
0
    WCHAR* pv;
622
0
  } pSrcData;
623
0
  char* pDstData = NULL;
624
625
0
  pSrcData.cpv = NULL;
626
627
0
  WINPR_ASSERT(clipboard);
628
0
  WINPR_ASSERT(pSize);
629
630
0
  if (formatId == ClipboardGetFormatId(clipboard, mime_html))
631
0
  {
632
0
    const size_t SrcSize = (size_t)*pSize;
633
0
    const size_t DstSize = SrcSize + 200;
634
0
    char* body = NULL;
635
0
    char num[20] = { 0 };
636
637
    /* Create a copy, we modify the input data */
638
0
    pSrcData.pv = calloc(1, SrcSize + 1);
639
0
    if (!pSrcData.pv)
640
0
      goto fail;
641
0
    memcpy(pSrcData.pv, pData, SrcSize);
642
643
0
    if (SrcSize > 2)
644
0
    {
645
0
      if (SrcSize > INT_MAX)
646
0
        goto fail;
647
648
      /* Check the BOM (Byte Order Mark) */
649
0
      if ((pSrcData.cpb[0] == 0xFE) && (pSrcData.cpb[1] == 0xFF))
650
0
        ByteSwapUnicode(pSrcData.pv, (SrcSize / 2));
651
652
      /* Check if we have WCHAR, convert to UTF-8 */
653
0
      if ((pSrcData.cpb[0] == 0xFF) && (pSrcData.cpb[1] == 0xFE))
654
0
      {
655
0
        char* utfString =
656
0
            ConvertWCharNToUtf8Alloc(&pSrcData.pv[1], SrcSize / sizeof(WCHAR), NULL);
657
0
        free(pSrcData.pv);
658
0
        pSrcData.cpc = utfString;
659
0
        if (!utfString)
660
0
          goto fail;
661
0
      }
662
0
    }
663
664
0
    pDstData = (char*)calloc(1, DstSize);
665
666
0
    if (!pDstData)
667
0
      goto fail;
668
669
0
    (void)sprintf_s(pDstData, DstSize,
670
0
                    "Version:0.9\r\n"
671
0
                    "StartHTML:0000000000\r\n"
672
0
                    "EndHTML:0000000000\r\n"
673
0
                    "StartFragment:0000000000\r\n"
674
0
                    "EndFragment:0000000000\r\n");
675
0
    body = strstr(pSrcData.cpc, "<body");
676
677
0
    if (!body)
678
0
      body = strstr(pSrcData.cpc, "<BODY");
679
680
    /* StartHTML */
681
0
    (void)sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, DstSize));
682
0
    CopyMemory(&pDstData[23], num, 10);
683
684
0
    if (!body)
685
0
    {
686
0
      if (!winpr_str_append("<HTML><BODY>", pDstData, DstSize, NULL))
687
0
        goto fail;
688
0
    }
689
690
0
    if (!winpr_str_append("<!--StartFragment-->", pDstData, DstSize, NULL))
691
0
      goto fail;
692
693
    /* StartFragment */
694
0
    (void)sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, SrcSize + 200));
695
0
    CopyMemory(&pDstData[69], num, 10);
696
697
0
    if (!winpr_str_append(pSrcData.cpc, pDstData, DstSize, NULL))
698
0
      goto fail;
699
700
    /* EndFragment */
701
0
    (void)sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, SrcSize + 200));
702
0
    CopyMemory(&pDstData[93], num, 10);
703
704
0
    if (!winpr_str_append("<!--EndFragment-->", pDstData, DstSize, NULL))
705
0
      goto fail;
706
707
0
    if (!body)
708
0
    {
709
0
      if (!winpr_str_append("</BODY></HTML>", pDstData, DstSize, NULL))
710
0
        goto fail;
711
0
    }
712
713
    /* EndHTML */
714
0
    (void)sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, DstSize));
715
0
    CopyMemory(&pDstData[43], num, 10);
716
0
    *pSize = (UINT32)strnlen(pDstData, DstSize) + 1;
717
0
  }
718
0
fail:
719
0
  free(pSrcData.pv);
720
0
  return pDstData;
721
0
}
722
723
static char* html_pre_write(wStream* s, const char* what)
724
0
{
725
0
  const size_t len = strlen(what);
726
0
  Stream_Write(s, what, len);
727
0
  char* startHTML = Stream_PointerAs(s, char);
728
0
  for (size_t x = 0; x < 10; x++)
729
0
    Stream_Write_INT8(s, '0');
730
0
  Stream_Write(s, "\r\n", 2);
731
0
  return startHTML;
732
0
}
733
734
static void html_fill_number(char* pos, size_t val)
735
0
{
736
0
  char str[11] = { 0 };
737
0
  (void)_snprintf(str, sizeof(str), "%010" PRIuz, val);
738
0
  memcpy(pos, str, 10);
739
0
}
740
741
static void* clipboard_wrap_html(const char* mime, const char* idata, size_t ilength,
742
                                 uint32_t* plen)
743
0
{
744
0
  WINPR_ASSERT(mime);
745
0
  WINPR_ASSERT(plen);
746
747
0
  *plen = 0;
748
749
0
  size_t b64len = 0;
750
0
  char* b64 = b64_encode((const BYTE*)idata, ilength, &b64len);
751
0
  if (!b64)
752
0
    return NULL;
753
754
0
  const size_t mimelen = strlen(mime);
755
0
  wStream* s = Stream_New(NULL, b64len + 225 + mimelen);
756
0
  if (!s)
757
0
  {
758
0
    free(b64);
759
0
    return NULL;
760
0
  }
761
762
0
  char* startHTML = html_pre_write(s, "Version:0.9\r\nStartHTML:");
763
0
  char* endHTML = html_pre_write(s, "EndHTML:");
764
0
  char* startFragment = html_pre_write(s, "StartFragment:");
765
0
  char* endFragment = html_pre_write(s, "EndFragment:");
766
767
0
  html_fill_number(startHTML, Stream_GetPosition(s));
768
0
  const char html[] = "<html><!--StartFragment-->";
769
0
  Stream_Write(s, html, strnlen(html, sizeof(html)));
770
771
0
  html_fill_number(startFragment, Stream_GetPosition(s));
772
773
0
  const char body[] = "<body><img alt=\"FreeRDP clipboard image\" src=\"data:";
774
0
  Stream_Write(s, body, strnlen(body, sizeof(body)));
775
776
0
  Stream_Write(s, mime, mimelen);
777
778
0
  const char base64[] = ";base64,";
779
0
  Stream_Write(s, base64, strnlen(base64, sizeof(base64)));
780
0
  Stream_Write(s, b64, b64len);
781
782
0
  const char end[] = "\"/></body>";
783
0
  Stream_Write(s, end, strnlen(end, sizeof(end)));
784
785
0
  html_fill_number(endFragment, Stream_GetPosition(s));
786
787
0
  const char fragend[] = "<!--EndFragment--></html>";
788
0
  Stream_Write(s, fragend, strnlen(fragend, sizeof(fragend)));
789
0
  html_fill_number(endHTML, Stream_GetPosition(s));
790
791
0
  void* res = Stream_Buffer(s);
792
0
  const size_t pos = Stream_GetPosition(s);
793
0
  *plen = WINPR_ASSERTING_INT_CAST(uint32_t, pos);
794
0
  Stream_Free(s, FALSE);
795
0
  free(b64);
796
0
  return res;
797
0
}
798
799
static void* clipboard_wrap_format_to_html(uint32_t bmpFormat, const char* idata, size_t ilength,
800
                                           uint32_t* plen)
801
0
{
802
0
  void* res = NULL;
803
0
  wImage* img = winpr_image_new();
804
0
  if (!img)
805
0
    goto fail;
806
807
0
  if (winpr_image_read_buffer(img, (const BYTE*)idata, ilength) <= 0)
808
0
    goto fail;
809
810
0
  size_t bmpsize = 0;
811
0
  void* bmp = winpr_image_write_buffer(img, bmpFormat, &bmpsize);
812
0
  if (!bmp)
813
0
    goto fail;
814
815
0
  res = clipboard_wrap_html(winpr_image_format_mime(bmpFormat), bmp, bmpsize, plen);
816
0
  free(bmp);
817
818
0
fail:
819
0
  winpr_image_free(img, TRUE);
820
0
  return res;
821
0
}
822
823
static void* clipboard_wrap_bmp_to_html(const char* idata, size_t ilength, uint32_t* plen)
824
0
{
825
0
  const uint32_t formats[] = { WINPR_IMAGE_WEBP, WINPR_IMAGE_PNG, WINPR_IMAGE_JPEG };
826
827
0
  for (size_t x = 0; x < ARRAYSIZE(formats); x++)
828
0
  {
829
0
    const uint32_t format = formats[x];
830
0
    if (winpr_image_format_is_supported(format))
831
0
    {
832
0
      return clipboard_wrap_format_to_html(format, idata, ilength, plen);
833
0
    }
834
0
  }
835
0
  const uint32_t bmpFormat = WINPR_IMAGE_BITMAP;
836
0
  return clipboard_wrap_html(winpr_image_format_mime(bmpFormat), idata, ilength, plen);
837
0
}
838
839
static void* clipboard_synthesize_image_html(WINPR_ATTR_UNUSED wClipboard* clipboard,
840
                                             UINT32 formatId, const void* data, UINT32* pSize)
841
0
{
842
0
  WINPR_ASSERT(pSize);
843
844
0
  const size_t datalen = *pSize;
845
846
0
  switch (formatId)
847
0
  {
848
0
    case CF_TIFF:
849
0
      return clipboard_wrap_html(mime_tiff, data, datalen, pSize);
850
0
    case CF_DIB:
851
0
    case CF_DIBV5:
852
0
    {
853
0
      uint32_t bmplen = *pSize;
854
0
      void* bmp = clipboard_synthesize_image_bmp(clipboard, formatId, data, &bmplen);
855
0
      if (!bmp)
856
0
      {
857
0
        WLog_WARN(TAG, "failed to convert formatId 0x%08" PRIx32 " [%s]", formatId,
858
0
                  ClipboardGetFormatName(clipboard, formatId));
859
0
        *pSize = 0;
860
0
        return NULL;
861
0
      }
862
863
0
      void* res = clipboard_wrap_bmp_to_html(bmp, bmplen, pSize);
864
0
      free(bmp);
865
0
      return res;
866
0
    }
867
0
    default:
868
0
    {
869
0
      const uint32_t idWebp = ClipboardRegisterFormat(clipboard, mime_webp);
870
0
      const uint32_t idPng = ClipboardRegisterFormat(clipboard, mime_png);
871
0
      const uint32_t idJpeg = ClipboardRegisterFormat(clipboard, mime_jpeg);
872
0
      const uint32_t idTiff = ClipboardRegisterFormat(clipboard, mime_tiff);
873
0
      if (formatId == idWebp)
874
0
      {
875
0
        return clipboard_wrap_html(mime_webp, data, datalen, pSize);
876
0
      }
877
0
      else if (formatId == idPng)
878
0
      {
879
0
        return clipboard_wrap_html(mime_png, data, datalen, pSize);
880
0
      }
881
0
      else if (formatId == idJpeg)
882
0
      {
883
0
        return clipboard_wrap_html(mime_jpeg, data, datalen, pSize);
884
0
      }
885
0
      else if (formatId == idTiff)
886
0
      {
887
0
        return clipboard_wrap_html(mime_tiff, data, datalen, pSize);
888
0
      }
889
0
      else
890
0
      {
891
0
        for (size_t x = 0; x < ARRAYSIZE(mime_bitmap); x++)
892
0
        {
893
0
          const char* mime = mime_bitmap[x];
894
0
          const uint32_t id = ClipboardRegisterFormat(clipboard, mime);
895
896
0
          if (formatId == id)
897
0
            return clipboard_wrap_bmp_to_html(data, datalen, pSize);
898
0
        }
899
0
      }
900
901
0
      WLog_WARN(TAG, "Unsupported image format id 0x%08" PRIx32 " [%s]", formatId,
902
0
                ClipboardGetFormatName(clipboard, formatId));
903
0
      *pSize = 0;
904
0
      return NULL;
905
0
    }
906
0
  }
907
0
}
908
909
/**
910
 * "text/html":
911
 *
912
 * HTML text format.
913
 */
914
915
static void* clipboard_synthesize_text_html(wClipboard* clipboard, UINT32 formatId,
916
                                            const void* data, UINT32* pSize)
917
0
{
918
0
  char* pDstData = NULL;
919
920
0
  if (formatId == ClipboardGetFormatId(clipboard, mime_ms_html))
921
0
  {
922
0
    const char* str = (const char*)data;
923
0
    const size_t SrcSize = *pSize;
924
0
    const char* begStr = strstr(str, "StartHTML:");
925
0
    const char* endStr = strstr(str, "EndHTML:");
926
927
0
    if (!begStr || !endStr)
928
0
      return NULL;
929
930
0
    errno = 0;
931
0
    const long beg = strtol(&begStr[10], NULL, 10);
932
933
0
    if (errno != 0)
934
0
      return NULL;
935
936
0
    const long end = strtol(&endStr[8], NULL, 10);
937
938
0
    if ((beg < 0) || (end < 0) || ((size_t)beg > SrcSize) || ((size_t)end > SrcSize) ||
939
0
        (beg >= end) || (errno != 0))
940
0
      return NULL;
941
942
0
    const size_t DstSize = (size_t)(end - beg);
943
0
    pDstData = calloc(DstSize + 1, sizeof(char));
944
945
0
    if (!pDstData)
946
0
      return NULL;
947
948
0
    CopyMemory(pDstData, &str[beg], DstSize);
949
0
    const size_t rc = ConvertLineEndingToLF(pDstData, DstSize);
950
0
    WINPR_ASSERT(rc <= UINT32_MAX);
951
0
    *pSize = (UINT32)rc;
952
0
  }
953
954
0
  return pDstData;
955
0
}
956
957
BOOL ClipboardInitSynthesizers(wClipboard* clipboard)
958
0
{
959
  /**
960
   * CF_TEXT
961
   */
962
0
  {
963
0
    ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_OEMTEXT,
964
0
                                 clipboard_synthesize_cf_oemtext);
965
0
    ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_UNICODETEXT,
966
0
                                 clipboard_synthesize_cf_unicodetext);
967
0
    ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_LOCALE, clipboard_synthesize_cf_locale);
968
969
0
    UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
970
0
    ClipboardRegisterSynthesizer(clipboard, CF_TEXT, altFormatId,
971
0
                                 clipboard_synthesize_utf8_string);
972
0
  }
973
  /**
974
   * CF_OEMTEXT
975
   */
976
0
  {
977
0
    ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_TEXT, clipboard_synthesize_cf_text);
978
0
    ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_UNICODETEXT,
979
0
                                 clipboard_synthesize_cf_unicodetext);
980
0
    ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_LOCALE,
981
0
                                 clipboard_synthesize_cf_locale);
982
0
    UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
983
0
    ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, altFormatId,
984
0
                                 clipboard_synthesize_utf8_string);
985
0
  }
986
  /**
987
   * CF_UNICODETEXT
988
   */
989
0
  {
990
0
    ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_TEXT,
991
0
                                 clipboard_synthesize_cf_text);
992
0
    ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_OEMTEXT,
993
0
                                 clipboard_synthesize_cf_oemtext);
994
0
    ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_LOCALE,
995
0
                                 clipboard_synthesize_cf_locale);
996
0
    UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
997
0
    ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, altFormatId,
998
0
                                 clipboard_synthesize_utf8_string);
999
0
  }
1000
  /**
1001
   * UTF8_STRING
1002
   */
1003
0
  {
1004
0
    UINT32 formatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
1005
1006
0
    if (formatId)
1007
0
    {
1008
0
      ClipboardRegisterSynthesizer(clipboard, formatId, CF_TEXT,
1009
0
                                   clipboard_synthesize_cf_text);
1010
0
      ClipboardRegisterSynthesizer(clipboard, formatId, CF_OEMTEXT,
1011
0
                                   clipboard_synthesize_cf_oemtext);
1012
0
      ClipboardRegisterSynthesizer(clipboard, formatId, CF_UNICODETEXT,
1013
0
                                   clipboard_synthesize_cf_unicodetext);
1014
0
      ClipboardRegisterSynthesizer(clipboard, formatId, CF_LOCALE,
1015
0
                                   clipboard_synthesize_cf_locale);
1016
0
    }
1017
0
  }
1018
  /**
1019
   * text/plain
1020
   */
1021
0
  {
1022
0
    UINT32 formatId = ClipboardRegisterFormat(clipboard, mime_text_plain);
1023
1024
0
    if (formatId)
1025
0
    {
1026
0
      ClipboardRegisterSynthesizer(clipboard, formatId, CF_TEXT,
1027
0
                                   clipboard_synthesize_cf_text);
1028
0
      ClipboardRegisterSynthesizer(clipboard, formatId, CF_OEMTEXT,
1029
0
                                   clipboard_synthesize_cf_oemtext);
1030
0
      ClipboardRegisterSynthesizer(clipboard, formatId, CF_UNICODETEXT,
1031
0
                                   clipboard_synthesize_cf_unicodetext);
1032
0
      ClipboardRegisterSynthesizer(clipboard, formatId, CF_LOCALE,
1033
0
                                   clipboard_synthesize_cf_locale);
1034
0
    }
1035
0
  }
1036
1037
0
  const uint32_t htmlFormat = ClipboardRegisterFormat(clipboard, mime_ms_html);
1038
0
  const uint32_t tiffFormat = ClipboardRegisterFormat(clipboard, mime_tiff);
1039
1040
  /**
1041
   * CF_TIFF
1042
   */
1043
0
  ClipboardRegisterSynthesizer(clipboard, CF_TIFF, htmlFormat, clipboard_synthesize_image_html);
1044
0
  ClipboardRegisterSynthesizer(clipboard, tiffFormat, htmlFormat,
1045
0
                               clipboard_synthesize_image_html);
1046
1047
  /**
1048
   * CF_DIB
1049
   */
1050
0
  {
1051
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1052
    ClipboardRegisterSynthesizer(clipboard, CF_DIB, CF_DIBV5, clipboard_synthesize_cf_dibv5);
1053
#endif
1054
0
    for (size_t x = 0; x < ARRAYSIZE(mime_bitmap); x++)
1055
0
    {
1056
0
      const char* mime = mime_bitmap[x];
1057
0
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime);
1058
0
      if (altFormatId == 0)
1059
0
        continue;
1060
0
      ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId,
1061
0
                                   clipboard_synthesize_image_bmp);
1062
0
    }
1063
0
    ClipboardRegisterSynthesizer(clipboard, CF_DIB, htmlFormat,
1064
0
                                 clipboard_synthesize_image_html);
1065
0
  }
1066
1067
  /**
1068
   * CF_DIBV5
1069
   */
1070
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1071
  {
1072
    ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, CF_DIB, clipboard_synthesize_cf_dib);
1073
1074
    for (size_t x = 0; x < ARRAYSIZE(mime_bitmap); x++)
1075
    {
1076
      const char* mime = mime_bitmap[x];
1077
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime);
1078
      if (altFormatId == 0)
1079
        continue;
1080
      ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId,
1081
                                   clipboard_synthesize_image_bmp);
1082
    }
1083
    ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, htmlFormat,
1084
                                 clipboard_synthesize_image_html);
1085
  }
1086
#endif
1087
1088
  /**
1089
   * image/bmp
1090
   */
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
    ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIB, clipboard_synthesize_cf_dib);
1098
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1099
    ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIBV5,
1100
                                 clipboard_synthesize_cf_dibv5);
1101
#endif
1102
0
    ClipboardRegisterSynthesizer(clipboard, altFormatId, htmlFormat,
1103
0
                                 clipboard_synthesize_image_html);
1104
0
  }
1105
1106
  /**
1107
   * image/png
1108
   */
1109
#if defined(WINPR_UTILS_IMAGE_PNG)
1110
  {
1111
    const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_png);
1112
    ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId,
1113
                                 clipboard_synthesize_image_bmp_to_png);
1114
    ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIB,
1115
                                 clipboard_synthesize_image_png_to_bmp);
1116
    ClipboardRegisterSynthesizer(clipboard, altFormatId, htmlFormat,
1117
                                 clipboard_synthesize_image_html);
1118
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1119
    ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId,
1120
                                 clipboard_synthesize_image_bmp_to_png);
1121
    ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIBV5,
1122
                                 clipboard_synthesize_image_png_to_bmp);
1123
#endif
1124
  }
1125
#endif
1126
1127
  /**
1128
   * image/webp
1129
   */
1130
#if defined(WINPR_UTILS_IMAGE_WEBP)
1131
  {
1132
    const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_webp);
1133
    ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId,
1134
                                 clipboard_synthesize_image_bmp_to_webp);
1135
    ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIB,
1136
                                 clipboard_synthesize_image_webp_to_bmp);
1137
    ClipboardRegisterSynthesizer(clipboard, altFormatId, htmlFormat,
1138
                                 clipboard_synthesize_image_html);
1139
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1140
    ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId,
1141
                                 clipboard_synthesize_image_bmp_to_webp);
1142
    ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIBV5,
1143
                                 clipboard_synthesize_image_webp_to_bmp);
1144
#endif
1145
  }
1146
#endif
1147
1148
  /**
1149
   * image/jpeg
1150
   */
1151
#if defined(WINPR_UTILS_IMAGE_JPEG)
1152
  {
1153
    const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_jpeg);
1154
    ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId,
1155
                                 clipboard_synthesize_image_bmp_to_jpeg);
1156
    ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIB,
1157
                                 clipboard_synthesize_image_jpeg_to_bmp);
1158
    ClipboardRegisterSynthesizer(clipboard, altFormatId, htmlFormat,
1159
                                 clipboard_synthesize_image_html);
1160
#if defined(WINPR_UTILS_IMAGE_DIBv5)
1161
    ClipboardRegisterSynthesizer(clipboard, altFormatId, CF_DIBV5,
1162
                                 clipboard_synthesize_image_jpeg_to_bmp);
1163
    ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId,
1164
                                 clipboard_synthesize_image_bmp_to_jpeg);
1165
#endif
1166
  }
1167
#endif
1168
1169
  /**
1170
   * HTML Format
1171
   */
1172
0
  {
1173
0
    UINT32 formatId = ClipboardRegisterFormat(clipboard, mime_ms_html);
1174
1175
0
    if (formatId)
1176
0
    {
1177
0
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_html);
1178
0
      ClipboardRegisterSynthesizer(clipboard, formatId, altFormatId,
1179
0
                                   clipboard_synthesize_text_html);
1180
0
    }
1181
0
  }
1182
1183
  /**
1184
   * text/html
1185
   */
1186
0
  {
1187
0
    UINT32 formatId = ClipboardRegisterFormat(clipboard, mime_html);
1188
1189
0
    if (formatId)
1190
0
    {
1191
0
      const UINT32 altFormatId = ClipboardRegisterFormat(clipboard, mime_ms_html);
1192
0
      ClipboardRegisterSynthesizer(clipboard, formatId, altFormatId,
1193
0
                                   clipboard_synthesize_html_format);
1194
0
    }
1195
0
  }
1196
1197
0
  return TRUE;
1198
0
}