• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #include <curl/curl.h>
26 
27 #include "strcase.h"
28 
29 static char raw_tolower(char in);
30 
31 /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
32    its behavior is altered by the current locale. */
Curl_raw_toupper(char in)33 char Curl_raw_toupper(char in)
34 {
35 #if !defined(CURL_DOES_CONVERSIONS)
36   if(in >= 'a' && in <= 'z')
37     return (char)('A' + in - 'a');
38 #else
39   switch(in) {
40   case 'a':
41     return 'A';
42   case 'b':
43     return 'B';
44   case 'c':
45     return 'C';
46   case 'd':
47     return 'D';
48   case 'e':
49     return 'E';
50   case 'f':
51     return 'F';
52   case 'g':
53     return 'G';
54   case 'h':
55     return 'H';
56   case 'i':
57     return 'I';
58   case 'j':
59     return 'J';
60   case 'k':
61     return 'K';
62   case 'l':
63     return 'L';
64   case 'm':
65     return 'M';
66   case 'n':
67     return 'N';
68   case 'o':
69     return 'O';
70   case 'p':
71     return 'P';
72   case 'q':
73     return 'Q';
74   case 'r':
75     return 'R';
76   case 's':
77     return 'S';
78   case 't':
79     return 'T';
80   case 'u':
81     return 'U';
82   case 'v':
83     return 'V';
84   case 'w':
85     return 'W';
86   case 'x':
87     return 'X';
88   case 'y':
89     return 'Y';
90   case 'z':
91     return 'Z';
92   }
93 #endif
94 
95   return in;
96 }
97 
98 
99 /* Portable, consistent tolower (remember EBCDIC). Do not use tolower() because
100    its behavior is altered by the current locale. */
raw_tolower(char in)101 static char raw_tolower(char in)
102 {
103 #if !defined(CURL_DOES_CONVERSIONS)
104   if(in >= 'A' && in <= 'Z')
105     return (char)('a' + in - 'A');
106 #else
107   switch(in) {
108   case 'A':
109     return 'a';
110   case 'B':
111     return 'b';
112   case 'C':
113     return 'c';
114   case 'D':
115     return 'd';
116   case 'E':
117     return 'e';
118   case 'F':
119     return 'f';
120   case 'G':
121     return 'g';
122   case 'H':
123     return 'h';
124   case 'I':
125     return 'i';
126   case 'J':
127     return 'j';
128   case 'K':
129     return 'k';
130   case 'L':
131     return 'l';
132   case 'M':
133     return 'm';
134   case 'N':
135     return 'n';
136   case 'O':
137     return 'o';
138   case 'P':
139     return 'p';
140   case 'Q':
141     return 'q';
142   case 'R':
143     return 'r';
144   case 'S':
145     return 's';
146   case 'T':
147     return 't';
148   case 'U':
149     return 'u';
150   case 'V':
151     return 'v';
152   case 'W':
153     return 'w';
154   case 'X':
155     return 'x';
156   case 'Y':
157     return 'y';
158   case 'Z':
159     return 'z';
160   }
161 #endif
162 
163   return in;
164 }
165 
166 
167 /*
168  * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is
169  * meant to be locale independent and only compare strings we know are safe
170  * for this.  See
171  * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some
172  * further explanation to why this function is necessary.
173  *
174  * The function is capable of comparing a-z case insensitively even for
175  * non-ascii.
176  *
177  * @unittest: 1301
178  */
179 
Curl_strcasecompare(const char * first,const char * second)180 int Curl_strcasecompare(const char *first, const char *second)
181 {
182   while(*first && *second) {
183     if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
184       /* get out of the loop as soon as they don't match */
185       break;
186     first++;
187     second++;
188   }
189   /* we do the comparison here (possibly again), just to make sure that if the
190      loop above is skipped because one of the strings reached zero, we must not
191      return this as a successful match */
192   return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
193 }
194 
Curl_safe_strcasecompare(const char * first,const char * second)195 int Curl_safe_strcasecompare(const char *first, const char *second)
196 {
197   if(first && second)
198     /* both pointers point to something then compare them */
199     return Curl_strcasecompare(first, second);
200 
201   /* if both pointers are NULL then treat them as equal */
202   return (NULL == first && NULL == second);
203 }
204 
205 /*
206  * @unittest: 1301
207  */
Curl_strncasecompare(const char * first,const char * second,size_t max)208 int Curl_strncasecompare(const char *first, const char *second, size_t max)
209 {
210   while(*first && *second && max) {
211     if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
212       break;
213     }
214     max--;
215     first++;
216     second++;
217   }
218   if(0 == max)
219     return 1; /* they are equal this far */
220 
221   return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
222 }
223 
224 /* Copy an upper case version of the string from src to dest.  The
225  * strings may overlap.  No more than n characters of the string are copied
226  * (including any NUL) and the destination string will NOT be
227  * NUL-terminated if that limit is reached.
228  */
Curl_strntoupper(char * dest,const char * src,size_t n)229 void Curl_strntoupper(char *dest, const char *src, size_t n)
230 {
231   if(n < 1)
232     return;
233 
234   do {
235     *dest++ = Curl_raw_toupper(*src);
236   } while(*src++ && --n);
237 }
238 
239 /* Copy a lower case version of the string from src to dest.  The
240  * strings may overlap.  No more than n characters of the string are copied
241  * (including any NUL) and the destination string will NOT be
242  * NUL-terminated if that limit is reached.
243  */
Curl_strntolower(char * dest,const char * src,size_t n)244 void Curl_strntolower(char *dest, const char *src, size_t n)
245 {
246   if(n < 1)
247     return;
248 
249   do {
250     *dest++ = raw_tolower(*src);
251   } while(*src++ && --n);
252 }
253 
254 /* Compare case-sensitive NUL-terminated strings, taking care of possible
255  * null pointers. Return true if arguments match.
256  */
Curl_safecmp(char * a,char * b)257 bool Curl_safecmp(char *a, char *b)
258 {
259   if(a && b)
260     return !strcmp(a, b);
261   return !a && !b;
262 }
263 
264 /*
265  * Curl_timestrcmp() returns 0 if the two strings are identical. The time this
266  * function spends is a function of the shortest string, not of the contents.
267  */
Curl_timestrcmp(const char * a,const char * b)268 int Curl_timestrcmp(const char *a, const char *b)
269 {
270   int match = 0;
271   int i = 0;
272 
273   if(a && b) {
274     while(1) {
275       match |= a[i]^b[i];
276       if(!a[i] || !b[i])
277         break;
278       i++;
279     }
280   }
281   else
282     return a || b;
283   return match;
284 }
285 
286 /* --- public functions --- */
287 
curl_strequal(const char * first,const char * second)288 int curl_strequal(const char *first, const char *second)
289 {
290   return Curl_strcasecompare(first, second);
291 }
curl_strnequal(const char * first,const char * second,size_t max)292 int curl_strnequal(const char *first, const char *second, size_t max)
293 {
294   return Curl_strncasecompare(first, second, max);
295 }
296