Coverage Report

Created: 2024-09-08 06:18

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