winemenubuilder: silence an err
[wine/multimedia.git] / dlls / shlwapi / string.c
blobe2f1cba9b944835508e4ce36c725c20147ef061f
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 characters 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 characters 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 if (lpszStr && lpszSrc)
481 strcatW(lpszStr, lpszSrc);
482 return lpszStr;
485 /*************************************************************************
486 * StrCpyW [SHLWAPI.@]
488 * Copy a string to another string.
490 * PARAMS
491 * lpszStr [O] Destination string
492 * lpszSrc [I] Source string
494 * RETURNS
495 * lpszStr.
497 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
499 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
501 if (lpszStr && lpszSrc)
502 strcpyW(lpszStr, lpszSrc);
503 return lpszStr;
506 /*************************************************************************
507 * StrCpyNW [SHLWAPI.@]
509 * Copy a string to another string, up to a maximum number of characters.
511 * PARAMS
512 * dst [O] Destination string
513 * src [I] Source string
514 * count [I] Maximum number of chars to copy
516 * RETURNS
517 * dst.
519 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
521 LPWSTR d = dst;
522 LPCWSTR s = src;
524 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count);
526 if (s)
528 while ((count > 1) && *s)
530 count--;
531 *d++ = *s++;
534 if (count) *d = 0;
536 return dst;
539 /*************************************************************************
540 * SHLWAPI_StrStrHelperA
542 * Internal implementation of StrStrA/StrStrIA
544 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
545 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
547 size_t iLen;
549 if (!lpszStr || !lpszSearch || !*lpszSearch)
550 return NULL;
552 iLen = strlen(lpszSearch);
554 while (*lpszStr)
556 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
557 return (LPSTR)lpszStr;
558 lpszStr = CharNextA(lpszStr);
560 return NULL;
563 /*************************************************************************
564 * StrStrA [SHLWAPI.@]
566 * Find a substring within a string.
568 * PARAMS
569 * lpszStr [I] String to search in
570 * lpszSearch [I] String to look for
572 * RETURNS
573 * The start of lpszSearch within lpszStr, or NULL if not found.
575 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
577 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
579 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
582 /*************************************************************************
583 * StrStrW [SHLWAPI.@]
585 * See StrStrA.
587 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
589 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
591 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL;
592 return strstrW( lpszStr, lpszSearch );
595 /*************************************************************************
596 * StrRStrIA [SHLWAPI.@]
598 * Find the last occurrence of a substring within a string.
600 * PARAMS
601 * lpszStr [I] String to search in
602 * lpszEnd [I] End of lpszStr
603 * lpszSearch [I] String to look for
605 * RETURNS
606 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
608 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
610 WORD ch1, ch2;
611 INT iLen;
613 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
615 if (!lpszStr || !lpszSearch || !*lpszSearch)
616 return NULL;
618 if (!lpszEnd)
619 lpszEnd = lpszStr + lstrlenA(lpszStr);
620 if (lpszEnd == lpszStr)
621 return NULL;
623 if (IsDBCSLeadByte(*lpszSearch))
624 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
625 else
626 ch1 = *lpszSearch;
627 iLen = lstrlenA(lpszSearch);
631 lpszEnd = CharPrevA(lpszStr, lpszEnd);
632 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
633 if (!ChrCmpIA(ch1, ch2))
635 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
636 return (LPSTR)lpszEnd;
638 } while (lpszEnd > lpszStr);
639 return NULL;
642 /*************************************************************************
643 * StrRStrIW [SHLWAPI.@]
645 * See StrRStrIA.
647 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
649 INT iLen;
651 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
653 if (!lpszStr || !lpszSearch || !*lpszSearch)
654 return NULL;
656 if (!lpszEnd)
657 lpszEnd = lpszStr + strlenW(lpszStr);
659 iLen = strlenW(lpszSearch);
661 while (lpszEnd > lpszStr)
663 lpszEnd--;
664 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
665 return (LPWSTR)lpszEnd;
667 return NULL;
670 /*************************************************************************
671 * StrStrIA [SHLWAPI.@]
673 * Find a substring within a string, ignoring case.
675 * PARAMS
676 * lpszStr [I] String to search in
677 * lpszSearch [I] String to look for
679 * RETURNS
680 * The start of lpszSearch within lpszStr, or NULL if not found.
682 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
684 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
686 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
689 /*************************************************************************
690 * StrStrIW [SHLWAPI.@]
692 * See StrStrIA.
694 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
696 int iLen;
698 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
700 if (!lpszStr || !lpszSearch || !*lpszSearch)
701 return NULL;
703 iLen = strlenW(lpszSearch);
705 while (*lpszStr)
707 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
708 return (LPWSTR)lpszStr;
709 lpszStr++;
711 return NULL;
714 /*************************************************************************
715 * StrStrNW [SHLWAPI.@]
717 * Find a substring within a string up to a given number of initial characters.
719 * PARAMS
720 * lpFirst [I] String to search in
721 * lpSrch [I] String to look for
722 * cchMax [I] Maximum number of initial search characters
724 * RETURNS
725 * The start of lpFirst within lpSrch, or NULL if not found.
727 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
729 UINT i;
730 int len;
732 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
734 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
735 return NULL;
737 len = strlenW(lpSrch);
739 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
741 if (!strncmpW(lpFirst, lpSrch, len))
742 return (LPWSTR)lpFirst;
745 return NULL;
748 /*************************************************************************
749 * StrStrNIW [SHLWAPI.@]
751 * Find a substring within a string up to a given number of initial characters,
752 * ignoring case.
754 * PARAMS
755 * lpFirst [I] String to search in
756 * lpSrch [I] String to look for
757 * cchMax [I] Maximum number of initial search characters
759 * RETURNS
760 * The start of lpFirst within lpSrch, or NULL if not found.
762 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
764 UINT i;
765 int len;
767 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
769 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
770 return NULL;
772 len = strlenW(lpSrch);
774 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
776 if (!strncmpiW(lpFirst, lpSrch, len))
777 return (LPWSTR)lpFirst;
780 return NULL;
783 /*************************************************************************
784 * StrToIntA [SHLWAPI.@]
786 * Read a signed integer from a string.
788 * PARAMS
789 * lpszStr [I] String to read integer from
791 * RETURNS
792 * The signed integer value represented by the string, or 0 if no integer is
793 * present.
795 * NOTES
796 * No leading space is allowed before the number, although a leading '-' is.
798 int WINAPI StrToIntA(LPCSTR lpszStr)
800 int iRet = 0;
802 TRACE("(%s)\n", debugstr_a(lpszStr));
804 if (!lpszStr)
806 WARN("Invalid lpszStr would crash under Win32!\n");
807 return 0;
810 if (*lpszStr == '-' || isdigit(*lpszStr))
811 StrToIntExA(lpszStr, 0, &iRet);
812 return iRet;
815 /*************************************************************************
816 * StrToIntW [SHLWAPI.@]
818 * See StrToIntA.
820 int WINAPI StrToIntW(LPCWSTR lpszStr)
822 int iRet = 0;
824 TRACE("(%s)\n", debugstr_w(lpszStr));
826 if (!lpszStr)
828 WARN("Invalid lpszStr would crash under Win32!\n");
829 return 0;
832 if (*lpszStr == '-' || isdigitW(*lpszStr))
833 StrToIntExW(lpszStr, 0, &iRet);
834 return iRet;
837 /*************************************************************************
838 * StrToIntExA [SHLWAPI.@]
840 * Read an integer from a string.
842 * PARAMS
843 * lpszStr [I] String to read integer from
844 * dwFlags [I] Flags controlling the conversion
845 * lpiRet [O] Destination for read integer.
847 * RETURNS
848 * Success: TRUE. lpiRet contains the integer value represented by the string.
849 * Failure: FALSE, if the string is invalid, or no number is present.
851 * NOTES
852 * Leading whitespace, '-' and '+' are allowed before the number. If
853 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
854 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
855 * the string is treated as a decimal string. A leading '-' is ignored for
856 * hexadecimal numbers.
858 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
860 LONGLONG li;
861 BOOL bRes;
863 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
865 bRes = StrToInt64ExA(lpszStr, dwFlags, &li);
866 if (bRes) *lpiRet = li;
867 return bRes;
870 /*************************************************************************
871 * StrToInt64ExA [SHLWAPI.@]
873 * See StrToIntExA.
875 BOOL WINAPI StrToInt64ExA(LPCSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
877 BOOL bNegative = FALSE;
878 LONGLONG iRet = 0;
880 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
882 if (!lpszStr || !lpiRet)
884 WARN("Invalid parameter would crash under Win32!\n");
885 return FALSE;
887 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
889 /* Skip leading space, '+', '-' */
890 while (isspace(*lpszStr))
891 lpszStr = CharNextA(lpszStr);
893 if (*lpszStr == '-')
895 bNegative = TRUE;
896 lpszStr++;
898 else if (*lpszStr == '+')
899 lpszStr++;
901 if (dwFlags & STIF_SUPPORT_HEX &&
902 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
904 /* Read hex number */
905 lpszStr += 2;
907 if (!isxdigit(*lpszStr))
908 return FALSE;
910 while (isxdigit(*lpszStr))
912 iRet = iRet * 16;
913 if (isdigit(*lpszStr))
914 iRet += (*lpszStr - '0');
915 else
916 iRet += 10 + (tolower(*lpszStr) - 'a');
917 lpszStr++;
919 *lpiRet = iRet;
920 return TRUE;
923 /* Read decimal number */
924 if (!isdigit(*lpszStr))
925 return FALSE;
927 while (isdigit(*lpszStr))
929 iRet = iRet * 10;
930 iRet += (*lpszStr - '0');
931 lpszStr++;
933 *lpiRet = bNegative ? -iRet : iRet;
934 return TRUE;
937 /*************************************************************************
938 * StrToIntExW [SHLWAPI.@]
940 * See StrToIntExA.
942 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
944 LONGLONG li;
945 BOOL bRes;
947 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
949 bRes = StrToInt64ExW(lpszStr, dwFlags, &li);
950 if (bRes) *lpiRet = li;
951 return bRes;
954 /*************************************************************************
955 * StrToInt64ExW [SHLWAPI.@]
957 * See StrToIntExA.
959 BOOL WINAPI StrToInt64ExW(LPCWSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
961 BOOL bNegative = FALSE;
962 LONGLONG iRet = 0;
964 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
966 if (!lpszStr || !lpiRet)
968 WARN("Invalid parameter would crash under Win32!\n");
969 return FALSE;
971 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
973 /* Skip leading space, '+', '-' */
974 while (isspaceW(*lpszStr)) lpszStr++;
976 if (*lpszStr == '-')
978 bNegative = TRUE;
979 lpszStr++;
981 else if (*lpszStr == '+')
982 lpszStr++;
984 if (dwFlags & STIF_SUPPORT_HEX &&
985 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
987 /* Read hex number */
988 lpszStr += 2;
990 if (!isxdigitW(*lpszStr))
991 return FALSE;
993 while (isxdigitW(*lpszStr))
995 iRet = iRet * 16;
996 if (isdigitW(*lpszStr))
997 iRet += (*lpszStr - '0');
998 else
999 iRet += 10 + (tolowerW(*lpszStr) - 'a');
1000 lpszStr++;
1002 *lpiRet = iRet;
1003 return TRUE;
1006 /* Read decimal number */
1007 if (!isdigitW(*lpszStr))
1008 return FALSE;
1010 while (isdigitW(*lpszStr))
1012 iRet = iRet * 10;
1013 iRet += (*lpszStr - '0');
1014 lpszStr++;
1016 *lpiRet = bNegative ? -iRet : iRet;
1017 return TRUE;
1020 /*************************************************************************
1021 * StrDupA [SHLWAPI.@]
1023 * Duplicate a string.
1025 * PARAMS
1026 * lpszStr [I] String to duplicate.
1028 * RETURNS
1029 * Success: A pointer to a new string containing the contents of lpszStr
1030 * Failure: NULL, if memory cannot be allocated
1032 * NOTES
1033 * The string memory is allocated with LocalAlloc(), and so should be released
1034 * by calling LocalFree().
1036 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
1038 int iLen;
1039 LPSTR lpszRet;
1041 TRACE("(%s)\n",debugstr_a(lpszStr));
1043 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
1044 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1046 if (lpszRet)
1048 if (lpszStr)
1049 memcpy(lpszRet, lpszStr, iLen);
1050 else
1051 *lpszRet = '\0';
1053 return lpszRet;
1056 /*************************************************************************
1057 * StrDupW [SHLWAPI.@]
1059 * See StrDupA.
1061 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
1063 int iLen;
1064 LPWSTR lpszRet;
1066 TRACE("(%s)\n",debugstr_w(lpszStr));
1068 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
1069 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1071 if (lpszRet)
1073 if (lpszStr)
1074 memcpy(lpszRet, lpszStr, iLen);
1075 else
1076 *lpszRet = '\0';
1078 return lpszRet;
1081 /*************************************************************************
1082 * SHLWAPI_StrSpnHelperA
1084 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1086 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1087 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1088 BOOL bInvert)
1090 LPCSTR lpszRead = lpszStr;
1091 if (lpszStr && *lpszStr && lpszMatch)
1093 while (*lpszRead)
1095 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1097 if (!bInvert && !lpszTest)
1098 break;
1099 if (bInvert && lpszTest)
1100 break;
1101 lpszRead = CharNextA(lpszRead);
1104 return lpszRead - lpszStr;
1107 /*************************************************************************
1108 * StrSpnA [SHLWAPI.@]
1110 * Find the length of the start of a string that contains only certain
1111 * characters.
1113 * PARAMS
1114 * lpszStr [I] String to search
1115 * lpszMatch [I] Characters that can be in the substring
1117 * RETURNS
1118 * The length of the part of lpszStr containing only chars from lpszMatch,
1119 * or 0 if any parameter is invalid.
1121 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1123 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1125 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1128 /*************************************************************************
1129 * StrSpnW [SHLWAPI.@]
1131 * See StrSpnA.
1133 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1135 if (!lpszStr || !lpszMatch) return 0;
1136 return strspnW( lpszStr, lpszMatch );
1139 /*************************************************************************
1140 * StrCSpnA [SHLWAPI.@]
1142 * Find the length of the start of a string that does not contain certain
1143 * characters.
1145 * PARAMS
1146 * lpszStr [I] String to search
1147 * lpszMatch [I] Characters that cannot be in the substring
1149 * RETURNS
1150 * The length of the part of lpszStr containing only chars not in lpszMatch,
1151 * or 0 if any parameter is invalid.
1153 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1155 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1157 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1160 /*************************************************************************
1161 * StrCSpnW [SHLWAPI.@]
1163 * See StrCSpnA.
1165 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1167 if (!lpszStr || !lpszMatch) return 0;
1168 return strcspnW( lpszStr, lpszMatch );
1171 /*************************************************************************
1172 * StrCSpnIA [SHLWAPI.@]
1174 * Find the length of the start of a string that does not contain certain
1175 * characters, ignoring case.
1177 * PARAMS
1178 * lpszStr [I] String to search
1179 * lpszMatch [I] Characters that cannot be in the substring
1181 * RETURNS
1182 * The length of the part of lpszStr containing only chars not in lpszMatch,
1183 * or 0 if any parameter is invalid.
1185 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1187 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1189 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1192 /*************************************************************************
1193 * StrCSpnIW [SHLWAPI.@]
1195 * See StrCSpnIA.
1197 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1199 LPCWSTR lpszRead = lpszStr;
1201 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1203 if (lpszStr && *lpszStr && lpszMatch)
1205 while (*lpszRead)
1207 if (StrChrIW(lpszMatch, *lpszRead)) break;
1208 lpszRead++;
1211 return lpszRead - lpszStr;
1214 /*************************************************************************
1215 * StrPBrkA [SHLWAPI.@]
1217 * Search a string for any of a group of characters.
1219 * PARAMS
1220 * lpszStr [I] String to search
1221 * lpszMatch [I] Characters to match
1223 * RETURNS
1224 * A pointer to the first matching character in lpszStr, or NULL if no
1225 * match was found.
1227 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1229 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1231 if (lpszStr && lpszMatch && *lpszMatch)
1233 while (*lpszStr)
1235 if (StrChrA(lpszMatch, *lpszStr))
1236 return (LPSTR)lpszStr;
1237 lpszStr = CharNextA(lpszStr);
1240 return NULL;
1243 /*************************************************************************
1244 * StrPBrkW [SHLWAPI.@]
1246 * See StrPBrkA.
1248 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1250 if (!lpszStr || !lpszMatch) return NULL;
1251 return strpbrkW( lpszStr, lpszMatch );
1254 /*************************************************************************
1255 * SHLWAPI_StrRChrHelperA
1257 * Internal implementation of StrRChrA/StrRChrIA.
1259 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1260 LPCSTR lpszEnd, WORD ch,
1261 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1263 LPCSTR lpszRet = NULL;
1265 if (lpszStr)
1267 WORD ch2;
1269 if (!lpszEnd)
1270 lpszEnd = lpszStr + lstrlenA(lpszStr);
1272 while (*lpszStr && lpszStr <= lpszEnd)
1274 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1276 if (!pChrCmpFn(ch, ch2))
1277 lpszRet = lpszStr;
1278 lpszStr = CharNextA(lpszStr);
1281 return (LPSTR)lpszRet;
1284 /**************************************************************************
1285 * StrRChrA [SHLWAPI.@]
1287 * Find the last occurrence of a character in string.
1289 * PARAMS
1290 * lpszStr [I] String to search in
1291 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1292 * ch [I] Character to search for.
1294 * RETURNS
1295 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1296 * or NULL if not found.
1297 * Failure: NULL, if any arguments are invalid.
1299 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1301 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1303 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1306 /**************************************************************************
1307 * StrRChrW [SHLWAPI.@]
1309 * See StrRChrA.
1311 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1313 WCHAR *ret = NULL;
1315 if (!str) return NULL;
1316 if (!end) end = str + strlenW(str);
1317 while (str < end)
1319 if (*str == ch) ret = (WCHAR *)str;
1320 str++;
1322 return ret;
1325 /**************************************************************************
1326 * StrRChrIA [SHLWAPI.@]
1328 * Find the last occurrence of a character in string, ignoring case.
1330 * PARAMS
1331 * lpszStr [I] String to search in
1332 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1333 * ch [I] Character to search for.
1335 * RETURNS
1336 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1337 * or NULL if not found.
1338 * Failure: NULL, if any arguments are invalid.
1340 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1342 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1344 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1347 /**************************************************************************
1348 * StrRChrIW [SHLWAPI.@]
1350 * See StrRChrIA.
1352 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1354 WCHAR *ret = NULL;
1356 if (!str) return NULL;
1357 if (!end) end = str + strlenW(str);
1358 while (str < end)
1360 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1361 str++;
1363 return ret;
1366 /*************************************************************************
1367 * StrCatBuffA [SHLWAPI.@]
1369 * Concatenate two strings together.
1371 * PARAMS
1372 * lpszStr [O] String to concatenate to
1373 * lpszCat [I] String to add to lpszCat
1374 * cchMax [I] Maximum number of characters for the whole string
1376 * RETURNS
1377 * lpszStr.
1379 * NOTES
1380 * cchMax determines the number of characters in the final length of the
1381 * string, not the number appended to lpszStr from lpszCat.
1383 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1385 INT iLen;
1387 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1389 if (!lpszStr)
1391 WARN("Invalid lpszStr would crash under Win32!\n");
1392 return NULL;
1395 iLen = strlen(lpszStr);
1396 cchMax -= iLen;
1398 if (cchMax > 0)
1399 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1400 return lpszStr;
1403 /*************************************************************************
1404 * StrCatBuffW [SHLWAPI.@]
1406 * See StrCatBuffA.
1408 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1410 INT iLen;
1412 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1414 if (!lpszStr)
1416 WARN("Invalid lpszStr would crash under Win32!\n");
1417 return NULL;
1420 iLen = strlenW(lpszStr);
1421 cchMax -= iLen;
1423 if (cchMax > 0)
1424 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1425 return lpszStr;
1428 /*************************************************************************
1429 * StrRetToBufA [SHLWAPI.@]
1431 * Convert a STRRET to a normal string.
1433 * PARAMS
1434 * lpStrRet [O] STRRET to convert
1435 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1436 * lpszDest [O] Destination for normal string
1437 * dwLen [I] Length of lpszDest
1439 * RETURNS
1440 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1441 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1442 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1443 * Failure: E_FAIL, if any parameters are invalid.
1445 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1447 /* NOTE:
1448 * This routine is identical to that in dlls/shell32/shellstring.c.
1449 * It was duplicated because not every version of Shlwapi.dll exports
1450 * StrRetToBufA. If you change one routine, change them both.
1452 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1454 if (!src)
1456 WARN("Invalid lpStrRet would crash under Win32!\n");
1457 if (dest)
1458 *dest = '\0';
1459 return E_FAIL;
1462 if (!dest || !len)
1463 return E_FAIL;
1465 *dest = '\0';
1467 switch (src->uType)
1469 case STRRET_WSTR:
1470 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1471 CoTaskMemFree(src->u.pOleStr);
1472 break;
1474 case STRRET_CSTR:
1475 lstrcpynA(dest, src->u.cStr, len);
1476 break;
1478 case STRRET_OFFSET:
1479 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1480 break;
1482 default:
1483 FIXME("unknown type!\n");
1484 return FALSE;
1486 return S_OK;
1489 /*************************************************************************
1490 * StrRetToBufW [SHLWAPI.@]
1492 * See StrRetToBufA.
1494 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1496 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1498 if (!src)
1500 WARN("Invalid lpStrRet would crash under Win32!\n");
1501 if (dest)
1502 *dest = '\0';
1503 return E_FAIL;
1506 if (!dest || !len)
1507 return E_FAIL;
1509 *dest = '\0';
1511 switch (src->uType)
1513 case STRRET_WSTR:
1514 lstrcpynW(dest, src->u.pOleStr, len);
1515 CoTaskMemFree(src->u.pOleStr);
1516 break;
1518 case STRRET_CSTR:
1519 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1520 dest[len-1] = 0;
1521 break;
1523 case STRRET_OFFSET:
1524 if (pidl)
1526 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1527 dest, len ))
1528 dest[len-1] = 0;
1530 break;
1532 default:
1533 FIXME("unknown type!\n");
1534 return FALSE;
1536 return S_OK;
1539 /*************************************************************************
1540 * StrRetToStrA [SHLWAPI.@]
1542 * Converts a STRRET to a normal string.
1544 * PARAMS
1545 * lpStrRet [O] STRRET to convert
1546 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1547 * ppszName [O] Destination for converted string
1549 * RETURNS
1550 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1551 * Failure: E_FAIL, if any parameters are invalid.
1553 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1555 HRESULT hRet = E_FAIL;
1557 switch (lpStrRet->uType)
1559 case STRRET_WSTR:
1560 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1561 CoTaskMemFree(lpStrRet->u.pOleStr);
1562 break;
1564 case STRRET_CSTR:
1565 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1566 break;
1568 case STRRET_OFFSET:
1569 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1570 break;
1572 default:
1573 *ppszName = NULL;
1576 return hRet;
1579 /*************************************************************************
1580 * StrRetToStrW [SHLWAPI.@]
1582 * See StrRetToStrA.
1584 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1586 HRESULT hRet = E_FAIL;
1588 switch (lpStrRet->uType)
1590 case STRRET_WSTR:
1591 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1592 CoTaskMemFree(lpStrRet->u.pOleStr);
1593 break;
1595 case STRRET_CSTR:
1596 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1597 break;
1599 case STRRET_OFFSET:
1600 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1601 break;
1603 default:
1604 *ppszName = NULL;
1607 return hRet;
1610 /* Create an ASCII string copy using SysAllocString() */
1611 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1613 *pBstrOut = NULL;
1615 if (src)
1617 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1618 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1620 if (szTemp)
1622 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1623 *pBstrOut = SysAllocString(szTemp);
1624 HeapFree(GetProcessHeap(), 0, szTemp);
1626 if (*pBstrOut)
1627 return S_OK;
1630 return E_OUTOFMEMORY;
1633 /*************************************************************************
1634 * StrRetToBSTR [SHLWAPI.@]
1636 * Converts a STRRET to a BSTR.
1638 * PARAMS
1639 * lpStrRet [O] STRRET to convert
1640 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1641 * pBstrOut [O] Destination for converted BSTR
1643 * RETURNS
1644 * Success: S_OK. pBstrOut contains the new string.
1645 * Failure: E_FAIL, if any parameters are invalid.
1647 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1649 HRESULT hRet = E_FAIL;
1651 switch (lpStrRet->uType)
1653 case STRRET_WSTR:
1654 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1655 if (*pBstrOut)
1656 hRet = S_OK;
1657 CoTaskMemFree(lpStrRet->u.pOleStr);
1658 break;
1660 case STRRET_CSTR:
1661 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1662 break;
1664 case STRRET_OFFSET:
1665 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1666 break;
1668 default:
1669 *pBstrOut = NULL;
1672 return hRet;
1675 /*************************************************************************
1676 * StrFormatKBSizeA [SHLWAPI.@]
1678 * Create a formatted string containing a byte count in Kilobytes.
1680 * PARAMS
1681 * llBytes [I] Byte size to format
1682 * lpszDest [I] Destination for formatted string
1683 * cchMax [I] Size of lpszDest
1685 * RETURNS
1686 * lpszDest.
1688 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1690 WCHAR wszBuf[256];
1692 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1693 return NULL;
1694 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1695 return NULL;
1696 return lpszDest;
1699 /*************************************************************************
1700 * StrFormatKBSizeW [SHLWAPI.@]
1702 * See StrFormatKBSizeA.
1704 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1706 static const WCHAR kb[] = {' ','K','B',0};
1707 LONGLONG llKB = (llBytes + 1023) >> 10;
1708 int len;
1710 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1712 if (!FormatInt(llKB, lpszDest, cchMax))
1713 return NULL;
1715 len = lstrlenW(lpszDest);
1716 if (cchMax - len < 4)
1717 return NULL;
1718 lstrcatW(lpszDest, kb);
1719 return lpszDest;
1722 /*************************************************************************
1723 * StrNCatA [SHLWAPI.@]
1725 * Concatenate two strings together.
1727 * PARAMS
1728 * lpszStr [O] String to concatenate to
1729 * lpszCat [I] String to add to lpszCat
1730 * cchMax [I] Maximum number of characters to concatenate
1732 * RETURNS
1733 * lpszStr.
1735 * NOTES
1736 * cchMax determines the number of characters that are appended to lpszStr,
1737 * not the total length of the string.
1739 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1741 LPSTR lpszRet = lpszStr;
1743 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1745 if (!lpszStr)
1747 WARN("Invalid lpszStr would crash under Win32!\n");
1748 return NULL;
1751 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1752 return lpszRet;
1755 /*************************************************************************
1756 * StrNCatW [SHLWAPI.@]
1758 * See StrNCatA.
1760 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1762 LPWSTR lpszRet = lpszStr;
1764 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1766 if (!lpszStr)
1768 WARN("Invalid lpszStr would crash under Win32\n");
1769 return NULL;
1772 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1773 return lpszRet;
1776 /*************************************************************************
1777 * StrTrimA [SHLWAPI.@]
1779 * Remove characters from the start and end of a string.
1781 * PARAMS
1782 * lpszStr [O] String to remove characters from
1783 * lpszTrim [I] Characters to remove from lpszStr
1785 * RETURNS
1786 * TRUE If lpszStr was valid and modified
1787 * FALSE Otherwise
1789 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1791 DWORD dwLen;
1792 LPSTR lpszRead = lpszStr;
1793 BOOL bRet = FALSE;
1795 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1797 if (lpszRead && *lpszRead)
1799 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1800 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1802 dwLen = strlen(lpszRead);
1804 if (lpszRead != lpszStr)
1806 memmove(lpszStr, lpszRead, dwLen + 1);
1807 bRet = TRUE;
1809 if (dwLen > 0)
1811 lpszRead = lpszStr + dwLen;
1812 while (StrChrA(lpszTrim, lpszRead[-1]))
1813 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1815 if (lpszRead != lpszStr + dwLen)
1817 *lpszRead = '\0';
1818 bRet = TRUE;
1822 return bRet;
1825 /*************************************************************************
1826 * StrTrimW [SHLWAPI.@]
1828 * See StrTrimA.
1830 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1832 DWORD dwLen;
1833 LPWSTR lpszRead = lpszStr;
1834 BOOL bRet = FALSE;
1836 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1838 if (lpszRead && *lpszRead)
1840 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1842 dwLen = strlenW(lpszRead);
1844 if (lpszRead != lpszStr)
1846 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1847 bRet = TRUE;
1849 if (dwLen > 0)
1851 lpszRead = lpszStr + dwLen;
1852 while (StrChrW(lpszTrim, lpszRead[-1]))
1853 lpszRead--; /* Skip trailing matches */
1855 if (lpszRead != lpszStr + dwLen)
1857 *lpszRead = '\0';
1858 bRet = TRUE;
1862 return bRet;
1865 /*************************************************************************
1866 * _SHStrDupAA [INTERNAL]
1868 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1870 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1872 HRESULT hr;
1873 int len = 0;
1875 if (src) {
1876 len = lstrlenA(src) + 1;
1877 *dest = CoTaskMemAlloc(len);
1878 } else {
1879 *dest = NULL;
1882 if (*dest) {
1883 lstrcpynA(*dest,src, len);
1884 hr = S_OK;
1885 } else {
1886 hr = E_OUTOFMEMORY;
1889 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1890 return hr;
1893 /*************************************************************************
1894 * SHStrDupA [SHLWAPI.@]
1896 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1898 * PARAMS
1899 * lpszStr [I] String to copy
1900 * lppszDest [O] Destination for the new string copy
1902 * RETURNS
1903 * Success: S_OK. lppszDest contains the new string in Unicode format.
1904 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1905 * fails.
1907 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1909 HRESULT hRet;
1910 int len = 0;
1912 if (lpszStr)
1914 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1915 *lppszDest = CoTaskMemAlloc(len);
1917 else
1918 *lppszDest = NULL;
1920 if (*lppszDest)
1922 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1923 hRet = S_OK;
1925 else
1926 hRet = E_OUTOFMEMORY;
1928 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1929 return hRet;
1932 /*************************************************************************
1933 * _SHStrDupAW [INTERNAL]
1935 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1937 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1939 HRESULT hr;
1940 int len = 0;
1942 if (src) {
1943 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1944 *dest = CoTaskMemAlloc(len);
1945 } else {
1946 *dest = NULL;
1949 if (*dest) {
1950 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1951 hr = S_OK;
1952 } else {
1953 hr = E_OUTOFMEMORY;
1956 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1957 return hr;
1960 /*************************************************************************
1961 * SHStrDupW [SHLWAPI.@]
1963 * See SHStrDupA.
1965 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1967 HRESULT hr;
1968 int len = 0;
1970 if (src) {
1971 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1972 *dest = CoTaskMemAlloc(len);
1973 } else {
1974 *dest = NULL;
1977 if (*dest) {
1978 memcpy(*dest, src, len);
1979 hr = S_OK;
1980 } else {
1981 hr = E_OUTOFMEMORY;
1984 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1985 return hr;
1988 /*************************************************************************
1989 * SHLWAPI_WriteReverseNum
1991 * Internal helper for SHLWAPI_WriteTimeClass.
1993 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1995 *lpszOut-- = '\0';
1997 /* Write a decimal number to a string, backwards */
2000 DWORD dwNextDigit = dwNum % 10;
2001 *lpszOut-- = '0' + dwNextDigit;
2002 dwNum = (dwNum - dwNextDigit) / 10;
2003 } while (dwNum > 0);
2005 return lpszOut;
2008 /*************************************************************************
2009 * SHLWAPI_FormatSignificant
2011 * Internal helper for SHLWAPI_WriteTimeClass.
2013 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
2015 /* Zero non significant digits, return remaining significant digits */
2016 while (*lpszNum)
2018 lpszNum++;
2019 if (--dwDigits == 0)
2021 while (*lpszNum)
2022 *lpszNum++ = '0';
2023 return 0;
2026 return dwDigits;
2029 /*************************************************************************
2030 * SHLWAPI_WriteTimeClass
2032 * Internal helper for StrFromTimeIntervalW.
2034 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2035 UINT uClassStringId, int iDigits)
2037 WCHAR szBuff[64], *szOut = szBuff + 32;
2039 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2040 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2041 *szOut = ' ';
2042 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2043 strcatW(lpszOut, szOut);
2044 return iDigits;
2047 /*************************************************************************
2048 * StrFromTimeIntervalA [SHLWAPI.@]
2050 * Format a millisecond time interval into a string
2052 * PARAMS
2053 * lpszStr [O] Output buffer for formatted time interval
2054 * cchMax [I] Size of lpszStr
2055 * dwMS [I] Number of milliseconds
2056 * iDigits [I] Number of digits to print
2058 * RETURNS
2059 * The length of the formatted string, or 0 if any parameter is invalid.
2061 * NOTES
2062 * This implementation mimics the Win32 behaviour of always writing a leading
2063 * space before the time interval begins.
2065 * iDigits is used to provide approximate times if accuracy is not important.
2066 * This number of digits will be written of the first non-zero time class
2067 * (hours/minutes/seconds). If this does not complete the time classification,
2068 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2069 * If there are digits remaining following the writing of a time class, the
2070 * next time class will be written.
2072 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2073 * following will result from the given values of iDigits:
2075 *| iDigits 1 2 3 4 5 ...
2076 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2078 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2079 int iDigits)
2081 INT iRet = 0;
2083 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2085 if (lpszStr && cchMax)
2087 WCHAR szBuff[128];
2088 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2089 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2091 return iRet;
2095 /*************************************************************************
2096 * StrFromTimeIntervalW [SHLWAPI.@]
2098 * See StrFromTimeIntervalA.
2100 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2101 int iDigits)
2103 INT iRet = 0;
2105 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2107 if (lpszStr && cchMax)
2109 WCHAR szCopy[128];
2110 DWORD dwHours, dwMinutes;
2112 if (!iDigits || cchMax == 1)
2114 *lpszStr = '\0';
2115 return 0;
2118 /* Calculate the time classes */
2119 dwMS = (dwMS + 500) / 1000;
2120 dwHours = dwMS / 3600;
2121 dwMS -= dwHours * 3600;
2122 dwMinutes = dwMS / 60;
2123 dwMS -= dwMinutes * 60;
2125 szCopy[0] = '\0';
2127 if (dwHours)
2128 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2130 if (dwMinutes && iDigits)
2131 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2133 if (iDigits) /* Always write seconds if we have significant digits */
2134 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2136 lstrcpynW(lpszStr, szCopy, cchMax);
2137 iRet = strlenW(lpszStr);
2139 return iRet;
2142 /*************************************************************************
2143 * StrIsIntlEqualA [SHLWAPI.@]
2145 * Compare two strings.
2147 * PARAMS
2148 * bCase [I] Whether to compare case sensitively
2149 * lpszStr [I] First string to compare
2150 * lpszComp [I] Second string to compare
2151 * iLen [I] Length to compare
2153 * RETURNS
2154 * TRUE If the strings are equal.
2155 * FALSE Otherwise.
2157 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2158 int iLen)
2160 DWORD dwFlags;
2162 TRACE("(%d,%s,%s,%d)\n", bCase,
2163 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2165 /* FIXME: This flag is undocumented and unknown by our CompareString.
2166 * We need a define for it.
2168 dwFlags = 0x10000000;
2169 if (!bCase) dwFlags |= NORM_IGNORECASE;
2171 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2174 /*************************************************************************
2175 * StrIsIntlEqualW [SHLWAPI.@]
2177 * See StrIsIntlEqualA.
2179 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2180 int iLen)
2182 DWORD dwFlags;
2184 TRACE("(%d,%s,%s,%d)\n", bCase,
2185 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2187 /* FIXME: This flag is undocumented and unknown by our CompareString.
2188 * We need a define for it.
2190 dwFlags = 0x10000000;
2191 if (!bCase) dwFlags |= NORM_IGNORECASE;
2193 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2196 /*************************************************************************
2197 * @ [SHLWAPI.399]
2199 * Copy a string to another string, up to a maximum number of characters.
2201 * PARAMS
2202 * lpszDest [O] Destination string
2203 * lpszSrc [I] Source string
2204 * iLen [I] Maximum number of chars to copy
2206 * RETURNS
2207 * Success: A pointer to the last character written to lpszDest.
2208 * Failure: lpszDest, if any arguments are invalid.
2210 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2212 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2214 if (lpszDest && lpszSrc && iLen > 0)
2216 while ((iLen-- > 1) && *lpszSrc)
2217 *lpszDest++ = *lpszSrc++;
2218 if (iLen >= 0)
2219 *lpszDest = '\0';
2221 return lpszDest;
2224 /*************************************************************************
2225 * @ [SHLWAPI.400]
2227 * Unicode version of StrCpyNXA.
2229 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2231 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2233 if (lpszDest && lpszSrc && iLen > 0)
2235 while ((iLen-- > 1) && *lpszSrc)
2236 *lpszDest++ = *lpszSrc++;
2237 if (iLen >= 0)
2238 *lpszDest = '\0';
2240 return lpszDest;
2243 /*************************************************************************
2244 * StrCmpLogicalW [SHLWAPI.@]
2246 * Compare two strings, ignoring case and comparing digits as numbers.
2248 * PARAMS
2249 * lpszStr [I] First string to compare
2250 * lpszComp [I] Second string to compare
2251 * iLen [I] Length to compare
2253 * RETURNS
2254 * TRUE If the strings are equal.
2255 * FALSE Otherwise.
2257 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2259 INT iDiff;
2261 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2263 if (lpszStr && lpszComp)
2265 while (*lpszStr)
2267 if (!*lpszComp)
2268 return 1;
2269 else if (isdigitW(*lpszStr))
2271 int iStr, iComp;
2273 if (!isdigitW(*lpszComp))
2274 return -1;
2276 /* Compare the numbers */
2277 StrToIntExW(lpszStr, 0, &iStr);
2278 StrToIntExW(lpszComp, 0, &iComp);
2280 if (iStr < iComp)
2281 return -1;
2282 else if (iStr > iComp)
2283 return 1;
2285 /* Skip */
2286 while (isdigitW(*lpszStr))
2287 lpszStr++;
2288 while (isdigitW(*lpszComp))
2289 lpszComp++;
2291 else if (isdigitW(*lpszComp))
2292 return 1;
2293 else
2295 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2296 if (iDiff > 0)
2297 return 1;
2298 else if (iDiff < 0)
2299 return -1;
2301 lpszStr++;
2302 lpszComp++;
2305 if (*lpszComp)
2306 return -1;
2308 return 0;
2311 /* Structure for formatting byte strings */
2312 typedef struct tagSHLWAPI_BYTEFORMATS
2314 LONGLONG dLimit;
2315 double dDivisor;
2316 double dNormaliser;
2317 int nDecimals;
2318 WCHAR wPrefix;
2319 } SHLWAPI_BYTEFORMATS;
2321 /*************************************************************************
2322 * StrFormatByteSizeW [SHLWAPI.@]
2324 * Create a string containing an abbreviated byte count of up to 2^63-1.
2326 * PARAMS
2327 * llBytes [I] Byte size to format
2328 * lpszDest [I] Destination for formatted string
2329 * cchMax [I] Size of lpszDest
2331 * RETURNS
2332 * lpszDest.
2334 * NOTES
2335 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2337 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2339 #define KB ((ULONGLONG)1024)
2340 #define MB (KB*KB)
2341 #define GB (KB*KB*KB)
2342 #define TB (KB*KB*KB*KB)
2343 #define PB (KB*KB*KB*KB*KB)
2345 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2347 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2348 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2349 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2350 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2351 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2352 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2353 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2354 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2355 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2356 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2357 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2358 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2359 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2360 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2361 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2362 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2364 WCHAR wszAdd[] = {' ','?','B',0};
2365 double dBytes;
2366 UINT i = 0;
2368 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2370 if (!lpszDest || !cchMax)
2371 return lpszDest;
2373 if (llBytes < 1024) /* 1K */
2375 WCHAR wszBytesFormat[64];
2376 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2377 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
2378 return lpszDest;
2381 /* Note that if this loop completes without finding a match, i will be
2382 * pointing at the last entry, which is a catch all for > 1000 PB
2384 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2386 if (llBytes < bfFormats[i].dLimit)
2387 break;
2388 i++;
2390 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2391 * this number we integer shift down by 1 MB first. The table above has
2392 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2393 * for this. We also add a small fudge factor to get the correct result for
2394 * counts that lie exactly on a 1024 byte boundary.
2396 if (i > 8)
2397 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
2398 else
2399 dBytes = (double)llBytes + 0.00001;
2401 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2403 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2404 return NULL;
2405 wszAdd[1] = bfFormats[i].wPrefix;
2406 StrCatBuffW(lpszDest, wszAdd, cchMax);
2407 return lpszDest;
2410 /*************************************************************************
2411 * StrFormatByteSize64A [SHLWAPI.@]
2413 * See StrFormatByteSizeW.
2415 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2417 WCHAR wszBuff[32];
2419 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2421 if (lpszDest)
2422 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2423 return lpszDest;
2426 /*************************************************************************
2427 * StrFormatByteSizeA [SHLWAPI.@]
2429 * Create a string containing an abbreviated byte count of up to 2^31-1.
2431 * PARAMS
2432 * dwBytes [I] Byte size to format
2433 * lpszDest [I] Destination for formatted string
2434 * cchMax [I] Size of lpszDest
2436 * RETURNS
2437 * lpszDest.
2439 * NOTES
2440 * The Ascii and Unicode versions of this function accept a different
2441 * integer type for dwBytes. See StrFormatByteSize64A().
2443 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2445 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2447 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2450 /*************************************************************************
2451 * @ [SHLWAPI.162]
2453 * Remove a hanging lead byte from the end of a string, if present.
2455 * PARAMS
2456 * lpStr [I] String to check for a hanging lead byte
2457 * size [I] Length of lpStr
2459 * RETURNS
2460 * Success: The new length of the string. Any hanging lead bytes are removed.
2461 * Failure: 0, if any parameters are invalid.
2463 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2465 if (lpStr && size)
2467 LPSTR lastByte = lpStr + size - 1;
2469 while(lpStr < lastByte)
2470 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2472 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2474 *lpStr = '\0';
2475 size--;
2477 return size;
2479 return 0;
2482 /*************************************************************************
2483 * @ [SHLWAPI.203]
2485 * Remove a single non-trailing ampersand ('&') from a string.
2487 * PARAMS
2488 * lpszStr [I/O] String to remove ampersand from.
2490 * RETURNS
2491 * The character after the first ampersand in lpszStr, or the first character
2492 * in lpszStr if there is no ampersand in the string.
2494 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2496 LPSTR lpszIter, lpszTmp;
2497 char ch;
2499 TRACE("(%s)\n", debugstr_a(lpszStr));
2501 ch = *lpszStr;
2503 if ((lpszIter = StrChrA(lpszStr, '&')))
2505 lpszTmp = CharNextA(lpszIter);
2506 if (*lpszTmp)
2508 if (*lpszTmp != '&')
2509 ch = *lpszTmp;
2511 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
2515 return ch;
2518 /*************************************************************************
2519 * @ [SHLWAPI.225]
2521 * Unicode version of SHStripMneumonicA.
2523 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2525 LPWSTR lpszIter, lpszTmp;
2526 WCHAR ch;
2528 TRACE("(%s)\n", debugstr_w(lpszStr));
2530 ch = *lpszStr;
2532 if ((lpszIter = StrChrW(lpszStr, '&')))
2534 lpszTmp = lpszIter + 1;
2535 if (*lpszTmp)
2537 if (*lpszTmp != '&')
2538 ch = *lpszTmp;
2540 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
2544 return ch;
2547 /*************************************************************************
2548 * @ [SHLWAPI.216]
2550 * Convert an Ascii string to Unicode.
2552 * PARAMS
2553 * dwCp [I] Code page for the conversion
2554 * lpSrcStr [I] Source Ascii string to convert
2555 * lpDstStr [O] Destination for converted Unicode string
2556 * iLen [I] Length of lpDstStr
2558 * RETURNS
2559 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2561 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2563 DWORD dwRet;
2565 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2566 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2567 return dwRet;
2570 /*************************************************************************
2571 * @ [SHLWAPI.215]
2573 * Convert an Ascii string to Unicode.
2575 * PARAMS
2576 * lpSrcStr [I] Source Ascii string to convert
2577 * lpDstStr [O] Destination for converted Unicode string
2578 * iLen [I] Length of lpDstStr
2580 * RETURNS
2581 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2583 * NOTES
2584 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2586 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2588 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2591 /*************************************************************************
2592 * @ [SHLWAPI.218]
2594 * Convert a Unicode string to Ascii.
2596 * PARAMS
2597 * CodePage [I] Code page to use for the conversion
2598 * lpSrcStr [I] Source Unicode string to convert
2599 * lpDstStr [O] Destination for converted Ascii string
2600 * dstlen [I] Length of buffer at lpDstStr
2602 * RETURNS
2603 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2604 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2605 * the result is not nul-terminated.
2606 * When using a different codepage, the length in bytes of the truncated
2607 * result at lpDstStr (including the terminator) is returned and
2608 * lpDstStr is always nul-terminated.
2611 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2613 static const WCHAR emptyW[] = { '\0' };
2614 int len , reqLen;
2615 LPSTR mem;
2617 if (!lpDstStr || !dstlen)
2618 return 0;
2620 if (!lpSrcStr)
2621 lpSrcStr = emptyW;
2623 *lpDstStr = '\0';
2625 len = strlenW(lpSrcStr) + 1;
2627 switch (CodePage)
2629 case CP_WINUNICODE:
2630 CodePage = CP_UTF8; /* Fall through... */
2631 case 0x0000C350: /* FIXME: CP_ #define */
2632 case CP_UTF7:
2633 case CP_UTF8:
2635 DWORD dwMode = 0;
2636 INT lenW = len - 1;
2637 INT needed = dstlen - 1;
2638 HRESULT hr;
2640 /* try the user supplied buffer first */
2641 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2642 if (hr == S_OK)
2644 lpDstStr[needed] = '\0';
2645 return needed + 1;
2648 /* user buffer too small. exclude termination and copy as much as possible */
2649 lenW = len;
2650 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2651 needed++;
2652 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2653 if (!mem)
2654 return 0;
2656 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2657 if (hr == S_OK)
2659 reqLen = SHTruncateString(mem, dstlen);
2660 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2662 HeapFree(GetProcessHeap(), 0, mem);
2663 return 0;
2665 default:
2666 break;
2669 /* try the user supplied buffer first */
2670 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2672 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2674 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2675 if (reqLen)
2677 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2678 if (mem)
2680 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2681 reqLen, NULL, NULL);
2683 reqLen = SHTruncateString(mem, dstlen -1);
2684 reqLen++;
2686 lstrcpynA(lpDstStr, mem, reqLen);
2687 HeapFree(GetProcessHeap(), 0, mem);
2688 lpDstStr[reqLen-1] = '\0';
2692 return reqLen;
2695 /*************************************************************************
2696 * @ [SHLWAPI.217]
2698 * Convert a Unicode string to Ascii.
2700 * PARAMS
2701 * lpSrcStr [I] Source Unicode string to convert
2702 * lpDstStr [O] Destination for converted Ascii string
2703 * iLen [O] Length of lpDstStr in characters
2705 * RETURNS
2706 * See SHUnicodeToAnsiCP
2708 * NOTES
2709 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2711 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2713 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2716 /*************************************************************************
2717 * @ [SHLWAPI.345]
2719 * Copy one string to another.
2721 * PARAMS
2722 * lpszSrc [I] Source string to copy
2723 * lpszDst [O] Destination for copy
2724 * iLen [I] Length of lpszDst in characters
2726 * RETURNS
2727 * The length of the copied string, including the terminating NUL. lpszDst
2728 * contains iLen characters of lpszSrc.
2730 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2732 LPSTR lpszRet;
2734 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2736 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2737 return lpszRet - lpszDst + 1;
2740 /*************************************************************************
2741 * @ [SHLWAPI.346]
2743 * Unicode version of SSHAnsiToAnsi.
2745 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2747 LPWSTR lpszRet;
2749 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2751 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2752 return lpszRet - lpszDst + 1;
2755 /*************************************************************************
2756 * @ [SHLWAPI.364]
2758 * Determine if an Ascii string converts to Unicode and back identically.
2760 * PARAMS
2761 * lpSrcStr [I] Source Unicode string to convert
2762 * lpDst [O] Destination for resulting Ascii string
2763 * iLen [I] Length of lpDst in characters
2765 * RETURNS
2766 * TRUE, since Ascii strings always convert identically.
2768 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2770 lstrcpynA(lpDst, lpSrcStr, iLen);
2771 return TRUE;
2774 /*************************************************************************
2775 * @ [SHLWAPI.365]
2777 * Determine if a Unicode string converts to Ascii and back identically.
2779 * PARAMS
2780 * lpSrcStr [I] Source Unicode string to convert
2781 * lpDst [O] Destination for resulting Ascii string
2782 * iLen [I] Length of lpDst in characters
2784 * RETURNS
2785 * TRUE, if lpSrcStr converts to Ascii and back identically,
2786 * FALSE otherwise.
2788 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2790 WCHAR szBuff[MAX_PATH];
2792 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2793 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2794 return !strcmpW(lpSrcStr, szBuff);
2797 /*************************************************************************
2798 * SHLoadIndirectString [SHLWAPI.@]
2800 * If passed a string that begins with '@', extract the string from the
2801 * appropriate resource, otherwise do a straight copy.
2804 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2806 WCHAR *dllname = NULL;
2807 HMODULE hmod = NULL;
2808 HRESULT hr = E_FAIL;
2810 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2812 if(src[0] == '@')
2814 WCHAR *index_str;
2815 int index;
2817 dst[0] = 0;
2818 dllname = StrDupW(src + 1);
2819 index_str = strchrW(dllname, ',');
2821 if(!index_str) goto end;
2823 *index_str = 0;
2824 index_str++;
2825 index = atoiW(index_str);
2827 hmod = LoadLibraryW(dllname);
2828 if(!hmod) goto end;
2830 if(index < 0)
2832 if(LoadStringW(hmod, -index, dst, dst_len))
2833 hr = S_OK;
2835 else
2836 FIXME("can't handle non-negative indices (%d)\n", index);
2838 else
2840 if(dst != src)
2841 lstrcpynW(dst, src, dst_len);
2842 hr = S_OK;
2845 TRACE("returning %s\n", debugstr_w(dst));
2846 end:
2847 if(hmod) FreeLibrary(hmod);
2848 HeapFree(GetProcessHeap(), 0, dllname);
2849 return hr;