Coverage Report

Created: 2025-08-03 07:05

/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.53M
#define UNI_MAX_BMP (uint32_t)0x0000FFFF
62
792
#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.2M
#define UNI_SUR_HIGH_START (uint32_t)0xD800
86
71.2k
#define UNI_SUR_HIGH_END (uint32_t)0xDBFF
87
1.21M
#define UNI_SUR_LOW_START (uint32_t)0xDC00
88
71.4k
#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
415
{
144
415
  bool computeLength = (!targetEnd) ? true : false;
145
415
  const uint16_t* source = *sourceStart;
146
415
  uint8_t* target = *targetStart;
147
415
  ConversionResult result = conversionOK;
148
149
607k
  while (source < sourceEnd)
150
607k
  {
151
607k
    uint32_t ch = 0;
152
607k
    unsigned short bytesToWrite = 0;
153
607k
    const uint32_t byteMask = 0xBF;
154
607k
    const uint32_t byteMark = 0x80;
155
607k
    const uint16_t* oldSource =
156
607k
        source; /* In case we have to back up because of target overflow. */
157
158
607k
    ch = *source++;
159
160
    /* If we have a surrogate pair, convert to UTF32 first. */
161
607k
    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
162
911
    {
163
      /* If the 16 bits following the high surrogate are in the source buffer... */
164
911
      if (source < sourceEnd)
165
910
      {
166
910
        uint32_t ch2 = *source;
167
168
        /* If it's a low surrogate, convert to UTF32. */
169
910
        if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
170
853
        {
171
853
          ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) +
172
853
               halfBase;
173
853
          ++source;
174
853
        }
175
57
        else if (flags == strictConversion)
176
57
        {
177
          /* it's an unpaired high surrogate */
178
57
          --source; /* return to the illegal value itself */
179
57
          result = sourceIllegal;
180
57
          break;
181
57
        }
182
910
      }
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
911
    }
191
606k
    else if (flags == strictConversion)
192
606k
    {
193
      /* UTF-16 surrogate values are illegal in UTF-32 */
194
606k
      if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
195
21
      {
196
21
        --source; /* return to the illegal value itself */
197
21
        result = sourceIllegal;
198
21
        break;
199
21
      }
200
606k
    }
201
202
    /* Figure out how many bytes the result will require */
203
607k
    if (ch < (uint32_t)0x80)
204
847
    {
205
847
      bytesToWrite = 1;
206
847
    }
207
606k
    else if (ch < (uint32_t)0x800)
208
41.0k
    {
209
41.0k
      bytesToWrite = 2;
210
41.0k
    }
211
565k
    else if (ch < (uint32_t)0x10000)
212
564k
    {
213
564k
      bytesToWrite = 3;
214
564k
    }
215
853
    else if (ch < (uint32_t)0x110000)
216
853
    {
217
853
      bytesToWrite = 4;
218
853
    }
219
0
    else
220
0
    {
221
0
      bytesToWrite = 3;
222
0
      ch = UNI_REPLACEMENT_CHAR;
223
0
    }
224
225
607k
    target += bytesToWrite;
226
227
607k
    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
607k
    if (!computeLength)
236
302k
    {
237
302k
      switch (bytesToWrite)
238
302k
      {
239
          /* note: everything falls through. */
240
424
        case 4:
241
424
          *--target = (uint8_t)((ch | byteMark) & byteMask);
242
424
          ch >>= 6;
243
          /* fallthrough */
244
424
          WINPR_FALLTHROUGH
245
281k
        case 3:
246
281k
          *--target = (uint8_t)((ch | byteMark) & byteMask);
247
281k
          ch >>= 6;
248
          /* fallthrough */
249
281k
          WINPR_FALLTHROUGH
250
251
302k
        case 2:
252
302k
          *--target = (uint8_t)((ch | byteMark) & byteMask);
253
302k
          ch >>= 6;
254
          /* fallthrough */
255
302k
          WINPR_FALLTHROUGH
256
257
302k
        case 1:
258
302k
          *--target = (uint8_t)(ch | firstByteMark[bytesToWrite]);
259
302k
      }
260
302k
    }
261
304k
    else
262
304k
    {
263
304k
      switch (bytesToWrite)
264
304k
      {
265
          /* note: everything falls through. */
266
429
        case 4:
267
429
          --target;
268
          /* fallthrough */
269
429
          WINPR_FALLTHROUGH
270
271
283k
        case 3:
272
283k
          --target;
273
          /* fallthrough */
274
283k
          WINPR_FALLTHROUGH
275
276
303k
        case 2:
277
303k
          --target;
278
          /* fallthrough */
279
303k
          WINPR_FALLTHROUGH
280
281
304k
        case 1:
282
304k
          --target;
283
304k
      }
284
304k
    }
285
286
607k
    target += bytesToWrite;
287
607k
  }
288
289
415
  *sourceStart = source;
290
415
  *targetStart = target;
291
415
  return result;
