Coverage Report

Created: 2025-07-18 07:08

/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
14.8M
#define UNI_MAX_BMP (uint32_t)0x0000FFFF
62
874
#define UNI_MAX_UTF16 (uint32_t)0x0010FFFF
63
#define UNI_MAX_UTF32 (uint32_t)0x7FFFFFFF
64
#define UNI_MAX_LEGAL_UTF32 (uint32_t)0x0010FFFF
65
66
typedef enum
67
{
68
  conversionOK,    /* conversion successful */
69
  sourceExhausted, /* partial character in source, but hit end */
70
  targetExhausted, /* insuff. room in target for conversion */
71
  sourceIllegal    /* source sequence is illegal/malformed */
72
} ConversionResult;
73
74
typedef enum
75
{
76
  strictConversion = 0,
77
  lenientConversion
78
} ConversionFlags;
79
80
static const int halfShift = 10; /* used for shifting by 10 bits */
81
82
static const uint32_t halfBase = 0x0010000UL;
83
static const uint32_t halfMask = 0x3FFUL;
84
85
45.7M
#define UNI_SUR_HIGH_START (uint32_t)0xD800
86
129k
#define UNI_SUR_HIGH_END (uint32_t)0xDBFF
87
16.1M
#define UNI_SUR_LOW_START (uint32_t)0xDC00
88
129k
#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
465k
{
144
465k
  bool computeLength = (!targetEnd) ? true : false;
145
465k
  const uint16_t* source = *sourceStart;
146
465k
  uint8_t* target = *targetStart;
147
465k
  ConversionResult result = conversionOK;
148
149
8.53M
  while (source < sourceEnd)
150
8.07M
  {
151
8.07M
    uint32_t ch = 0;
152
8.07M
    unsigned short bytesToWrite = 0;
153
8.07M
    const uint32_t byteMask = 0xBF;
154
8.07M
    const uint32_t byteMark = 0x80;
155
8.07M
    const uint16_t* oldSource =
156
8.07M
        source; /* In case we have to back up because of target overflow. */
157
158
8.07M
    ch = *source++;
159
160
    /* If we have a surrogate pair, convert to UTF32 first. */
161
8.07M
    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
162
1.34k
    {
163
      /* If the 16 bits following the high surrogate are in the source buffer... */
164
1.34k
      if (source < sourceEnd)
165
1.32k
      {
166
1.32k
        uint32_t ch2 = *source;
167
168
        /* If it's a low surrogate, convert to UTF32. */
169
1.32k
        if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
170
962
        {
171
962
          ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) +
172
962
               halfBase;
173
962
          ++source;
174
962
        }
175
361
        else if (flags == strictConversion)
176
361
        {
177
          /* it's an unpaired high surrogate */
178
361
          --source; /* return to the illegal value itself */
179
361
          result = sourceIllegal;
180
361
          break;
181
361
        }
182
1.32k
      }
183
20
      else
184
20
      {
185
        /* We don't have the 16 bits following the high surrogate. */
186
20
        --source; /* return to the high surrogate */
187
20
        result = sourceExhausted;
188
20
        break;
189
20
      }
190
1.34k
    }
191
8.07M
    else if (flags == strictConversion)
192
8.07M
    {
193
      /* UTF-16 surrogate values are illegal in UTF-32 */
194
8.07M
      if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
195
254
      {
196
254
        --source; /* return to the illegal value itself */
197
254
        result = sourceIllegal;
198
254
        break;
199
254
      }
200
8.07M
    }
201
202
    /* Figure out how many bytes the result will require */
203
8.07M
    if (ch < (uint32_t)0x80)
204
7.01M
    {
205
7.01M
      bytesToWrite = 1;
206
7.01M
    }
207
1.05M
    else if (ch < (uint32_t)0x800)
208
92.7k
    {
209
92.7k
      bytesToWrite = 2;
210
92.7k
    }
211
963k
    else if (ch < (uint32_t)0x10000)
212
962k
    {
213
962k
      bytesToWrite = 3;
214
962k
    }
215
962
    else if (ch < (uint32_t)0x110000)
216
962
    {
217
962
      bytesToWrite = 4;
218
962
    }
219
0
    else
220
0
    {
221
0
      bytesToWrite = 3;
222
0
      ch = UNI_REPLACEMENT_CHAR;
223
0
    }
224
225
8.07M
    target += bytesToWrite;
226
227
8.07M
    if ((target > targetEnd) && (!computeLength))
228
6.39k
    {
229
6.39k
      source = oldSource; /* Back up source pointer! */
230
6.39k
      target -= bytesToWrite;
231
6.39k
      result = targetExhausted;
232
6.39k
      break;
233
6.39k
    }
234
235
8.06M
    if (!computeLength)
236
7.47M
    {
237
7.47M
      switch (bytesToWrite)
238
7.47M
      {
239
          /* note: everything falls through. */
240
472
        case 4:
241
472
          *--target = (uint8_t)((ch | byteMark) & byteMask);
242
472
          ch >>= 6;
243
          /* fallthrough */
244
472
          WINPR_FALLTHROUGH
245
623k
        case 3:
246
623k
          *--target = (uint8_t)((ch | byteMark) & byteMask);
247
623k
          ch >>= 6;
248
          /* fallthrough */
249
623k
          WINPR_FALLTHROUGH
250
251
686k
        case 2:
252
686k
          *--target = (uint8_t)((ch | byteMark) & byteMask);
253
686k
          ch >>= 6;
254
          /* fallthrough */
255
686k
          WINPR_FALLTHROUGH
256
257
7.47M
        case 1:
258
7.47M
          *--target = (uint8_t)(ch | firstByteMark[bytesToWrite]);
259
7.47M
      }
260
7.47M
    }
261
591k
    else
262
591k
    {
263
591k
      switch (bytesToWrite)
264
591k
      {
265
          /* note: everything falls through. */
266
490
        case 4:
267
490
          --target;
268
          /* fallthrough */
269
490
          WINPR_FALLTHROUGH
270
271
334k
        case 3:
272
334k
          --target;
273
          /* fallthrough */
274
334k
          WINPR_FALLTHROUGH
275
276
363k
        case 2:
277
363k
          --target;
278
          /* fallthrough */
279
363k
          WINPR_FALLTHROUGH
280
281
591k
        case 1:
282
591k
          --target;
283
591k
      }
284
591k
    }
285
286
8.06M
    target += bytesToWrite;
287
8.06M
  }
