Coverage Report

Created: 2025-07-18 07:03

/src/FreeRDP/winpr/libwinpr/crt/unicode_builtin.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2001-2004 Unicode, Inc.
3
 *
4
 * Disclaimer
5
 *
6
 * This source code is provided as is by Unicode, Inc. No claims are
7
 * made as to fitness for any particular purpose. No warranties of any
8
 * kind are expressed or implied. The recipient agrees to determine
9
 * applicability of information provided. If this file has been
10
 * purchased on magnetic or optical media from Unicode, Inc., the
11
 * sole remedy for any claim will be exchange of defective media
12
 * within 90 days of receipt.
13
 *
14
 * Limitations on Rights to Redistribute This Code
15
 *
16
 * Unicode, Inc. hereby grants the right to freely use the information
17
 * supplied in this file in the creation of products supporting the
18
 * Unicode Standard, and to make copies of this file in any form
19
 * for internal or external distribution as long as this notice
20
 * remains attached.
21
 */
22
23
/* ---------------------------------------------------------------------
24
25
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
26
Author: Mark E. Davis, 1994.
27
Rev History: Rick McGowan, fixes & updates May 2001.
28
Sept 2001: fixed const & error conditions per
29
mods suggested by S. Parent & A. Lillich.
30
June 2002: Tim Dodd added detection and handling of incomplete
31
source sequences, enhanced error detection, added casts
32
to eliminate compiler warnings.
33
July 2003: slight mods to back out aggressive FFFE detection.
34
Jan 2004: updated switches in from-UTF8 conversions.
35
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
36
37
See the header file "utf.h" for complete documentation.
38
39
------------------------------------------------------------------------ */
40
41
#include <winpr/wtypes.h>
42
#include <winpr/string.h>
43
#include <winpr/assert.h>
44
#include <winpr/cast.h>
45
46
#include "unicode.h"
47
48
#include "../log.h"
49
#define TAG WINPR_TAG("unicode")
50
51
/*
52
 * Character Types:
53
 *
54
 * UTF8:    uint8_t   8 bits
55
 * UTF16: uint16_t  16 bits
56
 * UTF32: uint32_t  32 bits
57
 */
58
59
/* Some fundamental constants */
60
0
#define UNI_REPLACEMENT_CHAR (uint32_t)0x0000FFFD
61
6.50M
#define UNI_MAX_BMP (uint32_t)0x0000FFFF
62
874
#define UNI_MAX_UTF16 (uint32_t)0x0010FFFF
63
#define UNI_MAX_UTF32 (uint32_t)0x7FFFFFFF
64
#define UNI_MAX_LEGAL_UTF32 (uint32_t)0x0010FFFF
65
66
typedef enum
67
{
68
  conversionOK,    /* conversion successful */
69
  sourceExhausted, /* partial character in source, but hit end */
70
  targetExhausted, /* insuff. room in target for conversion */
71
  sourceIllegal    /* source sequence is illegal/malformed */
72
} ConversionResult;
73
74
typedef enum
75
{
76
  strictConversion = 0,
77
  lenientConversion
78
} ConversionFlags;
79
80
static const int halfShift = 10; /* used for shifting by 10 bits */
81
82
static const uint32_t halfBase = 0x0010000UL;
83
static const uint32_t halfMask = 0x3FFUL;
84
85
14.3M
#define UNI_SUR_HIGH_START (uint32_t)0xD800
86
80.6k
#define UNI_SUR_HIGH_END (uint32_t)0xDBFF
87
1.37M
#define UNI_SUR_LOW_START (uint32_t)0xDC00
88
80.8k
#define UNI_SUR_LOW_END (uint32_t)0xDFFF
89
90
/* --------------------------------------------------------------------- */
91
92
/*
93
 * Index into the table below with the first byte of a UTF-8 sequence to
94
 * get the number of trailing bytes that are supposed to follow it.
95
 * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
96
 * left as-is for anyone who may want to do such conversion, which was
97
 * allowed in earlier algorithms.
98
 */
