Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / shlwapi / string.c
blob210dd9202a45ee96293f7cfa4061dc72efde03df
1 /*
2 * Shlwapi string functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define COM_NO_WINDOWS_H
23 #include "config.h"
24 #include "wine/port.h"
26 #include <math.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33 #include "windef.h"
34 #include "winbase.h"
35 #define NO_SHLWAPI_REG
36 #define NO_SHLWAPI_STREAM
37 #include "shlwapi.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "shlobj.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(shell);
46 static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
47 static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*);
49 /*************************************************************************
50 * SHLWAPI_ChrCmpHelperA
52 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
54 * NOTES
55 * Both this function and its Unicode counterpart are very inneficient. To
56 * fix this, CompareString must be completely implemented and optimised
57 * first. Then the core character test can be taken out of that function and
58 * placed here, so that it need never be called at all. Until then, do not
59 * attempt to optimise this code unless you are willing to test that it
60 * still performs correctly.
62 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
64 char str1[3], str2[3];
66 str1[0] = LOBYTE(ch1);
67 if (IsDBCSLeadByte(ch1))
69 str1[1] = HIBYTE(ch1);
70 str1[2] = '\0';
72 else
73 str1[1] = '\0';
75 str2[0] = LOBYTE(ch2);
76 if (IsDBCSLeadByte(ch2))
78 str2[1] = HIBYTE(ch2);
79 str2[2] = '\0';
81 else
82 str2[1] = '\0';
84 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
87 /*************************************************************************
88 * SHLWAPI_ChrCmpHelperW
90 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
92 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
94 WCHAR str1[2], str2[2];
96 str1[0] = ch1;
97 str1[1] = '\0';
98 str2[0] = ch2;
99 str2[1] = '\0';
100 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
103 /*************************************************************************
104 * SHLWAPI_ChrCmpA
106 * Internal helper function.
108 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
110 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
113 /*************************************************************************
114 * ChrCmpIA (SHLWAPI.385)
116 * Compare two characters, ignoring case.
118 * PARAMS
119 * ch1 [I] First character to compare
120 * ch2 [I] Second character to compare
122 * RETURNS
123 * FALSE, if the characters are equal.
124 * Non-zero otherwise.
126 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
128 TRACE("(%d,%d)\n", ch1, ch2);
130 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
133 /*************************************************************************
134 * SHLWAPI_ChrCmpW
136 * Internal helper function.
138 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
140 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
143 /*************************************************************************
144 * ChrCmpIW [SHLWAPI.386]
146 * See ChrCmpIA.
148 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
150 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
153 /*************************************************************************
154 * StrChrA [SHLWAPI.@]
156 * Find a given character in a string.
158 * PARAMS
159 * lpszStr [I] String to search in.
160 * ch [I] Character to search for.
162 * RETURNS
163 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
164 * not found.
165 * Failure: NULL, if any arguments are invalid.
167 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
169 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
171 if (lpszStr)
173 while (*lpszStr)
175 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
176 return (LPSTR)lpszStr;
177 lpszStr = CharNextA(lpszStr);
180 return NULL;
183 /*************************************************************************
184 * StrChrW [SHLWAPI.@]
186 * See StrChrA.
188 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
190 LPWSTR lpszRet = NULL;
192 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
194 if (lpszStr)
195 lpszRet = strchrW(lpszStr, ch);
196 return lpszRet;
199 /*************************************************************************
200 * StrChrIA [SHLWAPI.@]
202 * Find a given character in a string, ignoring case.
204 * PARAMS
205 * lpszStr [I] String to search in.
206 * ch [I] Character to search for.
208 * RETURNS
209 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
210 * not found.
211 * Failure: NULL, if any arguments are invalid.
213 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
215 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
217 if (lpszStr)
219 while (*lpszStr)
221 if (!ChrCmpIA(*lpszStr, ch))
222 return (LPSTR)lpszStr;
223 lpszStr = CharNextA(lpszStr);
226 return NULL;
229 /*************************************************************************
230 * StrChrIW [SHLWAPI.@]
232 * See StrChrA.
234 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
236 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
238 if (lpszStr)
240 ch = toupperW(ch);
241 while (*lpszStr)
243 if (toupperW(*lpszStr) == ch)
244 return (LPWSTR)lpszStr;
245 lpszStr = CharNextW(lpszStr);
247 lpszStr = NULL;
249 return (LPWSTR)lpszStr;
252 /*************************************************************************
253 * StrCmpIW [SHLWAPI.@]
255 * Compare two strings, ignoring case.
257 * PARAMS
258 * lpszStr [I] First string to compare
259 * lpszComp [I] Second string to compare
261 * RETURNS
262 * An integer less than, equal to or greater than 0, indicating that
263 * lpszStr is less than, the same, or greater than lpszComp.
265 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
267 INT iRet;
269 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
271 iRet = strcmpiW(lpszStr, lpszComp);
272 return iRet < 0 ? -1 : iRet ? 1 : 0;
275 /*************************************************************************
276 * SHLWAPI_StrCmpNHelperA
278 * Internal helper for StrCmpNA/StrCmpNIA.
280 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
281 INT iLen,
282 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
284 if (!lpszStr)
286 if (!lpszComp)
287 return 0;
288 return 1;
290 else if (!lpszComp)
291 return -1;
293 while (iLen-- > 0)
295 int iDiff;
296 WORD ch1, ch2;
298 ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
299 ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
301 if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
302 return -1;
303 else if (iDiff > 0)
304 return 1;
305 else if (!*lpszStr && !*lpszComp)
306 return 0;
308 lpszStr = CharNextA(lpszStr);
309 lpszComp = CharNextA(lpszComp);
311 return 0;
314 /*************************************************************************
315 * StrCmpNA [SHLWAPI.@]
317 * Compare two strings, up to a maximum length.
319 * PARAMS
320 * lpszStr [I] First string to compare
321 * lpszComp [I] Second string to compare
322 * iLen [I] Maximum number of chars to compare.
324 * RETURNS
325 * An integer less than, equal to or greater than 0, indicating that
326 * lpszStr is less than, the same, or greater than lpszComp.
328 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
330 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
332 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
335 /*************************************************************************
336 * StrCmpNW [SHLWAPI.@]
338 * See StrCmpNA.
340 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
342 INT iRet;
344 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
346 iRet = strncmpW(lpszStr, lpszComp, iLen);
347 return iRet < 0 ? -1 : iRet ? 1 : 0;
350 /*************************************************************************
351 * StrCmpNIA [SHLWAPI.@]
353 * Compare two strings, up to a maximum length, ignoring case.
355 * PARAMS
356 * lpszStr [I] First string to compare
357 * lpszComp [I] Second string to compare
358 * iLen [I] Maximum number of chars to compare.
360 * RETURNS
361 * An integer less than, equal to or greater than 0, indicating that
362 * lpszStr is less than, the same, or greater than lpszComp.
364 * NOTES
365 * The Win32 version of this function is _completely_ broken for cases
366 * where iLen is greater than the length of lpszComp. Examples:
368 *| StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
369 *| StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
370 *| StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
372 * This implementation behaves correctly, since it is unlikely any
373 * applications actually rely on this function being broken.
375 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
377 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
379 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
382 /*************************************************************************
383 * StrCmpNIW [SHLWAPI.@]
385 * See StrCmpNIA.
387 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
389 INT iRet;
391 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
393 iRet = strncmpiW(lpszStr, lpszComp, iLen);
394 return iRet < 0 ? -1 : iRet ? 1 : 0;
397 /*************************************************************************
398 * StrCmpW [SHLWAPI.@]
400 * Compare two strings.
402 * PARAMS
403 * lpszStr [I] First string to compare
404 * lpszComp [I] Second string to compare
406 * RETURNS
407 * An integer less than, equal to or greater than 0, indicating that
408 * lpszStr is less than, the same, or greater than lpszComp.
410 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
412 INT iRet;
414 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
416 iRet = strcmpW(lpszStr, lpszComp);
417 return iRet < 0 ? -1 : iRet ? 1 : 0;
420 /*************************************************************************
421 * StrCatW [SHLWAPI.@]
423 * Concatanate two strings.
425 * PARAMS
426 * lpszStr [O] Initial string
427 * lpszSrc [I] String to concatanate
429 * RETURNS
430 * lpszStr.
432 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
434 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
436 strcatW(lpszStr, lpszSrc);
437 return lpszStr;
440 /*************************************************************************
441 * StrCpyW [SHLWAPI.@]
443 * Copy a string to another string.
445 * PARAMS
446 * lpszStr [O] Destination string
447 * lpszSrc [I] Source string
449 * RETURNS
450 * lpszStr.
452 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
454 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
456 strcpyW(lpszStr, lpszSrc);
457 return lpszStr;
460 /*************************************************************************
461 * StrCpyNW [SHLWAPI.@]
463 * Copy a string to another string, up to a maximum number of characters.
465 * PARAMS
466 * lpszStr [O] Destination string
467 * lpszSrc [I] Source string
468 * iLen [I] Maximum number of chars to copy
470 * RETURNS
471 * lpszStr.
473 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
475 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
477 lstrcpynW(lpszStr, lpszSrc, iLen);
478 return lpszStr;
483 /*************************************************************************
484 * SHLWAPI_StrStrHelperA
486 * Internal implementation of StrStrA/StrStrIA
488 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
489 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
491 size_t iLen;
493 if (!lpszStr || !lpszSearch || !*lpszSearch)
494 return NULL;
496 iLen = strlen(lpszSearch);
498 while (*lpszStr)
500 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
501 return (LPSTR)lpszStr;
502 lpszStr = CharNextA(lpszStr);
504 return NULL;
507 /*************************************************************************
508 * SHLWAPI_StrStrHelperW
510 * Internal implementation of StrStrW/StrStrIW
512 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
513 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
515 int iLen;
517 if (!lpszStr || !lpszSearch || !*lpszSearch)
518 return NULL;
520 iLen = strlenW(lpszSearch);
522 while (*lpszStr)
524 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
525 return (LPWSTR)lpszStr;
526 lpszStr = CharNextW(lpszStr);
528 return NULL;
531 /*************************************************************************
532 * StrStrA [SHLWAPI.@]
534 * Find a substring within a string.
536 * PARAMS
537 * lpszStr [I] String to search in
538 * lpszSearch [I] String to look for
540 * RETURNS
541 * The start of lpszSearch within lpszStr, or NULL if not found.
543 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
545 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
547 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
550 /*************************************************************************
551 * StrStrW [SHLWAPI.@]
553 * See StrStrA.
555 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
557 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
559 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
562 /*************************************************************************
563 * StrRStrIA [SHLWAPI.@]
565 * Find the last occurence of a substring within a string.
567 * PARAMS
568 * lpszStr [I] String to search in
569 * lpszEnd [I] End of lpszStr
570 * lpszSearch [I] String to look for
572 * RETURNS
573 * The last occurence lpszSearch within lpszStr, or NULL if not found.
575 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
577 LPSTR lpszRet = NULL;
578 WORD ch1, ch2;
579 INT iLen;
581 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
583 if (!lpszStr || !lpszSearch || !*lpszSearch)
584 return NULL;
586 if (!lpszEnd)
587 lpszEnd = lpszStr + lstrlenA(lpszStr);
589 if (IsDBCSLeadByte(*lpszSearch))
590 ch1 = *lpszSearch << 8 | lpszSearch[1];
591 else
592 ch1 = *lpszSearch;
593 iLen = lstrlenA(lpszSearch);
595 while (lpszStr <= lpszEnd && *lpszStr)
597 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
598 if (!ChrCmpIA(ch1, ch2))
600 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
601 lpszRet = (LPSTR)lpszStr;
603 lpszStr = CharNextA(lpszStr);
605 return lpszRet;
608 /*************************************************************************
609 * StrRStrIW [SHLWAPI.@]
611 * See StrRStrIA.
613 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
615 LPWSTR lpszRet = NULL;
616 INT iLen;
618 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
620 if (!lpszStr || !lpszSearch || !*lpszSearch)
621 return NULL;
623 if (!lpszEnd)
624 lpszEnd = lpszStr + strlenW(lpszStr);
626 iLen = strlenW(lpszSearch);
628 while (lpszStr <= lpszEnd && *lpszStr)
630 if (!ChrCmpIA(*lpszSearch, *lpszStr))
632 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
633 lpszRet = (LPWSTR)lpszStr;
635 lpszStr = CharNextW(lpszStr);
637 return lpszRet;
640 /*************************************************************************
641 * StrStrIA [SHLWAPI.@]
643 * Find a substring within a string, ignoring case.
645 * PARAMS
646 * lpszStr [I] String to search in
647 * lpszSearch [I] String to look for
649 * RETURNS
650 * The start of lpszSearch within lpszStr, or NULL if not found.
652 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
654 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
656 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
659 /*************************************************************************
660 * StrStrIW [SHLWAPI.@]
662 * See StrStrIA.
664 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
666 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
668 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
671 /*************************************************************************
672 * StrToIntA [SHLWAPI.@]
674 * Read an integer from a string.
676 * PARAMS
677 * lpszStr [I] String to read integer from
679 * RETURNS
680 * The integer value represented by the string, or 0 if no integer is
681 * present.
683 * NOTES
684 * No leading space is allowed before the number, although a leading '-' is.
686 int WINAPI StrToIntA(LPCSTR lpszStr)
688 int iRet = 0;
690 TRACE("(%s)\n", debugstr_a(lpszStr));
692 if (!lpszStr)
694 WARN("Invalid lpszStr would crash under Win32!\n");
695 return 0;
698 if (*lpszStr == '-' || isdigit(*lpszStr))
699 StrToIntExA(lpszStr, 0, &iRet);
700 return iRet;
703 /*************************************************************************
704 * StrToIntW [SHLWAPI.@]
706 * See StrToIntA.
708 int WINAPI StrToIntW(LPCWSTR lpszStr)
710 int iRet = 0;
712 TRACE("(%s)\n", debugstr_w(lpszStr));
714 if (!lpszStr)
716 WARN("Invalid lpszStr would crash under Win32!\n");
717 return 0;
720 if (*lpszStr == '-' || isdigitW(*lpszStr))
721 StrToIntExW(lpszStr, 0, &iRet);
722 return iRet;
725 /*************************************************************************
726 * StrToIntExA [SHLWAPI.@]
728 * Read an integer from a string.
730 * PARAMS
731 * lpszStr [I] String to read integer from
732 * dwFlags [I] Flags controlling the conversion
733 * lpiRet [O] Destination for read integer.
735 * RETURNS
736 * Success: TRUE. lpiRet contains the integer value represented by the string.
737 * Failure: FALSE, if the string is invalid, or no number is present.
739 * NOTES
740 * Leading whitespace, '-' and '+' are allowed before the number. If
741 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
742 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
743 * the string is treated as a decimal string. A leading '-' is ignored for
744 * hexidecimal numbers.
746 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
748 BOOL bNegative = FALSE;
749 int iRet = 0;
751 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
753 if (!lpszStr || !lpiRet)
755 WARN("Invalid parameter would crash under Win32!\n");
756 return FALSE;
758 if (dwFlags > STIF_SUPPORT_HEX)
760 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
763 /* Skip leading space, '+', '-' */
764 while (isspace(*lpszStr))
765 lpszStr = CharNextA(lpszStr);
767 if (*lpszStr == '-')
769 bNegative = TRUE;
770 lpszStr++;
772 else if (*lpszStr == '+')
773 lpszStr++;
775 if (dwFlags & STIF_SUPPORT_HEX &&
776 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
778 /* Read hex number */
779 lpszStr += 2;
781 if (!isxdigit(*lpszStr))
782 return FALSE;
784 while (isxdigit(*lpszStr))
786 iRet = iRet * 16;
787 if (isdigit(*lpszStr))
788 iRet += (*lpszStr - '0');
789 else
790 iRet += 10 + (tolower(*lpszStr) - 'a');
791 lpszStr++;
793 *lpiRet = iRet;
794 return TRUE;
797 /* Read decimal number */
798 if (!isdigit(*lpszStr))
799 return FALSE;
801 while (isdigit(*lpszStr))
803 iRet = iRet * 10;
804 iRet += (*lpszStr - '0');
805 lpszStr++;
807 *lpiRet = bNegative ? -iRet : iRet;
808 return TRUE;
811 /*************************************************************************
812 * StrToIntExW [SHLWAPI.@]
814 * See StrToIntExA.
816 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
818 BOOL bNegative = FALSE;
819 int iRet = 0;
821 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
823 if (!lpszStr || !lpiRet)
825 WARN("Invalid parameter would crash under Win32!\n");
826 return FALSE;
828 if (dwFlags > STIF_SUPPORT_HEX)
830 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
833 /* Skip leading space, '+', '-' */
834 while (isspaceW(*lpszStr))
835 lpszStr = CharNextW(lpszStr);
837 if (*lpszStr == '-')
839 bNegative = TRUE;
840 lpszStr++;
842 else if (*lpszStr == '+')
843 lpszStr++;
845 if (dwFlags & STIF_SUPPORT_HEX &&
846 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
848 /* Read hex number */
849 lpszStr += 2;
851 if (!isxdigitW(*lpszStr))
852 return FALSE;
854 while (isxdigitW(*lpszStr))
856 iRet = iRet * 16;
857 if (isdigitW(*lpszStr))
858 iRet += (*lpszStr - '0');
859 else
860 iRet += 10 + (tolowerW(*lpszStr) - 'a');
861 lpszStr++;
863 *lpiRet = iRet;
864 return TRUE;
867 /* Read decimal number */
868 if (!isdigitW(*lpszStr))
869 return FALSE;
871 while (isdigitW(*lpszStr))
873 iRet = iRet * 10;
874 iRet += (*lpszStr - '0');
875 lpszStr++;
877 *lpiRet = bNegative ? -iRet : iRet;
878 return TRUE;
881 /*************************************************************************
882 * StrDupA [SHLWAPI.@]
884 * Duplicate a string.
886 * PARAMS
887 * lpszStr [I] String to duplicate.
889 * RETURNS
890 * Success: A pointer to a new string containing the contents of lpszStr
891 * Failure: NULL, if memory cannot be allocated
893 * NOTES
894 * The string memory is allocated with LocalAlloc(), and so should be released
895 * by calling LocalFree().
897 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
899 int iLen;
900 LPSTR lpszRet;
902 TRACE("(%s)\n",debugstr_a(lpszStr));
904 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
905 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
907 if (lpszRet)
909 if (lpszStr)
910 memcpy(lpszRet, lpszStr, iLen);
911 else
912 *lpszRet = '\0';
914 return lpszRet;
917 /*************************************************************************
918 * StrDupW [SHLWAPI.@]
920 * See StrDupA.
922 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
924 int iLen;
925 LPWSTR lpszRet;
927 TRACE("(%s)\n",debugstr_w(lpszStr));
929 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
930 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
932 if (lpszRet)
934 if (lpszStr)
935 memcpy(lpszRet, lpszStr, iLen);
936 else
937 *lpszRet = '\0';
939 return lpszRet;
942 /*************************************************************************
943 * SHLWAPI_StrSpnHelperA
945 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
947 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
948 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
949 BOOL bInvert)
951 LPCSTR lpszRead = lpszStr;
952 if (lpszStr && *lpszStr && lpszMatch)
954 while (*lpszRead)
956 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
958 if (!bInvert && !lpszTest)
959 break;
960 if (bInvert && lpszTest)
961 break;
962 lpszRead = CharNextA(lpszRead);
965 return lpszRead - lpszStr;
968 /*************************************************************************
969 * SHLWAPI_StrSpnHelperW
971 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
973 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
974 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
975 BOOL bInvert)
977 LPCWSTR lpszRead = lpszStr;
978 if (lpszStr && *lpszStr && lpszMatch)
980 while (*lpszRead)
982 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
984 if (!bInvert && !lpszTest)
985 break;
986 if (bInvert && lpszTest)
987 break;
988 lpszRead = CharNextW(lpszRead);
991 return lpszRead - lpszStr;
994 /*************************************************************************
995 * StrSpnA [SHLWAPI.@]
997 * Find the length of the start of a string that contains only certain
998 * characters.
1000 * PARAMS
1001 * lpszStr [I] String to search
1002 * lpszMatch [I] Characters that can be in the substring
1004 * RETURNS
1005 * The length of the part of lpszStr containing only chars from lpszMatch,
1006 * or 0 if any parameter is invalid.
1008 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1010 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1012 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1015 /*************************************************************************
1016 * StrSpnW [SHLWAPI.@]
1018 * See StrSpnA.
1020 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1022 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1024 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1027 /*************************************************************************
1028 * StrCSpnA [SHLWAPI.@]
1030 * Find the length of the start of a string that does not contain certain
1031 * characters.
1033 * PARAMS
1034 * lpszStr [I] String to search
1035 * lpszMatch [I] Characters that cannot be in the substring
1037 * RETURNS
1038 * The length of the part of lpszStr containing only chars not in lpszMatch,
1039 * or 0 if any parameter is invalid.
1041 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1043 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1045 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1048 /*************************************************************************
1049 * StrCSpnW [SHLWAPI.@]
1051 * See StrCSpnA.
1053 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1055 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1057 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1060 /*************************************************************************
1061 * StrCSpnIA [SHLWAPI.@]
1063 * Find the length of the start of a string that does not contain certain
1064 * characters, ignoring case.
1066 * PARAMS
1067 * lpszStr [I] String to search
1068 * lpszMatch [I] Characters that cannot be in the substring
1070 * RETURNS
1071 * The length of the part of lpszStr containing only chars not in lpszMatch,
1072 * or 0 if any parameter is invalid.
1074 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1076 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1078 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1081 /*************************************************************************
1082 * StrCSpnIW [SHLWAPI.@]
1084 * See StrCSpnIA.
1086 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1088 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1090 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1093 /*************************************************************************
1094 * StrPBrkA [SHLWAPI.@]
1096 * Search a string for any of a group of characters.
1098 * PARAMS
1099 * lpszStr [I] String to search
1100 * lpszMatch [I] Characters to match
1102 * RETURNS
1103 * A pointer to the first matching character in lpszStr, or NULL if no
1104 * match was found.
1106 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1108 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1110 if (lpszStr && lpszMatch && *lpszMatch)
1112 while (*lpszStr)
1114 if (StrChrA(lpszMatch, *lpszStr))
1115 return (LPSTR)lpszStr;
1116 lpszStr = CharNextA(lpszStr);
1119 return NULL;
1122 /*************************************************************************
1123 * StrPBrkW [SHLWAPI.@]
1125 * See StrPBrkA.
1127 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1129 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1131 if (lpszStr && lpszMatch && *lpszMatch)
1133 while (*lpszStr)
1135 if (StrChrW(lpszMatch, *lpszStr))
1136 return (LPWSTR)lpszStr;
1137 lpszStr = CharNextW(lpszStr);
1140 return NULL;
1143 /*************************************************************************
1144 * SHLWAPI_StrRChrHelperA
1146 * Internal implementation of StrRChrA/StrRChrIA.
1148 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1149 LPCSTR lpszEnd, WORD ch,
1150 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1152 LPCSTR lpszRet = NULL;
1154 if (lpszStr)
1156 WORD ch2;
1158 if (!lpszEnd)
1159 lpszEnd = lpszStr + lstrlenA(lpszStr);
1161 while (*lpszStr && lpszStr <= lpszEnd)
1163 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1165 if (!pChrCmpFn(ch, ch2))
1166 lpszRet = lpszStr;
1167 lpszStr = CharNextA(lpszStr);
1170 return (LPSTR)lpszRet;
1173 /*************************************************************************
1174 * SHLWAPI_StrRChrHelperW
1176 * Internal implementation of StrRChrW/StrRChrIW.
1178 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1179 LPCWSTR lpszEnd, WCHAR ch,
1180 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1182 LPCWSTR lpszRet = NULL;
1184 if (lpszStr)
1186 if (!lpszEnd)
1187 lpszEnd = lpszStr + strlenW(lpszStr);
1189 while (*lpszStr && lpszStr <= lpszEnd)
1191 if (!pChrCmpFn(ch, *lpszStr))
1192 lpszRet = lpszStr;
1193 lpszStr = CharNextW(lpszStr);
1196 return (LPWSTR)lpszRet;
1199 /**************************************************************************
1200 * StrRChrA [SHLWAPI.@]
1202 * Find the last occurence of a character in string.
1204 * PARAMS
1205 * lpszStr [I] String to search in
1206 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1207 * ch [I] Character to search for.
1209 * RETURNS
1210 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1211 * or NULL if not found.
1212 * Failure: NULL, if any arguments are invalid.
1214 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1216 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1218 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1221 /**************************************************************************
1222 * StrRChrW [SHLWAPI.@]
1224 * See StrRChrA.
1226 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1228 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1230 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1233 /**************************************************************************
1234 * StrRChrIA [SHLWAPI.@]
1236 * Find the last occurence of a character in string, ignoring case.
1238 * PARAMS
1239 * lpszStr [I] String to search in
1240 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1241 * ch [I] Character to search for.
1243 * RETURNS
1244 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1245 * or NULL if not found.
1246 * Failure: NULL, if any arguments are invalid.
1248 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1250 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1252 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1255 /**************************************************************************
1256 * StrRChrIW [SHLWAPI.@]
1258 * See StrRChrIA.
1260 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1262 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1264 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1267 /*************************************************************************
1268 * StrCatBuffA [SHLWAPI.@]
1270 * Concatenate two strings together.
1272 * PARAMS
1273 * lpszStr [O] String to concatenate to
1274 * lpszCat [I] String to add to lpszCat
1275 * cchMax [I] Maximum number of characters for the whole string
1277 * RETURNS
1278 * lpszStr.
1280 * NOTES
1281 * cchMax determines the number of characters in the final length of the
1282 * string, not the number appended to lpszStr from lpszCat.
1284 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1286 INT iLen;
1288 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1290 if (!lpszStr)
1292 WARN("Invalid lpszStr would crash under Win32!\n");
1293 return NULL;
1296 iLen = strlen(lpszStr);
1297 cchMax -= iLen;
1299 if (cchMax > 0)
1300 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1301 return lpszStr;
1304 /*************************************************************************
1305 * StrCatBuffW [SHLWAPI.@]
1307 * See StrCatBuffA.
1309 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1311 INT iLen;
1313 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1315 if (!lpszStr)
1317 WARN("Invalid lpszStr would crash under Win32!\n");
1318 return NULL;
1321 iLen = strlenW(lpszStr);
1322 cchMax -= iLen;
1324 if (cchMax > 0)
1325 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1326 return lpszStr;
1329 /*************************************************************************
1330 * StrRetToBufA [SHLWAPI.@]
1332 * Convert a STRRET to a normal string.
1334 * PARAMS
1335 * lpStrRet [O] STRRET to convert
1336 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1337 * lpszDest [O] Destination for normal string
1338 * dwLen [I] Length of lpszDest
1340 * RETURNS
1341 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1342 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1343 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1344 * Failure: E_FAIL, if any parameters are invalid.
1346 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1348 /* NOTE:
1349 * This routine is identical to that in dlls/shell32/shellstring.c.
1350 * It was duplicated because not every version of Shlwapi.dll exports
1351 * StrRetToBufA. If you change one routine, change them both.
1353 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1355 if (!src)
1357 WARN("Invalid lpStrRet would crash under Win32!\n");
1358 if (dest)
1359 *dest = '\0';
1360 return E_FAIL;
1363 if (!dest || !len)
1364 return E_FAIL;
1366 *dest = '\0';
1368 switch (src->uType)
1370 case STRRET_WSTR:
1371 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1372 CoTaskMemFree(src->u.pOleStr);
1373 break;
1375 case STRRET_CSTR:
1376 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1377 break;
1379 case STRRET_OFFSET:
1380 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1381 break;
1383 default:
1384 FIXME("unknown type!\n");
1385 return FALSE;
1387 return S_OK;
1390 /*************************************************************************
1391 * StrRetToBufW [SHLWAPI.@]
1393 * See StrRetToBufA.
1395 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1397 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1399 if (!src)
1401 WARN("Invalid lpStrRet would crash under Win32!\n");
1402 if (dest)
1403 *dest = '\0';
1404 return E_FAIL;
1407 if (!dest || !len)
1408 return E_FAIL;
1410 *dest = '\0';
1412 switch (src->uType)
1414 case STRRET_WSTR:
1415 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1416 CoTaskMemFree(src->u.pOleStr);
1417 break;
1419 case STRRET_CSTR:
1420 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1421 dest[len-1] = 0;
1422 break;
1424 case STRRET_OFFSET:
1425 if (pidl)
1427 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1428 dest, len ) && len)
1429 dest[len-1] = 0;
1431 break;
1433 default:
1434 FIXME("unknown type!\n");
1435 return FALSE;
1437 return S_OK;
1440 /*************************************************************************
1441 * StrRetToStrA [SHLWAPI.@]
1443 * Converts a STRRET to a normal string.
1445 * PARAMS
1446 * lpStrRet [O] STRRET to convert
1447 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1448 * ppszName [O] Destination for converted string
1450 * RETURNS
1451 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1452 * Failure: E_FAIL, if any parameters are invalid.
1454 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1456 HRESULT hRet = E_FAIL;
1458 switch (lpStrRet->uType)
1460 case STRRET_WSTR:
1461 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1462 CoTaskMemFree(lpStrRet->u.pOleStr);
1463 break;
1465 case STRRET_CSTR:
1466 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1467 break;
1469 case STRRET_OFFSET:
1470 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1471 break;
1473 default:
1474 *ppszName = NULL;
1477 return hRet;
1480 /*************************************************************************
1481 * StrRetToStrW [SHLWAPI.@]
1483 * See StrRetToStrA.
1485 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1487 HRESULT hRet = E_FAIL;
1489 switch (lpStrRet->uType)
1491 case STRRET_WSTR:
1492 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1493 CoTaskMemFree(lpStrRet->u.pOleStr);
1494 break;
1496 case STRRET_CSTR:
1497 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1498 break;
1500 case STRRET_OFFSET:
1501 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1502 break;
1504 default:
1505 *ppszName = NULL;
1508 return hRet;
1511 /*************************************************************************
1512 * StrFormatKBSizeA [SHLWAPI.@]
1514 * Create a formatted string containing a byte count in Kilobytes.
1516 * PARAMS
1517 * llBytes [I] Byte size to format
1518 * lpszDest [I] Destination for formatted string
1519 * cchMax [I] Size of lpszDest
1521 * RETURNS
1522 * lpszDest.
1524 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1526 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1527 LONGLONG ulKB = (llBytes + 1023) >> 10;
1529 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1531 *szOut-- = '\0';
1532 *szOut-- = 'B';
1533 *szOut-- = 'K';
1534 *szOut-- = ' ';
1538 LONGLONG ulNextDigit = ulKB % 10;
1539 *szOut-- = '0' + ulNextDigit;
1540 ulKB = (ulKB - ulNextDigit) / 10;
1541 } while (ulKB > 0);
1543 strncpy(lpszDest, szOut + 1, cchMax);
1544 return lpszDest;
1547 /*************************************************************************
1548 * StrFormatKBSizeW [SHLWAPI.@]
1550 * See StrFormatKBSizeA.
1552 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1554 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
1555 LONGLONG ulKB = (llBytes + 1023) >> 10;
1557 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1559 *szOut-- = '\0';
1560 *szOut-- = 'B';
1561 *szOut-- = 'K';
1562 *szOut-- = ' ';
1566 LONGLONG ulNextDigit = ulKB % 10;
1567 *szOut-- = '0' + ulNextDigit;
1568 ulKB = (ulKB - ulNextDigit) / 10;
1569 } while (ulKB > 0);
1571 strncpyW(lpszDest, szOut + 1, cchMax);
1572 return lpszDest;
1575 /*************************************************************************
1576 * StrNCatA [SHLWAPI.@]
1578 * Concatenate two strings together.
1580 * PARAMS
1581 * lpszStr [O] String to concatenate to
1582 * lpszCat [I] String to add to lpszCat
1583 * cchMax [I] Maximum number of characters to concatenate
1585 * RETURNS
1586 * lpszStr.
1588 * NOTES
1589 * cchMax determines the number of characters that are appended to lpszStr,
1590 * not the total length of the string.
1592 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1594 LPSTR lpszRet = lpszStr;
1596 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1598 if (!lpszStr)
1600 WARN("Invalid lpszStr would crash under Win32!\n");
1601 return NULL;
1604 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1605 return lpszRet;
1608 /*************************************************************************
1609 * StrNCatW [SHLWAPI.@]
1611 * See StrNCatA.
1613 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1615 LPWSTR lpszRet = lpszStr;
1617 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1619 if (!lpszStr)
1621 WARN("Invalid lpszStr would crash under Win32\n");
1622 return NULL;
1625 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1626 return lpszRet;
1629 /*************************************************************************
1630 * StrTrimA [SHLWAPI.@]
1632 * Remove characters from the start and end of a string.
1634 * PARAMS
1635 * lpszStr [O] String to remove characters from
1636 * lpszTrim [I] Characters to remove from lpszStr
1638 * RETURNS
1639 * TRUE If lpszStr was valid and modified
1640 * FALSE Otherwise
1642 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1644 DWORD dwLen;
1645 LPSTR lpszRead = lpszStr;
1646 BOOL bRet = FALSE;
1648 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1650 if (lpszRead && *lpszRead)
1652 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1653 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1655 dwLen = strlen(lpszRead);
1657 if (lpszRead != lpszStr)
1659 memmove(lpszStr, lpszRead, dwLen + 1);
1660 bRet = TRUE;
1662 if (dwLen > 0)
1664 lpszRead = lpszStr + dwLen;
1665 while (StrChrA(lpszTrim, lpszRead[-1]))
1666 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1668 if (lpszRead != lpszStr + dwLen)
1670 *lpszRead = '\0';
1671 bRet = TRUE;
1675 return bRet;
1678 /*************************************************************************
1679 * StrTrimW [SHLWAPI.@]
1681 * See StrTrimA.
1683 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1685 DWORD dwLen;
1686 LPWSTR lpszRead = lpszStr;
1687 BOOL bRet = FALSE;
1689 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1691 if (lpszRead && *lpszRead)
1693 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1694 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1696 dwLen = strlenW(lpszRead);
1698 if (lpszRead != lpszStr)
1700 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1701 bRet = TRUE;
1703 if (dwLen > 0)
1705 lpszRead = lpszStr + dwLen;
1706 while (StrChrW(lpszTrim, lpszRead[-1]))
1707 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1709 if (lpszRead != lpszStr + dwLen)
1711 *lpszRead = '\0';
1712 bRet = TRUE;
1716 return bRet;
1719 /*************************************************************************
1720 * _SHStrDupAA [INTERNAL]
1722 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1724 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1726 HRESULT hr;
1727 int len = 0;
1729 if (src) {
1730 len = lstrlenA(src) + 1;
1731 *dest = CoTaskMemAlloc(len);
1732 } else {
1733 *dest = NULL;
1736 if (*dest) {
1737 lstrcpynA(*dest,src, len);
1738 hr = S_OK;
1739 } else {
1740 hr = E_OUTOFMEMORY;
1743 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1744 return hr;
1747 /*************************************************************************
1748 * SHStrDupA
1750 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1752 * PARAMS
1753 * lpszStr [I] String to copy
1754 * lppszDest [O] Destination for the new string copy
1756 * RETURNS
1757 * Success: S_OK. lppszDest contains the new string in Unicode format.
1758 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1759 * fails.
1761 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1763 HRESULT hRet;
1764 int len = 0;
1766 if (lpszStr)
1768 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1769 *lppszDest = CoTaskMemAlloc(len);
1771 else
1772 *lppszDest = NULL;
1774 if (*lppszDest)
1776 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len);
1777 hRet = S_OK;
1779 else
1780 hRet = E_OUTOFMEMORY;
1782 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1783 return hRet;
1786 /*************************************************************************
1787 * _SHStrDupAW [INTERNAL]
1789 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1791 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1793 HRESULT hr;
1794 int len = 0;
1796 if (src) {
1797 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1798 *dest = CoTaskMemAlloc(len);
1799 } else {
1800 *dest = NULL;
1803 if (*dest) {
1804 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1805 hr = S_OK;
1806 } else {
1807 hr = E_OUTOFMEMORY;
1810 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1811 return hr;
1814 /*************************************************************************
1815 * SHStrDupW
1817 * See SHStrDupA.
1819 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1821 HRESULT hr;
1822 int len = 0;
1824 if (src) {
1825 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1826 *dest = CoTaskMemAlloc(len);
1827 } else {
1828 *dest = NULL;
1831 if (*dest) {
1832 memcpy(*dest, src, len);
1833 hr = S_OK;
1834 } else {
1835 hr = E_OUTOFMEMORY;
1838 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1839 return hr;
1842 /*************************************************************************
1843 * SHLWAPI_WriteReverseNum
1845 * Internal helper for SHLWAPI_WriteTimeClass.
1847 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1849 *lpszOut-- = '\0';
1851 /* Write a decimal number to a string, backwards */
1854 DWORD dwNextDigit = dwNum % 10;
1855 *lpszOut-- = '0' + dwNextDigit;
1856 dwNum = (dwNum - dwNextDigit) / 10;
1857 } while (dwNum > 0);
1859 return lpszOut;
1862 /*************************************************************************
1863 * SHLWAPI_FormatSignificant
1865 * Internal helper for SHLWAPI_WriteTimeClass.
1867 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1869 /* Zero non significant digits, return remaining significant digits */
1870 while (*lpszNum)
1872 lpszNum++;
1873 if (--dwDigits == 0)
1875 while (*lpszNum)
1876 *lpszNum++ = '0';
1877 return 0;
1880 return dwDigits;
1883 /*************************************************************************
1884 * SHLWAPI_WriteTimeClass
1886 * Internal helper for StrFromTimeIntervalW.
1888 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1889 LPCWSTR lpszClass, int iDigits)
1891 WCHAR szBuff[64], *szOut = szBuff + 32;
1893 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1894 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1895 *szOut = ' ';
1896 strcpyW(szBuff + 32, lpszClass);
1897 strcatW(lpszOut, szOut);
1898 return iDigits;
1901 /*************************************************************************
1902 * StrFromTimeIntervalA [SHLWAPI.@]
1904 * Format a millisecond time interval into a string
1906 * PARAMS
1907 * lpszStr [O] Output buffer for formatted time interval
1908 * cchMax [I] Size of lpszStr
1909 * dwMS [I] Number of milliseconds
1910 * iDigits [I] Number of digits to print
1912 * RETURNS
1913 * The length of the formatted string, or 0 if any parameter is invalid.
1915 * NOTES
1916 * This implementation mimics the Win32 behaviour of always writing a leading
1917 * space before the time interval begins.
1919 * iDigits is used to provide approximate times if accuracy is not important.
1920 * This number of digits will be written of the first non-zero time class
1921 * (hours/minutes/seconds). If this does not complete the time classification,
1922 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1923 * If there are digits remaining following the writing of a time class, the
1924 * next time class will be written.
1926 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1927 * following will result from the given values of iDigits:
1929 *| iDigits 1 2 3 4 5 ...
1930 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1932 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1933 int iDigits)
1935 INT iRet = 0;
1937 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1939 if (lpszStr && cchMax)
1941 WCHAR szBuff[128];
1942 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1943 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1945 return iRet;
1949 /*************************************************************************
1950 * StrFromTimeIntervalW [SHLWAPI.@]
1952 * See StrFromTimeIntervalA.
1954 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1955 int iDigits)
1957 static const WCHAR szHr[] = {' ','h','r','\0'};
1958 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1959 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1960 INT iRet = 0;
1962 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1964 if (lpszStr && cchMax)
1966 WCHAR szCopy[128];
1967 DWORD dwHours, dwMinutes;
1969 if (!iDigits || cchMax == 1)
1971 *lpszStr = '\0';
1972 return 0;
1975 /* Calculate the time classes */
1976 dwMS = (dwMS + 500) / 1000;
1977 dwHours = dwMS / 3600;
1978 dwMS -= dwHours * 3600;
1979 dwMinutes = dwMS / 60;
1980 dwMS -= dwMinutes * 60;
1982 szCopy[0] = '\0';
1984 if (dwHours)
1985 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
1987 if (dwMinutes && iDigits)
1988 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
1990 if (iDigits) /* Always write seconds if we have significant digits */
1991 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
1993 strncpyW(lpszStr, szCopy, cchMax);
1994 iRet = strlenW(lpszStr);
1996 return iRet;
1999 /*************************************************************************
2000 * StrIsIntlEqualA [SHLWAPI.@]
2002 * Compare two strings.
2004 * PARAMS
2005 * bCase [I] Whether to compare case sensitively
2006 * lpszStr [I] First string to compare
2007 * lpszComp [I] Second string to compare
2008 * iLen [I] Length to compare
2010 * RETURNS
2011 * TRUE If the strings are equal.
2012 * FALSE Otherwise.
2014 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2015 int iLen)
2017 DWORD dwFlags = LOCALE_USE_CP_ACP;
2018 int iRet;
2020 TRACE("(%d,%s,%s,%d)\n", bCase,
2021 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2023 /* FIXME: These flags are undocumented and unknown by our CompareString.
2024 * We need defines for them.
2026 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2028 iRet = CompareStringA(GetThreadLocale(),
2029 dwFlags, lpszStr, iLen, lpszComp, iLen);
2031 if (!iRet)
2032 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2034 return iRet == 2 ? TRUE : FALSE;
2037 /*************************************************************************
2038 * StrIsIntlEqualW [SHLWAPI.@]
2040 * See StrIsIntlEqualA.
2042 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2043 int iLen)
2045 DWORD dwFlags;
2046 int iRet;
2048 TRACE("(%d,%s,%s,%d)\n", bCase,
2049 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2051 /* FIXME: These flags are undocumented and unknown by our CompareString.
2052 * We need defines for them.
2054 dwFlags = bCase ? 0x10000000 : 0x10000001;
2056 iRet = CompareStringW(GetThreadLocale(),
2057 dwFlags, lpszStr, iLen, lpszComp, iLen);
2059 if (!iRet)
2060 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2062 return iRet == 2 ? TRUE : FALSE;
2065 /*************************************************************************
2066 * @ [SHLWAPI.399]
2068 * Copy a string to another string, up to a maximum number of characters.
2070 * PARAMS
2071 * lpszDest [O] Destination string
2072 * lpszSrc [I] Source string
2073 * iLen [I] Maximum number of chars to copy
2075 * RETURNS
2076 * Success: A pointer to the last character written.
2077 * Failure: lpszDest, if any arguments are invalid.
2079 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2081 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2083 if (lpszDest && lpszSrc && iLen > 0)
2085 while ((iLen-- > 1) && *lpszSrc)
2086 *lpszDest++ = *lpszSrc++;
2087 if (iLen >= 0)
2088 *lpszDest = '\0';
2090 return lpszDest;
2093 /*************************************************************************
2094 * @ [SHLWAPI.400]
2096 * Unicode version of SHLWAPI_399.
2098 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2100 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2102 if (lpszDest && lpszSrc && iLen > 0)
2104 while ((iLen-- > 1) && *lpszSrc)
2105 *lpszDest++ = *lpszSrc++;
2106 if (iLen >= 0)
2107 *lpszDest = '\0';
2109 return lpszDest;
2112 /*************************************************************************
2113 * StrCmpLogicalW [SHLWAPI.@]
2115 * Compare two strings, ignoring case and comparing digits as numbers.
2117 * PARAMS
2118 * lpszStr [I] First string to compare
2119 * lpszComp [I] Second string to compare
2120 * iLen [I] Length to compare
2122 * RETURNS
2123 * TRUE If the strings are equal.
2124 * FALSE Otherwise.
2126 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2128 INT iDiff;
2130 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2132 if (lpszStr && lpszComp)
2134 while (*lpszStr)
2136 if (!*lpszComp)
2137 return 1;
2138 else if (isdigitW(*lpszStr))
2140 int iStr, iComp;
2142 if (!isdigitW(*lpszComp))
2143 return -1;
2145 /* Compare the numbers */
2146 StrToIntExW(lpszStr, 0, &iStr);
2147 StrToIntExW(lpszComp, 0, &iComp);
2149 if (iStr < iComp)
2150 return -1;
2151 else if (iStr > iComp)
2152 return 1;
2154 /* Skip */
2155 while (isdigitW(*lpszStr))
2156 lpszStr++;
2157 while (isdigitW(*lpszComp))
2158 lpszComp++;
2160 else if (isdigitW(*lpszComp))
2161 return 1;
2162 else
2164 iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE);
2165 if (iDiff > 0)
2166 return 1;
2167 else if (iDiff < 0)
2168 return -1;
2170 lpszStr++;
2171 lpszComp++;
2174 if (*lpszComp)
2175 return -1;
2177 return 0;
2180 /* Structure for formatting byte strings */
2181 typedef struct tagSHLWAPI_BYTEFORMATS
2183 LONGLONG dLimit;
2184 double dDivisor;
2185 double dNormaliser;
2186 LPCSTR lpszFormat;
2187 CHAR wPrefix;
2188 } SHLWAPI_BYTEFORMATS;
2190 /*************************************************************************
2191 * StrFormatByteSize64A [SHLWAPI.@]
2193 * Create a string containing an abbreviated byte count of up to 2^63-1.
2195 * PARAMS
2196 * llBytes [I] Byte size to format
2197 * lpszDest [I] Destination for formatted string
2198 * cchMax [I] Size of lpszDest
2200 * RETURNS
2201 * lpszDest.
2203 * NOTES
2204 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2206 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2208 static const char szBytes[] = "%ld bytes";
2209 static const char sz3_0[] = "%3.0f";
2210 static const char sz3_1[] = "%3.1f";
2211 static const char sz3_2[] = "%3.2f";
2213 #define KB ((ULONGLONG)1024)
2214 #define MB (KB*KB)
2215 #define GB (KB*KB*KB)
2216 #define TB (KB*KB*KB*KB)
2217 #define PB (KB*KB*KB*KB*KB)
2219 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2221 { 10*KB, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */
2222 { 100*KB, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */
2223 { 1000*KB, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */
2224 { 10*MB, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */
2225 { 100*MB, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */
2226 { 1000*MB, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */
2227 { 10*GB, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */
2228 { 100*GB, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */
2229 { 1000*GB, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */
2230 { 10*TB, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */
2231 { 100*TB, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */
2232 { 1000*TB, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */
2233 { 10*PB, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */
2234 { 100*PB, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */
2235 { 1000*PB, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */
2236 { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */
2238 char szBuff[32];
2239 char szAdd[4];
2240 double dBytes;
2241 UINT i = 0;
2243 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2245 if (!lpszDest || !cchMax)
2246 return lpszDest;
2248 if (llBytes < 1024) /* 1K */
2250 snprintf (lpszDest, cchMax, szBytes, (long)llBytes);
2251 return lpszDest;
2254 /* Note that if this loop completes without finding a match, i will be
2255 * pointing at the last entry, which is a catch all for > 1000 PB
2257 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2259 if (llBytes < bfFormats[i].dLimit)
2260 break;
2261 i++;
2263 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2264 * this number we integer shift down by 1 MB first. The table above has
2265 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2266 * for this. We also add a small fudge factor to get the correct result for
2267 * counts that lie exactly on a 1024 byte boundary.
2269 if (i > 8)
2270 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2271 else
2272 dBytes = (double)llBytes + 0.00001;
2274 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2276 sprintf(szBuff, bfFormats[i].lpszFormat, dBytes);
2277 szAdd[0] = ' ';
2278 szAdd[1] = bfFormats[i].wPrefix;
2279 szAdd[2] = 'B';
2280 szAdd[3] = '\0';
2281 strcat(szBuff, szAdd);
2282 strncpy(lpszDest, szBuff, cchMax);
2283 return lpszDest;
2286 /*************************************************************************
2287 * StrFormatByteSizeW [SHLWAPI.@]
2289 * See StrFormatByteSize64A.
2291 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest,
2292 UINT cchMax)
2294 char szBuff[32];
2296 StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff));
2298 if (lpszDest)
2299 MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax);
2300 return lpszDest;
2303 /*************************************************************************
2304 * StrFormatByteSizeA [SHLWAPI.@]
2306 * Create a string containing an abbreviated byte count of up to 2^31-1.
2308 * PARAMS
2309 * dwBytes [I] Byte size to format
2310 * lpszDest [I] Destination for formatted string
2311 * cchMax [I] Size of lpszDest
2313 * RETURNS
2314 * lpszDest.
2316 * NOTES
2317 * The Ascii and Unicode versions of this function accept a different
2318 * integer type for dwBytes. See StrFormatByteSize64A().
2320 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2322 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2324 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2327 /*************************************************************************
2328 * SHLWAPI_203 [SHLWAPI.203]
2330 * Remove a single non-trailing ampersand ('&') from a string.
2332 * PARAMS
2333 * lpszStr [I/O] String to remove ampersand from.
2335 * RETURNS
2336 * The character after the first ampersand in lpszStr, or the first character
2337 * in lpszStr if there is no ampersand in the string.
2339 char WINAPI SHLWAPI_203(LPCSTR lpszStr)
2341 LPSTR lpszIter, lpszTmp;
2342 char ch;
2344 TRACE("(%s)\n", debugstr_a(lpszStr));
2346 ch = *lpszStr;
2348 if ((lpszIter = StrChrA(lpszStr, '&')))
2350 lpszTmp = CharNextA(lpszIter);
2351 if (lpszTmp && *lpszTmp)
2353 if (*lpszTmp != '&')
2354 ch = *lpszTmp;
2356 while (lpszIter && *lpszIter)
2358 lpszTmp = CharNextA(lpszIter);
2359 *lpszIter = *lpszTmp;
2360 lpszIter = lpszTmp;
2365 return ch;