shlwapi: Fix some printf format warnings.
[wine/multimedia.git] / dlls / shlwapi / string.c
blob903c9814e86b253f5f9c498943c4fe82ad78c62b
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <math.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32 #include "windef.h"
33 #include "winbase.h"
34 #define NO_SHLWAPI_REG
35 #define NO_SHLWAPI_STREAM
36 #include "shlwapi.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "shlobj.h"
40 #include "mlang.h"
41 #include "ddeml.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 #include "resource.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(shell);
49 extern HINSTANCE shlwapi_hInstance;
51 static HRESULT _SHStrDupAA(LPCSTR,LPSTR*);
52 static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*);
55 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
56 LPWSTR thousand_buffer, int thousand_bufwlen)
58 WCHAR grouping[64];
59 WCHAR *c;
61 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
62 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
63 fmt->NumDigits = 0;
64 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
65 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
66 fmt->lpThousandSep = thousand_buffer;
67 fmt->lpDecimalSep = decimal_buffer;
69 /*
70 * Converting grouping string to number as described on
71 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
73 fmt->Grouping = 0;
74 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
75 for (c = grouping; *c; c++)
76 if (*c >= '0' && *c < '9')
78 fmt->Grouping *= 10;
79 fmt->Grouping += *c - '0';
82 if (fmt->Grouping % 10 == 0)
83 fmt->Grouping /= 10;
84 else
85 fmt->Grouping *= 10;
88 /*************************************************************************
89 * FormatInt [internal]
91 * Format an integer according to the current locale
93 * RETURNS
94 * The number of bytes written on success or 0 on failure
96 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
98 NUMBERFMTW fmt;
99 WCHAR decimal[8], thousand[8];
100 WCHAR buf[24];
101 WCHAR *c;
102 BOOL neg = (qdwValue < 0);
104 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
105 thousand, sizeof thousand / sizeof (WCHAR));
107 c = &buf[24];
108 *(--c) = 0;
111 *(--c) = '0' + (qdwValue%10);
112 qdwValue /= 10;
113 } while (qdwValue > 0);
114 if (neg)
115 *(--c) = '-';
117 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
120 /*************************************************************************
121 * FormatDouble [internal]
123 * Format an integer according to the current locale. Prints the specified number of digits
124 * after the decimal point
126 * RETURNS
127 * The number of bytes written on success or 0 on failure
129 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
131 static const WCHAR flfmt[] = {'%','f',0};
132 WCHAR buf[64];
133 NUMBERFMTW fmt;
134 WCHAR decimal[8], thousand[8];
136 snprintfW(buf, 64, flfmt, value);
138 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
139 thousand, sizeof thousand / sizeof (WCHAR));
140 fmt.NumDigits = decimals;
141 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
144 /*************************************************************************
145 * SHLWAPI_ChrCmpHelperA
147 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
149 * NOTES
150 * Both this function and its Unicode counterpart are very inefficient. To
151 * fix this, CompareString must be completely implemented and optimised
152 * first. Then the core character test can be taken out of that function and
153 * placed here, so that it need never be called at all. Until then, do not
154 * attempt to optimise this code unless you are willing to test that it
155 * still performs correctly.
157 static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
159 char str1[3], str2[3];
161 str1[0] = LOBYTE(ch1);
162 if (IsDBCSLeadByte(str1[0]))
164 str1[1] = HIBYTE(ch1);
165 str1[2] = '\0';
167 else
168 str1[1] = '\0';
170 str2[0] = LOBYTE(ch2);
171 if (IsDBCSLeadByte(str2[0]))
173 str2[1] = HIBYTE(ch2);
174 str2[2] = '\0';
176 else
177 str2[1] = '\0';
179 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
182 /*************************************************************************
183 * SHLWAPI_ChrCmpA
185 * Internal helper function.
187 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
189 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
192 /*************************************************************************
193 * ChrCmpIA (SHLWAPI.385)
195 * Compare two characters, ignoring case.
197 * PARAMS
198 * ch1 [I] First character to compare
199 * ch2 [I] Second character to compare
201 * RETURNS
202 * FALSE, if the characters are equal.
203 * Non-zero otherwise.
205 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
207 TRACE("(%d,%d)\n", ch1, ch2);
209 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
212 /*************************************************************************
213 * ChrCmpIW [SHLWAPI.386]
215 * See ChrCmpIA.
217 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
219 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - 2;
222 /*************************************************************************
223 * StrChrA [SHLWAPI.@]
225 * Find a given character in a string.
227 * PARAMS
228 * lpszStr [I] String to search in.
229 * ch [I] Character to search for.
231 * RETURNS
232 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
233 * not found.
234 * Failure: NULL, if any arguments are invalid.
236 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
238 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
240 if (lpszStr)
242 while (*lpszStr)
244 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
245 return (LPSTR)lpszStr;
246 lpszStr = CharNextA(lpszStr);
249 return NULL;
252 /*************************************************************************
253 * StrChrW [SHLWAPI.@]
255 * See StrChrA.
257 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
259 LPWSTR lpszRet = NULL;
261 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
263 if (lpszStr)
264 lpszRet = strchrW(lpszStr, ch);
265 return lpszRet;
268 /*************************************************************************
269 * StrChrIA [SHLWAPI.@]
271 * Find a given character in a string, ignoring case.
273 * PARAMS
274 * lpszStr [I] String to search in.
275 * ch [I] Character to search for.
277 * RETURNS
278 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
279 * not found.
280 * Failure: NULL, if any arguments are invalid.
282 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
284 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
286 if (lpszStr)
288 while (*lpszStr)
290 if (!ChrCmpIA(*lpszStr, ch))
291 return (LPSTR)lpszStr;
292 lpszStr = CharNextA(lpszStr);
295 return NULL;
298 /*************************************************************************
299 * StrChrIW [SHLWAPI.@]
301 * See StrChrA.
303 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
305 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
307 if (lpszStr)
309 ch = toupperW(ch);
310 while (*lpszStr)
312 if (toupperW(*lpszStr) == ch)
313 return (LPWSTR)lpszStr;
314 lpszStr++;
316 lpszStr = NULL;
318 return (LPWSTR)lpszStr;
321 /*************************************************************************
322 * StrChrNW [SHLWAPI.@]
324 LPWSTR WINAPI StrChrNW(LPCWSTR lpszStr, WCHAR ch, UINT cchMax)
326 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr,cchMax), cchMax, ch);
328 if (lpszStr)
330 while (*lpszStr && cchMax-- > 0)
332 if (*lpszStr == ch)
333 return (LPWSTR)lpszStr;
334 lpszStr++;
337 return NULL;
340 /*************************************************************************
341 * StrCmpIW [SHLWAPI.@]
343 * Compare two strings, ignoring case.
345 * PARAMS
346 * lpszStr [I] First string to compare
347 * lpszComp [I] Second string to compare
349 * RETURNS
350 * An integer less than, equal to or greater than 0, indicating that
351 * lpszStr is less than, the same, or greater than lpszComp.
353 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
355 int iRet;
357 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
359 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
360 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
363 /*************************************************************************
364 * StrCmpNA [SHLWAPI.@]
366 * Compare two strings, up to a maximum length.
368 * PARAMS
369 * lpszStr [I] First string to compare
370 * lpszComp [I] Second string to compare
371 * iLen [I] Maximum number of chars to compare.
373 * RETURNS
374 * An integer less than, equal to or greater than 0, indicating that
375 * lpszStr is less than, the same, or greater than lpszComp.
377 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
379 INT iRet;
381 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
383 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
384 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
387 /*************************************************************************
388 * StrCmpNW [SHLWAPI.@]
390 * See StrCmpNA.
392 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
394 INT iRet;
396 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
398 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
399 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
402 /*************************************************************************
403 * StrCmpNIA [SHLWAPI.@]
405 * Compare two strings, up to a maximum length, ignoring case.
407 * PARAMS
408 * lpszStr [I] First string to compare
409 * lpszComp [I] Second string to compare
410 * iLen [I] Maximum number of chars to compare.
412 * RETURNS
413 * An integer less than, equal to or greater than 0, indicating that
414 * lpszStr is less than, the same, or greater than lpszComp.
416 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
418 INT iRet;
420 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
422 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
423 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
426 /*************************************************************************
427 * StrCmpNIW [SHLWAPI.@]
429 * See StrCmpNIA.
431 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
433 INT iRet;
435 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
437 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
438 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
441 /*************************************************************************
442 * StrCmpW [SHLWAPI.@]
444 * Compare two strings.
446 * PARAMS
447 * lpszStr [I] First string to compare
448 * lpszComp [I] Second string to compare
450 * RETURNS
451 * An integer less than, equal to or greater than 0, indicating that
452 * lpszStr is less than, the same, or greater than lpszComp.
454 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
456 INT iRet;
458 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
460 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
461 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
464 /*************************************************************************
465 * StrCatW [SHLWAPI.@]
467 * Concatenate two strings.
469 * PARAMS
470 * lpszStr [O] Initial string
471 * lpszSrc [I] String to concatenate
473 * RETURNS
474 * lpszStr.
476 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
478 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
480 strcatW(lpszStr, lpszSrc);
481 return lpszStr;
484 /*************************************************************************
485 * StrCpyW [SHLWAPI.@]
487 * Copy a string to another string.
489 * PARAMS
490 * lpszStr [O] Destination string
491 * lpszSrc [I] Source string
493 * RETURNS
494 * lpszStr.
496 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
498 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
500 strcpyW(lpszStr, lpszSrc);
501 return lpszStr;
504 /*************************************************************************
505 * StrCpyNW [SHLWAPI.@]
507 * Copy a string to another string, up to a maximum number of characters.
509 * PARAMS
510 * dst [O] Destination string
511 * src [I] Source string
512 * count [I] Maximum number of chars to copy
514 * RETURNS
515 * dst.
517 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
519 LPWSTR d = dst;
520 LPCWSTR s = src;
522 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count);
524 if (s)
526 while ((count > 1) && *s)
528 count--;
529 *d++ = *s++;
532 if (count) *d = 0;
534 return dst;
537 /*************************************************************************
538 * SHLWAPI_StrStrHelperA
540 * Internal implementation of StrStrA/StrStrIA
542 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
543 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
545 size_t iLen;
547 if (!lpszStr || !lpszSearch || !*lpszSearch)
548 return NULL;
550 iLen = strlen(lpszSearch);
552 while (*lpszStr)
554 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
555 return (LPSTR)lpszStr;
556 lpszStr = CharNextA(lpszStr);
558 return NULL;
561 /*************************************************************************
562 * StrStrA [SHLWAPI.@]
564 * Find a substring within a string.
566 * PARAMS
567 * lpszStr [I] String to search in
568 * lpszSearch [I] String to look for
570 * RETURNS
571 * The start of lpszSearch within lpszStr, or NULL if not found.
573 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
575 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
577 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
580 /*************************************************************************
581 * StrStrW [SHLWAPI.@]
583 * See StrStrA.
585 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
587 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
589 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL;
590 return strstrW( lpszStr, lpszSearch );
593 /*************************************************************************
594 * StrRStrIA [SHLWAPI.@]
596 * Find the last occurrence of a substring within a string.
598 * PARAMS
599 * lpszStr [I] String to search in
600 * lpszEnd [I] End of lpszStr
601 * lpszSearch [I] String to look for
603 * RETURNS
604 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
606 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
608 WORD ch1, ch2;
609 INT iLen;
611 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
613 if (!lpszStr || !lpszSearch || !*lpszSearch)
614 return NULL;
616 if (!lpszEnd)
617 lpszEnd = lpszStr + lstrlenA(lpszStr);
618 if (lpszEnd == lpszStr)
619 return NULL;
621 if (IsDBCSLeadByte(*lpszSearch))
622 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
623 else
624 ch1 = *lpszSearch;
625 iLen = lstrlenA(lpszSearch);
629 lpszEnd = CharPrevA(lpszStr, lpszEnd);
630 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
631 if (!ChrCmpIA(ch1, ch2))
633 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
634 return (LPSTR)lpszEnd;
636 } while (lpszEnd > lpszStr);
637 return NULL;
640 /*************************************************************************
641 * StrRStrIW [SHLWAPI.@]
643 * See StrRStrIA.
645 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
647 INT iLen;
649 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
651 if (!lpszStr || !lpszSearch || !*lpszSearch)
652 return NULL;
654 if (!lpszEnd)
655 lpszEnd = lpszStr + strlenW(lpszStr);
657 iLen = strlenW(lpszSearch);
659 while (lpszEnd > lpszStr)
661 lpszEnd--;
662 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
663 return (LPWSTR)lpszEnd;
665 return NULL;
668 /*************************************************************************
669 * StrStrIA [SHLWAPI.@]
671 * Find a substring within a string, ignoring case.
673 * PARAMS
674 * lpszStr [I] String to search in
675 * lpszSearch [I] String to look for
677 * RETURNS
678 * The start of lpszSearch within lpszStr, or NULL if not found.
680 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
682 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
684 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
687 /*************************************************************************
688 * StrStrIW [SHLWAPI.@]
690 * See StrStrIA.
692 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
694 int iLen;
696 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
698 if (!lpszStr || !lpszSearch || !*lpszSearch)
699 return NULL;
701 iLen = strlenW(lpszSearch);
703 while (*lpszStr)
705 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
706 return (LPWSTR)lpszStr;
707 lpszStr++;
709 return NULL;
712 /*************************************************************************
713 * StrStrNW [SHLWAPI.@]
715 * Find a substring within a string up to a given number of initial characters.
717 * PARAMS
718 * lpFirst [I] String to search in
719 * lpSrch [I] String to look for
720 * cchMax [I] Maximum number of initial search characters
722 * RETURNS
723 * The start of lpFirst within lpSrch, or NULL if not found.
725 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
727 UINT i;
728 int len;
730 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
732 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
733 return NULL;
735 len = strlenW(lpSrch);
737 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
739 if (!strncmpW(lpFirst, lpSrch, len))
740 return (LPWSTR)lpFirst;
743 return NULL;
746 /*************************************************************************
747 * StrStrNIW [SHLWAPI.@]
749 * Find a substring within a string up to a given number of initial characters,
750 * ignoring case.
752 * PARAMS
753 * lpFirst [I] String to search in
754 * lpSrch [I] String to look for
755 * cchMax [I] Maximum number of initial search characters
757 * RETURNS
758 * The start of lpFirst within lpSrch, or NULL if not found.
760 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
762 UINT i;
763 int len;
765 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
767 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
768 return NULL;
770 len = strlenW(lpSrch);
772 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
774 if (!strncmpiW(lpFirst, lpSrch, len))
775 return (LPWSTR)lpFirst;
778 return NULL;
781 /*************************************************************************
782 * StrToIntA [SHLWAPI.@]
784 * Read a signed integer from a string.
786 * PARAMS
787 * lpszStr [I] String to read integer from
789 * RETURNS
790 * The signed integer value represented by the string, or 0 if no integer is
791 * present.
793 * NOTES
794 * No leading space is allowed before the number, although a leading '-' is.
796 int WINAPI StrToIntA(LPCSTR lpszStr)
798 int iRet = 0;
800 TRACE("(%s)\n", debugstr_a(lpszStr));
802 if (!lpszStr)
804 WARN("Invalid lpszStr would crash under Win32!\n");
805 return 0;
808 if (*lpszStr == '-' || isdigit(*lpszStr))
809 StrToIntExA(lpszStr, 0, &iRet);
810 return iRet;
813 /*************************************************************************
814 * StrToIntW [SHLWAPI.@]
816 * See StrToIntA.
818 int WINAPI StrToIntW(LPCWSTR lpszStr)
820 int iRet = 0;
822 TRACE("(%s)\n", debugstr_w(lpszStr));
824 if (!lpszStr)
826 WARN("Invalid lpszStr would crash under Win32!\n");
827 return 0;
830 if (*lpszStr == '-' || isdigitW(*lpszStr))
831 StrToIntExW(lpszStr, 0, &iRet);
832 return iRet;
835 /*************************************************************************
836 * StrToIntExA [SHLWAPI.@]
838 * Read an integer from a string.
840 * PARAMS
841 * lpszStr [I] String to read integer from
842 * dwFlags [I] Flags controlling the conversion
843 * lpiRet [O] Destination for read integer.
845 * RETURNS
846 * Success: TRUE. lpiRet contains the integer value represented by the string.
847 * Failure: FALSE, if the string is invalid, or no number is present.
849 * NOTES
850 * Leading whitespace, '-' and '+' are allowed before the number. If
851 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
852 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
853 * the string is treated as a decimal string. A leading '-' is ignored for
854 * hexadecimal numbers.
856 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
858 BOOL bNegative = FALSE;
859 int iRet = 0;
861 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
863 if (!lpszStr || !lpiRet)
865 WARN("Invalid parameter would crash under Win32!\n");
866 return FALSE;
868 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
870 /* Skip leading space, '+', '-' */
871 while (isspace(*lpszStr))
872 lpszStr = CharNextA(lpszStr);
874 if (*lpszStr == '-')
876 bNegative = TRUE;
877 lpszStr++;
879 else if (*lpszStr == '+')
880 lpszStr++;
882 if (dwFlags & STIF_SUPPORT_HEX &&
883 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
885 /* Read hex number */
886 lpszStr += 2;
888 if (!isxdigit(*lpszStr))
889 return FALSE;
891 while (isxdigit(*lpszStr))
893 iRet = iRet * 16;
894 if (isdigit(*lpszStr))
895 iRet += (*lpszStr - '0');
896 else
897 iRet += 10 + (tolower(*lpszStr) - 'a');
898 lpszStr++;
900 *lpiRet = iRet;
901 return TRUE;
904 /* Read decimal number */
905 if (!isdigit(*lpszStr))
906 return FALSE;
908 while (isdigit(*lpszStr))
910 iRet = iRet * 10;
911 iRet += (*lpszStr - '0');
912 lpszStr++;
914 *lpiRet = bNegative ? -iRet : iRet;
915 return TRUE;
918 /*************************************************************************
919 * StrToIntExW [SHLWAPI.@]
921 * See StrToIntExA.
923 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
925 BOOL bNegative = FALSE;
926 int iRet = 0;
928 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
930 if (!lpszStr || !lpiRet)
932 WARN("Invalid parameter would crash under Win32!\n");
933 return FALSE;
935 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
937 /* Skip leading space, '+', '-' */
938 while (isspaceW(*lpszStr)) lpszStr++;
940 if (*lpszStr == '-')
942 bNegative = TRUE;
943 lpszStr++;
945 else if (*lpszStr == '+')
946 lpszStr++;
948 if (dwFlags & STIF_SUPPORT_HEX &&
949 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
951 /* Read hex number */
952 lpszStr += 2;
954 if (!isxdigitW(*lpszStr))
955 return FALSE;
957 while (isxdigitW(*lpszStr))
959 iRet = iRet * 16;
960 if (isdigitW(*lpszStr))
961 iRet += (*lpszStr - '0');
962 else
963 iRet += 10 + (tolowerW(*lpszStr) - 'a');
964 lpszStr++;
966 *lpiRet = iRet;
967 return TRUE;
970 /* Read decimal number */
971 if (!isdigitW(*lpszStr))
972 return FALSE;
974 while (isdigitW(*lpszStr))
976 iRet = iRet * 10;
977 iRet += (*lpszStr - '0');
978 lpszStr++;
980 *lpiRet = bNegative ? -iRet : iRet;
981 return TRUE;
984 /*************************************************************************
985 * StrDupA [SHLWAPI.@]
987 * Duplicate a string.
989 * PARAMS
990 * lpszStr [I] String to duplicate.
992 * RETURNS
993 * Success: A pointer to a new string containing the contents of lpszStr
994 * Failure: NULL, if memory cannot be allocated
996 * NOTES
997 * The string memory is allocated with LocalAlloc(), and so should be released
998 * by calling LocalFree().
1000 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
1002 int iLen;
1003 LPSTR lpszRet;
1005 TRACE("(%s)\n",debugstr_a(lpszStr));
1007 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
1008 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1010 if (lpszRet)
1012 if (lpszStr)
1013 memcpy(lpszRet, lpszStr, iLen);
1014 else
1015 *lpszRet = '\0';
1017 return lpszRet;
1020 /*************************************************************************
1021 * StrDupW [SHLWAPI.@]
1023 * See StrDupA.
1025 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
1027 int iLen;
1028 LPWSTR lpszRet;
1030 TRACE("(%s)\n",debugstr_w(lpszStr));
1032 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
1033 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1035 if (lpszRet)
1037 if (lpszStr)
1038 memcpy(lpszRet, lpszStr, iLen);
1039 else
1040 *lpszRet = '\0';
1042 return lpszRet;
1045 /*************************************************************************
1046 * SHLWAPI_StrSpnHelperA
1048 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1050 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1051 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1052 BOOL bInvert)
1054 LPCSTR lpszRead = lpszStr;
1055 if (lpszStr && *lpszStr && lpszMatch)
1057 while (*lpszRead)
1059 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1061 if (!bInvert && !lpszTest)
1062 break;
1063 if (bInvert && lpszTest)
1064 break;
1065 lpszRead = CharNextA(lpszRead);
1068 return lpszRead - lpszStr;
1071 /*************************************************************************
1072 * StrSpnA [SHLWAPI.@]
1074 * Find the length of the start of a string that contains only certain
1075 * characters.
1077 * PARAMS
1078 * lpszStr [I] String to search
1079 * lpszMatch [I] Characters that can be in the substring
1081 * RETURNS
1082 * The length of the part of lpszStr containing only chars from lpszMatch,
1083 * or 0 if any parameter is invalid.
1085 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1087 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1089 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1092 /*************************************************************************
1093 * StrSpnW [SHLWAPI.@]
1095 * See StrSpnA.
1097 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1099 if (!lpszStr || !lpszMatch) return 0;
1100 return strspnW( lpszStr, lpszMatch );
1103 /*************************************************************************
1104 * StrCSpnA [SHLWAPI.@]
1106 * Find the length of the start of a string that does not contain certain
1107 * characters.
1109 * PARAMS
1110 * lpszStr [I] String to search
1111 * lpszMatch [I] Characters that cannot be in the substring
1113 * RETURNS
1114 * The length of the part of lpszStr containing only chars not in lpszMatch,
1115 * or 0 if any parameter is invalid.
1117 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1119 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1121 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1124 /*************************************************************************
1125 * StrCSpnW [SHLWAPI.@]
1127 * See StrCSpnA.
1129 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1131 if (!lpszStr || !lpszMatch) return 0;
1132 return strcspnW( lpszStr, lpszMatch );
1135 /*************************************************************************
1136 * StrCSpnIA [SHLWAPI.@]
1138 * Find the length of the start of a string that does not contain certain
1139 * characters, ignoring case.
1141 * PARAMS
1142 * lpszStr [I] String to search
1143 * lpszMatch [I] Characters that cannot be in the substring
1145 * RETURNS
1146 * The length of the part of lpszStr containing only chars not in lpszMatch,
1147 * or 0 if any parameter is invalid.
1149 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1151 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1153 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1156 /*************************************************************************
1157 * StrCSpnIW [SHLWAPI.@]
1159 * See StrCSpnIA.
1161 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1163 LPCWSTR lpszRead = lpszStr;
1165 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1167 if (lpszStr && *lpszStr && lpszMatch)
1169 while (*lpszRead)
1171 if (StrChrIW(lpszMatch, *lpszRead)) break;
1172 lpszRead++;
1175 return lpszRead - lpszStr;
1178 /*************************************************************************
1179 * StrPBrkA [SHLWAPI.@]
1181 * Search a string for any of a group of characters.
1183 * PARAMS
1184 * lpszStr [I] String to search
1185 * lpszMatch [I] Characters to match
1187 * RETURNS
1188 * A pointer to the first matching character in lpszStr, or NULL if no
1189 * match was found.
1191 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1193 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1195 if (lpszStr && lpszMatch && *lpszMatch)
1197 while (*lpszStr)
1199 if (StrChrA(lpszMatch, *lpszStr))
1200 return (LPSTR)lpszStr;
1201 lpszStr = CharNextA(lpszStr);
1204 return NULL;
1207 /*************************************************************************
1208 * StrPBrkW [SHLWAPI.@]
1210 * See StrPBrkA.
1212 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1214 if (!lpszStr || !lpszMatch) return NULL;
1215 return strpbrkW( lpszStr, lpszMatch );
1218 /*************************************************************************
1219 * SHLWAPI_StrRChrHelperA
1221 * Internal implementation of StrRChrA/StrRChrIA.
1223 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1224 LPCSTR lpszEnd, WORD ch,
1225 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1227 LPCSTR lpszRet = NULL;
1229 if (lpszStr)
1231 WORD ch2;
1233 if (!lpszEnd)
1234 lpszEnd = lpszStr + lstrlenA(lpszStr);
1236 while (*lpszStr && lpszStr <= lpszEnd)
1238 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1240 if (!pChrCmpFn(ch, ch2))
1241 lpszRet = lpszStr;
1242 lpszStr = CharNextA(lpszStr);
1245 return (LPSTR)lpszRet;
1248 /**************************************************************************
1249 * StrRChrA [SHLWAPI.@]
1251 * Find the last occurrence of a character in string.
1253 * PARAMS
1254 * lpszStr [I] String to search in
1255 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1256 * ch [I] Character to search for.
1258 * RETURNS
1259 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1260 * or NULL if not found.
1261 * Failure: NULL, if any arguments are invalid.
1263 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1265 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1267 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1270 /**************************************************************************
1271 * StrRChrW [SHLWAPI.@]
1273 * See StrRChrA.
1275 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1277 WCHAR *ret = NULL;
1279 if (!str) return NULL;
1280 if (!end) end = str + strlenW(str);
1281 while (str < end)
1283 if (*str == ch) ret = (WCHAR *)str;
1284 str++;
1286 return ret;
1289 /**************************************************************************
1290 * StrRChrIA [SHLWAPI.@]
1292 * Find the last occurrence of a character in string, ignoring case.
1294 * PARAMS
1295 * lpszStr [I] String to search in
1296 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1297 * ch [I] Character to search for.
1299 * RETURNS
1300 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1301 * or NULL if not found.
1302 * Failure: NULL, if any arguments are invalid.
1304 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1306 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1308 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1311 /**************************************************************************
1312 * StrRChrIW [SHLWAPI.@]
1314 * See StrRChrIA.
1316 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1318 WCHAR *ret = NULL;
1320 if (!str) return NULL;
1321 if (!end) end = str + strlenW(str);
1322 while (str < end)
1324 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1325 str++;
1327 return ret;
1330 /*************************************************************************
1331 * StrCatBuffA [SHLWAPI.@]
1333 * Concatenate two strings together.
1335 * PARAMS
1336 * lpszStr [O] String to concatenate to
1337 * lpszCat [I] String to add to lpszCat
1338 * cchMax [I] Maximum number of characters for the whole string
1340 * RETURNS
1341 * lpszStr.
1343 * NOTES
1344 * cchMax determines the number of characters in the final length of the
1345 * string, not the number appended to lpszStr from lpszCat.
1347 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1349 INT iLen;
1351 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1353 if (!lpszStr)
1355 WARN("Invalid lpszStr would crash under Win32!\n");
1356 return NULL;
1359 iLen = strlen(lpszStr);
1360 cchMax -= iLen;
1362 if (cchMax > 0)
1363 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1364 return lpszStr;
1367 /*************************************************************************
1368 * StrCatBuffW [SHLWAPI.@]
1370 * See StrCatBuffA.
1372 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1374 INT iLen;
1376 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1378 if (!lpszStr)
1380 WARN("Invalid lpszStr would crash under Win32!\n");
1381 return NULL;
1384 iLen = strlenW(lpszStr);
1385 cchMax -= iLen;
1387 if (cchMax > 0)
1388 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1389 return lpszStr;
1392 /*************************************************************************
1393 * StrRetToBufA [SHLWAPI.@]
1395 * Convert a STRRET to a normal string.
1397 * PARAMS
1398 * lpStrRet [O] STRRET to convert
1399 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1400 * lpszDest [O] Destination for normal string
1401 * dwLen [I] Length of lpszDest
1403 * RETURNS
1404 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1405 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1406 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1407 * Failure: E_FAIL, if any parameters are invalid.
1409 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1411 /* NOTE:
1412 * This routine is identical to that in dlls/shell32/shellstring.c.
1413 * It was duplicated because not every version of Shlwapi.dll exports
1414 * StrRetToBufA. If you change one routine, change them both.
1416 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1418 if (!src)
1420 WARN("Invalid lpStrRet would crash under Win32!\n");
1421 if (dest)
1422 *dest = '\0';
1423 return E_FAIL;
1426 if (!dest || !len)
1427 return E_FAIL;
1429 *dest = '\0';
1431 switch (src->uType)
1433 case STRRET_WSTR:
1434 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1435 CoTaskMemFree(src->u.pOleStr);
1436 break;
1438 case STRRET_CSTR:
1439 lstrcpynA(dest, src->u.cStr, len);
1440 break;
1442 case STRRET_OFFSET:
1443 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1444 break;
1446 default:
1447 FIXME("unknown type!\n");
1448 return FALSE;
1450 return S_OK;
1453 /*************************************************************************
1454 * StrRetToBufW [SHLWAPI.@]
1456 * See StrRetToBufA.
1458 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1460 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1462 if (!src)
1464 WARN("Invalid lpStrRet would crash under Win32!\n");
1465 if (dest)
1466 *dest = '\0';
1467 return E_FAIL;
1470 if (!dest || !len)
1471 return E_FAIL;
1473 *dest = '\0';
1475 switch (src->uType)
1477 case STRRET_WSTR:
1478 lstrcpynW(dest, src->u.pOleStr, len);
1479 CoTaskMemFree(src->u.pOleStr);
1480 break;
1482 case STRRET_CSTR:
1483 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1484 dest[len-1] = 0;
1485 break;
1487 case STRRET_OFFSET:
1488 if (pidl)
1490 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1491 dest, len ))
1492 dest[len-1] = 0;
1494 break;
1496 default:
1497 FIXME("unknown type!\n");
1498 return FALSE;
1500 return S_OK;
1503 /*************************************************************************
1504 * StrRetToStrA [SHLWAPI.@]
1506 * Converts a STRRET to a normal string.
1508 * PARAMS
1509 * lpStrRet [O] STRRET to convert
1510 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1511 * ppszName [O] Destination for converted string
1513 * RETURNS
1514 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1515 * Failure: E_FAIL, if any parameters are invalid.
1517 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1519 HRESULT hRet = E_FAIL;
1521 switch (lpStrRet->uType)
1523 case STRRET_WSTR:
1524 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1525 CoTaskMemFree(lpStrRet->u.pOleStr);
1526 break;
1528 case STRRET_CSTR:
1529 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1530 break;
1532 case STRRET_OFFSET:
1533 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1534 break;
1536 default:
1537 *ppszName = NULL;
1540 return hRet;
1543 /*************************************************************************
1544 * StrRetToStrW [SHLWAPI.@]
1546 * See StrRetToStrA.
1548 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1550 HRESULT hRet = E_FAIL;
1552 switch (lpStrRet->uType)
1554 case STRRET_WSTR:
1555 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1556 CoTaskMemFree(lpStrRet->u.pOleStr);
1557 break;
1559 case STRRET_CSTR:
1560 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1561 break;
1563 case STRRET_OFFSET:
1564 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1565 break;
1567 default:
1568 *ppszName = NULL;
1571 return hRet;
1574 /* Create an ASCII string copy using SysAllocString() */
1575 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1577 *pBstrOut = NULL;
1579 if (src)
1581 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1582 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1584 if (szTemp)
1586 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1587 *pBstrOut = SysAllocString(szTemp);
1588 HeapFree(GetProcessHeap(), 0, szTemp);
1590 if (*pBstrOut)
1591 return S_OK;
1594 return E_OUTOFMEMORY;
1597 /*************************************************************************
1598 * StrRetToBSTR [SHLWAPI.@]
1600 * Converts a STRRET to a BSTR.
1602 * PARAMS
1603 * lpStrRet [O] STRRET to convert
1604 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1605 * pBstrOut [O] Destination for converted BSTR
1607 * RETURNS
1608 * Success: S_OK. pBstrOut contains the new string.
1609 * Failure: E_FAIL, if any parameters are invalid.
1611 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1613 HRESULT hRet = E_FAIL;
1615 switch (lpStrRet->uType)
1617 case STRRET_WSTR:
1618 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1619 if (*pBstrOut)
1620 hRet = S_OK;
1621 CoTaskMemFree(lpStrRet->u.pOleStr);
1622 break;
1624 case STRRET_CSTR:
1625 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1626 break;
1628 case STRRET_OFFSET:
1629 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1630 break;
1632 default:
1633 *pBstrOut = NULL;
1636 return hRet;
1639 /*************************************************************************
1640 * StrFormatKBSizeA [SHLWAPI.@]
1642 * Create a formatted string containing a byte count in Kilobytes.
1644 * PARAMS
1645 * llBytes [I] Byte size to format
1646 * lpszDest [I] Destination for formatted string
1647 * cchMax [I] Size of lpszDest
1649 * RETURNS
1650 * lpszDest.
1652 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1654 WCHAR wszBuf[256];
1656 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1657 return NULL;
1658 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1659 return NULL;
1660 return lpszDest;
1663 /*************************************************************************
1664 * StrFormatKBSizeW [SHLWAPI.@]
1666 * See StrFormatKBSizeA.
1668 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1670 static const WCHAR kb[] = {' ','K','B',0};
1671 LONGLONG llKB = (llBytes + 1023) >> 10;
1672 int len;
1674 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1676 if (!FormatInt(llKB, lpszDest, cchMax))
1677 return NULL;
1679 len = lstrlenW(lpszDest);
1680 if (cchMax - len < 4)
1681 return NULL;
1682 lstrcatW(lpszDest, kb);
1683 return lpszDest;
1686 /*************************************************************************
1687 * StrNCatA [SHLWAPI.@]
1689 * Concatenate two strings together.
1691 * PARAMS
1692 * lpszStr [O] String to concatenate to
1693 * lpszCat [I] String to add to lpszCat
1694 * cchMax [I] Maximum number of characters to concatenate
1696 * RETURNS
1697 * lpszStr.
1699 * NOTES
1700 * cchMax determines the number of characters that are appended to lpszStr,
1701 * not the total length of the string.
1703 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1705 LPSTR lpszRet = lpszStr;
1707 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1709 if (!lpszStr)
1711 WARN("Invalid lpszStr would crash under Win32!\n");
1712 return NULL;
1715 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1716 return lpszRet;
1719 /*************************************************************************
1720 * StrNCatW [SHLWAPI.@]
1722 * See StrNCatA.
1724 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1726 LPWSTR lpszRet = lpszStr;
1728 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1730 if (!lpszStr)
1732 WARN("Invalid lpszStr would crash under Win32\n");
1733 return NULL;
1736 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1737 return lpszRet;
1740 /*************************************************************************
1741 * StrTrimA [SHLWAPI.@]
1743 * Remove characters from the start and end of a string.
1745 * PARAMS
1746 * lpszStr [O] String to remove characters from
1747 * lpszTrim [I] Characters to remove from lpszStr
1749 * RETURNS
1750 * TRUE If lpszStr was valid and modified
1751 * FALSE Otherwise
1753 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1755 DWORD dwLen;
1756 LPSTR lpszRead = lpszStr;
1757 BOOL bRet = FALSE;
1759 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1761 if (lpszRead && *lpszRead)
1763 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1764 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1766 dwLen = strlen(lpszRead);
1768 if (lpszRead != lpszStr)
1770 memmove(lpszStr, lpszRead, dwLen + 1);
1771 bRet = TRUE;
1773 if (dwLen > 0)
1775 lpszRead = lpszStr + dwLen;
1776 while (StrChrA(lpszTrim, lpszRead[-1]))
1777 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1779 if (lpszRead != lpszStr + dwLen)
1781 *lpszRead = '\0';
1782 bRet = TRUE;
1786 return bRet;
1789 /*************************************************************************
1790 * StrTrimW [SHLWAPI.@]
1792 * See StrTrimA.
1794 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1796 DWORD dwLen;
1797 LPWSTR lpszRead = lpszStr;
1798 BOOL bRet = FALSE;
1800 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1802 if (lpszRead && *lpszRead)
1804 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1806 dwLen = strlenW(lpszRead);
1808 if (lpszRead != lpszStr)
1810 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1811 bRet = TRUE;
1813 if (dwLen > 0)
1815 lpszRead = lpszStr + dwLen;
1816 while (StrChrW(lpszTrim, lpszRead[-1]))
1817 lpszRead--; /* Skip trailing matches */
1819 if (lpszRead != lpszStr + dwLen)
1821 *lpszRead = '\0';
1822 bRet = TRUE;
1826 return bRet;
1829 /*************************************************************************
1830 * _SHStrDupAA [INTERNAL]
1832 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1834 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1836 HRESULT hr;
1837 int len = 0;
1839 if (src) {
1840 len = lstrlenA(src) + 1;
1841 *dest = CoTaskMemAlloc(len);
1842 } else {
1843 *dest = NULL;
1846 if (*dest) {
1847 lstrcpynA(*dest,src, len);
1848 hr = S_OK;
1849 } else {
1850 hr = E_OUTOFMEMORY;
1853 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1854 return hr;
1857 /*************************************************************************
1858 * SHStrDupA [SHLWAPI.@]
1860 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1862 * PARAMS
1863 * lpszStr [I] String to copy
1864 * lppszDest [O] Destination for the new string copy
1866 * RETURNS
1867 * Success: S_OK. lppszDest contains the new string in Unicode format.
1868 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1869 * fails.
1871 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1873 HRESULT hRet;
1874 int len = 0;
1876 if (lpszStr)
1878 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1879 *lppszDest = CoTaskMemAlloc(len);
1881 else
1882 *lppszDest = NULL;
1884 if (*lppszDest)
1886 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1887 hRet = S_OK;
1889 else
1890 hRet = E_OUTOFMEMORY;
1892 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1893 return hRet;
1896 /*************************************************************************
1897 * _SHStrDupAW [INTERNAL]
1899 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1901 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1903 HRESULT hr;
1904 int len = 0;
1906 if (src) {
1907 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1908 *dest = CoTaskMemAlloc(len);
1909 } else {
1910 *dest = NULL;
1913 if (*dest) {
1914 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1915 hr = S_OK;
1916 } else {
1917 hr = E_OUTOFMEMORY;
1920 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1921 return hr;
1924 /*************************************************************************
1925 * SHStrDupW [SHLWAPI.@]
1927 * See SHStrDupA.
1929 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1931 HRESULT hr;
1932 int len = 0;
1934 if (src) {
1935 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1936 *dest = CoTaskMemAlloc(len);
1937 } else {
1938 *dest = NULL;
1941 if (*dest) {
1942 memcpy(*dest, src, len);
1943 hr = S_OK;
1944 } else {
1945 hr = E_OUTOFMEMORY;
1948 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1949 return hr;
1952 /*************************************************************************
1953 * SHLWAPI_WriteReverseNum
1955 * Internal helper for SHLWAPI_WriteTimeClass.
1957 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1959 *lpszOut-- = '\0';
1961 /* Write a decimal number to a string, backwards */
1964 DWORD dwNextDigit = dwNum % 10;
1965 *lpszOut-- = '0' + dwNextDigit;
1966 dwNum = (dwNum - dwNextDigit) / 10;
1967 } while (dwNum > 0);
1969 return lpszOut;
1972 /*************************************************************************
1973 * SHLWAPI_FormatSignificant
1975 * Internal helper for SHLWAPI_WriteTimeClass.
1977 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1979 /* Zero non significant digits, return remaining significant digits */
1980 while (*lpszNum)
1982 lpszNum++;
1983 if (--dwDigits == 0)
1985 while (*lpszNum)
1986 *lpszNum++ = '0';
1987 return 0;
1990 return dwDigits;
1993 /*************************************************************************
1994 * SHLWAPI_WriteTimeClass
1996 * Internal helper for StrFromTimeIntervalW.
1998 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1999 UINT uClassStringId, int iDigits)
2001 WCHAR szBuff[64], *szOut = szBuff + 32;
2003 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2004 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2005 *szOut = ' ';
2006 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2007 strcatW(lpszOut, szOut);
2008 return iDigits;
2011 /*************************************************************************
2012 * StrFromTimeIntervalA [SHLWAPI.@]
2014 * Format a millisecond time interval into a string
2016 * PARAMS
2017 * lpszStr [O] Output buffer for formatted time interval
2018 * cchMax [I] Size of lpszStr
2019 * dwMS [I] Number of milliseconds
2020 * iDigits [I] Number of digits to print
2022 * RETURNS
2023 * The length of the formatted string, or 0 if any parameter is invalid.
2025 * NOTES
2026 * This implementation mimics the Win32 behaviour of always writing a leading
2027 * space before the time interval begins.
2029 * iDigits is used to provide approximate times if accuracy is not important.
2030 * This number of digits will be written of the first non-zero time class
2031 * (hours/minutes/seconds). If this does not complete the time classification,
2032 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2033 * If there are digits remaining following the writing of a time class, the
2034 * next time class will be written.
2036 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2037 * following will result from the given values of iDigits:
2039 *| iDigits 1 2 3 4 5 ...
2040 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2042 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2043 int iDigits)
2045 INT iRet = 0;
2047 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2049 if (lpszStr && cchMax)
2051 WCHAR szBuff[128];
2052 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2053 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2055 return iRet;
2059 /*************************************************************************
2060 * StrFromTimeIntervalW [SHLWAPI.@]
2062 * See StrFromTimeIntervalA.
2064 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2065 int iDigits)
2067 INT iRet = 0;
2069 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2071 if (lpszStr && cchMax)
2073 WCHAR szCopy[128];
2074 DWORD dwHours, dwMinutes;
2076 if (!iDigits || cchMax == 1)
2078 *lpszStr = '\0';
2079 return 0;
2082 /* Calculate the time classes */
2083 dwMS = (dwMS + 500) / 1000;
2084 dwHours = dwMS / 3600;
2085 dwMS -= dwHours * 3600;
2086 dwMinutes = dwMS / 60;
2087 dwMS -= dwMinutes * 60;
2089 szCopy[0] = '\0';
2091 if (dwHours)
2092 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2094 if (dwMinutes && iDigits)
2095 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2097 if (iDigits) /* Always write seconds if we have significant digits */
2098 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2100 lstrcpynW(lpszStr, szCopy, cchMax);
2101 iRet = strlenW(lpszStr);
2103 return iRet;
2106 /*************************************************************************
2107 * StrIsIntlEqualA [SHLWAPI.@]
2109 * Compare two strings.
2111 * PARAMS
2112 * bCase [I] Whether to compare case sensitively
2113 * lpszStr [I] First string to compare
2114 * lpszComp [I] Second string to compare
2115 * iLen [I] Length to compare
2117 * RETURNS
2118 * TRUE If the strings are equal.
2119 * FALSE Otherwise.
2121 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2122 int iLen)
2124 DWORD dwFlags;
2126 TRACE("(%d,%s,%s,%d)\n", bCase,
2127 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2129 /* FIXME: This flag is undocumented and unknown by our CompareString.
2130 * We need a define for it.
2132 dwFlags = 0x10000000;
2133 if (!bCase) dwFlags |= NORM_IGNORECASE;
2135 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2138 /*************************************************************************
2139 * StrIsIntlEqualW [SHLWAPI.@]
2141 * See StrIsIntlEqualA.
2143 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2144 int iLen)
2146 DWORD dwFlags;
2148 TRACE("(%d,%s,%s,%d)\n", bCase,
2149 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2151 /* FIXME: This flag is undocumented and unknown by our CompareString.
2152 * We need a define for it.
2154 dwFlags = 0x10000000;
2155 if (!bCase) dwFlags |= NORM_IGNORECASE;
2157 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2160 /*************************************************************************
2161 * @ [SHLWAPI.399]
2163 * Copy a string to another string, up to a maximum number of characters.
2165 * PARAMS
2166 * lpszDest [O] Destination string
2167 * lpszSrc [I] Source string
2168 * iLen [I] Maximum number of chars to copy
2170 * RETURNS
2171 * Success: A pointer to the last character written to lpszDest.
2172 * Failure: lpszDest, if any arguments are invalid.
2174 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2176 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2178 if (lpszDest && lpszSrc && iLen > 0)
2180 while ((iLen-- > 1) && *lpszSrc)
2181 *lpszDest++ = *lpszSrc++;
2182 if (iLen >= 0)
2183 *lpszDest = '\0';
2185 return lpszDest;
2188 /*************************************************************************
2189 * @ [SHLWAPI.400]
2191 * Unicode version of StrCpyNXA.
2193 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2195 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2197 if (lpszDest && lpszSrc && iLen > 0)
2199 while ((iLen-- > 1) && *lpszSrc)
2200 *lpszDest++ = *lpszSrc++;
2201 if (iLen >= 0)
2202 *lpszDest = '\0';
2204 return lpszDest;
2207 /*************************************************************************
2208 * StrCmpLogicalW [SHLWAPI.@]
2210 * Compare two strings, ignoring case and comparing digits as numbers.
2212 * PARAMS
2213 * lpszStr [I] First string to compare
2214 * lpszComp [I] Second string to compare
2215 * iLen [I] Length to compare
2217 * RETURNS
2218 * TRUE If the strings are equal.
2219 * FALSE Otherwise.
2221 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2223 INT iDiff;
2225 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2227 if (lpszStr && lpszComp)
2229 while (*lpszStr)
2231 if (!*lpszComp)
2232 return 1;
2233 else if (isdigitW(*lpszStr))
2235 int iStr, iComp;
2237 if (!isdigitW(*lpszComp))
2238 return -1;
2240 /* Compare the numbers */
2241 StrToIntExW(lpszStr, 0, &iStr);
2242 StrToIntExW(lpszComp, 0, &iComp);
2244 if (iStr < iComp)
2245 return -1;
2246 else if (iStr > iComp)
2247 return 1;
2249 /* Skip */
2250 while (isdigitW(*lpszStr))
2251 lpszStr++;
2252 while (isdigitW(*lpszComp))
2253 lpszComp++;
2255 else if (isdigitW(*lpszComp))
2256 return 1;
2257 else
2259 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2260 if (iDiff > 0)
2261 return 1;
2262 else if (iDiff < 0)
2263 return -1;
2265 lpszStr++;
2266 lpszComp++;
2269 if (*lpszComp)
2270 return -1;
2272 return 0;
2275 /* Structure for formatting byte strings */
2276 typedef struct tagSHLWAPI_BYTEFORMATS
2278 LONGLONG dLimit;
2279 double dDivisor;
2280 double dNormaliser;
2281 int nDecimals;
2282 WCHAR wPrefix;
2283 } SHLWAPI_BYTEFORMATS;
2285 /*************************************************************************
2286 * StrFormatByteSizeW [SHLWAPI.@]
2288 * Create a string containing an abbreviated byte count of up to 2^63-1.
2290 * PARAMS
2291 * llBytes [I] Byte size to format
2292 * lpszDest [I] Destination for formatted string
2293 * cchMax [I] Size of lpszDest
2295 * RETURNS
2296 * lpszDest.
2298 * NOTES
2299 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2301 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2303 #define KB ((ULONGLONG)1024)
2304 #define MB (KB*KB)
2305 #define GB (KB*KB*KB)
2306 #define TB (KB*KB*KB*KB)
2307 #define PB (KB*KB*KB*KB*KB)
2309 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2311 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2312 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2313 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2314 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2315 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2316 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2317 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2318 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2319 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2320 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2321 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2322 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2323 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2324 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2325 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2326 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2328 WCHAR wszAdd[] = {' ','?','B',0};
2329 double dBytes;
2330 UINT i = 0;
2332 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2334 if (!lpszDest || !cchMax)
2335 return lpszDest;
2337 if (llBytes < 1024) /* 1K */
2339 WCHAR wszBytesFormat[64];
2340 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2341 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
2342 return lpszDest;
2345 /* Note that if this loop completes without finding a match, i will be
2346 * pointing at the last entry, which is a catch all for > 1000 PB
2348 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2350 if (llBytes < bfFormats[i].dLimit)
2351 break;
2352 i++;
2354 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2355 * this number we integer shift down by 1 MB first. The table above has
2356 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2357 * for this. We also add a small fudge factor to get the correct result for
2358 * counts that lie exactly on a 1024 byte boundary.
2360 if (i > 8)
2361 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
2362 else
2363 dBytes = (double)llBytes + 0.00001;
2365 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2367 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2368 return NULL;
2369 wszAdd[1] = bfFormats[i].wPrefix;
2370 StrCatBuffW(lpszDest, wszAdd, cchMax);
2371 return lpszDest;
2374 /*************************************************************************
2375 * StrFormatByteSize64A [SHLWAPI.@]
2377 * See StrFormatByteSizeW.
2379 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2381 WCHAR wszBuff[32];
2383 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2385 if (lpszDest)
2386 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2387 return lpszDest;
2390 /*************************************************************************
2391 * StrFormatByteSizeA [SHLWAPI.@]
2393 * Create a string containing an abbreviated byte count of up to 2^31-1.
2395 * PARAMS
2396 * dwBytes [I] Byte size to format
2397 * lpszDest [I] Destination for formatted string
2398 * cchMax [I] Size of lpszDest
2400 * RETURNS
2401 * lpszDest.
2403 * NOTES
2404 * The Ascii and Unicode versions of this function accept a different
2405 * integer type for dwBytes. See StrFormatByteSize64A().
2407 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2409 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2411 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2414 /*************************************************************************
2415 * @ [SHLWAPI.162]
2417 * Remove a hanging lead byte from the end of a string, if present.
2419 * PARAMS
2420 * lpStr [I] String to check for a hanging lead byte
2421 * size [I] Length of lpStr
2423 * RETURNS
2424 * Success: The new length of the string. Any hanging lead bytes are removed.
2425 * Failure: 0, if any parameters are invalid.
2427 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2429 if (lpStr && size)
2431 LPSTR lastByte = lpStr + size - 1;
2433 while(lpStr < lastByte)
2434 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2436 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2438 *lpStr = '\0';
2439 size--;
2441 return size;
2443 return 0;
2446 /*************************************************************************
2447 * @ [SHLWAPI.203]
2449 * Remove a single non-trailing ampersand ('&') from a string.
2451 * PARAMS
2452 * lpszStr [I/O] String to remove ampersand from.
2454 * RETURNS
2455 * The character after the first ampersand in lpszStr, or the first character
2456 * in lpszStr if there is no ampersand in the string.
2458 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2460 LPSTR lpszIter, lpszTmp;
2461 char ch;
2463 TRACE("(%s)\n", debugstr_a(lpszStr));
2465 ch = *lpszStr;
2467 if ((lpszIter = StrChrA(lpszStr, '&')))
2469 lpszTmp = CharNextA(lpszIter);
2470 if (*lpszTmp)
2472 if (*lpszTmp != '&')
2473 ch = *lpszTmp;
2475 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
2479 return ch;
2482 /*************************************************************************
2483 * @ [SHLWAPI.225]
2485 * Unicode version of SHStripMneumonicA.
2487 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2489 LPWSTR lpszIter, lpszTmp;
2490 WCHAR ch;
2492 TRACE("(%s)\n", debugstr_w(lpszStr));
2494 ch = *lpszStr;
2496 if ((lpszIter = StrChrW(lpszStr, '&')))
2498 lpszTmp = lpszIter + 1;
2499 if (*lpszTmp)
2501 if (*lpszTmp != '&')
2502 ch = *lpszTmp;
2504 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
2508 return ch;
2511 /*************************************************************************
2512 * @ [SHLWAPI.216]
2514 * Convert an Ascii string to Unicode.
2516 * PARAMS
2517 * dwCp [I] Code page for the conversion
2518 * lpSrcStr [I] Source Ascii string to convert
2519 * lpDstStr [O] Destination for converted Unicode string
2520 * iLen [I] Length of lpDstStr
2522 * RETURNS
2523 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2525 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2527 DWORD dwRet;
2529 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2530 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2531 return dwRet;
2534 /*************************************************************************
2535 * @ [SHLWAPI.215]
2537 * Convert an Ascii string to Unicode.
2539 * PARAMS
2540 * lpSrcStr [I] Source Ascii string to convert
2541 * lpDstStr [O] Destination for converted Unicode string
2542 * iLen [I] Length of lpDstStr
2544 * RETURNS
2545 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2547 * NOTES
2548 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2550 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2552 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2555 /*************************************************************************
2556 * @ [SHLWAPI.218]
2558 * Convert a Unicode string to Ascii.
2560 * PARAMS
2561 * CodePage [I] Code page to use for the conversion
2562 * lpSrcStr [I] Source Unicode string to convert
2563 * lpDstStr [O] Destination for converted Ascii string
2564 * dstlen [I] Length of buffer at lpDstStr
2566 * RETURNS
2567 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2568 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2569 * the result is not nul-terminated.
2570 * When using a different codepage, the length in bytes of the truncated
2571 * result at lpDstStr (including the terminator) is returned and
2572 * lpDstStr is always nul-terminated.
2575 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2577 static const WCHAR emptyW[] = { '\0' };
2578 int len , reqLen;
2579 LPSTR mem;
2581 if (!lpDstStr || !dstlen)
2582 return 0;
2584 if (!lpSrcStr)
2585 lpSrcStr = emptyW;
2587 *lpDstStr = '\0';
2589 len = strlenW(lpSrcStr) + 1;
2591 switch (CodePage)
2593 case CP_WINUNICODE:
2594 CodePage = CP_UTF8; /* Fall through... */
2595 case 0x0000C350: /* FIXME: CP_ #define */
2596 case CP_UTF7:
2597 case CP_UTF8:
2599 DWORD dwMode = 0;
2600 INT lenW = len - 1;
2601 INT needed = dstlen - 1;
2602 HRESULT hr;
2604 /* try the user supplied buffer first */
2605 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2606 if (hr == S_OK)
2608 lpDstStr[needed] = '\0';
2609 return needed + 1;
2612 /* user buffer too small. exclude termination and copy as much as possible */
2613 lenW = len;
2614 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2615 needed++;
2616 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2617 if (!mem)
2618 return 0;
2620 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2621 if (hr == S_OK)
2623 reqLen = SHTruncateString(mem, dstlen);
2624 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2626 HeapFree(GetProcessHeap(), 0, mem);
2627 return 0;
2629 default:
2630 break;
2633 /* try the user supplied buffer first */
2634 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2636 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2638 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2639 if (reqLen)
2641 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2642 if (mem)
2644 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2645 reqLen, NULL, NULL);
2647 reqLen = SHTruncateString(mem, dstlen -1);
2648 reqLen++;
2650 lstrcpynA(lpDstStr, mem, reqLen);
2651 HeapFree(GetProcessHeap(), 0, mem);
2652 lpDstStr[reqLen-1] = '\0';
2656 return reqLen;
2659 /*************************************************************************
2660 * @ [SHLWAPI.217]
2662 * Convert a Unicode string to Ascii.
2664 * PARAMS
2665 * lpSrcStr [I] Source Unicode string to convert
2666 * lpDstStr [O] Destination for converted Ascii string
2667 * iLen [O] Length of lpDstStr in characters
2669 * RETURNS
2670 * See SHUnicodeToAnsiCP
2672 * NOTES
2673 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2675 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2677 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2680 /*************************************************************************
2681 * @ [SHLWAPI.345]
2683 * Copy one string to another.
2685 * PARAMS
2686 * lpszSrc [I] Source string to copy
2687 * lpszDst [O] Destination for copy
2688 * iLen [I] Length of lpszDst in characters
2690 * RETURNS
2691 * The length of the copied string, including the terminating NUL. lpszDst
2692 * contains iLen characters of lpszSrc.
2694 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2696 LPSTR lpszRet;
2698 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2700 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2701 return lpszRet - lpszDst + 1;
2704 /*************************************************************************
2705 * @ [SHLWAPI.346]
2707 * Unicode version of SSHAnsiToAnsi.
2709 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2711 LPWSTR lpszRet;
2713 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2715 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2716 return lpszRet - lpszDst + 1;
2719 /*************************************************************************
2720 * @ [SHLWAPI.364]
2722 * Determine if an Ascii string converts to Unicode and back identically.
2724 * PARAMS
2725 * lpSrcStr [I] Source Unicode string to convert
2726 * lpDst [O] Destination for resulting Ascii string
2727 * iLen [I] Length of lpDst in characters
2729 * RETURNS
2730 * TRUE, since Ascii strings always convert identically.
2732 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2734 lstrcpynA(lpDst, lpSrcStr, iLen);
2735 return TRUE;
2738 /*************************************************************************
2739 * @ [SHLWAPI.365]
2741 * Determine if a Unicode string converts to Ascii and back identically.
2743 * PARAMS
2744 * lpSrcStr [I] Source Unicode string to convert
2745 * lpDst [O] Destination for resulting Ascii string
2746 * iLen [I] Length of lpDst in characters
2748 * RETURNS
2749 * TRUE, if lpSrcStr converts to Ascii and back identically,
2750 * FALSE otherwise.
2752 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2754 WCHAR szBuff[MAX_PATH];
2756 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2757 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2758 return !strcmpW(lpSrcStr, szBuff);
2761 /*************************************************************************
2762 * SHLoadIndirectString [SHLWAPI.@]
2764 * If passed a string that begins with '@', extract the string from the
2765 * appropriate resource, otherwise do a straight copy.
2768 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2770 WCHAR *dllname = NULL;
2771 HMODULE hmod = NULL;
2772 HRESULT hr = E_FAIL;
2774 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2776 if(src[0] == '@')
2778 WCHAR *index_str;
2779 int index;
2781 dst[0] = 0;
2782 dllname = StrDupW(src + 1);
2783 index_str = strchrW(dllname, ',');
2785 if(!index_str) goto end;
2787 *index_str = 0;
2788 index_str++;
2789 index = atoiW(index_str);
2791 hmod = LoadLibraryW(dllname);
2792 if(!hmod) goto end;
2794 if(index < 0)
2796 if(LoadStringW(hmod, -index, dst, dst_len))
2797 hr = S_OK;
2799 else
2800 FIXME("can't handle non-negative indices (%d)\n", index);
2802 else
2804 if(dst != src)
2805 lstrcpynW(dst, src, dst_len);
2806 hr = S_OK;
2809 TRACE("returning %s\n", debugstr_w(dst));
2810 end:
2811 if(hmod) FreeLibrary(hmod);
2812 HeapFree(GetProcessHeap(), 0, dllname);
2813 return hr;