99
static const char trailingBytesForUTF8[256] = {
100
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
107
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
108
};
109
110
/*
111
 * Magic values subtracted from a buffer value during UTF8 conversion.
112
 * This table contains as many values as there might be trailing bytes
113
 * in a UTF-8 sequence.
114
 */
115
static const uint32_t offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
116
                                           0x03C82080UL, 0xFA082080UL, 0x82082080UL };
117
118
/*
119
 * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
120
 * into the first byte, depending on how many bytes follow.  There are
121
 * as many entries in this table as there are UTF-8 sequence types.
122
 * (I.e., one byte sequence, two byte... etc.). Remember that sequence
123
 * for *legal* UTF-8 will be 4 or fewer bytes total.
124
 */
125
static const uint8_t firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
126
127
/* --------------------------------------------------------------------- */
128
129
/* The interface converts a whole buffer to avoid function-call overhead.
130
 * Constants have been gathered. Loops & conditionals have been removed as
131
 * much as possible for efficiency, in favor of drop-through switches.
132
 * (See "Note A" at the bottom of the file for equivalent code.)
133
 * If your compiler supports it, the "isLegalUTF8" call can be turned
134
 * into an inline function.
135
 */
136
137
/* --------------------------------------------------------------------- */
138
139
static ConversionResult winpr_ConvertUTF16toUTF8_Internal(const uint16_t** sourceStart,
140
                                                          const uint16_t* sourceEnd,
141
                                                          uint8_t** targetStart, uint8_t* targetEnd,
142
                                                          ConversionFlags flags)
143
435
{
144
435
  bool computeLength = (!targetEnd) ? true : false;
145
435
  const uint16_t* source = *sourceStart;
146
435
  uint8_t* target = *targetStart;
147
435
  ConversionResult result = conversionOK;
148
149
684k
  while (source < sourceEnd)
150
684k
  {
151
684k
    uint32_t ch = 0;
152
684k
    unsigned short bytesToWrite = 0;
153
684k
    const uint32_t byteMask = 0xBF;
154
684k
    const uint32_t byteMark = 0x80;
155
684k
    const uint16_t* oldSource =
156
684k
        source; /* In case we have to back up because of target overflow. */
157
158
684k
    ch = *source++;
159
160
    /* If we have a surrogate pair, convert to UTF32 first. */
161
684k
    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
162
871
    {
163
      /* If the 16 bits following the high surrogate are in the source buffer... */
164
871
      if (source < sourceEnd)
165
870
      {
166
870
        uint32_t ch2 = *source;
167
168
        /* If it's a low surrogate, convert to UTF32. */
169
870
        if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
170
823
        {
171
823
          ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) +
172
823
               halfBase;
173
823
          ++source;
174
823
        }
175
47
        else if (flags == strictConversion)
176
47
        {
177
          /* it's an unpaired high surrogate */
178
47
          --source; /* return to the illegal value itself */
179
47
          result = sourceIllegal;
180
47
          break;
181
47
        }
182
870
      }
183
1
      else
184
1
      {
185
        /* We don't have the 16 bits following the high surrogate. */
186
1
        --source; /* return to the high surrogate */
187
1
        result = sourceExhausted;
188
1
        break;
189
1
      }
190
871
    }
191
683k
    else if (flags == strictConversion)
192
683k
    {
193
      /* UTF-16 surrogate values are illegal in UTF-32 */
194
683k
      if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
195
31
      {
196
31
        --source; /* return to the illegal value itself */
197
31
        result = sourceIllegal;
198
31
        break;
199
31
      }
200
683k
    }
201
202
    /* Figure out how many bytes the result will require */
203
684k
    if (ch < (uint32_t)0x80)
204
922
    {
205
922
      bytesToWrite = 1;
206
922
    }
207
683k
    else if (ch < (uint32_t)0x800)
208
46.4k
    {
209
46.4k
      bytesToWrite = 2;
210
46.4k
    }
211
637k
    else if (ch < (uint32_t)0x10000)
212
636k
    {
213
636k
      bytesToWrite = 3;
214
636k
    }
215
823
    else if (ch < (uint32_t)0x110000)
216
823
    {
217
823
      bytesToWrite = 4;
218
823
    }
219
0
    else
220
0
    {
221
0
      bytesToWrite = 3;
222
0
      ch = UNI_REPLACEMENT_CHAR;
223
0
    }
224
225
684k
    target += bytesToWrite;
226
227
684k
    if ((target > targetEnd) && (!computeLength))
228
0
    {
229
0
      source = oldSource; /* Back up source pointer! */
230
0
      target -= bytesToWrite;
231
0
      result = targetExhausted;
232
0
      break;
233
0
    }
234
235
684k
    if (!computeLength)
236
341k
    {
237
341k
      switch (bytesToWrite)
238
341k
      {
239
          /* note: everything falls through. */
240
411
        case 4:
241
411
          *--target = (uint8_t)((ch | byteMark) & byteMask);
242
411
          ch >>= 6;
243
          /* fallthrough */
244
411
          WINPR_FALLTHROUGH
245
317k
        case 3:
246
317k
          *--target = (uint8_t)((ch | byteMark) & byteMask);
247
317k
          ch >>= 6;
248
          /* fallthrough */
249
317k
          WINPR_FALLTHROUGH
250
251
341k
        case 2:
252
341k
          *--target = (uint8_t)((ch | byteMark) & byteMask);
253
341k
          ch >>= 6;
254
          /* fallthrough */
255
341k
          WINPR_FALLTHROUGH
256
257
341k
        case 1:
258
341k
          *--target = (uint8_t)(ch | firstByteMark[bytesToWrite]);
259
341k
      }
260
341k
    }
261
342k
    else
262
342k
    {
263
342k
      switch (bytesToWrite)
264
342k
      {
265
          /* note: everything falls through. */
266
412
        case 4:
267
412
          --target;
268
          /* fallthrough */
269
412
          WINPR_FALLTHROUGH
270
271
319k
        case 3:
272
319k
          --target;
273
          /* fallthrough */
274
319k
          WINPR_FALLTHROUGH
275
276
342k
        case 2:
277
342k
          --target;
278
          /* fallthrough */
279
342k
          WINPR_FALLTHROUGH
280
281
342k
        case 1:
282
342k
          --target;
283
342k
      }
284
342k
    }
285
286
684k
    target += bytesToWrite;
287
684k
  }
