wordpad: Add Ukrainian translations.
[wine/hacks.git] / dlls / shlwapi / string.c
blobcfb59ea440040dabbc29d27ef77f7eaecb02692c
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 * lpszStr [O] Destination string
511 * lpszSrc [I] Source string
512 * iLen [I] Maximum number of chars to copy
514 * RETURNS
515 * lpszStr.
517 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
519 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
521 lstrcpynW(lpszStr, lpszSrc, iLen);
522 return lpszStr;
527 /*************************************************************************
528 * SHLWAPI_StrStrHelperA
530 * Internal implementation of StrStrA/StrStrIA
532 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
533 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
535 size_t iLen;
537 if (!lpszStr || !lpszSearch || !*lpszSearch)
538 return NULL;
540 iLen = strlen(lpszSearch);
542 while (*lpszStr)
544 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
545 return (LPSTR)lpszStr;
546 lpszStr = CharNextA(lpszStr);
548 return NULL;
551 /*************************************************************************
552 * StrStrA [SHLWAPI.@]
554 * Find a substring within a string.
556 * PARAMS
557 * lpszStr [I] String to search in
558 * lpszSearch [I] String to look for
560 * RETURNS
561 * The start of lpszSearch within lpszStr, or NULL if not found.
563 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
565 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
567 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
570 /*************************************************************************
571 * StrStrW [SHLWAPI.@]
573 * See StrStrA.
575 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
577 if (!lpszStr || !lpszSearch) return NULL;
578 return strstrW( lpszStr, lpszSearch );
581 /*************************************************************************
582 * StrRStrIA [SHLWAPI.@]
584 * Find the last occurrence of a substring within a string.
586 * PARAMS
587 * lpszStr [I] String to search in
588 * lpszEnd [I] End of lpszStr
589 * lpszSearch [I] String to look for
591 * RETURNS
592 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
594 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
596 WORD ch1, ch2;
597 INT iLen;
599 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
601 if (!lpszStr || !lpszSearch || !*lpszSearch)
602 return NULL;
604 if (!lpszEnd)
605 lpszEnd = lpszStr + lstrlenA(lpszStr);
606 if (lpszEnd == lpszStr)
607 return NULL;
609 if (IsDBCSLeadByte(*lpszSearch))
610 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
611 else
612 ch1 = *lpszSearch;
613 iLen = lstrlenA(lpszSearch);
617 lpszEnd = CharPrevA(lpszStr, lpszEnd);
618 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
619 if (!ChrCmpIA(ch1, ch2))
621 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
622 return (LPSTR)lpszEnd;
624 } while (lpszEnd > lpszStr);
625 return NULL;
628 /*************************************************************************
629 * StrRStrIW [SHLWAPI.@]
631 * See StrRStrIA.
633 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
635 INT iLen;
637 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
639 if (!lpszStr || !lpszSearch || !*lpszSearch)
640 return NULL;
642 if (!lpszEnd)
643 lpszEnd = lpszStr + strlenW(lpszStr);
645 iLen = strlenW(lpszSearch);
647 while (lpszEnd > lpszStr)
649 lpszEnd--;
650 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
651 return (LPWSTR)lpszEnd;
653 return NULL;
656 /*************************************************************************
657 * StrStrIA [SHLWAPI.@]
659 * Find a substring within a string, ignoring case.
661 * PARAMS
662 * lpszStr [I] String to search in
663 * lpszSearch [I] String to look for
665 * RETURNS
666 * The start of lpszSearch within lpszStr, or NULL if not found.
668 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
670 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
672 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
675 /*************************************************************************
676 * StrStrIW [SHLWAPI.@]
678 * See StrStrIA.
680 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
682 int iLen;
684 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
686 if (!lpszStr || !lpszSearch || !*lpszSearch)
687 return NULL;
689 iLen = strlenW(lpszSearch);
691 while (*lpszStr)
693 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
694 return (LPWSTR)lpszStr;
695 lpszStr++;
697 return NULL;
700 /*************************************************************************
701 * StrToIntA [SHLWAPI.@]
703 * Read a signed integer from a string.
705 * PARAMS
706 * lpszStr [I] String to read integer from
708 * RETURNS
709 * The signed integer value represented by the string, or 0 if no integer is
710 * present.
712 * NOTES
713 * No leading space is allowed before the number, although a leading '-' is.
715 int WINAPI StrToIntA(LPCSTR lpszStr)
717 int iRet = 0;
719 TRACE("(%s)\n", debugstr_a(lpszStr));
721 if (!lpszStr)
723 WARN("Invalid lpszStr would crash under Win32!\n");
724 return 0;
727 if (*lpszStr == '-' || isdigit(*lpszStr))
728 StrToIntExA(lpszStr, 0, &iRet);
729 return iRet;
732 /*************************************************************************
733 * StrToIntW [SHLWAPI.@]
735 * See StrToIntA.
737 int WINAPI StrToIntW(LPCWSTR lpszStr)
739 int iRet = 0;
741 TRACE("(%s)\n", debugstr_w(lpszStr));
743 if (!lpszStr)
745 WARN("Invalid lpszStr would crash under Win32!\n");
746 return 0;
749 if (*lpszStr == '-' || isdigitW(*lpszStr))
750 StrToIntExW(lpszStr, 0, &iRet);
751 return iRet;
754 /*************************************************************************
755 * StrToIntExA [SHLWAPI.@]
757 * Read an integer from a string.
759 * PARAMS
760 * lpszStr [I] String to read integer from
761 * dwFlags [I] Flags controlling the conversion
762 * lpiRet [O] Destination for read integer.
764 * RETURNS
765 * Success: TRUE. lpiRet contains the integer value represented by the string.
766 * Failure: FALSE, if the string is invalid, or no number is present.
768 * NOTES
769 * Leading whitespace, '-' and '+' are allowed before the number. If
770 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
771 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
772 * the string is treated as a decimal string. A leading '-' is ignored for
773 * hexadecimal numbers.
775 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
777 BOOL bNegative = FALSE;
778 int iRet = 0;
780 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
782 if (!lpszStr || !lpiRet)
784 WARN("Invalid parameter would crash under Win32!\n");
785 return FALSE;
787 if (dwFlags > STIF_SUPPORT_HEX)
789 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
792 /* Skip leading space, '+', '-' */
793 while (isspace(*lpszStr))
794 lpszStr = CharNextA(lpszStr);
796 if (*lpszStr == '-')
798 bNegative = TRUE;
799 lpszStr++;
801 else if (*lpszStr == '+')
802 lpszStr++;
804 if (dwFlags & STIF_SUPPORT_HEX &&
805 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
807 /* Read hex number */
808 lpszStr += 2;
810 if (!isxdigit(*lpszStr))
811 return FALSE;
813 while (isxdigit(*lpszStr))
815 iRet = iRet * 16;
816 if (isdigit(*lpszStr))
817 iRet += (*lpszStr - '0');
818 else
819 iRet += 10 + (tolower(*lpszStr) - 'a');
820 lpszStr++;
822 *lpiRet = iRet;
823 return TRUE;
826 /* Read decimal number */
827 if (!isdigit(*lpszStr))
828 return FALSE;
830 while (isdigit(*lpszStr))
832 iRet = iRet * 10;
833 iRet += (*lpszStr - '0');
834 lpszStr++;
836 *lpiRet = bNegative ? -iRet : iRet;
837 return TRUE;
840 /*************************************************************************
841 * StrToIntExW [SHLWAPI.@]
843 * See StrToIntExA.
845 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
847 BOOL bNegative = FALSE;
848 int iRet = 0;
850 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
852 if (!lpszStr || !lpiRet)
854 WARN("Invalid parameter would crash under Win32!\n");
855 return FALSE;
857 if (dwFlags > STIF_SUPPORT_HEX)
859 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
862 /* Skip leading space, '+', '-' */
863 while (isspaceW(*lpszStr)) lpszStr++;
865 if (*lpszStr == '-')
867 bNegative = TRUE;
868 lpszStr++;
870 else if (*lpszStr == '+')
871 lpszStr++;
873 if (dwFlags & STIF_SUPPORT_HEX &&
874 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
876 /* Read hex number */
877 lpszStr += 2;
879 if (!isxdigitW(*lpszStr))
880 return FALSE;
882 while (isxdigitW(*lpszStr))
884 iRet = iRet * 16;
885 if (isdigitW(*lpszStr))
886 iRet += (*lpszStr - '0');
887 else
888 iRet += 10 + (tolowerW(*lpszStr) - 'a');
889 lpszStr++;
891 *lpiRet = iRet;
892 return TRUE;
895 /* Read decimal number */
896 if (!isdigitW(*lpszStr))
897 return FALSE;
899 while (isdigitW(*lpszStr))
901 iRet = iRet * 10;
902 iRet += (*lpszStr - '0');
903 lpszStr++;
905 *lpiRet = bNegative ? -iRet : iRet;
906 return TRUE;
909 /*************************************************************************
910 * StrDupA [SHLWAPI.@]
912 * Duplicate a string.
914 * PARAMS
915 * lpszStr [I] String to duplicate.
917 * RETURNS
918 * Success: A pointer to a new string containing the contents of lpszStr
919 * Failure: NULL, if memory cannot be allocated
921 * NOTES
922 * The string memory is allocated with LocalAlloc(), and so should be released
923 * by calling LocalFree().
925 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
927 int iLen;
928 LPSTR lpszRet;
930 TRACE("(%s)\n",debugstr_a(lpszStr));
932 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
933 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
935 if (lpszRet)
937 if (lpszStr)
938 memcpy(lpszRet, lpszStr, iLen);
939 else
940 *lpszRet = '\0';
942 return lpszRet;
945 /*************************************************************************
946 * StrDupW [SHLWAPI.@]
948 * See StrDupA.
950 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
952 int iLen;
953 LPWSTR lpszRet;
955 TRACE("(%s)\n",debugstr_w(lpszStr));
957 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
958 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
960 if (lpszRet)
962 if (lpszStr)
963 memcpy(lpszRet, lpszStr, iLen);
964 else
965 *lpszRet = '\0';
967 return lpszRet;
970 /*************************************************************************
971 * SHLWAPI_StrSpnHelperA
973 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
975 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
976 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
977 BOOL bInvert)
979 LPCSTR lpszRead = lpszStr;
980 if (lpszStr && *lpszStr && lpszMatch)
982 while (*lpszRead)
984 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
986 if (!bInvert && !lpszTest)
987 break;
988 if (bInvert && lpszTest)
989 break;
990 lpszRead = CharNextA(lpszRead);
993 return lpszRead - lpszStr;
996 /*************************************************************************
997 * StrSpnA [SHLWAPI.@]
999 * Find the length of the start of a string that contains only certain
1000 * characters.
1002 * PARAMS
1003 * lpszStr [I] String to search
1004 * lpszMatch [I] Characters that can be in the substring
1006 * RETURNS
1007 * The length of the part of lpszStr containing only chars from lpszMatch,
1008 * or 0 if any parameter is invalid.
1010 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1012 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1014 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1017 /*************************************************************************
1018 * StrSpnW [SHLWAPI.@]
1020 * See StrSpnA.
1022 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1024 if (!lpszStr || !lpszMatch) return 0;
1025 return strspnW( lpszStr, lpszMatch );
1028 /*************************************************************************
1029 * StrCSpnA [SHLWAPI.@]
1031 * Find the length of the start of a string that does not contain certain
1032 * characters.
1034 * PARAMS
1035 * lpszStr [I] String to search
1036 * lpszMatch [I] Characters that cannot be in the substring
1038 * RETURNS
1039 * The length of the part of lpszStr containing only chars not in lpszMatch,
1040 * or 0 if any parameter is invalid.
1042 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1044 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1046 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1049 /*************************************************************************
1050 * StrCSpnW [SHLWAPI.@]
1052 * See StrCSpnA.
1054 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1056 if (!lpszStr || !lpszMatch) return 0;
1057 return strcspnW( lpszStr, lpszMatch );
1060 /*************************************************************************
1061 * StrCSpnIA [SHLWAPI.@]
1063 * Find the length of the start of a string that does not contain certain
1064 * characters, ignoring case.
1066 * PARAMS
1067 * lpszStr [I] String to search
1068 * lpszMatch [I] Characters that cannot be in the substring
1070 * RETURNS
1071 * The length of the part of lpszStr containing only chars not in lpszMatch,
1072 * or 0 if any parameter is invalid.
1074 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1076 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1078 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1081 /*************************************************************************
1082 * StrCSpnIW [SHLWAPI.@]
1084 * See StrCSpnIA.
1086 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1088 LPCWSTR lpszRead = lpszStr;
1090 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1092 if (lpszStr && *lpszStr && lpszMatch)
1094 while (*lpszRead)
1096 if (StrChrIW(lpszMatch, *lpszRead)) break;
1097 lpszRead++;
1100 return lpszRead - lpszStr;
1103 /*************************************************************************
1104 * StrPBrkA [SHLWAPI.@]
1106 * Search a string for any of a group of characters.
1108 * PARAMS
1109 * lpszStr [I] String to search
1110 * lpszMatch [I] Characters to match
1112 * RETURNS
1113 * A pointer to the first matching character in lpszStr, or NULL if no
1114 * match was found.
1116 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1118 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1120 if (lpszStr && lpszMatch && *lpszMatch)
1122 while (*lpszStr)
1124 if (StrChrA(lpszMatch, *lpszStr))
1125 return (LPSTR)lpszStr;
1126 lpszStr = CharNextA(lpszStr);
1129 return NULL;
1132 /*************************************************************************
1133 * StrPBrkW [SHLWAPI.@]
1135 * See StrPBrkA.
1137 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1139 if (!lpszStr || !lpszMatch) return NULL;
1140 return strpbrkW( lpszStr, lpszMatch );
1143 /*************************************************************************
1144 * SHLWAPI_StrRChrHelperA
1146 * Internal implementation of StrRChrA/StrRChrIA.
1148 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1149 LPCSTR lpszEnd, WORD ch,
1150 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1152 LPCSTR lpszRet = NULL;
1154 if (lpszStr)
1156 WORD ch2;
1158 if (!lpszEnd)
1159 lpszEnd = lpszStr + lstrlenA(lpszStr);
1161 while (*lpszStr && lpszStr <= lpszEnd)
1163 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1165 if (!pChrCmpFn(ch, ch2))
1166 lpszRet = lpszStr;
1167 lpszStr = CharNextA(lpszStr);
1170 return (LPSTR)lpszRet;
1173 /**************************************************************************
1174 * StrRChrA [SHLWAPI.@]
1176 * Find the last occurrence of a character in string.
1178 * PARAMS
1179 * lpszStr [I] String to search in
1180 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1181 * ch [I] Character to search for.
1183 * RETURNS
1184 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1185 * or NULL if not found.
1186 * Failure: NULL, if any arguments are invalid.
1188 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1190 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1192 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1195 /**************************************************************************
1196 * StrRChrW [SHLWAPI.@]
1198 * See StrRChrA.
1200 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1202 WCHAR *ret = NULL;
1204 if (!str) return NULL;
1205 if (!end) end = str + strlenW(str);
1206 while (str < end)
1208 if (*str == ch) ret = (WCHAR *)str;
1209 str++;
1211 return ret;
1214 /**************************************************************************
1215 * StrRChrIA [SHLWAPI.@]
1217 * Find the last occurrence of a character in string, ignoring case.
1219 * PARAMS
1220 * lpszStr [I] String to search in
1221 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1222 * ch [I] Character to search for.
1224 * RETURNS
1225 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1226 * or NULL if not found.
1227 * Failure: NULL, if any arguments are invalid.
1229 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1231 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1233 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1236 /**************************************************************************
1237 * StrRChrIW [SHLWAPI.@]
1239 * See StrRChrIA.
1241 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1243 WCHAR *ret = NULL;
1245 if (!str) return NULL;
1246 if (!end) end = str + strlenW(str);
1247 while (str < end)
1249 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1250 str++;
1252 return ret;
1255 /*************************************************************************
1256 * StrCatBuffA [SHLWAPI.@]
1258 * Concatenate two strings together.
1260 * PARAMS
1261 * lpszStr [O] String to concatenate to
1262 * lpszCat [I] String to add to lpszCat
1263 * cchMax [I] Maximum number of characters for the whole string
1265 * RETURNS
1266 * lpszStr.
1268 * NOTES
1269 * cchMax determines the number of characters in the final length of the
1270 * string, not the number appended to lpszStr from lpszCat.
1272 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1274 INT iLen;
1276 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1278 if (!lpszStr)
1280 WARN("Invalid lpszStr would crash under Win32!\n");
1281 return NULL;
1284 iLen = strlen(lpszStr);
1285 cchMax -= iLen;
1287 if (cchMax > 0)
1288 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1289 return lpszStr;
1292 /*************************************************************************
1293 * StrCatBuffW [SHLWAPI.@]
1295 * See StrCatBuffA.
1297 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1299 INT iLen;
1301 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1303 if (!lpszStr)
1305 WARN("Invalid lpszStr would crash under Win32!\n");
1306 return NULL;
1309 iLen = strlenW(lpszStr);
1310 cchMax -= iLen;
1312 if (cchMax > 0)
1313 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1314 return lpszStr;
1317 /*************************************************************************
1318 * StrRetToBufA [SHLWAPI.@]
1320 * Convert a STRRET to a normal string.
1322 * PARAMS
1323 * lpStrRet [O] STRRET to convert
1324 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1325 * lpszDest [O] Destination for normal string
1326 * dwLen [I] Length of lpszDest
1328 * RETURNS
1329 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1330 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1331 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1332 * Failure: E_FAIL, if any parameters are invalid.
1334 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1336 /* NOTE:
1337 * This routine is identical to that in dlls/shell32/shellstring.c.
1338 * It was duplicated because not every version of Shlwapi.dll exports
1339 * StrRetToBufA. If you change one routine, change them both.
1341 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1343 if (!src)
1345 WARN("Invalid lpStrRet would crash under Win32!\n");
1346 if (dest)
1347 *dest = '\0';
1348 return E_FAIL;
1351 if (!dest || !len)
1352 return E_FAIL;
1354 *dest = '\0';
1356 switch (src->uType)
1358 case STRRET_WSTR:
1359 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1360 CoTaskMemFree(src->u.pOleStr);
1361 break;
1363 case STRRET_CSTR:
1364 lstrcpynA(dest, src->u.cStr, len);
1365 break;
1367 case STRRET_OFFSET:
1368 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1369 break;
1371 default:
1372 FIXME("unknown type!\n");
1373 return FALSE;
1375 return S_OK;
1378 /*************************************************************************
1379 * StrRetToBufW [SHLWAPI.@]
1381 * See StrRetToBufA.
1383 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1385 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1387 if (!src)
1389 WARN("Invalid lpStrRet would crash under Win32!\n");
1390 if (dest)
1391 *dest = '\0';
1392 return E_FAIL;
1395 if (!dest || !len)
1396 return E_FAIL;
1398 *dest = '\0';
1400 switch (src->uType)
1402 case STRRET_WSTR:
1403 lstrcpynW(dest, src->u.pOleStr, len);
1404 CoTaskMemFree(src->u.pOleStr);
1405 break;
1407 case STRRET_CSTR:
1408 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1409 dest[len-1] = 0;
1410 break;
1412 case STRRET_OFFSET:
1413 if (pidl)
1415 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1416 dest, len ) && len)
1417 dest[len-1] = 0;
1419 break;
1421 default:
1422 FIXME("unknown type!\n");
1423 return FALSE;
1425 return S_OK;
1428 /*************************************************************************
1429 * StrRetToStrA [SHLWAPI.@]
1431 * Converts a STRRET to a normal string.
1433 * PARAMS
1434 * lpStrRet [O] STRRET to convert
1435 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1436 * ppszName [O] Destination for converted string
1438 * RETURNS
1439 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1440 * Failure: E_FAIL, if any parameters are invalid.
1442 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1444 HRESULT hRet = E_FAIL;
1446 switch (lpStrRet->uType)
1448 case STRRET_WSTR:
1449 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1450 CoTaskMemFree(lpStrRet->u.pOleStr);
1451 break;
1453 case STRRET_CSTR:
1454 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1455 break;
1457 case STRRET_OFFSET:
1458 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1459 break;
1461 default:
1462 *ppszName = NULL;
1465 return hRet;
1468 /*************************************************************************
1469 * StrRetToStrW [SHLWAPI.@]
1471 * See StrRetToStrA.
1473 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1475 HRESULT hRet = E_FAIL;
1477 switch (lpStrRet->uType)
1479 case STRRET_WSTR:
1480 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1481 CoTaskMemFree(lpStrRet->u.pOleStr);
1482 break;
1484 case STRRET_CSTR:
1485 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1486 break;
1488 case STRRET_OFFSET:
1489 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1490 break;
1492 default:
1493 *ppszName = NULL;
1496 return hRet;
1499 /* Create an ASCII string copy using SysAllocString() */
1500 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1502 *pBstrOut = NULL;
1504 if (src)
1506 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1507 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1509 if (szTemp)
1511 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1512 *pBstrOut = SysAllocString(szTemp);
1513 HeapFree(GetProcessHeap(), 0, szTemp);
1515 if (*pBstrOut)
1516 return S_OK;
1519 return E_OUTOFMEMORY;
1522 /*************************************************************************
1523 * StrRetToBSTR [SHLWAPI.@]
1525 * Converts a STRRET to a BSTR.
1527 * PARAMS
1528 * lpStrRet [O] STRRET to convert
1529 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1530 * pBstrOut [O] Destination for converted BSTR
1532 * RETURNS
1533 * Success: S_OK. pBstrOut contains the new string.
1534 * Failure: E_FAIL, if any parameters are invalid.
1536 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1538 HRESULT hRet = E_FAIL;
1540 switch (lpStrRet->uType)
1542 case STRRET_WSTR:
1543 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1544 if (*pBstrOut)
1545 hRet = S_OK;
1546 CoTaskMemFree(lpStrRet->u.pOleStr);
1547 break;
1549 case STRRET_CSTR:
1550 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1551 break;
1553 case STRRET_OFFSET:
1554 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1555 break;
1557 default:
1558 *pBstrOut = NULL;
1561 return hRet;
1564 /*************************************************************************
1565 * StrFormatKBSizeA [SHLWAPI.@]
1567 * Create a formatted string containing a byte count in Kilobytes.
1569 * PARAMS
1570 * llBytes [I] Byte size to format
1571 * lpszDest [I] Destination for formatted string
1572 * cchMax [I] Size of lpszDest
1574 * RETURNS
1575 * lpszDest.
1577 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1579 WCHAR wszBuf[256];
1581 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1582 return NULL;
1583 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1584 return NULL;
1585 return lpszDest;
1588 /*************************************************************************
1589 * StrFormatKBSizeW [SHLWAPI.@]
1591 * See StrFormatKBSizeA.
1593 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1595 static const WCHAR kb[] = {' ','K','B',0};
1596 LONGLONG llKB = (llBytes + 1023) >> 10;
1597 int len;
1599 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1601 if (!FormatInt(llKB, lpszDest, cchMax))
1602 return NULL;
1604 len = lstrlenW(lpszDest);
1605 if (cchMax - len < 4)
1606 return NULL;
1607 lstrcatW(lpszDest, kb);
1608 return lpszDest;
1611 /*************************************************************************
1612 * StrNCatA [SHLWAPI.@]
1614 * Concatenate two strings together.
1616 * PARAMS
1617 * lpszStr [O] String to concatenate to
1618 * lpszCat [I] String to add to lpszCat
1619 * cchMax [I] Maximum number of characters to concatenate
1621 * RETURNS
1622 * lpszStr.
1624 * NOTES
1625 * cchMax determines the number of characters that are appended to lpszStr,
1626 * not the total length of the string.
1628 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1630 LPSTR lpszRet = lpszStr;
1632 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1634 if (!lpszStr)
1636 WARN("Invalid lpszStr would crash under Win32!\n");
1637 return NULL;
1640 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1641 return lpszRet;
1644 /*************************************************************************
1645 * StrNCatW [SHLWAPI.@]
1647 * See StrNCatA.
1649 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1651 LPWSTR lpszRet = lpszStr;
1653 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1655 if (!lpszStr)
1657 WARN("Invalid lpszStr would crash under Win32\n");
1658 return NULL;
1661 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1662 return lpszRet;
1665 /*************************************************************************
1666 * StrTrimA [SHLWAPI.@]
1668 * Remove characters from the start and end of a string.
1670 * PARAMS
1671 * lpszStr [O] String to remove characters from
1672 * lpszTrim [I] Characters to remove from lpszStr
1674 * RETURNS
1675 * TRUE If lpszStr was valid and modified
1676 * FALSE Otherwise
1678 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1680 DWORD dwLen;
1681 LPSTR lpszRead = lpszStr;
1682 BOOL bRet = FALSE;
1684 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1686 if (lpszRead && *lpszRead)
1688 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1689 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1691 dwLen = strlen(lpszRead);
1693 if (lpszRead != lpszStr)
1695 memmove(lpszStr, lpszRead, dwLen + 1);
1696 bRet = TRUE;
1698 if (dwLen > 0)
1700 lpszRead = lpszStr + dwLen;
1701 while (StrChrA(lpszTrim, lpszRead[-1]))
1702 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1704 if (lpszRead != lpszStr + dwLen)
1706 *lpszRead = '\0';
1707 bRet = TRUE;
1711 return bRet;
1714 /*************************************************************************
1715 * StrTrimW [SHLWAPI.@]
1717 * See StrTrimA.
1719 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1721 DWORD dwLen;
1722 LPWSTR lpszRead = lpszStr;
1723 BOOL bRet = FALSE;
1725 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1727 if (lpszRead && *lpszRead)
1729 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1731 dwLen = strlenW(lpszRead);
1733 if (lpszRead != lpszStr)
1735 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1736 bRet = TRUE;
1738 if (dwLen > 0)
1740 lpszRead = lpszStr + dwLen;
1741 while (StrChrW(lpszTrim, lpszRead[-1]))
1742 lpszRead--; /* Skip trailing matches */
1744 if (lpszRead != lpszStr + dwLen)
1746 *lpszRead = '\0';
1747 bRet = TRUE;
1751 return bRet;
1754 /*************************************************************************
1755 * _SHStrDupAA [INTERNAL]
1757 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1759 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1761 HRESULT hr;
1762 int len = 0;
1764 if (src) {
1765 len = lstrlenA(src) + 1;
1766 *dest = CoTaskMemAlloc(len);
1767 } else {
1768 *dest = NULL;
1771 if (*dest) {
1772 lstrcpynA(*dest,src, len);
1773 hr = S_OK;
1774 } else {
1775 hr = E_OUTOFMEMORY;
1778 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1779 return hr;
1782 /*************************************************************************
1783 * SHStrDupA [SHLWAPI.@]
1785 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1787 * PARAMS
1788 * lpszStr [I] String to copy
1789 * lppszDest [O] Destination for the new string copy
1791 * RETURNS
1792 * Success: S_OK. lppszDest contains the new string in Unicode format.
1793 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1794 * fails.
1796 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1798 HRESULT hRet;
1799 int len = 0;
1801 if (lpszStr)
1803 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1804 *lppszDest = CoTaskMemAlloc(len);
1806 else
1807 *lppszDest = NULL;
1809 if (*lppszDest)
1811 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1812 hRet = S_OK;
1814 else
1815 hRet = E_OUTOFMEMORY;
1817 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1818 return hRet;
1821 /*************************************************************************
1822 * _SHStrDupAW [INTERNAL]
1824 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1826 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1828 HRESULT hr;
1829 int len = 0;
1831 if (src) {
1832 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1833 *dest = CoTaskMemAlloc(len);
1834 } else {
1835 *dest = NULL;
1838 if (*dest) {
1839 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1840 hr = S_OK;
1841 } else {
1842 hr = E_OUTOFMEMORY;
1845 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1846 return hr;
1849 /*************************************************************************
1850 * SHStrDupW [SHLWAPI.@]
1852 * See SHStrDupA.
1854 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1856 HRESULT hr;
1857 int len = 0;
1859 if (src) {
1860 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1861 *dest = CoTaskMemAlloc(len);
1862 } else {
1863 *dest = NULL;
1866 if (*dest) {
1867 memcpy(*dest, src, len);
1868 hr = S_OK;
1869 } else {
1870 hr = E_OUTOFMEMORY;
1873 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1874 return hr;
1877 /*************************************************************************
1878 * SHLWAPI_WriteReverseNum
1880 * Internal helper for SHLWAPI_WriteTimeClass.
1882 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1884 *lpszOut-- = '\0';
1886 /* Write a decimal number to a string, backwards */
1889 DWORD dwNextDigit = dwNum % 10;
1890 *lpszOut-- = '0' + dwNextDigit;
1891 dwNum = (dwNum - dwNextDigit) / 10;
1892 } while (dwNum > 0);
1894 return lpszOut;
1897 /*************************************************************************
1898 * SHLWAPI_FormatSignificant
1900 * Internal helper for SHLWAPI_WriteTimeClass.
1902 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1904 /* Zero non significant digits, return remaining significant digits */
1905 while (*lpszNum)
1907 lpszNum++;
1908 if (--dwDigits == 0)
1910 while (*lpszNum)
1911 *lpszNum++ = '0';
1912 return 0;
1915 return dwDigits;
1918 /*************************************************************************
1919 * SHLWAPI_WriteTimeClass
1921 * Internal helper for StrFromTimeIntervalW.
1923 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1924 UINT uClassStringId, int iDigits)
1926 WCHAR szBuff[64], *szOut = szBuff + 32;
1928 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1929 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1930 *szOut = ' ';
1931 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
1932 strcatW(lpszOut, szOut);
1933 return iDigits;
1936 /*************************************************************************
1937 * StrFromTimeIntervalA [SHLWAPI.@]
1939 * Format a millisecond time interval into a string
1941 * PARAMS
1942 * lpszStr [O] Output buffer for formatted time interval
1943 * cchMax [I] Size of lpszStr
1944 * dwMS [I] Number of milliseconds
1945 * iDigits [I] Number of digits to print
1947 * RETURNS
1948 * The length of the formatted string, or 0 if any parameter is invalid.
1950 * NOTES
1951 * This implementation mimics the Win32 behaviour of always writing a leading
1952 * space before the time interval begins.
1954 * iDigits is used to provide approximate times if accuracy is not important.
1955 * This number of digits will be written of the first non-zero time class
1956 * (hours/minutes/seconds). If this does not complete the time classification,
1957 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1958 * If there are digits remaining following the writing of a time class, the
1959 * next time class will be written.
1961 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1962 * following will result from the given values of iDigits:
1964 *| iDigits 1 2 3 4 5 ...
1965 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1967 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1968 int iDigits)
1970 INT iRet = 0;
1972 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1974 if (lpszStr && cchMax)
1976 WCHAR szBuff[128];
1977 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1978 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1980 return iRet;
1984 /*************************************************************************
1985 * StrFromTimeIntervalW [SHLWAPI.@]
1987 * See StrFromTimeIntervalA.
1989 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1990 int iDigits)
1992 INT iRet = 0;
1994 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1996 if (lpszStr && cchMax)
1998 WCHAR szCopy[128];
1999 DWORD dwHours, dwMinutes;
2001 if (!iDigits || cchMax == 1)
2003 *lpszStr = '\0';
2004 return 0;
2007 /* Calculate the time classes */
2008 dwMS = (dwMS + 500) / 1000;
2009 dwHours = dwMS / 3600;
2010 dwMS -= dwHours * 3600;
2011 dwMinutes = dwMS / 60;
2012 dwMS -= dwMinutes * 60;
2014 szCopy[0] = '\0';
2016 if (dwHours)
2017 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2019 if (dwMinutes && iDigits)
2020 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2022 if (iDigits) /* Always write seconds if we have significant digits */
2023 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2025 lstrcpynW(lpszStr, szCopy, cchMax);
2026 iRet = strlenW(lpszStr);
2028 return iRet;
2031 /*************************************************************************
2032 * StrIsIntlEqualA [SHLWAPI.@]
2034 * Compare two strings.
2036 * PARAMS
2037 * bCase [I] Whether to compare case sensitively
2038 * lpszStr [I] First string to compare
2039 * lpszComp [I] Second string to compare
2040 * iLen [I] Length to compare
2042 * RETURNS
2043 * TRUE If the strings are equal.
2044 * FALSE Otherwise.
2046 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2047 int iLen)
2049 DWORD dwFlags;
2051 TRACE("(%d,%s,%s,%d)\n", bCase,
2052 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2054 /* FIXME: This flag is undocumented and unknown by our CompareString.
2055 * We need a define for it.
2057 dwFlags = 0x10000000;
2058 if (!bCase) dwFlags |= NORM_IGNORECASE;
2060 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2063 /*************************************************************************
2064 * StrIsIntlEqualW [SHLWAPI.@]
2066 * See StrIsIntlEqualA.
2068 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2069 int iLen)
2071 DWORD dwFlags;
2073 TRACE("(%d,%s,%s,%d)\n", bCase,
2074 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2076 /* FIXME: This flag is undocumented and unknown by our CompareString.
2077 * We need a define for it.
2079 dwFlags = 0x10000000;
2080 if (!bCase) dwFlags |= NORM_IGNORECASE;
2082 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2085 /*************************************************************************
2086 * @ [SHLWAPI.399]
2088 * Copy a string to another string, up to a maximum number of characters.
2090 * PARAMS
2091 * lpszDest [O] Destination string
2092 * lpszSrc [I] Source string
2093 * iLen [I] Maximum number of chars to copy
2095 * RETURNS
2096 * Success: A pointer to the last character written to lpszDest.
2097 * Failure: lpszDest, if any arguments are invalid.
2099 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2101 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2103 if (lpszDest && lpszSrc && iLen > 0)
2105 while ((iLen-- > 1) && *lpszSrc)
2106 *lpszDest++ = *lpszSrc++;
2107 if (iLen >= 0)
2108 *lpszDest = '\0';
2110 return lpszDest;
2113 /*************************************************************************
2114 * @ [SHLWAPI.400]
2116 * Unicode version of StrCpyNXA.
2118 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2120 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2122 if (lpszDest && lpszSrc && iLen > 0)
2124 while ((iLen-- > 1) && *lpszSrc)
2125 *lpszDest++ = *lpszSrc++;
2126 if (iLen >= 0)
2127 *lpszDest = '\0';
2129 return lpszDest;
2132 /*************************************************************************
2133 * StrCmpLogicalW [SHLWAPI.@]
2135 * Compare two strings, ignoring case and comparing digits as numbers.
2137 * PARAMS
2138 * lpszStr [I] First string to compare
2139 * lpszComp [I] Second string to compare
2140 * iLen [I] Length to compare
2142 * RETURNS
2143 * TRUE If the strings are equal.
2144 * FALSE Otherwise.
2146 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2148 INT iDiff;
2150 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2152 if (lpszStr && lpszComp)
2154 while (*lpszStr)
2156 if (!*lpszComp)
2157 return 1;
2158 else if (isdigitW(*lpszStr))
2160 int iStr, iComp;
2162 if (!isdigitW(*lpszComp))
2163 return -1;
2165 /* Compare the numbers */
2166 StrToIntExW(lpszStr, 0, &iStr);
2167 StrToIntExW(lpszComp, 0, &iComp);
2169 if (iStr < iComp)
2170 return -1;
2171 else if (iStr > iComp)
2172 return 1;
2174 /* Skip */
2175 while (isdigitW(*lpszStr))
2176 lpszStr++;
2177 while (isdigitW(*lpszComp))
2178 lpszComp++;
2180 else if (isdigitW(*lpszComp))
2181 return 1;
2182 else
2184 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2185 if (iDiff > 0)
2186 return 1;
2187 else if (iDiff < 0)
2188 return -1;
2190 lpszStr++;
2191 lpszComp++;
2194 if (*lpszComp)
2195 return -1;
2197 return 0;
2200 /* Structure for formatting byte strings */
2201 typedef struct tagSHLWAPI_BYTEFORMATS
2203 LONGLONG dLimit;
2204 double dDivisor;
2205 double dNormaliser;
2206 int nDecimals;
2207 WCHAR wPrefix;
2208 } SHLWAPI_BYTEFORMATS;
2210 /*************************************************************************
2211 * StrFormatByteSizeW [SHLWAPI.@]
2213 * Create a string containing an abbreviated byte count of up to 2^63-1.
2215 * PARAMS
2216 * llBytes [I] Byte size to format
2217 * lpszDest [I] Destination for formatted string
2218 * cchMax [I] Size of lpszDest
2220 * RETURNS
2221 * lpszDest.
2223 * NOTES
2224 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2226 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2228 #define KB ((ULONGLONG)1024)
2229 #define MB (KB*KB)
2230 #define GB (KB*KB*KB)
2231 #define TB (KB*KB*KB*KB)
2232 #define PB (KB*KB*KB*KB*KB)
2234 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2236 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2237 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2238 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2239 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2240 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2241 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2242 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2243 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2244 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2245 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2246 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2247 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2248 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2249 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2250 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2251 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2253 WCHAR wszAdd[] = {' ','?','B',0};
2254 double dBytes;
2255 UINT i = 0;
2257 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2259 if (!lpszDest || !cchMax)
2260 return lpszDest;
2262 if (llBytes < 1024) /* 1K */
2264 WCHAR wszBytesFormat[64];
2265 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2266 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2267 return lpszDest;
2270 /* Note that if this loop completes without finding a match, i will be
2271 * pointing at the last entry, which is a catch all for > 1000 PB
2273 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2275 if (llBytes < bfFormats[i].dLimit)
2276 break;
2277 i++;
2279 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2280 * this number we integer shift down by 1 MB first. The table above has
2281 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2282 * for this. We also add a small fudge factor to get the correct result for
2283 * counts that lie exactly on a 1024 byte boundary.
2285 if (i > 8)
2286 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2287 else
2288 dBytes = (double)llBytes + 0.00001;
2290 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2292 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2293 return NULL;
2294 wszAdd[1] = bfFormats[i].wPrefix;
2295 StrCatBuffW(lpszDest, wszAdd, cchMax);
2296 return lpszDest;
2299 /*************************************************************************
2300 * StrFormatByteSize64A [SHLWAPI.@]
2302 * See StrFormatByteSizeW.
2304 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2306 WCHAR wszBuff[32];
2308 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2310 if (lpszDest)
2311 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2312 return lpszDest;
2315 /*************************************************************************
2316 * StrFormatByteSizeA [SHLWAPI.@]
2318 * Create a string containing an abbreviated byte count of up to 2^31-1.
2320 * PARAMS
2321 * dwBytes [I] Byte size to format
2322 * lpszDest [I] Destination for formatted string
2323 * cchMax [I] Size of lpszDest
2325 * RETURNS
2326 * lpszDest.
2328 * NOTES
2329 * The Ascii and Unicode versions of this function accept a different
2330 * integer type for dwBytes. See StrFormatByteSize64A().
2332 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2334 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2336 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2339 /*************************************************************************
2340 * @ [SHLWAPI.162]
2342 * Remove a hanging lead byte from the end of a string, if present.
2344 * PARAMS
2345 * lpStr [I] String to check for a hanging lead byte
2346 * size [I] Length of lpStr
2348 * RETURNS
2349 * Success: The new length of the string. Any hanging lead bytes are removed.
2350 * Failure: 0, if any parameters are invalid.
2352 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2354 if (lpStr && size)
2356 LPSTR lastByte = lpStr + size - 1;
2358 while(lpStr < lastByte)
2359 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2361 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2363 *lpStr = '\0';
2364 size--;
2366 return size;
2368 return 0;
2371 /*************************************************************************
2372 * @ [SHLWAPI.203]
2374 * Remove a single non-trailing ampersand ('&') from a string.
2376 * PARAMS
2377 * lpszStr [I/O] String to remove ampersand from.
2379 * RETURNS
2380 * The character after the first ampersand in lpszStr, or the first character
2381 * in lpszStr if there is no ampersand in the string.
2383 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2385 LPSTR lpszIter, lpszTmp;
2386 char ch;
2388 TRACE("(%s)\n", debugstr_a(lpszStr));
2390 ch = *lpszStr;
2392 if ((lpszIter = StrChrA(lpszStr, '&')))
2394 lpszTmp = CharNextA(lpszIter);
2395 if (lpszTmp && *lpszTmp)
2397 if (*lpszTmp != '&')
2398 ch = *lpszTmp;
2400 while (lpszIter && *lpszIter)
2402 lpszTmp = CharNextA(lpszIter);
2403 *lpszIter = *lpszTmp;
2404 lpszIter = lpszTmp;
2409 return ch;
2412 /*************************************************************************
2413 * @ [SHLWAPI.225]
2415 * Unicode version of SHStripMneumonicA.
2417 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2419 LPWSTR lpszIter, lpszTmp;
2420 WCHAR ch;
2422 TRACE("(%s)\n", debugstr_w(lpszStr));
2424 ch = *lpszStr;
2426 if ((lpszIter = StrChrW(lpszStr, '&')))
2428 lpszTmp = lpszIter + 1;
2429 if (lpszTmp && *lpszTmp)
2431 if (*lpszTmp != '&')
2432 ch = *lpszTmp;
2434 while (lpszIter && *lpszIter)
2436 lpszTmp = lpszIter + 1;
2437 *lpszIter = *lpszTmp;
2438 lpszIter = lpszTmp;
2443 return ch;
2446 /*************************************************************************
2447 * @ [SHLWAPI.216]
2449 * Convert an Ascii string to Unicode.
2451 * PARAMS
2452 * dwCp [I] Code page for the conversion
2453 * lpSrcStr [I] Source Ascii string to convert
2454 * lpDstStr [O] Destination for converted Unicode string
2455 * iLen [I] Length of lpDstStr
2457 * RETURNS
2458 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2460 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2462 DWORD dwRet;
2464 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2465 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2466 return dwRet;
2469 /*************************************************************************
2470 * @ [SHLWAPI.215]
2472 * Convert an Ascii string to Unicode.
2474 * PARAMS
2475 * lpSrcStr [I] Source Ascii string to convert
2476 * lpDstStr [O] Destination for converted Unicode string
2477 * iLen [I] Length of lpDstStr
2479 * RETURNS
2480 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2482 * NOTES
2483 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2485 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2487 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2490 /*************************************************************************
2491 * @ [SHLWAPI.218]
2493 * Convert a Unicode string to Ascii.
2495 * PARAMS
2496 * CodePage [I] Code page to use for the conversion
2497 * lpSrcStr [I] Source Unicode string to convert
2498 * lpDstStr [O] Destination for converted Ascii string
2499 * dstlen [I] Length of buffer at lpDstStr
2501 * RETURNS
2502 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2503 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2504 * the result is not nul-terminated.
2505 * When using a different codepage, the length in bytes of the truncated
2506 * result at lpDstStr (including the terminator) is returned and
2507 * lpDstStr is always nul-terminated.
2510 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2512 static const WCHAR emptyW[] = { '\0' };
2513 int len , reqLen;
2514 LPSTR mem;
2516 if (!lpDstStr || !dstlen)
2517 return 0;
2519 if (!lpSrcStr)
2520 lpSrcStr = emptyW;
2522 *lpDstStr = '\0';
2524 len = strlenW(lpSrcStr) + 1;
2526 switch (CodePage)
2528 case CP_WINUNICODE:
2529 CodePage = CP_UTF8; /* Fall through... */
2530 case 0x0000C350: /* FIXME: CP_ #define */
2531 case CP_UTF7:
2532 case CP_UTF8:
2534 DWORD dwMode = 0;
2535 INT lenW = len - 1;
2536 INT needed = dstlen - 1;
2537 HRESULT hr;
2539 /* try the user supplied buffer first */
2540 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2541 if (hr == S_OK)
2543 lpDstStr[needed] = '\0';
2544 return needed + 1;
2547 /* user buffer too small. exclude termination and copy as much as possible */
2548 lenW = len;
2549 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2550 needed++;
2551 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2552 if (!mem)
2553 return 0;
2555 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2556 if (hr == S_OK)
2558 reqLen = SHTruncateString(mem, dstlen);
2559 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2561 HeapFree(GetProcessHeap(), 0, mem);
2562 return 0;
2564 default:
2565 break;
2568 /* try the user supplied buffer first */
2569 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2571 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2573 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2574 if (reqLen)
2576 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2577 if (mem)
2579 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2580 reqLen, NULL, NULL);
2582 reqLen = SHTruncateString(mem, dstlen -1);
2583 reqLen++;
2585 lstrcpynA(lpDstStr, mem, reqLen);
2586 HeapFree(GetProcessHeap(), 0, mem);
2587 lpDstStr[reqLen-1] = '\0';
2591 return reqLen;
2594 /*************************************************************************
2595 * @ [SHLWAPI.217]
2597 * Convert a Unicode string to Ascii.
2599 * PARAMS
2600 * lpSrcStr [I] Source Unicode string to convert
2601 * lpDstStr [O] Destination for converted Ascii string
2602 * iLen [O] Length of lpDstStr in characters
2604 * RETURNS
2605 * See SHUnicodeToAnsiCP
2607 * NOTES
2608 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2610 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2612 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2615 /*************************************************************************
2616 * @ [SHLWAPI.345]
2618 * Copy one string to another.
2620 * PARAMS
2621 * lpszSrc [I] Source string to copy
2622 * lpszDst [O] Destination for copy
2623 * iLen [I] Length of lpszDst in characters
2625 * RETURNS
2626 * The length of the copied string, including the terminating NUL. lpszDst
2627 * contains iLen characters of lpszSrc.
2629 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2631 LPSTR lpszRet;
2633 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2635 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2636 return lpszRet - lpszDst + 1;
2639 /*************************************************************************
2640 * @ [SHLWAPI.346]
2642 * Unicode version of SSHAnsiToAnsi.
2644 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2646 LPWSTR lpszRet;
2648 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2650 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2651 return lpszRet - lpszDst + 1;
2654 /*************************************************************************
2655 * @ [SHLWAPI.364]
2657 * Determine if an Ascii string converts to Unicode and back identically.
2659 * PARAMS
2660 * lpSrcStr [I] Source Unicode string to convert
2661 * lpDst [O] Destination for resulting Ascii string
2662 * iLen [I] Length of lpDst in characters
2664 * RETURNS
2665 * TRUE, since Ascii strings always convert identically.
2667 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2669 lstrcpynA(lpDst, lpSrcStr, iLen);
2670 return TRUE;
2673 /*************************************************************************
2674 * @ [SHLWAPI.365]
2676 * Determine if a Unicode string converts to Ascii and back identically.
2678 * PARAMS
2679 * lpSrcStr [I] Source Unicode string to convert
2680 * lpDst [O] Destination for resulting Ascii string
2681 * iLen [I] Length of lpDst in characters
2683 * RETURNS
2684 * TRUE, if lpSrcStr converts to Ascii and back identically,
2685 * FALSE otherwise.
2687 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2689 WCHAR szBuff[MAX_PATH];
2691 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2692 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2693 return !strcmpW(lpSrcStr, szBuff);
2696 /*************************************************************************
2697 * SHLoadIndirectString [SHLWAPI.@]
2699 * If passed a string that begins with '@', extract the string from the
2700 * appropriate resource, otherwise do a straight copy.
2703 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2705 WCHAR *dllname = NULL;
2706 HMODULE hmod = NULL;
2707 HRESULT hr = E_FAIL;
2709 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2711 if(src[0] == '@')
2713 WCHAR *index_str;
2714 int index;
2716 dst[0] = 0;
2717 dllname = StrDupW(src + 1);
2718 index_str = strchrW(dllname, ',');
2720 if(!index_str) goto end;
2722 *index_str = 0;
2723 index_str++;
2724 index = atoiW(index_str);
2726 hmod = LoadLibraryW(dllname);
2727 if(!hmod) goto end;
2729 if(index < 0)
2731 if(LoadStringW(hmod, -index, dst, dst_len))
2732 hr = S_OK;
2734 else
2735 FIXME("can't handle non-negative indices (%d)\n", index);
2737 else
2739 if(dst != src)
2740 lstrcpynW(dst, src, dst_len);
2741 hr = S_OK;
2744 TRACE("returning %s\n", debugstr_w(dst));
2745 end:
2746 if(hmod) FreeLibrary(hmod);
2747 HeapFree(GetProcessHeap(), 0, dllname);
2748 return hr;