1 /***
2 *a_map.c - A version of LCMapString.
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 * Use either LCMapStringA or LCMapStringW depending on which is available
8 *
9 *******************************************************************************/
10 #include <corecrt_internal.h>
11 #include <locale.h>
12
13 /***
14 *int __cdecl __acrt_LCMapStringA - Get type information about an ANSI string.
15 *
16 *Purpose:
17 * Internal support function. Assumes info in ANSI string format. Tries
18 * to use NLS API call LCMapStringA if available and uses LCMapStringW
19 * if it must. If neither are available it fails and returns 0.
20 *
21 *Entry:
22 * LPCWSTR LocaleName - locale context for the comparison.
23 * DWORD dwMapFlags - see NT\Chicago docs
24 * PCCH cchSrc - wide char (word) count of input string
25 * (including nullptr if any)
26 * (-1 if nullptr terminated)
27 * PCH lpDestStr - pointer to memory to store mapping
28 * int cchDest - char (byte) count of buffer (including nullptr)
29 * int code_page - for MB/WC conversion. If 0, use __lc_codepage
30 * BOOL bError - TRUE if MB_ERR_INVALID_CHARS set on call to
31 * MultiByteToWideChar when GetStringTypeW used.
32 *
33 *Exit:
34 * Success: number of chars written to lpDestStr (including nullptr)
35 * Failure: 0
36 *
37 *Exceptions:
38 *
39 *******************************************************************************/
40
__acrt_LCMapStringA_stat(_In_opt_ _locale_t plocinfo,_In_ LPCWSTR LocaleName,_In_ DWORD dwMapFlags,_In_CRT_NLS_string_ (cchSrc)PCCH lpSrcStr,_In_ int cchSrc,_Out_writes_opt_ (cchDest)PCH lpDestStr,_In_ int cchDest,_In_ int code_page,_In_ BOOL bError)41 static _Success_(return != 0) int __cdecl __acrt_LCMapStringA_stat(
42 _In_opt_ _locale_t plocinfo,
43 _In_ LPCWSTR LocaleName,
44 _In_ DWORD dwMapFlags,
45 _In_CRT_NLS_string_(cchSrc) PCCH lpSrcStr,
46 _In_ int cchSrc,
47 _Out_writes_opt_(cchDest) PCH lpDestStr,
48 _In_ int cchDest,
49 _In_ int code_page,
50 _In_ BOOL bError
51 )
52 {
53 // LCMapString will map past the null terminator. We must find the null
54 // terminator if it occurs in the string before cchSrc characters
55 // and cap the number of characters to be considered.
56 if (cchSrc > 0)
57 {
58 int cchSrcCnt = static_cast<int>(__strncnt(lpSrcStr, cchSrc));
59
60 // Include the null terminator if the source string is terminated within
61 // the buffer.
62 if (cchSrcCnt < cchSrc)
63 {
64 cchSrc = cchSrcCnt + 1;
65 }
66 else
67 {
68 cchSrc = cchSrcCnt;
69 }
70 }
71
72 int retval = 0;
73 int inbuff_size;
74 int outbuff_size;
75
76 /*
77 * Convert string and return the requested information. Note that
78 * we are converting to a wide string so there is not a
79 * one-to-one correspondence between number of wide chars in the
80 * input string and the number of *bytes* in the buffer. However,
81 * there had *better be* a one-to-one correspondence between the
82 * number of wide characters and the number of multibyte characters
83 * or the resulting mapped string will be worthless to the user.
84 */
85
86 /*
87 * Use __lc_codepage for conversion if code_page not specified
88 */
89
90 if (0 == code_page)
91 code_page = plocinfo->locinfo->_public._locale_lc_codepage;
92
93 /* find out how big a buffer we need (includes nullptr if any) */
94 if ( 0 == (inbuff_size =
95 __acrt_MultiByteToWideChar( code_page,
96 bError ? MB_PRECOMPOSED |
97 MB_ERR_INVALID_CHARS :
98 MB_PRECOMPOSED,
99 lpSrcStr,
100 cchSrc,
101 nullptr,
102 0 )) )
103 return 0;
104
105 /* allocate enough space for wide chars */
106 __crt_scoped_stack_ptr<wchar_t> const inwbuffer(_malloca_crt_t(wchar_t, inbuff_size));
107 if (!inwbuffer)
108 return 0;
109
110 /* do the conversion */
111 if ( 0 == __acrt_MultiByteToWideChar( code_page,
112 MB_PRECOMPOSED,
113 lpSrcStr,
114 cchSrc,
115 inwbuffer.get(),
116 inbuff_size) )
117 return retval;
118
119 /* get size required for string mapping */
120 if ( 0 == (retval = __acrt_LCMapStringEx( LocaleName,
121 dwMapFlags,
122 inwbuffer.get(),
123 inbuff_size,
124 nullptr,
125 0,
126 nullptr,
127 nullptr,
128 0)) )
129 return retval;
130
131 if (dwMapFlags & LCMAP_SORTKEY) {
132 /* retval is size in BYTES */
133
134 if (0 != cchDest) {
135
136 if (retval > cchDest)
137 return 0;
138
139 /* do string mapping */
140 // The buffer overflow warning here is due to an inadequate annotation
141 // on __acrt_LCMapStringEx. When the map flags include LCMAP_SORTKEY,
142 // the destination buffer is actually required to be an array of bytes,
143 // despite the type of the buffer being a wchar_t*.
144 __pragma(warning(suppress: __WARNING_BUFFER_OVERFLOW))
145 if ( 0 == (retval = __acrt_LCMapStringEx( LocaleName,
146 dwMapFlags,
147 inwbuffer.get(),
148 inbuff_size,
149 reinterpret_cast<PWCH>(lpDestStr),
150 cchDest,
151 nullptr,
152 nullptr,
153 0)) )
154 return retval;
155 }
156 }
157 else {
158 /* retval is size in wide chars */
159
160 outbuff_size = retval;
161
162 /* allocate enough space for wide chars (includes nullptr if any) */
163 __crt_scoped_stack_ptr<wchar_t> const outwbuffer(_malloca_crt_t(wchar_t, outbuff_size));
164 if (!outwbuffer)
165 return 0;
166
167 /* do string mapping */
168 if ( 0 == (retval = __acrt_LCMapStringEx( LocaleName,
169 dwMapFlags,
170 inwbuffer.get(),
171 inbuff_size,
172 outwbuffer.get(),
173 outbuff_size,
174 nullptr,
175 nullptr,
176 0)) )
177 return retval;
178
179 if (0 == cchDest) {
180 /* get size required */
181 if ( 0 == (retval =
182 __acrt_WideCharToMultiByte( code_page,
183 0,
184 outwbuffer.get(),
185 outbuff_size,
186 nullptr,
187 0,
188 nullptr,
189 nullptr )) )
190 return retval;
191 }
192 else {
193 /* convert mapping */
194 if ( 0 == (retval =
195 __acrt_WideCharToMultiByte( code_page,
196 0,
197 outwbuffer.get(),
198 outbuff_size,
199 lpDestStr,
200 cchDest,
201 nullptr,
202 nullptr )) )
203 return retval;
204 }
205 }
206
207 return retval;
208 }
209
__acrt_LCMapStringA(_locale_t const plocinfo,PCWSTR const LocaleName,DWORD const dwMapFlags,PCCH const lpSrcStr,int const cchSrc,PCH const lpDestStr,int const cchDest,int const code_page,BOOL const bError)210 extern "C" int __cdecl __acrt_LCMapStringA(
211 _locale_t const plocinfo,
212 PCWSTR const LocaleName,
213 DWORD const dwMapFlags,
214 PCCH const lpSrcStr,
215 int const cchSrc,
216 PCH const lpDestStr,
217 int const cchDest,
218 int const code_page,
219 BOOL const bError
220 )
221 {
222 _LocaleUpdate _loc_update(plocinfo);
223
224 return __acrt_LCMapStringA_stat(
225 _loc_update.GetLocaleT(),
226 LocaleName,
227 dwMapFlags,
228 lpSrcStr,
229 cchSrc,
230 lpDestStr,
231 cchDest,
232 code_page,
233 bError
234 );
235 }
236