288
289
435
  *sourceStart = source;
290
435
  *targetStart = target;
291
435
  return result;
292
435
}
293
294
/* --------------------------------------------------------------------- */
295
296
/*
297
 * Utility routine to tell whether a sequence of bytes is legal UTF-8.
298
 * This must be called with the length pre-determined by the first byte.
299
 * If not calling this from ConvertUTF8to*, then the length can be set by:
300
 *  length = trailingBytesForUTF8[*source]+1;
301
 * and the sequence is illegal right away if there aren't that many bytes
302
 * available.
303
 * If presented with a length > 4, this returns false.  The Unicode
304
 * definition of UTF-8 goes up to 4-byte sequences.
305
 */
306
307
static bool isLegalUTF8(const uint8_t* source, int length)
308
6.50M
{
309
6.50M
  uint8_t a = 0;
310
6.50M
  const uint8_t* srcptr = source + length;
311
312
6.50M
  switch (length)
313
6.50M
  {
314
3
    default:
315
3
      return false;
316
317
      /* Everything else falls through when "true"... */
318
898
    case 4:
319
898
      if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
320
11
        return false;
321
      /* fallthrough */
322
887
      WINPR_FALLTHROUGH
323
324
1.73k
    case 3:
325
1.73k
      if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
326
13
        return false;
327
      /* fallthrough */
328
1.72k
      WINPR_FALLTHROUGH
329
330
1.98k
    case 2:
331
1.98k
      if ((a = (*--srcptr)) > 0xBF)
332
3
        return false;
333
334
1.98k
      switch (*source)
335
1.98k
      {
336
          /* no fall-through in this inner switch */
337
257
        case 0xE0:
338
257
          if (a < 0xA0)
339
11
            return false;
340
341
246
          break;
342
343
246
        case 0xED:
344
229
          if (a > 0x9F)
345
2
            return false;
346
347
227
          break;
348
349
277
        case 0xF0:
350
277
          if (a < 0x90)
351
9
            return false;
352
353
268
          break;
354
355
513
        case 0xF4:
356
513
          if (a > 0x8F)
357
1
            return false;
358
359
512
          break;
360
361
710
        default:
362
710
          if (a < 0x80)
363
5
            return false;
364
705
          break;
365
1.98k
      }
366
      /* fallthrough */
367
1.95k
      WINPR_FALLTHROUGH
368
369
6.50M
    case 1:
370
6.50M
      if (*source >= 0x80 && *source < 0xC2)
371
21
        return false;
372
6.50M
  }
373
374
6.50M
  if (*source > 0xF4)
375
2
    return false;
376
377
6.50M
  return true;
378
6.50M
}
379
380
/* --------------------------------------------------------------------- */
381
382
static ConversionResult winpr_ConvertUTF8toUTF16_Internal(const uint8_t** sourceStart,
383
                                                          const uint8_t* sourceEnd,
384
                                                          uint16_t** targetStart,
385
                                                          uint16_t* targetEnd,
386
                                                          ConversionFlags flags)
