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
23 #include "wine/port.h"
36 #define NO_SHLWAPI_STREAM
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.
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
);
73 str2
[0] = LOBYTE(ch2
);
74 if (IsDBCSLeadByte(ch2
))
76 str2
[1] = HIBYTE(ch2
);
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];
98 return CompareStringW(GetThreadLocale(), dwFlags
, str1
, 2, str2
, 2) - 2;
101 /*************************************************************************
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.
117 * ch1 [I] First character to compare
118 * ch2 [I] Second character to compare
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 /*************************************************************************
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]
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.
157 * lpszStr [I] String to search in.
158 * ch [I] Character to search for.
161 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
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
);
173 if (!SHLWAPI_ChrCmpA(*lpszStr
, ch
))
174 return (LPSTR
)lpszStr
;
175 lpszStr
= CharNextA(lpszStr
);
181 /*************************************************************************
182 * StrChrW [SHLWAPI.@]
186 LPWSTR WINAPI
StrChrW(LPCWSTR lpszStr
, WCHAR ch
)
188 LPWSTR lpszRet
= NULL
;
190 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
193 lpszRet
= strchrW(lpszStr
, ch
);
197 /*************************************************************************
198 * StrChrIA [SHLWAPI.@]
200 * Find a given character in a string, ignoring case.
203 * lpszStr [I] String to search in.
204 * ch [I] Character to search for.
207 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
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
);
219 if (!ChrCmpIA(*lpszStr
, ch
))
220 return (LPSTR
)lpszStr
;
221 lpszStr
= CharNextA(lpszStr
);
227 /*************************************************************************
228 * StrChrIW [SHLWAPI.@]
232 LPWSTR WINAPI
StrChrIW(LPCWSTR lpszStr
, WCHAR ch
)
234 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
241 if (toupperW(*lpszStr
) == ch
)
242 return (LPWSTR
)lpszStr
;
243 lpszStr
= CharNextW(lpszStr
);
247 return (LPWSTR
)lpszStr
;
250 /*************************************************************************
251 * StrCmpIW [SHLWAPI.@]
253 * Compare two strings, ignoring case.
256 * lpszStr [I] First string to compare
257 * lpszComp [I] Second string to compare
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
)
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
,
280 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
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)
303 else if (!*lpszStr
&& !*lpszComp
)
306 lpszStr
= CharNextA(lpszStr
);
307 lpszComp
= CharNextA(lpszComp
);
312 /*************************************************************************
313 * StrCmpNA [SHLWAPI.@]
315 * Compare two strings, up to a maximum length.
318 * lpszStr [I] First string to compare
319 * lpszComp [I] Second string to compare
320 * iLen [I] Maximum number of chars to compare.
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.@]
338 INT WINAPI
StrCmpNW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, INT iLen
)
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.
354 * lpszStr [I] First string to compare
355 * lpszComp [I] Second string to compare
356 * iLen [I] Maximum number of chars to compare.
359 * An integer less than, equal to or greater than 0, indicating that
360 * lpszStr is less than, the same, or greater than lpszComp.
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.@]
385 INT WINAPI
StrCmpNIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, int iLen
)
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.
401 * lpszStr [I] First string to compare
402 * lpszComp [I] Second string to compare
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
)
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.
424 * lpszStr [O] Initial string
425 * lpszSrc [I] String to concatanate
430 LPWSTR WINAPI
StrCatW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
432 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSrc
));
434 strcatW(lpszStr
, lpszSrc
);
438 /*************************************************************************
439 * StrCpyW [SHLWAPI.@]
441 * Copy a string to another string.
444 * lpszStr [O] Destination string
445 * lpszSrc [I] Source string
450 LPWSTR WINAPI
StrCpyW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
452 TRACE("(%p,%s)\n", lpszStr
, debugstr_w(lpszSrc
));
454 strcpyW(lpszStr
, lpszSrc
);
458 /*************************************************************************
459 * StrCpyNW [SHLWAPI.@]
461 * Copy a string to another string, up to a maximum number of characters.
464 * lpszStr [O] Destination string
465 * lpszSrc [I] Source string
466 * iLen [I] Maximum number of chars to copy
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
);
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))
491 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
494 iLen
= strlen(lpszSearch
);
498 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
499 return (LPSTR
)lpszStr
;
500 lpszStr
= CharNextA(lpszStr
);
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))
515 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
518 iLen
= strlenW(lpszSearch
);
522 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
523 return (LPWSTR
)lpszStr
;
524 lpszStr
= CharNextW(lpszStr
);
529 /*************************************************************************
530 * StrStrA [SHLWAPI.@]
532 * Find a substring within a string.
535 * lpszStr [I] String to search in
536 * lpszSearch [I] String to look for
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.@]
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.
566 * lpszStr [I] String to search in
567 * lpszEnd [I] End of lpszStr
568 * lpszSearch [I] String to look for
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
;
579 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
581 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
585 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
587 if (IsDBCSLeadByte(*lpszSearch
))
588 ch1
= *lpszSearch
<< 8 | lpszSearch
[1];
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
);
606 /*************************************************************************
607 * StrRStrIW [SHLWAPI.@]
611 LPWSTR WINAPI
StrRStrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, LPCWSTR lpszSearch
)
613 LPWSTR lpszRet
= NULL
;
616 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
618 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
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
);
638 /*************************************************************************
639 * StrStrIA [SHLWAPI.@]
641 * Find a substring within a string, ignoring case.
644 * lpszStr [I] String to search in
645 * lpszSearch [I] String to look for
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.@]
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.
675 * lpszStr [I] String to read integer from
678 * The integer value represented by the string, or 0 if no integer is
682 * No leading space is allowed before the number, although a leading '-' is.
684 int WINAPI
StrToIntA(LPCSTR lpszStr
)
688 TRACE("(%s)\n", debugstr_a(lpszStr
));
692 WARN("Invalid lpszStr would crash under Win32!\n");
696 if (*lpszStr
== '-' || isdigit(*lpszStr
))
697 StrToIntExA(lpszStr
, 0, &iRet
);
701 /*************************************************************************
702 * StrToIntW [SHLWAPI.@]
706 int WINAPI
StrToIntW(LPCWSTR lpszStr
)
710 TRACE("(%s)\n", debugstr_w(lpszStr
));
714 WARN("Invalid lpszStr would crash under Win32!\n");
718 if (*lpszStr
== '-' || isdigitW(*lpszStr
))
719 StrToIntExW(lpszStr
, 0, &iRet
);
723 /*************************************************************************
724 * StrToIntExA [SHLWAPI.@]
726 * Read an integer from a string.
729 * lpszStr [I] String to read integer from
730 * dwFlags [I] Flags controlling the conversion
731 * lpiRet [O] Destination for read integer.
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.
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
;
749 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
751 if (!lpszStr
|| !lpiRet
)
753 WARN("Invalid parameter would crash under Win32!\n");
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
);
770 else if (*lpszStr
== '+')
773 if (dwFlags
& STIF_SUPPORT_HEX
&&
774 *lpszStr
== '0' && tolower(lpszStr
[1]) == 'x')
776 /* Read hex number */
779 if (!isxdigit(*lpszStr
))
782 while (isxdigit(*lpszStr
))
785 if (isdigit(*lpszStr
))
786 iRet
+= (*lpszStr
- '0');
788 iRet
+= 10 + (tolower(*lpszStr
) - 'a');
795 /* Read decimal number */
796 if (!isdigit(*lpszStr
))
799 while (isdigit(*lpszStr
))
802 iRet
+= (*lpszStr
- '0');
805 *lpiRet
= bNegative
? -iRet
: iRet
;
809 /*************************************************************************
810 * StrToIntExW [SHLWAPI.@]
814 BOOL WINAPI
StrToIntExW(LPCWSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
816 BOOL bNegative
= FALSE
;
819 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
821 if (!lpszStr
|| !lpiRet
)
823 WARN("Invalid parameter would crash under Win32!\n");
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
);
840 else if (*lpszStr
== '+')
843 if (dwFlags
& STIF_SUPPORT_HEX
&&
844 *lpszStr
== '0' && tolowerW(lpszStr
[1]) == 'x')
846 /* Read hex number */
849 if (!isxdigitW(*lpszStr
))
852 while (isxdigitW(*lpszStr
))
855 if (isdigitW(*lpszStr
))
856 iRet
+= (*lpszStr
- '0');
858 iRet
+= 10 + (tolowerW(*lpszStr
) - 'a');
865 /* Read decimal number */
866 if (!isdigitW(*lpszStr
))
869 while (isdigitW(*lpszStr
))
872 iRet
+= (*lpszStr
- '0');
875 *lpiRet
= bNegative
? -iRet
: iRet
;
879 /*************************************************************************
880 * StrDupA [SHLWAPI.@]
882 * Duplicate a string.
885 * lpszStr [I] String to duplicate.
888 * Success: A pointer to a new string containing the contents of lpszStr
889 * Failure: NULL, if memory cannot be allocated
892 * The string memory is allocated with LocalAlloc, and so should be released
893 * by calling LocalFree.
895 LPSTR WINAPI
StrDupA(LPCSTR lpszStr
)
900 TRACE("(%s)\n",debugstr_a(lpszStr
));
902 iLen
= lpszStr
? strlen(lpszStr
) + 1 : 1;
903 lpszRet
= (LPSTR
)LocalAlloc(LMEM_FIXED
, iLen
);
908 memcpy(lpszRet
, lpszStr
, iLen
);
915 /*************************************************************************
916 * StrDupW [SHLWAPI.@]
920 LPWSTR WINAPI
StrDupW(LPCWSTR lpszStr
)
925 TRACE("(%s)\n",debugstr_w(lpszStr
));
927 iLen
= (lpszStr
? strlenW(lpszStr
) + 1 : 1) * sizeof(WCHAR
);
928 lpszRet
= (LPWSTR
)LocalAlloc(LMEM_FIXED
, iLen
);
933 memcpy(lpszRet
, lpszStr
, iLen
);
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
),
949 LPCSTR lpszRead
= lpszStr
;
950 if (lpszStr
&& *lpszStr
&& lpszMatch
)
954 LPCSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
956 if (!bInvert
&& !lpszTest
)
958 if (bInvert
&& lpszTest
)
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
),
975 LPCWSTR lpszRead
= lpszStr
;
976 if (lpszStr
&& *lpszStr
&& lpszMatch
)
980 LPCWSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
982 if (!bInvert
&& !lpszTest
)
984 if (bInvert
&& lpszTest
)
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
999 * lpszStr [I] String to search
1000 * lpszMatch [I] Characters that can be in the substring
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.@]
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
1032 * lpszStr [I] String to search
1033 * lpszMatch [I] Characters that cannot be in the substring
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.@]
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.
1065 * lpszStr [I] String to search
1066 * lpszMatch [I] Characters that cannot be in the substring
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.@]
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.
1097 * lpszStr [I] String to search
1098 * lpszMatch [I] Characters to match
1101 * A pointer to the first matching character in lpszStr, or NULL if no
1104 LPSTR WINAPI
StrPBrkA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1106 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1108 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1112 if (StrChrA(lpszMatch
, *lpszStr
))
1113 return (LPSTR
)lpszStr
;
1114 lpszStr
= CharNextA(lpszStr
);
1120 /*************************************************************************
1121 * StrPBrkW [SHLWAPI.@]
1125 LPWSTR WINAPI
StrPBrkW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1127 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1129 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1133 if (StrChrW(lpszMatch
, *lpszStr
))
1134 return (LPWSTR
)lpszStr
;
1135 lpszStr
= CharNextW(lpszStr
);
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
;
1157 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
1159 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1161 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
1163 if (!pChrCmpFn(ch
, ch2
))
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
;
1185 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
1187 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1189 if (!pChrCmpFn(ch
, *lpszStr
))
1191 lpszStr
= CharNextW(lpszStr
);
1194 return (LPWSTR
)lpszRet
;
1197 /**************************************************************************
1198 * StrRChrA [SHLWAPI.@]
1200 * Find the last occurence of a character in string.
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.
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.@]
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.
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.
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.@]
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.
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
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
)
1286 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_a(lpszCat
), cchMax
);
1290 WARN("Invalid lpszStr would crash under Win32!\n");
1294 iLen
= strlen(lpszStr
);
1298 StrCpyNA(lpszStr
+ iLen
, lpszCat
, cchMax
);
1302 /*************************************************************************
1303 * StrCatBuffW [SHLWAPI.@]
1307 LPWSTR WINAPI
StrCatBuffW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1311 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_w(lpszCat
), cchMax
);
1315 WARN("Invalid lpszStr would crash under Win32!\n");
1319 iLen
= strlenW(lpszStr
);
1323 StrCpyNW(lpszStr
+ iLen
, lpszCat
, cchMax
);
1327 /*************************************************************************
1328 * StrRetToBufA [SHLWAPI.@]
1330 * Convert a STRRET to a normal string.
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
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
)
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
);
1355 WARN("Invalid lpStrRet would crash under Win32!\n");
1369 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, dest
, len
, NULL
, NULL
);
1370 CoTaskMemFree(src
->u
.pOleStr
);
1374 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
1378 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
1382 FIXME("unknown type!\n");
1388 /*************************************************************************
1389 * StrRetToBufW [SHLWAPI.@]
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
);
1399 WARN("Invalid lpStrRet would crash under Win32!\n");
1413 lstrcpynW((LPWSTR
)dest
, src
->u
.pOleStr
, len
);
1414 CoTaskMemFree(src
->u
.pOleStr
);
1418 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
1425 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1,
1432 FIXME("unknown type!\n");
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
) {
1449 ret
= _SHStrDupAW(pstr
->u
.pOleStr
, ppszName
);
1450 CoTaskMemFree(pstr
->u
.pOleStr
);
1454 ret
= _SHStrDupAA(pstr
->u
.cStr
, ppszName
);
1458 ret
= _SHStrDupAA(((LPCSTR
)&pidl
->mkid
)+pstr
->u
.uOffset
, ppszName
);
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
) {
1478 ret
= SHStrDupW(pstr
->u
.pOleStr
, ppszName
);
1479 CoTaskMemFree(pstr
->u
.pOleStr
);
1483 ret
= SHStrDupA(pstr
->u
.cStr
, ppszName
);
1487 ret
= SHStrDupA(((LPCSTR
)&pidl
->mkid
)+pstr
->u
.uOffset
, ppszName
);
1496 /*************************************************************************
1497 * StrFormatByteSizeA [SHLWAPI.@]
1499 LPSTR WINAPI
StrFormatByteSizeA ( DWORD dw
, LPSTR pszBuf
, UINT cchBuf
)
1501 TRACE("%lx %p %i\n", dw
, pszBuf
, cchBuf
);
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);
1512 { sprintf (buf
,"%3.1f GB", (FLOAT
)dw
/1073741824L);
1514 lstrcpynA (pszBuf
, buf
, cchBuf
);
1518 /*************************************************************************
1519 * StrFormatByteSizeW [SHLWAPI.@]
1521 LPWSTR WINAPI
StrFormatByteSizeW ( DWORD dw
, LPWSTR pszBuf
, UINT cchBuf
)
1524 StrFormatByteSizeA( dw
, buf
, sizeof(buf
) );
1525 if (!MultiByteToWideChar( CP_ACP
, 0, buf
, -1, pszBuf
, cchBuf
) && cchBuf
)
1526 pszBuf
[cchBuf
-1] = 0;
1530 /*************************************************************************
1531 * StrFormatKBSizeA [SHLWAPI.@]
1533 * Create a formatted string containing a byte count in Kilobytes.
1536 * llBytes [I] Byte size to format
1537 * lpszDest [I] Destination for formatted string
1538 * cchMax [I] Size of 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
);
1557 LONGLONG ulNextDigit
= ulKB
% 10;
1558 *szOut
-- = '0' + ulNextDigit
;
1559 ulKB
= (ulKB
- ulNextDigit
) / 10;
1562 strncpy(lpszDest
, szOut
+ 1, cchMax
);
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
);
1585 LONGLONG ulNextDigit
= ulKB
% 10;
1586 *szOut
-- = '0' + ulNextDigit
;
1587 ulKB
= (ulKB
- ulNextDigit
) / 10;
1590 strncpyW(lpszDest
, szOut
+ 1, cchMax
);
1594 /*************************************************************************
1595 * StrNCatA [SHLWAPI.@]
1597 * Concatenate two strings together.
1600 * lpszStr [O] String to concatenate to
1601 * lpszCat [I] String to add to lpszCat
1602 * cchMax [I] Maximum number of characters to concatenate
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
);
1619 WARN("Invalid lpszStr would crash under Win32!\n");
1623 StrCpyNA(lpszStr
+ strlen(lpszStr
), lpszCat
, cchMax
);
1627 /*************************************************************************
1628 * StrNCatW [SHLWAPI.@]
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
);
1640 WARN("Invalid lpszStr would crash under Win32\n");
1644 StrCpyNW(lpszStr
+ strlenW(lpszStr
), lpszCat
, cchMax
);
1648 /*************************************************************************
1649 * StrTrimA [SHLWAPI.@]
1651 * Remove characters from the start and end of a string.
1654 * lpszStr [O] String to remove characters from
1655 * lpszTrim [I] Characters to remove from lpszStr
1658 * TRUE If lpszStr was valid and modified
1661 BOOL WINAPI
StrTrimA(LPSTR lpszStr
, LPCSTR lpszTrim
)
1664 LPSTR lpszRead
= lpszStr
;
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);
1683 lpszRead
= lpszStr
+ dwLen
;
1684 while (StrChrA(lpszTrim
, lpszRead
[-1]))
1685 lpszRead
= CharPrevA(lpszStr
, lpszRead
); /* Skip trailing matches */
1687 if (lpszRead
!= lpszStr
+ dwLen
)
1697 /*************************************************************************
1698 * StrTrimW [SHLWAPI.@]
1702 BOOL WINAPI
StrTrimW(LPWSTR lpszStr
, LPCWSTR lpszTrim
)
1705 LPWSTR lpszRead
= lpszStr
;
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
));
1724 lpszRead
= lpszStr
+ dwLen
;
1725 while (StrChrW(lpszTrim
, lpszRead
[-1]))
1726 lpszRead
= CharPrevW(lpszStr
, lpszRead
); /* Skip trailing matches */
1728 if (lpszRead
!= lpszStr
+ dwLen
)
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
)
1749 len
= lstrlenA(src
);
1750 *dest
= CoTaskMemAlloc(len
);
1756 lstrcpynA(*dest
,src
, len
);
1762 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1766 /*************************************************************************
1769 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc.
1772 * lpszStr [I] String to copy
1773 * lppszDest [O] Destination for the new string copy
1776 * Success: S_OK. lppszDest contains the new string in Unicode format.
1777 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1780 HRESULT WINAPI
SHStrDupA(LPCSTR src
, LPWSTR
* dest
)
1786 len
= (MultiByteToWideChar(0,0,src
,-1,0,0) + 1)* sizeof(WCHAR
);
1787 *dest
= CoTaskMemAlloc(len
);
1793 MultiByteToWideChar(0,0,src
,-1,*dest
,len
);
1799 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
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
)
1814 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1815 *dest
= CoTaskMemAlloc(len
);
1821 WideCharToMultiByte(CP_ACP
, 0, src
, -1, *dest
, len
, NULL
, NULL
);
1827 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1831 /*************************************************************************
1836 HRESULT WINAPI
SHStrDupW(LPCWSTR src
, LPWSTR
* dest
)
1842 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1843 *dest
= CoTaskMemAlloc(len
);
1849 memcpy(*dest
, src
, len
);
1855 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1859 /*************************************************************************
1860 * SHLWAPI_WriteReverseNum
1862 * Internal helper for SHLWAPI_WriteTimeClass.
1864 inline static LPWSTR
SHLWAPI_WriteReverseNum(LPWSTR lpszOut
, DWORD dwNum
)
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);
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 */
1890 if (--dwDigits
== 0)
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
);
1913 strcpyW(szBuff
+ 32, lpszClass
);
1914 strcatW(lpszOut
, szOut
);
1918 /*************************************************************************
1919 * StrFromTimeIntervalA [SHLWAPI.@]
1921 * Format a millisecond time interval into a string
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
1930 * The length of the formatted string, or 0 if any parameter is invalid.
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
,
1952 TRACE("(%p,%d,%ld,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
1954 if (lpszStr
&& cchMax
)
1957 StrFromTimeIntervalW(szBuff
, sizeof(szBuff
)/sizeof(WCHAR
), dwMS
, iDigits
);
1958 WideCharToMultiByte(CP_ACP
,0,szBuff
,-1,lpszStr
,cchMax
,0,0);
1964 /*************************************************************************
1965 * StrFromTimeIntervalW [SHLWAPI.@]
1967 * See StrFromTimeIntervalA.
1969 INT WINAPI
StrFromTimeIntervalW(LPWSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
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'};
1977 TRACE("(%p,%d,%ld,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
1979 if (lpszStr
&& cchMax
)
1982 DWORD dwHours
, dwMinutes
;
1984 if (!iDigits
|| cchMax
== 1)
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;
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
);
2014 /*************************************************************************
2015 * StrIsIntlEqualA [SHLWAPI.@]
2017 * Compare two strings.
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
2026 * TRUE If the strings are equal.
2029 BOOL WINAPI
StrIsIntlEqualA(BOOL bCase
, LPCSTR lpszStr
, LPCSTR lpszComp
,
2032 DWORD dwFlags
= LOCALE_USE_CP_ACP
;
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
);
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
,
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
);
2075 iRet
= CompareStringW(2048, dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2077 return iRet
== 2 ? TRUE
: FALSE
;
2080 /*************************************************************************
2083 * Copy a string to another string, up to a maximum number of characters.
2086 * lpszDest [O] Destination string
2087 * lpszSrc [I] Source string
2088 * iLen [I] Maximum number of chars to copy
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
++;
2108 /*************************************************************************
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
++;