xref: /reactos/sdk/lib/ucrt/locale/LCMapStringA.cpp (revision 04e0dc4a)
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