387
2.00k
{
388
2.00k
  bool computeLength = (!targetEnd) ? true : false;
389
2.00k
  ConversionResult result = conversionOK;
390
2.00k
  const uint8_t* source = *sourceStart;
391
2.00k
  uint16_t* target = *targetStart;
392
393
6.50M
  while (source < sourceEnd)
394
6.50M
  {
395
6.50M
    uint32_t ch = 0;
396
6.50M
    unsigned short extraBytesToRead =
397
13.0M
        WINPR_ASSERTING_INT_CAST(unsigned short, trailingBytesForUTF8[*source]);
398
399
6.50M
    if ((source + extraBytesToRead) >= sourceEnd)
400
1
    {
401
1
      result = sourceExhausted;
402
1
      break;
403
1
    }
404
405
    /* Do this check whether lenient or strict */
406
6.50M
    if (!isLegalUTF8(source, extraBytesToRead + 1))
407
81
    {
408
81
      result = sourceIllegal;
409
81
      break;
410
81
    }
411
412
    /*
413
     * The cases all fall through. See "Note A" below.
414
     */
415
6.50M
    switch (extraBytesToRead)
416
6.50M
    {
417
0
      case 5:
418
0
        ch += *source++;
419
0
        ch <<= 6; /* remember, illegal UTF-8 */
420
                  /* fallthrough */
421
0
        WINPR_FALLTHROUGH
422
423
0
      case 4:
424
0
        ch += *source++;
425
0
        ch <<= 6; /* remember, illegal UTF-8 */
426
                  /* fallthrough */
427
0
        WINPR_FALLTHROUGH
428
429
874
      case 3:
430
874
        ch += *source++;
431
874
        ch <<= 6;
432
        /* fallthrough */
433
874
        WINPR_FALLTHROUGH
434
435
1.70k
      case 2:
436
1.70k
        ch += *source++;
437
1.70k
        ch <<= 6;
438
        /* fallthrough */
439
1.70k
        WINPR_FALLTHROUGH
440
441
1.95k
      case 1:
442
1.95k
        ch += *source++;
443
1.95k
        ch <<= 6;
444
        /* fallthrough */
445
1.95k
        WINPR_FALLTHROUGH
446
447
6.50M
      case 0:
448
6.50M
        ch += *source++;
449
6.50M
    }
450
451
6.50M
    ch -= offsetsFromUTF8[extraBytesToRead];
452
453
6.50M
    if ((target >= targetEnd) && (!computeLength))
454
0
    {
455
0
      source -= (extraBytesToRead + 1); /* Back up source pointer! */
456
0
      result = targetExhausted;
457
0
      break;
458
0
    }
459
460
6.50M
    if (ch <= UNI_MAX_BMP)
461
6.50M
    {
462
      /* Target is a character <= 0xFFFF */
463
      /* UTF-16 surrogate values are illegal in UTF-32 */
464
6.50M
      if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
465
0
      {
466
0
        if (flags == strictConversion)
467
0
        {
468
0
          source -= (extraBytesToRead + 1); /* return to the illegal value itself */
469
0
          result = sourceIllegal;
470
0
          break;
471
0
        }
472
0
        else
473
0
        {
474
0
          if (!computeLength)
475
0
            *target++ = UNI_REPLACEMENT_CHAR;
476
0
          else
477
0
            target++;
478
0
        }
479
0
      }
480
6.50M
      else
481
6.50M
      {
482
6.50M
        if (!computeLength)
483
3.24M
          *target++ = (uint16_t)ch; /* normal case */
484
3.26M
        else
485
3.26M
          target++;
486
6.50M
      }
487
6.50M
    }
488
874
    else if (ch > UNI_MAX_UTF16)
489
0
    {
490
0
      if (flags == strictConversion)
491
0
      {
492
0
        result = sourceIllegal;
493
0
        source -= (extraBytesToRead + 1); /* return to the start */
494
0
        break;                            /* Bail out; shouldn't continue */
495
0
      }
496
0
      else
497
0
      {
498
0
        if (!computeLength)
499
0
          *target++ = UNI_REPLACEMENT_CHAR;
500
0
        else
501
0
          target++;
502
0
      }
503
0
    }
504
874
    else
505
874
    {
506
      /* target is a character in range 0xFFFF - 0x10FFFF. */
507
874
      if ((target + 1 >= targetEnd) && (!computeLength))
508
0
      {
509
0
        source -= (extraBytesToRead + 1); /* Back up source pointer! */
510
0
        result = targetExhausted;
511
0
        break;
512
0
      }
513
514
874
      ch -= halfBase;
515
516
874
      if (!computeLength)
517
432
      {
518
432
        *target++ = (uint16_t)((ch >> halfShift) + UNI_SUR_HIGH_START);
519
432
        *target++ = (uint16_t)((ch & halfMask) + UNI_SUR_LOW_START);
520
432
      }
521
442
      else
522
442
      {
523
442
        target++;
524
442
        target++;
525
442
      }
526
874
    }
527
6.50M
  }
528
529
2.00k
  *sourceStart = source;
530
2.00k
  *targetStart = target;
531
2.00k
  return result;
532
2.00k
}
533
534
/**
535
 * WinPR built-in Unicode API
536
 */
