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 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 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