Coverage Report

Created: 2026-10-15 06:29

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