537
538
static int winpr_ConvertUTF8toUTF16(const uint8_t* src, int cchSrc, uint16_t* dst, int cchDst)
539
2.00k
{
540
2.00k
  size_t length = 0;
541
2.00k
  uint16_t* dstBeg = NULL;
542
2.00k
  uint16_t* dstEnd = NULL;
543
2.00k
  const uint8_t* srcBeg = NULL;
544
2.00k
  const uint8_t* srcEnd = NULL;
545
2.00k
  ConversionResult result = sourceIllegal;
546
547
2.00k
  if (cchSrc == -1)
548
0
    cchSrc = (int)strnlen((const char*)src, INT32_MAX - 1) + 1;
549
550
2.00k
  srcBeg = src;
551
2.00k
  srcEnd = &src[cchSrc];
552
553
2.00k
  if (cchDst == 0)
554
1.04k
  {
555
1.04k
    result =
556
1.04k
        winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
557
558
1.04k
    length = dstBeg - (uint16_t*)NULL;
559
1.04k
  }
560
961
  else
561
961
  {
562
961
    dstBeg = dst;
563
961
    dstEnd = &dst[cchDst];
564
565
961
    result =
566
961
        winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
567
568
961
    length = dstBeg - dst;
569
961
  }
570
571
2.00k
  if (result == targetExhausted)
572
0
  {
573
0
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
574
0
    return 0;
575
0
  }
576
577
2.00k
  return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
578
2.00k
}
579
580
static int winpr_ConvertUTF16toUTF8(const uint16_t* src, int cchSrc, uint8_t* dst, int cchDst)
581
435
{
582
435
  size_t length = 0;
583
435
  uint8_t* dstBeg = NULL;
584
435
  uint8_t* dstEnd = NULL;
585
435
  const uint16_t* srcBeg = NULL;
586
435
  const uint16_t* srcEnd = NULL;
587
435
  ConversionResult result = sourceIllegal;
588
589
435
  if (cchSrc == -1)
590
0
    cchSrc = (int)_wcsnlen((const WCHAR*)src, INT32_MAX - 1) + 1;
591
592
435
  srcBeg = src;
593
435
  srcEnd = &src[cchSrc];
594
595
435
  if (cchDst == 0)
596
257
  {
597
257
    result =
598
257
        winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
599
600
257
    length = dstBeg - ((uint8_t*)NULL);
601
257
  }
602
178
  else
603
178
  {
604
178
    dstBeg = dst;
605
178
    dstEnd = &dst[cchDst];
606
607
178
    result =
608
178
        winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
609
610
178
    length = dstBeg - dst;
611
178
  }
612
613
435
  if (result == targetExhausted)
614
0
  {
615
0
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
616
0
    return 0;
617
0
  }
618
619
435
  return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
620
435
}
621
622
/* --------------------------------------------------------------------- */
623
624
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
625
                            LPWSTR lpWideCharStr, int cchWideChar)