292
415
}
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.53M
{
309
6.53M
  uint8_t a = 0;
310
6.53M
  const uint8_t* srcptr = source + length;
311
312
6.53M
  switch (length)
313
6.53M
  {
314
4
    default:
315
4
      return false;
316
317
      /* Everything else falls through when "true"... */
318
815
    case 4:
319
815
      if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
320
12
        return false;
321
      /* fallthrough */
322
803
      WINPR_FALLTHROUGH
323
324
1.63k
    case 3:
325
1.63k
      if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
326
12
        return false;
327
      /* fallthrough */
328
1.62k
      WINPR_FALLTHROUGH
329
330
1.93k
    case 2:
331
1.93k
      if ((a = (*--srcptr)) > 0xBF)
332
3
        return false;
333
334
1.93k
      switch (*source)
335
1.93k
      {
336
          /* no fall-through in this inner switch */
337
348
        case 0xE0:
338
348
          if (a < 0xA0)
339
12
            return false;
340
341
336
          break;
342
343
336
        case 0xED:
344
230
          if (a > 0x9F)
345
3
            return false;
346
347
227
          break;
348
349
276
        case 0xF0:
350
276
          if (a < 0x90)
351
8
            return false;
352
353
268
          break;
354
355
517
        case 0xF4:
356
517
          if (a > 0x8F)
357
1
            return false;
358
359
516
          break;
360
361
560
        default:
362
560
          if (a < 0x80)
363
6
            return false;
364
554
          break;
365
1.93k
      }
366
      /* fallthrough */
367
1.90k
      WINPR_FALLTHROUGH
368
369
6.53M
    case 1:
370
6.53M
      if (*source >= 0x80 && *source < 0xC2)
371
20
        return false;
372
6.53M
  }
373
374
6.53M
  if (*source > 0xF4)
375
1
    return false;
376
377
6.53M
  return true;
378
6.53M
}
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
1.98k
{
388
1.98k
  bool computeLength = (!targetEnd) ? true : false;
389
1.98k
  ConversionResult result = conversionOK;
390
1.98k
  const uint8_t* source = *sourceStart;
391
1.98k
  uint16_t* target = *targetStart;
392
393
6.53M
  while (source < sourceEnd)
394
6.53M
  {
395
6.53M
    uint32_t ch = 0;
396
6.53M
    unsigned short extraBytesToRead =
397
13.0M
        WINPR_ASSERTING_INT_CAST(unsigned short, trailingBytesForUTF8[*source]);
398
399
6.53M
    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.53M
    if (!isLegalUTF8(source, extraBytesToRead + 1))
407
82
    {
408
82
      result = sourceIllegal;
409
82
      break;
410
82
    }
411
412
    /*
413
     * The cases all fall through. See "Note A" below.
414
     */
415
6.53M
    switch (extraBytesToRead)
416
6.53M
    {
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
792
      case 3:
430
792
        ch += *source++;
431
792
        ch <<= 6;
432
        /* fallthrough */
433
792
        WINPR_FALLTHROUGH
434
435
1.59k
      case 2:
436
1.59k
        ch += *source++;
437
1.59k
        ch <<= 6;
438
        /* fallthrough */
439
1.59k
        WINPR_FALLTHROUGH
440
441
1.89k
      case 1:
442
1.89k
        ch += *source++;
443
1.89k
        ch <<= 6;
444
        /* fallthrough */
445
1.89k
        WINPR_FALLTHROUGH
446
447
6.53M
      case 0:
448
6.53M
        ch += *source++;
449
6.53M
    }
450
451
6.53M
    ch -= offsetsFromUTF8[extraBytesToRead];
452
453
6.53M
    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.53M
    if (ch <= UNI_MAX_BMP)
461
6.53M
    {
462
      /* Target is a character <= 0xFFFF */
463
      /* UTF-16 surrogate values are illegal in UTF-32 */
464
6.53M
      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.53M
      else
481
6.53M
      {
482
6.53M
        if (!computeLength)
483
3.23M
          *target++ = (uint16_t)ch; /* normal case */
484
3.29M
        else
485
3.29M
          target++;
486
6.53M
      }
487
6.53M
    }
488
792
    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
792
    else
505
792
    {
506
      /* target is a character in range 0xFFFF - 0x10FFFF. */
507
792
      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
792
      ch -= halfBase;
515
516
792
      if (!computeLength)
517
391
      {
518
391
        *target++ = (uint16_t)((ch >> halfShift) + UNI_SUR_HIGH_START);
519
391
        *target++ = (uint16_t)((ch & halfMask) + UNI_SUR_LOW_START);
520
391
      }
521
401
      else
522
401
      {
523
401
        target++;
524
401
        target++;
525
401
      }
526
792
    }
527
6.53M
  }
528
529
1.98k
  *sourceStart = source;
530
1.98k
  *targetStart = target;
531
1.98k
  return result;
532
1.98k
}
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
1.98k
{
540
1.98k
  size_t length = 0;
541
1.98k
  uint16_t* dstBeg = NULL;
542
1.98k
  uint16_t* dstEnd = NULL;
543
1.98k
  const uint8_t* srcBeg = NULL;
544
1.98k
  const uint8_t* srcEnd = NULL;
545
1.98k
  ConversionResult result = sourceIllegal;
546
547
1.98k
  if (cchSrc == -1)
548
0
    cchSrc = (int)strnlen((const char*)src, INT32_MAX - 1) + 1;
549
550
1.98k
  srcBeg = src;
551
1.98k
  srcEnd = &src[cchSrc];
552
553
1.98k
  if (cchDst == 0)
554
1.03k
  {
555
1.03k
    result =
556
1.03k
        winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
557
558
1.03k
    length = dstBeg - (uint16_t*)NULL;
559
1.03k
  }
560
950
  else
561
950
  {
562
950
    dstBeg = dst;
563
950
    dstEnd = &dst[cchDst];
564
565
950
    result =
566
950
        winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
567
568
950
    length = dstBeg - dst;
569
950
  }
570
571
1.98k
  if (result == targetExhausted)
572
0
  {
573
0
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
574
0
    return 0;
575
0
  }
576
577
1.98k
  return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
578
1.98k
}
579
580
static int winpr_ConvertUTF16toUTF8(const uint16_t* src, int cchSrc, uint8_t* dst, int cchDst)
581
415
{
582
415
  size_t length = 0;
583
415
  uint8_t* dstBeg = NULL;
584
415
  uint8_t* dstEnd = NULL;
585
415
  const uint16_t* srcBeg = NULL;
586
415
  const uint16_t* srcEnd = NULL;
587
415
  ConversionResult result = sourceIllegal;
588
589
415
  if (cchSrc == -1)
590
0
    cchSrc = (int)_wcsnlen((const WCHAR*)src, INT32_MAX - 1) + 1;
591
592
415
  srcBeg = src;
593
415
  srcEnd = &src[cchSrc];
594
595
415
  if (cchDst == 0)
596
247
  {
597
247
    result =
598
247
        winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
599
600
247
    length = dstBeg - ((uint8_t*)NULL);
601
247
  }
602
168
  else
603
168
  {
604
168
    dstBeg = dst;
605
168
    dstEnd = &dst[cchDst];
606
607
168
    result =
608
168
        winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
609
610
168
    length = dstBeg - dst;
611
168
  }
612
613
415
  if (result == targetExhausted)
614
0
  {
615
0
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
616
0
    return 0;
617
0
  }
618
619
415
  return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
620
415
}
621
622
/* --------------------------------------------------------------------- */
623
624
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
625
                            LPWSTR lpWideCharStr, int cchWideChar)