288
289
465k
  *sourceStart = source;
290
465k
  *targetStart = target;
291
465k
  return result;
292
465k
}
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
14.8M
{
309
14.8M
  uint8_t a = 0;
310
14.8M
  const uint8_t* srcptr = source + length;
311
312
14.8M
  switch (length)
313
14.8M
  {
314
3
    default:
315
3
      return false;
316
317
      /* Everything else falls through when "true"... */
318
898
    case 4:
319
898
      if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
320
11
        return false;
321
      /* fallthrough */
322
887
      WINPR_FALLTHROUGH
323
324
1.73k
    case 3:
325
1.73k
      if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
326
13
        return false;
327
      /* fallthrough */
328
1.72k
      WINPR_FALLTHROUGH
329
330
1.98k
    case 2:
331
1.98k
      if ((a = (*--srcptr)) > 0xBF)
332
3
        return false;
333
334
1.98k
      switch (*source)
335
1.98k
      {
336
          /* no fall-through in this inner switch */
337
257
        case 0xE0:
338
257
          if (a < 0xA0)
339
11
            return false;
340
341
246
          break;
342
343
246
        case 0xED:
344
229
          if (a > 0x9F)
345
2
            return false;
346
347
227
          break;
348
349
277
        case 0xF0:
350
277
          if (a < 0x90)
351
9
            return false;
352
353
268
          break;
354
355
513
        case 0xF4:
356
513
          if (a > 0x8F)
357
1
            return false;
358
359
512
          break;
360
361
710
        default:
362
710
          if (a < 0x80)
363
5
            return false;
364
705
          break;
365
1.98k
      }
366
      /* fallthrough */
367
1.95k
      WINPR_FALLTHROUGH
368
369
14.8M
    case 1:
370
14.8M
      if (*source >= 0x80 && *source < 0xC2)
371
21
        return false;
372
14.8M
  }
373
374
14.8M
  if (*source > 0xF4)
375
2
    return false;
376
377
14.8M
  return true;
378
14.8M
}
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
439k
{
388
439k
  bool computeLength = (!targetEnd) ? true : false;
389
439k
  ConversionResult result = conversionOK;
390
439k
  const uint8_t* source = *sourceStart;
391
439k
  uint16_t* target = *targetStart;
392
393
15.2M
  while (source < sourceEnd)
394
14.8M
  {
395
14.8M
    uint32_t ch = 0;
396
14.8M
    unsigned short extraBytesToRead =
397
29.6M
        WINPR_ASSERTING_INT_CAST(unsigned short, trailingBytesForUTF8[*source]);
398
399
14.8M
    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
14.8M
    if (!isLegalUTF8(source, extraBytesToRead + 1))
407
81
    {
408
81
      result = sourceIllegal;
409
81
      break;
410
81
    }
411
412
    /*
413
     * The cases all fall through. See "Note A" below.
414
     */
415
14.8M
    switch (extraBytesToRead)
416
14.8M
    {
417
0
      case 5:
418
0
        ch += *source++;
419
0
        ch <<= 6; /* remember, illegal UTF-8 */
420
                  /* fallthrough */
421
0
        WINPR_FALLTHROUGH
422
423
0
      case 4:
424
0
        ch += *source++;
425
0
        ch <<= 6; /* remember, illegal UTF-8 */
426
                  /* fallthrough */
427
0
        WINPR_FALLTHROUGH
428
429
874
      case 3:
430
874
        ch += *source++;
431
874
        ch <<= 6;
432
        /* fallthrough */
433
874
        WINPR_FALLTHROUGH
434
435
1.70k
      case 2:
436
1.70k
        ch += *source++;
437
1.70k
        ch <<= 6;
438
        /* fallthrough */
439
1.70k
        WINPR_FALLTHROUGH
440
441
1.95k
      case 1:
442
1.95k
        ch += *source++;
443
1.95k
        ch <<= 6;
444
        /* fallthrough */
445
1.95k
        WINPR_FALLTHROUGH
446
447
14.8M
      case 0:
448
14.8M
        ch += *source++;
449
14.8M
    }
450
451
14.8M
    ch -= offsetsFromUTF8[extraBytesToRead];
452
453
14.8M
    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
14.8M
    if (ch <= UNI_MAX_BMP)
461
14.8M
    {
462
      /* Target is a character <= 0xFFFF */
463
      /* UTF-16 surrogate values are illegal in UTF-32 */
464
14.8M
      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
14.8M
      else
481
14.8M
      {
482
14.8M
        if (!computeLength)
483
11.5M
          *target++ = (uint16_t)ch; /* normal case */
484
3.26M
        else
485
3.26M
          target++;
486
14.8M
      }
487
14.8M
    }
488
874
    else if (ch > UNI_MAX_UTF16)
489
0
    {
490
0
      if (flags == strictConversion)
491
0
      {
492
0
        result = sourceIllegal;
493
0
        source -= (extraBytesToRead + 1); /* return to the start */
494
0
        break;                            /* Bail out; shouldn't continue */
495
0
      }
496
0
      else
497
0
      {
498
0
        if (!computeLength)
499
0
          *target++ = UNI_REPLACEMENT_CHAR;
500
0
        else
501
0
          target++;
502
0
      }
503
0
    }
504
874
    else
505
874
    {
506
      /* target is a character in range 0xFFFF - 0x10FFFF. */
507
874
      if ((target + 1 >= targetEnd) && (!computeLength))
508
0
      {
509
0
        source -= (extraBytesToRead + 1); /* Back up source pointer! */
510
0
        result = targetExhausted;
511
0
        break;
512
0
      }
513
514
874
      ch -= halfBase;
515
516
874
      if (!computeLength)
517
432
      {
518
432
        *target++ = (uint16_t)((ch >> halfShift) + UNI_SUR_HIGH_START);
519
432
        *target++ = (uint16_t)((ch & halfMask) + UNI_SUR_LOW_START);
520
432
      }
521
442
      else
522
442
      {
523
442
        target++;
524
442
        target++;
525
442
      }
526
874
    }
527
14.8M
  }
528
529
439k
  *sourceStart = source;
530
439k
  *targetStart = target;
531
439k
  return result;
532
439k
}
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
439k
{
540
439k
  size_t length = 0;
541
439k
  uint16_t* dstBeg = NULL;
542
439k
  uint16_t* dstEnd = NULL;
543
439k
  const uint8_t* srcBeg = NULL;
544
439k
  const uint8_t* srcEnd = NULL;
545
439k
  ConversionResult result = sourceIllegal;
546
547
439k
  if (cchSrc == -1)
548
0
    cchSrc = (int)strnlen((const char*)src, INT32_MAX - 1) + 1;
549
550
439k
  srcBeg = src;
551
439k
  srcEnd = &src[cchSrc];
552
553
439k
  if (cchDst == 0)
554
1.04k
  {
555
1.04k
    result =
556
1.04k
        winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
557
558
1.04k
    length = dstBeg - (uint16_t*)NULL;
559
1.04k
  }
560
438k
  else
561
438k
  {
562
438k
    dstBeg = dst;
563
438k
    dstEnd = &dst[cchDst];
564
565
438k
    result =
566
438k
        winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
567
568
438k
    length = dstBeg - dst;
569
438k
  }
570
571
439k
  if (result == targetExhausted)
572
0
  {
573
0
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
574
0
    return 0;
575
0
  }
576
577
439k
  return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
578
439k
}
579
580
static int winpr_ConvertUTF16toUTF8(const uint16_t* src, int cchSrc, uint8_t* dst, int cchDst)
581
465k
{
582
465k
  size_t length = 0;
583
465k
  uint8_t* dstBeg = NULL;
584
465k
  uint8_t* dstEnd = NULL;
585
465k
  const uint16_t* srcBeg = NULL;
586
465k
  const uint16_t* srcEnd = NULL;
587
465k
  ConversionResult result = sourceIllegal;
588
589
465k
  if (cchSrc == -1)
590
0
    cchSrc = (int)_wcsnlen((const WCHAR*)src, INT32_MAX - 1) + 1;
591
592
465k
  srcBeg = src;
593
465k
  srcEnd = &src[cchSrc];
594
595
465k
  if (cchDst == 0)
596
55.8k
  {
597
55.8k
    result =
598
55.8k
        winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
599
600
55.8k
    length = dstBeg - ((uint8_t*)NULL);
601
55.8k
  }
602
410k
  else
603
410k
  {
604
410k
    dstBeg = dst;
605
410k
    dstEnd = &dst[cchDst];
606
607
410k
    result =
608
410k
        winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
609
610
410k
    length = dstBeg - dst;
611
410k
  }
612
613
465k
  if (result == targetExhausted)
614
6.39k
  {
615
6.39k
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
616
6.39k
    return 0;
617
6.39k
  }
618
619
459k
  return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
620
459k
}
621
622
/* --------------------------------------------------------------------- */
623
624
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
625
                            LPWSTR lpWideCharStr, int cchWideChar)
