[SHLWAPI] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / shlwapi / string.c
index 2ee2aa9..0b34d43 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define WIN32_NO_STATUS
-#define _INC_WINDOWS
-#define COM_NO_WINDOWS_H
-
-#include <config.h>
-//#include "wine/port.h"
+#include "config.h"
+#include "wine/port.h"
 
 #include <math.h>
 #include <stdarg.h>
-//#include <stdio.h>
-//#include <string.h>
+#include <stdio.h>
+#include <string.h>
 
 #define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-#include <windef.h>
-#include <winbase.h>
+
+#include "windef.h"
+#include "winbase.h"
 #define NO_SHLWAPI_REG
 #define NO_SHLWAPI_STREAM
-#include <shlwapi.h>
-//#include "wingdi.h"
-//#include "winuser.h"
-#include <shlobj.h>
-#include <mlang.h>
-#include <ddeml.h>
-#include <wine/unicode.h>
-#include <wine/debug.h>
+#include "shlwapi.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "shlobj.h"
+#include "mlang.h"
+#include "ddeml.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
 
 #include "resource.h"
 
@@ -368,7 +364,7 @@ int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
  * PARAMS
  *  lpszStr  [I] First string to compare
  *  lpszComp [I] Second string to compare
- *  iLen     [I] Maximum number of chars to compare.
+ *  iLen     [I] Number of chars to compare
  *
  * RETURNS
  *  An integer less than, equal to or greater than 0, indicating that
@@ -399,7 +395,7 @@ INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
  * PARAMS
  *  lpszStr  [I] First string to compare
  *  lpszComp [I] Second string to compare
- *  iLen     [I] Maximum number of chars to compare.
+ *  iLen     [I] Number of chars to compare
  *
  * RETURNS
  *  An integer less than, equal to or greater than 0, indicating that
@@ -462,6 +458,47 @@ LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
   return lpszStr;
 }
 
