xref: /reactos/sdk/lib/ucrt/convert/_mbslen.cpp (revision 04e0dc4a)
1 //
2 // _mbslen.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Defines the mbstrlen functions, which return the number of multibyte
7 // characters in a multibyte string, excluding the null terminator.  This
8 // function is locale-dependent.  If the string contains invalid multibyte
9 // characters, -1 is returned and errno is set to EILSEQ.
10 //
11 // There are two variations of these functions:  mbstrnlen (note the 'n'),
12 // which takes a max_size, which is the maximum number of bytes to scan
13 // in the string.  These variations also validate their arguments.  The
14 // variations without the 'n' (mbstrlen) stop only when the null terminator
15 // is reached and do not validate their arguments.
16 //
17 #include <corecrt_internal.h>
18 #include <stdlib.h>
19 
20 
21 
22 _Check_return_
_String_length_(string)23 _Post_satisfies_((return <= _String_length_(string) && return <= max_size) || return == (size_t)-1)
24 static size_t __cdecl common_mbstrlen_l(
25     char const* const string,
26     size_t      const max_size,
27     _locale_t   const locale
28     )
29 {
30     _LocaleUpdate locale_update(locale);
31 
32     _ASSERTE(
33         locale_update.GetLocaleT()->locinfo->_public._locale_mb_cur_max == 1 ||
34         locale_update.GetLocaleT()->locinfo->_public._locale_mb_cur_max == 2);
35 
36     // Handle single byte character sets:
37     if (locale_update.GetLocaleT()->locinfo->_public._locale_mb_cur_max == 1)
38     {
39         return strnlen(string, max_size);
40     }
41 
42     // Verify that all of the multibyte characters are valid:
43     if (__acrt_MultiByteToWideChar(
44             locale_update.GetLocaleT()->locinfo->_public._locale_lc_codepage,
45             MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
46             string,
47             static_cast<int>(max_size),
48             nullptr,
49             0
50         ) == 0)
51     {
52         // There was a bad multibyte character:
53         errno = EILSEQ;
54         return static_cast<size_t>(-1);
55     }
56 
57     // Count multibyte characters:
58     size_t n    = 0; // Number of multibyte characters read
59     size_t size = 0; // Number of bytes read
60     for (char const* it = string; size < max_size && *it; ++n, ++it, ++size)
61     {
62         if (_isleadbyte_fast_internal(static_cast<unsigned char>(*it), locale_update.GetLocaleT()))
63         {
64             ++size;
65             if (size >= max_size)
66                 break;
67 
68             ++it;
69             if (*it == '\0')
70                 break;
71         }
72     }
73 
74     return size >= max_size ? max_size : n;
75 }
76 
77 
78 
_mbstrlen_l(char const * const string,_locale_t const locale)79 extern "C" size_t __cdecl _mbstrlen_l(
80     char const* const string,
81     _locale_t   const locale
82     )
83 {
84     return common_mbstrlen_l(string, _CRT_UNBOUNDED_BUFFER_SIZE, locale);
85 }
86 
_mbstrlen(char const * const string)87 extern "C" size_t __cdecl _mbstrlen(char const* const string)
88 {
89     if (!__acrt_locale_changed())
90     {
91         return strlen(string);
92     }
93     else
94     {
95         return _mbstrlen_l(string, nullptr);
96     }
97 }
98 
99 
100 
_mbstrnlen_l(char const * const string,size_t const max_size,_locale_t const locale)101 extern "C" size_t __cdecl _mbstrnlen_l(
102     char const* const string,
103     size_t      const max_size,
104     _locale_t   const locale
105     )
106 {
107     _VALIDATE_RETURN(string != nullptr,   EINVAL, static_cast<size_t>(-1));
108     _VALIDATE_RETURN(max_size <= INT_MAX, EINVAL, static_cast<size_t>(-1));
109 
110     return common_mbstrlen_l(string, max_size, locale);
111 }
112 
_mbstrnlen(char const * const string,size_t const max_size)113 extern "C" size_t __cdecl _mbstrnlen(
114     char const* const string,
115     size_t      const max_size
116     )
117 {
118     return _mbstrnlen_l(string, max_size, nullptr);
119 }
120