Moved mode setting out of .spec file into Makefile.
[wine/gsoc_dplay.git] / dlls / shlwapi / string.c
blob45db498203214ce59f7247d5971db7fb195b1fa9
1 /*
2 * Shlwapi string functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include "winerror.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winreg.h"
36 #define NO_SHLWAPI_STREAM
37 #include "shlwapi.h"
38 #include "shlobj.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(shell);
44 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest);
45 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest);
47 /*************************************************************************
48 * SHLWAPI_ChrCmpHelperA
50 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
52 * NOTES
53 * Both this function and its Unicode counterpart are very inneficient. To
54 * fix this, CompareString must be completely implemented and optimised
55 * first. Then the core character test can be taken out of that function and
56 * placed here, so that it need never be called at all. Until then, do not
57 * attempt to optimise this code unless you are willing to test that it
58 * still performs correctly.
60 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
62 char str1[3], str2[3];
64 str1[0] = LOBYTE(ch1);
65 if (IsDBCSLeadByte(ch1))
67 str1[1] = HIBYTE(ch1);
68 str1[2] = '\0';
70 else
71 str1[1] = '\0';
73 str2[0] = LOBYTE(ch2);
74 if (IsDBCSLeadByte(ch2))
76 str2[1] = HIBYTE(ch2);
77 str2[2] = '\0';
79 else
80 str2[1] = '\0';
82 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
85 /*************************************************************************
86 * SHLWAPI_ChrCmpHelperW
88 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
90 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
92 WCHAR str1[2], str2[2];
94 str1[0] = ch1;
95 str1[1] = '\0';
96 str2[0] = ch2;
97 str2[1] = '\0';
98 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
101 /*************************************************************************
102 * SHLWAPI_ChrCmpA
104 * Internal helper function.
106 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
108 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
111 /*************************************************************************
112 * ChrCmpIA [SHLWAPI.385]
114 * Compare two characters, ignoring case.
116 * PARAMS
117 * ch1 [I] First character to compare
118 * ch2 [I] Second character to compare
120 * RETURNS
121 * FALSE, if the characters are equal.
122 * Non-zero otherwise.
124 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
126 TRACE("(%d,%d)\n", ch1, ch2);
128 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
131 /*************************************************************************
132 * SHLWAPI_ChrCmpW
134 * Internal helper function.
136 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
138 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
141 /*************************************************************************
142 * ChrCmpIW [SHLWAPI.386]
144 * See ChrCmpIA.
146 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
148 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
151 /*************************************************************************
152 * StrChrA [SHLWAPI.@]
154 * Find a given character in a string.
156 * PARAMS
157 * lpszStr [I] String to search in.
158 * ch [I] Character to search for.
160 * RETURNS
161 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
162 * not found.
163 * Failure: NULL, if any arguments are invalid.
165 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
167 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
169 if (lpszStr)
171 while (*lpszStr)
173 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
174 return (LPSTR)lpszStr;
175 lpszStr = CharNextA(lpszStr);
178 return NULL;
181 /*************************************************************************
182 * StrChrW [SHLWAPI.@]
184 * See StrChrA.
186 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
188 LPWSTR lpszRet = NULL;
190 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
192 if (lpszStr)
193 lpszRet = strchrW(lpszStr, ch);
194 return lpszRet;
197 /*************************************************************************
198 * StrChrIA [SHLWAPI.@]
200 * Find a given character in a string, ignoring case.
202 * PARAMS
203 * lpszStr [I] String to search in.
204 * ch [I] Character to search for.
206 * RETURNS
207 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
208 * not found.
209 * Failure: NULL, if any arguments are invalid.
211 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
213 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
215 if (lpszStr)
217 while (*lpszStr)
219 if (!ChrCmpIA(*lpszStr, ch))
220 return (LPSTR)lpszStr;
221 lpszStr = CharNextA(lpszStr);
224 return NULL;
227 /*************************************************************************
228 * StrChrIW [SHLWAPI.@]
230 * See StrChrA.
232 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
234 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
236 if (lpszStr)
238 ch = toupperW(ch);
239 while (*lpszStr)
241 if (toupperW(*lpszStr) == ch)
242 return (LPWSTR)lpszStr;
243 lpszStr = CharNextW(lpszStr);
245 lpszStr = NULL;
247 return (LPWSTR)lpszStr;
250 /*************************************************************************
251 * StrCmpIW [SHLWAPI.@]
253 * Compare two strings, ignoring case.
255 * PARAMS
256 * lpszStr [I] First string to compare
257 * lpszComp [I] Second string to compare
259 * RETURNS
260 * An integer less than, equal to or greater than 0, indicating that
261 * lpszStr is less than, the same, or greater than lpszComp.
263 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
265 INT iRet;
267 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
269 iRet = strcmpiW(lpszStr, lpszComp);
270 return iRet < 0 ? -1 : iRet ? 1 : 0;
273 /*************************************************************************
274 * SHLWAPI_StrCmpNHelperA
276 * Internal helper for StrCmpNA/StrCmpNIA.
278 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
279 INT iLen,
280 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
282 if (!lpszStr)
284 if (!lpszComp)
285 return 0;
286 return 1;
288 else if (!lpszComp)
289 return -1;
291 while (iLen-- > 0)
293 int iDiff;
294 WORD ch1, ch2;
296 ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
297 ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
299 if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
300 return -1;
301 else if (iDiff > 0)
302 return 1;
303 else if (!*lpszStr && !*lpszComp)
304 return 0;
306 lpszStr = CharNextA(lpszStr);
307 lpszComp = CharNextA(lpszComp);
309 return 0;
312 /*************************************************************************
313 * StrCmpNA [SHLWAPI.@]
315 * Compare two strings, up to a maximum length.
317 * PARAMS
318 * lpszStr [I] First string to compare
319 * lpszComp [I] Second string to compare
320 * iLen [I] Maximum number of chars to compare.
322 * RETURNS
323 * An integer less than, equal to or greater than 0, indicating that
324 * lpszStr is less than, the same, or greater than lpszComp.
326 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
328 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
330 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
333 /*************************************************************************
334 * StrCmpNW [SHLWAPI.@]
336 * See StrCmpNA.
338 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
340 INT iRet;
342 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
344 iRet = strncmpW(lpszStr, lpszComp, iLen);
345 return iRet < 0 ? -1 : iRet ? 1 : 0;
348 /*************************************************************************
349 * StrCmpNIA [SHLWAPI.@]
351 * Compare two strings, up to a maximum length, ignoring case.
353 * PARAMS
354 * lpszStr [I] First string to compare
355 * lpszComp [I] Second string to compare
356 * iLen [I] Maximum number of chars to compare.
358 * RETURNS
359 * An integer less than, equal to or greater than 0, indicating that
360 * lpszStr is less than, the same, or greater than lpszComp.
362 * NOTES
363 * The Win32 version of this function is _completely_ broken for cases
364 * where iLen is greater than the length of lpszComp. Examples:
366 * StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
367 * StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
368 * StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
370 * This implementation behaves correctly, since it is unlikely any
371 * applications actually rely on this function being broken.
373 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
375 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
377 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
380 /*************************************************************************
381 * StrCmpNIW [SHLWAPI.@]
383 * See StrCmpNIA.
385 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
387 INT iRet;
389 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
391 iRet = strncmpiW(lpszStr, lpszComp, iLen);
392 return iRet < 0 ? -1 : iRet ? 1 : 0;
395 /*************************************************************************
396 * StrCmpW [SHLWAPI.@]
398 * Compare two strings.
400 * PARAMS
401 * lpszStr [I] First string to compare
402 * lpszComp [I] Second string to compare
404 * RETURNS
405 * An integer less than, equal to or greater than 0, indicating that
406 * lpszStr is less than, the same, or greater than lpszComp.
408 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
410 INT iRet;
412 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
414 iRet = strcmpW(lpszStr, lpszComp);
415 return iRet < 0 ? -1 : iRet ? 1 : 0;
418 /*************************************************************************
419 * StrCatW [SHLWAPI.@]
421 * Concatanate two strings.
423 * PARAMS
424 * lpszStr [O] Initial string
425 * lpszSrc [I] String to concatanate
427 * RETURNS
428 * lpszStr.
430 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
432 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
434 strcatW(lpszStr, lpszSrc);
435 return lpszStr;
438 /*************************************************************************
439 * StrCpyW [SHLWAPI.@]
441 * Copy a string to another string.
443 * PARAMS
444 * lpszStr [O] Destination string
445 * lpszSrc [I] Source string
447 * RETURNS
448 * lpszStr.
450 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
452 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
454 strcpyW(lpszStr, lpszSrc);
455 return lpszStr;
458 /*************************************************************************
459 * StrCpyNW [SHLWAPI.@]
461 * Copy a string to another string, up to a maximum number of characters.
463 * PARAMS
464 * lpszStr [O] Destination string
465 * lpszSrc [I] Source string
466 * iLen [I] Maximum number of chars to copy
468 * RETURNS
469 * lpszStr.
471 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
473 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
475 lstrcpynW(lpszStr, lpszSrc, iLen);
476 return lpszStr;
481 /*************************************************************************
482 * SHLWAPI_StrStrHelperA
484 * Internal implementation of StrStrA/StrStrIA
486 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
487 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
489 size_t iLen;
491 if (!lpszStr || !lpszSearch || !*lpszSearch)
492 return NULL;
494 iLen = strlen(lpszSearch);
496 while (*lpszStr)
498 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
499 return (LPSTR)lpszStr;
500 lpszStr = CharNextA(lpszStr);
502 return NULL;
505 /*************************************************************************
506 * SHLWAPI_StrStrHelperW
508 * Internal implementation of StrStrW/StrStrIW
510 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
511 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
513 int iLen;
515 if (!lpszStr || !lpszSearch || !*lpszSearch)
516 return NULL;
518 iLen = strlenW(lpszSearch);
520 while (*lpszStr)
522 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
523 return (LPWSTR)lpszStr;
524 lpszStr = CharNextW(lpszStr);
526 return NULL;
529 /*************************************************************************
530 * StrStrA [SHLWAPI.@]
532 * Find a substring within a string.
534 * PARAMS
535 * lpszStr [I] String to search in
536 * lpszSearch [I] String to look for
538 * RETURNS
539 * The start of lpszSearch within lpszStr, or NULL if not found.
541 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
543 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
545 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
548 /*************************************************************************
549 * StrStrW [SHLWAPI.@]
551 * See StrStrA.
553 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
555 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
557 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
560 /*************************************************************************
561 * StrRStrIA [SHLWAPI.@]
563 * Find the last occurence of a substring within a string.
565 * PARAMS
566 * lpszStr [I] String to search in
567 * lpszEnd [I] End of lpszStr
568 * lpszSearch [I] String to look for
570 * RETURNS
571 * The last occurence lpszSearch within lpszStr, or NULL if not found.
573 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
575 LPSTR lpszRet = NULL;
576 WORD ch1, ch2;
577 INT iLen;
579 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
581 if (!lpszStr || !lpszSearch || !*lpszSearch)
582 return NULL;
584 if (!lpszEnd)
585 lpszEnd = lpszStr + lstrlenA(lpszStr);
587 if (IsDBCSLeadByte(*lpszSearch))
588 ch1 = *lpszSearch << 8 | lpszSearch[1];
589 else
590 ch1 = *lpszSearch;
591 iLen = lstrlenA(lpszSearch);
593 while (lpszStr <= lpszEnd && *lpszStr)
595 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
596 if (!ChrCmpIA(ch1, ch2))
598 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
599 lpszRet = (LPSTR)lpszStr;
601 lpszStr = CharNextA(lpszStr);
603 return lpszRet;
606 /*************************************************************************
607 * StrRStrIW [SHLWAPI.@]
609 * See StrRStrIA.
611 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
613 LPWSTR lpszRet = NULL;
614 INT iLen;
616 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
618 if (!lpszStr || !lpszSearch || !*lpszSearch)
619 return NULL;
621 if (!lpszEnd)
622 lpszEnd = lpszStr + strlenW(lpszStr);
624 iLen = strlenW(lpszSearch);
626 while (lpszStr <= lpszEnd && *lpszStr)
628 if (!ChrCmpIA(*lpszSearch, *lpszStr))
630 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
631 lpszRet = (LPWSTR)lpszStr;
633 lpszStr = CharNextW(lpszStr);
635 return lpszRet;
638 /*************************************************************************
639 * StrStrIA [SHLWAPI.@]
641 * Find a substring within a string, ignoring case.
643 * PARAMS
644 * lpszStr [I] String to search in
645 * lpszSearch [I] String to look for
647 * RETURNS
648 * The start of lpszSearch within lpszStr, or NULL if not found.
650 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
652 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
654 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
657 /*************************************************************************
658 * StrStrIW [SHLWAPI.@]
660 * See StrStrIA.
662 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
664 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
666 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
669 /*************************************************************************
670 * StrToIntA [SHLWAPI.@]
672 * Read an integer from a string.
674 * PARAMS
675 * lpszStr [I] String to read integer from
677 * RETURNS
678 * The integer value represented by the string, or 0 if no integer is
679 * present.
681 * NOTES
682 * No leading space is allowed before the number, although a leading '-' is.
684 int WINAPI StrToIntA(LPCSTR lpszStr)
686 int iRet = 0;
688 TRACE("(%s)\n", debugstr_a(lpszStr));
690 if (!lpszStr)
692 WARN("Invalid lpszStr would crash under Win32!\n");
693 return 0;
696 if (*lpszStr == '-' || isdigit(*lpszStr))
697 StrToIntExA(lpszStr, 0, &iRet);
698 return iRet;
701 /*************************************************************************
702 * StrToIntW [SHLWAPI.@]
704 * See StrToIntA.
706 int WINAPI StrToIntW(LPCWSTR lpszStr)
708 int iRet = 0;
710 TRACE("(%s)\n", debugstr_w(lpszStr));
712 if (!lpszStr)
714 WARN("Invalid lpszStr would crash under Win32!\n");
715 return 0;
718 if (*lpszStr == '-' || isdigitW(*lpszStr))
719 StrToIntExW(lpszStr, 0, &iRet);
720 return iRet;
723 /*************************************************************************
724 * StrToIntExA [SHLWAPI.@]
726 * Read an integer from a string.
728 * PARAMS
729 * lpszStr [I] String to read integer from
730 * dwFlags [I] Flags controlling the conversion
731 * lpiRet [O] Destination for read integer.
733 * RETURNS
734 * Success: TRUE. lpiRet contains the integer value represented by the string.
735 * Failure: FALSE, if the string is invalid, or no number is present.
737 * NOTES
738 * Leading whitespace, '-' and '+' are allowed before the number. If
739 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
740 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
741 * the string is treated as a decimal string. A leading '-' is ignored for
742 * hexidecimal numbers.
744 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
746 BOOL bNegative = FALSE;
747 int iRet = 0;
749 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
751 if (!lpszStr || !lpiRet)
753 WARN("Invalid parameter would crash under Win32!\n");
754 return FALSE;
756 if (dwFlags > STIF_SUPPORT_HEX)
758 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
761 /* Skip leading space, '+', '-' */
762 while (isspace(*lpszStr))
763 lpszStr = CharNextA(lpszStr);
765 if (*lpszStr == '-')
767 bNegative = TRUE;
768 lpszStr++;
770 else if (*lpszStr == '+')
771 lpszStr++;
773 if (dwFlags & STIF_SUPPORT_HEX &&
774 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
776 /* Read hex number */
777 lpszStr += 2;
779 if (!isxdigit(*lpszStr))
780 return FALSE;
782 while (isxdigit(*lpszStr))
784 iRet = iRet * 16;
785 if (isdigit(*lpszStr))
786 iRet += (*lpszStr - '0');
787 else
788 iRet += 10 + (tolower(*lpszStr) - 'a');
789 lpszStr++;
791 *lpiRet = iRet;
792 return TRUE;
795 /* Read decimal number */
796 if (!isdigit(*lpszStr))
797 return FALSE;
799 while (isdigit(*lpszStr))
801 iRet = iRet * 10;
802 iRet += (*lpszStr - '0');
803 lpszStr++;
805 *lpiRet = bNegative ? -iRet : iRet;
806 return TRUE;
809 /*************************************************************************
810 * StrToIntExW [SHLWAPI.@]
812 * See StrToIntExA.
814 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
816 BOOL bNegative = FALSE;
817 int iRet = 0;
819 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
821 if (!lpszStr || !lpiRet)
823 WARN("Invalid parameter would crash under Win32!\n");
824 return FALSE;
826 if (dwFlags > STIF_SUPPORT_HEX)
828 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
831 /* Skip leading space, '+', '-' */
832 while (isspaceW(*lpszStr))
833 lpszStr = CharNextW(lpszStr);
835 if (*lpszStr == '-')
837 bNegative = TRUE;
838 lpszStr++;
840 else if (*lpszStr == '+')
841 lpszStr++;
843 if (dwFlags & STIF_SUPPORT_HEX &&
844 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
846 /* Read hex number */
847 lpszStr += 2;
849 if (!isxdigitW(*lpszStr))
850 return FALSE;
852 while (isxdigitW(*lpszStr))
854 iRet = iRet * 16;
855 if (isdigitW(*lpszStr))
856 iRet += (*lpszStr - '0');
857 else
858 iRet += 10 + (tolowerW(*lpszStr) - 'a');
859 lpszStr++;
861 *lpiRet = iRet;
862 return TRUE;
865 /* Read decimal number */
866 if (!isdigitW(*lpszStr))
867 return FALSE;
869 while (isdigitW(*lpszStr))
871 iRet = iRet * 10;
872 iRet += (*lpszStr - '0');
873 lpszStr++;
875 *lpiRet = bNegative ? -iRet : iRet;
876 return TRUE;
879 /*************************************************************************
880 * StrDupA [SHLWAPI.@]
882 * Duplicate a string.
884 * PARAMS
885 * lpszStr [I] String to duplicate.
887 * RETURNS
888 * Success: A pointer to a new string containing the contents of lpszStr
889 * Failure: NULL, if memory cannot be allocated
891 * NOTES
892 * The string memory is allocated with LocalAlloc, and so should be released
893 * by calling LocalFree.
895 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
897 int iLen;
898 LPSTR lpszRet;
900 TRACE("(%s)\n",debugstr_a(lpszStr));
902 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
903 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
905 if (lpszRet)
907 if (lpszStr)
908 memcpy(lpszRet, lpszStr, iLen);
909 else
910 *lpszRet = '\0';
912 return lpszRet;
915 /*************************************************************************
916 * StrDupW [SHLWAPI.@]
918 * See StrDupA.
920 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
922 int iLen;
923 LPWSTR lpszRet;
925 TRACE("(%s)\n",debugstr_w(lpszStr));
927 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
928 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
930 if (lpszRet)
932 if (lpszStr)
933 memcpy(lpszRet, lpszStr, iLen);
934 else
935 *lpszRet = '\0';
937 return lpszRet;
940 /*************************************************************************
941 * SHLWAPI_StrSpnHelperA
943 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
945 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
946 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
947 BOOL bInvert)
949 LPCSTR lpszRead = lpszStr;
950 if (lpszStr && *lpszStr && lpszMatch)
952 while (*lpszRead)
954 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
956 if (!bInvert && !lpszTest)
957 break;
958 if (bInvert && lpszTest)
959 break;
960 lpszRead = CharNextA(lpszRead);
963 return lpszRead - lpszStr;
966 /*************************************************************************
967 * SHLWAPI_StrSpnHelperW
969 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
971 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
972 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
973 BOOL bInvert)
975 LPCWSTR lpszRead = lpszStr;
976 if (lpszStr && *lpszStr && lpszMatch)
978 while (*lpszRead)
980 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
982 if (!bInvert && !lpszTest)
983 break;
984 if (bInvert && lpszTest)
985 break;
986 lpszRead = CharNextW(lpszRead);
989 return lpszRead - lpszStr;
992 /*************************************************************************
993 * StrSpnA [SHLWAPI.@]
995 * Find the length of the start of a string that contains only certain
996 * characters.
998 * PARAMS
999 * lpszStr [I] String to search
1000 * lpszMatch [I] Characters that can be in the substring
1002 * RETURNS
1003 * The length of the part of lpszStr containing only chars from lpszMatch,
1004 * or 0 if any parameter is invalid.
1006 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1008 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1010 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1013 /*************************************************************************
1014 * StrSpnW [SHLWAPI.@]
1016 * See StrSpnA.
1018 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1020 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1022 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1025 /*************************************************************************
1026 * StrCSpnA [SHLWAPI.@]
1028 * Find the length of the start of a string that does not contain certain
1029 * characters.
1031 * PARAMS
1032 * lpszStr [I] String to search
1033 * lpszMatch [I] Characters that cannot be in the substring
1035 * RETURNS
1036 * The length of the part of lpszStr containing only chars not in lpszMatch,
1037 * or 0 if any parameter is invalid.
1039 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1041 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1043 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1046 /*************************************************************************
1047 * StrCSpnW [SHLWAPI.@]
1049 * See StrCSpnA.
1051 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1053 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1055 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1058 /*************************************************************************
1059 * StrCSpnIA [SHLWAPI.@]
1061 * Find the length of the start of a string that does not contain certain
1062 * characters, ignoring case.
1064 * PARAMS
1065 * lpszStr [I] String to search
1066 * lpszMatch [I] Characters that cannot be in the substring
1068 * RETURNS
1069 * The length of the part of lpszStr containing only chars not in lpszMatch,
1070 * or 0 if any parameter is invalid.
1072 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1074 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1076 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1079 /*************************************************************************
1080 * StrCSpnIW [SHLWAPI.@]
1082 * See StrCSpnIA.
1084 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1086 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1088 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1091 /*************************************************************************
1092 * StrPBrkA [SHLWAPI.@]
1094 * Search a string for any of a group of characters.
1096 * PARAMS
1097 * lpszStr [I] String to search
1098 * lpszMatch [I] Characters to match
1100 * RETURNS
1101 * A pointer to the first matching character in lpszStr, or NULL if no
1102 * match was found.
1104 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1106 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1108 if (lpszStr && lpszMatch && *lpszMatch)
1110 while (*lpszStr)
1112 if (StrChrA(lpszMatch, *lpszStr))
1113 return (LPSTR)lpszStr;
1114 lpszStr = CharNextA(lpszStr);
1117 return NULL;
1120 /*************************************************************************
1121 * StrPBrkW [SHLWAPI.@]
1123 * See StrPBrkA.
1125 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1127 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1129 if (lpszStr && lpszMatch && *lpszMatch)
1131 while (*lpszStr);
1133 if (StrChrW(lpszMatch, *lpszStr))
1134 return (LPWSTR)lpszStr;
1135 lpszStr = CharNextW(lpszStr);
1136 } while (*lpszStr);
1138 return NULL;
1141 /*************************************************************************
1142 * SHLWAPI_StrRChrHelperA
1144 * Internal implementation of StrRChrA/StrRChrIA.
1146 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1147 LPCSTR lpszEnd, WORD ch,
1148 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1150 LPCSTR lpszRet = NULL;
1152 if (lpszStr)
1154 WORD ch2;
1156 if (!lpszEnd)
1157 lpszEnd = lpszStr + lstrlenA(lpszStr);
1159 while (*lpszStr && lpszStr <= lpszEnd)
1161 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1163 if (!pChrCmpFn(ch, ch2))
1164 lpszRet = lpszStr;
1165 lpszStr = CharNextA(lpszStr);
1168 return (LPSTR)lpszRet;
1171 /*************************************************************************
1172 * SHLWAPI_StrRChrHelperW
1174 * Internal implementation of StrRChrW/StrRChrIW.
1176 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1177 LPCWSTR lpszEnd, WCHAR ch,
1178 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1180 LPCWSTR lpszRet = NULL;
1182 if (lpszStr)
1184 if (!lpszEnd)
1185 lpszEnd = lpszStr + strlenW(lpszStr);
1187 while (*lpszStr && lpszStr <= lpszEnd)
1189 if (!pChrCmpFn(ch, *lpszStr))
1190 lpszRet = lpszStr;
1191 lpszStr = CharNextW(lpszStr);
1194 return (LPWSTR)lpszRet;
1197 /**************************************************************************
1198 * StrRChrA [SHLWAPI.@]
1200 * Find the last occurence of a character in string.
1202 * PARAMS
1203 * lpszStr [I] String to search in
1204 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1205 * ch [I] Character to search for.
1207 * RETURNS
1208 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1209 * or NULL if not found.
1210 * Failure: NULL, if any arguments are invalid.
1212 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1214 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1216 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1219 /**************************************************************************
1220 * StrRChrW [SHLWAPI.@]
1222 * See StrRChrA.
1224 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1226 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1228 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1231 /**************************************************************************
1232 * StrRChrIA [SHLWAPI.@]
1234 * Find the last occurence of a character in string, ignoring case.
1236 * PARAMS
1237 * lpszStr [I] String to search in
1238 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1239 * ch [I] Character to search for.
1241 * RETURNS
1242 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1243 * or NULL if not found.
1244 * Failure: NULL, if any arguments are invalid.
1246 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1248 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1250 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1253 /**************************************************************************
1254 * StrRChrIW [SHLWAPI.@]
1256 * See StrRChrIA.
1258 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1260 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1262 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1265 /*************************************************************************
1266 * StrCatBuffA [SHLWAPI.@]
1268 * Concatenate two strings together.
1270 * PARAMS
1271 * lpszStr [O] String to concatenate to
1272 * lpszCat [I] String to add to lpszCat
1273 * cchMax [I] Maximum number of characters for the whole string
1275 * RETURNS
1276 * lpszStr.
1278 * NOTES
1279 * cchMax dtermines the number of characters in the final length of the
1280 * string, not the number appended to lpszStr from lpszCat.
1282 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1284 INT iLen;
1286 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1288 if (!lpszStr)
1290 WARN("Invalid lpszStr would crash under Win32!\n");
1291 return NULL;
1294 iLen = strlen(lpszStr);
1295 cchMax -= iLen;
1297 if (cchMax > 0)
1298 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1299 return lpszStr;
1302 /*************************************************************************
1303 * StrCatBuffW [SHLWAPI.@]
1305 * See StrCatBuffA.
1307 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1309 INT iLen;
1311 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1313 if (!lpszStr)
1315 WARN("Invalid lpszStr would crash under Win32!\n");
1316 return NULL;
1319 iLen = strlenW(lpszStr);
1320 cchMax -= iLen;
1322 if (cchMax > 0)
1323 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1324 return lpszStr;
1327 /*************************************************************************
1328 * StrRetToBufA [SHLWAPI.@]
1330 * Convert a STRRET to a normal string.
1332 * PARAMS
1333 * lpStrRet [O] STRRET to convert
1334 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1335 * lpszDest [O] Destination for normal string
1336 * dwLen [I] Length of lpszDest
1338 * RETURNS
1339 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1340 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1341 * CoTaskMemFree and its type set to STRRET_CSTRA.
1342 * Failure: E_FAIL, if any parameters are invalid.
1344 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1346 /* NOTE:
1347 * This routine is identical to that in dlls/shell32/shellstring.c.
1348 * It was duplicated because not every version of Shlwapi.dll exports
1349 * StrRetToBufA. If you change one routine, change them both.
1351 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1353 if (!src)
1355 WARN("Invalid lpStrRet would crash under Win32!\n");
1356 if (dest)
1357 *dest = '\0';
1358 return E_FAIL;
1361 if (!dest || !len)
1362 return E_FAIL;
1364 *dest = '\0';
1366 switch (src->uType)
1368 case STRRET_WSTR:
1369 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1370 CoTaskMemFree(src->u.pOleStr);
1371 break;
1373 case STRRET_CSTR:
1374 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1375 break;
1377 case STRRET_OFFSET:
1378 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1379 break;
1381 default:
1382 FIXME("unknown type!\n");
1383 return FALSE;
1385 return S_OK;
1388 /*************************************************************************
1389 * StrRetToBufW [SHLWAPI.@]
1391 * See StrRetToBufA.
1393 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1395 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1397 if (!src)
1399 WARN("Invalid lpStrRet would crash under Win32!\n");
1400 if (dest)
1401 *dest = '\0';
1402 return E_FAIL;
1405 if (!dest || !len)
1406 return E_FAIL;
1408 *dest = '\0';
1410 switch (src->uType)
1412 case STRRET_WSTR:
1413 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1414 CoTaskMemFree(src->u.pOleStr);
1415 break;
1417 case STRRET_CSTR:
1418 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1419 dest[len-1] = 0;
1420 break;
1422 case STRRET_OFFSET:
1423 if (pidl)
1425 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1426 dest, len ) && len)
1427 dest[len-1] = 0;
1429 break;
1431 default:
1432 FIXME("unknown type!\n");
1433 return FALSE;
1435 return S_OK;
1438 /*************************************************************************
1439 * StrRetToStrA [SHLWAPI.@]
1441 * converts a STRRET to a normal string
1443 HRESULT WINAPI StrRetToStrA(LPSTRRET pstr, const ITEMIDLIST * pidl, LPSTR* ppszName)
1445 HRESULT ret = E_FAIL;
1447 switch (pstr->uType) {
1448 case STRRET_WSTR:
1449 ret = _SHStrDupAW(pstr->u.pOleStr, ppszName);
1450 CoTaskMemFree(pstr->u.pOleStr);
1451 break;
1453 case STRRET_CSTR:
1454 ret = _SHStrDupAA(pstr->u.cStr, ppszName);
1455 break;
1457 case STRRET_OFFSET:
1458 ret = _SHStrDupAA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1459 break;
1461 default:
1462 *ppszName = NULL;
1464 return ret;
1467 /*************************************************************************
1468 * StrRetToStrW [SHLWAPI.@]
1470 * converts a STRRET to a normal string
1472 HRESULT WINAPI StrRetToStrW(LPSTRRET pstr, const ITEMIDLIST * pidl, LPWSTR* ppszName)
1474 HRESULT ret = E_FAIL;
1476 switch (pstr->uType) {
1477 case STRRET_WSTR:
1478 ret = SHStrDupW(pstr->u.pOleStr, ppszName);
1479 CoTaskMemFree(pstr->u.pOleStr);
1480 break;
1482 case STRRET_CSTR:
1483 ret = SHStrDupA(pstr->u.cStr, ppszName);
1484 break;
1486 case STRRET_OFFSET:
1487 ret = SHStrDupA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1488 break;
1490 default:
1491 *ppszName = NULL;
1493 return ret;
1496 /*************************************************************************
1497 * StrFormatByteSizeA [SHLWAPI.@]
1499 LPSTR WINAPI StrFormatByteSizeA ( DWORD dw, LPSTR pszBuf, UINT cchBuf )
1500 { char buf[64];
1501 TRACE("%lx %p %i\n", dw, pszBuf, cchBuf);
1502 if ( dw<1024L )
1503 { sprintf (buf,"%ld bytes", dw);
1505 else if ( dw<1048576L)
1506 { sprintf (buf,"%3.1f KB", (FLOAT)dw/1024);
1508 else if ( dw < 1073741824L)
1509 { sprintf (buf,"%3.1f MB", (FLOAT)dw/1048576L);
1511 else
1512 { sprintf (buf,"%3.1f GB", (FLOAT)dw/1073741824L);
1514 lstrcpynA (pszBuf, buf, cchBuf);
1515 return pszBuf;
1518 /*************************************************************************
1519 * StrFormatByteSizeW [SHLWAPI.@]
1521 LPWSTR WINAPI StrFormatByteSizeW ( DWORD dw, LPWSTR pszBuf, UINT cchBuf )
1523 char buf[64];
1524 StrFormatByteSizeA( dw, buf, sizeof(buf) );
1525 if (!MultiByteToWideChar( CP_ACP, 0, buf, -1, pszBuf, cchBuf ) && cchBuf)
1526 pszBuf[cchBuf-1] = 0;
1527 return pszBuf;
1530 /*************************************************************************
1531 * StrFormatKBSizeA [SHLWAPI.@]
1533 * Create a formatted string containing a byte count in Kilobytes.
1535 * PARAMS
1536 * llBytes [I] Byte size to format
1537 * lpszDest [I] Destination for formatted string
1538 * cchMax [I] Size of lpszDest
1540 * RETURNS
1541 * lpszDest.
1543 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1545 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1546 LONGLONG ulKB = (llBytes + 1023) >> 10;
1548 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1550 *szOut-- = '\0';
1551 *szOut-- = 'B';
1552 *szOut-- = 'K';
1553 *szOut-- = ' ';
1557 LONGLONG ulNextDigit = ulKB % 10;
1558 *szOut-- = '0' + ulNextDigit;
1559 ulKB = (ulKB - ulNextDigit) / 10;
1560 } while (ulKB > 0);
1562 strncpy(lpszDest, szOut + 1, cchMax);
1563 return lpszDest;
1566 /*************************************************************************
1567 * StrFormatKBSizeW [SHLWAPI.@]
1569 * See StrFormatKBSizeA.
1571 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1573 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1574 LONGLONG ulKB = (llBytes + 1023) >> 10;
1576 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1578 *szOut-- = '\0';
1579 *szOut-- = 'B';
1580 *szOut-- = 'K';
1581 *szOut-- = ' ';
1585 LONGLONG ulNextDigit = ulKB % 10;
1586 *szOut-- = '0' + ulNextDigit;
1587 ulKB = (ulKB - ulNextDigit) / 10;
1588 } while (ulKB > 0);
1590 strncpyW(lpszDest, szOut + 1, cchMax);
1591 return lpszDest;
1594 /*************************************************************************
1595 * StrNCatA [SHLWAPI.@]
1597 * Concatenate two strings together.
1599 * PARAMS
1600 * lpszStr [O] String to concatenate to
1601 * lpszCat [I] String to add to lpszCat
1602 * cchMax [I] Maximum number of characters to concatenate
1604 * RETURNS
1605 * lpszStr.
1607 * NOTES
1608 * cchMax dtermines the number of characters that are appended to lpszStr,
1609 * not the total length of the string.
1611 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1613 LPSTR lpszRet = lpszStr;
1615 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1617 if (!lpszStr)
1619 WARN("Invalid lpszStr would crash under Win32!\n");
1620 return NULL;
1623 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1624 return lpszRet;
1627 /*************************************************************************
1628 * StrNCatW [SHLWAPI.@]
1630 * See StrNCatA.
1632 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1634 LPWSTR lpszRet = lpszStr;
1636 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1638 if (!lpszStr)
1640 WARN("Invalid lpszStr would crash under Win32\n");
1641 return NULL;
1644 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1645 return lpszRet;
1648 /*************************************************************************
1649 * StrTrimA [SHLWAPI.@]
1651 * Remove characters from the start and end of a string.
1653 * PARAMS
1654 * lpszStr [O] String to remove characters from
1655 * lpszTrim [I] Characters to remove from lpszStr
1657 * RETURNS
1658 * TRUE If lpszStr was valid and modified
1659 * FALSE Otherwise
1661 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1663 DWORD dwLen;
1664 LPSTR lpszRead = lpszStr;
1665 BOOL bRet = FALSE;
1667 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1669 if (lpszRead && *lpszRead)
1671 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1672 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1674 dwLen = strlen(lpszRead);
1676 if (lpszRead != lpszStr)
1678 memmove(lpszStr, lpszRead, dwLen + 1);
1679 bRet = TRUE;
1681 if (dwLen > 0)
1683 lpszRead = lpszStr + dwLen;
1684 while (StrChrA(lpszTrim, lpszRead[-1]))
1685 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1687 if (lpszRead != lpszStr + dwLen)
1689 *lpszRead = '\0';
1690 bRet = TRUE;
1694 return bRet;
1697 /*************************************************************************
1698 * StrTrimW [SHLWAPI.@]
1700 * See StrTrimA.
1702 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1704 DWORD dwLen;
1705 LPWSTR lpszRead = lpszStr;
1706 BOOL bRet = FALSE;
1708 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1710 if (lpszRead && *lpszRead)
1712 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1713 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1715 dwLen = strlenW(lpszRead);
1717 if (lpszRead != lpszStr)
1719 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1720 bRet = TRUE;
1722 if (dwLen > 0)
1724 lpszRead = lpszStr + dwLen;
1725 while (StrChrW(lpszTrim, lpszRead[-1]))
1726 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1728 if (lpszRead != lpszStr + dwLen)
1730 *lpszRead = '\0';
1731 bRet = TRUE;
1735 return bRet;
1738 /*************************************************************************
1739 * _SHStrDupA [INTERNAL]
1741 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1743 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1745 HRESULT hr;
1746 int len = 0;
1748 if (src) {
1749 len = lstrlenA(src);
1750 *dest = CoTaskMemAlloc(len);
1751 } else {
1752 *dest = NULL;
1755 if (*dest) {
1756 lstrcpynA(*dest,src, len);
1757 hr = S_OK;
1758 } else {
1759 hr = E_OUTOFMEMORY;
1762 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1763 return hr;
1766 /*************************************************************************
1767 * SHStrDupA
1769 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc.
1771 * PARAMS
1772 * lpszStr [I] String to copy
1773 * lppszDest [O] Destination for the new string copy
1775 * RETURNS
1776 * Success: S_OK. lppszDest contains the new string in Unicode format.
1777 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1778 * fails.
1780 HRESULT WINAPI SHStrDupA(LPCSTR src, LPWSTR * dest)
1782 HRESULT hr;
1783 int len = 0;
1785 if (src) {
1786 len = (MultiByteToWideChar(0,0,src,-1,0,0) + 1)* sizeof(WCHAR);
1787 *dest = CoTaskMemAlloc(len);
1788 } else {
1789 *dest = NULL;
1792 if (*dest) {
1793 MultiByteToWideChar(0,0,src,-1,*dest,len);
1794 hr = S_OK;
1795 } else {
1796 hr = E_OUTOFMEMORY;
1799 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1800 return hr;
1803 /*************************************************************************
1804 * _SHStrDupAW [INTERNAL]
1806 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1808 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1810 HRESULT hr;
1811 int len = 0;
1813 if (src) {
1814 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1815 *dest = CoTaskMemAlloc(len);
1816 } else {
1817 *dest = NULL;
1820 if (*dest) {
1821 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1822 hr = S_OK;
1823 } else {
1824 hr = E_OUTOFMEMORY;
1827 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1828 return hr;
1831 /*************************************************************************
1832 * SHStrDupW
1834 * See SHStrDupA.
1836 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1838 HRESULT hr;
1839 int len = 0;
1841 if (src) {
1842 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1843 *dest = CoTaskMemAlloc(len);
1844 } else {
1845 *dest = NULL;
1848 if (*dest) {
1849 memcpy(*dest, src, len);
1850 hr = S_OK;
1851 } else {
1852 hr = E_OUTOFMEMORY;
1855 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1856 return hr;
1859 /*************************************************************************
1860 * SHLWAPI_WriteReverseNum
1862 * Internal helper for SHLWAPI_WriteTimeClass.
1864 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1866 *lpszOut-- = '\0';
1868 /* Write a decimal number to a string, backwards */
1871 DWORD dwNextDigit = dwNum % 10;
1872 *lpszOut-- = '0' + dwNextDigit;
1873 dwNum = (dwNum - dwNextDigit) / 10;
1874 } while (dwNum > 0);
1876 return lpszOut;
1879 /*************************************************************************
1880 * SHLWAPI_FormatSignificant
1882 * Internal helper for SHLWAPI_WriteTimeClass.
1884 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1886 /* Zero non significant digits, return remaining significant digits */
1887 while (*lpszNum)
1889 lpszNum++;
1890 if (--dwDigits == 0)
1892 while (*lpszNum)
1893 *lpszNum++ = '0';
1894 return 0;
1897 return dwDigits;
1900 /*************************************************************************
1901 * SHLWAPI_WriteTimeClass
1903 * Internal helper for StrFromTimeIntervalW.
1905 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1906 LPCWSTR lpszClass, int iDigits)
1908 WCHAR szBuff[64], *szOut = szBuff + 32;
1910 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1911 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1912 *szOut = ' ';
1913 strcpyW(szBuff + 32, lpszClass);
1914 strcatW(lpszOut, szOut);
1915 return iDigits;
1918 /*************************************************************************
1919 * StrFromTimeIntervalA [SHLWAPI.@]
1921 * Format a millisecond time interval into a string
1923 * PARAMS
1924 * lpszStr [O] Output buffer for formatted time interval
1925 * cchMax [I] Size of lpszStr
1926 * dwMS [I] Number of milliseconds
1927 * iDigits [I] Number of digits to print
1929 * RETURNS
1930 * The length of the formatted string, or 0 if any parameter is invalid.
1932 * NOTES
1933 * This implementation mimics the Win32 behaviour of always writing a leading
1934 * space before the time interval begins.
1935 * iDigits is used to provide approximate times if accuracy is not important.
1936 * This number of digits will be written of the first non-zero time class
1937 * (hours/minutes/seconds). If this does not complete the time classification,
1938 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1939 * If there are digits remaining following the writing of a time class, the
1940 * next time class will be written.
1941 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1942 * following will result from the given values of iDigits:
1944 * iDigits 1 2 3 4 5 ...
1945 * lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1947 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1948 int iDigits)
1950 INT iRet = 0;
1952 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1954 if (lpszStr && cchMax)
1956 WCHAR szBuff[128];
1957 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1958 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1960 return iRet;
1964 /*************************************************************************
1965 * StrFromTimeIntervalW [SHLWAPI.@]
1967 * See StrFromTimeIntervalA.
1969 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1970 int iDigits)
1972 static const WCHAR szHr[] = {' ','h','r','\0'};
1973 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1974 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1975 INT iRet = 0;
1977 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1979 if (lpszStr && cchMax)
1981 WCHAR szCopy[128];
1982 DWORD dwHours, dwMinutes;
1984 if (!iDigits || cchMax == 1)
1986 *lpszStr = '\0';
1987 return 0;
1990 /* Calculate the time classes */
1991 dwMS = (dwMS + 500) / 1000;
1992 dwHours = dwMS / 3600;
1993 dwMS -= dwHours * 3600;
1994 dwMinutes = dwMS / 60;
1995 dwMS -= dwMinutes * 60;
1997 szCopy[0] = '\0';
1999 if (dwHours)
2000 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
2002 if (dwMinutes && iDigits)
2003 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
2005 if (iDigits) /* Always write seconds if we have significant digits */
2006 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
2008 strncpyW(lpszStr, szCopy, cchMax);
2009 iRet = strlenW(lpszStr);
2011 return iRet;
2014 /*************************************************************************
2015 * StrIsIntlEqualA [SHLWAPI.@]
2017 * Compare two strings.
2019 * PARAMS
2020 * bCase [I] Whether to compare case sensitively
2021 * lpszStr [I] First string to compare
2022 * lpszComp [I] Second string to compare
2023 * iLen [I] Length to compare
2025 * RETURNS
2026 * TRUE If the strings are equal.
2027 * FALSE Otherwise.
2029 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2030 int iLen)
2032 DWORD dwFlags = LOCALE_USE_CP_ACP;
2033 int iRet;
2035 TRACE("(%d,%s,%s,%d)\n", bCase,
2036 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2038 /* FIXME: These flags are undocumented and unknown by our CompareString.
2039 * We need defines for them.
2041 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2043 iRet = CompareStringA(GetThreadLocale(),
2044 dwFlags, lpszStr, iLen, lpszComp, iLen);
2046 if (!iRet)
2047 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2049 return iRet == 2 ? TRUE : FALSE;
2052 /*************************************************************************
2053 * StrIsIntlEqualW [SHLWAPI.@]
2055 * See StrIsIntlEqualA.
2057 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2058 int iLen)
2060 DWORD dwFlags;
2061 int iRet;
2063 TRACE("(%d,%s,%s,%d)\n", bCase,
2064 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2066 /* FIXME: These flags are undocumented and unknown by our CompareString.
2067 * We need defines for them.
2069 dwFlags = bCase ? 0x10000000 : 0x10000001;
2071 iRet = CompareStringW(GetThreadLocale(),
2072 dwFlags, lpszStr, iLen, lpszComp, iLen);
2074 if (!iRet)
2075 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2077 return iRet == 2 ? TRUE : FALSE;
2080 /*************************************************************************
2081 * @ [SHLWAPI.399]
2083 * Copy a string to another string, up to a maximum number of characters.
2085 * PARAMS
2086 * lpszDest [O] Destination string
2087 * lpszSrc [I] Source string
2088 * iLen [I] Maximum number of chars to copy
2090 * RETURNS
2091 * Success: A pointer to the last character written.
2092 * Failure: lpszDest, if any arguments are invalid.
2094 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2096 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2098 if (lpszDest && lpszSrc && iLen > 0)
2100 while ((iLen-- > 1) && *lpszSrc)
2101 *lpszDest++ = *lpszSrc++;
2102 if (iLen >= 0)
2103 *lpszDest = '\0';
2105 return lpszDest;
2108 /*************************************************************************
2109 * @ [SHLWAPI.400]
2111 * Unicode version of SHLWAPI_399.
2113 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2115 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2117 if (lpszDest && lpszSrc && iLen > 0)
2119 while ((iLen-- > 1) && *lpszSrc)
2120 *lpszDest++ = *lpszSrc++;
2121 if (iLen >= 0)
2122 *lpszDest = '\0';
2124 return lpszDest;