+/*************************************************************************
+ * StrCatChainW        [SHLWAPI.@]
+ *
+ * Concatenates two unicode strings.
+ *
+ * PARAMS
+ *  lpszStr [O] Initial string
+ *  cchMax  [I] Length of destination buffer
+ *  ichAt   [I] Offset from the destination buffer to begin concatenation
+ *  lpszCat [I] String to concatenate
+ *
+ * RETURNS
+ *  The offset from the beginning of pszDst to the terminating NULL.
+ */
+DWORD WINAPI StrCatChainW(LPWSTR lpszStr, DWORD cchMax, DWORD ichAt, LPCWSTR lpszCat)
+{
+  TRACE("(%s,%u,%d,%s)\n", debugstr_w(lpszStr), cchMax, ichAt, debugstr_w(lpszCat));
+
+  if (ichAt == -1)
+    ichAt = strlenW(lpszStr);
+
+  if (!cchMax)
+    return ichAt;
+
+  if (ichAt == cchMax)
+    ichAt--;
+
+  if (lpszCat && ichAt < cchMax)
+  {
+    lpszStr += ichAt;
+    while (ichAt < cchMax - 1 && *lpszCat)
+    {
+      *lpszStr++ = *lpszCat++;
+      ichAt++;
+    }
+    *lpszStr = 0;
+  }
+
+  return ichAt;
+}
+
 /*************************************************************************
  * StrCpyW     [SHLWAPI.@]
  *
@@ -525,13 +562,15 @@ static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
                                    INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
 {
   size_t iLen;
+  LPCSTR end;
 
   if (!lpszStr || !lpszSearch || !*lpszSearch)
     return NULL;
 
   iLen = strlen(lpszSearch);
+  end = lpszStr + strlen(lpszStr);
 
-  while (*lpszStr)
+  while (lpszStr + iLen <= end)
   {
     if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
       return (LPSTR)lpszStr;
@@ -587,6 +626,7 @@ LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
  */
 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
 {
+  LPSTR lpszRet = NULL;
   WORD ch1, ch2;
   INT iLen;
 
@@ -595,28 +635,28 @@ LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
   if (!lpszStr || !lpszSearch || !*lpszSearch)
     return NULL;
 
-  if (!lpszEnd)
-    lpszEnd = lpszStr + lstrlenA(lpszStr);
-  if (lpszEnd == lpszStr)
-    return NULL;
-
   if (IsDBCSLeadByte(*lpszSearch))
     ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
   else
     ch1 = *lpszSearch;
   iLen = lstrlenA(lpszSearch);
 
-  do
+  if (!lpszEnd)
+    lpszEnd = lpszStr + lstrlenA(lpszStr);
+  else /* reproduce the broken behaviour on Windows */
+    lpszEnd += min(iLen - 1, lstrlenA(lpszEnd));
+
+  while (lpszStr + iLen <= lpszEnd && *lpszStr)
   {
-    lpszEnd = CharPrevA(lpszStr, lpszEnd);
-    ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
+    ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | (UCHAR)lpszStr[1] : *lpszStr;
     if (!ChrCmpIA(ch1, ch2))
     {
-      if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
-        return (LPSTR)lpszEnd;
+      if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
+        lpszRet = (LPSTR)lpszStr;
     }
-  } while (lpszEnd > lpszStr);
-  return NULL;
+    lpszStr = CharNextA(lpszStr);
+  }
+  return lpszRet;
 }
 
 /*************************************************************************
@@ -626,6 +666,7 @@ LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
  */
 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
 {
+  LPWSTR lpszRet = NULL;
   INT iLen;
 
   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
@@ -633,18 +674,23 @@ LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
   if (!lpszStr || !lpszSearch || !*lpszSearch)
     return NULL;
 
+  iLen = strlenW(lpszSearch);
+
   if (!lpszEnd)
     lpszEnd = lpszStr + strlenW(lpszStr);
+  else /* reproduce the broken behaviour on Windows */
+    lpszEnd += min(iLen - 1, lstrlenW(lpszEnd));
 
-  iLen = strlenW(lpszSearch);
-
-  while (lpszEnd > lpszStr)
+  while (lpszStr + iLen <= lpszEnd && *lpszStr)
   {
-    lpszEnd--;
-    if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
-      return (LPWSTR)lpszEnd;
+    if (!ChrCmpIW(*lpszSearch, *lpszStr))
+    {
+      if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
+        lpszRet = (LPWSTR)lpszStr;
+    }
+    lpszStr++;
   }
-  return NULL;
+  return lpszRet;
 }
 
 /*************************************************************************
@@ -674,6 +720,7 @@ LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
 {
   int iLen;
+  LPCWSTR end;
 
   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
 
@@ -681,8 +728,9 @@ LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
     return NULL;
 
   iLen = strlenW(lpszSearch);
+  end = lpszStr + strlenW(lpszStr);
 
-  while (*lpszStr)
+  while (lpszStr + iLen <= end)
   {
     if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
       return (LPWSTR)lpszStr;
@@ -1461,7 +1509,7 @@ HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, U
 
          default:
            FIXME("unknown type!\n");
-           return FALSE;
+           return E_NOTIMPL;
        }
        return S_OK;
 }
@@ -1473,47 +1521,58 @@ HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, U
  */
 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
 {
-        TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
+    TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
 
-       if (!src)
-       {
-         WARN("Invalid lpStrRet would crash under Win32!\n");
-         if (dest)
-           *dest = '\0';
-         return E_FAIL;
-       }
+    if (!dest || !len)
+        return E_FAIL;
 
-       if (!dest || !len)
-         return E_FAIL;
+    if (!src)
+    {
+        WARN("Invalid lpStrRet would crash under Win32!\n");
+        if (dest)
+            *dest = '\0';
+        return E_FAIL;
+    }
 
-       *dest = '\0';
+    *dest = '\0';
+
+    switch (src->uType) {
+    case STRRET_WSTR: {
+        size_t dst_len;
+        if (!src->u.pOleStr)
+            return E_FAIL;
+        dst_len = strlenW(src->u.pOleStr);
+        memcpy(dest, src->u.pOleStr, min(dst_len, len-1) * sizeof(WCHAR));
+        dest[min(dst_len, len-1)] = 0;
+        CoTaskMemFree(src->u.pOleStr);
+        if (len <= dst_len)
+        {
+            dest[0] = 0;
+            return E_NOT_SUFFICIENT_BUFFER;
+        }
+        break;
+    }
 
-       switch (src->uType)
-       {
-         case STRRET_WSTR:
-            lstrcpynW(dest, src->u.pOleStr, len);
-           CoTaskMemFree(src->u.pOleStr);
-           break;
+    case STRRET_CSTR:
+        if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
+            dest[len-1] = 0;
+        break;
 
-         case STRRET_CSTR:
-              if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
-                  dest[len-1] = 0;
-           break;
+    case STRRET_OFFSET:
+        if (pidl)
+       {
+            if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
+                                      dest, len ))
+                dest[len-1] = 0;
+        }
+        break;
 
-         case STRRET_OFFSET:
-           if (pidl)
-           {
-              if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
-                                        dest, len ))
-                  dest[len-1] = 0;
-           }
-           break;
+    default:
+        FIXME("unknown type!\n");
+        return E_NOTIMPL;
+    }
 
-         default:
-           FIXME("unknown type!\n");
-           return FALSE;
-       }
-       return S_OK;
+    return S_OK;
 }
 
 /*************************************************************************
@@ -1891,7 +1950,7 @@ HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
 
   if (lpszStr)
   {
-    len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
+    len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR);
     *lppszDest = CoTaskMemAlloc(len);
   }
   else
@@ -1899,7 +1958,7 @@ HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
 
   if (*lppszDest)
   {
-    MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
+    MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
     hRet = S_OK;
   }
   else
@@ -2657,8 +2716,7 @@ DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
       mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
       if (mem)
       {
-        reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
-                                     reqLen, NULL, NULL);
+        WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, reqLen, NULL, NULL);
 
         reqLen = SHTruncateString(mem, dstlen -1);
         reqLen++;
@@ -2825,6 +2883,31 @@ HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void
     TRACE("returning %s\n", debugstr_w(dst));
 end:
     if(hmod) FreeLibrary(hmod);
-    HeapFree(GetProcessHeap(), 0, dllname);
+    LocalFree(dllname);
     return hr;
 }
+
+BOOL WINAPI IsCharSpaceA(CHAR c)
+{
+    WORD CharType;
+    return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &CharType) && (CharType & C1_SPACE);
+}
+
+/*************************************************************************
+ *      @      [SHLWAPI.29]
+ *
+ * Determine if a Unicode character is a space.
+ *
+ * PARAMS
+ *  wc [I] Character to check.
+ *
+ * RETURNS
+ *  TRUE, if wc is a space,
+ *  FALSE otherwise.
+ */
+BOOL WINAPI IsCharSpaceW(WCHAR wc)
+{
+    WORD CharType;
+
+    return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE);
+}