[CMAKE]
[reactos.git] / lib / 3rdparty / fullfat / ff_string.c
1 /*****************************************************************************
2 * FullFAT - High Performance, Thread-Safe Embedded FAT File-System *
3 * Copyright (C) 2009 James Walmsley (james@worm.me.uk) *
4 * *
5 * This program is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 * *
18 * IMPORTANT NOTICE: *
19 * ================= *
20 * Alternative Licensing is available directly from the Copyright holder, *
21 * (James Walmsley). For more information consult LICENSING.TXT to obtain *
22 * a Commercial license. *
23 * *
24 * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. *
25 * *
26 * Removing the above notice is illegal and will invalidate this license. *
27 *****************************************************************************
28 * See http://worm.me.uk/fullfat for more information. *
29 * Or http://fullfat.googlecode.com/ for latest releases and the wiki. *
30 *****************************************************************************/
31
32 /**
33 * @file ff_string.c
34 * @author James Walmsley
35 * @ingroup STRING
36 *
37 * @defgroup STRING FullFAT String Library
38 * @brief Portable String Library for FullFAT
39 *
40 *
41 **/
42
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include "ff_string.h"
47 #include "ff_error.h"
48
49 #ifdef FF_UNICODE_SUPPORT
50 #include <wchar.h>
51 #include <wctype.h>
52 #endif
53
54 /*
55 * These will eventually be moved into a platform independent string
56 * library. Which will be optional. (To allow the use of system specific versions).
57 */
58
59 #ifdef FF_UNICODE_SUPPORT
60
61 void FF_cstrntowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource, FF_T_UINT32 len) {
62 while(*szpSource && len--) {
63 *wcsDest++ = *szpSource++;
64 }
65 *wcsDest = '\0';
66 }
67
68 void FF_cstrtowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource) {
69 while(*szpSource) {
70 *wcsDest++ = (FF_T_WCHAR) *szpSource++;
71 }
72 *wcsDest = '\0';
73 }
74
75 void FF_wcstocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource) {
76 while(*wcsSource) {
77 *szpDest++ = (FF_T_INT8) *wcsSource++;
78 }
79 *szpDest = '\0';
80 }
81
82 void FF_wcsntocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource, FF_T_UINT32 len) {
83 while(*wcsSource && len--) {
84 *szpDest++ = (FF_T_INT8) *wcsSource++;
85 }
86 *szpDest = '\0';
87 }
88
89 #endif
90
91 /**
92 * @private
93 * @brief Converts an ASCII string to lowercase.
94 **/
95 #ifndef FF_UNICODE_SUPPORT
96 /**
97 * @private
98 * @brief Converts an ASCII string to uppercase.
99 **/
100 void FF_toupper(FF_T_INT8 *string, FF_T_UINT32 strLen) {
101 FF_T_UINT32 i;
102 for(i = 0; i < strLen; i++) {
103 if(string[i] >= 'a' && string[i] <= 'z')
104 string[i] -= 32;
105 if(string[i] == '\0')
106 break;
107 }
108 }
109 void FF_tolower(FF_T_INT8 *string, FF_T_UINT32 strLen) {
110 FF_T_UINT32 i;
111 for(i = 0; i < strLen; i++) {
112 if(string[i] >= 'A' && string[i] <= 'Z')
113 string[i] += 32;
114 if(string[i] == '\0')
115 break;
116 }
117 }
118
119 #else
120 void FF_toupper(FF_T_WCHAR *string, FF_T_UINT32 strLen) {
121 FF_T_UINT32 i;
122 for(i = 0; i < strLen; i++) {
123 string[i] = towupper(string[i]);
124 }
125 }
126 void FF_tolower(FF_T_WCHAR *string, FF_T_UINT32 strLen) {
127 FF_T_UINT32 i;
128 for(i = 0; i < strLen; i++) {
129 string[i] = towlower(string[i]);
130 }
131 }
132 #endif
133
134
135
136
137 /**
138 * @private
139 * @brief Compares 2 strings for the specified length, and returns FF_TRUE is they are identical
140 * otherwise FF_FALSE is returned.
141 *
142 **/
143
144 #ifndef FF_UNICODE_SUPPORT
145 FF_T_BOOL FF_strmatch(const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len) {
146 register FF_T_UINT16 i;
147 register FF_T_INT8 char1, char2;
148
149 if(!len) {
150 if(strlen(str1) != strlen(str2)) {
151 return FF_FALSE;
152 }
153 len = (FF_T_UINT16) strlen(str1);
154 }
155
156 for(i = 0; i < len; i++) {
157 char1 = str1[i];
158 char2 = str2[i];
159 if(char1 >= 'A' && char1 <= 'Z') {
160 char1 += 32;
161 }
162 if(char2 >= 'A' && char2 <= 'Z') {
163 char2 += 32;
164 }
165
166 if(char1 != char2) {
167 return FF_FALSE;
168 }
169 }
170
171 return FF_TRUE;
172 }
173 #else
174
175 FF_T_BOOL FF_strmatch(const FF_T_WCHAR *str1, const FF_T_WCHAR *str2, FF_T_UINT16 len) {
176 register FF_T_UINT16 i;
177 register FF_T_WCHAR char1, char2;
178
179 if(!len) {
180 if(wcslen(str1) != wcslen(str2)) {
181 return FF_FALSE;
182 }
183 len = (FF_T_UINT16) wcslen(str1);
184 }
185
186 for(i = 0; i < len; i++) {
187 char1 = towlower(str1[i]);
188 char2 = towlower(str2[i]);
189 if(char1 != char2) {
190 return FF_FALSE;
191 }
192 }
193
194 return FF_TRUE;
195 }
196 #endif
197
198 /**
199 * @private
200 * @brief A re-entrant Strtok function. No documentation is provided :P
201 * Use at your own risk. (This is for FullFAT's use only).
202 **/
203
204 #ifndef FF_UNICODE_SUPPORT
205 FF_T_INT8 *FF_strtok(const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length) {
206 FF_T_UINT16 strLen = Length;
207 FF_T_UINT16 i,y, tokenStart, tokenEnd = 0;
208
209 i = 0;
210 y = 0;
211
212 if(string[i] == '\\' || string[i] == '/') {
213 i++;
214 }
215
216 tokenStart = i;
217
218 while(i < strLen) {
219 if(string[i] == '\\' || string[i] == '/') {
220 y++;
221 if(y == *tokenNumber) {
222 tokenStart = (FF_T_UINT16)(i + 1);
223 }
224 if(y == (*tokenNumber + 1)) {
225 tokenEnd = i;
226 break;
227 }
228 }
229 i++;
230 }
231
232 if(!tokenEnd) {
233 if(*last == FF_TRUE) {
234 return NULL;
235 } else {
236 *last = FF_TRUE;
237 }
238 tokenEnd = i;
239 }
240 if((tokenEnd - tokenStart) < FF_MAX_FILENAME) {
241 memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart));
242 token[tokenEnd - tokenStart] = '\0';
243 } else {
244 memcpy(token, (string + tokenStart), (FF_T_UINT32)(FF_MAX_FILENAME));
245 token[FF_MAX_FILENAME-1] = '\0';
246 }
247 //token[tokenEnd - tokenStart] = '\0';
248 *tokenNumber += 1;
249
250 return token;
251 }
252
253 #else
254 FF_T_WCHAR *FF_strtok(const FF_T_WCHAR *string, FF_T_WCHAR *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length) {
255 FF_T_UINT16 strLen = Length;
256 FF_T_UINT16 i,y, tokenStart, tokenEnd = 0;
257
258 i = 0;
259 y = 0;
260
261 if(string[i] == '\\' || string[i] == '/') {
262 i++;
263 }
264
265 tokenStart = i;
266
267 while(i < strLen) {
268 if(string[i] == '\\' || string[i] == '/') {
269 y++;
270 if(y == *tokenNumber) {
271 tokenStart = (FF_T_UINT16)(i + 1);
272 }
273 if(y == (*tokenNumber + 1)) {
274 tokenEnd = i;
275 break;
276 }
277 }
278 i++;
279 }
280
281 if(!tokenEnd) {
282 if(*last == FF_TRUE) {
283 return NULL;
284 } else {
285 *last = FF_TRUE;
286 }
287 tokenEnd = i;
288 }
289 if((tokenEnd - tokenStart) < FF_MAX_FILENAME) {
290 memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart) * sizeof(FF_T_WCHAR));
291 token[tokenEnd - tokenStart] = '\0';
292 } else {
293 memcpy(token, (string + tokenStart), (FF_T_UINT32)(FF_MAX_FILENAME) * sizeof(FF_T_WCHAR));
294 token[FF_MAX_FILENAME-1] = '\0';
295 }
296 //token[tokenEnd - tokenStart] = '\0';
297 *tokenNumber += 1;
298
299 return token;
300 }
301 #endif
302
303 /*
304 A Wild-Card Comparator Library function, Provided by Adam Fullerton.
305 This can be extended or altered to improve or advance wildCard matching
306 of the FF_FindFirst() and FF_FindNext() API's.
307 */
308 #ifdef FF_FINDAPI_ALLOW_WILDCARDS
309 /*FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) {
310 // Check to see if the string contains the wild card
311 if (!memchr(pszWildCard, '*', strlen(pszWildCard)))
312 {
313 // if it does not then do a straight string compare
314 if (strcmp(pszWildCard, pszString))
315 {
316 return FF_FALSE;
317 }
318 }
319 else
320 {
321 while ((*pszWildCard)
322 && (*pszString))
323 {
324 // Test for the wild card
325 if (*pszWildCard == '*')
326 {
327 // Eat more than one
328 while (*pszWildCard == '*')
329 {
330 pszWildCard++;
331 }
332 // If there are more chars in the string
333 if (*pszWildCard)
334 {
335 // Search for the next char
336 pszString = memchr(pszString, (int)*pszWildCard, strlen(pszString));
337 // if it does not exist then the strings don't match
338 if (!pszString)
339 {
340 return FF_FALSE;
341 }
342
343 }
344 else
345 {
346 if (*pszWildCard)
347 {
348 // continue
349 break;
350 }
351 else
352 {
353 return FF_TRUE;
354 }
355 }
356 }
357 else
358 {
359 // Fail if they don't match
360 if (*pszWildCard != *pszString)
361 {
362 return FF_FALSE;
363 }
364 }
365 // Bump both pointers
366 pszWildCard++;
367 pszString++;
368 }
369 // fail if different lengths
370 if (*pszWildCard != *pszString)
371 {
372 return FF_FALSE;
373 }
374 }
375
376 return FF_TRUE;
377 }*/
378 /*
379 This is a better Wild-card compare function, that works perfectly, and is much more efficient.
380 This function was contributed by one of our commercial customers.
381 */
382 #ifdef FF_UNICODE_SUPPORT
383 FF_T_BOOL FF_wildcompare(const FF_T_WCHAR *pszWildCard, const FF_T_WCHAR *pszString) {
384 register const FF_T_WCHAR *pszWc = NULL;
385 register const FF_T_WCHAR *pszStr = NULL; // Encourage the string pointers to be placed in memory.
386 do {
387 if ( *pszWildCard == '*' ) {
388 while(*(1 + pszWildCard++) == '*'); // Eat up multiple '*''s
389 pszWc = (pszWildCard - 1);
390 pszStr = pszString;
391 }
392 if (*pszWildCard == '?' && !*pszString) {
393 return FF_FALSE; // False when the string is ended, yet a ? charachter is demanded.
394 }
395 #ifdef FF_WILDCARD_CASE_INSENSITIVE
396 if (*pszWildCard != '?' && tolower(*pszWildCard) != tolower(*pszString)) {
397 #else
398 if (*pszWildCard != '?' && *pszWildCard != *pszString) {
399 #endif
400 if (pszWc == NULL) {
401 return FF_FALSE;
402 }
403 pszWildCard = pszWc;
404 pszString = pszStr++;
405 }
406 } while ( *pszWildCard++ && *pszString++ );
407
408 while(*pszWildCard == '*') {
409 pszWildCard++;
410 }
411
412 if(!*(pszWildCard - 1)) { // WildCard is at the end. (Terminated)
413 return FF_TRUE; // Therefore this must be a match.
414 }
415
416 return FF_FALSE; // If not, then return FF_FALSE!
417 }
418 #else
419 FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) {
420 register const FF_T_INT8 *pszWc = NULL;
421 register const FF_T_INT8 *pszStr = NULL; // Encourage the string pointers to be placed in memory.
422 do {
423 if ( *pszWildCard == '*' ) {
424 while(*(1 + pszWildCard++) == '*'); // Eat up multiple '*''s
425 pszWc = (pszWildCard - 1);
426 pszStr = pszString;
427 }
428 if (*pszWildCard == '?' && !*pszString) {
429 return FF_FALSE; // False when the string is ended, yet a ? charachter is demanded.
430 }
431 #ifdef FF_WILDCARD_CASE_INSENSITIVE
432 if (*pszWildCard != '?' && tolower(*pszWildCard) != tolower(*pszString)) {
433 #else
434 if (*pszWildCard != '?' && *pszWildCard != *pszString) {
435 #endif
436 if (pszWc == NULL) {
437 return FF_FALSE;
438 }
439 pszWildCard = pszWc;
440 pszString = pszStr++;
441 }
442 } while ( *pszWildCard++ && *pszString++ );
443
444 while(*pszWildCard == '*') {
445 pszWildCard++;
446 }
447
448 if(!*(pszWildCard - 1)) { // WildCard is at the end. (Terminated)
449 return FF_TRUE; // Therefore this must be a match.
450 }
451
452 return FF_FALSE; // If not, then return FF_FALSE!
453 }
454 #endif
455
456 #endif