Release 20030408.
[wine/gsoc-2012-control.git] / dlls / shlwapi / string.c
blob7b7d4a5f4cc6ccbef21a80391185c26b40591c08
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 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "winerror.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "winreg.h"
40 #define NO_SHLWAPI_STREAM
41 #include "shlwapi.h"
42 #include "shlobj.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest);
49 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest);
51 /*************************************************************************
52 * SHLWAPI_ChrCmpHelperA
54 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
56 * NOTES
57 * Both this function and its Unicode counterpart are very inneficient. To
58 * fix this, CompareString must be completely implemented and optimised
59 * first. Then the core character test can be taken out of that function and
60 * placed here, so that it need never be called at all. Until then, do not
61 * attempt to optimise this code unless you are willing to test that it
62 * still performs correctly.
64 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
66 char str1[3], str2[3];
68 str1[0] = LOBYTE(ch1);
69 if (IsDBCSLeadByte(ch1))
71 str1[1] = HIBYTE(ch1);
72 str1[2] = '\0';
74 else
75 str1[1] = '\0';
77 str2[0] = LOBYTE(ch2);
78 if (IsDBCSLeadByte(ch2))
80 str2[1] = HIBYTE(ch2);
81 str2[2] = '\0';
83 else
84 str2[1] = '\0';
86 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
89 /*************************************************************************
90 * SHLWAPI_ChrCmpHelperW
92 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
94 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
96 WCHAR str1[2], str2[2];
98 str1[0] = ch1;
99 str1[1] = '\0';
100 str2[0] = ch2;
101 str2[1] = '\0';
102 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
105 /*************************************************************************
106 * SHLWAPI_ChrCmpA
108 * Internal helper function.
110 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
112 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
115 /*************************************************************************
116 * ChrCmpIA (SHLWAPI.385)
118 * Compare two characters, ignoring case.
120 * PARAMS
121 * ch1 [I] First character to compare
122 * ch2 [I] Second character to compare
124 * RETURNS
125 * FALSE, if the characters are equal.
126 * Non-zero otherwise.
128 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
130 TRACE("(%d,%d)\n", ch1, ch2);
132 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
135 /*************************************************************************
136 * SHLWAPI_ChrCmpW
138 * Internal helper function.
140 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
142 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
145 /*************************************************************************
146 * ChrCmpIW [SHLWAPI.386]
148 * See ChrCmpIA.
150 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
152 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
155 /*************************************************************************
156 * StrChrA [SHLWAPI.@]
158 * Find a given character in a string.
160 * PARAMS
161 * lpszStr [I] String to search in.
162 * ch [I] Character to search for.
164 * RETURNS
165 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
166 * not found.
167 * Failure: NULL, if any arguments are invalid.
169 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
171 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
173 if (lpszStr)
175 while (*lpszStr)
177 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
178 return (LPSTR)lpszStr;
179 lpszStr = CharNextA(lpszStr);
182 return NULL;
185 /*************************************************************************
186 * StrChrW [SHLWAPI.@]
188 * See StrChrA.
190 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
192 LPWSTR lpszRet = NULL;
194 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
196 if (lpszStr)
197 lpszRet = strchrW(lpszStr, ch);
198 return lpszRet;
201 /*************************************************************************
202 * StrChrIA [SHLWAPI.@]
204 * Find a given character in a string, ignoring case.
206 * PARAMS
207 * lpszStr [I] String to search in.
208 * ch [I] Character to search for.
210 * RETURNS
211 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
212 * not found.
213 * Failure: NULL, if any arguments are invalid.
215 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
217 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
219 if (lpszStr)
221 while (*lpszStr)
223 if (!ChrCmpIA(*lpszStr, ch))
224 return (LPSTR)lpszStr;
225 lpszStr = CharNextA(lpszStr);
228 return NULL;
231 /*************************************************************************
232 * StrChrIW [SHLWAPI.@]
234 * See StrChrA.
236 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
238 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
240 if (lpszStr)
242 ch = toupperW(ch);
243 while (*lpszStr)
245 if (toupperW(*lpszStr) == ch)
246 return (LPWSTR)lpszStr;
247 lpszStr = CharNextW(lpszStr);
249 lpszStr = NULL;
251 return (LPWSTR)lpszStr;
254 /*************************************************************************
255 * StrCmpIW [SHLWAPI.@]
257 * Compare two strings, ignoring case.
259 * PARAMS
260 * lpszStr [I] First string to compare
261 * lpszComp [I] Second string to compare
263 * RETURNS
264 * An integer less than, equal to or greater than 0, indicating that
265 * lpszStr is less than, the same, or greater than lpszComp.
267 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
269 INT iRet;
271 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
273 iRet = strcmpiW(lpszStr, lpszComp);
274 return iRet < 0 ? -1 : iRet ? 1 : 0;
277 /*************************************************************************
278 * SHLWAPI_StrCmpNHelperA
280 * Internal helper for StrCmpNA/StrCmpNIA.
282 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
283 INT iLen,
284 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
286 if (!lpszStr)
288 if (!lpszComp)
289 return 0;
290 return 1;
292 else if (!lpszComp)
293 return -1;
295 while (iLen-- > 0)
297 int iDiff;
298 WORD ch1, ch2;
300 ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
301 ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
303 if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
304 return -1;
305 else if (iDiff > 0)
306 return 1;
307 else if (!*lpszStr && !*lpszComp)
308 return 0;
310 lpszStr = CharNextA(lpszStr);
311 lpszComp = CharNextA(lpszComp);
313 return 0;
316 /*************************************************************************
317 * StrCmpNA [SHLWAPI.@]
319 * Compare two strings, up to a maximum length.
321 * PARAMS
322 * lpszStr [I] First string to compare
323 * lpszComp [I] Second string to compare
324 * iLen [I] Maximum number of chars to compare.
326 * RETURNS
327 * An integer less than, equal to or greater than 0, indicating that
328 * lpszStr is less than, the same, or greater than lpszComp.
330 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
332 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
334 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
337 /*************************************************************************
338 * StrCmpNW [SHLWAPI.@]
340 * See StrCmpNA.
342 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
344 INT iRet;
346 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
348 iRet = strncmpW(lpszStr, lpszComp, iLen);
349 return iRet < 0 ? -1 : iRet ? 1 : 0;
352 /*************************************************************************
353 * StrCmpNIA [SHLWAPI.@]
355 * Compare two strings, up to a maximum length, ignoring case.
357 * PARAMS
358 * lpszStr [I] First string to compare
359 * lpszComp [I] Second string to compare
360 * iLen [I] Maximum number of chars to compare.
362 * RETURNS
363 * An integer less than, equal to or greater than 0, indicating that
364 * lpszStr is less than, the same, or greater than lpszComp.
366 * NOTES
367 * The Win32 version of this function is _completely_ broken for cases
368 * where iLen is greater than the length of lpszComp. Examples:
370 *| StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
371 *| StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
372 *| StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
374 * This implementation behaves correctly, since it is unlikely any
375 * applications actually rely on this function being broken.
377 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
379 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
381 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
384 /*************************************************************************
385 * StrCmpNIW [SHLWAPI.@]
387 * See StrCmpNIA.
389 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
391 INT iRet;
393 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
395 iRet = strncmpiW(lpszStr, lpszComp, iLen);
396 return iRet < 0 ? -1 : iRet ? 1 : 0;
399 /*************************************************************************
400 * StrCmpW [SHLWAPI.@]
402 * Compare two strings.
404 * PARAMS
405 * lpszStr [I] First string to compare
406 * lpszComp [I] Second string to compare
408 * RETURNS
409 * An integer less than, equal to or greater than 0, indicating that
410 * lpszStr is less than, the same, or greater than lpszComp.
412 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
414 INT iRet;
416 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
418 iRet = strcmpW(lpszStr, lpszComp);
419 return iRet < 0 ? -1 : iRet ? 1 : 0;
422 /*************************************************************************
423 * StrCatW [SHLWAPI.@]
425 * Concatanate two strings.
427 * PARAMS
428 * lpszStr [O] Initial string
429 * lpszSrc [I] String to concatanate
431 * RETURNS
432 * lpszStr.
434 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
436 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
438 strcatW(lpszStr, lpszSrc);
439 return lpszStr;
442 /*************************************************************************
443 * StrCpyW [SHLWAPI.@]
445 * Copy a string to another string.
447 * PARAMS
448 * lpszStr [O] Destination string
449 * lpszSrc [I] Source string
451 * RETURNS
452 * lpszStr.
454 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
456 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
458 strcpyW(lpszStr, lpszSrc);
459 return lpszStr;
462 /*************************************************************************
463 * StrCpyNW [SHLWAPI.@]
465 * Copy a string to another string, up to a maximum number of characters.
467 * PARAMS
468 * lpszStr [O] Destination string
469 * lpszSrc [I] Source string
470 * iLen [I] Maximum number of chars to copy
472 * RETURNS
473 * lpszStr.
475 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
477 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
479 lstrcpynW(lpszStr, lpszSrc, iLen);
480 return lpszStr;
485 /*************************************************************************
486 * SHLWAPI_StrStrHelperA
488 * Internal implementation of StrStrA/StrStrIA
490 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
491 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
493 size_t iLen;
495 if (!lpszStr || !lpszSearch || !*lpszSearch)
496 return NULL;
498 iLen = strlen(lpszSearch);
500 while (*lpszStr)
502 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
503 return (LPSTR)lpszStr;
504 lpszStr = CharNextA(lpszStr);
506 return NULL;
509 /*************************************************************************
510 * SHLWAPI_StrStrHelperW
512 * Internal implementation of StrStrW/StrStrIW
514 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
515 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
517 int iLen;
519 if (!lpszStr || !lpszSearch || !*lpszSearch)
520 return NULL;
522 iLen = strlenW(lpszSearch);
524 while (*lpszStr)
526 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
527 return (LPWSTR)lpszStr;
528 lpszStr = CharNextW(lpszStr);
530 return NULL;
533 /*************************************************************************
534 * StrStrA [SHLWAPI.@]
536 * Find a substring within a string.
538 * PARAMS
539 * lpszStr [I] String to search in
540 * lpszSearch [I] String to look for
542 * RETURNS
543 * The start of lpszSearch within lpszStr, or NULL if not found.
545 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
547 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
549 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
552 /*************************************************************************
553 * StrStrW [SHLWAPI.@]
555 * See StrStrA.
557 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
559 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
561 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
564 /*************************************************************************
565 * StrRStrIA [SHLWAPI.@]
567 * Find the last occurence of a substring within a string.
569 * PARAMS
570 * lpszStr [I] String to search in
571 * lpszEnd [I] End of lpszStr
572 * lpszSearch [I] String to look for
574 * RETURNS
575 * The last occurence lpszSearch within lpszStr, or NULL if not found.
577 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
579 LPSTR lpszRet = NULL;
580 WORD ch1, ch2;
581 INT iLen;
583 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
585 if (!lpszStr || !lpszSearch || !*lpszSearch)
586 return NULL;
588 if (!lpszEnd)
589 lpszEnd = lpszStr + lstrlenA(lpszStr);
591 if (IsDBCSLeadByte(*lpszSearch))
592 ch1 = *lpszSearch << 8 | lpszSearch[1];
593 else
594 ch1 = *lpszSearch;
595 iLen = lstrlenA(lpszSearch);
597 while (lpszStr <= lpszEnd && *lpszStr)
599 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
600 if (!ChrCmpIA(ch1, ch2))
602 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
603 lpszRet = (LPSTR)lpszStr;
605 lpszStr = CharNextA(lpszStr);
607 return lpszRet;
610 /*************************************************************************
611 * StrRStrIW [SHLWAPI.@]
613 * See StrRStrIA.
615 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
617 LPWSTR lpszRet = NULL;
618 INT iLen;
620 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
622 if (!lpszStr || !lpszSearch || !*lpszSearch)
623 return NULL;
625 if (!lpszEnd)
626 lpszEnd = lpszStr + strlenW(lpszStr);
628 iLen = strlenW(lpszSearch);
630 while (lpszStr <= lpszEnd && *lpszStr)
632 if (!ChrCmpIA(*lpszSearch, *lpszStr))
634 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
635 lpszRet = (LPWSTR)lpszStr;
637 lpszStr = CharNextW(lpszStr);
639 return lpszRet;
642 /*************************************************************************
643 * StrStrIA [SHLWAPI.@]
645 * Find a substring within a string, ignoring case.
647 * PARAMS
648 * lpszStr [I] String to search in
649 * lpszSearch [I] String to look for
651 * RETURNS
652 * The start of lpszSearch within lpszStr, or NULL if not found.
654 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
656 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
658 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
661 /*************************************************************************
662 * StrStrIW [SHLWAPI.@]
664 * See StrStrIA.
666 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
668 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
670 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
673 /*************************************************************************
674 * StrToIntA [SHLWAPI.@]
676 * Read an integer from a string.
678 * PARAMS
679 * lpszStr [I] String to read integer from
681 * RETURNS
682 * The integer value represented by the string, or 0 if no integer is
683 * present.
685 * NOTES
686 * No leading space is allowed before the number, although a leading '-' is.
688 int WINAPI StrToIntA(LPCSTR lpszStr)
690 int iRet = 0;
692 TRACE("(%s)\n", debugstr_a(lpszStr));
694 if (!lpszStr)
696 WARN("Invalid lpszStr would crash under Win32!\n");
697 return 0;
700 if (*lpszStr == '-' || isdigit(*lpszStr))
701 StrToIntExA(lpszStr, 0, &iRet);
702 return iRet;
705 /*************************************************************************
706 * StrToIntW [SHLWAPI.@]
708 * See StrToIntA.
710 int WINAPI StrToIntW(LPCWSTR lpszStr)
712 int iRet = 0;
714 TRACE("(%s)\n", debugstr_w(lpszStr));
716 if (!lpszStr)
718 WARN("Invalid lpszStr would crash under Win32!\n");
719 return 0;
722 if (*lpszStr == '-' || isdigitW(*lpszStr))
723 StrToIntExW(lpszStr, 0, &iRet);
724 return iRet;
727 /*************************************************************************
728 * StrToIntExA [SHLWAPI.@]
730 * Read an integer from a string.
732 * PARAMS
733 * lpszStr [I] String to read integer from
734 * dwFlags [I] Flags controlling the conversion
735 * lpiRet [O] Destination for read integer.
737 * RETURNS
738 * Success: TRUE. lpiRet contains the integer value represented by the string.
739 * Failure: FALSE, if the string is invalid, or no number is present.
741 * NOTES
742 * Leading whitespace, '-' and '+' are allowed before the number. If
743 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
744 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
745 * the string is treated as a decimal string. A leading '-' is ignored for
746 * hexidecimal numbers.
748 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
750 BOOL bNegative = FALSE;
751 int iRet = 0;
753 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
755 if (!lpszStr || !lpiRet)
757 WARN("Invalid parameter would crash under Win32!\n");
758 return FALSE;
760 if (dwFlags > STIF_SUPPORT_HEX)
762 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
765 /* Skip leading space, '+', '-' */
766 while (isspace(*lpszStr))
767 lpszStr = CharNextA(lpszStr);
769 if (*lpszStr == '-')
771 bNegative = TRUE;
772 lpszStr++;
774 else if (*lpszStr == '+')
775 lpszStr++;
777 if (dwFlags & STIF_SUPPORT_HEX &&
778 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
780 /* Read hex number */
781 lpszStr += 2;
783 if (!isxdigit(*lpszStr))
784 return FALSE;
786 while (isxdigit(*lpszStr))
788 iRet = iRet * 16;
789 if (isdigit(*lpszStr))
790 iRet += (*lpszStr - '0');
791 else
792 iRet += 10 + (tolower(*lpszStr) - 'a');
793 lpszStr++;
795 *lpiRet = iRet;
796 return TRUE;
799 /* Read decimal number */
800 if (!isdigit(*lpszStr))
801 return FALSE;
803 while (isdigit(*lpszStr))
805 iRet = iRet * 10;
806 iRet += (*lpszStr - '0');
807 lpszStr++;
809 *lpiRet = bNegative ? -iRet : iRet;
810 return TRUE;
813 /*************************************************************************
814 * StrToIntExW [SHLWAPI.@]
816 * See StrToIntExA.
818 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
820 BOOL bNegative = FALSE;
821 int iRet = 0;
823 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
825 if (!lpszStr || !lpiRet)
827 WARN("Invalid parameter would crash under Win32!\n");
828 return FALSE;
830 if (dwFlags > STIF_SUPPORT_HEX)
832 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
835 /* Skip leading space, '+', '-' */
836 while (isspaceW(*lpszStr))
837 lpszStr = CharNextW(lpszStr);
839 if (*lpszStr == '-')
841 bNegative = TRUE;
842 lpszStr++;
844 else if (*lpszStr == '+')
845 lpszStr++;
847 if (dwFlags & STIF_SUPPORT_HEX &&
848 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
850 /* Read hex number */
851 lpszStr += 2;
853 if (!isxdigitW(*lpszStr))
854 return FALSE;
856 while (isxdigitW(*lpszStr))
858 iRet = iRet * 16;
859 if (isdigitW(*lpszStr))
860 iRet += (*lpszStr - '0');
861 else
862 iRet += 10 + (tolowerW(*lpszStr) - 'a');
863 lpszStr++;
865 *lpiRet = iRet;
866 return TRUE;
869 /* Read decimal number */
870 if (!isdigitW(*lpszStr))
871 return FALSE;
873 while (isdigitW(*lpszStr))
875 iRet = iRet * 10;
876 iRet += (*lpszStr - '0');
877 lpszStr++;
879 *lpiRet = bNegative ? -iRet : iRet;
880 return TRUE;
883 /*************************************************************************
884 * StrDupA [SHLWAPI.@]
886 * Duplicate a string.
888 * PARAMS
889 * lpszStr [I] String to duplicate.
891 * RETURNS
892 * Success: A pointer to a new string containing the contents of lpszStr
893 * Failure: NULL, if memory cannot be allocated
895 * NOTES
896 * The string memory is allocated with LocalAlloc(), and so should be released
897 * by calling LocalFree().
899 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
901 int iLen;
902 LPSTR lpszRet;
904 TRACE("(%s)\n",debugstr_a(lpszStr));
906 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
907 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
909 if (lpszRet)
911 if (lpszStr)
912 memcpy(lpszRet, lpszStr, iLen);
913 else
914 *lpszRet = '\0';
916 return lpszRet;
919 /*************************************************************************
920 * StrDupW [SHLWAPI.@]
922 * See StrDupA.
924 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
926 int iLen;
927 LPWSTR lpszRet;
929 TRACE("(%s)\n",debugstr_w(lpszStr));
931 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
932 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
934 if (lpszRet)
936 if (lpszStr)
937 memcpy(lpszRet, lpszStr, iLen);
938 else
939 *lpszRet = '\0';
941 return lpszRet;
944 /*************************************************************************
945 * SHLWAPI_StrSpnHelperA
947 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
949 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
950 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
951 BOOL bInvert)
953 LPCSTR lpszRead = lpszStr;
954 if (lpszStr && *lpszStr && lpszMatch)
956 while (*lpszRead)
958 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
960 if (!bInvert && !lpszTest)
961 break;
962 if (bInvert && lpszTest)
963 break;
964 lpszRead = CharNextA(lpszRead);
967 return lpszRead - lpszStr;
970 /*************************************************************************
971 * SHLWAPI_StrSpnHelperW
973 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
975 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
976 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
977 BOOL bInvert)
979 LPCWSTR lpszRead = lpszStr;
980 if (lpszStr && *lpszStr && lpszMatch)
982 while (*lpszRead)
984 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
986 if (!bInvert && !lpszTest)
987 break;
988 if (bInvert && lpszTest)
989 break;
990 lpszRead = CharNextW(lpszRead);
993 return lpszRead - lpszStr;
996 /*************************************************************************
997 * StrSpnA [SHLWAPI.@]
999 * Find the length of the start of a string that contains only certain
1000 * characters.
1002 * PARAMS
1003 * lpszStr [I] String to search
1004 * lpszMatch [I] Characters that can be in the substring
1006 * RETURNS
1007 * The length of the part of lpszStr containing only chars from lpszMatch,
1008 * or 0 if any parameter is invalid.
1010 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1012 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1014 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1017 /*************************************************************************
1018 * StrSpnW [SHLWAPI.@]
1020 * See StrSpnA.
1022 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1024 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1026 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1029 /*************************************************************************
1030 * StrCSpnA [SHLWAPI.@]
1032 * Find the length of the start of a string that does not contain certain
1033 * characters.
1035 * PARAMS
1036 * lpszStr [I] String to search
1037 * lpszMatch [I] Characters that cannot be in the substring
1039 * RETURNS
1040 * The length of the part of lpszStr containing only chars not in lpszMatch,
1041 * or 0 if any parameter is invalid.
1043 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1045 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1047 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1050 /*************************************************************************
1051 * StrCSpnW [SHLWAPI.@]
1053 * See StrCSpnA.
1055 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1057 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1059 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1062 /*************************************************************************
1063 * StrCSpnIA [SHLWAPI.@]
1065 * Find the length of the start of a string that does not contain certain
1066 * characters, ignoring case.
1068 * PARAMS
1069 * lpszStr [I] String to search
1070 * lpszMatch [I] Characters that cannot be in the substring
1072 * RETURNS
1073 * The length of the part of lpszStr containing only chars not in lpszMatch,
1074 * or 0 if any parameter is invalid.
1076 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1078 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1080 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1083 /*************************************************************************
1084 * StrCSpnIW [SHLWAPI.@]
1086 * See StrCSpnIA.
1088 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1090 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1092 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1095 /*************************************************************************
1096 * StrPBrkA [SHLWAPI.@]
1098 * Search a string for any of a group of characters.
1100 * PARAMS
1101 * lpszStr [I] String to search
1102 * lpszMatch [I] Characters to match
1104 * RETURNS
1105 * A pointer to the first matching character in lpszStr, or NULL if no
1106 * match was found.
1108 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1110 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1112 if (lpszStr && lpszMatch && *lpszMatch)
1114 while (*lpszStr)
1116 if (StrChrA(lpszMatch, *lpszStr))
1117 return (LPSTR)lpszStr;
1118 lpszStr = CharNextA(lpszStr);
1121 return NULL;
1124 /*************************************************************************
1125 * StrPBrkW [SHLWAPI.@]
1127 * See StrPBrkA.
1129 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1131 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1133 if (lpszStr && lpszMatch && *lpszMatch)
1135 while (*lpszStr)
1137 if (StrChrW(lpszMatch, *lpszStr))
1138 return (LPWSTR)lpszStr;
1139 lpszStr = CharNextW(lpszStr);
1142 return NULL;
1145 /*************************************************************************
1146 * SHLWAPI_StrRChrHelperA
1148 * Internal implementation of StrRChrA/StrRChrIA.
1150 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1151 LPCSTR lpszEnd, WORD ch,
1152 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1154 LPCSTR lpszRet = NULL;
1156 if (lpszStr)
1158 WORD ch2;
1160 if (!lpszEnd)
1161 lpszEnd = lpszStr + lstrlenA(lpszStr);
1163 while (*lpszStr && lpszStr <= lpszEnd)
1165 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1167 if (!pChrCmpFn(ch, ch2))
1168 lpszRet = lpszStr;
1169 lpszStr = CharNextA(lpszStr);
1172 return (LPSTR)lpszRet;
1175 /*************************************************************************
1176 * SHLWAPI_StrRChrHelperW
1178 * Internal implementation of StrRChrW/StrRChrIW.
1180 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1181 LPCWSTR lpszEnd, WCHAR ch,
1182 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1184 LPCWSTR lpszRet = NULL;
1186 if (lpszStr)
1188 if (!lpszEnd)
1189 lpszEnd = lpszStr + strlenW(lpszStr);
1191 while (*lpszStr && lpszStr <= lpszEnd)
1193 if (!pChrCmpFn(ch, *lpszStr))
1194 lpszRet = lpszStr;
1195 lpszStr = CharNextW(lpszStr);
1198 return (LPWSTR)lpszRet;
1201 /**************************************************************************
1202 * StrRChrA [SHLWAPI.@]
1204 * Find the last occurence of a character in string.
1206 * PARAMS
1207 * lpszStr [I] String to search in
1208 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1209 * ch [I] Character to search for.
1211 * RETURNS
1212 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1213 * or NULL if not found.
1214 * Failure: NULL, if any arguments are invalid.
1216 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1218 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1220 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1223 /**************************************************************************
1224 * StrRChrW [SHLWAPI.@]
1226 * See StrRChrA.
1228 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1230 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1232 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1235 /**************************************************************************
1236 * StrRChrIA [SHLWAPI.@]
1238 * Find the last occurence of a character in string, ignoring case.
1240 * PARAMS
1241 * lpszStr [I] String to search in
1242 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1243 * ch [I] Character to search for.
1245 * RETURNS
1246 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1247 * or NULL if not found.
1248 * Failure: NULL, if any arguments are invalid.
1250 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1252 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1254 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1257 /**************************************************************************
1258 * StrRChrIW [SHLWAPI.@]
1260 * See StrRChrIA.
1262 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1264 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1266 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1269 /*************************************************************************
1270 * StrCatBuffA [SHLWAPI.@]
1272 * Concatenate two strings together.
1274 * PARAMS
1275 * lpszStr [O] String to concatenate to
1276 * lpszCat [I] String to add to lpszCat
1277 * cchMax [I] Maximum number of characters for the whole string
1279 * RETURNS
1280 * lpszStr.
1282 * NOTES
1283 * cchMax dtermines the number of characters in the final length of the
1284 * string, not the number appended to lpszStr from lpszCat.
1286 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1288 INT iLen;
1290 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1292 if (!lpszStr)
1294 WARN("Invalid lpszStr would crash under Win32!\n");
1295 return NULL;
1298 iLen = strlen(lpszStr);
1299 cchMax -= iLen;
1301 if (cchMax > 0)
1302 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1303 return lpszStr;
1306 /*************************************************************************
1307 * StrCatBuffW [SHLWAPI.@]
1309 * See StrCatBuffA.
1311 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1313 INT iLen;
1315 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1317 if (!lpszStr)
1319 WARN("Invalid lpszStr would crash under Win32!\n");
1320 return NULL;
1323 iLen = strlenW(lpszStr);
1324 cchMax -= iLen;
1326 if (cchMax > 0)
1327 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1328 return lpszStr;
1331 /*************************************************************************
1332 * StrRetToBufA [SHLWAPI.@]
1334 * Convert a STRRET to a normal string.
1336 * PARAMS
1337 * lpStrRet [O] STRRET to convert
1338 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1339 * lpszDest [O] Destination for normal string
1340 * dwLen [I] Length of lpszDest
1342 * RETURNS
1343 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1344 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1345 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1346 * Failure: E_FAIL, if any parameters are invalid.
1348 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1350 /* NOTE:
1351 * This routine is identical to that in dlls/shell32/shellstring.c.
1352 * It was duplicated because not every version of Shlwapi.dll exports
1353 * StrRetToBufA. If you change one routine, change them both.
1355 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1357 if (!src)
1359 WARN("Invalid lpStrRet would crash under Win32!\n");
1360 if (dest)
1361 *dest = '\0';
1362 return E_FAIL;
1365 if (!dest || !len)
1366 return E_FAIL;
1368 *dest = '\0';
1370 switch (src->uType)
1372 case STRRET_WSTR:
1373 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1374 CoTaskMemFree(src->u.pOleStr);
1375 break;
1377 case STRRET_CSTR:
1378 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1379 break;
1381 case STRRET_OFFSET:
1382 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1383 break;
1385 default:
1386 FIXME("unknown type!\n");
1387 return FALSE;
1389 return S_OK;
1392 /*************************************************************************
1393 * StrRetToBufW [SHLWAPI.@]
1395 * See StrRetToBufA.
1397 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1399 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1401 if (!src)
1403 WARN("Invalid lpStrRet would crash under Win32!\n");
1404 if (dest)
1405 *dest = '\0';
1406 return E_FAIL;
1409 if (!dest || !len)
1410 return E_FAIL;
1412 *dest = '\0';
1414 switch (src->uType)
1416 case STRRET_WSTR:
1417 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1418 CoTaskMemFree(src->u.pOleStr);
1419 break;
1421 case STRRET_CSTR:
1422 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1423 dest[len-1] = 0;
1424 break;
1426 case STRRET_OFFSET:
1427 if (pidl)
1429 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1430 dest, len ) && len)
1431 dest[len-1] = 0;
1433 break;
1435 default:
1436 FIXME("unknown type!\n");
1437 return FALSE;
1439 return S_OK;
1442 /*************************************************************************
1443 * StrRetToStrA [SHLWAPI.@]
1445 * converts a STRRET to a normal string
1447 HRESULT WINAPI StrRetToStrA(LPSTRRET pstr, const ITEMIDLIST * pidl, LPSTR* ppszName)
1449 HRESULT ret = E_FAIL;
1451 switch (pstr->uType) {
1452 case STRRET_WSTR:
1453 ret = _SHStrDupAW(pstr->u.pOleStr, ppszName);
1454 CoTaskMemFree(pstr->u.pOleStr);
1455 break;
1457 case STRRET_CSTR:
1458 ret = _SHStrDupAA(pstr->u.cStr, ppszName);
1459 break;
1461 case STRRET_OFFSET:
1462 ret = _SHStrDupAA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1463 break;
1465 default:
1466 *ppszName = NULL;
1468 return ret;
1471 /*************************************************************************
1472 * StrRetToStrW [SHLWAPI.@]
1474 * converts a STRRET to a normal string
1476 HRESULT WINAPI StrRetToStrW(LPSTRRET pstr, const ITEMIDLIST * pidl, LPWSTR* ppszName)
1478 HRESULT ret = E_FAIL;
1480 switch (pstr->uType) {
1481 case STRRET_WSTR:
1482 ret = SHStrDupW(pstr->u.pOleStr, ppszName);
1483 CoTaskMemFree(pstr->u.pOleStr);
1484 break;
1486 case STRRET_CSTR:
1487 ret = SHStrDupA(pstr->u.cStr, ppszName);
1488 break;
1490 case STRRET_OFFSET:
1491 ret = SHStrDupA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1492 break;
1494 default:
1495 *ppszName = NULL;
1497 return ret;
1500 /*************************************************************************
1501 * StrFormatKBSizeA [SHLWAPI.@]
1503 * Create a formatted string containing a byte count in Kilobytes.
1505 * PARAMS
1506 * llBytes [I] Byte size to format
1507 * lpszDest [I] Destination for formatted string
1508 * cchMax [I] Size of lpszDest
1510 * RETURNS
1511 * lpszDest.
1513 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1515 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1516 LONGLONG ulKB = (llBytes + 1023) >> 10;
1518 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1520 *szOut-- = '\0';
1521 *szOut-- = 'B';
1522 *szOut-- = 'K';
1523 *szOut-- = ' ';
1527 LONGLONG ulNextDigit = ulKB % 10;
1528 *szOut-- = '0' + ulNextDigit;
1529 ulKB = (ulKB - ulNextDigit) / 10;
1530 } while (ulKB > 0);
1532 strncpy(lpszDest, szOut + 1, cchMax);
1533 return lpszDest;
1536 /*************************************************************************
1537 * StrFormatKBSizeW [SHLWAPI.@]
1539 * See StrFormatKBSizeA.
1541 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1543 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1544 LONGLONG ulKB = (llBytes + 1023) >> 10;
1546 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1548 *szOut-- = '\0';
1549 *szOut-- = 'B';
1550 *szOut-- = 'K';
1551 *szOut-- = ' ';
1555 LONGLONG ulNextDigit = ulKB % 10;
1556 *szOut-- = '0' + ulNextDigit;
1557 ulKB = (ulKB - ulNextDigit) / 10;
1558 } while (ulKB > 0);
1560 strncpyW(lpszDest, szOut + 1, cchMax);
1561 return lpszDest;
1564 /*************************************************************************
1565 * StrNCatA [SHLWAPI.@]
1567 * Concatenate two strings together.
1569 * PARAMS
1570 * lpszStr [O] String to concatenate to
1571 * lpszCat [I] String to add to lpszCat
1572 * cchMax [I] Maximum number of characters to concatenate
1574 * RETURNS
1575 * lpszStr.
1577 * NOTES
1578 * cchMax dtermines the number of characters that are appended to lpszStr,
1579 * not the total length of the string.
1581 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1583 LPSTR lpszRet = lpszStr;
1585 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1587 if (!lpszStr)
1589 WARN("Invalid lpszStr would crash under Win32!\n");
1590 return NULL;
1593 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1594 return lpszRet;
1597 /*************************************************************************
1598 * StrNCatW [SHLWAPI.@]
1600 * See StrNCatA.
1602 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1604 LPWSTR lpszRet = lpszStr;
1606 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1608 if (!lpszStr)
1610 WARN("Invalid lpszStr would crash under Win32\n");
1611 return NULL;
1614 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1615 return lpszRet;
1618 /*************************************************************************
1619 * StrTrimA [SHLWAPI.@]
1621 * Remove characters from the start and end of a string.
1623 * PARAMS
1624 * lpszStr [O] String to remove characters from
1625 * lpszTrim [I] Characters to remove from lpszStr
1627 * RETURNS
1628 * TRUE If lpszStr was valid and modified
1629 * FALSE Otherwise
1631 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1633 DWORD dwLen;
1634 LPSTR lpszRead = lpszStr;
1635 BOOL bRet = FALSE;
1637 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1639 if (lpszRead && *lpszRead)
1641 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1642 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1644 dwLen = strlen(lpszRead);
1646 if (lpszRead != lpszStr)
1648 memmove(lpszStr, lpszRead, dwLen + 1);
1649 bRet = TRUE;
1651 if (dwLen > 0)
1653 lpszRead = lpszStr + dwLen;
1654 while (StrChrA(lpszTrim, lpszRead[-1]))
1655 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1657 if (lpszRead != lpszStr + dwLen)
1659 *lpszRead = '\0';
1660 bRet = TRUE;
1664 return bRet;
1667 /*************************************************************************
1668 * StrTrimW [SHLWAPI.@]
1670 * See StrTrimA.
1672 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1674 DWORD dwLen;
1675 LPWSTR lpszRead = lpszStr;
1676 BOOL bRet = FALSE;
1678 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1680 if (lpszRead && *lpszRead)
1682 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1683 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1685 dwLen = strlenW(lpszRead);
1687 if (lpszRead != lpszStr)
1689 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1690 bRet = TRUE;
1692 if (dwLen > 0)
1694 lpszRead = lpszStr + dwLen;
1695 while (StrChrW(lpszTrim, lpszRead[-1]))
1696 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1698 if (lpszRead != lpszStr + dwLen)
1700 *lpszRead = '\0';
1701 bRet = TRUE;
1705 return bRet;
1708 /*************************************************************************
1709 * _SHStrDupA [INTERNAL]
1711 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1713 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1715 HRESULT hr;
1716 int len = 0;
1718 if (src) {
1719 len = lstrlenA(src) + 1;
1720 *dest = CoTaskMemAlloc(len);
1721 } else {
1722 *dest = NULL;
1725 if (*dest) {
1726 lstrcpynA(*dest,src, len);
1727 hr = S_OK;
1728 } else {
1729 hr = E_OUTOFMEMORY;
1732 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1733 return hr;
1736 /*************************************************************************
1737 * SHStrDupA
1739 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1741 * PARAMS
1742 * lpszStr [I] String to copy
1743 * lppszDest [O] Destination for the new string copy
1745 * RETURNS
1746 * Success: S_OK. lppszDest contains the new string in Unicode format.
1747 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1748 * fails.
1750 HRESULT WINAPI SHStrDupA(LPCSTR src, LPWSTR * dest)
1752 HRESULT hr;
1753 int len = 0;
1755 if (src) {
1756 len = MultiByteToWideChar(0,0,src,-1,0,0)* sizeof(WCHAR);
1757 *dest = CoTaskMemAlloc(len);
1758 } else {
1759 *dest = NULL;
1762 if (*dest) {
1763 MultiByteToWideChar(0,0,src,-1,*dest,len);
1764 hr = S_OK;
1765 } else {
1766 hr = E_OUTOFMEMORY;
1769 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1770 return hr;
1773 /*************************************************************************
1774 * _SHStrDupAW [INTERNAL]
1776 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1778 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1780 HRESULT hr;
1781 int len = 0;
1783 if (src) {
1784 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1785 *dest = CoTaskMemAlloc(len);
1786 } else {
1787 *dest = NULL;
1790 if (*dest) {
1791 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1792 hr = S_OK;
1793 } else {
1794 hr = E_OUTOFMEMORY;
1797 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1798 return hr;
1801 /*************************************************************************
1802 * SHStrDupW
1804 * See SHStrDupA.
1806 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1808 HRESULT hr;
1809 int len = 0;
1811 if (src) {
1812 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1813 *dest = CoTaskMemAlloc(len);
1814 } else {
1815 *dest = NULL;
1818 if (*dest) {
1819 memcpy(*dest, src, len);
1820 hr = S_OK;
1821 } else {
1822 hr = E_OUTOFMEMORY;
1825 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1826 return hr;
1829 /*************************************************************************
1830 * SHLWAPI_WriteReverseNum
1832 * Internal helper for SHLWAPI_WriteTimeClass.
1834 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1836 *lpszOut-- = '\0';
1838 /* Write a decimal number to a string, backwards */
1841 DWORD dwNextDigit = dwNum % 10;
1842 *lpszOut-- = '0' + dwNextDigit;
1843 dwNum = (dwNum - dwNextDigit) / 10;
1844 } while (dwNum > 0);
1846 return lpszOut;
1849 /*************************************************************************
1850 * SHLWAPI_FormatSignificant
1852 * Internal helper for SHLWAPI_WriteTimeClass.
1854 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1856 /* Zero non significant digits, return remaining significant digits */
1857 while (*lpszNum)
1859 lpszNum++;
1860 if (--dwDigits == 0)
1862 while (*lpszNum)
1863 *lpszNum++ = '0';
1864 return 0;
1867 return dwDigits;
1870 /*************************************************************************
1871 * SHLWAPI_WriteTimeClass
1873 * Internal helper for StrFromTimeIntervalW.
1875 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1876 LPCWSTR lpszClass, int iDigits)
1878 WCHAR szBuff[64], *szOut = szBuff + 32;
1880 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1881 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1882 *szOut = ' ';
1883 strcpyW(szBuff + 32, lpszClass);
1884 strcatW(lpszOut, szOut);
1885 return iDigits;
1888 /*************************************************************************
1889 * StrFromTimeIntervalA [SHLWAPI.@]
1891 * Format a millisecond time interval into a string
1893 * PARAMS
1894 * lpszStr [O] Output buffer for formatted time interval
1895 * cchMax [I] Size of lpszStr
1896 * dwMS [I] Number of milliseconds
1897 * iDigits [I] Number of digits to print
1899 * RETURNS
1900 * The length of the formatted string, or 0 if any parameter is invalid.
1902 * NOTES
1903 * This implementation mimics the Win32 behaviour of always writing a leading
1904 * space before the time interval begins.
1906 * iDigits is used to provide approximate times if accuracy is not important.
1907 * This number of digits will be written of the first non-zero time class
1908 * (hours/minutes/seconds). If this does not complete the time classification,
1909 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1910 * If there are digits remaining following the writing of a time class, the
1911 * next time class will be written.
1913 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1914 * following will result from the given values of iDigits:
1916 *| iDigits 1 2 3 4 5 ...
1917 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1919 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1920 int iDigits)
1922 INT iRet = 0;
1924 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1926 if (lpszStr && cchMax)
1928 WCHAR szBuff[128];
1929 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1930 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1932 return iRet;
1936 /*************************************************************************
1937 * StrFromTimeIntervalW [SHLWAPI.@]
1939 * See StrFromTimeIntervalA.
1941 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1942 int iDigits)
1944 static const WCHAR szHr[] = {' ','h','r','\0'};
1945 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1946 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1947 INT iRet = 0;
1949 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1951 if (lpszStr && cchMax)
1953 WCHAR szCopy[128];
1954 DWORD dwHours, dwMinutes;
1956 if (!iDigits || cchMax == 1)
1958 *lpszStr = '\0';
1959 return 0;
1962 /* Calculate the time classes */
1963 dwMS = (dwMS + 500) / 1000;
1964 dwHours = dwMS / 3600;
1965 dwMS -= dwHours * 3600;
1966 dwMinutes = dwMS / 60;
1967 dwMS -= dwMinutes * 60;
1969 szCopy[0] = '\0';
1971 if (dwHours)
1972 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
1974 if (dwMinutes && iDigits)
1975 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
1977 if (iDigits) /* Always write seconds if we have significant digits */
1978 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
1980 strncpyW(lpszStr, szCopy, cchMax);
1981 iRet = strlenW(lpszStr);
1983 return iRet;
1986 /*************************************************************************
1987 * StrIsIntlEqualA [SHLWAPI.@]
1989 * Compare two strings.
1991 * PARAMS
1992 * bCase [I] Whether to compare case sensitively
1993 * lpszStr [I] First string to compare
1994 * lpszComp [I] Second string to compare
1995 * iLen [I] Length to compare
1997 * RETURNS
1998 * TRUE If the strings are equal.
1999 * FALSE Otherwise.
2001 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2002 int iLen)
2004 DWORD dwFlags = LOCALE_USE_CP_ACP;
2005 int iRet;
2007 TRACE("(%d,%s,%s,%d)\n", bCase,
2008 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2010 /* FIXME: These flags are undocumented and unknown by our CompareString.
2011 * We need defines for them.
2013 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2015 iRet = CompareStringA(GetThreadLocale(),
2016 dwFlags, lpszStr, iLen, lpszComp, iLen);
2018 if (!iRet)
2019 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2021 return iRet == 2 ? TRUE : FALSE;
2024 /*************************************************************************
2025 * StrIsIntlEqualW [SHLWAPI.@]
2027 * See StrIsIntlEqualA.
2029 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2030 int iLen)
2032 DWORD dwFlags;
2033 int iRet;
2035 TRACE("(%d,%s,%s,%d)\n", bCase,
2036 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2038 /* FIXME: These flags are undocumented and unknown by our CompareString.
2039 * We need defines for them.
2041 dwFlags = bCase ? 0x10000000 : 0x10000001;
2043 iRet = CompareStringW(GetThreadLocale(),
2044 dwFlags, lpszStr, iLen, lpszComp, iLen);
2046 if (!iRet)
2047 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2049 return iRet == 2 ? TRUE : FALSE;
2052 /*************************************************************************
2053 * @ [SHLWAPI.399]
2055 * Copy a string to another string, up to a maximum number of characters.
2057 * PARAMS
2058 * lpszDest [O] Destination string
2059 * lpszSrc [I] Source string
2060 * iLen [I] Maximum number of chars to copy
2062 * RETURNS
2063 * Success: A pointer to the last character written.
2064 * Failure: lpszDest, if any arguments are invalid.
2066 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2068 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2070 if (lpszDest && lpszSrc && iLen > 0)
2072 while ((iLen-- > 1) && *lpszSrc)
2073 *lpszDest++ = *lpszSrc++;
2074 if (iLen >= 0)
2075 *lpszDest = '\0';
2077 return lpszDest;
2080 /*************************************************************************
2081 * @ [SHLWAPI.400]
2083 * Unicode version of SHLWAPI_399.
2085 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2087 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2089 if (lpszDest && lpszSrc && iLen > 0)
2091 while ((iLen-- > 1) && *lpszSrc)
2092 *lpszDest++ = *lpszSrc++;
2093 if (iLen >= 0)
2094 *lpszDest = '\0';
2096 return lpszDest;
2099 /*************************************************************************
2100 * StrCmpLogicalW [SHLWAPI.@]
2102 * Compare two strings, ignoring case and comparing digits as numbers.
2104 * PARAMS
2105 * lpszStr [I] First string to compare
2106 * lpszComp [I] Second string to compare
2107 * iLen [I] Length to compare
2109 * RETURNS
2110 * TRUE If the strings are equal.
2111 * FALSE Otherwise.
2113 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2115 INT iDiff;
2117 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2119 if (lpszStr && lpszComp)
2121 while (*lpszStr)
2123 if (!*lpszComp)
2124 return 1;
2125 else if (isdigitW(*lpszStr))
2127 int iStr, iComp;
2129 if (!isdigitW(*lpszComp))
2130 return -1;
2132 /* Compare the numbers */
2133 StrToIntExW(lpszStr, 0, &iStr);
2134 StrToIntExW(lpszComp, 0, &iComp);
2136 if (iStr < iComp)
2137 return -1;
2138 else if (iStr > iComp)
2139 return 1;
2141 /* Skip */
2142 while (isdigitW(*lpszStr))
2143 lpszStr++;
2144 while (isdigitW(*lpszComp))
2145 lpszComp++;
2147 else if (isdigitW(*lpszComp))
2148 return 1;
2149 else
2151 iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE);
2152 if (iDiff > 0)
2153 return 1;
2154 else if (iDiff < 0)
2155 return -1;
2157 lpszStr++;
2158 lpszComp++;
2161 if (*lpszComp)
2162 return -1;
2164 return 0;
2167 /* Structure for formatting byte strings */
2168 typedef struct tagSHLWAPI_BYTEFORMATS
2170 LONGLONG dLimit;
2171 double dDivisor;
2172 double dNormaliser;
2173 LPCSTR lpszFormat;
2174 CHAR wPrefix;
2175 } SHLWAPI_BYTEFORMATS;
2177 /*************************************************************************
2178 * StrFormatByteSize64A [SHLWAPI.@]
2180 * Create a string containing an abbreviated byte count of up to 2^63-1.
2182 * PARAMS
2183 * llBytes [I] Byte size to format
2184 * lpszDest [I] Destination for formatted string
2185 * cchMax [I] Size of lpszDest
2187 * RETURNS
2188 * lpszDest.
2190 * NOTES
2191 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2193 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2195 static const char szBytes[] = "%ld bytes";
2196 static const char sz3_0[] = "%3.0f";
2197 static const char sz3_1[] = "%3.1f";
2198 static const char sz3_2[] = "%3.2f";
2200 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2202 { 10240, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */
2203 { 102400, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */
2204 { 1024000, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */
2205 { 10485760, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */
2206 { 104857600, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */
2207 { 1048576000, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */
2208 { 10737418240, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */
2209 { 107374182400, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */
2210 { 1073741824000, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */
2211 { 10995116277760, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */
2212 { 109951162777600, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */
2213 { 1099511627776000, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */
2214 { 11258999068426240, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */
2215 { 112589990684262400, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */
2216 { 1125899906842624000, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */
2217 { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */
2219 char szBuff[32];
2220 char szAdd[4];
2221 double dBytes;
2222 UINT i = 0;
2224 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2226 if (!lpszDest || !cchMax)
2227 return lpszDest;
2229 if (llBytes < 1024) /* 1K */
2231 snprintf (lpszDest, cchMax, szBytes, (long)llBytes);
2232 return lpszDest;
2235 /* Note that if this loop completes without finding a match, i will be
2236 * pointing at the last entry, which is a catch all for > 1000 PB
2238 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2240 if (llBytes < bfFormats[i].dLimit)
2241 break;
2242 i++;
2244 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2245 * this number we integer shift down by 1 MB first. The table above has
2246 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2247 * for this. We also add a small fudge factor to get the correct result for
2248 * counts that lie exactly on a 1024 byte boundary.
2250 if (i > 8)
2251 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2252 else
2253 dBytes = (double)llBytes + 0.00001;
2255 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2257 sprintf(szBuff, bfFormats[i].lpszFormat, dBytes);
2258 szAdd[0] = ' ';
2259 szAdd[1] = bfFormats[i].wPrefix;
2260 szAdd[2] = 'B';
2261 szAdd[3] = '\0';
2262 strcat(szBuff, szAdd);
2263 strncpy(lpszDest, szBuff, cchMax);
2264 return lpszDest;
2267 /*************************************************************************
2268 * StrFormatByteSizeW [SHLWAPI.@]
2270 * See StrFormatByteSize64A.
2272 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest,
2273 UINT cchMax)
2275 char szBuff[32];
2277 StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff));
2279 if (lpszDest)
2280 MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax);
2281 return lpszDest;
2284 /*************************************************************************
2285 * StrFormatByteSizeA [SHLWAPI.@]
2287 * Create a string containing an abbreviated byte count of up to 2^31-1.
2289 * PARAMS
2290 * dwBytes [I] Byte size to format
2291 * lpszDest [I] Destination for formatted string
2292 * cchMax [I] Size of lpszDest
2294 * RETURNS
2295 * lpszDest.
2297 * NOTES
2298 * The Ascii and Unicode versions of this function accept a different
2299 * integer type for dwBytes. See StrFormatByteSize64A().
2301 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2303 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2305 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);