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