626
2.00k
{
627
2.00k
  size_t cbCharLen = (size_t)cbMultiByte;
628
629
2.00k
  WINPR_UNUSED(dwFlags);
630
631
  /* If cbMultiByte is 0, the function fails */
632
2.00k
  if ((cbMultiByte == 0) || (cbMultiByte < -1))
633
0
    return 0;
634
635
2.00k
  if (cchWideChar < 0)
636
0
    return -1;
637
638
2.00k
  if (cbMultiByte < 0)
639
0
  {
640
0
    const size_t len = strlen(lpMultiByteStr);
641
0
    if (len >= INT32_MAX)
642
0
      return 0;
643
0
    cbCharLen = (int)len + 1;
644
0
  }
645
2.00k
  else
646
2.00k
    cbCharLen = cbMultiByte;
647
648
2.00k
  WINPR_ASSERT(lpMultiByteStr);
649
2.00k
  switch (CodePage)
650
2.00k
  {
651
0
    case CP_ACP:
652
2.00k
    case CP_UTF8:
653
2.00k
      break;
654
655
0
    default:
656
0
      WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
657
0
      return 0;
658
2.00k
  }
659
660
2.00k
  return winpr_ConvertUTF8toUTF16((const uint8_t*)lpMultiByteStr,
661
2.00k
                                  WINPR_ASSERTING_INT_CAST(int, cbCharLen),
662
0
                                  (uint16_t*)lpWideCharStr, cchWideChar);
663
2.00k
}
664
665
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
666
                            LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
667
                            LPBOOL lpUsedDefaultChar)
668
435
{
669
435
  size_t cbCharLen = (size_t)cchWideChar;
670
671
435
  WINPR_UNUSED(dwFlags);
672
  /* If cchWideChar is 0, the function fails */
673
435
  if ((cchWideChar == 0) || (cchWideChar < -1))
674
0
    return 0;
675
676
435
  if (cbMultiByte < 0)
677
0
    return -1;
678
679
435
  WINPR_ASSERT(lpWideCharStr);
680
  /* If cchWideChar is -1, the string is null-terminated */
681
435
  if (cchWideChar == -1)
682
0
  {
683
0
    const size_t len = _wcslen(lpWideCharStr);
684
0
    if (len >= INT32_MAX)
685
0
      return 0;
686
0
    cbCharLen = (int)len + 1;
687
0
  }
688
435
  else
689
435
    cbCharLen = cchWideChar;
690
691
  /*
692
   * if cbMultiByte is 0, the function returns the required buffer size
693
   * in bytes for lpMultiByteStr and makes no use of the output parameter itself.
694
   */
695
696
435
  return winpr_ConvertUTF16toUTF8((const uint16_t*)lpWideCharStr,
697
435
                                  WINPR_ASSERTING_INT_CAST(int, cbCharLen),
698
0
                                  (uint8_t*)lpMultiByteStr, cbMultiByte);
699
435
}