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