Eliminate lots of __WINE__ conditionals from the headers.
[wine/wine64.git] / dlls / shlwapi / string.c
blob2428e3d6fea90ff2ced7b9c36f12c90d90561bf1
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 <ctype.h>
27 #include <math.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
32 #include "winerror.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "winreg.h"
38 #define NO_SHLWAPI_STREAM
39 #include "shlwapi.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 src, LPSTR * dest);
47 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest);
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);
1138 } while (*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 dtermines the number of characters in the final length of the
1282 * string, not the number appended to lpszStr from lpszCat.
1284 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
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 HRESULT WINAPI StrRetToStrA(LPSTRRET pstr, const ITEMIDLIST * pidl, LPSTR* ppszName)
1447 HRESULT ret = E_FAIL;
1449 switch (pstr->uType) {
1450 case STRRET_WSTR:
1451 ret = _SHStrDupAW(pstr->u.pOleStr, ppszName);
1452 CoTaskMemFree(pstr->u.pOleStr);
1453 break;
1455 case STRRET_CSTR:
1456 ret = _SHStrDupAA(pstr->u.cStr, ppszName);
1457 break;
1459 case STRRET_OFFSET:
1460 ret = _SHStrDupAA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1461 break;
1463 default:
1464 *ppszName = NULL;
1466 return ret;
1469 /*************************************************************************
1470 * StrRetToStrW [SHLWAPI.@]
1472 * converts a STRRET to a normal string
1474 HRESULT WINAPI StrRetToStrW(LPSTRRET pstr, const ITEMIDLIST * pidl, LPWSTR* ppszName)
1476 HRESULT ret = E_FAIL;
1478 switch (pstr->uType) {
1479 case STRRET_WSTR:
1480 ret = SHStrDupW(pstr->u.pOleStr, ppszName);
1481 CoTaskMemFree(pstr->u.pOleStr);
1482 break;
1484 case STRRET_CSTR:
1485 ret = SHStrDupA(pstr->u.cStr, ppszName);
1486 break;
1488 case STRRET_OFFSET:
1489 ret = SHStrDupA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1490 break;
1492 default:
1493 *ppszName = NULL;
1495 return ret;
1498 /*************************************************************************
1499 * StrFormatKBSizeA [SHLWAPI.@]
1501 * Create a formatted string containing a byte count in Kilobytes.
1503 * PARAMS
1504 * llBytes [I] Byte size to format
1505 * lpszDest [I] Destination for formatted string
1506 * cchMax [I] Size of lpszDest
1508 * RETURNS
1509 * lpszDest.
1511 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1513 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1514 LONGLONG ulKB = (llBytes + 1023) >> 10;
1516 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1518 *szOut-- = '\0';
1519 *szOut-- = 'B';
1520 *szOut-- = 'K';
1521 *szOut-- = ' ';
1525 LONGLONG ulNextDigit = ulKB % 10;
1526 *szOut-- = '0' + ulNextDigit;
1527 ulKB = (ulKB - ulNextDigit) / 10;
1528 } while (ulKB > 0);
1530 strncpy(lpszDest, szOut + 1, cchMax);
1531 return lpszDest;
1534 /*************************************************************************
1535 * StrFormatKBSizeW [SHLWAPI.@]
1537 * See StrFormatKBSizeA.
1539 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1541 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1542 LONGLONG ulKB = (llBytes + 1023) >> 10;
1544 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1546 *szOut-- = '\0';
1547 *szOut-- = 'B';
1548 *szOut-- = 'K';
1549 *szOut-- = ' ';
1553 LONGLONG ulNextDigit = ulKB % 10;
1554 *szOut-- = '0' + ulNextDigit;
1555 ulKB = (ulKB - ulNextDigit) / 10;
1556 } while (ulKB > 0);
1558 strncpyW(lpszDest, szOut + 1, cchMax);
1559 return lpszDest;
1562 /*************************************************************************
1563 * StrNCatA [SHLWAPI.@]
1565 * Concatenate two strings together.
1567 * PARAMS
1568 * lpszStr [O] String to concatenate to
1569 * lpszCat [I] String to add to lpszCat
1570 * cchMax [I] Maximum number of characters to concatenate
1572 * RETURNS
1573 * lpszStr.
1575 * NOTES
1576 * cchMax dtermines the number of characters that are appended to lpszStr,
1577 * not the total length of the string.
1579 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1581 LPSTR lpszRet = lpszStr;
1583 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1585 if (!lpszStr)
1587 WARN("Invalid lpszStr would crash under Win32!\n");
1588 return NULL;
1591 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1592 return lpszRet;
1595 /*************************************************************************
1596 * StrNCatW [SHLWAPI.@]
1598 * See StrNCatA.
1600 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1602 LPWSTR lpszRet = lpszStr;
1604 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1606 if (!lpszStr)
1608 WARN("Invalid lpszStr would crash under Win32\n");
1609 return NULL;
1612 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1613 return lpszRet;
1616 /*************************************************************************
1617 * StrTrimA [SHLWAPI.@]
1619 * Remove characters from the start and end of a string.
1621 * PARAMS
1622 * lpszStr [O] String to remove characters from
1623 * lpszTrim [I] Characters to remove from lpszStr
1625 * RETURNS
1626 * TRUE If lpszStr was valid and modified
1627 * FALSE Otherwise
1629 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1631 DWORD dwLen;
1632 LPSTR lpszRead = lpszStr;
1633 BOOL bRet = FALSE;
1635 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1637 if (lpszRead && *lpszRead)
1639 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1640 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1642 dwLen = strlen(lpszRead);
1644 if (lpszRead != lpszStr)
1646 memmove(lpszStr, lpszRead, dwLen + 1);
1647 bRet = TRUE;
1649 if (dwLen > 0)
1651 lpszRead = lpszStr + dwLen;
1652 while (StrChrA(lpszTrim, lpszRead[-1]))
1653 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1655 if (lpszRead != lpszStr + dwLen)
1657 *lpszRead = '\0';
1658 bRet = TRUE;
1662 return bRet;
1665 /*************************************************************************
1666 * StrTrimW [SHLWAPI.@]
1668 * See StrTrimA.
1670 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1672 DWORD dwLen;
1673 LPWSTR lpszRead = lpszStr;
1674 BOOL bRet = FALSE;
1676 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1678 if (lpszRead && *lpszRead)
1680 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1681 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1683 dwLen = strlenW(lpszRead);
1685 if (lpszRead != lpszStr)
1687 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1688 bRet = TRUE;
1690 if (dwLen > 0)
1692 lpszRead = lpszStr + dwLen;
1693 while (StrChrW(lpszTrim, lpszRead[-1]))
1694 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1696 if (lpszRead != lpszStr + dwLen)
1698 *lpszRead = '\0';
1699 bRet = TRUE;
1703 return bRet;
1706 /*************************************************************************
1707 * _SHStrDupA [INTERNAL]
1709 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1711 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1713 HRESULT hr;
1714 int len = 0;
1716 if (src) {
1717 len = lstrlenA(src);
1718 *dest = CoTaskMemAlloc(len);
1719 } else {
1720 *dest = NULL;
1723 if (*dest) {
1724 lstrcpynA(*dest,src, len);
1725 hr = S_OK;
1726 } else {
1727 hr = E_OUTOFMEMORY;
1730 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1731 return hr;
1734 /*************************************************************************
1735 * SHStrDupA
1737 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc.
1739 * PARAMS
1740 * lpszStr [I] String to copy
1741 * lppszDest [O] Destination for the new string copy
1743 * RETURNS
1744 * Success: S_OK. lppszDest contains the new string in Unicode format.
1745 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1746 * fails.
1748 HRESULT WINAPI SHStrDupA(LPCSTR src, LPWSTR * dest)
1750 HRESULT hr;
1751 int len = 0;
1753 if (src) {
1754 len = (MultiByteToWideChar(0,0,src,-1,0,0) + 1)* sizeof(WCHAR);
1755 *dest = CoTaskMemAlloc(len);
1756 } else {
1757 *dest = NULL;
1760 if (*dest) {
1761 MultiByteToWideChar(0,0,src,-1,*dest,len);
1762 hr = S_OK;
1763 } else {
1764 hr = E_OUTOFMEMORY;
1767 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1768 return hr;
1771 /*************************************************************************
1772 * _SHStrDupAW [INTERNAL]
1774 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1776 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1778 HRESULT hr;
1779 int len = 0;
1781 if (src) {
1782 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1783 *dest = CoTaskMemAlloc(len);
1784 } else {
1785 *dest = NULL;
1788 if (*dest) {
1789 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1790 hr = S_OK;
1791 } else {
1792 hr = E_OUTOFMEMORY;
1795 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1796 return hr;
1799 /*************************************************************************
1800 * SHStrDupW
1802 * See SHStrDupA.
1804 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1806 HRESULT hr;
1807 int len = 0;
1809 if (src) {
1810 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1811 *dest = CoTaskMemAlloc(len);
1812 } else {
1813 *dest = NULL;
1816 if (*dest) {
1817 memcpy(*dest, src, len);
1818 hr = S_OK;
1819 } else {
1820 hr = E_OUTOFMEMORY;
1823 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1824 return hr;
1827 /*************************************************************************
1828 * SHLWAPI_WriteReverseNum
1830 * Internal helper for SHLWAPI_WriteTimeClass.
1832 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1834 *lpszOut-- = '\0';
1836 /* Write a decimal number to a string, backwards */
1839 DWORD dwNextDigit = dwNum % 10;
1840 *lpszOut-- = '0' + dwNextDigit;
1841 dwNum = (dwNum - dwNextDigit) / 10;
1842 } while (dwNum > 0);
1844 return lpszOut;
1847 /*************************************************************************
1848 * SHLWAPI_FormatSignificant
1850 * Internal helper for SHLWAPI_WriteTimeClass.
1852 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1854 /* Zero non significant digits, return remaining significant digits */
1855 while (*lpszNum)
1857 lpszNum++;
1858 if (--dwDigits == 0)
1860 while (*lpszNum)
1861 *lpszNum++ = '0';
1862 return 0;
1865 return dwDigits;
1868 /*************************************************************************
1869 * SHLWAPI_WriteTimeClass
1871 * Internal helper for StrFromTimeIntervalW.
1873 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1874 LPCWSTR lpszClass, int iDigits)
1876 WCHAR szBuff[64], *szOut = szBuff + 32;
1878 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1879 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1880 *szOut = ' ';
1881 strcpyW(szBuff + 32, lpszClass);
1882 strcatW(lpszOut, szOut);
1883 return iDigits;
1886 /*************************************************************************
1887 * StrFromTimeIntervalA [SHLWAPI.@]
1889 * Format a millisecond time interval into a string
1891 * PARAMS
1892 * lpszStr [O] Output buffer for formatted time interval
1893 * cchMax [I] Size of lpszStr
1894 * dwMS [I] Number of milliseconds
1895 * iDigits [I] Number of digits to print
1897 * RETURNS
1898 * The length of the formatted string, or 0 if any parameter is invalid.
1900 * NOTES
1901 * This implementation mimics the Win32 behaviour of always writing a leading
1902 * space before the time interval begins.
1903 * iDigits is used to provide approximate times if accuracy is not important.
1904 * This number of digits will be written of the first non-zero time class
1905 * (hours/minutes/seconds). If this does not complete the time classification,
1906 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1907 * If there are digits remaining following the writing of a time class, the
1908 * next time class will be written.
1909 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1910 * following will result from the given values of iDigits:
1912 * iDigits 1 2 3 4 5 ...
1913 * lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1915 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1916 int iDigits)
1918 INT iRet = 0;
1920 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1922 if (lpszStr && cchMax)
1924 WCHAR szBuff[128];
1925 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1926 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1928 return iRet;
1932 /*************************************************************************
1933 * StrFromTimeIntervalW [SHLWAPI.@]
1935 * See StrFromTimeIntervalA.
1937 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1938 int iDigits)
1940 static const WCHAR szHr[] = {' ','h','r','\0'};
1941 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1942 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1943 INT iRet = 0;
1945 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1947 if (lpszStr && cchMax)
1949 WCHAR szCopy[128];
1950 DWORD dwHours, dwMinutes;
1952 if (!iDigits || cchMax == 1)
1954 *lpszStr = '\0';
1955 return 0;
1958 /* Calculate the time classes */
1959 dwMS = (dwMS + 500) / 1000;
1960 dwHours = dwMS / 3600;
1961 dwMS -= dwHours * 3600;
1962 dwMinutes = dwMS / 60;
1963 dwMS -= dwMinutes * 60;
1965 szCopy[0] = '\0';
1967 if (dwHours)
1968 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
1970 if (dwMinutes && iDigits)
1971 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
1973 if (iDigits) /* Always write seconds if we have significant digits */
1974 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
1976 strncpyW(lpszStr, szCopy, cchMax);
1977 iRet = strlenW(lpszStr);
1979 return iRet;
1982 /*************************************************************************
1983 * StrIsIntlEqualA [SHLWAPI.@]
1985 * Compare two strings.
1987 * PARAMS
1988 * bCase [I] Whether to compare case sensitively
1989 * lpszStr [I] First string to compare
1990 * lpszComp [I] Second string to compare
1991 * iLen [I] Length to compare
1993 * RETURNS
1994 * TRUE If the strings are equal.
1995 * FALSE Otherwise.
1997 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
1998 int iLen)
2000 DWORD dwFlags = LOCALE_USE_CP_ACP;
2001 int iRet;
2003 TRACE("(%d,%s,%s,%d)\n", bCase,
2004 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2006 /* FIXME: These flags are undocumented and unknown by our CompareString.
2007 * We need defines for them.
2009 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2011 iRet = CompareStringA(GetThreadLocale(),
2012 dwFlags, lpszStr, iLen, lpszComp, iLen);
2014 if (!iRet)
2015 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2017 return iRet == 2 ? TRUE : FALSE;
2020 /*************************************************************************
2021 * StrIsIntlEqualW [SHLWAPI.@]
2023 * See StrIsIntlEqualA.
2025 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2026 int iLen)
2028 DWORD dwFlags;
2029 int iRet;
2031 TRACE("(%d,%s,%s,%d)\n", bCase,
2032 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2034 /* FIXME: These flags are undocumented and unknown by our CompareString.
2035 * We need defines for them.
2037 dwFlags = bCase ? 0x10000000 : 0x10000001;
2039 iRet = CompareStringW(GetThreadLocale(),
2040 dwFlags, lpszStr, iLen, lpszComp, iLen);
2042 if (!iRet)
2043 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2045 return iRet == 2 ? TRUE : FALSE;
2048 /*************************************************************************
2049 * @ [SHLWAPI.399]
2051 * Copy a string to another string, up to a maximum number of characters.
2053 * PARAMS
2054 * lpszDest [O] Destination string
2055 * lpszSrc [I] Source string
2056 * iLen [I] Maximum number of chars to copy
2058 * RETURNS
2059 * Success: A pointer to the last character written.
2060 * Failure: lpszDest, if any arguments are invalid.
2062 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2064 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2066 if (lpszDest && lpszSrc && iLen > 0)
2068 while ((iLen-- > 1) && *lpszSrc)
2069 *lpszDest++ = *lpszSrc++;
2070 if (iLen >= 0)
2071 *lpszDest = '\0';
2073 return lpszDest;
2076 /*************************************************************************
2077 * @ [SHLWAPI.400]
2079 * Unicode version of SHLWAPI_399.
2081 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2083 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2085 if (lpszDest && lpszSrc && iLen > 0)
2087 while ((iLen-- > 1) && *lpszSrc)
2088 *lpszDest++ = *lpszSrc++;
2089 if (iLen >= 0)
2090 *lpszDest = '\0';
2092 return lpszDest;
2095 /*************************************************************************
2096 * StrCmpLogicalW [SHLWAPI.@]
2098 * Compare two strings, ignoring case and comparing digits as numbers.
2100 * PARAMS
2101 * lpszStr [I] First string to compare
2102 * lpszComp [I] Second string to compare
2103 * iLen [I] Length to compare
2105 * RETURNS
2106 * TRUE If the strings are equal.
2107 * FALSE Otherwise.
2109 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2111 INT iDiff;
2113 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2115 if (lpszStr && lpszComp)
2117 while (*lpszStr)
2119 if (!*lpszComp)
2120 return 1;
2121 else if (isdigitW(*lpszStr))
2123 int iStr, iComp;
2125 if (!isdigitW(*lpszComp))
2126 return -1;
2128 /* Compare the numbers */
2129 StrToIntExW(lpszStr, 0, &iStr);
2130 StrToIntExW(lpszComp, 0, &iComp);
2132 if (iStr < iComp)
2133 return -1;
2134 else if (iStr > iComp)
2135 return 1;
2137 /* Skip */
2138 while (isdigitW(*lpszStr))
2139 lpszStr++;
2140 while (isdigitW(*lpszComp))
2141 lpszComp++;
2143 else if (isdigitW(*lpszComp))
2144 return 1;
2145 else
2147 iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE);
2148 if (iDiff > 0)
2149 return 1;
2150 else if (iDiff < 0)
2151 return -1;
2153 lpszStr++;
2154 lpszComp++;
2157 if (*lpszComp)
2158 return -1;
2160 return 0;
2163 /* Structure for formatting byte strings */
2164 typedef struct tagSHLWAPI_BYTEFORMATS
2166 LONGLONG dLimit;
2167 double dDivisor;
2168 double dNormaliser;
2169 LPCSTR lpszFormat;
2170 CHAR wPrefix;
2171 } SHLWAPI_BYTEFORMATS;
2173 /*************************************************************************
2174 * StrFormatByteSize64A [SHLWAPI.@]
2176 * Create a string containing an abbreviated byte count of up to 2^63-1.
2178 * PARAMS
2179 * llBytes [I] Byte size to format
2180 * lpszDest [I] Destination for formatted string
2181 * cchMax [I] Size of lpszDest
2183 * RETURNS
2184 * lpszDest.
2186 * NOTES
2187 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW.
2189 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2191 static const char szBytes[] = "%ld bytes";
2192 static const char sz3_0[] = "%3.0f";
2193 static const char sz3_1[] = "%3.1f";
2194 static const char sz3_2[] = "%3.2f";
2196 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2198 { 10240, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */
2199 { 102400, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */
2200 { 1024000, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */
2201 { 10485760, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */
2202 { 104857600, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */
2203 { 1048576000, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */
2204 { 10737418240, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */
2205 { 107374182400, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */
2206 { 1073741824000, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */
2207 { 10995116277760, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */
2208 { 109951162777600, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */
2209 { 1099511627776000, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */
2210 { 11258999068426240, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */
2211 { 112589990684262400, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */
2212 { 1125899906842624000, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */
2213 { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */
2215 char szBuff[32];
2216 char szAdd[4];
2217 double dBytes;
2218 UINT i = 0;
2220 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2222 if (!lpszDest || !cchMax)
2223 return lpszDest;
2225 if (llBytes < 1024) /* 1K */
2227 snprintf (lpszDest, cchMax, szBytes, (long)llBytes);
2228 return lpszDest;
2231 /* Note that if this loop completes without finding a match, i will be
2232 * pointing at the last entry, which is a catch all for > 1000 PB
2234 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2236 if (llBytes < bfFormats[i].dLimit)
2237 break;
2238 i++;
2240 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2241 * this number we integer shift down by 1 MB first. The table above has
2242 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2243 * for this. We also add a small fudge factor to get the correct result for
2244 * counts that lie exactly on a 1024 byte boundary.
2246 if (i > 8)
2247 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2248 else
2249 dBytes = (double)llBytes + 0.00001;
2251 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2253 sprintf(szBuff, bfFormats[i].lpszFormat, dBytes);
2254 szAdd[0] = ' ';
2255 szAdd[1] = bfFormats[i].wPrefix;
2256 szAdd[2] = 'B';
2257 szAdd[3] = '\0';
2258 strcat(szBuff, szAdd);
2259 strncpy(lpszDest, szBuff, cchMax);
2260 return lpszDest;
2263 /*************************************************************************
2264 * StrFormatByteSizeW [SHLWAPI.@]
2266 * See StrFormatByteSize64A.
2268 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest,
2269 UINT cchMax)
2271 char szBuff[32];
2273 StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff));
2275 if (lpszDest)
2276 MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax);
2277 return lpszDest;
2280 /*************************************************************************
2281 * StrFormatByteSizeA [SHLWAPI.@]
2283 * Create a string containing an abbreviated byte count of up to 2^31-1.
2285 * PARAMS
2286 * dwBytes [I] Byte size to format
2287 * lpszDest [I] Destination for formatted string
2288 * cchMax [I] Size of lpszDest
2290 * RETURNS
2291 * lpszDest.
2293 * NOTES
2294 * The ASCII and Unicode versions of this function accept a different
2295 * integer size for dwBytes. See StrFormatByteSize64A.
2297 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2299 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2301 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);