Coverage Report

Created: 2025-07-11 06:46

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