xref: /reactos/sdk/lib/ucrt/locale/CompareStringA.cpp (revision fe93a3f9)
1 /***
2 *a_cmp.c - A version of CompareString.
3 *
4 *       Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 *       Use either CompareStringA or CompareStringW depending on which is
8 *       available
9 *
10 *******************************************************************************/
11 #include <corecrt_internal.h>
12 
13 
14 
15 /***
16 *int __cdecl __acrt_CompareStringA - Get type information about an ANSI string.
17 *
18 *Purpose:
19 *       Internal support function. Assumes info in ANSI string format. Tries
20 *       to use NLS API call CompareStringA if available and uses CompareStringW
21 *       if it must. If neither are available it fails and returns 0.
22 *
23 *Entry:
24 *       LPCWSTR LocaleName  - locale context for the comparison.
25 *       DWORD   dwCmpFlags  - see NT\Chicago docs
26 *       LPCSTR  lpStringn   - multibyte string to be compared
27 *       int     cchCountn   - char (byte) count (NOT including nullptr)
28 *                             (-1 if nullptr terminated)
29 *       int     code_page   - for MB/WC conversion. If 0, use __lc_codepage
30 *
31 *Exit:
32 *       Success: 1 - if lpString1 <  lpString2
33 *                2 - if lpString1 == lpString2
34 *                3 - if lpString1 >  lpString2
35 *       Failure: 0
36 *
37 *Exceptions:
38 *
39 *******************************************************************************/
40 
41 static int __cdecl InternalCompareStringA(
42     _locale_t plocinfo,
43     LPCWSTR   LocaleName,
44     DWORD     dwCmpFlags,
45     PCCH      lpString1,
46     int       cchCount1,
47     PCCH      lpString2,
48     int       cchCount2,
49     int       code_page
50     ) throw()
51 {
52     /*
53      * CompareString will compare past nullptr. Must find nullptr if in string
54      * before cchCountn chars.
55      */
56 
57     if (cchCount1 > 0)
58         cchCount1 = static_cast<int>(__strncnt(lpString1, cchCount1));
59     else if (cchCount1 < -1)
60         return FALSE;
61 
62     if (cchCount2 > 0)
63         cchCount2 = static_cast<int>(__strncnt(lpString2, cchCount2));
64     else if (cchCount2 < -1)
65         return FALSE;
66 
67 
68     int buff_size1;
69     int buff_size2;
70 
71     /*
72      * Use __lc_codepage for conversion if code_page not specified
73      */
74 
75     if (0 == code_page)
76         code_page = plocinfo->locinfo->_public._locale_lc_codepage;
77 
78     /*
79      * Special case: at least one count is zero
80      */
81 
82     if (!cchCount1 || !cchCount2)
83     {
84         unsigned char *cp;  // char pointer
85         CPINFO cpInfo;      // struct for use with GetCPInfo
86 
87         /* both strings zero */
88         if (cchCount1 == cchCount2)
89             return 2;
90 
91         /* string 1 greater */
92         if (cchCount2 > 1)
93             return 1;
94 
95         /* string 2 greater */
96         if (cchCount1 > 1)
97             return 3;
98 
99         /*
100          * one has zero count, the other has a count of one
101          * - if the one count is a naked lead byte, the strings are equal
102          * - otherwise it is a single character and they are unequal
103          */
104 
105         if (GetCPInfo(code_page, &cpInfo) == FALSE)
106             return 0;
107 
108         _ASSERTE(cchCount1==0 && cchCount2==1 || cchCount1==1 && cchCount2==0);
109 
110         /* string 1 has count of 1 */
111         if (cchCount1 > 0)
112         {
113             if (cpInfo.MaxCharSize < 2)
114                 return 3;
115 
116             for ( cp = (unsigned char *)cpInfo.LeadByte ;
117                   cp[0] && cp[1] ;
118                   cp += 2 )
119                 if ( (*(unsigned char *)lpString1 >= cp[0]) &&
120                      (*(unsigned char *)lpString1 <= cp[1]) )
121                     return 2;
122 
123             return 3;
124         }
125 
126         /* string 2 has count of 1 */
127         if (cchCount2 > 0)
128         {
129             if (cpInfo.MaxCharSize < 2)
130             return 1;
131 
132             for ( cp = (unsigned char *)cpInfo.LeadByte ;
133                   cp[0] && cp[1] ;
134                   cp += 2 )
135                 if ( (*(unsigned char *)lpString2 >= cp[0]) &&
136                      (*(unsigned char *)lpString2 <= cp[1]) )
137                     return 2;
138 
139             return 1;
140         }
141     }
142 
143     /*
144      * Convert strings and return the requested information.
145      */
146 
147     /* find out how big a buffer we need (includes nullptr if any) */
148     if ( 0 == (buff_size1 = __acrt_MultiByteToWideChar( code_page,
149                                                  MB_PRECOMPOSED |
150                                                     MB_ERR_INVALID_CHARS,
151                                                  lpString1,
152                                                  cchCount1,
153                                                  nullptr,
154                                                  0 )) )
155         return 0;
156 
157     /* allocate enough space for chars */
158     __crt_scoped_stack_ptr<wchar_t> wbuffer1(_malloca_crt_t(wchar_t, buff_size1));
159     if (wbuffer1.get() == nullptr)
160         return 0;
161 
162     /* do the conversion */
163     if ( 0 == __acrt_MultiByteToWideChar( code_page,
164                                    MB_PRECOMPOSED,
165                                    lpString1,
166                                    cchCount1,
167                                    wbuffer1.get(),
168                                    buff_size1 ) )
169         return 0;
170 
171     /* find out how big a buffer we need (includes nullptr if any) */
172     if ( 0 == (buff_size2 = __acrt_MultiByteToWideChar( code_page,
173                                                  MB_PRECOMPOSED |
174                                                     MB_ERR_INVALID_CHARS,
175                                                  lpString2,
176                                                  cchCount2,
177                                                  nullptr,
178                                                  0 )) )
179         return 0;
180 
181     /* allocate enough space for chars */
182     __crt_scoped_stack_ptr<wchar_t> const wbuffer2(_malloca_crt_t(wchar_t, buff_size2));
183     if (wbuffer2.get() == nullptr)
184         return 0;
185 
186     int const actual_size = __acrt_MultiByteToWideChar(
187         code_page,
188         MB_PRECOMPOSED,
189         lpString2,
190         cchCount2,
191         wbuffer2.get(),
192         buff_size2);
193 
194     if (actual_size == 0)
195         return 0;
196 
197     return __acrt_CompareStringEx(
198         LocaleName,
199         dwCmpFlags,
200         wbuffer1.get(),
201         buff_size1,
202         wbuffer2.get(),
203         buff_size2,
204         nullptr,
205         nullptr,
206         0);
207 }
208 
209 extern "C" int __cdecl __acrt_CompareStringA(
210     _locale_t const locale,
211     LPCWSTR   const locale_name,
212     DWORD     const compare_flags,
213     PCCH      const string1,
214     int       const string1_count,
215     PCCH      const string2,
216     int       const string2_count,
217     int       const code_page
218     )
219 {
220     _LocaleUpdate locale_update(locale);
221 
222     return InternalCompareStringA(
223         locale_update.GetLocaleT(),
224         locale_name,
225         compare_flags,
226         string1,
227         string1_count,
228         string2,
229         string2_count,
230         code_page
231         );
232 }
233