Added some flex options to avoid compiler warnings.
[wine/hacks.git] / dlls / shlwapi / string.c
blob1ff9d815030aa859ce8e5e8143e9a9f53968e8d9
1 /*
2 * Shlwapi string functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define COM_NO_WINDOWS_H
23 #include "config.h"
24 #include "wine/port.h"
26 #include <math.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33 #include "windef.h"
34 #include "winbase.h"
35 #define NO_SHLWAPI_REG
36 #define NO_SHLWAPI_STREAM
37 #include "shlwapi.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "shlobj.h"
41 #include "ddeml.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(shell);
47 /* Get a function pointer from a DLL handle */
48 #define GET_FUNC(func, module, name, fail) \
49 do { \
50 if (!func) { \
51 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
52 func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
53 if (!func) return fail; \
54 } \
55 } while (0)
57 extern HMODULE SHLWAPI_hmlang;
59 typedef HRESULT (WINAPI *fnpConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT);
60 static fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte;
62 static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
63 static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*);
65 /*************************************************************************
66 * SHLWAPI_ChrCmpHelperA
68 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
70 * NOTES
71 * Both this function and its Unicode counterpart are very inneficient. To
72 * fix this, CompareString must be completely implemented and optimised
73 * first. Then the core character test can be taken out of that function and
74 * placed here, so that it need never be called at all. Until then, do not
75 * attempt to optimise this code unless you are willing to test that it
76 * still performs correctly.
78 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
80 char str1[3], str2[3];
82 str1[0] = LOBYTE(ch1);
83 if (IsDBCSLeadByte(str1[0]))
85 str1[1] = HIBYTE(ch1);
86 str1[2] = '\0';
88 else
89 str1[1] = '\0';
91 str2[0] = LOBYTE(ch2);
92 if (IsDBCSLeadByte(str2[0]))
94 str2[1] = HIBYTE(ch2);
95 str2[2] = '\0';
97 else
98 str2[1] = '\0';
100 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
103 /*************************************************************************
104 * SHLWAPI_ChrCmpHelperW
106 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
108 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
110 WCHAR str1[2], str2[2];
112 str1[0] = ch1;
113 str1[1] = '\0';
114 str2[0] = ch2;
115 str2[1] = '\0';
116 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
119 /*************************************************************************
120 * SHLWAPI_ChrCmpA
122 * Internal helper function.
124 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
126 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
129 /*************************************************************************
130 * ChrCmpIA (SHLWAPI.385)
132 * Compare two characters, ignoring case.
134 * PARAMS
135 * ch1 [I] First character to compare
136 * ch2 [I] Second character to compare
138 * RETURNS
139 * FALSE, if the characters are equal.
140 * Non-zero otherwise.
142 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
144 TRACE("(%d,%d)\n", ch1, ch2);
146 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
149 /*************************************************************************
150 * SHLWAPI_ChrCmpW
152 * Internal helper function.
154 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
156 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
159 /*************************************************************************
160 * ChrCmpIW [SHLWAPI.386]
162 * See ChrCmpIA.
164 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
166 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
169 /*************************************************************************
170 * StrChrA [SHLWAPI.@]
172 * Find a given character in a string.
174 * PARAMS
175 * lpszStr [I] String to search in.
176 * ch [I] Character to search for.
178 * RETURNS
179 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
180 * not found.
181 * Failure: NULL, if any arguments are invalid.
183 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
185 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
187 if (lpszStr)
189 while (*lpszStr)
191 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
192 return (LPSTR)lpszStr;
193 lpszStr = CharNextA(lpszStr);
196 return NULL;
199 /*************************************************************************
200 * StrChrW [SHLWAPI.@]
202 * See StrChrA.
204 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
206 LPWSTR lpszRet = NULL;
208 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
210 if (lpszStr)
211 lpszRet = strchrW(lpszStr, ch);
212 return lpszRet;
215 /*************************************************************************
216 * StrChrIA [SHLWAPI.@]
218 * Find a given character in a string, ignoring case.
220 * PARAMS
221 * lpszStr [I] String to search in.
222 * ch [I] Character to search for.
224 * RETURNS
225 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
226 * not found.
227 * Failure: NULL, if any arguments are invalid.
229 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
231 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
233 if (lpszStr)
235 while (*lpszStr)
237 if (!ChrCmpIA(*lpszStr, ch))
238 return (LPSTR)lpszStr;
239 lpszStr = CharNextA(lpszStr);
242 return NULL;
245 /*************************************************************************
246 * StrChrIW [SHLWAPI.@]
248 * See StrChrA.
250 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
252 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
254 if (lpszStr)
256 ch = toupperW(ch);
257 while (*lpszStr)
259 if (toupperW(*lpszStr) == ch)
260 return (LPWSTR)lpszStr;
261 lpszStr = CharNextW(lpszStr);
263 lpszStr = NULL;
265 return (LPWSTR)lpszStr;
268 /*************************************************************************
269 * StrCmpIW [SHLWAPI.@]
271 * Compare two strings, ignoring case.
273 * PARAMS
274 * lpszStr [I] First string to compare
275 * lpszComp [I] Second string to compare
277 * RETURNS
278 * An integer less than, equal to or greater than 0, indicating that
279 * lpszStr is less than, the same, or greater than lpszComp.
281 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
283 int iRet;
285 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
287 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
288 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
291 /*************************************************************************
292 * StrCmpNA [SHLWAPI.@]
294 * Compare two strings, up to a maximum length.
296 * PARAMS
297 * lpszStr [I] First string to compare
298 * lpszComp [I] Second string to compare
299 * iLen [I] Maximum number of chars to compare.
301 * RETURNS
302 * An integer less than, equal to or greater than 0, indicating that
303 * lpszStr is less than, the same, or greater than lpszComp.
305 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
307 INT iRet;
309 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
311 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
312 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
315 /*************************************************************************
316 * StrCmpNW [SHLWAPI.@]
318 * See StrCmpNA.
320 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
322 INT iRet;
324 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
326 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
327 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
330 /*************************************************************************
331 * StrCmpNIA [SHLWAPI.@]
333 * Compare two strings, up to a maximum length, ignoring case.
335 * PARAMS
336 * lpszStr [I] First string to compare
337 * lpszComp [I] Second string to compare
338 * iLen [I] Maximum number of chars to compare.
340 * RETURNS
341 * An integer less than, equal to or greater than 0, indicating that
342 * lpszStr is less than, the same, or greater than lpszComp.
344 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
346 INT iRet;
348 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
350 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
351 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
354 /*************************************************************************
355 * StrCmpNIW [SHLWAPI.@]
357 * See StrCmpNIA.
359 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
361 INT iRet;
363 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
365 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
366 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
369 /*************************************************************************
370 * StrCmpW [SHLWAPI.@]
372 * Compare two strings.
374 * PARAMS
375 * lpszStr [I] First string to compare
376 * lpszComp [I] Second string to compare
378 * RETURNS
379 * An integer less than, equal to or greater than 0, indicating that
380 * lpszStr is less than, the same, or greater than lpszComp.
382 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
384 INT iRet;
386 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
388 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
389 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
392 /*************************************************************************
393 * StrCatW [SHLWAPI.@]
395 * Concatanate two strings.
397 * PARAMS
398 * lpszStr [O] Initial string
399 * lpszSrc [I] String to concatanate
401 * RETURNS
402 * lpszStr.
404 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
406 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
408 strcatW(lpszStr, lpszSrc);
409 return lpszStr;
412 /*************************************************************************
413 * StrCpyW [SHLWAPI.@]
415 * Copy a string to another string.
417 * PARAMS
418 * lpszStr [O] Destination string
419 * lpszSrc [I] Source string
421 * RETURNS
422 * lpszStr.
424 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
426 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
428 strcpyW(lpszStr, lpszSrc);
429 return lpszStr;
432 /*************************************************************************
433 * StrCpyNW [SHLWAPI.@]
435 * Copy a string to another string, up to a maximum number of characters.
437 * PARAMS
438 * lpszStr [O] Destination string
439 * lpszSrc [I] Source string
440 * iLen [I] Maximum number of chars to copy
442 * RETURNS
443 * lpszStr.
445 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
447 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
449 lstrcpynW(lpszStr, lpszSrc, iLen);
450 return lpszStr;
455 /*************************************************************************
456 * SHLWAPI_StrStrHelperA
458 * Internal implementation of StrStrA/StrStrIA
460 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
461 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
463 size_t iLen;
465 if (!lpszStr || !lpszSearch || !*lpszSearch)
466 return NULL;
468 iLen = strlen(lpszSearch);
470 while (*lpszStr)
472 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
473 return (LPSTR)lpszStr;
474 lpszStr = CharNextA(lpszStr);
476 return NULL;
479 /*************************************************************************
480 * SHLWAPI_StrStrHelperW
482 * Internal implementation of StrStrW/StrStrIW
484 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
485 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
487 int iLen;
489 if (!lpszStr || !lpszSearch || !*lpszSearch)
490 return NULL;
492 iLen = strlenW(lpszSearch);
494 while (*lpszStr)
496 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
497 return (LPWSTR)lpszStr;
498 lpszStr = CharNextW(lpszStr);
500 return NULL;
503 /*************************************************************************
504 * StrStrA [SHLWAPI.@]
506 * Find a substring within a string.
508 * PARAMS
509 * lpszStr [I] String to search in
510 * lpszSearch [I] String to look for
512 * RETURNS
513 * The start of lpszSearch within lpszStr, or NULL if not found.
515 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
517 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
519 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
522 /*************************************************************************
523 * StrStrW [SHLWAPI.@]
525 * See StrStrA.
527 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
529 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
531 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
534 /*************************************************************************
535 * StrRStrIA [SHLWAPI.@]
537 * Find the last occurrence of a substring within a string.
539 * PARAMS
540 * lpszStr [I] String to search in
541 * lpszEnd [I] End of lpszStr
542 * lpszSearch [I] String to look for
544 * RETURNS
545 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
547 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
549 LPSTR lpszRet = NULL;
550 WORD ch1, ch2;
551 INT iLen;
553 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
555 if (!lpszStr || !lpszSearch || !*lpszSearch)
556 return NULL;
558 if (!lpszEnd)
559 lpszEnd = lpszStr + lstrlenA(lpszStr);
561 if (IsDBCSLeadByte(*lpszSearch))
562 ch1 = *lpszSearch << 8 | lpszSearch[1];
563 else
564 ch1 = *lpszSearch;
565 iLen = lstrlenA(lpszSearch);
567 while (lpszStr <= lpszEnd && *lpszStr)
569 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
570 if (!ChrCmpIA(ch1, ch2))
572 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
573 lpszRet = (LPSTR)lpszStr;
575 lpszStr = CharNextA(lpszStr);
577 return lpszRet;
580 /*************************************************************************
581 * StrRStrIW [SHLWAPI.@]
583 * See StrRStrIA.
585 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
587 LPWSTR lpszRet = NULL;
588 INT iLen;
590 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
592 if (!lpszStr || !lpszSearch || !*lpszSearch)
593 return NULL;
595 if (!lpszEnd)
596 lpszEnd = lpszStr + strlenW(lpszStr);
598 iLen = strlenW(lpszSearch);
600 while (lpszStr <= lpszEnd && *lpszStr)
602 if (!ChrCmpIW(*lpszSearch, *lpszStr))
604 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
605 lpszRet = (LPWSTR)lpszStr;
607 lpszStr = CharNextW(lpszStr);
609 return lpszRet;
612 /*************************************************************************
613 * StrStrIA [SHLWAPI.@]
615 * Find a substring within a string, ignoring case.
617 * PARAMS
618 * lpszStr [I] String to search in
619 * lpszSearch [I] String to look for
621 * RETURNS
622 * The start of lpszSearch within lpszStr, or NULL if not found.
624 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
626 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
628 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
631 /*************************************************************************
632 * StrStrIW [SHLWAPI.@]
634 * See StrStrIA.
636 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
638 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
640 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
643 /*************************************************************************
644 * StrToIntA [SHLWAPI.@]
646 * Read a signed integer from a string.
648 * PARAMS
649 * lpszStr [I] String to read integer from
651 * RETURNS
652 * The signed integer value represented by the string, or 0 if no integer is
653 * present.
655 * NOTES
656 * No leading space is allowed before the number, although a leading '-' is.
658 int WINAPI StrToIntA(LPCSTR lpszStr)
660 int iRet = 0;
662 TRACE("(%s)\n", debugstr_a(lpszStr));
664 if (!lpszStr)
666 WARN("Invalid lpszStr would crash under Win32!\n");
667 return 0;
670 if (*lpszStr == '-' || isdigit(*lpszStr))
671 StrToIntExA(lpszStr, 0, &iRet);
672 return iRet;
675 /*************************************************************************
676 * StrToIntW [SHLWAPI.@]
678 * See StrToIntA.
680 int WINAPI StrToIntW(LPCWSTR lpszStr)
682 int iRet = 0;
684 TRACE("(%s)\n", debugstr_w(lpszStr));
686 if (!lpszStr)
688 WARN("Invalid lpszStr would crash under Win32!\n");
689 return 0;
692 if (*lpszStr == '-' || isdigitW(*lpszStr))
693 StrToIntExW(lpszStr, 0, &iRet);
694 return iRet;
697 /*************************************************************************
698 * StrToIntExA [SHLWAPI.@]
700 * Read an integer from a string.
702 * PARAMS
703 * lpszStr [I] String to read integer from
704 * dwFlags [I] Flags controlling the conversion
705 * lpiRet [O] Destination for read integer.
707 * RETURNS
708 * Success: TRUE. lpiRet contains the integer value represented by the string.
709 * Failure: FALSE, if the string is invalid, or no number is present.
711 * NOTES
712 * Leading whitespace, '-' and '+' are allowed before the number. If
713 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
714 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
715 * the string is treated as a decimal string. A leading '-' is ignored for
716 * hexadecimal numbers.
718 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
720 BOOL bNegative = FALSE;
721 int iRet = 0;
723 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
725 if (!lpszStr || !lpiRet)
727 WARN("Invalid parameter would crash under Win32!\n");
728 return FALSE;
730 if (dwFlags > STIF_SUPPORT_HEX)
732 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
735 /* Skip leading space, '+', '-' */
736 while (isspace(*lpszStr))
737 lpszStr = CharNextA(lpszStr);
739 if (*lpszStr == '-')
741 bNegative = TRUE;
742 lpszStr++;
744 else if (*lpszStr == '+')
745 lpszStr++;
747 if (dwFlags & STIF_SUPPORT_HEX &&
748 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
750 /* Read hex number */
751 lpszStr += 2;
753 if (!isxdigit(*lpszStr))
754 return FALSE;
756 while (isxdigit(*lpszStr))
758 iRet = iRet * 16;
759 if (isdigit(*lpszStr))
760 iRet += (*lpszStr - '0');
761 else
762 iRet += 10 + (tolower(*lpszStr) - 'a');
763 lpszStr++;
765 *lpiRet = iRet;
766 return TRUE;
769 /* Read decimal number */
770 if (!isdigit(*lpszStr))
771 return FALSE;
773 while (isdigit(*lpszStr))
775 iRet = iRet * 10;
776 iRet += (*lpszStr - '0');
777 lpszStr++;
779 *lpiRet = bNegative ? -iRet : iRet;
780 return TRUE;
783 /*************************************************************************
784 * StrToIntExW [SHLWAPI.@]
786 * See StrToIntExA.
788 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
790 BOOL bNegative = FALSE;
791 int iRet = 0;
793 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
795 if (!lpszStr || !lpiRet)
797 WARN("Invalid parameter would crash under Win32!\n");
798 return FALSE;
800 if (dwFlags > STIF_SUPPORT_HEX)
802 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
805 /* Skip leading space, '+', '-' */
806 while (isspaceW(*lpszStr))
807 lpszStr = CharNextW(lpszStr);
809 if (*lpszStr == '-')
811 bNegative = TRUE;
812 lpszStr++;
814 else if (*lpszStr == '+')
815 lpszStr++;
817 if (dwFlags & STIF_SUPPORT_HEX &&
818 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
820 /* Read hex number */
821 lpszStr += 2;
823 if (!isxdigitW(*lpszStr))
824 return FALSE;
826 while (isxdigitW(*lpszStr))
828 iRet = iRet * 16;
829 if (isdigitW(*lpszStr))
830 iRet += (*lpszStr - '0');
831 else
832 iRet += 10 + (tolowerW(*lpszStr) - 'a');
833 lpszStr++;
835 *lpiRet = iRet;
836 return TRUE;
839 /* Read decimal number */
840 if (!isdigitW(*lpszStr))
841 return FALSE;
843 while (isdigitW(*lpszStr))
845 iRet = iRet * 10;
846 iRet += (*lpszStr - '0');
847 lpszStr++;
849 *lpiRet = bNegative ? -iRet : iRet;
850 return TRUE;
853 /*************************************************************************
854 * StrDupA [SHLWAPI.@]
856 * Duplicate a string.
858 * PARAMS
859 * lpszStr [I] String to duplicate.
861 * RETURNS
862 * Success: A pointer to a new string containing the contents of lpszStr
863 * Failure: NULL, if memory cannot be allocated
865 * NOTES
866 * The string memory is allocated with LocalAlloc(), and so should be released
867 * by calling LocalFree().
869 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
871 int iLen;
872 LPSTR lpszRet;
874 TRACE("(%s)\n",debugstr_a(lpszStr));
876 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
877 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
879 if (lpszRet)
881 if (lpszStr)
882 memcpy(lpszRet, lpszStr, iLen);
883 else
884 *lpszRet = '\0';
886 return lpszRet;
889 /*************************************************************************
890 * StrDupW [SHLWAPI.@]
892 * See StrDupA.
894 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
896 int iLen;
897 LPWSTR lpszRet;
899 TRACE("(%s)\n",debugstr_w(lpszStr));
901 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
902 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
904 if (lpszRet)
906 if (lpszStr)
907 memcpy(lpszRet, lpszStr, iLen);
908 else
909 *lpszRet = '\0';
911 return lpszRet;
914 /*************************************************************************
915 * SHLWAPI_StrSpnHelperA
917 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
919 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
920 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
921 BOOL bInvert)
923 LPCSTR lpszRead = lpszStr;
924 if (lpszStr && *lpszStr && lpszMatch)
926 while (*lpszRead)
928 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
930 if (!bInvert && !lpszTest)
931 break;
932 if (bInvert && lpszTest)
933 break;
934 lpszRead = CharNextA(lpszRead);
937 return lpszRead - lpszStr;
940 /*************************************************************************
941 * SHLWAPI_StrSpnHelperW
943 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
945 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
946 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
947 BOOL bInvert)
949 LPCWSTR lpszRead = lpszStr;
950 if (lpszStr && *lpszStr && lpszMatch)
952 while (*lpszRead)
954 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
956 if (!bInvert && !lpszTest)
957 break;
958 if (bInvert && lpszTest)
959 break;
960 lpszRead = CharNextW(lpszRead);
963 return lpszRead - lpszStr;
966 /*************************************************************************
967 * StrSpnA [SHLWAPI.@]
969 * Find the length of the start of a string that contains only certain
970 * characters.
972 * PARAMS
973 * lpszStr [I] String to search
974 * lpszMatch [I] Characters that can be in the substring
976 * RETURNS
977 * The length of the part of lpszStr containing only chars from lpszMatch,
978 * or 0 if any parameter is invalid.
980 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
982 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
984 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
987 /*************************************************************************
988 * StrSpnW [SHLWAPI.@]
990 * See StrSpnA.
992 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
994 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
996 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
999 /*************************************************************************
1000 * StrCSpnA [SHLWAPI.@]
1002 * Find the length of the start of a string that does not contain certain
1003 * characters.
1005 * PARAMS
1006 * lpszStr [I] String to search
1007 * lpszMatch [I] Characters that cannot be in the substring
1009 * RETURNS
1010 * The length of the part of lpszStr containing only chars not in lpszMatch,
1011 * or 0 if any parameter is invalid.
1013 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1015 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1017 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1020 /*************************************************************************
1021 * StrCSpnW [SHLWAPI.@]
1023 * See StrCSpnA.
1025 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1027 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1029 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1032 /*************************************************************************
1033 * StrCSpnIA [SHLWAPI.@]
1035 * Find the length of the start of a string that does not contain certain
1036 * characters, ignoring case.
1038 * PARAMS
1039 * lpszStr [I] String to search
1040 * lpszMatch [I] Characters that cannot be in the substring
1042 * RETURNS
1043 * The length of the part of lpszStr containing only chars not in lpszMatch,
1044 * or 0 if any parameter is invalid.
1046 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1048 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1050 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1053 /*************************************************************************
1054 * StrCSpnIW [SHLWAPI.@]
1056 * See StrCSpnIA.
1058 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1060 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1062 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1065 /*************************************************************************
1066 * StrPBrkA [SHLWAPI.@]
1068 * Search a string for any of a group of characters.
1070 * PARAMS
1071 * lpszStr [I] String to search
1072 * lpszMatch [I] Characters to match
1074 * RETURNS
1075 * A pointer to the first matching character in lpszStr, or NULL if no
1076 * match was found.
1078 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1080 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1082 if (lpszStr && lpszMatch && *lpszMatch)
1084 while (*lpszStr)
1086 if (StrChrA(lpszMatch, *lpszStr))
1087 return (LPSTR)lpszStr;
1088 lpszStr = CharNextA(lpszStr);
1091 return NULL;
1094 /*************************************************************************
1095 * StrPBrkW [SHLWAPI.@]
1097 * See StrPBrkA.
1099 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1101 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1103 if (lpszStr && lpszMatch && *lpszMatch)
1105 while (*lpszStr)
1107 if (StrChrW(lpszMatch, *lpszStr))
1108 return (LPWSTR)lpszStr;
1109 lpszStr = CharNextW(lpszStr);
1112 return NULL;
1115 /*************************************************************************
1116 * SHLWAPI_StrRChrHelperA
1118 * Internal implementation of StrRChrA/StrRChrIA.
1120 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1121 LPCSTR lpszEnd, WORD ch,
1122 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1124 LPCSTR lpszRet = NULL;
1126 if (lpszStr)
1128 WORD ch2;
1130 if (!lpszEnd)
1131 lpszEnd = lpszStr + lstrlenA(lpszStr);
1133 while (*lpszStr && lpszStr <= lpszEnd)
1135 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1137 if (!pChrCmpFn(ch, ch2))
1138 lpszRet = lpszStr;
1139 lpszStr = CharNextA(lpszStr);
1142 return (LPSTR)lpszRet;
1145 /*************************************************************************
1146 * SHLWAPI_StrRChrHelperW
1148 * Internal implementation of StrRChrW/StrRChrIW.
1150 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1151 LPCWSTR lpszEnd, WCHAR ch,
1152 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1154 LPCWSTR lpszRet = NULL;
1156 if (lpszStr)
1158 if (!lpszEnd)
1159 lpszEnd = lpszStr + strlenW(lpszStr);
1161 while (*lpszStr && lpszStr <= lpszEnd)
1163 if (!pChrCmpFn(ch, *lpszStr))
1164 lpszRet = lpszStr;
1165 lpszStr = CharNextW(lpszStr);
1168 return (LPWSTR)lpszRet;
1171 /**************************************************************************
1172 * StrRChrA [SHLWAPI.@]
1174 * Find the last occurrence of a character in string.
1176 * PARAMS
1177 * lpszStr [I] String to search in
1178 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1179 * ch [I] Character to search for.
1181 * RETURNS
1182 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1183 * or NULL if not found.
1184 * Failure: NULL, if any arguments are invalid.
1186 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1188 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1190 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1193 /**************************************************************************
1194 * StrRChrW [SHLWAPI.@]
1196 * See StrRChrA.
1198 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1200 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1202 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1205 /**************************************************************************
1206 * StrRChrIA [SHLWAPI.@]
1208 * Find the last occurrence of a character in string, ignoring case.
1210 * PARAMS
1211 * lpszStr [I] String to search in
1212 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1213 * ch [I] Character to search for.
1215 * RETURNS
1216 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1217 * or NULL if not found.
1218 * Failure: NULL, if any arguments are invalid.
1220 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1222 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1224 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1227 /**************************************************************************
1228 * StrRChrIW [SHLWAPI.@]
1230 * See StrRChrIA.
1232 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1234 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1236 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1239 /*************************************************************************
1240 * StrCatBuffA [SHLWAPI.@]
1242 * Concatenate two strings together.
1244 * PARAMS
1245 * lpszStr [O] String to concatenate to
1246 * lpszCat [I] String to add to lpszCat
1247 * cchMax [I] Maximum number of characters for the whole string
1249 * RETURNS
1250 * lpszStr.
1252 * NOTES
1253 * cchMax determines the number of characters in the final length of the
1254 * string, not the number appended to lpszStr from lpszCat.
1256 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1258 INT iLen;
1260 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1262 if (!lpszStr)
1264 WARN("Invalid lpszStr would crash under Win32!\n");
1265 return NULL;
1268 iLen = strlen(lpszStr);
1269 cchMax -= iLen;
1271 if (cchMax > 0)
1272 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1273 return lpszStr;
1276 /*************************************************************************
1277 * StrCatBuffW [SHLWAPI.@]
1279 * See StrCatBuffA.
1281 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1283 INT iLen;
1285 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1287 if (!lpszStr)
1289 WARN("Invalid lpszStr would crash under Win32!\n");
1290 return NULL;
1293 iLen = strlenW(lpszStr);
1294 cchMax -= iLen;
1296 if (cchMax > 0)
1297 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1298 return lpszStr;
1301 /*************************************************************************
1302 * StrRetToBufA [SHLWAPI.@]
1304 * Convert a STRRET to a normal string.
1306 * PARAMS
1307 * lpStrRet [O] STRRET to convert
1308 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1309 * lpszDest [O] Destination for normal string
1310 * dwLen [I] Length of lpszDest
1312 * RETURNS
1313 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1314 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1315 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1316 * Failure: E_FAIL, if any parameters are invalid.
1318 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1320 /* NOTE:
1321 * This routine is identical to that in dlls/shell32/shellstring.c.
1322 * It was duplicated because not every version of Shlwapi.dll exports
1323 * StrRetToBufA. If you change one routine, change them both.
1325 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1327 if (!src)
1329 WARN("Invalid lpStrRet would crash under Win32!\n");
1330 if (dest)
1331 *dest = '\0';
1332 return E_FAIL;
1335 if (!dest || !len)
1336 return E_FAIL;
1338 *dest = '\0';
1340 switch (src->uType)
1342 case STRRET_WSTR:
1343 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1344 CoTaskMemFree(src->u.pOleStr);
1345 break;
1347 case STRRET_CSTR:
1348 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1349 break;
1351 case STRRET_OFFSET:
1352 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1353 break;
1355 default:
1356 FIXME("unknown type!\n");
1357 return FALSE;
1359 return S_OK;
1362 /*************************************************************************
1363 * StrRetToBufW [SHLWAPI.@]
1365 * See StrRetToBufA.
1367 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1369 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1371 if (!src)
1373 WARN("Invalid lpStrRet would crash under Win32!\n");
1374 if (dest)
1375 *dest = '\0';
1376 return E_FAIL;
1379 if (!dest || !len)
1380 return E_FAIL;
1382 *dest = '\0';
1384 switch (src->uType)
1386 case STRRET_WSTR:
1387 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1388 CoTaskMemFree(src->u.pOleStr);
1389 break;
1391 case STRRET_CSTR:
1392 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1393 dest[len-1] = 0;
1394 break;
1396 case STRRET_OFFSET:
1397 if (pidl)
1399 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1400 dest, len ) && len)
1401 dest[len-1] = 0;
1403 break;
1405 default:
1406 FIXME("unknown type!\n");
1407 return FALSE;
1409 return S_OK;
1412 /*************************************************************************
1413 * StrRetToStrA [SHLWAPI.@]
1415 * Converts a STRRET to a normal string.
1417 * PARAMS
1418 * lpStrRet [O] STRRET to convert
1419 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1420 * ppszName [O] Destination for converted string
1422 * RETURNS
1423 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1424 * Failure: E_FAIL, if any parameters are invalid.
1426 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1428 HRESULT hRet = E_FAIL;
1430 switch (lpStrRet->uType)
1432 case STRRET_WSTR:
1433 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1434 CoTaskMemFree(lpStrRet->u.pOleStr);
1435 break;
1437 case STRRET_CSTR:
1438 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1439 break;
1441 case STRRET_OFFSET:
1442 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1443 break;
1445 default:
1446 *ppszName = NULL;
1449 return hRet;
1452 /*************************************************************************
1453 * StrRetToStrW [SHLWAPI.@]
1455 * See StrRetToStrA.
1457 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1459 HRESULT hRet = E_FAIL;
1461 switch (lpStrRet->uType)
1463 case STRRET_WSTR:
1464 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1465 CoTaskMemFree(lpStrRet->u.pOleStr);
1466 break;
1468 case STRRET_CSTR:
1469 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1470 break;
1472 case STRRET_OFFSET:
1473 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1474 break;
1476 default:
1477 *ppszName = NULL;
1480 return hRet;
1483 /* Create an ASCII string copy using SysAllocString() */
1484 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1486 *pBstrOut = NULL;
1488 if (src)
1490 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1491 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1493 if (szTemp)
1495 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1496 *pBstrOut = SysAllocString(szTemp);
1497 HeapFree(GetProcessHeap(), 0, szTemp);
1499 if (*pBstrOut)
1500 return S_OK;
1503 return E_OUTOFMEMORY;
1506 /*************************************************************************
1507 * StrRetToBSTR [SHLWAPI.@]
1509 * Converts a STRRET to a BSTR.
1511 * PARAMS
1512 * lpStrRet [O] STRRET to convert
1513 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1514 * pBstrOut [O] Destination for converted BSTR
1516 * RETURNS
1517 * Success: S_OK. pBstrOut contains the new string.
1518 * Failure: E_FAIL, if any parameters are invalid.
1520 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1522 HRESULT hRet = E_FAIL;
1524 switch (lpStrRet->uType)
1526 case STRRET_WSTR:
1527 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1528 if (*pBstrOut)
1529 hRet = S_OK;
1530 CoTaskMemFree(lpStrRet->u.pOleStr);
1531 break;
1533 case STRRET_CSTR:
1534 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1535 break;
1537 case STRRET_OFFSET:
1538 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1539 break;
1541 default:
1542 *pBstrOut = NULL;
1545 return hRet;
1548 /*************************************************************************
1549 * StrFormatKBSizeA [SHLWAPI.@]
1551 * Create a formatted string containing a byte count in Kilobytes.
1553 * PARAMS
1554 * llBytes [I] Byte size to format
1555 * lpszDest [I] Destination for formatted string
1556 * cchMax [I] Size of lpszDest
1558 * RETURNS
1559 * lpszDest.
1561 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1563 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1564 LONGLONG ulKB = (llBytes + 1023) >> 10;
1566 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1568 *szOut-- = '\0';
1569 *szOut-- = 'B';
1570 *szOut-- = 'K';
1571 *szOut-- = ' ';
1575 LONGLONG ulNextDigit = ulKB % 10;
1576 *szOut-- = '0' + ulNextDigit;
1577 ulKB = (ulKB - ulNextDigit) / 10;
1578 } while (ulKB > 0);
1580 lstrcpynA(lpszDest, szOut + 1, cchMax);
1581 return lpszDest;
1584 /*************************************************************************
1585 * StrFormatKBSizeW [SHLWAPI.@]
1587 * See StrFormatKBSizeA.
1589 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1591 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
1592 LONGLONG ulKB = (llBytes + 1023) >> 10;
1594 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1596 *szOut-- = '\0';
1597 *szOut-- = 'B';
1598 *szOut-- = 'K';
1599 *szOut-- = ' ';
1603 LONGLONG ulNextDigit = ulKB % 10;
1604 *szOut-- = '0' + ulNextDigit;
1605 ulKB = (ulKB - ulNextDigit) / 10;
1606 } while (ulKB > 0);
1608 lstrcpynW(lpszDest, szOut + 1, cchMax);
1609 return lpszDest;
1612 /*************************************************************************
1613 * StrNCatA [SHLWAPI.@]
1615 * Concatenate two strings together.
1617 * PARAMS
1618 * lpszStr [O] String to concatenate to
1619 * lpszCat [I] String to add to lpszCat
1620 * cchMax [I] Maximum number of characters to concatenate
1622 * RETURNS
1623 * lpszStr.
1625 * NOTES
1626 * cchMax determines the number of characters that are appended to lpszStr,
1627 * not the total length of the string.
1629 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1631 LPSTR lpszRet = lpszStr;
1633 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1635 if (!lpszStr)
1637 WARN("Invalid lpszStr would crash under Win32!\n");
1638 return NULL;
1641 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1642 return lpszRet;
1645 /*************************************************************************
1646 * StrNCatW [SHLWAPI.@]
1648 * See StrNCatA.
1650 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1652 LPWSTR lpszRet = lpszStr;
1654 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1656 if (!lpszStr)
1658 WARN("Invalid lpszStr would crash under Win32\n");
1659 return NULL;
1662 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1663 return lpszRet;
1666 /*************************************************************************
1667 * StrTrimA [SHLWAPI.@]
1669 * Remove characters from the start and end of a string.
1671 * PARAMS
1672 * lpszStr [O] String to remove characters from
1673 * lpszTrim [I] Characters to remove from lpszStr
1675 * RETURNS
1676 * TRUE If lpszStr was valid and modified
1677 * FALSE Otherwise
1679 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1681 DWORD dwLen;
1682 LPSTR lpszRead = lpszStr;
1683 BOOL bRet = FALSE;
1685 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1687 if (lpszRead && *lpszRead)
1689 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1690 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1692 dwLen = strlen(lpszRead);
1694 if (lpszRead != lpszStr)
1696 memmove(lpszStr, lpszRead, dwLen + 1);
1697 bRet = TRUE;
1699 if (dwLen > 0)
1701 lpszRead = lpszStr + dwLen;
1702 while (StrChrA(lpszTrim, lpszRead[-1]))
1703 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1705 if (lpszRead != lpszStr + dwLen)
1707 *lpszRead = '\0';
1708 bRet = TRUE;
1712 return bRet;
1715 /*************************************************************************
1716 * StrTrimW [SHLWAPI.@]
1718 * See StrTrimA.
1720 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1722 DWORD dwLen;
1723 LPWSTR lpszRead = lpszStr;
1724 BOOL bRet = FALSE;
1726 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1728 if (lpszRead && *lpszRead)
1730 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1731 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1733 dwLen = strlenW(lpszRead);
1735 if (lpszRead != lpszStr)
1737 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1738 bRet = TRUE;
1740 if (dwLen > 0)
1742 lpszRead = lpszStr + dwLen;
1743 while (StrChrW(lpszTrim, lpszRead[-1]))
1744 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1746 if (lpszRead != lpszStr + dwLen)
1748 *lpszRead = '\0';
1749 bRet = TRUE;
1753 return bRet;
1756 /*************************************************************************
1757 * _SHStrDupAA [INTERNAL]
1759 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1761 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1763 HRESULT hr;
1764 int len = 0;
1766 if (src) {
1767 len = lstrlenA(src) + 1;
1768 *dest = CoTaskMemAlloc(len);
1769 } else {
1770 *dest = NULL;
1773 if (*dest) {
1774 lstrcpynA(*dest,src, len);
1775 hr = S_OK;
1776 } else {
1777 hr = E_OUTOFMEMORY;
1780 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1781 return hr;
1784 /*************************************************************************
1785 * SHStrDupA [SHLWAPI.@]
1787 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1789 * PARAMS
1790 * lpszStr [I] String to copy
1791 * lppszDest [O] Destination for the new string copy
1793 * RETURNS
1794 * Success: S_OK. lppszDest contains the new string in Unicode format.
1795 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1796 * fails.
1798 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1800 HRESULT hRet;
1801 int len = 0;
1803 if (lpszStr)
1805 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1806 *lppszDest = CoTaskMemAlloc(len);
1808 else
1809 *lppszDest = NULL;
1811 if (*lppszDest)
1813 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1814 hRet = S_OK;
1816 else
1817 hRet = E_OUTOFMEMORY;
1819 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1820 return hRet;
1823 /*************************************************************************
1824 * _SHStrDupAW [INTERNAL]
1826 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1828 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1830 HRESULT hr;
1831 int len = 0;
1833 if (src) {
1834 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1835 *dest = CoTaskMemAlloc(len);
1836 } else {
1837 *dest = NULL;
1840 if (*dest) {
1841 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1842 hr = S_OK;
1843 } else {
1844 hr = E_OUTOFMEMORY;
1847 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1848 return hr;
1851 /*************************************************************************
1852 * SHStrDupW [SHLWAPI.@]
1854 * See SHStrDupA.
1856 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1858 HRESULT hr;
1859 int len = 0;
1861 if (src) {
1862 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1863 *dest = CoTaskMemAlloc(len);
1864 } else {
1865 *dest = NULL;
1868 if (*dest) {
1869 memcpy(*dest, src, len);
1870 hr = S_OK;
1871 } else {
1872 hr = E_OUTOFMEMORY;
1875 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1876 return hr;
1879 /*************************************************************************
1880 * SHLWAPI_WriteReverseNum
1882 * Internal helper for SHLWAPI_WriteTimeClass.
1884 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1886 *lpszOut-- = '\0';
1888 /* Write a decimal number to a string, backwards */
1891 DWORD dwNextDigit = dwNum % 10;
1892 *lpszOut-- = '0' + dwNextDigit;
1893 dwNum = (dwNum - dwNextDigit) / 10;
1894 } while (dwNum > 0);
1896 return lpszOut;
1899 /*************************************************************************
1900 * SHLWAPI_FormatSignificant
1902 * Internal helper for SHLWAPI_WriteTimeClass.
1904 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1906 /* Zero non significant digits, return remaining significant digits */
1907 while (*lpszNum)
1909 lpszNum++;
1910 if (--dwDigits == 0)
1912 while (*lpszNum)
1913 *lpszNum++ = '0';
1914 return 0;
1917 return dwDigits;
1920 /*************************************************************************
1921 * SHLWAPI_WriteTimeClass
1923 * Internal helper for StrFromTimeIntervalW.
1925 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1926 LPCWSTR lpszClass, int iDigits)
1928 WCHAR szBuff[64], *szOut = szBuff + 32;
1930 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1931 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1932 *szOut = ' ';
1933 strcpyW(szBuff + 32, lpszClass);
1934 strcatW(lpszOut, szOut);
1935 return iDigits;
1938 /*************************************************************************
1939 * StrFromTimeIntervalA [SHLWAPI.@]
1941 * Format a millisecond time interval into a string
1943 * PARAMS
1944 * lpszStr [O] Output buffer for formatted time interval
1945 * cchMax [I] Size of lpszStr
1946 * dwMS [I] Number of milliseconds
1947 * iDigits [I] Number of digits to print
1949 * RETURNS
1950 * The length of the formatted string, or 0 if any parameter is invalid.
1952 * NOTES
1953 * This implementation mimics the Win32 behaviour of always writing a leading
1954 * space before the time interval begins.
1956 * iDigits is used to provide approximate times if accuracy is not important.
1957 * This number of digits will be written of the first non-zero time class
1958 * (hours/minutes/seconds). If this does not complete the time classification,
1959 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1960 * If there are digits remaining following the writing of a time class, the
1961 * next time class will be written.
1963 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1964 * following will result from the given values of iDigits:
1966 *| iDigits 1 2 3 4 5 ...
1967 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1969 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1970 int iDigits)
1972 INT iRet = 0;
1974 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1976 if (lpszStr && cchMax)
1978 WCHAR szBuff[128];
1979 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1980 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1982 return iRet;
1986 /*************************************************************************
1987 * StrFromTimeIntervalW [SHLWAPI.@]
1989 * See StrFromTimeIntervalA.
1991 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1992 int iDigits)
1994 static const WCHAR szHr[] = {' ','h','r','\0'};
1995 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1996 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1997 INT iRet = 0;
1999 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2001 if (lpszStr && cchMax)
2003 WCHAR szCopy[128];
2004 DWORD dwHours, dwMinutes;
2006 if (!iDigits || cchMax == 1)
2008 *lpszStr = '\0';
2009 return 0;
2012 /* Calculate the time classes */
2013 dwMS = (dwMS + 500) / 1000;
2014 dwHours = dwMS / 3600;
2015 dwMS -= dwHours * 3600;
2016 dwMinutes = dwMS / 60;
2017 dwMS -= dwMinutes * 60;
2019 szCopy[0] = '\0';
2021 if (dwHours)
2022 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
2024 if (dwMinutes && iDigits)
2025 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
2027 if (iDigits) /* Always write seconds if we have significant digits */
2028 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
2030 lstrcpynW(lpszStr, szCopy, cchMax);
2031 iRet = strlenW(lpszStr);
2033 return iRet;
2036 /*************************************************************************
2037 * StrIsIntlEqualA [SHLWAPI.@]
2039 * Compare two strings.
2041 * PARAMS
2042 * bCase [I] Whether to compare case sensitively
2043 * lpszStr [I] First string to compare
2044 * lpszComp [I] Second string to compare
2045 * iLen [I] Length to compare
2047 * RETURNS
2048 * TRUE If the strings are equal.
2049 * FALSE Otherwise.
2051 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2052 int iLen)
2054 DWORD dwFlags;
2056 TRACE("(%d,%s,%s,%d)\n", bCase,
2057 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2059 /* FIXME: This flag is undocumented and unknown by our CompareString.
2060 * We need a define for it.
2062 dwFlags = 0x10000000;
2063 if (!bCase) dwFlags |= NORM_IGNORECASE;
2065 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2068 /*************************************************************************
2069 * StrIsIntlEqualW [SHLWAPI.@]
2071 * See StrIsIntlEqualA.
2073 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2074 int iLen)
2076 DWORD dwFlags;
2078 TRACE("(%d,%s,%s,%d)\n", bCase,
2079 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2081 /* FIXME: This flag is undocumented and unknown by our CompareString.
2082 * We need a define for it.
2084 dwFlags = 0x10000000;
2085 if (!bCase) dwFlags |= NORM_IGNORECASE;
2087 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2090 /*************************************************************************
2091 * @ [SHLWAPI.399]
2093 * Copy a string to another string, up to a maximum number of characters.
2095 * PARAMS
2096 * lpszDest [O] Destination string
2097 * lpszSrc [I] Source string
2098 * iLen [I] Maximum number of chars to copy
2100 * RETURNS
2101 * Success: A pointer to the last character written to lpszDest..
2102 * Failure: lpszDest, if any arguments are invalid.
2104 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2106 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2108 if (lpszDest && lpszSrc && iLen > 0)
2110 while ((iLen-- > 1) && *lpszSrc)
2111 *lpszDest++ = *lpszSrc++;
2112 if (iLen >= 0)
2113 *lpszDest = '\0';
2115 return lpszDest;
2118 /*************************************************************************
2119 * @ [SHLWAPI.400]
2121 * Unicode version of StrCpyNXA.
2123 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2125 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2127 if (lpszDest && lpszSrc && iLen > 0)
2129 while ((iLen-- > 1) && *lpszSrc)
2130 *lpszDest++ = *lpszSrc++;
2131 if (iLen >= 0)
2132 *lpszDest = '\0';
2134 return lpszDest;
2137 /*************************************************************************
2138 * StrCmpLogicalW [SHLWAPI.@]
2140 * Compare two strings, ignoring case and comparing digits as numbers.
2142 * PARAMS
2143 * lpszStr [I] First string to compare
2144 * lpszComp [I] Second string to compare
2145 * iLen [I] Length to compare
2147 * RETURNS
2148 * TRUE If the strings are equal.
2149 * FALSE Otherwise.
2151 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2153 INT iDiff;
2155 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2157 if (lpszStr && lpszComp)
2159 while (*lpszStr)
2161 if (!*lpszComp)
2162 return 1;
2163 else if (isdigitW(*lpszStr))
2165 int iStr, iComp;
2167 if (!isdigitW(*lpszComp))
2168 return -1;
2170 /* Compare the numbers */
2171 StrToIntExW(lpszStr, 0, &iStr);
2172 StrToIntExW(lpszComp, 0, &iComp);
2174 if (iStr < iComp)
2175 return -1;
2176 else if (iStr > iComp)
2177 return 1;
2179 /* Skip */
2180 while (isdigitW(*lpszStr))
2181 lpszStr++;
2182 while (isdigitW(*lpszComp))
2183 lpszComp++;
2185 else if (isdigitW(*lpszComp))
2186 return 1;
2187 else
2189 iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE);
2190 if (iDiff > 0)
2191 return 1;
2192 else if (iDiff < 0)
2193 return -1;
2195 lpszStr++;
2196 lpszComp++;
2199 if (*lpszComp)
2200 return -1;
2202 return 0;
2205 /* Structure for formatting byte strings */
2206 typedef struct tagSHLWAPI_BYTEFORMATS
2208 LONGLONG dLimit;
2209 double dDivisor;
2210 double dNormaliser;
2211 LPCWSTR lpwszFormat;
2212 WCHAR wPrefix;
2213 } SHLWAPI_BYTEFORMATS;
2215 /*************************************************************************
2216 * StrFormatByteSizeW [SHLWAPI.@]
2218 * Create a string containing an abbreviated byte count of up to 2^63-1.
2220 * PARAMS
2221 * llBytes [I] Byte size to format
2222 * lpszDest [I] Destination for formatted string
2223 * cchMax [I] Size of lpszDest
2225 * RETURNS
2226 * lpszDest.
2228 * NOTES
2229 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2231 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2233 static const WCHAR wszBytes[] = {'%','l','d',' ','b','y','t','e','s',0};
2234 static const WCHAR wsz3_0[] = {'%','3','.','0','f',0};
2235 static const WCHAR wsz3_1[] = {'%','3','.','1','f',0};
2236 static const WCHAR wsz3_2[] = {'%','3','.','2','f',0};
2238 #define KB ((ULONGLONG)1024)
2239 #define MB (KB*KB)
2240 #define GB (KB*KB*KB)
2241 #define TB (KB*KB*KB*KB)
2242 #define PB (KB*KB*KB*KB*KB)
2244 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2246 { 10*KB, 10.24, 100.0, wsz3_2, 'K' }, /* 10 KB */
2247 { 100*KB, 102.4, 10.0, wsz3_1, 'K' }, /* 100 KB */
2248 { 1000*KB, 1024.0, 1.0, wsz3_0, 'K' }, /* 1000 KB */
2249 { 10*MB, 10485.76, 100.0, wsz3_2, 'M' }, /* 10 MB */
2250 { 100*MB, 104857.6, 10.0, wsz3_1, 'M' }, /* 100 MB */
2251 { 1000*MB, 1048576.0, 1.0, wsz3_0, 'M' }, /* 1000 MB */
2252 { 10*GB, 10737418.24, 100.0, wsz3_2, 'G' }, /* 10 GB */
2253 { 100*GB, 107374182.4, 10.0, wsz3_1, 'G' }, /* 100 GB */
2254 { 1000*GB, 1073741824.0, 1.0, wsz3_0, 'G' }, /* 1000 GB */
2255 { 10*TB, 10485.76, 100.0, wsz3_2, 'T' }, /* 10 TB */
2256 { 100*TB, 104857.6, 10.0, wsz3_1, 'T' }, /* 100 TB */
2257 { 1000*TB, 1048576.0, 1.0, wsz3_0, 'T' }, /* 1000 TB */
2258 { 10*PB, 10737418.24, 100.00, wsz3_2, 'P' }, /* 10 PB */
2259 { 100*PB, 107374182.4, 10.00, wsz3_1, 'P' }, /* 100 PB */
2260 { 1000*PB, 1073741824.0, 1.00, wsz3_0, 'P' }, /* 1000 PB */
2261 { 0, 10995116277.76, 100.00, wsz3_2, 'E' } /* EB's, catch all */
2263 WCHAR wszBuff[32];
2264 WCHAR wszAdd[] = {' ','?','B',0};
2265 double dBytes;
2266 UINT i = 0;
2268 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2270 if (!lpszDest || !cchMax)
2271 return lpszDest;
2273 if (llBytes < 1024) /* 1K */
2275 snprintfW(lpszDest, cchMax, wszBytes, (long)llBytes);
2276 return lpszDest;
2279 /* Note that if this loop completes without finding a match, i will be
2280 * pointing at the last entry, which is a catch all for > 1000 PB
2282 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2284 if (llBytes < bfFormats[i].dLimit)
2285 break;
2286 i++;
2288 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2289 * this number we integer shift down by 1 MB first. The table above has
2290 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2291 * for this. We also add a small fudge factor to get the correct result for
2292 * counts that lie exactly on a 1024 byte boundary.
2294 if (i > 8)
2295 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2296 else
2297 dBytes = (double)llBytes + 0.00001;
2299 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2301 sprintfW(wszBuff, bfFormats[i].lpwszFormat, dBytes);
2302 wszAdd[1] = bfFormats[i].wPrefix;
2303 strcatW(wszBuff, wszAdd);
2304 lstrcpynW(lpszDest, wszBuff, cchMax);
2305 return lpszDest;
2308 /*************************************************************************
2309 * StrFormatByteSize64A [SHLWAPI.@]
2311 * See StrFormatByteSizeW.
2313 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2315 WCHAR wszBuff[32];
2317 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2319 if (lpszDest)
2320 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2321 return lpszDest;
2324 /*************************************************************************
2325 * StrFormatByteSizeA [SHLWAPI.@]
2327 * Create a string containing an abbreviated byte count of up to 2^31-1.
2329 * PARAMS
2330 * dwBytes [I] Byte size to format
2331 * lpszDest [I] Destination for formatted string
2332 * cchMax [I] Size of lpszDest
2334 * RETURNS
2335 * lpszDest.
2337 * NOTES
2338 * The Ascii and Unicode versions of this function accept a different
2339 * integer type for dwBytes. See StrFormatByteSize64A().
2341 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2343 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2345 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2348 /*************************************************************************
2349 * @ [SHLWAPI.162]
2351 * Remove a hanging lead byte from the end of a string, if present.
2353 * PARAMS
2354 * lpStr [I] String to check for a hanging lead byte
2355 * size [I] Length of lpStr
2357 * RETURNS
2358 * Success: The new length of the string. Any hanging lead bytes are removed.
2359 * Failure: 0, if any parameters are invalid.
2361 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2363 if (lpStr && size)
2365 LPSTR lastByte = lpStr + size - 1;
2367 while(lpStr < lastByte)
2368 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2370 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2372 *lpStr = '\0';
2373 size--;
2375 return size;
2377 return 0;
2380 /*************************************************************************
2381 * @ [SHLWAPI.203]
2383 * Remove a single non-trailing ampersand ('&') from a string.
2385 * PARAMS
2386 * lpszStr [I/O] String to remove ampersand from.
2388 * RETURNS
2389 * The character after the first ampersand in lpszStr, or the first character
2390 * in lpszStr if there is no ampersand in the string.
2392 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2394 LPSTR lpszIter, lpszTmp;
2395 char ch;
2397 TRACE("(%s)\n", debugstr_a(lpszStr));
2399 ch = *lpszStr;
2401 if ((lpszIter = StrChrA(lpszStr, '&')))
2403 lpszTmp = CharNextA(lpszIter);
2404 if (lpszTmp && *lpszTmp)
2406 if (*lpszTmp != '&')
2407 ch = *lpszTmp;
2409 while (lpszIter && *lpszIter)
2411 lpszTmp = CharNextA(lpszIter);
2412 *lpszIter = *lpszTmp;
2413 lpszIter = lpszTmp;
2418 return ch;
2421 /*************************************************************************
2422 * @ [SHLWAPI.225]
2424 * Unicode version of SHStripMneumonicA.
2426 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2428 LPWSTR lpszIter, lpszTmp;
2429 WCHAR ch;
2431 TRACE("(%s)\n", debugstr_w(lpszStr));
2433 ch = *lpszStr;
2435 if ((lpszIter = StrChrW(lpszStr, '&')))
2437 lpszTmp = CharNextW(lpszIter);
2438 if (lpszTmp && *lpszTmp)
2440 if (*lpszTmp != '&')
2441 ch = *lpszTmp;
2443 while (lpszIter && *lpszIter)
2445 lpszTmp = CharNextW(lpszIter);
2446 *lpszIter = *lpszTmp;
2447 lpszIter = lpszTmp;
2452 return ch;
2455 /*************************************************************************
2456 * @ [SHLWAPI.216]
2458 * Convert an Ascii string to Unicode.
2460 * PARAMS
2461 * dwCp [I] Code page for the conversion
2462 * lpSrcStr [I] Source Ascii string to convert
2463 * lpDstStr [O] Destination for converted Unicode string
2464 * iLen [I] Length of lpDstStr
2466 * RETURNS
2467 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2469 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2471 DWORD dwRet;
2473 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2474 TRACE("%s->%s,ret=%ld\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2475 return dwRet;
2478 /*************************************************************************
2479 * @ [SHLWAPI.215]
2481 * Convert an Ascii string to Unicode.
2483 * PARAMS
2484 * lpSrcStr [I] Source Ascii string to convert
2485 * lpDstStr [O] Destination for converted Unicode string
2486 * iLen [I] Length of lpDstStr
2488 * RETURNS
2489 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2491 * NOTES
2492 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2494 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2496 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2499 /*************************************************************************
2500 * @ [SHLWAPI.218]
2502 * Convert a Unicode string to Ascii.
2504 * PARAMS
2505 * CodePage [I] Code page to use for the conversion
2506 * lpSrcStr [I] Source Unicode string to convert
2507 * lpDstStr [O] Destination for converted Ascii string
2508 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2510 * RETURNS
2511 * Success: The number of characters that result from the conversion.
2512 * Failure: 0.
2514 INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
2515 LPINT lpiLen)
2517 static const WCHAR emptyW[] = { '\0' };
2518 int len , reqLen;
2519 LPSTR mem;
2521 if (!lpDstStr || !lpiLen)
2522 return 0;
2524 if (!lpSrcStr)
2525 lpSrcStr = emptyW;
2527 *lpDstStr = '\0';
2529 len = strlenW(lpSrcStr) + 1;
2531 switch (CodePage)
2533 case CP_WINUNICODE:
2534 CodePage = CP_UTF8; /* Fall through... */
2535 case 0x0000C350: /* FIXME: CP_ #define */
2536 case CP_UTF7:
2537 case CP_UTF8:
2539 DWORD dwMode = 0;
2540 INT nWideCharCount = len - 1;
2542 GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0);
2543 if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
2544 lpiLen))
2545 return 0;
2547 if (nWideCharCount < len - 1)
2549 mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen);
2550 if (!mem)
2551 return 0;
2553 *lpiLen = 0;
2555 if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen))
2557 SHTruncateString(mem, *lpiLen);
2558 lstrcpynA(lpDstStr, mem, *lpiLen + 1);
2559 HeapFree(GetProcessHeap(), 0, mem);
2560 return *lpiLen + 1;
2562 HeapFree(GetProcessHeap(), 0, mem);
2563 return *lpiLen;
2565 lpDstStr[*lpiLen] = '\0';
2566 return *lpiLen;
2568 default:
2569 break;
2572 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
2573 *lpiLen, NULL, NULL);
2575 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2577 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2578 if (reqLen)
2580 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2581 if (mem)
2583 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2584 reqLen, NULL, NULL);
2586 reqLen = SHTruncateString(mem, *lpiLen);
2587 reqLen++;
2589 lstrcpynA(lpDstStr, mem, *lpiLen);
2591 HeapFree(GetProcessHeap(), 0, mem);
2595 return reqLen;
2598 /*************************************************************************
2599 * @ [SHLWAPI.217]
2601 * Convert a Unicode string to Ascii.
2603 * PARAMS
2604 * lpSrcStr [I] Source Unicode string to convert
2605 * lpDstStr [O] Destination for converted Ascii string
2606 * iLen [O] Length of lpDstStr in characters
2608 * RETURNS
2609 * See SHUnicodeToAnsiCP
2611 * NOTES
2612 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2614 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2616 INT myint = iLen;
2618 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
2621 /*************************************************************************
2622 * @ [SHLWAPI.345]
2624 * Copy one string to another.
2626 * PARAMS
2627 * lpszSrc [I] Source string to copy
2628 * lpszDst [O] Destination for copy
2629 * iLen [I] Length of lpszDst in characters
2631 * RETURNS
2632 * The length of the copied string, including the terminating NUL. lpszDst
2633 * contains iLen characters of lpszSrc.
2635 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2637 LPSTR lpszRet;
2639 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2641 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2642 return lpszRet - lpszDst + 1;
2645 /*************************************************************************
2646 * @ [SHLWAPI.346]
2648 * Unicode version of SSHAnsiToAnsi.
2650 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2652 LPWSTR lpszRet;
2654 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2656 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2657 return lpszRet - lpszDst + 1;
2660 /*************************************************************************
2661 * @ [SHLWAPI.364]
2663 * Determine if an Ascii string converts to Unicode and back identically.
2665 * PARAMS
2666 * lpSrcStr [I] Source Unicode string to convert
2667 * lpDst [O] Destination for resulting Ascii string
2668 * iLen [I] Length of lpDst in characters
2670 * RETURNS
2671 * TRUE, since Ascii strings always convert identically.
2673 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2675 lstrcpynA(lpDst, lpSrcStr, iLen);
2676 return TRUE;
2679 /*************************************************************************
2680 * @ [SHLWAPI.365]
2682 * Determine if a Unicode string converts to Ascii and back identically.
2684 * PARAMS
2685 * lpSrcStr [I] Source Unicode string to convert
2686 * lpDst [O] Destination for resulting Ascii string
2687 * iLen [I] Length of lpDst in characters
2689 * RETURNS
2690 * TRUE, if lpSrcStr converts to Ascii and back identically,
2691 * FALSE otherwise.
2693 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2695 WCHAR szBuff[MAX_PATH];
2697 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2698 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2699 return !strcmpW(lpSrcStr, szBuff);
2702 /*************************************************************************
2703 * SHLoadIndirectString [SHLWAPI.@]
2705 * If passed a string that begins with a '@' extract the string from the
2706 * appropriate resource, otherwise do a straight copy.
2709 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2711 WCHAR *dllname = NULL;
2712 HMODULE hmod = NULL;
2713 HRESULT hr = E_FAIL;
2715 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2717 if(src[0] == '@')
2719 WCHAR *index_str;
2720 int index;
2722 dst[0] = 0;
2723 dllname = StrDupW(src + 1);
2724 index_str = strchrW(dllname, ',');
2726 if(!index_str) goto end;
2728 *index_str = 0;
2729 index_str++;
2730 index = atoiW(index_str);
2732 hmod = LoadLibraryW(dllname);
2733 if(!hmod) goto end;
2735 if(index < 0)
2737 if(LoadStringW(hmod, -index, dst, dst_len))
2738 hr = S_OK;
2740 else
2741 FIXME("can't handle non-negative indicies (%d)\n", index);
2743 else
2745 if(dst != src)
2746 lstrcpynW(dst, src, dst_len);
2747 hr = S_OK;
2750 TRACE("returing %s\n", debugstr_w(dst));
2751 end:
2752 if(hmod) FreeLibrary(hmod);
2753 HeapFree(GetProcessHeap(), 0, dllname);
2754 return hr;