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 #define COM_NO_WINDOWS_H
24 #include "wine/port.h"
38 #define NO_SHLWAPI_STREAM
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
46 static HRESULT WINAPI
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
);
47 static HRESULT WINAPI
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
);
49 /*************************************************************************
50 * SHLWAPI_ChrCmpHelperA
52 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
55 * Both this function and its Unicode counterpart are very inneficient. To
56 * fix this, CompareString must be completely implemented and optimised
57 * first. Then the core character test can be taken out of that function and
58 * placed here, so that it need never be called at all. Until then, do not
59 * attempt to optimise this code unless you are willing to test that it
60 * still performs correctly.
62 static BOOL WINAPI
SHLWAPI_ChrCmpHelperA(WORD ch1
, WORD ch2
, DWORD dwFlags
)
64 char str1
[3], str2
[3];
66 str1
[0] = LOBYTE(ch1
);
67 if (IsDBCSLeadByte(ch1
))
69 str1
[1] = HIBYTE(ch1
);
75 str2
[0] = LOBYTE(ch2
);
76 if (IsDBCSLeadByte(ch2
))
78 str2
[1] = HIBYTE(ch2
);
84 return CompareStringA(GetThreadLocale(), dwFlags
, str1
, -1, str2
, -1) - 2;
87 /*************************************************************************
88 * SHLWAPI_ChrCmpHelperW
90 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
92 static BOOL WINAPI
SHLWAPI_ChrCmpHelperW(WCHAR ch1
, WCHAR ch2
, DWORD dwFlags
)
94 WCHAR str1
[2], str2
[2];
100 return CompareStringW(GetThreadLocale(), dwFlags
, str1
, 2, str2
, 2) - 2;
103 /*************************************************************************
106 * Internal helper function.
108 static BOOL WINAPI
SHLWAPI_ChrCmpA(WORD ch1
, WORD ch2
)
110 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, 0);
113 /*************************************************************************
114 * ChrCmpIA [SHLWAPI.385]
116 * Compare two characters, ignoring case.
119 * ch1 [I] First character to compare
120 * ch2 [I] Second character to compare
123 * FALSE, if the characters are equal.
124 * Non-zero otherwise.
126 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
128 TRACE("(%d,%d)\n", ch1
, ch2
);
130 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, NORM_IGNORECASE
);
133 /*************************************************************************
136 * Internal helper function.
138 static BOOL WINAPI
SHLWAPI_ChrCmpW(WCHAR ch1
, WCHAR ch2
)
140 return SHLWAPI_ChrCmpHelperW(ch1
, ch2
, 0);
143 /*************************************************************************
144 * ChrCmpIW [SHLWAPI.386]
148 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
150 return SHLWAPI_ChrCmpHelperW(ch1
, ch2
, NORM_IGNORECASE
);
153 /*************************************************************************
154 * StrChrA [SHLWAPI.@]
156 * Find a given character in a string.
159 * lpszStr [I] String to search in.
160 * ch [I] Character to search for.
163 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
165 * Failure: NULL, if any arguments are invalid.
167 LPSTR WINAPI
StrChrA(LPCSTR lpszStr
, WORD ch
)
169 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
175 if (!SHLWAPI_ChrCmpA(*lpszStr
, ch
))
176 return (LPSTR
)lpszStr
;
177 lpszStr
= CharNextA(lpszStr
);
183 /*************************************************************************
184 * StrChrW [SHLWAPI.@]
188 LPWSTR WINAPI
StrChrW(LPCWSTR lpszStr
, WCHAR ch
)
190 LPWSTR lpszRet
= NULL
;
192 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
195 lpszRet
= strchrW(lpszStr
, ch
);
199 /*************************************************************************
200 * StrChrIA [SHLWAPI.@]
202 * Find a given character in a string, ignoring case.
205 * lpszStr [I] String to search in.
206 * ch [I] Character to search for.
209 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
211 * Failure: NULL, if any arguments are invalid.
213 LPSTR WINAPI
StrChrIA(LPCSTR lpszStr
, WORD ch
)
215 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
221 if (!ChrCmpIA(*lpszStr
, ch
))
222 return (LPSTR
)lpszStr
;
223 lpszStr
= CharNextA(lpszStr
);
229 /*************************************************************************
230 * StrChrIW [SHLWAPI.@]
234 LPWSTR WINAPI
StrChrIW(LPCWSTR lpszStr
, WCHAR ch
)
236 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
243 if (toupperW(*lpszStr
) == ch
)
244 return (LPWSTR
)lpszStr
;
245 lpszStr
= CharNextW(lpszStr
);
249 return (LPWSTR
)lpszStr
;
252 /*************************************************************************
253 * StrCmpIW [SHLWAPI.@]
255 * Compare two strings, ignoring case.
258 * lpszStr [I] First string to compare
259 * lpszComp [I] Second string to compare
262 * An integer less than, equal to or greater than 0, indicating that
263 * lpszStr is less than, the same, or greater than lpszComp.
265 int WINAPI
StrCmpIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
269 TRACE("(%s,%s)\n", debugstr_w(lpszStr
),debugstr_w(lpszComp
));
271 iRet
= strcmpiW(lpszStr
, lpszComp
);
272 return iRet
< 0 ? -1 : iRet
? 1 : 0;
275 /*************************************************************************
276 * SHLWAPI_StrCmpNHelperA
278 * Internal helper for StrCmpNA/StrCmpNIA.
280 static INT WINAPI
SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr
, LPCSTR lpszComp
,
282 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
298 ch1
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
299 ch2
= IsDBCSLeadByte(*lpszComp
)? *lpszComp
<< 8 | lpszComp
[1] : *lpszComp
;
301 if ((iDiff
= pChrCmpFn(ch1
, ch2
)) < 0)
305 else if (!*lpszStr
&& !*lpszComp
)
308 lpszStr
= CharNextA(lpszStr
);
309 lpszComp
= CharNextA(lpszComp
);
314 /*************************************************************************
315 * StrCmpNA [SHLWAPI.@]
317 * Compare two strings, up to a maximum length.
320 * lpszStr [I] First string to compare
321 * lpszComp [I] Second string to compare
322 * iLen [I] Maximum number of chars to compare.
325 * An integer less than, equal to or greater than 0, indicating that
326 * lpszStr is less than, the same, or greater than lpszComp.
328 INT WINAPI
StrCmpNA(LPCSTR lpszStr
, LPCSTR lpszComp
, INT iLen
)
330 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
332 return SHLWAPI_StrCmpNHelperA(lpszStr
, lpszComp
, iLen
, SHLWAPI_ChrCmpA
);
335 /*************************************************************************
336 * StrCmpNW [SHLWAPI.@]
340 INT WINAPI
StrCmpNW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, INT iLen
)
344 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
346 iRet
= strncmpW(lpszStr
, lpszComp
, iLen
);
347 return iRet
< 0 ? -1 : iRet
? 1 : 0;
350 /*************************************************************************
351 * StrCmpNIA [SHLWAPI.@]
353 * Compare two strings, up to a maximum length, ignoring case.
356 * lpszStr [I] First string to compare
357 * lpszComp [I] Second string to compare
358 * iLen [I] Maximum number of chars to compare.
361 * An integer less than, equal to or greater than 0, indicating that
362 * lpszStr is less than, the same, or greater than lpszComp.
365 * The Win32 version of this function is _completely_ broken for cases
366 * where iLen is greater than the length of lpszComp. Examples:
368 * StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
369 * StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
370 * StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
372 * This implementation behaves correctly, since it is unlikely any
373 * applications actually rely on this function being broken.
375 int WINAPI
StrCmpNIA(LPCSTR lpszStr
, LPCSTR lpszComp
, int iLen
)
377 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
379 return SHLWAPI_StrCmpNHelperA(lpszStr
, lpszComp
, iLen
, ChrCmpIA
);
382 /*************************************************************************
383 * StrCmpNIW [SHLWAPI.@]
387 INT WINAPI
StrCmpNIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, int iLen
)
391 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
393 iRet
= strncmpiW(lpszStr
, lpszComp
, iLen
);
394 return iRet
< 0 ? -1 : iRet
? 1 : 0;
397 /*************************************************************************
398 * StrCmpW [SHLWAPI.@]
400 * Compare two strings.
403 * lpszStr [I] First string to compare
404 * lpszComp [I] Second string to compare
407 * An integer less than, equal to or greater than 0, indicating that
408 * lpszStr is less than, the same, or greater than lpszComp.
410 int WINAPI
StrCmpW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
414 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
416 iRet
= strcmpW(lpszStr
, lpszComp
);
417 return iRet
< 0 ? -1 : iRet
? 1 : 0;
420 /*************************************************************************
421 * StrCatW [SHLWAPI.@]
423 * Concatanate two strings.
426 * lpszStr [O] Initial string
427 * lpszSrc [I] String to concatanate
432 LPWSTR WINAPI
StrCatW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
434 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSrc
));
436 strcatW(lpszStr
, lpszSrc
);
440 /*************************************************************************
441 * StrCpyW [SHLWAPI.@]
443 * Copy a string to another string.
446 * lpszStr [O] Destination string
447 * lpszSrc [I] Source string
452 LPWSTR WINAPI
StrCpyW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
454 TRACE("(%p,%s)\n", lpszStr
, debugstr_w(lpszSrc
));
456 strcpyW(lpszStr
, lpszSrc
);
460 /*************************************************************************
461 * StrCpyNW [SHLWAPI.@]
463 * Copy a string to another string, up to a maximum number of characters.
466 * lpszStr [O] Destination string
467 * lpszSrc [I] Source string
468 * iLen [I] Maximum number of chars to copy
473 LPWSTR WINAPI
StrCpyNW(LPWSTR lpszStr
, LPCWSTR lpszSrc
, int iLen
)
475 TRACE("(%p,%s,%i)\n", lpszStr
, debugstr_w(lpszSrc
), iLen
);
477 lstrcpynW(lpszStr
, lpszSrc
, iLen
);
483 /*************************************************************************
484 * SHLWAPI_StrStrHelperA
486 * Internal implementation of StrStrA/StrStrIA
488 static LPSTR WINAPI
SHLWAPI_StrStrHelperA(LPCSTR lpszStr
, LPCSTR lpszSearch
,
489 int (*pStrCmpFn
)(LPCSTR
,LPCSTR
,size_t))
493 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
496 iLen
= strlen(lpszSearch
);
500 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
501 return (LPSTR
)lpszStr
;
502 lpszStr
= CharNextA(lpszStr
);
507 /*************************************************************************
508 * SHLWAPI_StrStrHelperW
510 * Internal implementation of StrStrW/StrStrIW
512 static LPWSTR WINAPI
SHLWAPI_StrStrHelperW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
,
513 int (*pStrCmpFn
)(LPCWSTR
,LPCWSTR
,int))
517 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
520 iLen
= strlenW(lpszSearch
);
524 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
525 return (LPWSTR
)lpszStr
;
526 lpszStr
= CharNextW(lpszStr
);
531 /*************************************************************************
532 * StrStrA [SHLWAPI.@]
534 * Find a substring within a string.
537 * lpszStr [I] String to search in
538 * lpszSearch [I] String to look for
541 * The start of lpszSearch within lpszStr, or NULL if not found.
543 LPSTR WINAPI
StrStrA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
545 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
547 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, strncmp
);
550 /*************************************************************************
551 * StrStrW [SHLWAPI.@]
555 LPWSTR WINAPI
StrStrW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
557 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
559 return SHLWAPI_StrStrHelperW(lpszStr
, lpszSearch
, strncmpW
);
562 /*************************************************************************
563 * StrRStrIA [SHLWAPI.@]
565 * Find the last occurence of a substring within a string.
568 * lpszStr [I] String to search in
569 * lpszEnd [I] End of lpszStr
570 * lpszSearch [I] String to look for
573 * The last occurence lpszSearch within lpszStr, or NULL if not found.
575 LPSTR WINAPI
StrRStrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, LPCSTR lpszSearch
)
577 LPSTR lpszRet
= NULL
;
581 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
583 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
587 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
589 if (IsDBCSLeadByte(*lpszSearch
))
590 ch1
= *lpszSearch
<< 8 | lpszSearch
[1];
593 iLen
= lstrlenA(lpszSearch
);
595 while (lpszStr
<= lpszEnd
&& *lpszStr
)
597 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
598 if (!ChrCmpIA(ch1
, ch2
))
600 if (!StrCmpNIA(lpszStr
, lpszSearch
, iLen
))
601 lpszRet
= (LPSTR
)lpszStr
;
603 lpszStr
= CharNextA(lpszStr
);
608 /*************************************************************************
609 * StrRStrIW [SHLWAPI.@]
613 LPWSTR WINAPI
StrRStrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, LPCWSTR lpszSearch
)
615 LPWSTR lpszRet
= NULL
;
618 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
620 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
624 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
626 iLen
= strlenW(lpszSearch
);
628 while (lpszStr
<= lpszEnd
&& *lpszStr
)
630 if (!ChrCmpIA(*lpszSearch
, *lpszStr
))
632 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
633 lpszRet
= (LPWSTR
)lpszStr
;
635 lpszStr
= CharNextW(lpszStr
);
640 /*************************************************************************
641 * StrStrIA [SHLWAPI.@]
643 * Find a substring within a string, ignoring case.
646 * lpszStr [I] String to search in
647 * lpszSearch [I] String to look for
650 * The start of lpszSearch within lpszStr, or NULL if not found.
652 LPSTR WINAPI
StrStrIA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
654 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
656 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, strncasecmp
);
659 /*************************************************************************
660 * StrStrIW [SHLWAPI.@]
664 LPWSTR WINAPI
StrStrIW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
666 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
668 return SHLWAPI_StrStrHelperW(lpszStr
, lpszSearch
, strncmpiW
);
671 /*************************************************************************
672 * StrToIntA [SHLWAPI.@]
674 * Read an integer from a string.
677 * lpszStr [I] String to read integer from
680 * The integer value represented by the string, or 0 if no integer is
684 * No leading space is allowed before the number, although a leading '-' is.
686 int WINAPI
StrToIntA(LPCSTR lpszStr
)
690 TRACE("(%s)\n", debugstr_a(lpszStr
));
694 WARN("Invalid lpszStr would crash under Win32!\n");
698 if (*lpszStr
== '-' || isdigit(*lpszStr
))
699 StrToIntExA(lpszStr
, 0, &iRet
);
703 /*************************************************************************
704 * StrToIntW [SHLWAPI.@]
708 int WINAPI
StrToIntW(LPCWSTR lpszStr
)
712 TRACE("(%s)\n", debugstr_w(lpszStr
));
716 WARN("Invalid lpszStr would crash under Win32!\n");
720 if (*lpszStr
== '-' || isdigitW(*lpszStr
))
721 StrToIntExW(lpszStr
, 0, &iRet
);
725 /*************************************************************************
726 * StrToIntExA [SHLWAPI.@]
728 * Read an integer from a string.
731 * lpszStr [I] String to read integer from
732 * dwFlags [I] Flags controlling the conversion
733 * lpiRet [O] Destination for read integer.
736 * Success: TRUE. lpiRet contains the integer value represented by the string.
737 * Failure: FALSE, if the string is invalid, or no number is present.
740 * Leading whitespace, '-' and '+' are allowed before the number. If
741 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
742 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
743 * the string is treated as a decimal string. A leading '-' is ignored for
744 * hexidecimal numbers.
746 BOOL WINAPI
StrToIntExA(LPCSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
748 BOOL bNegative
= FALSE
;
751 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
753 if (!lpszStr
|| !lpiRet
)
755 WARN("Invalid parameter would crash under Win32!\n");
758 if (dwFlags
> STIF_SUPPORT_HEX
)
760 WARN("Unknown flags (%08lX)!\n", dwFlags
& ~STIF_SUPPORT_HEX
);
763 /* Skip leading space, '+', '-' */
764 while (isspace(*lpszStr
))
765 lpszStr
= CharNextA(lpszStr
);
772 else if (*lpszStr
== '+')
775 if (dwFlags
& STIF_SUPPORT_HEX
&&
776 *lpszStr
== '0' && tolower(lpszStr
[1]) == 'x')
778 /* Read hex number */
781 if (!isxdigit(*lpszStr
))
784 while (isxdigit(*lpszStr
))
787 if (isdigit(*lpszStr
))
788 iRet
+= (*lpszStr
- '0');
790 iRet
+= 10 + (tolower(*lpszStr
) - 'a');
797 /* Read decimal number */
798 if (!isdigit(*lpszStr
))
801 while (isdigit(*lpszStr
))
804 iRet
+= (*lpszStr
- '0');
807 *lpiRet
= bNegative
? -iRet
: iRet
;
811 /*************************************************************************
812 * StrToIntExW [SHLWAPI.@]
816 BOOL WINAPI
StrToIntExW(LPCWSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
818 BOOL bNegative
= FALSE
;
821 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
823 if (!lpszStr
|| !lpiRet
)
825 WARN("Invalid parameter would crash under Win32!\n");
828 if (dwFlags
> STIF_SUPPORT_HEX
)
830 WARN("Unknown flags (%08lX)!\n", dwFlags
& ~STIF_SUPPORT_HEX
);
833 /* Skip leading space, '+', '-' */
834 while (isspaceW(*lpszStr
))
835 lpszStr
= CharNextW(lpszStr
);
842 else if (*lpszStr
== '+')
845 if (dwFlags
& STIF_SUPPORT_HEX
&&
846 *lpszStr
== '0' && tolowerW(lpszStr
[1]) == 'x')
848 /* Read hex number */
851 if (!isxdigitW(*lpszStr
))
854 while (isxdigitW(*lpszStr
))
857 if (isdigitW(*lpszStr
))
858 iRet
+= (*lpszStr
- '0');
860 iRet
+= 10 + (tolowerW(*lpszStr
) - 'a');
867 /* Read decimal number */
868 if (!isdigitW(*lpszStr
))
871 while (isdigitW(*lpszStr
))
874 iRet
+= (*lpszStr
- '0');
877 *lpiRet
= bNegative
? -iRet
: iRet
;
881 /*************************************************************************
882 * StrDupA [SHLWAPI.@]
884 * Duplicate a string.
887 * lpszStr [I] String to duplicate.
890 * Success: A pointer to a new string containing the contents of lpszStr
891 * Failure: NULL, if memory cannot be allocated
894 * The string memory is allocated with LocalAlloc, and so should be released
895 * by calling LocalFree.
897 LPSTR WINAPI
StrDupA(LPCSTR lpszStr
)
902 TRACE("(%s)\n",debugstr_a(lpszStr
));
904 iLen
= lpszStr
? strlen(lpszStr
) + 1 : 1;
905 lpszRet
= (LPSTR
)LocalAlloc(LMEM_FIXED
, iLen
);
910 memcpy(lpszRet
, lpszStr
, iLen
);
917 /*************************************************************************
918 * StrDupW [SHLWAPI.@]
922 LPWSTR WINAPI
StrDupW(LPCWSTR lpszStr
)
927 TRACE("(%s)\n",debugstr_w(lpszStr
));
929 iLen
= (lpszStr
? strlenW(lpszStr
) + 1 : 1) * sizeof(WCHAR
);
930 lpszRet
= (LPWSTR
)LocalAlloc(LMEM_FIXED
, iLen
);
935 memcpy(lpszRet
, lpszStr
, iLen
);
942 /*************************************************************************
943 * SHLWAPI_StrSpnHelperA
945 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
947 static int WINAPI
SHLWAPI_StrSpnHelperA(LPCSTR lpszStr
, LPCSTR lpszMatch
,
948 LPSTR (WINAPI
*pStrChrFn
)(LPCSTR
,WORD
),
951 LPCSTR lpszRead
= lpszStr
;
952 if (lpszStr
&& *lpszStr
&& lpszMatch
)
956 LPCSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
958 if (!bInvert
&& !lpszTest
)
960 if (bInvert
&& lpszTest
)
962 lpszRead
= CharNextA(lpszRead
);
965 return lpszRead
- lpszStr
;
968 /*************************************************************************
969 * SHLWAPI_StrSpnHelperW
971 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
973 static int WINAPI
SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
,
974 LPWSTR (WINAPI
*pStrChrFn
)(LPCWSTR
,WCHAR
),
977 LPCWSTR lpszRead
= lpszStr
;
978 if (lpszStr
&& *lpszStr
&& lpszMatch
)
982 LPCWSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
984 if (!bInvert
&& !lpszTest
)
986 if (bInvert
&& lpszTest
)
988 lpszRead
= CharNextW(lpszRead
);
991 return lpszRead
- lpszStr
;
994 /*************************************************************************
995 * StrSpnA [SHLWAPI.@]
997 * Find the length of the start of a string that contains only certain
1001 * lpszStr [I] String to search
1002 * lpszMatch [I] Characters that can be in the substring
1005 * The length of the part of lpszStr containing only chars from lpszMatch,
1006 * or 0 if any parameter is invalid.
1008 int WINAPI
StrSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1010 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1012 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, FALSE
);
1015 /*************************************************************************
1016 * StrSpnW [SHLWAPI.@]
1020 int WINAPI
StrSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1022 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1024 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrW
, FALSE
);
1027 /*************************************************************************
1028 * StrCSpnA [SHLWAPI.@]
1030 * Find the length of the start of a string that does not contain certain
1034 * lpszStr [I] String to search
1035 * lpszMatch [I] Characters that cannot be in the substring
1038 * The length of the part of lpszStr containing only chars not in lpszMatch,
1039 * or 0 if any parameter is invalid.
1041 int WINAPI
StrCSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1043 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1045 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, TRUE
);
1048 /*************************************************************************
1049 * StrCSpnW [SHLWAPI.@]
1053 int WINAPI
StrCSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1055 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1057 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrW
, TRUE
);
1060 /*************************************************************************
1061 * StrCSpnIA [SHLWAPI.@]
1063 * Find the length of the start of a string that does not contain certain
1064 * characters, ignoring case.
1067 * lpszStr [I] String to search
1068 * lpszMatch [I] Characters that cannot be in the substring
1071 * The length of the part of lpszStr containing only chars not in lpszMatch,
1072 * or 0 if any parameter is invalid.
1074 int WINAPI
StrCSpnIA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1076 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1078 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrIA
, TRUE
);
1081 /*************************************************************************
1082 * StrCSpnIW [SHLWAPI.@]
1086 int WINAPI
StrCSpnIW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1088 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1090 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrIW
, TRUE
);
1093 /*************************************************************************
1094 * StrPBrkA [SHLWAPI.@]
1096 * Search a string for any of a group of characters.
1099 * lpszStr [I] String to search
1100 * lpszMatch [I] Characters to match
1103 * A pointer to the first matching character in lpszStr, or NULL if no
1106 LPSTR WINAPI
StrPBrkA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1108 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1110 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1114 if (StrChrA(lpszMatch
, *lpszStr
))
1115 return (LPSTR
)lpszStr
;
1116 lpszStr
= CharNextA(lpszStr
);
1122 /*************************************************************************
1123 * StrPBrkW [SHLWAPI.@]
1127 LPWSTR WINAPI
StrPBrkW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1129 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1131 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1135 if (StrChrW(lpszMatch
, *lpszStr
))
1136 return (LPWSTR
)lpszStr
;
1137 lpszStr
= CharNextW(lpszStr
);
1143 /*************************************************************************
1144 * SHLWAPI_StrRChrHelperA
1146 * Internal implementation of StrRChrA/StrRChrIA.
1148 static LPSTR WINAPI
SHLWAPI_StrRChrHelperA(LPCSTR lpszStr
,
1149 LPCSTR lpszEnd
, WORD ch
,
1150 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
1152 LPCSTR lpszRet
= NULL
;
1159 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
1161 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1163 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
1165 if (!pChrCmpFn(ch
, ch2
))
1167 lpszStr
= CharNextA(lpszStr
);
1170 return (LPSTR
)lpszRet
;
1173 /*************************************************************************
1174 * SHLWAPI_StrRChrHelperW
1176 * Internal implementation of StrRChrW/StrRChrIW.
1178 static LPWSTR WINAPI
SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr
,
1179 LPCWSTR lpszEnd
, WCHAR ch
,
1180 BOOL (WINAPI
*pChrCmpFn
)(WCHAR
,WCHAR
))
1182 LPCWSTR lpszRet
= NULL
;
1187 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
1189 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1191 if (!pChrCmpFn(ch
, *lpszStr
))
1193 lpszStr
= CharNextW(lpszStr
);
1196 return (LPWSTR
)lpszRet
;
1199 /**************************************************************************
1200 * StrRChrA [SHLWAPI.@]
1202 * Find the last occurence of a character in string.
1205 * lpszStr [I] String to search in
1206 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1207 * ch [I] Character to search for.
1210 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1211 * or NULL if not found.
1212 * Failure: NULL, if any arguments are invalid.
1214 LPSTR WINAPI
StrRChrA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1216 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1218 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpA
);
1221 /**************************************************************************
1222 * StrRChrW [SHLWAPI.@]
1226 LPWSTR WINAPI
StrRChrW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, WORD ch
)
1228 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr
), debugstr_w(lpszEnd
), ch
);
1230 return SHLWAPI_StrRChrHelperW(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpW
);
1233 /**************************************************************************
1234 * StrRChrIA [SHLWAPI.@]
1236 * Find the last occurence of a character in string, ignoring case.
1239 * lpszStr [I] String to search in
1240 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1241 * ch [I] Character to search for.
1244 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1245 * or NULL if not found.
1246 * Failure: NULL, if any arguments are invalid.
1248 LPSTR WINAPI
StrRChrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1250 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1252 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, ChrCmpIA
);
1255 /**************************************************************************
1256 * StrRChrIW [SHLWAPI.@]
1260 LPWSTR WINAPI
StrRChrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, WORD ch
)
1262 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr
), debugstr_w(lpszEnd
), ch
);
1264 return SHLWAPI_StrRChrHelperW(lpszStr
, lpszEnd
, ch
, ChrCmpIW
);
1267 /*************************************************************************
1268 * StrCatBuffA [SHLWAPI.@]
1270 * Concatenate two strings together.
1273 * lpszStr [O] String to concatenate to
1274 * lpszCat [I] String to add to lpszCat
1275 * cchMax [I] Maximum number of characters for the whole string
1281 * cchMax dtermines the number of characters in the final length of the
1282 * string, not the number appended to lpszStr from lpszCat.
1284 LPSTR WINAPI
StrCatBuffA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1288 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_a(lpszCat
), cchMax
);
1292 WARN("Invalid lpszStr would crash under Win32!\n");
1296 iLen
= strlen(lpszStr
);
1300 StrCpyNA(lpszStr
+ iLen
, lpszCat
, cchMax
);
1304 /*************************************************************************
1305 * StrCatBuffW [SHLWAPI.@]
1309 LPWSTR WINAPI
StrCatBuffW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1313 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_w(lpszCat
), cchMax
);
1317 WARN("Invalid lpszStr would crash under Win32!\n");
1321 iLen
= strlenW(lpszStr
);
1325 StrCpyNW(lpszStr
+ iLen
, lpszCat
, cchMax
);
1329 /*************************************************************************
1330 * StrRetToBufA [SHLWAPI.@]
1332 * Convert a STRRET to a normal string.
1335 * lpStrRet [O] STRRET to convert
1336 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1337 * lpszDest [O] Destination for normal string
1338 * dwLen [I] Length of lpszDest
1341 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1342 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1343 * CoTaskMemFree and its type set to STRRET_CSTRA.
1344 * Failure: E_FAIL, if any parameters are invalid.
1346 HRESULT WINAPI
StrRetToBufA (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPSTR dest
, DWORD len
)
1349 * This routine is identical to that in dlls/shell32/shellstring.c.
1350 * It was duplicated because not every version of Shlwapi.dll exports
1351 * StrRetToBufA. If you change one routine, change them both.
1353 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest
,len
,src
,pidl
);
1357 WARN("Invalid lpStrRet would crash under Win32!\n");
1371 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, dest
, len
, NULL
, NULL
);
1372 CoTaskMemFree(src
->u
.pOleStr
);
1376 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
1380 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
1384 FIXME("unknown type!\n");
1390 /*************************************************************************
1391 * StrRetToBufW [SHLWAPI.@]
1395 HRESULT WINAPI
StrRetToBufW (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPWSTR dest
, DWORD len
)
1397 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest
,len
,src
,pidl
);
1401 WARN("Invalid lpStrRet would crash under Win32!\n");
1415 lstrcpynW((LPWSTR
)dest
, src
->u
.pOleStr
, len
);
1416 CoTaskMemFree(src
->u
.pOleStr
);
1420 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
1427 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1,
1434 FIXME("unknown type!\n");
1440 /*************************************************************************
1441 * StrRetToStrA [SHLWAPI.@]
1443 * converts a STRRET to a normal string
1445 HRESULT WINAPI
StrRetToStrA(LPSTRRET pstr
, const ITEMIDLIST
* pidl
, LPSTR
* ppszName
)
1447 HRESULT ret
= E_FAIL
;
1449 switch (pstr
->uType
) {
1451 ret
= _SHStrDupAW(pstr
->u
.pOleStr
, ppszName
);
1452 CoTaskMemFree(pstr
->u
.pOleStr
);
1456 ret
= _SHStrDupAA(pstr
->u
.cStr
, ppszName
);
1460 ret
= _SHStrDupAA(((LPCSTR
)&pidl
->mkid
)+pstr
->u
.uOffset
, ppszName
);
1469 /*************************************************************************
1470 * StrRetToStrW [SHLWAPI.@]
1472 * converts a STRRET to a normal string
1474 HRESULT WINAPI
StrRetToStrW(LPSTRRET pstr
, const ITEMIDLIST
* pidl
, LPWSTR
* ppszName
)
1476 HRESULT ret
= E_FAIL
;
1478 switch (pstr
->uType
) {
1480 ret
= SHStrDupW(pstr
->u
.pOleStr
, ppszName
);
1481 CoTaskMemFree(pstr
->u
.pOleStr
);
1485 ret
= SHStrDupA(pstr
->u
.cStr
, ppszName
);
1489 ret
= SHStrDupA(((LPCSTR
)&pidl
->mkid
)+pstr
->u
.uOffset
, ppszName
);
1498 /*************************************************************************
1499 * StrFormatKBSizeA [SHLWAPI.@]
1501 * Create a formatted string containing a byte count in Kilobytes.
1504 * llBytes [I] Byte size to format
1505 * lpszDest [I] Destination for formatted string
1506 * cchMax [I] Size of lpszDest
1511 LPSTR WINAPI
StrFormatKBSizeA(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
1513 char szBuff
[256], *szOut
= szBuff
+ sizeof(szBuff
) - 1;
1514 LONGLONG ulKB
= (llBytes
+ 1023) >> 10;
1516 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
1525 LONGLONG ulNextDigit
= ulKB
% 10;
1526 *szOut
-- = '0' + ulNextDigit
;
1527 ulKB
= (ulKB
- ulNextDigit
) / 10;
1530 strncpy(lpszDest
, szOut
+ 1, cchMax
);
1534 /*************************************************************************
1535 * StrFormatKBSizeW [SHLWAPI.@]
1537 * See StrFormatKBSizeA.
1539 LPWSTR WINAPI
StrFormatKBSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
1541 WCHAR szBuff
[256], *szOut
= szBuff
+ sizeof(szBuff
) - 1;
1542 LONGLONG ulKB
= (llBytes
+ 1023) >> 10;
1544 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
1553 LONGLONG ulNextDigit
= ulKB
% 10;
1554 *szOut
-- = '0' + ulNextDigit
;
1555 ulKB
= (ulKB
- ulNextDigit
) / 10;
1558 strncpyW(lpszDest
, szOut
+ 1, cchMax
);
1562 /*************************************************************************
1563 * StrNCatA [SHLWAPI.@]
1565 * Concatenate two strings together.
1568 * lpszStr [O] String to concatenate to
1569 * lpszCat [I] String to add to lpszCat
1570 * cchMax [I] Maximum number of characters to concatenate
1576 * cchMax dtermines the number of characters that are appended to lpszStr,
1577 * not the total length of the string.
1579 LPSTR WINAPI
StrNCatA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1581 LPSTR lpszRet
= lpszStr
;
1583 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszCat
), cchMax
);
1587 WARN("Invalid lpszStr would crash under Win32!\n");
1591 StrCpyNA(lpszStr
+ strlen(lpszStr
), lpszCat
, cchMax
);
1595 /*************************************************************************
1596 * StrNCatW [SHLWAPI.@]
1600 LPWSTR WINAPI
StrNCatW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1602 LPWSTR lpszRet
= lpszStr
;
1604 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszCat
), cchMax
);
1608 WARN("Invalid lpszStr would crash under Win32\n");
1612 StrCpyNW(lpszStr
+ strlenW(lpszStr
), lpszCat
, cchMax
);
1616 /*************************************************************************
1617 * StrTrimA [SHLWAPI.@]
1619 * Remove characters from the start and end of a string.
1622 * lpszStr [O] String to remove characters from
1623 * lpszTrim [I] Characters to remove from lpszStr
1626 * TRUE If lpszStr was valid and modified
1629 BOOL WINAPI
StrTrimA(LPSTR lpszStr
, LPCSTR lpszTrim
)
1632 LPSTR lpszRead
= lpszStr
;
1635 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszTrim
));
1637 if (lpszRead
&& *lpszRead
)
1639 while (*lpszRead
&& StrChrA(lpszTrim
, *lpszRead
))
1640 lpszRead
= CharNextA(lpszRead
); /* Skip leading matches */
1642 dwLen
= strlen(lpszRead
);
1644 if (lpszRead
!= lpszStr
)
1646 memmove(lpszStr
, lpszRead
, dwLen
+ 1);
1651 lpszRead
= lpszStr
+ dwLen
;
1652 while (StrChrA(lpszTrim
, lpszRead
[-1]))
1653 lpszRead
= CharPrevA(lpszStr
, lpszRead
); /* Skip trailing matches */
1655 if (lpszRead
!= lpszStr
+ dwLen
)
1665 /*************************************************************************
1666 * StrTrimW [SHLWAPI.@]
1670 BOOL WINAPI
StrTrimW(LPWSTR lpszStr
, LPCWSTR lpszTrim
)
1673 LPWSTR lpszRead
= lpszStr
;
1676 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszTrim
));
1678 if (lpszRead
&& *lpszRead
)
1680 while (*lpszRead
&& StrChrW(lpszTrim
, *lpszRead
))
1681 lpszRead
= CharNextW(lpszRead
); /* Skip leading matches */
1683 dwLen
= strlenW(lpszRead
);
1685 if (lpszRead
!= lpszStr
)
1687 memmove(lpszStr
, lpszRead
, (dwLen
+ 1) * sizeof(WCHAR
));
1692 lpszRead
= lpszStr
+ dwLen
;
1693 while (StrChrW(lpszTrim
, lpszRead
[-1]))
1694 lpszRead
= CharPrevW(lpszStr
, lpszRead
); /* Skip trailing matches */
1696 if (lpszRead
!= lpszStr
+ dwLen
)
1706 /*************************************************************************
1707 * _SHStrDupA [INTERNAL]
1709 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1711 static HRESULT WINAPI
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
)
1717 len
= lstrlenA(src
);
1718 *dest
= CoTaskMemAlloc(len
);
1724 lstrcpynA(*dest
,src
, len
);
1730 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1734 /*************************************************************************
1737 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc.
1740 * lpszStr [I] String to copy
1741 * lppszDest [O] Destination for the new string copy
1744 * Success: S_OK. lppszDest contains the new string in Unicode format.
1745 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1748 HRESULT WINAPI
SHStrDupA(LPCSTR src
, LPWSTR
* dest
)
1754 len
= (MultiByteToWideChar(0,0,src
,-1,0,0) + 1)* sizeof(WCHAR
);
1755 *dest
= CoTaskMemAlloc(len
);
1761 MultiByteToWideChar(0,0,src
,-1,*dest
,len
);
1767 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1771 /*************************************************************************
1772 * _SHStrDupAW [INTERNAL]
1774 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1776 static HRESULT WINAPI
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
)
1782 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1783 *dest
= CoTaskMemAlloc(len
);
1789 WideCharToMultiByte(CP_ACP
, 0, src
, -1, *dest
, len
, NULL
, NULL
);
1795 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1799 /*************************************************************************
1804 HRESULT WINAPI
SHStrDupW(LPCWSTR src
, LPWSTR
* dest
)
1810 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1811 *dest
= CoTaskMemAlloc(len
);
1817 memcpy(*dest
, src
, len
);
1823 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1827 /*************************************************************************
1828 * SHLWAPI_WriteReverseNum
1830 * Internal helper for SHLWAPI_WriteTimeClass.
1832 inline static LPWSTR
SHLWAPI_WriteReverseNum(LPWSTR lpszOut
, DWORD dwNum
)
1836 /* Write a decimal number to a string, backwards */
1839 DWORD dwNextDigit
= dwNum
% 10;
1840 *lpszOut
-- = '0' + dwNextDigit
;
1841 dwNum
= (dwNum
- dwNextDigit
) / 10;
1842 } while (dwNum
> 0);
1847 /*************************************************************************
1848 * SHLWAPI_FormatSignificant
1850 * Internal helper for SHLWAPI_WriteTimeClass.
1852 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum
, int dwDigits
)
1854 /* Zero non significant digits, return remaining significant digits */
1858 if (--dwDigits
== 0)
1868 /*************************************************************************
1869 * SHLWAPI_WriteTimeClass
1871 * Internal helper for StrFromTimeIntervalW.
1873 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut
, DWORD dwValue
,
1874 LPCWSTR lpszClass
, int iDigits
)
1876 WCHAR szBuff
[64], *szOut
= szBuff
+ 32;
1878 szOut
= SHLWAPI_WriteReverseNum(szOut
, dwValue
);
1879 iDigits
= SHLWAPI_FormatSignificant(szOut
+ 1, iDigits
);
1881 strcpyW(szBuff
+ 32, lpszClass
);
1882 strcatW(lpszOut
, szOut
);
1886 /*************************************************************************
1887 * StrFromTimeIntervalA [SHLWAPI.@]
1889 * Format a millisecond time interval into a string
1892 * lpszStr [O] Output buffer for formatted time interval
1893 * cchMax [I] Size of lpszStr
1894 * dwMS [I] Number of milliseconds
1895 * iDigits [I] Number of digits to print
1898 * The length of the formatted string, or 0 if any parameter is invalid.
1901 * This implementation mimics the Win32 behaviour of always writing a leading
1902 * space before the time interval begins.
1903 * iDigits is used to provide approximate times if accuracy is not important.
1904 * This number of digits will be written of the first non-zero time class
1905 * (hours/minutes/seconds). If this does not complete the time classification,
1906 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1907 * If there are digits remaining following the writing of a time class, the
1908 * next time class will be written.
1909 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1910 * following will result from the given values of iDigits:
1912 * iDigits 1 2 3 4 5 ...
1913 * lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1915 INT WINAPI
StrFromTimeIntervalA(LPSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
1920 TRACE("(%p,%d,%ld,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
1922 if (lpszStr
&& cchMax
)
1925 StrFromTimeIntervalW(szBuff
, sizeof(szBuff
)/sizeof(WCHAR
), dwMS
, iDigits
);
1926 WideCharToMultiByte(CP_ACP
,0,szBuff
,-1,lpszStr
,cchMax
,0,0);
1932 /*************************************************************************
1933 * StrFromTimeIntervalW [SHLWAPI.@]
1935 * See StrFromTimeIntervalA.
1937 INT WINAPI
StrFromTimeIntervalW(LPWSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
1940 static const WCHAR szHr
[] = {' ','h','r','\0'};
1941 static const WCHAR szMin
[] = {' ','m','i','n','\0'};
1942 static const WCHAR szSec
[] = {' ','s','e','c','\0'};
1945 TRACE("(%p,%d,%ld,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
1947 if (lpszStr
&& cchMax
)
1950 DWORD dwHours
, dwMinutes
;
1952 if (!iDigits
|| cchMax
== 1)
1958 /* Calculate the time classes */
1959 dwMS
= (dwMS
+ 500) / 1000;
1960 dwHours
= dwMS
/ 3600;
1961 dwMS
-= dwHours
* 3600;
1962 dwMinutes
= dwMS
/ 60;
1963 dwMS
-= dwMinutes
* 60;
1968 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwHours
, szHr
, iDigits
);
1970 if (dwMinutes
&& iDigits
)
1971 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwMinutes
, szMin
, iDigits
);
1973 if (iDigits
) /* Always write seconds if we have significant digits */
1974 SHLWAPI_WriteTimeClass(szCopy
, dwMS
, szSec
, iDigits
);
1976 strncpyW(lpszStr
, szCopy
, cchMax
);
1977 iRet
= strlenW(lpszStr
);
1982 /*************************************************************************
1983 * StrIsIntlEqualA [SHLWAPI.@]
1985 * Compare two strings.
1988 * bCase [I] Whether to compare case sensitively
1989 * lpszStr [I] First string to compare
1990 * lpszComp [I] Second string to compare
1991 * iLen [I] Length to compare
1994 * TRUE If the strings are equal.
1997 BOOL WINAPI
StrIsIntlEqualA(BOOL bCase
, LPCSTR lpszStr
, LPCSTR lpszComp
,
2000 DWORD dwFlags
= LOCALE_USE_CP_ACP
;
2003 TRACE("(%d,%s,%s,%d)\n", bCase
,
2004 debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
2006 /* FIXME: These flags are undocumented and unknown by our CompareString.
2007 * We need defines for them.
2009 dwFlags
|= bCase
? 0x10000000 : 0x10000001;
2011 iRet
= CompareStringA(GetThreadLocale(),
2012 dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2015 iRet
= CompareStringA(2048, dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2017 return iRet
== 2 ? TRUE
: FALSE
;
2020 /*************************************************************************
2021 * StrIsIntlEqualW [SHLWAPI.@]
2023 * See StrIsIntlEqualA.
2025 BOOL WINAPI
StrIsIntlEqualW(BOOL bCase
, LPCWSTR lpszStr
, LPCWSTR lpszComp
,
2031 TRACE("(%d,%s,%s,%d)\n", bCase
,
2032 debugstr_w(lpszStr
),debugstr_w(lpszComp
), iLen
);
2034 /* FIXME: These flags are undocumented and unknown by our CompareString.
2035 * We need defines for them.
2037 dwFlags
= bCase
? 0x10000000 : 0x10000001;
2039 iRet
= CompareStringW(GetThreadLocale(),
2040 dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2043 iRet
= CompareStringW(2048, dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2045 return iRet
== 2 ? TRUE
: FALSE
;
2048 /*************************************************************************
2051 * Copy a string to another string, up to a maximum number of characters.
2054 * lpszDest [O] Destination string
2055 * lpszSrc [I] Source string
2056 * iLen [I] Maximum number of chars to copy
2059 * Success: A pointer to the last character written.
2060 * Failure: lpszDest, if any arguments are invalid.
2062 LPSTR WINAPI
SHLWAPI_399(LPSTR lpszDest
, LPCSTR lpszSrc
, int iLen
)
2064 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_a(lpszSrc
), iLen
);
2066 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2068 while ((iLen
-- > 1) && *lpszSrc
)
2069 *lpszDest
++ = *lpszSrc
++;
2076 /*************************************************************************
2079 * Unicode version of SHLWAPI_399.
2081 LPWSTR WINAPI
SHLWAPI_400(LPWSTR lpszDest
, LPCWSTR lpszSrc
, int iLen
)
2083 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_w(lpszSrc
), iLen
);
2085 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2087 while ((iLen
-- > 1) && *lpszSrc
)
2088 *lpszDest
++ = *lpszSrc
++;
2095 /*************************************************************************
2096 * StrCmpLogicalW [SHLWAPI.@]
2098 * Compare two strings, ignoring case and comparing digits as numbers.
2101 * lpszStr [I] First string to compare
2102 * lpszComp [I] Second string to compare
2103 * iLen [I] Length to compare
2106 * TRUE If the strings are equal.
2109 INT WINAPI
StrCmpLogicalW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
2113 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
2115 if (lpszStr
&& lpszComp
)
2121 else if (isdigitW(*lpszStr
))
2125 if (!isdigitW(*lpszComp
))
2128 /* Compare the numbers */
2129 StrToIntExW(lpszStr
, 0, &iStr
);
2130 StrToIntExW(lpszComp
, 0, &iComp
);
2134 else if (iStr
> iComp
)
2138 while (isdigitW(*lpszStr
))
2140 while (isdigitW(*lpszComp
))
2143 else if (isdigitW(*lpszComp
))
2147 iDiff
= SHLWAPI_ChrCmpHelperA(*lpszStr
,*lpszComp
,NORM_IGNORECASE
);
2163 /* Structure for formatting byte strings */
2164 typedef struct tagSHLWAPI_BYTEFORMATS
2171 } SHLWAPI_BYTEFORMATS
;
2173 /*************************************************************************
2174 * StrFormatByteSize64A [SHLWAPI.@]
2176 * Create a string containing an abbreviated byte count of up to 2^63-1.
2179 * llBytes [I] Byte size to format
2180 * lpszDest [I] Destination for formatted string
2181 * cchMax [I] Size of lpszDest
2187 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW.
2189 LPSTR WINAPI
StrFormatByteSize64A(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
2191 static const char szBytes
[] = "%ld bytes";
2192 static const char sz3_0
[] = "%3.0f";
2193 static const char sz3_1
[] = "%3.1f";
2194 static const char sz3_2
[] = "%3.2f";
2196 static const SHLWAPI_BYTEFORMATS bfFormats
[] =
2198 { 10240, 10.24, 100.0, sz3_2
, 'K' }, /* 10 KB */
2199 { 102400, 102.4, 10.0, sz3_1
, 'K' }, /* 100 KB */
2200 { 1024000, 1024.0, 1.0, sz3_0
, 'K' }, /* 1000 KB */
2201 { 10485760, 10485.76, 100.0, sz3_2
, 'M' }, /* 10 MB */
2202 { 104857600, 104857.6, 10.0, sz3_1
, 'M' }, /* 100 MB */
2203 { 1048576000, 1048576.0, 1.0, sz3_0
, 'M' }, /* 1000 MB */
2204 { 10737418240, 10737418.24, 100.0, sz3_2
, 'G' }, /* 10 GB */
2205 { 107374182400, 107374182.4, 10.0, sz3_1
, 'G' }, /* 100 GB */
2206 { 1073741824000, 1073741824.0, 1.0, sz3_0
, 'G' }, /* 1000 GB */
2207 { 10995116277760, 10485.76, 100.0, sz3_2
, 'T' }, /* 10 TB */
2208 { 109951162777600, 104857.6, 10.0, sz3_1
, 'T' }, /* 100 TB */
2209 { 1099511627776000, 1048576.0, 1.0, sz3_0
, 'T' }, /* 1000 TB */
2210 { 11258999068426240, 10737418.24, 100.00, sz3_2
, 'P' }, /* 10 PB */
2211 { 112589990684262400, 107374182.4, 10.00, sz3_1
, 'P' }, /* 100 PB */
2212 { 1125899906842624000, 1073741824.0, 1.00, sz3_0
, 'P' }, /* 1000 PB */
2213 { 0, 10995116277.76, 100.00, sz3_2
, 'E' } /* EB's, catch all */
2220 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
2222 if (!lpszDest
|| !cchMax
)
2225 if (llBytes
< 1024) /* 1K */
2227 snprintf (lpszDest
, cchMax
, szBytes
, (long)llBytes
);
2231 /* Note that if this loop completes without finding a match, i will be
2232 * pointing at the last entry, which is a catch all for > 1000 PB
2234 while (i
< sizeof(bfFormats
) / sizeof(SHLWAPI_BYTEFORMATS
) - 1)
2236 if (llBytes
< bfFormats
[i
].dLimit
)
2240 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2241 * this number we integer shift down by 1 MB first. The table above has
2242 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2243 * for this. We also add a small fudge factor to get the correct result for
2244 * counts that lie exactly on a 1024 byte boundary.
2247 dBytes
= (double)(llBytes
>> 20) + 0.001; /* Scale down by I MB */
2249 dBytes
= (double)llBytes
+ 0.00001;
2251 dBytes
= floor(dBytes
/ bfFormats
[i
].dDivisor
) / bfFormats
[i
].dNormaliser
;
2253 sprintf(szBuff
, bfFormats
[i
].lpszFormat
, dBytes
);
2255 szAdd
[1] = bfFormats
[i
].wPrefix
;
2258 strcat(szBuff
, szAdd
);
2259 strncpy(lpszDest
, szBuff
, cchMax
);
2263 /*************************************************************************
2264 * StrFormatByteSizeW [SHLWAPI.@]
2266 * See StrFormatByteSize64A.
2268 LPWSTR WINAPI
StrFormatByteSizeW(LONGLONG llBytes
, LPWSTR lpszDest
,
2273 StrFormatByteSize64A(llBytes
, szBuff
, sizeof(szBuff
));
2276 MultiByteToWideChar(CP_ACP
, 0, szBuff
, -1, lpszDest
, cchMax
);
2280 /*************************************************************************
2281 * StrFormatByteSizeA [SHLWAPI.@]
2283 * Create a string containing an abbreviated byte count of up to 2^31-1.
2286 * dwBytes [I] Byte size to format
2287 * lpszDest [I] Destination for formatted string
2288 * cchMax [I] Size of lpszDest
2294 * The ASCII and Unicode versions of this function accept a different
2295 * integer size for dwBytes. See StrFormatByteSize64A.
2297 LPSTR WINAPI
StrFormatByteSizeA(DWORD dwBytes
, LPSTR lpszDest
, UINT cchMax
)
2299 TRACE("(%ld,%p,%d)\n", dwBytes
, lpszDest
, cchMax
);
2301 return StrFormatByteSize64A(dwBytes
, lpszDest
, cchMax
);