626
1.98k
{
627
1.98k
  size_t cbCharLen = (size_t)cbMultiByte;
628
629
1.98k
  WINPR_UNUSED(dwFlags);
630
631
  /* If cbMultiByte is 0, the function fails */
632
1.98k
  if ((cbMultiByte == 0) || (cbMultiByte < -1))
633
0
    return 0;
634
635
1.98k
  if (cchWideChar < 0)
636
0
    return -1;
637
638
1.98k
  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
1.98k
  else
646
1.98k
    cbCharLen = cbMultiByte;
647
648
1.98k
  WINPR_ASSERT(lpMultiByteStr);
649
1.98k
  switch (CodePage)
650
1.98k
  {
651
0
    case CP_ACP:
652
1.98k
    case CP_UTF8:
653
1.98k
      break;
654
655
0
    default:
656
0
      WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
657
0
      return 0;
658
1.98k
  }
659
660
1.98k
  return winpr_ConvertUTF8toUTF16((const uint8_t*)lpMultiByteStr,
661
1.98k
                                  WINPR_ASSERTING_INT_CAST(int, cbCharLen),
662
0
                                  (uint16_t*)lpWideCharStr, cchWideChar);
663
1.98k
}
664
665
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
666
                            LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
667
                            LPBOOL lpUsedDefaultChar)
668
415
{
669
415
  size_t cbCharLen = (size_t)cchWideChar;
670
671
415
  WINPR_UNUSED(dwFlags);
672
  /* If cchWideChar is 0, the function fails */
673
415
  if ((cchWideChar == 0) || (cchWideChar < -1))
674
0
    return 0;
675
676
415
  if (cbMultiByte < 0)
677
0
    return -1;
678
679
415
  WINPR_ASSERT(lpWideCharStr);
680
  /* If cchWideChar is -1, the string is null-terminated */
681
415
  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
415
  else
689
415
    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
415
  return winpr_ConvertUTF16toUTF8((const uint16_t*)lpWideCharStr,
697
415
                                  WINPR_ASSERTING_INT_CAST(int, cbCharLen),
698
0
                                  (uint8_t*)lpMultiByteStr, cbMultiByte);
699
415
}