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"
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
40 #define NO_SHLWAPI_STREAM
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
48 static HRESULT WINAPI
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
);
49 static HRESULT WINAPI
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
);
51 /*************************************************************************
52 * SHLWAPI_ChrCmpHelperA
54 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
57 * Both this function and its Unicode counterpart are very inneficient. To
58 * fix this, CompareString must be completely implemented and optimised
59 * first. Then the core character test can be taken out of that function and
60 * placed here, so that it need never be called at all. Until then, do not
61 * attempt to optimise this code unless you are willing to test that it
62 * still performs correctly.
64 static BOOL WINAPI
SHLWAPI_ChrCmpHelperA(WORD ch1
, WORD ch2
, DWORD dwFlags
)
66 char str1
[3], str2
[3];
68 str1
[0] = LOBYTE(ch1
);
69 if (IsDBCSLeadByte(ch1
))
71 str1
[1] = HIBYTE(ch1
);
77 str2
[0] = LOBYTE(ch2
);
78 if (IsDBCSLeadByte(ch2
))
80 str2
[1] = HIBYTE(ch2
);
86 return CompareStringA(GetThreadLocale(), dwFlags
, str1
, -1, str2
, -1) - 2;
89 /*************************************************************************
90 * SHLWAPI_ChrCmpHelperW
92 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
94 static BOOL WINAPI
SHLWAPI_ChrCmpHelperW(WCHAR ch1
, WCHAR ch2
, DWORD dwFlags
)
96 WCHAR str1
[2], str2
[2];
102 return CompareStringW(GetThreadLocale(), dwFlags
, str1
, 2, str2
, 2) - 2;
105 /*************************************************************************
108 * Internal helper function.
110 static BOOL WINAPI
SHLWAPI_ChrCmpA(WORD ch1
, WORD ch2
)
112 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, 0);
115 /*************************************************************************
116 * ChrCmpIA (SHLWAPI.385)
118 * Compare two characters, ignoring case.
121 * ch1 [I] First character to compare
122 * ch2 [I] Second character to compare
125 * FALSE, if the characters are equal.
126 * Non-zero otherwise.
128 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
130 TRACE("(%d,%d)\n", ch1
, ch2
);
132 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, NORM_IGNORECASE
);
135 /*************************************************************************
138 * Internal helper function.
140 static BOOL WINAPI
SHLWAPI_ChrCmpW(WCHAR ch1
, WCHAR ch2
)
142 return SHLWAPI_ChrCmpHelperW(ch1
, ch2
, 0);
145 /*************************************************************************
146 * ChrCmpIW [SHLWAPI.386]
150 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
152 return SHLWAPI_ChrCmpHelperW(ch1
, ch2
, NORM_IGNORECASE
);
155 /*************************************************************************
156 * StrChrA [SHLWAPI.@]
158 * Find a given character in a string.
161 * lpszStr [I] String to search in.
162 * ch [I] Character to search for.
165 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
167 * Failure: NULL, if any arguments are invalid.
169 LPSTR WINAPI
StrChrA(LPCSTR lpszStr
, WORD ch
)
171 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
177 if (!SHLWAPI_ChrCmpA(*lpszStr
, ch
))
178 return (LPSTR
)lpszStr
;
179 lpszStr
= CharNextA(lpszStr
);
185 /*************************************************************************
186 * StrChrW [SHLWAPI.@]
190 LPWSTR WINAPI
StrChrW(LPCWSTR lpszStr
, WCHAR ch
)
192 LPWSTR lpszRet
= NULL
;
194 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
197 lpszRet
= strchrW(lpszStr
, ch
);
201 /*************************************************************************
202 * StrChrIA [SHLWAPI.@]
204 * Find a given character in a string, ignoring case.
207 * lpszStr [I] String to search in.
208 * ch [I] Character to search for.
211 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
213 * Failure: NULL, if any arguments are invalid.
215 LPSTR WINAPI
StrChrIA(LPCSTR lpszStr
, WORD ch
)
217 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
223 if (!ChrCmpIA(*lpszStr
, ch
))
224 return (LPSTR
)lpszStr
;
225 lpszStr
= CharNextA(lpszStr
);
231 /*************************************************************************
232 * StrChrIW [SHLWAPI.@]
236 LPWSTR WINAPI
StrChrIW(LPCWSTR lpszStr
, WCHAR ch
)
238 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
245 if (toupperW(*lpszStr
) == ch
)
246 return (LPWSTR
)lpszStr
;
247 lpszStr
= CharNextW(lpszStr
);
251 return (LPWSTR
)lpszStr
;
254 /*************************************************************************
255 * StrCmpIW [SHLWAPI.@]
257 * Compare two strings, ignoring case.
260 * lpszStr [I] First string to compare
261 * lpszComp [I] Second string to compare
264 * An integer less than, equal to or greater than 0, indicating that
265 * lpszStr is less than, the same, or greater than lpszComp.
267 int WINAPI
StrCmpIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
271 TRACE("(%s,%s)\n", debugstr_w(lpszStr
),debugstr_w(lpszComp
));
273 iRet
= strcmpiW(lpszStr
, lpszComp
);
274 return iRet
< 0 ? -1 : iRet
? 1 : 0;
277 /*************************************************************************
278 * SHLWAPI_StrCmpNHelperA
280 * Internal helper for StrCmpNA/StrCmpNIA.
282 static INT WINAPI
SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr
, LPCSTR lpszComp
,
284 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
300 ch1
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
301 ch2
= IsDBCSLeadByte(*lpszComp
)? *lpszComp
<< 8 | lpszComp
[1] : *lpszComp
;
303 if ((iDiff
= pChrCmpFn(ch1
, ch2
)) < 0)
307 else if (!*lpszStr
&& !*lpszComp
)
310 lpszStr
= CharNextA(lpszStr
);
311 lpszComp
= CharNextA(lpszComp
);
316 /*************************************************************************
317 * StrCmpNA [SHLWAPI.@]
319 * Compare two strings, up to a maximum length.
322 * lpszStr [I] First string to compare
323 * lpszComp [I] Second string to compare
324 * iLen [I] Maximum number of chars to compare.
327 * An integer less than, equal to or greater than 0, indicating that
328 * lpszStr is less than, the same, or greater than lpszComp.
330 INT WINAPI
StrCmpNA(LPCSTR lpszStr
, LPCSTR lpszComp
, INT iLen
)
332 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
334 return SHLWAPI_StrCmpNHelperA(lpszStr
, lpszComp
, iLen
, SHLWAPI_ChrCmpA
);
337 /*************************************************************************
338 * StrCmpNW [SHLWAPI.@]
342 INT WINAPI
StrCmpNW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, INT iLen
)
346 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
348 iRet
= strncmpW(lpszStr
, lpszComp
, iLen
);
349 return iRet
< 0 ? -1 : iRet
? 1 : 0;
352 /*************************************************************************
353 * StrCmpNIA [SHLWAPI.@]
355 * Compare two strings, up to a maximum length, ignoring case.
358 * lpszStr [I] First string to compare
359 * lpszComp [I] Second string to compare
360 * iLen [I] Maximum number of chars to compare.
363 * An integer less than, equal to or greater than 0, indicating that
364 * lpszStr is less than, the same, or greater than lpszComp.
367 * The Win32 version of this function is _completely_ broken for cases
368 * where iLen is greater than the length of lpszComp. Examples:
370 *| StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
371 *| StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
372 *| StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
374 * This implementation behaves correctly, since it is unlikely any
375 * applications actually rely on this function being broken.
377 int WINAPI
StrCmpNIA(LPCSTR lpszStr
, LPCSTR lpszComp
, int iLen
)
379 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
381 return SHLWAPI_StrCmpNHelperA(lpszStr
, lpszComp
, iLen
, ChrCmpIA
);
384 /*************************************************************************
385 * StrCmpNIW [SHLWAPI.@]
389 INT WINAPI
StrCmpNIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, int iLen
)
393 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
395 iRet
= strncmpiW(lpszStr
, lpszComp
, iLen
);
396 return iRet
< 0 ? -1 : iRet
? 1 : 0;
399 /*************************************************************************
400 * StrCmpW [SHLWAPI.@]
402 * Compare two strings.
405 * lpszStr [I] First string to compare
406 * lpszComp [I] Second string to compare
409 * An integer less than, equal to or greater than 0, indicating that
410 * lpszStr is less than, the same, or greater than lpszComp.
412 int WINAPI
StrCmpW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
416 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
418 iRet
= strcmpW(lpszStr
, lpszComp
);
419 return iRet
< 0 ? -1 : iRet
? 1 : 0;
422 /*************************************************************************
423 * StrCatW [SHLWAPI.@]
425 * Concatanate two strings.
428 * lpszStr [O] Initial string
429 * lpszSrc [I] String to concatanate
434 LPWSTR WINAPI
StrCatW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
436 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSrc
));
438 strcatW(lpszStr
, lpszSrc
);
442 /*************************************************************************
443 * StrCpyW [SHLWAPI.@]
445 * Copy a string to another string.
448 * lpszStr [O] Destination string
449 * lpszSrc [I] Source string
454 LPWSTR WINAPI
StrCpyW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
456 TRACE("(%p,%s)\n", lpszStr
, debugstr_w(lpszSrc
));
458 strcpyW(lpszStr
, lpszSrc
);
462 /*************************************************************************
463 * StrCpyNW [SHLWAPI.@]
465 * Copy a string to another string, up to a maximum number of characters.
468 * lpszStr [O] Destination string
469 * lpszSrc [I] Source string
470 * iLen [I] Maximum number of chars to copy
475 LPWSTR WINAPI
StrCpyNW(LPWSTR lpszStr
, LPCWSTR lpszSrc
, int iLen
)
477 TRACE("(%p,%s,%i)\n", lpszStr
, debugstr_w(lpszSrc
), iLen
);
479 lstrcpynW(lpszStr
, lpszSrc
, iLen
);
485 /*************************************************************************
486 * SHLWAPI_StrStrHelperA
488 * Internal implementation of StrStrA/StrStrIA
490 static LPSTR WINAPI
SHLWAPI_StrStrHelperA(LPCSTR lpszStr
, LPCSTR lpszSearch
,
491 int (*pStrCmpFn
)(LPCSTR
,LPCSTR
,size_t))
495 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
498 iLen
= strlen(lpszSearch
);
502 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
503 return (LPSTR
)lpszStr
;
504 lpszStr
= CharNextA(lpszStr
);
509 /*************************************************************************
510 * SHLWAPI_StrStrHelperW
512 * Internal implementation of StrStrW/StrStrIW
514 static LPWSTR WINAPI
SHLWAPI_StrStrHelperW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
,
515 int (*pStrCmpFn
)(LPCWSTR
,LPCWSTR
,int))
519 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
522 iLen
= strlenW(lpszSearch
);
526 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
527 return (LPWSTR
)lpszStr
;
528 lpszStr
= CharNextW(lpszStr
);
533 /*************************************************************************
534 * StrStrA [SHLWAPI.@]
536 * Find a substring within a string.
539 * lpszStr [I] String to search in
540 * lpszSearch [I] String to look for
543 * The start of lpszSearch within lpszStr, or NULL if not found.
545 LPSTR WINAPI
StrStrA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
547 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
549 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, strncmp
);
552 /*************************************************************************
553 * StrStrW [SHLWAPI.@]
557 LPWSTR WINAPI
StrStrW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
559 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
561 return SHLWAPI_StrStrHelperW(lpszStr
, lpszSearch
, strncmpW
);
564 /*************************************************************************
565 * StrRStrIA [SHLWAPI.@]
567 * Find the last occurence of a substring within a string.
570 * lpszStr [I] String to search in
571 * lpszEnd [I] End of lpszStr
572 * lpszSearch [I] String to look for
575 * The last occurence lpszSearch within lpszStr, or NULL if not found.
577 LPSTR WINAPI
StrRStrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, LPCSTR lpszSearch
)
579 LPSTR lpszRet
= NULL
;
583 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
585 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
589 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
591 if (IsDBCSLeadByte(*lpszSearch
))
592 ch1
= *lpszSearch
<< 8 | lpszSearch
[1];
595 iLen
= lstrlenA(lpszSearch
);
597 while (lpszStr
<= lpszEnd
&& *lpszStr
)
599 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
600 if (!ChrCmpIA(ch1
, ch2
))
602 if (!StrCmpNIA(lpszStr
, lpszSearch
, iLen
))
603 lpszRet
= (LPSTR
)lpszStr
;
605 lpszStr
= CharNextA(lpszStr
);
610 /*************************************************************************
611 * StrRStrIW [SHLWAPI.@]
615 LPWSTR WINAPI
StrRStrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, LPCWSTR lpszSearch
)
617 LPWSTR lpszRet
= NULL
;
620 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
622 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
626 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
628 iLen
= strlenW(lpszSearch
);
630 while (lpszStr
<= lpszEnd
&& *lpszStr
)
632 if (!ChrCmpIA(*lpszSearch
, *lpszStr
))
634 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
635 lpszRet
= (LPWSTR
)lpszStr
;
637 lpszStr
= CharNextW(lpszStr
);
642 /*************************************************************************
643 * StrStrIA [SHLWAPI.@]
645 * Find a substring within a string, ignoring case.
648 * lpszStr [I] String to search in
649 * lpszSearch [I] String to look for
652 * The start of lpszSearch within lpszStr, or NULL if not found.
654 LPSTR WINAPI
StrStrIA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
656 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
658 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, strncasecmp
);
661 /*************************************************************************
662 * StrStrIW [SHLWAPI.@]
666 LPWSTR WINAPI
StrStrIW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
668 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
670 return SHLWAPI_StrStrHelperW(lpszStr
, lpszSearch
, strncmpiW
);
673 /*************************************************************************
674 * StrToIntA [SHLWAPI.@]
676 * Read an integer from a string.
679 * lpszStr [I] String to read integer from
682 * The integer value represented by the string, or 0 if no integer is
686 * No leading space is allowed before the number, although a leading '-' is.
688 int WINAPI
StrToIntA(LPCSTR lpszStr
)
692 TRACE("(%s)\n", debugstr_a(lpszStr
));
696 WARN("Invalid lpszStr would crash under Win32!\n");
700 if (*lpszStr
== '-' || isdigit(*lpszStr
))
701 StrToIntExA(lpszStr
, 0, &iRet
);
705 /*************************************************************************
706 * StrToIntW [SHLWAPI.@]
710 int WINAPI
StrToIntW(LPCWSTR lpszStr
)
714 TRACE("(%s)\n", debugstr_w(lpszStr
));
718 WARN("Invalid lpszStr would crash under Win32!\n");
722 if (*lpszStr
== '-' || isdigitW(*lpszStr
))
723 StrToIntExW(lpszStr
, 0, &iRet
);
727 /*************************************************************************
728 * StrToIntExA [SHLWAPI.@]
730 * Read an integer from a string.
733 * lpszStr [I] String to read integer from
734 * dwFlags [I] Flags controlling the conversion
735 * lpiRet [O] Destination for read integer.
738 * Success: TRUE. lpiRet contains the integer value represented by the string.
739 * Failure: FALSE, if the string is invalid, or no number is present.
742 * Leading whitespace, '-' and '+' are allowed before the number. If
743 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
744 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
745 * the string is treated as a decimal string. A leading '-' is ignored for
746 * hexidecimal numbers.
748 BOOL WINAPI
StrToIntExA(LPCSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
750 BOOL bNegative
= FALSE
;
753 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
755 if (!lpszStr
|| !lpiRet
)
757 WARN("Invalid parameter would crash under Win32!\n");
760 if (dwFlags
> STIF_SUPPORT_HEX
)
762 WARN("Unknown flags (%08lX)!\n", dwFlags
& ~STIF_SUPPORT_HEX
);
765 /* Skip leading space, '+', '-' */
766 while (isspace(*lpszStr
))
767 lpszStr
= CharNextA(lpszStr
);
774 else if (*lpszStr
== '+')
777 if (dwFlags
& STIF_SUPPORT_HEX
&&
778 *lpszStr
== '0' && tolower(lpszStr
[1]) == 'x')
780 /* Read hex number */
783 if (!isxdigit(*lpszStr
))
786 while (isxdigit(*lpszStr
))
789 if (isdigit(*lpszStr
))
790 iRet
+= (*lpszStr
- '0');
792 iRet
+= 10 + (tolower(*lpszStr
) - 'a');
799 /* Read decimal number */
800 if (!isdigit(*lpszStr
))
803 while (isdigit(*lpszStr
))
806 iRet
+= (*lpszStr
- '0');
809 *lpiRet
= bNegative
? -iRet
: iRet
;
813 /*************************************************************************
814 * StrToIntExW [SHLWAPI.@]
818 BOOL WINAPI
StrToIntExW(LPCWSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
820 BOOL bNegative
= FALSE
;
823 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
825 if (!lpszStr
|| !lpiRet
)
827 WARN("Invalid parameter would crash under Win32!\n");
830 if (dwFlags
> STIF_SUPPORT_HEX
)
832 WARN("Unknown flags (%08lX)!\n", dwFlags
& ~STIF_SUPPORT_HEX
);
835 /* Skip leading space, '+', '-' */
836 while (isspaceW(*lpszStr
))
837 lpszStr
= CharNextW(lpszStr
);
844 else if (*lpszStr
== '+')
847 if (dwFlags
& STIF_SUPPORT_HEX
&&
848 *lpszStr
== '0' && tolowerW(lpszStr
[1]) == 'x')
850 /* Read hex number */
853 if (!isxdigitW(*lpszStr
))
856 while (isxdigitW(*lpszStr
))
859 if (isdigitW(*lpszStr
))
860 iRet
+= (*lpszStr
- '0');
862 iRet
+= 10 + (tolowerW(*lpszStr
) - 'a');
869 /* Read decimal number */
870 if (!isdigitW(*lpszStr
))
873 while (isdigitW(*lpszStr
))
876 iRet
+= (*lpszStr
- '0');
879 *lpiRet
= bNegative
? -iRet
: iRet
;
883 /*************************************************************************
884 * StrDupA [SHLWAPI.@]
886 * Duplicate a string.
889 * lpszStr [I] String to duplicate.
892 * Success: A pointer to a new string containing the contents of lpszStr
893 * Failure: NULL, if memory cannot be allocated
896 * The string memory is allocated with LocalAlloc(), and so should be released
897 * by calling LocalFree().
899 LPSTR WINAPI
StrDupA(LPCSTR lpszStr
)
904 TRACE("(%s)\n",debugstr_a(lpszStr
));
906 iLen
= lpszStr
? strlen(lpszStr
) + 1 : 1;
907 lpszRet
= (LPSTR
)LocalAlloc(LMEM_FIXED
, iLen
);
912 memcpy(lpszRet
, lpszStr
, iLen
);
919 /*************************************************************************
920 * StrDupW [SHLWAPI.@]
924 LPWSTR WINAPI
StrDupW(LPCWSTR lpszStr
)
929 TRACE("(%s)\n",debugstr_w(lpszStr
));
931 iLen
= (lpszStr
? strlenW(lpszStr
) + 1 : 1) * sizeof(WCHAR
);
932 lpszRet
= (LPWSTR
)LocalAlloc(LMEM_FIXED
, iLen
);
937 memcpy(lpszRet
, lpszStr
, iLen
);
944 /*************************************************************************
945 * SHLWAPI_StrSpnHelperA
947 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
949 static int WINAPI
SHLWAPI_StrSpnHelperA(LPCSTR lpszStr
, LPCSTR lpszMatch
,
950 LPSTR (WINAPI
*pStrChrFn
)(LPCSTR
,WORD
),
953 LPCSTR lpszRead
= lpszStr
;
954 if (lpszStr
&& *lpszStr
&& lpszMatch
)
958 LPCSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
960 if (!bInvert
&& !lpszTest
)
962 if (bInvert
&& lpszTest
)
964 lpszRead
= CharNextA(lpszRead
);
967 return lpszRead
- lpszStr
;
970 /*************************************************************************
971 * SHLWAPI_StrSpnHelperW
973 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
975 static int WINAPI
SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
,
976 LPWSTR (WINAPI
*pStrChrFn
)(LPCWSTR
,WCHAR
),
979 LPCWSTR lpszRead
= lpszStr
;
980 if (lpszStr
&& *lpszStr
&& lpszMatch
)
984 LPCWSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
986 if (!bInvert
&& !lpszTest
)
988 if (bInvert
&& lpszTest
)
990 lpszRead
= CharNextW(lpszRead
);
993 return lpszRead
- lpszStr
;
996 /*************************************************************************
997 * StrSpnA [SHLWAPI.@]
999 * Find the length of the start of a string that contains only certain
1003 * lpszStr [I] String to search
1004 * lpszMatch [I] Characters that can be in the substring
1007 * The length of the part of lpszStr containing only chars from lpszMatch,
1008 * or 0 if any parameter is invalid.
1010 int WINAPI
StrSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1012 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1014 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, FALSE
);
1017 /*************************************************************************
1018 * StrSpnW [SHLWAPI.@]
1022 int WINAPI
StrSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1024 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1026 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrW
, FALSE
);
1029 /*************************************************************************
1030 * StrCSpnA [SHLWAPI.@]
1032 * Find the length of the start of a string that does not contain certain
1036 * lpszStr [I] String to search
1037 * lpszMatch [I] Characters that cannot be in the substring
1040 * The length of the part of lpszStr containing only chars not in lpszMatch,
1041 * or 0 if any parameter is invalid.
1043 int WINAPI
StrCSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1045 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1047 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, TRUE
);
1050 /*************************************************************************
1051 * StrCSpnW [SHLWAPI.@]
1055 int WINAPI
StrCSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1057 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1059 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrW
, TRUE
);
1062 /*************************************************************************
1063 * StrCSpnIA [SHLWAPI.@]
1065 * Find the length of the start of a string that does not contain certain
1066 * characters, ignoring case.
1069 * lpszStr [I] String to search
1070 * lpszMatch [I] Characters that cannot be in the substring
1073 * The length of the part of lpszStr containing only chars not in lpszMatch,
1074 * or 0 if any parameter is invalid.
1076 int WINAPI
StrCSpnIA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1078 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1080 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrIA
, TRUE
);
1083 /*************************************************************************
1084 * StrCSpnIW [SHLWAPI.@]
1088 int WINAPI
StrCSpnIW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1090 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1092 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrIW
, TRUE
);
1095 /*************************************************************************
1096 * StrPBrkA [SHLWAPI.@]
1098 * Search a string for any of a group of characters.
1101 * lpszStr [I] String to search
1102 * lpszMatch [I] Characters to match
1105 * A pointer to the first matching character in lpszStr, or NULL if no
1108 LPSTR WINAPI
StrPBrkA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1110 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1112 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1116 if (StrChrA(lpszMatch
, *lpszStr
))
1117 return (LPSTR
)lpszStr
;
1118 lpszStr
= CharNextA(lpszStr
);
1124 /*************************************************************************
1125 * StrPBrkW [SHLWAPI.@]
1129 LPWSTR WINAPI
StrPBrkW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1131 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1133 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1137 if (StrChrW(lpszMatch
, *lpszStr
))
1138 return (LPWSTR
)lpszStr
;
1139 lpszStr
= CharNextW(lpszStr
);
1145 /*************************************************************************
1146 * SHLWAPI_StrRChrHelperA
1148 * Internal implementation of StrRChrA/StrRChrIA.
1150 static LPSTR WINAPI
SHLWAPI_StrRChrHelperA(LPCSTR lpszStr
,
1151 LPCSTR lpszEnd
, WORD ch
,
1152 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
1154 LPCSTR lpszRet
= NULL
;
1161 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
1163 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1165 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
1167 if (!pChrCmpFn(ch
, ch2
))
1169 lpszStr
= CharNextA(lpszStr
);
1172 return (LPSTR
)lpszRet
;
1175 /*************************************************************************
1176 * SHLWAPI_StrRChrHelperW
1178 * Internal implementation of StrRChrW/StrRChrIW.
1180 static LPWSTR WINAPI
SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr
,
1181 LPCWSTR lpszEnd
, WCHAR ch
,
1182 BOOL (WINAPI
*pChrCmpFn
)(WCHAR
,WCHAR
))
1184 LPCWSTR lpszRet
= NULL
;
1189 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
1191 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1193 if (!pChrCmpFn(ch
, *lpszStr
))
1195 lpszStr
= CharNextW(lpszStr
);
1198 return (LPWSTR
)lpszRet
;
1201 /**************************************************************************
1202 * StrRChrA [SHLWAPI.@]
1204 * Find the last occurence of a character in string.
1207 * lpszStr [I] String to search in
1208 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1209 * ch [I] Character to search for.
1212 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1213 * or NULL if not found.
1214 * Failure: NULL, if any arguments are invalid.
1216 LPSTR WINAPI
StrRChrA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1218 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1220 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpA
);
1223 /**************************************************************************
1224 * StrRChrW [SHLWAPI.@]
1228 LPWSTR WINAPI
StrRChrW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, WORD ch
)
1230 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr
), debugstr_w(lpszEnd
), ch
);
1232 return SHLWAPI_StrRChrHelperW(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpW
);
1235 /**************************************************************************
1236 * StrRChrIA [SHLWAPI.@]
1238 * Find the last occurence of a character in string, ignoring case.
1241 * lpszStr [I] String to search in
1242 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1243 * ch [I] Character to search for.
1246 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1247 * or NULL if not found.
1248 * Failure: NULL, if any arguments are invalid.
1250 LPSTR WINAPI
StrRChrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1252 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1254 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, ChrCmpIA
);
1257 /**************************************************************************
1258 * StrRChrIW [SHLWAPI.@]
1262 LPWSTR WINAPI
StrRChrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, WORD ch
)
1264 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr
), debugstr_w(lpszEnd
), ch
);
1266 return SHLWAPI_StrRChrHelperW(lpszStr
, lpszEnd
, ch
, ChrCmpIW
);
1269 /*************************************************************************
1270 * StrCatBuffA [SHLWAPI.@]
1272 * Concatenate two strings together.
1275 * lpszStr [O] String to concatenate to
1276 * lpszCat [I] String to add to lpszCat
1277 * cchMax [I] Maximum number of characters for the whole string
1283 * cchMax dtermines the number of characters in the final length of the
1284 * string, not the number appended to lpszStr from lpszCat.
1286 LPSTR WINAPI
StrCatBuffA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1290 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_a(lpszCat
), cchMax
);
1294 WARN("Invalid lpszStr would crash under Win32!\n");
1298 iLen
= strlen(lpszStr
);
1302 StrCpyNA(lpszStr
+ iLen
, lpszCat
, cchMax
);
1306 /*************************************************************************
1307 * StrCatBuffW [SHLWAPI.@]
1311 LPWSTR WINAPI
StrCatBuffW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1315 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_w(lpszCat
), cchMax
);
1319 WARN("Invalid lpszStr would crash under Win32!\n");
1323 iLen
= strlenW(lpszStr
);
1327 StrCpyNW(lpszStr
+ iLen
, lpszCat
, cchMax
);
1331 /*************************************************************************
1332 * StrRetToBufA [SHLWAPI.@]
1334 * Convert a STRRET to a normal string.
1337 * lpStrRet [O] STRRET to convert
1338 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1339 * lpszDest [O] Destination for normal string
1340 * dwLen [I] Length of lpszDest
1343 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1344 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1345 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1346 * Failure: E_FAIL, if any parameters are invalid.
1348 HRESULT WINAPI
StrRetToBufA (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPSTR dest
, DWORD len
)
1351 * This routine is identical to that in dlls/shell32/shellstring.c.
1352 * It was duplicated because not every version of Shlwapi.dll exports
1353 * StrRetToBufA. If you change one routine, change them both.
1355 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest
,len
,src
,pidl
);
1359 WARN("Invalid lpStrRet would crash under Win32!\n");
1373 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, dest
, len
, NULL
, NULL
);
1374 CoTaskMemFree(src
->u
.pOleStr
);
1378 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
1382 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
1386 FIXME("unknown type!\n");
1392 /*************************************************************************
1393 * StrRetToBufW [SHLWAPI.@]
1397 HRESULT WINAPI
StrRetToBufW (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPWSTR dest
, DWORD len
)
1399 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest
,len
,src
,pidl
);
1403 WARN("Invalid lpStrRet would crash under Win32!\n");
1417 lstrcpynW((LPWSTR
)dest
, src
->u
.pOleStr
, len
);
1418 CoTaskMemFree(src
->u
.pOleStr
);
1422 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
1429 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1,
1436 FIXME("unknown type!\n");
1442 /*************************************************************************
1443 * StrRetToStrA [SHLWAPI.@]
1445 * converts a STRRET to a normal string
1447 HRESULT WINAPI
StrRetToStrA(LPSTRRET pstr
, const ITEMIDLIST
* pidl
, LPSTR
* ppszName
)
1449 HRESULT ret
= E_FAIL
;
1451 switch (pstr
->uType
) {
1453 ret
= _SHStrDupAW(pstr
->u
.pOleStr
, ppszName
);
1454 CoTaskMemFree(pstr
->u
.pOleStr
);
1458 ret
= _SHStrDupAA(pstr
->u
.cStr
, ppszName
);
1462 ret
= _SHStrDupAA(((LPCSTR
)&pidl
->mkid
)+pstr
->u
.uOffset
, ppszName
);
1471 /*************************************************************************
1472 * StrRetToStrW [SHLWAPI.@]
1474 * converts a STRRET to a normal string
1476 HRESULT WINAPI
StrRetToStrW(LPSTRRET pstr
, const ITEMIDLIST
* pidl
, LPWSTR
* ppszName
)
1478 HRESULT ret
= E_FAIL
;
1480 switch (pstr
->uType
) {
1482 ret
= SHStrDupW(pstr
->u
.pOleStr
, ppszName
);
1483 CoTaskMemFree(pstr
->u
.pOleStr
);
1487 ret
= SHStrDupA(pstr
->u
.cStr
, ppszName
);
1491 ret
= SHStrDupA(((LPCSTR
)&pidl
->mkid
)+pstr
->u
.uOffset
, ppszName
);
1500 /*************************************************************************
1501 * StrFormatKBSizeA [SHLWAPI.@]
1503 * Create a formatted string containing a byte count in Kilobytes.
1506 * llBytes [I] Byte size to format
1507 * lpszDest [I] Destination for formatted string
1508 * cchMax [I] Size of lpszDest
1513 LPSTR WINAPI
StrFormatKBSizeA(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
1515 char szBuff
[256], *szOut
= szBuff
+ sizeof(szBuff
) - 1;
1516 LONGLONG ulKB
= (llBytes
+ 1023) >> 10;
1518 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
1527 LONGLONG ulNextDigit
= ulKB
% 10;
1528 *szOut
-- = '0' + ulNextDigit
;
1529 ulKB
= (ulKB
- ulNextDigit
) / 10;
1532 strncpy(lpszDest
, szOut
+ 1, cchMax
);
1536 /*************************************************************************
1537 * StrFormatKBSizeW [SHLWAPI.@]
1539 * See StrFormatKBSizeA.
1541 LPWSTR WINAPI
StrFormatKBSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
1543 WCHAR szBuff
[256], *szOut
= szBuff
+ sizeof(szBuff
) - 1;
1544 LONGLONG ulKB
= (llBytes
+ 1023) >> 10;
1546 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
1555 LONGLONG ulNextDigit
= ulKB
% 10;
1556 *szOut
-- = '0' + ulNextDigit
;
1557 ulKB
= (ulKB
- ulNextDigit
) / 10;
1560 strncpyW(lpszDest
, szOut
+ 1, cchMax
);
1564 /*************************************************************************
1565 * StrNCatA [SHLWAPI.@]
1567 * Concatenate two strings together.
1570 * lpszStr [O] String to concatenate to
1571 * lpszCat [I] String to add to lpszCat
1572 * cchMax [I] Maximum number of characters to concatenate
1578 * cchMax dtermines the number of characters that are appended to lpszStr,
1579 * not the total length of the string.
1581 LPSTR WINAPI
StrNCatA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1583 LPSTR lpszRet
= lpszStr
;
1585 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszCat
), cchMax
);
1589 WARN("Invalid lpszStr would crash under Win32!\n");
1593 StrCpyNA(lpszStr
+ strlen(lpszStr
), lpszCat
, cchMax
);
1597 /*************************************************************************
1598 * StrNCatW [SHLWAPI.@]
1602 LPWSTR WINAPI
StrNCatW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1604 LPWSTR lpszRet
= lpszStr
;
1606 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszCat
), cchMax
);
1610 WARN("Invalid lpszStr would crash under Win32\n");
1614 StrCpyNW(lpszStr
+ strlenW(lpszStr
), lpszCat
, cchMax
);
1618 /*************************************************************************
1619 * StrTrimA [SHLWAPI.@]
1621 * Remove characters from the start and end of a string.
1624 * lpszStr [O] String to remove characters from
1625 * lpszTrim [I] Characters to remove from lpszStr
1628 * TRUE If lpszStr was valid and modified
1631 BOOL WINAPI
StrTrimA(LPSTR lpszStr
, LPCSTR lpszTrim
)
1634 LPSTR lpszRead
= lpszStr
;
1637 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszTrim
));
1639 if (lpszRead
&& *lpszRead
)
1641 while (*lpszRead
&& StrChrA(lpszTrim
, *lpszRead
))
1642 lpszRead
= CharNextA(lpszRead
); /* Skip leading matches */
1644 dwLen
= strlen(lpszRead
);
1646 if (lpszRead
!= lpszStr
)
1648 memmove(lpszStr
, lpszRead
, dwLen
+ 1);
1653 lpszRead
= lpszStr
+ dwLen
;
1654 while (StrChrA(lpszTrim
, lpszRead
[-1]))
1655 lpszRead
= CharPrevA(lpszStr
, lpszRead
); /* Skip trailing matches */
1657 if (lpszRead
!= lpszStr
+ dwLen
)
1667 /*************************************************************************
1668 * StrTrimW [SHLWAPI.@]
1672 BOOL WINAPI
StrTrimW(LPWSTR lpszStr
, LPCWSTR lpszTrim
)
1675 LPWSTR lpszRead
= lpszStr
;
1678 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszTrim
));
1680 if (lpszRead
&& *lpszRead
)
1682 while (*lpszRead
&& StrChrW(lpszTrim
, *lpszRead
))
1683 lpszRead
= CharNextW(lpszRead
); /* Skip leading matches */
1685 dwLen
= strlenW(lpszRead
);
1687 if (lpszRead
!= lpszStr
)
1689 memmove(lpszStr
, lpszRead
, (dwLen
+ 1) * sizeof(WCHAR
));
1694 lpszRead
= lpszStr
+ dwLen
;
1695 while (StrChrW(lpszTrim
, lpszRead
[-1]))
1696 lpszRead
= CharPrevW(lpszStr
, lpszRead
); /* Skip trailing matches */
1698 if (lpszRead
!= lpszStr
+ dwLen
)
1708 /*************************************************************************
1709 * _SHStrDupA [INTERNAL]
1711 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1713 static HRESULT WINAPI
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
)
1719 len
= lstrlenA(src
) + 1;
1720 *dest
= CoTaskMemAlloc(len
);
1726 lstrcpynA(*dest
,src
, len
);
1732 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1736 /*************************************************************************
1739 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1742 * lpszStr [I] String to copy
1743 * lppszDest [O] Destination for the new string copy
1746 * Success: S_OK. lppszDest contains the new string in Unicode format.
1747 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1750 HRESULT WINAPI
SHStrDupA(LPCSTR src
, LPWSTR
* dest
)
1756 len
= MultiByteToWideChar(0,0,src
,-1,0,0)* sizeof(WCHAR
);
1757 *dest
= CoTaskMemAlloc(len
);
1763 MultiByteToWideChar(0,0,src
,-1,*dest
,len
);
1769 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1773 /*************************************************************************
1774 * _SHStrDupAW [INTERNAL]
1776 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1778 static HRESULT WINAPI
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
)
1784 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1785 *dest
= CoTaskMemAlloc(len
);
1791 WideCharToMultiByte(CP_ACP
, 0, src
, -1, *dest
, len
, NULL
, NULL
);
1797 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1801 /*************************************************************************
1806 HRESULT WINAPI
SHStrDupW(LPCWSTR src
, LPWSTR
* dest
)
1812 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1813 *dest
= CoTaskMemAlloc(len
);
1819 memcpy(*dest
, src
, len
);
1825 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1829 /*************************************************************************
1830 * SHLWAPI_WriteReverseNum
1832 * Internal helper for SHLWAPI_WriteTimeClass.
1834 inline static LPWSTR
SHLWAPI_WriteReverseNum(LPWSTR lpszOut
, DWORD dwNum
)
1838 /* Write a decimal number to a string, backwards */
1841 DWORD dwNextDigit
= dwNum
% 10;
1842 *lpszOut
-- = '0' + dwNextDigit
;
1843 dwNum
= (dwNum
- dwNextDigit
) / 10;
1844 } while (dwNum
> 0);
1849 /*************************************************************************
1850 * SHLWAPI_FormatSignificant
1852 * Internal helper for SHLWAPI_WriteTimeClass.
1854 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum
, int dwDigits
)
1856 /* Zero non significant digits, return remaining significant digits */
1860 if (--dwDigits
== 0)
1870 /*************************************************************************
1871 * SHLWAPI_WriteTimeClass
1873 * Internal helper for StrFromTimeIntervalW.
1875 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut
, DWORD dwValue
,
1876 LPCWSTR lpszClass
, int iDigits
)
1878 WCHAR szBuff
[64], *szOut
= szBuff
+ 32;
1880 szOut
= SHLWAPI_WriteReverseNum(szOut
, dwValue
);
1881 iDigits
= SHLWAPI_FormatSignificant(szOut
+ 1, iDigits
);
1883 strcpyW(szBuff
+ 32, lpszClass
);
1884 strcatW(lpszOut
, szOut
);
1888 /*************************************************************************
1889 * StrFromTimeIntervalA [SHLWAPI.@]
1891 * Format a millisecond time interval into a string
1894 * lpszStr [O] Output buffer for formatted time interval
1895 * cchMax [I] Size of lpszStr
1896 * dwMS [I] Number of milliseconds
1897 * iDigits [I] Number of digits to print
1900 * The length of the formatted string, or 0 if any parameter is invalid.
1903 * This implementation mimics the Win32 behaviour of always writing a leading
1904 * space before the time interval begins.
1906 * iDigits is used to provide approximate times if accuracy is not important.
1907 * This number of digits will be written of the first non-zero time class
1908 * (hours/minutes/seconds). If this does not complete the time classification,
1909 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1910 * If there are digits remaining following the writing of a time class, the
1911 * next time class will be written.
1913 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1914 * following will result from the given values of iDigits:
1916 *| iDigits 1 2 3 4 5 ...
1917 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1919 INT WINAPI
StrFromTimeIntervalA(LPSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
1924 TRACE("(%p,%d,%ld,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
1926 if (lpszStr
&& cchMax
)
1929 StrFromTimeIntervalW(szBuff
, sizeof(szBuff
)/sizeof(WCHAR
), dwMS
, iDigits
);
1930 WideCharToMultiByte(CP_ACP
,0,szBuff
,-1,lpszStr
,cchMax
,0,0);
1936 /*************************************************************************
1937 * StrFromTimeIntervalW [SHLWAPI.@]
1939 * See StrFromTimeIntervalA.
1941 INT WINAPI
StrFromTimeIntervalW(LPWSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
1944 static const WCHAR szHr
[] = {' ','h','r','\0'};
1945 static const WCHAR szMin
[] = {' ','m','i','n','\0'};
1946 static const WCHAR szSec
[] = {' ','s','e','c','\0'};
1949 TRACE("(%p,%d,%ld,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
1951 if (lpszStr
&& cchMax
)
1954 DWORD dwHours
, dwMinutes
;
1956 if (!iDigits
|| cchMax
== 1)
1962 /* Calculate the time classes */
1963 dwMS
= (dwMS
+ 500) / 1000;
1964 dwHours
= dwMS
/ 3600;
1965 dwMS
-= dwHours
* 3600;
1966 dwMinutes
= dwMS
/ 60;
1967 dwMS
-= dwMinutes
* 60;
1972 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwHours
, szHr
, iDigits
);
1974 if (dwMinutes
&& iDigits
)
1975 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwMinutes
, szMin
, iDigits
);
1977 if (iDigits
) /* Always write seconds if we have significant digits */
1978 SHLWAPI_WriteTimeClass(szCopy
, dwMS
, szSec
, iDigits
);
1980 strncpyW(lpszStr
, szCopy
, cchMax
);
1981 iRet
= strlenW(lpszStr
);
1986 /*************************************************************************
1987 * StrIsIntlEqualA [SHLWAPI.@]
1989 * Compare two strings.
1992 * bCase [I] Whether to compare case sensitively
1993 * lpszStr [I] First string to compare
1994 * lpszComp [I] Second string to compare
1995 * iLen [I] Length to compare
1998 * TRUE If the strings are equal.
2001 BOOL WINAPI
StrIsIntlEqualA(BOOL bCase
, LPCSTR lpszStr
, LPCSTR lpszComp
,
2004 DWORD dwFlags
= LOCALE_USE_CP_ACP
;
2007 TRACE("(%d,%s,%s,%d)\n", bCase
,
2008 debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
2010 /* FIXME: These flags are undocumented and unknown by our CompareString.
2011 * We need defines for them.
2013 dwFlags
|= bCase
? 0x10000000 : 0x10000001;
2015 iRet
= CompareStringA(GetThreadLocale(),
2016 dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2019 iRet
= CompareStringA(2048, dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2021 return iRet
== 2 ? TRUE
: FALSE
;
2024 /*************************************************************************
2025 * StrIsIntlEqualW [SHLWAPI.@]
2027 * See StrIsIntlEqualA.
2029 BOOL WINAPI
StrIsIntlEqualW(BOOL bCase
, LPCWSTR lpszStr
, LPCWSTR lpszComp
,
2035 TRACE("(%d,%s,%s,%d)\n", bCase
,
2036 debugstr_w(lpszStr
),debugstr_w(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
= CompareStringW(GetThreadLocale(),
2044 dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2047 iRet
= CompareStringW(2048, dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
);
2049 return iRet
== 2 ? TRUE
: FALSE
;
2052 /*************************************************************************
2055 * Copy a string to another string, up to a maximum number of characters.
2058 * lpszDest [O] Destination string
2059 * lpszSrc [I] Source string
2060 * iLen [I] Maximum number of chars to copy
2063 * Success: A pointer to the last character written.
2064 * Failure: lpszDest, if any arguments are invalid.
2066 LPSTR WINAPI
SHLWAPI_399(LPSTR lpszDest
, LPCSTR lpszSrc
, int iLen
)
2068 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_a(lpszSrc
), iLen
);
2070 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2072 while ((iLen
-- > 1) && *lpszSrc
)
2073 *lpszDest
++ = *lpszSrc
++;
2080 /*************************************************************************
2083 * Unicode version of SHLWAPI_399.
2085 LPWSTR WINAPI
SHLWAPI_400(LPWSTR lpszDest
, LPCWSTR lpszSrc
, int iLen
)
2087 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_w(lpszSrc
), iLen
);
2089 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2091 while ((iLen
-- > 1) && *lpszSrc
)
2092 *lpszDest
++ = *lpszSrc
++;
2099 /*************************************************************************
2100 * StrCmpLogicalW [SHLWAPI.@]
2102 * Compare two strings, ignoring case and comparing digits as numbers.
2105 * lpszStr [I] First string to compare
2106 * lpszComp [I] Second string to compare
2107 * iLen [I] Length to compare
2110 * TRUE If the strings are equal.
2113 INT WINAPI
StrCmpLogicalW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
2117 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
2119 if (lpszStr
&& lpszComp
)
2125 else if (isdigitW(*lpszStr
))
2129 if (!isdigitW(*lpszComp
))
2132 /* Compare the numbers */
2133 StrToIntExW(lpszStr
, 0, &iStr
);
2134 StrToIntExW(lpszComp
, 0, &iComp
);
2138 else if (iStr
> iComp
)
2142 while (isdigitW(*lpszStr
))
2144 while (isdigitW(*lpszComp
))
2147 else if (isdigitW(*lpszComp
))
2151 iDiff
= SHLWAPI_ChrCmpHelperA(*lpszStr
,*lpszComp
,NORM_IGNORECASE
);
2167 /* Structure for formatting byte strings */
2168 typedef struct tagSHLWAPI_BYTEFORMATS
2175 } SHLWAPI_BYTEFORMATS
;
2177 /*************************************************************************
2178 * StrFormatByteSize64A [SHLWAPI.@]
2180 * Create a string containing an abbreviated byte count of up to 2^63-1.
2183 * llBytes [I] Byte size to format
2184 * lpszDest [I] Destination for formatted string
2185 * cchMax [I] Size of lpszDest
2191 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2193 LPSTR WINAPI
StrFormatByteSize64A(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
2195 static const char szBytes
[] = "%ld bytes";
2196 static const char sz3_0
[] = "%3.0f";
2197 static const char sz3_1
[] = "%3.1f";
2198 static const char sz3_2
[] = "%3.2f";
2200 static const SHLWAPI_BYTEFORMATS bfFormats
[] =
2202 { 10240, 10.24, 100.0, sz3_2
, 'K' }, /* 10 KB */
2203 { 102400, 102.4, 10.0, sz3_1
, 'K' }, /* 100 KB */
2204 { 1024000, 1024.0, 1.0, sz3_0
, 'K' }, /* 1000 KB */
2205 { 10485760, 10485.76, 100.0, sz3_2
, 'M' }, /* 10 MB */
2206 { 104857600, 104857.6, 10.0, sz3_1
, 'M' }, /* 100 MB */
2207 { 1048576000, 1048576.0, 1.0, sz3_0
, 'M' }, /* 1000 MB */
2208 { 10737418240, 10737418.24, 100.0, sz3_2
, 'G' }, /* 10 GB */
2209 { 107374182400, 107374182.4, 10.0, sz3_1
, 'G' }, /* 100 GB */
2210 { 1073741824000, 1073741824.0, 1.0, sz3_0
, 'G' }, /* 1000 GB */
2211 { 10995116277760, 10485.76, 100.0, sz3_2
, 'T' }, /* 10 TB */
2212 { 109951162777600, 104857.6, 10.0, sz3_1
, 'T' }, /* 100 TB */
2213 { 1099511627776000, 1048576.0, 1.0, sz3_0
, 'T' }, /* 1000 TB */
2214 { 11258999068426240, 10737418.24, 100.00, sz3_2
, 'P' }, /* 10 PB */
2215 { 112589990684262400, 107374182.4, 10.00, sz3_1
, 'P' }, /* 100 PB */
2216 { 1125899906842624000, 1073741824.0, 1.00, sz3_0
, 'P' }, /* 1000 PB */
2217 { 0, 10995116277.76, 100.00, sz3_2
, 'E' } /* EB's, catch all */
2224 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
2226 if (!lpszDest
|| !cchMax
)
2229 if (llBytes
< 1024) /* 1K */
2231 snprintf (lpszDest
, cchMax
, szBytes
, (long)llBytes
);
2235 /* Note that if this loop completes without finding a match, i will be
2236 * pointing at the last entry, which is a catch all for > 1000 PB
2238 while (i
< sizeof(bfFormats
) / sizeof(SHLWAPI_BYTEFORMATS
) - 1)
2240 if (llBytes
< bfFormats
[i
].dLimit
)
2244 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2245 * this number we integer shift down by 1 MB first. The table above has
2246 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2247 * for this. We also add a small fudge factor to get the correct result for
2248 * counts that lie exactly on a 1024 byte boundary.
2251 dBytes
= (double)(llBytes
>> 20) + 0.001; /* Scale down by I MB */
2253 dBytes
= (double)llBytes
+ 0.00001;
2255 dBytes
= floor(dBytes
/ bfFormats
[i
].dDivisor
) / bfFormats
[i
].dNormaliser
;
2257 sprintf(szBuff
, bfFormats
[i
].lpszFormat
, dBytes
);
2259 szAdd
[1] = bfFormats
[i
].wPrefix
;
2262 strcat(szBuff
, szAdd
);
2263 strncpy(lpszDest
, szBuff
, cchMax
);
2267 /*************************************************************************
2268 * StrFormatByteSizeW [SHLWAPI.@]
2270 * See StrFormatByteSize64A.
2272 LPWSTR WINAPI
StrFormatByteSizeW(LONGLONG llBytes
, LPWSTR lpszDest
,
2277 StrFormatByteSize64A(llBytes
, szBuff
, sizeof(szBuff
));
2280 MultiByteToWideChar(CP_ACP
, 0, szBuff
, -1, lpszDest
, cchMax
);
2284 /*************************************************************************
2285 * StrFormatByteSizeA [SHLWAPI.@]
2287 * Create a string containing an abbreviated byte count of up to 2^31-1.
2290 * dwBytes [I] Byte size to format
2291 * lpszDest [I] Destination for formatted string
2292 * cchMax [I] Size of lpszDest
2298 * The Ascii and Unicode versions of this function accept a different
2299 * integer type for dwBytes. See StrFormatByteSize64A().
2301 LPSTR WINAPI
StrFormatByteSizeA(DWORD dwBytes
, LPSTR lpszDest
, UINT cchMax
)
2303 TRACE("(%ld,%p,%d)\n", dwBytes
, lpszDest
, cchMax
);
2305 return StrFormatByteSize64A(dwBytes
, lpszDest
, cchMax
);