626
439k
{
627
439k
  size_t cbCharLen = (size_t)cbMultiByte;
628
629
439k
  WINPR_UNUSED(dwFlags);
630
631
  /* If cbMultiByte is 0, the function fails */
632
439k
  if ((cbMultiByte == 0) || (cbMultiByte < -1))
633
0
    return 0;
634
635
439k
  if (cchWideChar < 0)
636
0
    return -1;
637
638
439k
  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
439k
  else
646
439k
    cbCharLen = cbMultiByte;
647
648
439k
  WINPR_ASSERT(lpMultiByteStr);
649
439k
  switch (CodePage)
650
439k
  {
651
0
    case CP_ACP:
652
439k
    case CP_UTF8:
653
439k
      break;
654
655
0
    default:
656
0
      WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
657
0
      return 0;
658
439k
  }
659
660
439k
  return winpr_ConvertUTF8toUTF16((const uint8_t*)lpMultiByteStr,
661
439k
                                  WINPR_ASSERTING_INT_CAST(int, cbCharLen),
662
0
                                  (uint16_t*)lpWideCharStr, cchWideChar);
663
439k
}
664
665
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
666
                            LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
667
                            LPBOOL lpUsedDefaultChar)
668
465k
{
669
465k
  size_t cbCharLen = (size_t)cchWideChar;
670
671
465k
  WINPR_UNUSED(dwFlags);
672
  /* If cchWideChar is 0, the function fails */
673
465k
  if ((cchWideChar == 0) || (cchWideChar < -1))
674
0
    return 0;
675
676
465k
  if (cbMultiByte < 0)
677
0
    return -1;
678
679
465k
  WINPR_ASSERT(lpWideCharStr);
680
  /* If cchWideChar is -1, the string is null-terminated */
681
465k
  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
465k
  else
689
465k
    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
465k
  return winpr_ConvertUTF16toUTF8((const uint16_t*)lpWideCharStr,
697
465k
                                  WINPR_ASSERTING_INT_CAST(int, cbCharLen),
698
0
                                  (uint8_t*)lpMultiByteStr, cbMultiByte);
699
465k
}