Reactos
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
41static 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
209extern "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}