mfplat: Add MFCreateAMMediaTypeFromMFMediaType stub.
[wine.git] / dlls / shlwapi / string.c
blob37d4d526fb6f3911b1fc0e328d36bb31c23133ee
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 <math.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #define NO_SHLWAPI_REG
30 #define NO_SHLWAPI_STREAM
31 #include "shlwapi.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "shlobj.h"
35 #include "mlang.h"
36 #include "ddeml.h"
37 #include "wine/debug.h"
39 #include "resource.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(shell);
43 extern HINSTANCE shlwapi_hInstance;
45 static HRESULT _SHStrDupAA(LPCSTR,LPSTR*);
46 static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*);
48 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size);
50 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
51 LPWSTR thousand_buffer, int thousand_bufwlen)
53 WCHAR grouping[64];
54 WCHAR *c;
56 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
57 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->NegativeOrder, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
58 fmt->NumDigits = 0;
59 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
60 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
61 fmt->lpThousandSep = thousand_buffer;
62 fmt->lpDecimalSep = decimal_buffer;
64 /*
65 * Converting grouping string to number as described on
66 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
68 fmt->Grouping = 0;
69 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, ARRAY_SIZE(grouping));
70 for (c = grouping; *c; c++)
71 if (*c >= '0' && *c < '9')
73 fmt->Grouping *= 10;
74 fmt->Grouping += *c - '0';
77 if (fmt->Grouping % 10 == 0)
78 fmt->Grouping /= 10;
79 else
80 fmt->Grouping *= 10;
83 /*************************************************************************
84 * FormatInt [internal]
86 * Format an integer according to the current locale
88 * RETURNS
89 * The number of characters written on success or 0 on failure
91 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
93 NUMBERFMTW fmt;
94 WCHAR decimal[8], thousand[8];
95 WCHAR buf[24];
96 WCHAR *c;
97 BOOL neg = (qdwValue < 0);
99 FillNumberFmt(&fmt, decimal, ARRAY_SIZE(decimal), thousand, ARRAY_SIZE(thousand));
101 c = &buf[24];
102 *(--c) = 0;
105 *(--c) = '0' + (qdwValue%10);
106 qdwValue /= 10;
107 } while (qdwValue > 0);
108 if (neg)
109 *(--c) = '-';
111 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
114 /*************************************************************************
115 * FormatDouble [internal]
117 * Format an integer according to the current locale. Prints the specified number of digits
118 * after the decimal point
120 * RETURNS
121 * The number of characters written on success or 0 on failure
123 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
125 static const WCHAR flfmt[] = {'%','f',0};
126 WCHAR buf[64];
127 NUMBERFMTW fmt;
128 WCHAR decimal[8], thousand[8];
130 swprintf(buf, 64, flfmt, value);
132 FillNumberFmt(&fmt, decimal, ARRAY_SIZE(decimal), thousand, ARRAY_SIZE(thousand));
133 fmt.NumDigits = decimals;
134 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
137 /*************************************************************************
138 * StrCatW [SHLWAPI.@]
140 * Concatenate two strings.
142 * PARAMS
143 * lpszStr [O] Initial string
144 * lpszSrc [I] String to concatenate
146 * RETURNS
147 * lpszStr.
149 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
151 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
153 if (lpszStr && lpszSrc)
154 lstrcatW(lpszStr, lpszSrc);
155 return lpszStr;
158 /*************************************************************************
159 * StrCpyW [SHLWAPI.@]
161 * Copy a string to another string.
163 * PARAMS
164 * lpszStr [O] Destination string
165 * lpszSrc [I] Source string
167 * RETURNS
168 * lpszStr.
170 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
172 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
174 if (lpszStr && lpszSrc)
175 lstrcpyW(lpszStr, lpszSrc);
176 return lpszStr;
179 /*************************************************************************
180 * StrRetToBufA [SHLWAPI.@]
182 * Convert a STRRET to a normal string.
184 * PARAMS
185 * lpStrRet [O] STRRET to convert
186 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
187 * lpszDest [O] Destination for normal string
188 * dwLen [I] Length of lpszDest
190 * RETURNS
191 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
192 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
193 * CoTaskMemFree() and its type set to STRRET_CSTRA.
194 * Failure: E_FAIL, if any parameters are invalid.
196 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
198 /* NOTE:
199 * This routine is identical to that in dlls/shell32/shellstring.c.
200 * It was duplicated because not every version of Shlwapi.dll exports
201 * StrRetToBufA. If you change one routine, change them both.
203 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
205 if (!src)
207 WARN("Invalid lpStrRet would crash under Win32!\n");
208 if (dest)
209 *dest = '\0';
210 return E_FAIL;
213 if (!dest || !len)
214 return E_FAIL;
216 *dest = '\0';
218 switch (src->uType)
220 case STRRET_WSTR:
221 WideCharToMultiByte(CP_ACP, 0, src->pOleStr, -1, dest, len, NULL, NULL);
222 CoTaskMemFree(src->pOleStr);
223 break;
225 case STRRET_CSTR:
226 lstrcpynA(dest, src->cStr, len);
227 break;
229 case STRRET_OFFSET:
230 lstrcpynA(dest, ((LPCSTR)&pidl->mkid)+src->uOffset, len);
231 break;
233 default:
234 FIXME("unknown type!\n");
235 return E_NOTIMPL;
237 return S_OK;
240 /*************************************************************************
241 * StrRetToBufW [SHLWAPI.@]
243 * See StrRetToBufA.
245 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
247 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
249 if (!dest || !len)
250 return E_FAIL;
252 if (!src)
254 WARN("Invalid lpStrRet would crash under Win32!\n");
255 *dest = '\0';
256 return E_FAIL;
259 *dest = '\0';
261 switch (src->uType) {
262 case STRRET_WSTR: {
263 size_t dst_len;
264 if (!src->pOleStr)
265 return E_FAIL;
266 dst_len = lstrlenW(src->pOleStr);
267 memcpy(dest, src->pOleStr, min(dst_len, len-1) * sizeof(WCHAR));
268 dest[min(dst_len, len-1)] = 0;
269 CoTaskMemFree(src->pOleStr);
270 if (len <= dst_len)
272 dest[0] = 0;
273 return E_NOT_SUFFICIENT_BUFFER;
275 break;
278 case STRRET_CSTR:
279 if (!MultiByteToWideChar( CP_ACP, 0, src->cStr, -1, dest, len ))
280 dest[len-1] = 0;
281 break;
283 case STRRET_OFFSET:
284 if (pidl)
286 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->uOffset, -1,
287 dest, len ))
288 dest[len-1] = 0;
290 break;
292 default:
293 FIXME("unknown type!\n");
294 return E_NOTIMPL;
297 return S_OK;
300 /*************************************************************************
301 * StrRetToStrA [SHLWAPI.@]
303 * Converts a STRRET to a normal string.
305 * PARAMS
306 * lpStrRet [O] STRRET to convert
307 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
308 * ppszName [O] Destination for converted string
310 * RETURNS
311 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
312 * Failure: E_FAIL, if any parameters are invalid.
314 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
316 HRESULT hRet = E_FAIL;
318 switch (lpStrRet->uType)
320 case STRRET_WSTR:
321 hRet = _SHStrDupAW(lpStrRet->pOleStr, ppszName);
322 CoTaskMemFree(lpStrRet->pOleStr);
323 break;
325 case STRRET_CSTR:
326 hRet = _SHStrDupAA(lpStrRet->cStr, ppszName);
327 break;
329 case STRRET_OFFSET:
330 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->uOffset, ppszName);
331 break;
333 default:
334 *ppszName = NULL;
337 return hRet;
340 /*************************************************************************
341 * StrRetToStrW [SHLWAPI.@]
343 * See StrRetToStrA.
345 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
347 HRESULT hRet = E_FAIL;
349 switch (lpStrRet->uType)
351 case STRRET_WSTR:
352 hRet = SHStrDupW(lpStrRet->pOleStr, ppszName);
353 CoTaskMemFree(lpStrRet->pOleStr);
354 break;
356 case STRRET_CSTR:
357 hRet = SHStrDupA(lpStrRet->cStr, ppszName);
358 break;
360 case STRRET_OFFSET:
361 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->uOffset, ppszName);
362 break;
364 default:
365 *ppszName = NULL;
368 return hRet;
371 /* Makes a Unicode copy of an ANSI string using SysAllocString() */
372 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
374 *pBstrOut = NULL;
376 if (src)
378 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
379 WCHAR *szTemp = malloc(len * sizeof(WCHAR));
381 if (szTemp)
383 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
384 *pBstrOut = SysAllocString(szTemp);
385 free(szTemp);
387 if (*pBstrOut)
388 return S_OK;
391 return E_OUTOFMEMORY;
394 /*************************************************************************
395 * StrRetToBSTR [SHLWAPI.@]
397 * Converts a STRRET to a BSTR.
399 * PARAMS
400 * lpStrRet [O] STRRET to convert
401 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
402 * pBstrOut [O] Destination for converted BSTR
404 * RETURNS
405 * Success: S_OK. pBstrOut contains the new string.
406 * Failure: E_FAIL, if any parameters are invalid.
408 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
410 HRESULT hRet = E_FAIL;
412 switch (lpStrRet->uType)
414 case STRRET_WSTR:
415 *pBstrOut = SysAllocString(lpStrRet->pOleStr);
416 if (*pBstrOut)
417 hRet = S_OK;
418 CoTaskMemFree(lpStrRet->pOleStr);
419 break;
421 case STRRET_CSTR:
422 hRet = _SHStrDupAToBSTR(lpStrRet->cStr, pBstrOut);
423 break;
425 case STRRET_OFFSET:
426 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->uOffset, pBstrOut);
427 break;
429 default:
430 *pBstrOut = NULL;
433 return hRet;
436 /*************************************************************************
437 * StrFormatKBSizeA [SHLWAPI.@]
439 * Create a formatted string containing a byte count in Kilobytes.
441 * PARAMS
442 * llBytes [I] Byte size to format
443 * lpszDest [I] Destination for formatted string
444 * cchMax [I] Size of lpszDest
446 * RETURNS
447 * lpszDest.
449 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
451 WCHAR wszBuf[256];
453 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
454 return NULL;
455 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
456 return NULL;
457 return lpszDest;
460 /*************************************************************************
461 * StrFormatKBSizeW [SHLWAPI.@]
463 * See StrFormatKBSizeA.
465 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
467 static const WCHAR kb[] = {' ','K','B',0};
468 LONGLONG llKB = (llBytes + 1023) >> 10;
469 int len;
471 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
473 if (!FormatInt(llKB, lpszDest, cchMax))
474 return NULL;
476 len = lstrlenW(lpszDest);
477 if (cchMax - len < 4)
478 return NULL;
479 lstrcatW(lpszDest, kb);
480 return lpszDest;
483 /*************************************************************************
484 * StrNCatA [SHLWAPI.@]
486 * Concatenate two strings together.
488 * PARAMS
489 * lpszStr [O] String to concatenate to
490 * lpszCat [I] String to add to lpszCat
491 * cchMax [I] Maximum number of characters to concatenate
493 * RETURNS
494 * lpszStr.
496 * NOTES
497 * cchMax determines the number of characters that are appended to lpszStr,
498 * not the total length of the string.
500 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
502 LPSTR lpszRet = lpszStr;
504 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
506 if (!lpszStr)
508 WARN("Invalid lpszStr would crash under Win32!\n");
509 return NULL;
512 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
513 return lpszRet;
516 /*************************************************************************
517 * StrNCatW [SHLWAPI.@]
519 * See StrNCatA.
521 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
523 LPWSTR lpszRet = lpszStr;
525 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
527 if (!lpszStr)
529 WARN("Invalid lpszStr would crash under Win32\n");
530 return NULL;
533 StrCpyNW(lpszStr + lstrlenW(lpszStr), lpszCat, cchMax);
534 return lpszRet;
537 /*************************************************************************
538 * _SHStrDupAA [INTERNAL]
540 * Duplicates a ANSI string to ANSI. The destination buffer is allocated.
542 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
544 HRESULT hr;
545 int len = 0;
547 if (src) {
548 len = lstrlenA(src) + 1;
549 *dest = CoTaskMemAlloc(len);
550 } else {
551 *dest = NULL;
554 if (*dest) {
555 lstrcpynA(*dest,src, len);
556 hr = S_OK;
557 } else {
558 hr = E_OUTOFMEMORY;
561 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
562 return hr;
565 /*************************************************************************
566 * SHStrDupA [SHLWAPI.@]
568 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
570 * PARAMS
571 * lpszStr [I] String to copy
572 * lppszDest [O] Destination for the new string copy
574 * RETURNS
575 * Success: S_OK. lppszDest contains the new string in Unicode format.
576 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
577 * fails.
579 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
581 HRESULT hRet;
582 int len = 0;
584 if (lpszStr)
586 len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR);
587 *lppszDest = CoTaskMemAlloc(len);
589 else
590 *lppszDest = NULL;
592 if (*lppszDest)
594 MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
595 hRet = S_OK;
597 else
598 hRet = E_OUTOFMEMORY;
600 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
601 return hRet;
604 /*************************************************************************
605 * _SHStrDupAW [INTERNAL]
607 * Duplicates a UNICODE to a ANSI string. The destination buffer is allocated.
609 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
611 HRESULT hr;
612 int len = 0;
614 if (src) {
615 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
616 *dest = CoTaskMemAlloc(len);
617 } else {
618 *dest = NULL;
621 if (*dest) {
622 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
623 hr = S_OK;
624 } else {
625 hr = E_OUTOFMEMORY;
628 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
629 return hr;
632 /*************************************************************************
633 * SHStrDupW [SHLWAPI.@]
635 * See SHStrDupA.
637 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
639 HRESULT hr;
640 int len = 0;
642 if (src) {
643 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
644 *dest = CoTaskMemAlloc(len);
645 } else {
646 *dest = NULL;
649 if (*dest) {
650 memcpy(*dest, src, len);
651 hr = S_OK;
652 } else {
653 hr = E_OUTOFMEMORY;
656 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
657 return hr;
660 /*************************************************************************
661 * SHLWAPI_WriteReverseNum
663 * Internal helper for SHLWAPI_WriteTimeClass.
665 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
667 *lpszOut-- = '\0';
669 /* Write a decimal number to a string, backwards */
672 DWORD dwNextDigit = dwNum % 10;
673 *lpszOut-- = '0' + dwNextDigit;
674 dwNum = (dwNum - dwNextDigit) / 10;
675 } while (dwNum > 0);
677 return lpszOut;
680 /*************************************************************************
681 * SHLWAPI_FormatSignificant
683 * Internal helper for SHLWAPI_WriteTimeClass.
685 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
687 /* Zero non significant digits, return remaining significant digits */
688 while (*lpszNum)
690 lpszNum++;
691 if (--dwDigits == 0)
693 while (*lpszNum)
694 *lpszNum++ = '0';
695 return 0;
698 return dwDigits;
701 /*************************************************************************
702 * SHLWAPI_WriteTimeClass
704 * Internal helper for StrFromTimeIntervalW.
706 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
707 UINT uClassStringId, int iDigits)
709 WCHAR szBuff[64], *szOut = szBuff + 32;
711 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
712 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
713 *szOut = ' ';
714 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
715 lstrcatW(lpszOut, szOut);
716 return iDigits;
719 /*************************************************************************
720 * StrFromTimeIntervalA [SHLWAPI.@]
722 * Format a millisecond time interval into a string
724 * PARAMS
725 * lpszStr [O] Output buffer for formatted time interval
726 * cchMax [I] Size of lpszStr
727 * dwMS [I] Number of milliseconds
728 * iDigits [I] Number of digits to print
730 * RETURNS
731 * The length of the formatted string, or 0 if any parameter is invalid.
733 * NOTES
734 * This implementation mimics the Win32 behaviour of always writing a leading
735 * space before the time interval begins.
737 * iDigits is used to provide approximate times if accuracy is not important.
738 * This number of digits will be written of the first non-zero time class
739 * (hours/minutes/seconds). If this does not complete the time classification,
740 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
741 * If there are digits remaining following the writing of a time class, the
742 * next time class will be written.
744 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
745 * following will result from the given values of iDigits:
747 *| iDigits 1 2 3 4 5 ...
748 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
750 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
751 int iDigits)
753 INT iRet = 0;
755 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
757 if (lpszStr && cchMax)
759 WCHAR szBuff[128];
760 StrFromTimeIntervalW(szBuff, ARRAY_SIZE(szBuff), dwMS, iDigits);
761 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
763 return iRet;
767 /*************************************************************************
768 * StrFromTimeIntervalW [SHLWAPI.@]
770 * See StrFromTimeIntervalA.
772 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
773 int iDigits)
775 INT iRet = 0;
777 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
779 if (lpszStr && cchMax)
781 WCHAR szCopy[128];
782 DWORD dwHours, dwMinutes;
784 if (!iDigits || cchMax == 1)
786 *lpszStr = '\0';
787 return 0;
790 /* Calculate the time classes */
791 dwMS = (dwMS + 500) / 1000;
792 dwHours = dwMS / 3600;
793 dwMS -= dwHours * 3600;
794 dwMinutes = dwMS / 60;
795 dwMS -= dwMinutes * 60;
797 szCopy[0] = '\0';
799 if (dwHours)
800 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
802 if (dwMinutes && iDigits)
803 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
805 if (iDigits) /* Always write seconds if we have significant digits */
806 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
808 lstrcpynW(lpszStr, szCopy, cchMax);
809 iRet = lstrlenW(lpszStr);
811 return iRet;
814 /* Structure for formatting byte strings */
815 typedef struct tagSHLWAPI_BYTEFORMATS
817 LONGLONG dLimit;
818 double dDivisor;
819 double dNormaliser;
820 int nDecimals;
821 WCHAR wPrefix;
822 } SHLWAPI_BYTEFORMATS;
824 /*************************************************************************
825 * StrFormatByteSizeW [SHLWAPI.@]
827 * Create a string containing an abbreviated byte count of up to 2^63-1.
829 * PARAMS
830 * llBytes [I] Byte size to format
831 * lpszDest [I] Destination for formatted string
832 * cchMax [I] Size of lpszDest
834 * RETURNS
835 * lpszDest.
837 * NOTES
838 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
840 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
842 HRESULT hr;
844 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
846 if (!lpszDest || !cchMax)
847 return lpszDest;
849 hr = StrFormatByteSizeEx(llBytes, SFBS_FLAGS_TRUNCATE_UNDISPLAYED_DECIMAL_DIGITS,
850 lpszDest, cchMax);
852 if (FAILED(hr))
853 return NULL;
855 return lpszDest;
858 /*************************************************************************
859 * StrFormatByteSizeEx [SHLWAPI.@]
863 HRESULT WINAPI StrFormatByteSizeEx(LONGLONG llBytes, SFBS_FLAGS flags, LPWSTR lpszDest,
864 UINT cchMax)
866 #define KB ((ULONGLONG)1024)
867 #define MB (KB*KB)
868 #define GB (KB*KB*KB)
869 #define TB (KB*KB*KB*KB)
870 #define PB (KB*KB*KB*KB*KB)
872 static const SHLWAPI_BYTEFORMATS bfFormats[] =
874 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
875 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
876 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
877 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
878 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
879 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
880 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
881 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
882 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
883 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
884 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
885 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
886 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
887 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
888 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
889 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
891 WCHAR wszAdd[] = {' ','?','B',0};
892 double dBytes;
893 UINT i = 0;
895 TRACE("(0x%s,%d,%p,%d)\n", wine_dbgstr_longlong(llBytes), flags, lpszDest, cchMax);
897 if (!cchMax)
898 return E_INVALIDARG;
900 if (llBytes < 1024) /* 1K */
902 WCHAR wszBytesFormat[64];
903 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
904 swprintf(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
905 return S_OK;
908 /* Note that if this loop completes without finding a match, i will be
909 * pointing at the last entry, which is a catch all for > 1000 PB
911 while (i < ARRAY_SIZE(bfFormats) - 1)
913 if (llBytes < bfFormats[i].dLimit)
914 break;
915 i++;
917 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
918 * this number we integer shift down by 1 MB first. The table above has
919 * the divisors scaled down from the '< 10 TB' entry onwards, to account
920 * for this. We also add a small fudge factor to get the correct result for
921 * counts that lie exactly on a 1024 byte boundary.
923 if (i > 8)
924 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
925 else
926 dBytes = (double)llBytes + 0.00001;
928 switch(flags)
930 case SFBS_FLAGS_ROUND_TO_NEAREST_DISPLAYED_DIGIT:
931 dBytes = round(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
932 break;
933 case SFBS_FLAGS_TRUNCATE_UNDISPLAYED_DECIMAL_DIGITS:
934 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
935 break;
936 default:
937 return E_INVALIDARG;
940 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
941 return E_FAIL;
943 wszAdd[1] = bfFormats[i].wPrefix;
944 StrCatBuffW(lpszDest, wszAdd, cchMax);
945 return S_OK;
948 /*************************************************************************
949 * StrFormatByteSize64A [SHLWAPI.@]
951 * See StrFormatByteSizeW.
953 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
955 WCHAR wszBuff[32];
957 StrFormatByteSizeW(llBytes, wszBuff, ARRAY_SIZE(wszBuff));
959 if (lpszDest)
960 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
961 return lpszDest;
964 /*************************************************************************
965 * StrFormatByteSizeA [SHLWAPI.@]
967 * Create a string containing an abbreviated byte count of up to 2^31-1.
969 * PARAMS
970 * dwBytes [I] Byte size to format
971 * lpszDest [I] Destination for formatted string
972 * cchMax [I] Size of lpszDest
974 * RETURNS
975 * lpszDest.
977 * NOTES
978 * The ANSI and Unicode versions of this function accept a different
979 * integer type for dwBytes. See StrFormatByteSize64A().
981 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
983 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
985 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
988 /*************************************************************************
989 * @ [SHLWAPI.203]
991 * Remove a single non-trailing ampersand ('&') from a string.
993 * PARAMS
994 * lpszStr [I/O] String to remove ampersand from.
996 * RETURNS
997 * The character after the first ampersand in lpszStr, or the first character
998 * in lpszStr if there is no ampersand in the string.
1000 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
1002 LPSTR lpszIter, lpszTmp;
1003 char ch;
1005 TRACE("(%s)\n", debugstr_a(lpszStr));
1007 ch = *lpszStr;
1009 if ((lpszIter = StrChrA(lpszStr, '&')))
1011 lpszTmp = CharNextA(lpszIter);
1012 if (*lpszTmp)
1014 if (*lpszTmp != '&')
1015 ch = *lpszTmp;
1017 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
1021 return ch;
1024 /*************************************************************************
1025 * @ [SHLWAPI.225]
1027 * Unicode version of SHStripMneumonicA.
1029 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
1031 LPWSTR lpszIter, lpszTmp;
1032 WCHAR ch;
1034 TRACE("(%s)\n", debugstr_w(lpszStr));
1036 ch = *lpszStr;
1038 if ((lpszIter = StrChrW(lpszStr, '&')))
1040 lpszTmp = lpszIter + 1;
1041 if (*lpszTmp)
1043 if (*lpszTmp != '&')
1044 ch = *lpszTmp;
1046 memmove( lpszIter, lpszTmp, (lstrlenW(lpszTmp) + 1) * sizeof(WCHAR) );
1050 return ch;
1053 /*************************************************************************
1054 * @ [SHLWAPI.216]
1056 * Convert an ANSI string to Unicode.
1058 * PARAMS
1059 * dwCp [I] Code page for the conversion
1060 * lpSrcStr [I] Source ANSI string to convert
1061 * lpDstStr [O] Destination for converted Unicode string
1062 * iLen [I] Length of lpDstStr
1064 * RETURNS
1065 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
1067 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
1069 DWORD dwRet;
1071 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
1072 TRACE("%s->%s,ret=%ld\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
1073 return dwRet;
1076 /*************************************************************************
1077 * @ [SHLWAPI.215]
1079 * Convert an ANSI string to Unicode.
1081 * PARAMS
1082 * lpSrcStr [I] Source ANSI string to convert
1083 * lpDstStr [O] Destination for converted Unicode string
1084 * iLen [I] Length of lpDstStr
1086 * RETURNS
1087 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
1089 * NOTES
1090 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
1092 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
1094 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
1097 /*************************************************************************
1098 * @ [SHLWAPI.218]
1100 * Convert a Unicode string to ANSI.
1102 * PARAMS
1103 * CodePage [I] Code page to use for the conversion
1104 * lpSrcStr [I] Source Unicode string to convert
1105 * lpDstStr [O] Destination for converted ANSI string
1106 * dstlen [I] Length of buffer at lpDstStr
1108 * RETURNS
1109 * Success: The length in bytes of the result at lpDstStr (including the terminator)
1110 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
1111 * the result is not nul-terminated.
1112 * When using a different codepage, the length in bytes of the truncated
1113 * result at lpDstStr (including the terminator) is returned and
1114 * lpDstStr is always nul-terminated.
1117 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
1119 static const WCHAR emptyW[] = { '\0' };
1120 int len , reqLen;
1121 LPSTR mem;
1123 if (!lpDstStr || !dstlen)
1124 return 0;
1126 if (!lpSrcStr)
1127 lpSrcStr = emptyW;
1129 *lpDstStr = '\0';
1131 len = lstrlenW(lpSrcStr) + 1;
1133 switch (CodePage)
1135 case CP_WINUNICODE:
1136 CodePage = CP_UTF8; /* Fall through... */
1137 case 0x0000C350: /* FIXME: CP_ #define */
1138 case CP_UTF7:
1139 case CP_UTF8:
1141 DWORD dwMode = 0;
1142 INT lenW = len - 1;
1143 INT needed = dstlen - 1;
1144 HRESULT hr;
1146 /* try the user supplied buffer first */
1147 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
1148 if (hr == S_OK)
1150 lpDstStr[needed] = '\0';
1151 return needed + 1;
1154 /* user buffer too small. exclude termination and copy as much as possible */
1155 lenW = len;
1156 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
1157 needed++;
1158 mem = malloc(needed);
1159 if (!mem)
1160 return 0;
1162 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
1163 if (hr == S_OK)
1165 reqLen = SHTruncateString(mem, dstlen);
1166 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
1168 free(mem);
1169 return 0;
1171 default:
1172 break;
1175 /* try the user supplied buffer first */
1176 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
1178 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1180 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
1181 if (reqLen)
1183 mem = malloc(reqLen);
1184 if (mem)
1186 WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, reqLen, NULL, NULL);
1188 reqLen = SHTruncateString(mem, dstlen -1);
1189 reqLen++;
1191 lstrcpynA(lpDstStr, mem, reqLen);
1192 free(mem);
1193 lpDstStr[reqLen-1] = '\0';
1197 return reqLen;
1200 /*************************************************************************
1201 * @ [SHLWAPI.217]
1203 * Convert a Unicode string to ANSI.
1205 * PARAMS
1206 * lpSrcStr [I] Source Unicode string to convert
1207 * lpDstStr [O] Destination for converted ANSI string
1208 * iLen [O] Length of lpDstStr in characters
1210 * RETURNS
1211 * See SHUnicodeToAnsiCP
1213 * NOTES
1214 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
1216 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
1218 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
1221 /*************************************************************************
1222 * @ [SHLWAPI.364]
1224 * Determine if an ANSI string converts to Unicode and back identically.
1226 * PARAMS
1227 * lpSrcStr [I] Source Unicode string to convert
1228 * lpDst [O] Destination for resulting ANSI string
1229 * iLen [I] Length of lpDst in characters
1231 * RETURNS
1232 * TRUE, since ANSI strings always convert identically.
1234 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
1236 lstrcpynA(lpDst, lpSrcStr, iLen);
1237 return TRUE;
1240 /*************************************************************************
1241 * @ [SHLWAPI.365]
1243 * Determine if a Unicode string converts to ANSI and back identically.
1245 * PARAMS
1246 * lpSrcStr [I] Source Unicode string to convert
1247 * lpDst [O] Destination for resulting ANSI string
1248 * iLen [I] Length of lpDst in characters
1250 * RETURNS
1251 * TRUE, if lpSrcStr converts to ANSI and back identically,
1252 * FALSE otherwise.
1254 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
1256 WCHAR szBuff[MAX_PATH];
1258 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
1259 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
1260 return !wcscmp(lpSrcStr, szBuff);