We can't cache the unscaled font's hfont, since the mapping mode may
[wine] / dlls / shlwapi / string.c
1 /*
2  * Shlwapi string functions
3  *
4  * Copyright 1998 Juergen Schmied
5  * Copyright 2002 Jon Griffiths
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <ctype.h>
26 #include <math.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "winerror.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wingdi.h"
35 #include "winuser.h"
36 #include "winreg.h"
37 #define NO_SHLWAPI_STREAM
38 #include "shlwapi.h"
39 #include "shlobj.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(shell);
44
45 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest);
46 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest);
47
48 /*************************************************************************
49  * SHLWAPI_ChrCmpHelperA
50  *
51  * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
52  *
53  * NOTES
54  *  Both this function and its Unicode counterpart are very inneficient. To
55  *  fix this, CompareString must be completely implemented and optimised
56  *  first. Then the core character test can be taken out of that function and
57  *  placed here, so that it need never be called at all. Until then, do not
58  *  attempt to optimise this code unless you are willing to test that it
59  *  still performs correctly.
60  */
61 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
62 {
63   char str1[3], str2[3];
64
65   str1[0] = LOBYTE(ch1);
66   if (IsDBCSLeadByte(ch1))
67   {
68     str1[1] = HIBYTE(ch1);
69     str1[2] = '\0';
70   }
71   else
72     str1[1] = '\0';
73
74   str2[0] = LOBYTE(ch2);
75   if (IsDBCSLeadByte(ch2))
76   {
77     str2[1] = HIBYTE(ch2);
78     str2[2] = '\0';
79   }
80   else
81     str2[1] = '\0';
82
83   return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
84 }
85
86 /*************************************************************************
87  * SHLWAPI_ChrCmpHelperW
88  *
89  * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
90  */
91 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
92 {
93   WCHAR str1[2], str2[2];
94
95   str1[0] = ch1;
96   str1[1] = '\0';
97   str2[0] = ch2;
98   str2[1] = '\0';
99   return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
100 }
101
102 /*************************************************************************
103  * SHLWAPI_ChrCmpA
104  *
105  * Internal helper function.
106  */
107 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
108 {
109   return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
110 }
111
112 /*************************************************************************
113  * ChrCmpIA     [SHLWAPI.385]
114  *
115  * Compare two characters, ignoring case.
116  *
117  * PARAMS
118  *  ch1 [I] First character to compare
119  *  ch2 [I] Second character to compare
120  *
121  * RETURNS
122  *  FALSE, if the characters are equal.
123  *  Non-zero otherwise.
124  */
125 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
126 {
127   TRACE("(%d,%d)\n", ch1, ch2);
128
129   return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
130 }
131
132 /*************************************************************************
133  * SHLWAPI_ChrCmpW
134  *
135  * Internal helper function.
136  */
137 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
138 {
139   return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
140 }
141
142 /*************************************************************************
143  * ChrCmpIW     [SHLWAPI.386]
144  *
145  * See ChrCmpIA.
146  */
147 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
148 {
149   return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
150 }
151
152 /*************************************************************************
153  * StrChrA      [SHLWAPI.@]
154  *
155  * Find a given character in a string.
156  *
157  * PARAMS
158  *  lpszStr [I] String to search in.
159  *  ch      [I] Character to search for.
160  *
161  * RETURNS
162  *  Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
163  *           not found.
164  *  Failure: NULL, if any arguments are invalid.
165  */
166 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
167 {
168   TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
169
170   if (lpszStr)
171   {
172     while (*lpszStr)
173     {
174       if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
175         return (LPSTR)lpszStr;
176       lpszStr = CharNextA(lpszStr);
177     }
178   }
179   return NULL;
180 }
181
182 /*************************************************************************
183  * StrChrW      [SHLWAPI.@]
184  *
185  * See StrChrA.
186  */
187 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
188 {
189   LPWSTR lpszRet = NULL;
190
191   TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
192
193   if (lpszStr)
194     lpszRet = strchrW(lpszStr, ch);
195   return lpszRet;
196 }
197
198 /*************************************************************************
199  * StrChrIA     [SHLWAPI.@]
200  *
201  * Find a given character in a string, ignoring case.
202  *
203  * PARAMS
204  *  lpszStr [I] String to search in.
205  *  ch      [I] Character to search for.
206  *
207  * RETURNS
208  *  Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
209  *           not found.
210  *  Failure: NULL, if any arguments are invalid.
211  */
212 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
213 {
214   TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
215
216   if (lpszStr)
217   {
218     while (*lpszStr)
219     {
220       if (!ChrCmpIA(*lpszStr, ch))
221         return (LPSTR)lpszStr;
222       lpszStr = CharNextA(lpszStr);
223     }
224   }
225   return NULL;
226 }
227
228 /*************************************************************************
229  * StrChrIW     [SHLWAPI.@]
230  *
231  * See StrChrA.
232  */
233 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
234 {
235   TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
236
237   if (lpszStr)
238   {
239     ch = toupperW(ch);
240     while (*lpszStr)
241     {
242       if (toupperW(*lpszStr) == ch)
243         return (LPWSTR)lpszStr;
244       lpszStr = CharNextW(lpszStr);
245     }
246     lpszStr = NULL;
247   }
248   return (LPWSTR)lpszStr;
249 }
250
251 /*************************************************************************
252  * StrCmpIW     [SHLWAPI.@]
253  *
254  * Compare two strings, ignoring case.
255  *
256  * PARAMS
257  *  lpszStr  [I] First string to compare
258  *  lpszComp [I] Second string to compare
259  *
260  * RETURNS
261  *  An integer less than, equal to or greater than 0, indicating that
262  *  lpszStr is less than, the same, or greater than lpszComp.
263  */
264 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
265 {
266   INT iRet;
267
268   TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
269
270   iRet = strcmpiW(lpszStr, lpszComp);
271   return iRet < 0 ? -1 : iRet ? 1 : 0;
272 }
273
274 /*************************************************************************
275  * SHLWAPI_StrCmpNHelperA
276  *
277  * Internal helper for StrCmpNA/StrCmpNIA.
278  */
279 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
280                                          INT iLen,
281                                          BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
282 {
283   if (!lpszStr)
284   {
285     if (!lpszComp)
286       return 0;
287     return 1;
288   }
289   else if (!lpszComp)
290     return -1;
291
292   while (iLen-- > 0)
293   {
294     int iDiff;
295     WORD ch1, ch2;
296
297     ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
298     ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
299
300     if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
301       return -1;
302     else if (iDiff > 0)
303       return 1;
304     else if (!*lpszStr && !*lpszComp)
305       return 0;
306
307     lpszStr = CharNextA(lpszStr);
308     lpszComp = CharNextA(lpszComp);
309   }
310   return 0;
311 }
312
313 /*************************************************************************
314  * StrCmpNA     [SHLWAPI.@]
315  *
316  * Compare two strings, up to a maximum length.
317  *
318  * PARAMS
319  *  lpszStr  [I] First string to compare
320  *  lpszComp [I] Second string to compare
321  *  iLen     [I] Maximum number of chars to compare.
322  *
323  * RETURNS
324  *  An integer less than, equal to or greater than 0, indicating that
325  *  lpszStr is less than, the same, or greater than lpszComp.
326  */
327 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
328 {
329   TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
330
331   return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
332 }
333
334 /*************************************************************************
335  * StrCmpNW     [SHLWAPI.@]
336  *
337  * See StrCmpNA.
338  */
339 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
340 {
341   INT iRet;
342
343   TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
344
345   iRet = strncmpW(lpszStr, lpszComp, iLen);
346   return iRet < 0 ? -1 : iRet ? 1 : 0;
347 }
348
349 /*************************************************************************
350  * StrCmpNIA    [SHLWAPI.@]
351  *
352  * Compare two strings, up to a maximum length, ignoring case.
353  *
354  * PARAMS
355  *  lpszStr  [I] First string to compare
356  *  lpszComp [I] Second string to compare
357  *  iLen     [I] Maximum number of chars to compare.
358  *
359  * RETURNS
360  *  An integer less than, equal to or greater than 0, indicating that
361  *  lpszStr is less than, the same, or greater than lpszComp.
362  *
363  * NOTES
364  *  The Win32 version of this function is _completely_ broken for cases
365  *  where iLen is greater than the length of lpszComp. Examples:
366  *
367  *  StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
368  *  StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
369  *  StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
370  *
371  *  This implementation behaves correctly, since it is unlikely any
372  *  applications actually rely on this function being broken.
373  */
374 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
375 {
376   TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
377
378   return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
379 }
380
381 /*************************************************************************
382  * StrCmpNIW    [SHLWAPI.@]
383  *
384  * See StrCmpNIA.
385  */
386 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
387 {
388   INT iRet;
389
390   TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
391
392   iRet = strncmpiW(lpszStr, lpszComp, iLen);
393   return iRet < 0 ? -1 : iRet ? 1 : 0;
394 }
395
396 /*************************************************************************
397  * StrCmpW      [SHLWAPI.@]
398  *
399  * Compare two strings.
400  *
401  * PARAMS
402  *  lpszStr  [I] First string to compare
403  *  lpszComp [I] Second string to compare
404  *
405  * RETURNS
406  *  An integer less than, equal to or greater than 0, indicating that
407  *  lpszStr is less than, the same, or greater than lpszComp.
408  */
409 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
410 {
411   INT iRet;
412
413   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
414
415   iRet = strcmpW(lpszStr, lpszComp);
416   return iRet < 0 ? -1 : iRet ? 1 : 0;
417 }
418
419 /*************************************************************************
420  * StrCatW      [SHLWAPI.@]
421  *
422  * Concatanate two strings.
423  *
424  * PARAMS
425  *  lpszStr [O] Initial string
426  *  lpszSrc [I] String to concatanate
427  *
428  * RETURNS
429  *  lpszStr.
430  */
431 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
432 {
433   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
434
435   strcatW(lpszStr, lpszSrc);
436   return lpszStr;
437 }
438
439 /*************************************************************************
440  * StrCpyW      [SHLWAPI.@]
441  *
442  * Copy a string to another string.
443  *
444  * PARAMS
445  *  lpszStr [O] Destination string
446  *  lpszSrc [I] Source string
447  *
448  * RETURNS
449  *  lpszStr.
450  */
451 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
452 {
453   TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
454
455   strcpyW(lpszStr, lpszSrc);
456   return lpszStr;
457 }
458
459 /*************************************************************************
460  * StrCpyNW     [SHLWAPI.@]
461  *
462  * Copy a string to another string, up to a maximum number of characters.
463  *
464  * PARAMS
465  *  lpszStr  [O] Destination string
466  *  lpszSrc  [I] Source string
467  *  iLen     [I] Maximum number of chars to copy
468  *
469  * RETURNS
470  *  lpszStr.
471  */
472 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
473 {
474   TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
475
476   lstrcpynW(lpszStr, lpszSrc, iLen);
477   return lpszStr;
478 }
479
480
481
482 /*************************************************************************
483  * SHLWAPI_StrStrHelperA
484  *
485  * Internal implementation of StrStrA/StrStrIA
486  */
487 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
488                                          int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
489 {
490   size_t iLen;
491
492   if (!lpszStr || !lpszSearch || !*lpszSearch)
493     return NULL;
494
495   iLen = strlen(lpszSearch);
496
497   while (*lpszStr)
498   {
499     if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
500       return (LPSTR)lpszStr;
501     lpszStr = CharNextA(lpszStr);
502   }
503   return NULL;
504 }
505
506 /*************************************************************************
507  * SHLWAPI_StrStrHelperW
508  *
509  * Internal implementation of StrStrW/StrStrIW
510  */
511 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
512                                           int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
513 {
514   int iLen;
515
516   if (!lpszStr || !lpszSearch || !*lpszSearch)
517     return NULL;
518
519   iLen = strlenW(lpszSearch);
520
521   while (*lpszStr)
522   {
523     if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
524       return (LPWSTR)lpszStr;
525     lpszStr = CharNextW(lpszStr);
526   }
527   return NULL;
528 }
529
530 /*************************************************************************
531  * StrStrA      [SHLWAPI.@]
532  *
533  * Find a substring within a string.
534  *
535  * PARAMS
536  *  lpszStr    [I] String to search in
537  *  lpszSearch [I] String to look for
538  *
539  * RETURNS
540  *  The start of lpszSearch within lpszStr, or NULL if not found.
541  */
542 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
543 {
544   TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
545
546   return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
547 }
548
549 /*************************************************************************
550  * StrStrW      [SHLWAPI.@]
551  *
552  * See StrStrA.
553  */
554 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
555 {
556   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
557
558   return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
559 }
560
561 /*************************************************************************
562  * StrRStrIA    [SHLWAPI.@]
563  *
564  * Find the last occurence of a substring within a string.
565  *
566  * PARAMS
567  *  lpszStr    [I] String to search in
568  *  lpszEnd    [I] End of lpszStr
569  *  lpszSearch [I] String to look for
570  *
571  * RETURNS
572  *  The last occurence lpszSearch within lpszStr, or NULL if not found.
573  */
574 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
575 {
576   LPSTR lpszRet = NULL;
577   WORD ch1, ch2;
578   INT iLen;
579
580   TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
581
582   if (!lpszStr || !lpszSearch || !*lpszSearch)
583     return NULL;
584
585   if (!lpszEnd)
586     lpszEnd = lpszStr + lstrlenA(lpszStr);
587
588   if (IsDBCSLeadByte(*lpszSearch))
589     ch1 = *lpszSearch << 8 | lpszSearch[1];
590   else
591     ch1 = *lpszSearch;
592   iLen = lstrlenA(lpszSearch);
593
594   while (lpszStr <= lpszEnd  && *lpszStr)
595   {
596     ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
597     if (!ChrCmpIA(ch1, ch2))
598     {
599       if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
600         lpszRet = (LPSTR)lpszStr;
601     }
602     lpszStr = CharNextA(lpszStr);
603   }
604   return lpszRet;
605 }
606
607 /*************************************************************************
608  * StrRStrIW    [SHLWAPI.@]
609  *
610  * See StrRStrIA.
611  */
612 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
613 {
614   LPWSTR lpszRet = NULL;
615   INT iLen;
616
617   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
618
619   if (!lpszStr || !lpszSearch || !*lpszSearch)
620     return NULL;
621
622   if (!lpszEnd)
623     lpszEnd = lpszStr + strlenW(lpszStr);
624
625   iLen = strlenW(lpszSearch);
626
627   while (lpszStr <= lpszEnd  && *lpszStr)
628   {
629     if (!ChrCmpIA(*lpszSearch, *lpszStr))
630     {
631       if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
632         lpszRet = (LPWSTR)lpszStr;
633     }
634     lpszStr = CharNextW(lpszStr);
635   }
636   return lpszRet;
637 }
638
639 /*************************************************************************
640  * StrStrIA     [SHLWAPI.@]
641  *
642  * Find a substring within a string, ignoring case.
643  *
644  * PARAMS
645  *  lpszStr    [I] String to search in
646  *  lpszSearch [I] String to look for
647  *
648  * RETURNS
649  *  The start of lpszSearch within lpszStr, or NULL if not found.
650  */
651 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
652 {
653   TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
654
655   return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
656 }
657
658 /*************************************************************************
659  * StrStrIW     [SHLWAPI.@]
660  *
661  * See StrStrIA.
662  */
663 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
664 {
665   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
666
667   return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
668 }
669
670 /*************************************************************************
671  * StrToIntA    [SHLWAPI.@]
672  *
673  * Read an integer from a string.
674  *
675  * PARAMS
676  *  lpszStr [I] String to read integer from
677  *
678  * RETURNS
679  *   The integer value represented by the string, or 0 if no integer is
680  *   present.
681  *
682  * NOTES
683  *  No leading space is allowed before the number, although a leading '-' is.
684  */
685 int WINAPI StrToIntA(LPCSTR lpszStr)
686 {
687   int iRet = 0;
688
689   TRACE("(%s)\n", debugstr_a(lpszStr));
690
691   if (!lpszStr)
692   {
693     WARN("Invalid lpszStr would crash under Win32!\n");
694     return 0;
695   }
696
697   if (*lpszStr == '-' || isdigit(*lpszStr))
698     StrToIntExA(lpszStr, 0, &iRet);
699   return iRet;
700 }
701
702 /*************************************************************************
703  * StrToIntW    [SHLWAPI.@]
704  *
705  * See StrToIntA.
706  */
707 int WINAPI StrToIntW(LPCWSTR lpszStr)
708 {
709   int iRet = 0;
710
711   TRACE("(%s)\n", debugstr_w(lpszStr));
712
713   if (!lpszStr)
714   {
715     WARN("Invalid lpszStr would crash under Win32!\n");
716     return 0;
717   }
718
719   if (*lpszStr == '-' || isdigitW(*lpszStr))
720     StrToIntExW(lpszStr, 0, &iRet);
721   return iRet;
722 }
723
724 /*************************************************************************
725  * StrToIntExA  [SHLWAPI.@]
726  *
727  * Read an integer from a string.
728  *
729  * PARAMS
730  *  lpszStr [I] String to read integer from
731  *  dwFlags [I] Flags controlling the conversion
732  *  lpiRet  [O] Destination for read integer.
733  *
734  * RETURNS
735  *  Success: TRUE. lpiRet contains the integer value represented by the string.
736  *  Failure: FALSE, if the string is invalid, or no number is present.
737  *
738  * NOTES
739  *  Leading whitespace, '-' and '+' are allowed before the number. If
740  *  dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
741  *  preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
742  *  the string is treated as a decimal string. A leading '-' is ignored for
743  *  hexidecimal numbers.
744  */
745 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
746 {
747   BOOL bNegative = FALSE;
748   int iRet = 0;
749
750   TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
751
752   if (!lpszStr || !lpiRet)
753   {
754     WARN("Invalid parameter would crash under Win32!\n");
755     return FALSE;
756   }
757   if (dwFlags > STIF_SUPPORT_HEX)
758   {
759     WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
760   }
761
762   /* Skip leading space, '+', '-' */
763   while (isspace(*lpszStr))
764     lpszStr = CharNextA(lpszStr);
765
766   if (*lpszStr == '-')
767   {
768     bNegative = TRUE;
769     lpszStr++;
770   }
771   else if (*lpszStr == '+')
772     lpszStr++;
773
774   if (dwFlags & STIF_SUPPORT_HEX &&
775       *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
776   {
777     /* Read hex number */
778     lpszStr += 2;
779
780     if (!isxdigit(*lpszStr))
781       return FALSE;
782
783     while (isxdigit(*lpszStr))
784     {
785       iRet = iRet * 16;
786       if (isdigit(*lpszStr))
787         iRet += (*lpszStr - '0');
788       else
789         iRet += 10 + (tolower(*lpszStr) - 'a');
790       lpszStr++;
791     }
792     *lpiRet = iRet;
793     return TRUE;
794   }
795
796   /* Read decimal number */
797   if (!isdigit(*lpszStr))
798     return FALSE;
799
800   while (isdigit(*lpszStr))
801   {
802     iRet = iRet * 10;
803     iRet += (*lpszStr - '0');
804     lpszStr++;
805   }
806   *lpiRet = bNegative ? -iRet : iRet;
807   return TRUE;
808 }
809
810 /*************************************************************************
811  * StrToIntExW  [SHLWAPI.@]
812  *
813  * See StrToIntExA.
814  */
815 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
816 {
817   BOOL bNegative = FALSE;
818   int iRet = 0;
819
820   TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
821
822   if (!lpszStr || !lpiRet)
823   {
824     WARN("Invalid parameter would crash under Win32!\n");
825     return FALSE;
826   }
827   if (dwFlags > STIF_SUPPORT_HEX)
828   {
829     WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
830   }
831
832   /* Skip leading space, '+', '-' */
833   while (isspaceW(*lpszStr))
834     lpszStr = CharNextW(lpszStr);
835
836   if (*lpszStr == '-')
837   {
838     bNegative = TRUE;
839     lpszStr++;
840   }
841   else if (*lpszStr == '+')
842     lpszStr++;
843
844   if (dwFlags & STIF_SUPPORT_HEX &&
845       *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
846   {
847     /* Read hex number */
848     lpszStr += 2;
849
850     if (!isxdigitW(*lpszStr))
851       return FALSE;
852
853     while (isxdigitW(*lpszStr))
854     {
855       iRet = iRet * 16;
856       if (isdigitW(*lpszStr))
857         iRet += (*lpszStr - '0');
858       else
859         iRet += 10 + (tolowerW(*lpszStr) - 'a');
860       lpszStr++;
861     }
862     *lpiRet = iRet;
863     return TRUE;
864   }
865
866   /* Read decimal number */
867   if (!isdigitW(*lpszStr))
868     return FALSE;
869
870   while (isdigitW(*lpszStr))
871   {
872     iRet = iRet * 10;
873     iRet += (*lpszStr - '0');
874     lpszStr++;
875   }
876   *lpiRet = bNegative ? -iRet : iRet;
877   return TRUE;
878 }
879
880 /*************************************************************************
881  * StrDupA      [SHLWAPI.@]
882  *
883  * Duplicate a string.
884  *
885  * PARAMS
886  *  lpszStr [I] String to duplicate.
887  *
888  * RETURNS
889  *  Success: A pointer to a new string containing the contents of lpszStr
890  *  Failure: NULL, if memory cannot be allocated
891  *
892  * NOTES
893  *  The string memory is allocated with LocalAlloc, and so should be released
894  *  by calling LocalFree.
895  */
896 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
897 {
898   int iLen;
899   LPSTR lpszRet;
900
901   TRACE("(%s)\n",debugstr_a(lpszStr));
902
903   iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
904   lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
905
906   if (lpszRet)
907   {
908     if (lpszStr)
909       memcpy(lpszRet, lpszStr, iLen);
910     else
911       *lpszRet = '\0';
912   }
913   return lpszRet;
914 }
915
916 /*************************************************************************
917  * StrDupW      [SHLWAPI.@]
918  *
919  * See StrDupA.
920  */
921 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
922 {
923   int iLen;
924   LPWSTR lpszRet;
925
926   TRACE("(%s)\n",debugstr_w(lpszStr));
927
928   iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
929   lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
930
931   if (lpszRet)
932   {
933     if (lpszStr)
934       memcpy(lpszRet, lpszStr, iLen);
935     else
936       *lpszRet = '\0';
937   }
938   return lpszRet;
939 }
940
941 /*************************************************************************
942  * SHLWAPI_StrSpnHelperA
943  *
944  * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
945  */
946 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
947                                         LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
948                                         BOOL bInvert)
949 {
950   LPCSTR lpszRead = lpszStr;
951   if (lpszStr && *lpszStr && lpszMatch)
952   {
953     while (*lpszRead)
954     {
955       LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
956
957       if (!bInvert && !lpszTest)
958         break;
959       if (bInvert && lpszTest)
960         break;
961       lpszRead = CharNextA(lpszRead);
962     };
963   }
964   return lpszRead - lpszStr;
965 }
966
967 /*************************************************************************
968  * SHLWAPI_StrSpnHelperW
969  *
970  * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
971  */
972 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
973                                       LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
974                                       BOOL bInvert)
975 {
976   LPCWSTR lpszRead = lpszStr;
977   if (lpszStr && *lpszStr && lpszMatch)
978   {
979     while (*lpszRead)
980     {
981       LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
982
983       if (!bInvert && !lpszTest)
984         break;
985       if (bInvert && lpszTest)
986         break;
987       lpszRead = CharNextW(lpszRead);
988     };
989   }
990   return lpszRead - lpszStr;
991 }
992
993 /*************************************************************************
994  * StrSpnA      [SHLWAPI.@]
995  *
996  * Find the length of the start of a string that contains only certain
997  * characters.
998  *
999  * PARAMS
1000  *  lpszStr   [I] String to search
1001  *  lpszMatch [I] Characters that can be in the substring
1002  *
1003  * RETURNS
1004  *  The length of the part of lpszStr containing only chars from lpszMatch,
1005  *  or 0 if any parameter is invalid.
1006  */
1007 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1008 {
1009   TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1010
1011   return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1012 }
1013
1014 /*************************************************************************
1015  * StrSpnW      [SHLWAPI.@]
1016  *
1017  * See StrSpnA.
1018  */
1019 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1020 {
1021   TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1022
1023   return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1024 }
1025
1026 /*************************************************************************
1027  * StrCSpnA     [SHLWAPI.@]
1028  *
1029  * Find the length of the start of a string that does not contain certain
1030  * characters.
1031  *
1032  * PARAMS
1033  *  lpszStr   [I] String to search
1034  *  lpszMatch [I] Characters that cannot be in the substring
1035  *
1036  * RETURNS
1037  *  The length of the part of lpszStr containing only chars not in lpszMatch,
1038  *  or 0 if any parameter is invalid.
1039  */
1040 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1041 {
1042   TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1043
1044   return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1045 }
1046
1047 /*************************************************************************
1048  * StrCSpnW     [SHLWAPI.@]
1049  *
1050  * See StrCSpnA.
1051  */
1052 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1053 {
1054   TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1055
1056   return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1057 }
1058
1059 /*************************************************************************
1060  * StrCSpnIA    [SHLWAPI.@]
1061  *
1062  * Find the length of the start of a string that does not contain certain
1063  * characters, ignoring case.
1064  *
1065  * PARAMS
1066  *  lpszStr   [I] String to search
1067  *  lpszMatch [I] Characters that cannot be in the substring
1068  *
1069  * RETURNS
1070  *  The length of the part of lpszStr containing only chars not in lpszMatch,
1071  *  or 0 if any parameter is invalid.
1072  */
1073 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1074 {
1075   TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1076
1077   return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1078 }
1079
1080 /*************************************************************************
1081  * StrCSpnIW    [SHLWAPI.@]
1082  *
1083  * See StrCSpnIA.
1084  */
1085 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1086 {
1087   TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1088
1089   return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1090 }
1091
1092 /*************************************************************************
1093  * StrPBrkA     [SHLWAPI.@]
1094  *
1095  * Search a string for any of a group of characters.
1096  *
1097  * PARAMS
1098  *  lpszStr   [I] String to search
1099  *  lpszMatch [I] Characters to match
1100  *
1101  * RETURNS
1102  *  A pointer to the first matching character in lpszStr, or NULL if no
1103  *  match was found.
1104  */
1105 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1106 {
1107   TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1108
1109   if (lpszStr && lpszMatch && *lpszMatch)
1110   {
1111     while (*lpszStr)
1112     {
1113       if (StrChrA(lpszMatch, *lpszStr))
1114         return (LPSTR)lpszStr;
1115       lpszStr = CharNextA(lpszStr);
1116     };
1117   }
1118   return NULL;
1119 }
1120
1121 /*************************************************************************
1122  * StrPBrkW     [SHLWAPI.@]
1123  *
1124  * See StrPBrkA.
1125  */
1126 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1127 {
1128   TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1129
1130   if (lpszStr && lpszMatch && *lpszMatch)
1131   {
1132     while (*lpszStr);
1133     {
1134       if (StrChrW(lpszMatch, *lpszStr))
1135         return (LPWSTR)lpszStr;
1136       lpszStr = CharNextW(lpszStr);
1137     } while (*lpszStr);
1138   }
1139   return NULL;
1140 }
1141
1142 /*************************************************************************
1143  * SHLWAPI_StrRChrHelperA
1144  *
1145  * Internal implementation of StrRChrA/StrRChrIA.
1146  */
1147 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1148                                            LPCSTR lpszEnd, WORD ch,
1149                                            BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1150 {
1151   LPCSTR lpszRet = NULL;
1152
1153   if (lpszStr)
1154   {
1155     WORD ch2;
1156
1157     if (!lpszEnd)
1158       lpszEnd = lpszStr + lstrlenA(lpszStr);
1159
1160     while (*lpszStr && lpszStr <= lpszEnd)
1161     {
1162       ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1163
1164       if (!pChrCmpFn(ch, ch2))
1165         lpszRet = lpszStr;
1166       lpszStr = CharNextA(lpszStr);
1167     }
1168   }
1169   return (LPSTR)lpszRet;
1170 }
1171
1172 /*************************************************************************
1173  * SHLWAPI_StrRChrHelperW
1174  *
1175  * Internal implementation of StrRChrW/StrRChrIW.
1176  */
1177 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1178                                          LPCWSTR lpszEnd, WCHAR ch,
1179                                          BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1180 {
1181   LPCWSTR lpszRet = NULL;
1182
1183   if (lpszStr)
1184   {
1185     if (!lpszEnd)
1186       lpszEnd = lpszStr + strlenW(lpszStr);
1187
1188     while (*lpszStr && lpszStr <= lpszEnd)
1189     {
1190       if (!pChrCmpFn(ch, *lpszStr))
1191         lpszRet = lpszStr;
1192       lpszStr = CharNextW(lpszStr);
1193     }
1194   }
1195   return (LPWSTR)lpszRet;
1196 }
1197
1198 /**************************************************************************
1199  * StrRChrA     [SHLWAPI.@]
1200  *
1201  * Find the last occurence of a character in string.
1202  *
1203  * PARAMS
1204  *  lpszStr [I] String to search in
1205  *  lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1206  *  ch      [I] Character to search for.
1207  *
1208  * RETURNS
1209  *  Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1210  *           or NULL if not found.
1211  *  Failure: NULL, if any arguments are invalid.
1212  */
1213 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1214 {
1215   TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1216
1217   return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1218 }
1219
1220 /**************************************************************************
1221  * StrRChrW     [SHLWAPI.@]
1222  *
1223  * See StrRChrA.
1224  */
1225 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1226 {
1227   TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1228
1229   return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1230 }
1231
1232 /**************************************************************************
1233  * StrRChrIA    [SHLWAPI.@]
1234  *
1235  * Find the last occurence of a character in string, ignoring case.
1236  *
1237  * PARAMS
1238  *  lpszStr [I] String to search in
1239  *  lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1240  *  ch      [I] Character to search for.
1241  *
1242  * RETURNS
1243  *  Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1244  *           or NULL if not found.
1245  *  Failure: NULL, if any arguments are invalid.
1246  */
1247 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1248 {
1249   TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1250
1251   return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1252 }
1253
1254 /**************************************************************************
1255  * StrRChrIW    [SHLWAPI.@]
1256  *
1257  * See StrRChrIA.
1258  */
1259 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1260 {
1261   TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1262
1263   return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1264 }
1265
1266 /*************************************************************************
1267  * StrCatBuffA  [SHLWAPI.@]
1268  *
1269  * Concatenate two strings together.
1270  *
1271  * PARAMS
1272  *  lpszStr [O] String to concatenate to
1273  *  lpszCat [I] String to add to lpszCat
1274  *  cchMax  [I] Maximum number of characters for the whole string
1275  *
1276  * RETURNS
1277  *  lpszStr.
1278  *
1279  * NOTES
1280  *  cchMax dtermines the number of characters in the final length of the
1281  *  string, not the number appended to lpszStr from lpszCat.
1282  */
1283 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1284 {
1285   INT iLen;
1286
1287   TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1288
1289   if (!lpszStr)
1290   {
1291     WARN("Invalid lpszStr would crash under Win32!\n");
1292     return NULL;
1293   }
1294
1295   iLen = strlen(lpszStr);
1296   cchMax -= iLen;
1297
1298   if (cchMax > 0)
1299     StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1300   return lpszStr;
1301 }
1302
1303 /*************************************************************************
1304  * StrCatBuffW  [SHLWAPI.@]
1305  *
1306  * See StrCatBuffA.
1307  */
1308 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1309 {
1310   INT iLen;
1311
1312   TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1313
1314   if (!lpszStr)
1315   {
1316     WARN("Invalid lpszStr would crash under Win32!\n");
1317     return NULL;
1318   }
1319
1320   iLen = strlenW(lpszStr);
1321   cchMax -= iLen;
1322
1323   if (cchMax > 0)
1324     StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1325   return lpszStr;
1326 }
1327
1328 /*************************************************************************
1329  * StrRetToBufA                                 [SHLWAPI.@]
1330  *
1331  * Convert a STRRET to a normal string.
1332  *
1333  * PARAMS
1334  *  lpStrRet [O] STRRET to convert
1335  *  pIdl     [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1336  *  lpszDest [O] Destination for normal string
1337  *  dwLen    [I] Length of lpszDest
1338  *
1339  * RETURNS
1340  *  Success: S_OK. lpszDest contains up to dwLen characters of the string.
1341  *           If lpStrRet is of type STRRET_WSTR, its memory is freed with
1342  *           CoTaskMemFree and its type set to STRRET_CSTRA.
1343  *  Failure: E_FAIL, if any parameters are invalid.
1344  */
1345 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1346 {
1347         /* NOTE:
1348          *  This routine is identical to that in dlls/shell32/shellstring.c.
1349          *  It was duplicated because not every version of Shlwapi.dll exports
1350          *  StrRetToBufA. If you change one routine, change them both.
1351          */
1352         TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1353
1354         if (!src)
1355         {
1356           WARN("Invalid lpStrRet would crash under Win32!\n");
1357           if (dest)
1358             *dest = '\0';
1359           return E_FAIL;
1360         }
1361
1362         if (!dest || !len)
1363           return E_FAIL;
1364
1365         *dest = '\0';
1366
1367         switch (src->uType)
1368         {
1369           case STRRET_WSTR:
1370             WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1371             CoTaskMemFree(src->u.pOleStr);
1372             break;
1373
1374           case STRRET_CSTR:
1375             lstrcpynA((LPSTR)dest, src->u.cStr, len);
1376             break;
1377
1378           case STRRET_OFFSET:
1379             lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1380             break;
1381
1382           default:
1383             FIXME("unknown type!\n");
1384             return FALSE;
1385         }
1386         return S_OK;
1387 }
1388
1389 /*************************************************************************
1390  * StrRetToBufW [SHLWAPI.@]
1391  *
1392  * See StrRetToBufA.
1393  */
1394 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1395 {
1396         TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1397
1398         if (!src)
1399         {
1400           WARN("Invalid lpStrRet would crash under Win32!\n");
1401           if (dest)
1402             *dest = '\0';
1403           return E_FAIL;
1404         }
1405
1406         if (!dest || !len)
1407           return E_FAIL;
1408
1409         *dest = '\0';
1410
1411         switch (src->uType)
1412         {
1413           case STRRET_WSTR:
1414             lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1415             CoTaskMemFree(src->u.pOleStr);
1416             break;
1417
1418           case STRRET_CSTR:
1419               if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1420                   dest[len-1] = 0;
1421             break;
1422
1423           case STRRET_OFFSET:
1424             if (pidl)
1425             {
1426               if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1427                                         dest, len ) && len)
1428                   dest[len-1] = 0;
1429             }
1430             break;
1431
1432           default:
1433             FIXME("unknown type!\n");
1434             return FALSE;
1435         }
1436         return S_OK;
1437 }
1438
1439 /*************************************************************************
1440  * StrRetToStrA                                 [SHLWAPI.@]
1441  *
1442  * converts a STRRET to a normal string
1443  */
1444 HRESULT WINAPI StrRetToStrA(LPSTRRET pstr, const ITEMIDLIST * pidl, LPSTR* ppszName)
1445 {
1446         HRESULT ret = E_FAIL;
1447
1448         switch (pstr->uType) {
1449             case STRRET_WSTR:
1450                 ret = _SHStrDupAW(pstr->u.pOleStr, ppszName);
1451                 CoTaskMemFree(pstr->u.pOleStr);
1452                 break;
1453
1454             case STRRET_CSTR:
1455                 ret = _SHStrDupAA(pstr->u.cStr, ppszName);
1456                 break;
1457
1458             case STRRET_OFFSET:
1459                 ret = _SHStrDupAA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1460                 break;
1461
1462             default:
1463                 *ppszName = NULL;
1464         }
1465         return ret;
1466 }
1467
1468 /*************************************************************************
1469  * StrRetToStrW                                 [SHLWAPI.@]
1470  *
1471  * converts a STRRET to a normal string
1472  */
1473 HRESULT WINAPI StrRetToStrW(LPSTRRET pstr, const ITEMIDLIST * pidl, LPWSTR* ppszName)
1474 {
1475         HRESULT ret = E_FAIL;
1476
1477         switch (pstr->uType) {
1478             case STRRET_WSTR:
1479                 ret = SHStrDupW(pstr->u.pOleStr, ppszName);
1480                 CoTaskMemFree(pstr->u.pOleStr);
1481                 break;
1482
1483             case STRRET_CSTR:
1484                 ret = SHStrDupA(pstr->u.cStr, ppszName);
1485                 break;
1486
1487             case STRRET_OFFSET:
1488                 ret = SHStrDupA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1489                 break;
1490
1491             default:
1492                 *ppszName = NULL;
1493         }
1494         return ret;
1495 }
1496
1497 /*************************************************************************
1498  * StrFormatKBSizeA     [SHLWAPI.@]
1499  *
1500  * Create a formatted string containing a byte count in Kilobytes.
1501  *
1502  * PARAMS
1503  *  llBytes  [I] Byte size to format
1504  *  lpszDest [I] Destination for formatted string
1505  *  cchMax   [I] Size of lpszDest
1506  *
1507  * RETURNS
1508  *  lpszDest.
1509  */
1510 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1511 {
1512   char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1513   LONGLONG ulKB = (llBytes + 1023) >> 10;
1514
1515   TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1516
1517   *szOut-- = '\0';
1518   *szOut-- = 'B';
1519   *szOut-- = 'K';
1520   *szOut-- = ' ';
1521
1522   do
1523   {
1524     LONGLONG ulNextDigit = ulKB % 10;
1525     *szOut-- = '0' + ulNextDigit;
1526     ulKB = (ulKB - ulNextDigit) / 10;
1527   } while (ulKB > 0);
1528
1529   strncpy(lpszDest, szOut + 1, cchMax);
1530   return lpszDest;
1531 }
1532
1533 /*************************************************************************
1534  * StrFormatKBSizeW     [SHLWAPI.@]
1535  *
1536  * See StrFormatKBSizeA.
1537  */
1538 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1539 {
1540   WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1541   LONGLONG ulKB = (llBytes + 1023) >> 10;
1542
1543   TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1544
1545   *szOut-- = '\0';
1546   *szOut-- = 'B';
1547   *szOut-- = 'K';
1548   *szOut-- = ' ';
1549
1550   do
1551   {
1552     LONGLONG ulNextDigit = ulKB % 10;
1553     *szOut-- = '0' + ulNextDigit;
1554     ulKB = (ulKB - ulNextDigit) / 10;
1555   } while (ulKB > 0);
1556
1557   strncpyW(lpszDest, szOut + 1, cchMax);
1558   return lpszDest;
1559 }
1560
1561 /*************************************************************************
1562  * StrNCatA     [SHLWAPI.@]
1563  *
1564  * Concatenate two strings together.
1565  *
1566  * PARAMS
1567  *  lpszStr [O] String to concatenate to
1568  *  lpszCat [I] String to add to lpszCat
1569  *  cchMax  [I] Maximum number of characters to concatenate
1570  *
1571  * RETURNS
1572  *  lpszStr.
1573  *
1574  * NOTES
1575  *  cchMax dtermines the number of characters that are appended to lpszStr,
1576  *  not the total length of the string.
1577  */
1578 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1579 {
1580   LPSTR lpszRet = lpszStr;
1581
1582   TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1583
1584   if (!lpszStr)
1585   {
1586     WARN("Invalid lpszStr would crash under Win32!\n");
1587     return NULL;
1588   }
1589
1590   StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1591   return lpszRet;
1592 }
1593
1594 /*************************************************************************
1595  * StrNCatW     [SHLWAPI.@]
1596  *
1597  * See StrNCatA.
1598  */
1599 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1600 {
1601   LPWSTR lpszRet = lpszStr;
1602
1603   TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1604
1605   if (!lpszStr)
1606   {
1607     WARN("Invalid lpszStr would crash under Win32\n");
1608     return NULL;
1609   }
1610
1611   StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1612   return lpszRet;
1613 }
1614
1615 /*************************************************************************
1616  * StrTrimA     [SHLWAPI.@]
1617  *
1618  * Remove characters from the start and end of a string.
1619  *
1620  * PARAMS
1621  *  lpszStr  [O] String to remove characters from
1622  *  lpszTrim [I] Characters to remove from lpszStr
1623  *
1624  * RETURNS
1625  *  TRUE  If lpszStr was valid and modified
1626  *  FALSE Otherwise
1627  */
1628 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1629 {
1630   DWORD dwLen;
1631   LPSTR lpszRead = lpszStr;
1632   BOOL bRet = FALSE;
1633
1634   TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1635
1636   if (lpszRead && *lpszRead)
1637   {
1638     while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1639       lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1640
1641     dwLen = strlen(lpszRead);
1642
1643     if (lpszRead != lpszStr)
1644     {
1645       memmove(lpszStr, lpszRead, dwLen + 1);
1646       bRet = TRUE;
1647     }
1648     if (dwLen > 0)
1649     {
1650       lpszRead = lpszStr + dwLen;
1651       while (StrChrA(lpszTrim, lpszRead[-1]))
1652         lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1653
1654       if (lpszRead != lpszStr + dwLen)
1655       {
1656         *lpszRead = '\0';
1657         bRet = TRUE;
1658       }
1659     }
1660   }
1661   return bRet;
1662 }
1663
1664 /*************************************************************************
1665  * StrTrimW     [SHLWAPI.@]
1666  *
1667  * See StrTrimA.
1668  */
1669 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1670 {
1671   DWORD dwLen;
1672   LPWSTR lpszRead = lpszStr;
1673   BOOL bRet = FALSE;
1674
1675   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1676
1677   if (lpszRead && *lpszRead)
1678   {
1679     while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1680       lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1681
1682     dwLen = strlenW(lpszRead);
1683
1684     if (lpszRead != lpszStr)
1685     {
1686       memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1687       bRet = TRUE;
1688     }
1689     if (dwLen > 0)
1690     {
1691       lpszRead = lpszStr + dwLen;
1692       while (StrChrW(lpszTrim, lpszRead[-1]))
1693         lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1694
1695       if (lpszRead != lpszStr + dwLen)
1696       {
1697         *lpszRead = '\0';
1698         bRet = TRUE;
1699       }
1700     }
1701   }
1702   return bRet;
1703 }
1704
1705 /*************************************************************************
1706  *      _SHStrDupA      [INTERNAL]
1707  *
1708  * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1709  */
1710 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1711 {
1712         HRESULT hr;
1713         int len = 0;
1714
1715         if (src) {
1716             len = lstrlenA(src);
1717             *dest = CoTaskMemAlloc(len);
1718         } else {
1719             *dest = NULL;
1720         }
1721
1722         if (*dest) {
1723             lstrcpynA(*dest,src, len);
1724             hr = S_OK;
1725         } else {
1726             hr = E_OUTOFMEMORY;
1727         }
1728
1729         TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1730         return hr;
1731 }
1732
1733 /*************************************************************************
1734  * SHStrDupA
1735  *
1736  * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc.
1737  *
1738  * PARAMS
1739  *  lpszStr   [I] String to copy
1740  *  lppszDest [O] Destination for the new string copy
1741  *
1742  * RETURNS
1743  *  Success: S_OK. lppszDest contains the new string in Unicode format.
1744  *  Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1745  *           fails.
1746  */
1747 HRESULT WINAPI SHStrDupA(LPCSTR src, LPWSTR * dest)
1748 {
1749         HRESULT hr;
1750         int len = 0;
1751
1752         if (src) {
1753             len = (MultiByteToWideChar(0,0,src,-1,0,0) + 1)* sizeof(WCHAR);
1754             *dest = CoTaskMemAlloc(len);
1755         } else {
1756             *dest = NULL;
1757         }
1758
1759         if (*dest) {
1760             MultiByteToWideChar(0,0,src,-1,*dest,len);
1761             hr = S_OK;
1762         } else {
1763             hr = E_OUTOFMEMORY;
1764         }
1765
1766         TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1767         return hr;
1768 }
1769
1770 /*************************************************************************
1771  *      _SHStrDupAW     [INTERNAL]
1772  *
1773  * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1774  */
1775 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1776 {
1777         HRESULT hr;
1778         int len = 0;
1779
1780         if (src) {
1781             len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1782             *dest = CoTaskMemAlloc(len);
1783         } else {
1784             *dest = NULL;
1785         }
1786
1787         if (*dest) {
1788             WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1789             hr = S_OK;
1790         } else {
1791             hr = E_OUTOFMEMORY;
1792         }
1793
1794         TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1795         return hr;
1796 }
1797
1798 /*************************************************************************
1799  * SHStrDupW
1800  *
1801  * See SHStrDupA.
1802  */
1803 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1804 {
1805         HRESULT hr;
1806         int len = 0;
1807
1808         if (src) {
1809             len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1810             *dest = CoTaskMemAlloc(len);
1811         } else {
1812             *dest = NULL;
1813         }
1814
1815         if (*dest) {
1816             memcpy(*dest, src, len);
1817             hr = S_OK;
1818         } else {
1819             hr = E_OUTOFMEMORY;
1820         }
1821
1822         TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1823         return hr;
1824 }
1825
1826 /*************************************************************************
1827  * SHLWAPI_WriteReverseNum
1828  *
1829  * Internal helper for SHLWAPI_WriteTimeClass.
1830  */
1831 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1832 {
1833   *lpszOut-- = '\0';
1834
1835   /* Write a decimal number to a string, backwards */
1836   do
1837   {
1838     DWORD dwNextDigit = dwNum % 10;
1839     *lpszOut-- = '0' + dwNextDigit;
1840     dwNum = (dwNum - dwNextDigit) / 10;
1841   } while (dwNum > 0);
1842
1843   return lpszOut;
1844 }
1845
1846 /*************************************************************************
1847  * SHLWAPI_FormatSignificant
1848  *
1849  * Internal helper for SHLWAPI_WriteTimeClass.
1850  */
1851 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1852 {
1853   /* Zero non significant digits, return remaining significant digits */
1854   while (*lpszNum)
1855   {
1856     lpszNum++;
1857     if (--dwDigits == 0)
1858     {
1859       while (*lpszNum)
1860         *lpszNum++ = '0';
1861       return 0;
1862     }
1863   }
1864   return dwDigits;
1865 }
1866
1867 /*************************************************************************
1868  * SHLWAPI_WriteTimeClass
1869  *
1870  * Internal helper for StrFromTimeIntervalW.
1871  */
1872 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1873                                   LPCWSTR lpszClass, int iDigits)
1874 {
1875   WCHAR szBuff[64], *szOut = szBuff + 32;
1876
1877   szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1878   iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1879   *szOut = ' ';
1880   strcpyW(szBuff + 32, lpszClass);
1881   strcatW(lpszOut, szOut);
1882   return iDigits;
1883 }
1884
1885 /*************************************************************************
1886  * StrFromTimeIntervalA [SHLWAPI.@]
1887  *
1888  * Format a millisecond time interval into a string
1889  *
1890  * PARAMS
1891  *  lpszStr  [O] Output buffer for formatted time interval
1892  *  cchMax   [I] Size of lpszStr
1893  *  dwMS     [I] Number of milliseconds
1894  *  iDigits  [I] Number of digits to print
1895  *
1896  * RETURNS
1897  *  The length of the formatted string, or 0 if any parameter is invalid.
1898  *
1899  * NOTES
1900  *  This implementation mimics the Win32 behaviour of always writing a leading
1901  *  space before the time interval begins.
1902  *  iDigits is used to provide approximate times if accuracy is not important.
1903  *  This number of digits will be written of the first non-zero time class
1904  *  (hours/minutes/seconds). If this does not complete the time classification,
1905  *  the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1906  *  If there are digits remaining following the writing of a time class, the
1907  *  next time class will be written.
1908  *  For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1909  *  following will result from the given values of iDigits:
1910  *
1911  *  iDigits    1        2        3        4               5               ...
1912  *  lpszStr   "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min"  ...
1913  */
1914 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1915                                 int iDigits)
1916 {
1917   INT iRet = 0;
1918
1919   TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1920
1921   if (lpszStr && cchMax)
1922   {
1923     WCHAR szBuff[128];
1924     StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1925     WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1926   }
1927   return iRet;
1928 }
1929
1930
1931 /*************************************************************************
1932  * StrFromTimeIntervalW [SHLWAPI.@]
1933  *
1934  * See StrFromTimeIntervalA.
1935  */
1936 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1937                                 int iDigits)
1938 {
1939   static const WCHAR szHr[] = {' ','h','r','\0'};
1940   static const WCHAR szMin[] = {' ','m','i','n','\0'};
1941   static const WCHAR szSec[] = {' ','s','e','c','\0'};
1942   INT iRet = 0;
1943
1944   TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1945
1946   if (lpszStr && cchMax)
1947   {
1948     WCHAR szCopy[128];
1949     DWORD dwHours, dwMinutes;
1950
1951     if (!iDigits || cchMax == 1)
1952     {
1953       *lpszStr = '\0';
1954       return 0;
1955     }
1956
1957     /* Calculate the time classes */
1958     dwMS = (dwMS + 500) / 1000;
1959     dwHours = dwMS / 3600;
1960     dwMS -= dwHours * 3600;
1961     dwMinutes = dwMS / 60;
1962     dwMS -= dwMinutes * 60;
1963
1964     szCopy[0] = '\0';
1965
1966     if (dwHours)
1967       iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
1968
1969     if (dwMinutes && iDigits)
1970       iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
1971
1972     if (iDigits) /* Always write seconds if we have significant digits */
1973       SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
1974
1975     strncpyW(lpszStr, szCopy, cchMax);
1976     iRet = strlenW(lpszStr);
1977   }
1978   return iRet;
1979 }
1980
1981 /*************************************************************************
1982  * StrIsIntlEqualA      [SHLWAPI.@]
1983  *
1984  * Compare two strings.
1985  *
1986  * PARAMS
1987  *  bCase    [I] Whether to compare case sensitively
1988  *  lpszStr  [I] First string to compare
1989  *  lpszComp [I] Second string to compare
1990  *  iLen     [I] Length to compare
1991  *
1992  * RETURNS
1993  *  TRUE  If the strings are equal.
1994  *  FALSE Otherwise.
1995  */
1996 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
1997                             int iLen)
1998 {
1999   DWORD dwFlags = LOCALE_USE_CP_ACP;
2000   int iRet;
2001
2002   TRACE("(%d,%s,%s,%d)\n", bCase,
2003         debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2004
2005   /* FIXME: These flags are undocumented and unknown by our CompareString.
2006    *        We need defines for them.
2007    */
2008   dwFlags |= bCase ? 0x10000000 : 0x10000001;
2009
2010   iRet = CompareStringA(GetThreadLocale(),
2011                         dwFlags, lpszStr, iLen, lpszComp, iLen);
2012
2013   if (!iRet)
2014     iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2015
2016   return iRet == 2 ? TRUE : FALSE;
2017 }
2018
2019 /*************************************************************************
2020  * StrIsIntlEqualW      [SHLWAPI.@]
2021  *
2022  * See StrIsIntlEqualA.
2023  */
2024 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2025                             int iLen)
2026 {
2027   DWORD dwFlags;
2028   int iRet;
2029
2030   TRACE("(%d,%s,%s,%d)\n", bCase,
2031         debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2032
2033   /* FIXME: These flags are undocumented and unknown by our CompareString.
2034    *        We need defines for them.
2035    */
2036   dwFlags = bCase ? 0x10000000 : 0x10000001;
2037
2038   iRet = CompareStringW(GetThreadLocale(),
2039                         dwFlags, lpszStr, iLen, lpszComp, iLen);
2040
2041   if (!iRet)
2042     iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2043
2044   return iRet == 2 ? TRUE : FALSE;
2045 }
2046
2047 /*************************************************************************
2048  * @    [SHLWAPI.399]
2049  *
2050  * Copy a string to another string, up to a maximum number of characters.
2051  *
2052  * PARAMS
2053  *  lpszDest [O] Destination string
2054  *  lpszSrc  [I] Source string
2055  *  iLen     [I] Maximum number of chars to copy
2056  *
2057  * RETURNS
2058  *  Success: A pointer to the last character written.
2059  *  Failure: lpszDest, if any arguments are invalid.
2060  */
2061 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2062 {
2063   TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2064
2065   if (lpszDest && lpszSrc && iLen > 0)
2066   {
2067     while ((iLen-- > 1) && *lpszSrc)
2068       *lpszDest++ = *lpszSrc++;
2069     if (iLen >= 0)
2070      *lpszDest = '\0';
2071   }
2072   return lpszDest;
2073 }
2074
2075 /*************************************************************************
2076  * @    [SHLWAPI.400]
2077  *
2078  * Unicode version of SHLWAPI_399.
2079  */
2080 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2081 {
2082   TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2083
2084   if (lpszDest && lpszSrc && iLen > 0)
2085   {
2086     while ((iLen-- > 1) && *lpszSrc)
2087       *lpszDest++ = *lpszSrc++;
2088     if (iLen >= 0)
2089      *lpszDest = '\0';
2090   }
2091   return lpszDest;
2092 }
2093
2094 /*************************************************************************
2095  * StrCmpLogicalW       [SHLWAPI.@]
2096  *
2097  * Compare two strings, ignoring case and comparing digits as numbers.
2098  *
2099  * PARAMS
2100  *  lpszStr  [I] First string to compare
2101  *  lpszComp [I] Second string to compare
2102  *  iLen     [I] Length to compare
2103  *
2104  * RETURNS
2105  *  TRUE  If the strings are equal.
2106  *  FALSE Otherwise.
2107  */
2108 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2109 {
2110   INT iDiff;
2111
2112   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2113
2114   if (lpszStr && lpszComp)
2115   {
2116     while (*lpszStr)
2117     {
2118       if (!*lpszComp)
2119         return 1;
2120       else if (isdigitW(*lpszStr))
2121       {
2122         int iStr, iComp;
2123
2124         if (!isdigitW(*lpszComp))
2125           return -1;
2126
2127         /* Compare the numbers */
2128         StrToIntExW(lpszStr, 0, &iStr);
2129         StrToIntExW(lpszComp, 0, &iComp);
2130
2131         if (iStr < iComp)
2132           return -1;
2133         else if (iStr > iComp)
2134           return 1;
2135
2136         /* Skip */
2137         while (isdigitW(*lpszStr))
2138           lpszStr++;
2139         while (isdigitW(*lpszComp))
2140           lpszComp++;
2141       }
2142       else if (isdigitW(*lpszComp))
2143         return 1;
2144       else
2145       {
2146         iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE);
2147         if (iDiff > 0)
2148           return 1;
2149         else if (iDiff < 0)
2150           return -1;
2151
2152         lpszStr++;
2153         lpszComp++;
2154       }
2155     }
2156     if (*lpszComp)
2157       return -1;
2158   }
2159   return 0;
2160 }
2161
2162 /* Structure for formatting byte strings */
2163 typedef struct tagSHLWAPI_BYTEFORMATS
2164 {
2165   LONGLONG dLimit;
2166   double   dDivisor;
2167   double   dNormaliser;
2168   LPCSTR   lpszFormat;
2169   CHAR     wPrefix;
2170 } SHLWAPI_BYTEFORMATS;
2171
2172 /*************************************************************************
2173  * StrFormatByteSize64A [SHLWAPI.@]
2174  *
2175  * Create a string containing an abbreviated byte count of up to 2^63-1.
2176  *
2177  * PARAMS
2178  *  llBytes  [I] Byte size to format
2179  *  lpszDest [I] Destination for formatted string
2180  *  cchMax   [I] Size of lpszDest
2181  *
2182  * RETURNS
2183  *  lpszDest.
2184  *
2185  * NOTES
2186  *  There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW.
2187  */
2188 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2189 {
2190   static const char szBytes[] = "%ld bytes";
2191   static const char sz3_0[] = "%3.0f";
2192   static const char sz3_1[] = "%3.1f";
2193   static const char sz3_2[] = "%3.2f";
2194
2195   static const SHLWAPI_BYTEFORMATS bfFormats[] =
2196   {
2197     { 10240, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */
2198     { 102400, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */
2199     { 1024000, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */
2200     { 10485760, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */
2201     { 104857600, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */
2202     { 1048576000, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */
2203     { 10737418240, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */
2204     { 107374182400, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */
2205     { 1073741824000, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */
2206     { 10995116277760, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */
2207     { 109951162777600, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */
2208     { 1099511627776000, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */
2209     { 11258999068426240, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */
2210     { 112589990684262400, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */
2211     { 1125899906842624000, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */
2212     { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */
2213   };
2214   char szBuff[32];
2215   char szAdd[4];
2216   double dBytes;
2217   UINT i = 0;
2218
2219   TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2220
2221   if (!lpszDest || !cchMax)
2222     return lpszDest;
2223
2224   if (llBytes < 1024)  /* 1K */
2225   {
2226     snprintf (lpszDest, cchMax, szBytes, (long)llBytes);
2227     return lpszDest;
2228   }
2229
2230   /* Note that if this loop completes without finding a match, i will be
2231    * pointing at the last entry, which is a catch all for > 1000 PB
2232    */
2233   while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2234   {
2235     if (llBytes < bfFormats[i].dLimit)
2236       break;
2237     i++;
2238   }
2239   /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2240    * this number we integer shift down by 1 MB first. The table above has
2241    * the divisors scaled down from the '< 10 TB' entry onwards, to account
2242    * for this. We also add a small fudge factor to get the correct result for
2243    * counts that lie exactly on a 1024 byte boundary.
2244    */
2245   if (i > 8)
2246     dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2247   else
2248     dBytes = (double)llBytes + 0.00001;
2249
2250   dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2251
2252   sprintf(szBuff, bfFormats[i].lpszFormat, dBytes);
2253   szAdd[0] = ' ';
2254   szAdd[1] = bfFormats[i].wPrefix;
2255   szAdd[2] = 'B';
2256   szAdd[3] = '\0';
2257   strcat(szBuff, szAdd);
2258   strncpy(lpszDest, szBuff, cchMax);
2259   return lpszDest;
2260 }
2261
2262 /*************************************************************************
2263  * StrFormatByteSizeW   [SHLWAPI.@]
2264  *
2265  * See StrFormatByteSize64A.
2266  */
2267 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest,
2268                                  UINT cchMax)
2269 {
2270   char szBuff[32];
2271
2272   StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff));
2273
2274   if (lpszDest)
2275     MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax);
2276   return lpszDest;
2277 }
2278
2279 /*************************************************************************
2280  * StrFormatByteSizeA   [SHLWAPI.@]
2281  *
2282  * Create a string containing an abbreviated byte count of up to 2^31-1.
2283  *
2284  * PARAMS
2285  *  dwBytes  [I] Byte size to format
2286  *  lpszDest [I] Destination for formatted string
2287  *  cchMax   [I] Size of lpszDest
2288  *
2289  * RETURNS
2290  *  lpszDest.
2291  *
2292  * NOTES
2293  *  The ASCII and Unicode versions of this function accept a different
2294  *  integer size for dwBytes. See StrFormatByteSize64A.
2295  */
2296 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2297 {
2298   TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2299
2300   return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2301 }