Coverage Report

Created: 2024-09-08 06:16

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