From c333fa4ed17b596624cf88f288f9bcf5b26822ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Wed, 20 Oct 2004 16:49:27 +0000 Subject: [PATCH] Sync to Wine-20041019: Francois Gouget - Don't define COBJMACROS in objbase.h. - Update the Wine sources accordingly. Robert Shearman - Don't define GWL_USERDATA, GWL_ID, GWL_HWNDPARENT, GWL_HINSTANCE and GWL_WNDPROC when compiling the Wine source. Mike McCormack - Fix some -Wsigned-compare warnings. Huw Davies - Rewrite PathCreateFromUrl. - Implement PathSearchAndQualify. - Fix UrlUnescapeW. - PathIsURL should return TRUE even if a scheme is unknown. - UrlEscape has different rules depending on the protocol. - Added a load of tests. - ParseURL is now documented, so move it into shlwapi.h. Bill Medland - Fix SHDeleteKey so that it will handle deleting a key with more than one subkey. Also includes test. Steven Edwards - Move URL_SCHEME typedef to match PSDK. svn path=/trunk/; revision=11348 --- reactos/lib/shlwapi/clist.c | 2 + reactos/lib/shlwapi/istream.c | 2 + reactos/lib/shlwapi/ordinal.c | 8 +- reactos/lib/shlwapi/path.c | 159 +++-- reactos/lib/shlwapi/reg.c | 15 +- reactos/lib/shlwapi/regstream.c | 2 + reactos/lib/shlwapi/thread.c | 2 + reactos/lib/shlwapi/url.c | 879 +++++++++++---------------- reactos/lib/shlwapi/winehq2ros.patch | 197 +++++- 9 files changed, 643 insertions(+), 623 deletions(-) diff --git a/reactos/lib/shlwapi/clist.c b/reactos/lib/shlwapi/clist.c index 9ea35584f8c..4eab19c68ab 100644 --- a/reactos/lib/shlwapi/clist.c +++ b/reactos/lib/shlwapi/clist.c @@ -20,6 +20,8 @@ #include #include +#define COBJMACROS + #include "windef.h" #include "winbase.h" #include "objbase.h" diff --git a/reactos/lib/shlwapi/istream.c b/reactos/lib/shlwapi/istream.c index bc1cb551d03..0b38ad2911f 100644 --- a/reactos/lib/shlwapi/istream.c +++ b/reactos/lib/shlwapi/istream.c @@ -20,8 +20,10 @@ #include #include +#define COBJMACROS #define NONAMELESSUNION #define NONAMELESSSTRUCT + #include "windef.h" #include "winbase.h" #include "winerror.h" diff --git a/reactos/lib/shlwapi/ordinal.c b/reactos/lib/shlwapi/ordinal.c index ba15832a3be..cd4baeda9a9 100644 --- a/reactos/lib/shlwapi/ordinal.c +++ b/reactos/lib/shlwapi/ordinal.c @@ -576,8 +576,8 @@ HRESULT WINAPI GetAcceptLanguagesW( LPWSTR langbuf, LPDWORD buflen) } memcpy( langbuf, mystr, min(*buflen,strlenW(mystr)+1)*sizeof(WCHAR) ); - if(*buflen > lstrlenW(mystr)) { - *buflen = lstrlenW(mystr); + if(*buflen > strlenW(mystr)) { + *buflen = strlenW(mystr); retval = S_OK; } else { *buflen = 0; @@ -2439,7 +2439,7 @@ HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle SetWindowLongA(hWnd, DWL_MSGRESULT, z); if (wndProc) - SetWindowLongA(hWnd, GWL_WNDPROC, wndProc); + SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc); } return hWnd; } @@ -2726,7 +2726,7 @@ HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle SetWindowLongA(hWnd, DWL_MSGRESULT, z); if (wndProc) - SetWindowLongA(hWnd, GWL_WNDPROC, wndProc); + SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc); } return hWnd; } diff --git a/reactos/lib/shlwapi/path.c b/reactos/lib/shlwapi/path.c index a8c8e7cb7a3..f1a3d3768d8 100644 --- a/reactos/lib/shlwapi/path.c +++ b/reactos/lib/shlwapi/path.c @@ -32,7 +32,7 @@ #include "wingdi.h" #include "winuser.h" #include "winreg.h" -#include "winnls.h" +#include "winternl.h" #define NO_SHLWAPI_STREAM #include "shlwapi.h" #include "wine/debug.h" @@ -3116,8 +3116,11 @@ BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt) */ BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf) { - FIXME("(%s,%p,0x%08x)-stub\n", debugstr_a(lpszPath), lpszBuf, cchBuf); - return FALSE; + TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszPath), lpszBuf, cchBuf); + + if(SearchPathA(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL)) + return TRUE; + return !!GetFullPathNameA(lpszPath, cchBuf, lpszBuf, NULL); } /************************************************************************* @@ -3127,8 +3130,11 @@ BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf) */ BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf) { - FIXME("(%s,%p,0x%08x)-stub\n", debugstr_w(lpszPath), lpszBuf, cchBuf); - return FALSE; + TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszPath), lpszBuf, cchBuf); + + if(SearchPathW(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL)) + return TRUE; + return !!GetFullPathNameW(lpszPath, cchBuf, lpszBuf, NULL); } /************************************************************************* @@ -3200,6 +3206,42 @@ LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath) /************************************************************************* * PathCreateFromUrlA [SHLWAPI.@] * + * See PathCreateFromUrlW + */ +HRESULT WINAPI PathCreateFromUrlA(LPCSTR pszUrl, LPSTR pszPath, + LPDWORD pcchPath, DWORD dwReserved) +{ + WCHAR bufW[MAX_PATH]; + WCHAR *pathW = bufW; + UNICODE_STRING urlW; + HRESULT ret; + DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; + + if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) + return E_INVALIDARG; + if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) { + pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); + ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved); + } + if(ret == S_OK) { + RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR)); + if(*pcchPath > lenA) { + RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR)); + pszPath[lenA] = 0; + *pcchPath = lenA; + } else { + *pcchPath = lenA + 1; + ret = E_POINTER; + } + } + if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW); + RtlFreeUnicodeString(&urlW); + return ret; +} + +/************************************************************************* + * PathCreateFromUrlW [SHLWAPI.@] + * * Create a path from a URL * * PARAMS @@ -3212,79 +3254,66 @@ LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath) * Success: S_OK. lpszPath contains the URL in path format, * Failure: An HRESULT error code such as E_INVALIDARG. */ -HRESULT WINAPI PathCreateFromUrlA(LPCSTR lpszUrl, LPSTR lpszPath, - LPDWORD pcchPath, DWORD dwFlags) +HRESULT WINAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath, + LPDWORD pcchPath, DWORD dwReserved) { - LPSTR pszPathPart; - TRACE("(%s,%p,%p,0x%08lx)\n", debugstr_a(lpszUrl), lpszPath, pcchPath, dwFlags); + static const WCHAR file_colon[] = { 'f','i','l','e',':',0 }; + HRESULT hr; + DWORD nslashes = 0; + WCHAR *ptr; - if (!lpszUrl || !lpszPath || !pcchPath || !*pcchPath) - return E_INVALIDARG; + TRACE("(%s,%p,%p,0x%08lx)\n", debugstr_w(pszUrl), pszPath, pcchPath, dwReserved); - pszPathPart = StrChrA(lpszUrl, ':'); - if ((((pszPathPart - lpszUrl) == 1) && isalpha(*lpszUrl)) || - !lstrcmpA(lpszUrl, "file:")) - { - return UrlUnescapeA(pszPathPart, lpszPath, pcchPath, dwFlags); - } - /* extracts thing prior to : in pszURL and checks against: - * https - * shell - * local - * about - if match returns E_INVALIDARG - */ + if (!pszUrl || !pszPath || !pcchPath || !*pcchPath) + return E_INVALIDARG; - return E_INVALIDARG; -} -/************************************************************************* - * PathCreateFromUrlW [SHLWAPI.@] - * - * See PathCreateFromUrlA. - */ -HRESULT WINAPI PathCreateFromUrlW(LPCWSTR lpszUrl, LPWSTR lpszPath, - LPDWORD pcchPath, DWORD dwFlags) -{ - static const WCHAR stemp[] = { 'f','i','l','e',':','/','/','/',0 }; - LPWSTR pwszPathPart; - HRESULT hr; + if (strncmpW(pszUrl, file_colon, 5)) + return E_INVALIDARG; + pszUrl += 5; - TRACE("(%s,%p,%p,0x%08lx)\n", debugstr_w(lpszUrl), lpszPath, pcchPath, dwFlags); + while(*pszUrl == '/' || *pszUrl == '\\') { + nslashes++; + pszUrl++; + } - if (!lpszUrl || !lpszPath || !pcchPath || !*pcchPath) - return E_INVALIDARG; + if(isalphaW(*pszUrl) && (pszUrl[1] == ':' || pszUrl[1] == '|') && (pszUrl[2] == '/' || pszUrl[2] == '\\')) + nslashes = 0; - /* Path of the form file:///... */ - if (!strncmpW(lpszUrl, stemp, 8)) - { - lpszUrl += 8; - } - /* Path of the form file://... */ - else if (!strncmpW(lpszUrl, stemp, 7)) - { - lpszUrl += 7; - } - /* Path of the form file:... */ - else if (!strncmpW(lpszUrl, stemp, 5)) - { - lpszUrl += 5; - } + switch(nslashes) { + case 2: + pszUrl -= 2; + break; + case 0: + break; + default: + pszUrl -= 1; + break; + } - /* Ensure that path is of the form c:... or c|... */ - if (lpszUrl[1] != ':' && lpszUrl[1] != '|' && isalphaW(*lpszUrl)) - return E_INVALIDARG; + hr = UrlUnescapeW((LPWSTR)pszUrl, pszPath, pcchPath, 0); + if(hr != S_OK) return hr; - hr = UrlUnescapeW((LPWSTR) lpszUrl, lpszPath, pcchPath, dwFlags); - if (lpszPath[1] == '|') - lpszPath[1] = ':'; + for(ptr = pszPath; *ptr; ptr++) + if(*ptr == '/') *ptr = '\\'; - for (pwszPathPart = lpszPath; *pwszPathPart; pwszPathPart++) - if (*pwszPathPart == '/') - *pwszPathPart = '\\'; + while(*pszPath == '\\') + pszPath++; + + if(isalphaW(*pszPath) && pszPath[1] == '|' && pszPath[2] == '\\') /* c|\ -> c:\ */ + pszPath[1] = ':'; - TRACE("Returning %s\n",debugstr_w(lpszPath)); + if(nslashes == 2 && (ptr = strchrW(pszPath, '\\'))) { /* \\host\c:\ -> \\hostc:\ */ + ptr++; + if(isalphaW(*ptr) && (ptr[1] == ':' || ptr[1] == '|') && ptr[2] == '\\') { + memmove(ptr - 1, ptr, (strlenW(ptr) + 1) * sizeof(WCHAR)); + (*pcchPath)--; + } + } - return hr; + TRACE("Returning %s\n",debugstr_w(pszPath)); + + return hr; } /************************************************************************* diff --git a/reactos/lib/shlwapi/reg.c b/reactos/lib/shlwapi/reg.c index e06bb293b28..c35d28eb0a2 100644 --- a/reactos/lib/shlwapi/reg.c +++ b/reactos/lib/shlwapi/reg.c @@ -1298,7 +1298,7 @@ DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue, */ DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey) { - DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i; + DWORD dwRet, dwMaxSubkeyLen = 0, dwSize; CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; HKEY hSubKey = 0; @@ -1307,8 +1307,8 @@ DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey) dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); if(!dwRet) { - /* Find how many subkeys there are */ - dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount, + /* Find the maximum subkey length so that we can allocate a buffer */ + dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL, &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); if(!dwRet) { @@ -1321,14 +1321,15 @@ DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey) dwRet = ERROR_NOT_ENOUGH_MEMORY; else { - /* Recursively delete all the subkeys */ - for(i = 0; i < dwKeyCount && !dwRet; i++) + while (dwRet == ERROR_SUCCESS) { dwSize = dwMaxSubkeyLen; - dwRet = RegEnumKeyExA(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL); - if(!dwRet) + dwRet = RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL); + if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA) dwRet = SHDeleteKeyA(hSubKey, lpszName); } + if (dwRet == ERROR_NO_MORE_ITEMS) + dwRet = ERROR_SUCCESS; if (lpszName != szNameBuf) HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */ } diff --git a/reactos/lib/shlwapi/regstream.c b/reactos/lib/shlwapi/regstream.c index 57f421205a6..614c70bd1b0 100644 --- a/reactos/lib/shlwapi/regstream.c +++ b/reactos/lib/shlwapi/regstream.c @@ -22,6 +22,8 @@ #include #include +#define COBJMACROS + #include "winerror.h" #include "windef.h" #include "winbase.h" diff --git a/reactos/lib/shlwapi/thread.c b/reactos/lib/shlwapi/thread.c index 95c5448d6a5..5fae0c01b30 100644 --- a/reactos/lib/shlwapi/thread.c +++ b/reactos/lib/shlwapi/thread.c @@ -21,6 +21,8 @@ #include #include +#define COBJMACROS + #include "windef.h" #include "winbase.h" #include "winnls.h" diff --git a/reactos/lib/shlwapi/url.c b/reactos/lib/shlwapi/url.c index 8b44c088a16..7446bef0023 100644 --- a/reactos/lib/shlwapi/url.c +++ b/reactos/lib/shlwapi/url.c @@ -30,6 +30,7 @@ #include "wine/unicode.h" #include "wininet.h" #include "winreg.h" +#include "winternl.h" #define NO_SHLWAPI_STREAM #include "shlwapi.h" #include "wine/debug.h" @@ -43,30 +44,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); /* The following schemes were identified in the native version of * SHLWAPI.DLL version 5.50 */ -typedef enum { - URL_SCHEME_INVALID = -1, - URL_SCHEME_UNKNOWN = 0, - URL_SCHEME_FTP, - URL_SCHEME_HTTP, - URL_SCHEME_GOPHER, - URL_SCHEME_MAILTO, - URL_SCHEME_NEWS, - URL_SCHEME_NNTP, - URL_SCHEME_TELNET, - URL_SCHEME_WAIS, - URL_SCHEME_FILE, - URL_SCHEME_MK, - URL_SCHEME_HTTPS, - URL_SCHEME_SHELL, - URL_SCHEME_SNEWS, - URL_SCHEME_LOCAL, - URL_SCHEME_JAVASCRIPT, - URL_SCHEME_VBSCRIPT, - URL_SCHEME_ABOUT, - URL_SCHEME_RES, - URL_SCHEME_MAXVALUE -} URL_SCHEME; - typedef struct { URL_SCHEME scheme_number; LPCSTR scheme_name; @@ -116,24 +93,6 @@ typedef enum { USERPASS, } WINE_URL_SCAN_TYPE; -typedef struct { - INT size; /* [in] (always 0x18) */ - LPCSTR ap1; /* [out] start of scheme */ - INT sizep1; /* [out] size of scheme (until colon) */ - LPCSTR ap2; /* [out] pointer following first colon */ - INT sizep2; /* [out] size of remainder */ - INT fcncde; /* [out] function match of p1 (0 if unknown) */ -} UNKNOWN_SHLWAPI_1; - -typedef struct { - INT size; /* [in] (always 0x18) */ - LPCWSTR ap1; /* [out] start of scheme */ - INT sizep1; /* [out] size of scheme (until colon) */ - LPCWSTR ap2; /* [out] pointer following first colon */ - INT sizep2; /* [out] size of remainder */ - INT fcncde; /* [out] function match of p1 (0 if unknown) */ -} UNKNOWN_SHLWAPI_2; - static const CHAR hexDigits[] = "0123456789ABCDEF"; static const WCHAR fileW[] = {'f','i','l','e','\0'}; @@ -160,96 +119,6 @@ static const unsigned char HashDataLookup[256] = { 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 }; -static inline BOOL URL_NeedEscapeA(CHAR ch, DWORD dwFlags) -{ - - if (isalnum(ch)) - return FALSE; - - if(dwFlags & URL_ESCAPE_SPACES_ONLY) { - if(ch == ' ') - return TRUE; - else - return FALSE; - } - - if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%')) - return TRUE; - - if (ch <= 31 || ch >= 127) - return TRUE; - - else { - switch (ch) { - case ' ': - case '<': - case '>': - case '\"': - case '{': - case '}': - case '|': -/* case '\\': */ - case '^': - case ']': - case '[': - case '`': - case '&': - return TRUE; - - case '/': - case '?': - if (dwFlags & URL_ESCAPE_SEGMENT_ONLY) return TRUE; - default: - return FALSE; - } - } -} - -static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags) -{ - - if (isalnumW(ch)) - return FALSE; - - if(dwFlags & URL_ESCAPE_SPACES_ONLY) { - if(ch == L' ') - return TRUE; - else - return FALSE; - } - - if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == L'%')) - return TRUE; - - if (ch <= 31 || ch >= 127) - return TRUE; - - else { - switch (ch) { - case L' ': - case L'<': - case L'>': - case L'\"': - case L'{': - case L'}': - case L'|': - case L'\\': - case L'^': - case L']': - case L'[': - case L'`': - case L'&': - return TRUE; - - case L'/': - case L'?': - if (dwFlags & URL_ESCAPE_SEGMENT_ONLY) return TRUE; - default: - return FALSE; - } - } -} - static BOOL URL_JustLocation(LPCWSTR str) { while(*str && (*str == L'/')) str++; @@ -276,25 +145,25 @@ static BOOL URL_JustLocation(LPCWSTR str) * Success: S_OK. y contains the parsed Url details. * Failure: An HRESULT error code. */ -DWORD WINAPI ParseURLA(LPCSTR x, UNKNOWN_SHLWAPI_1 *y) +HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y) { DWORD cnt; const SHL_2_inet_scheme *inet_pro; - y->fcncde = URL_SCHEME_INVALID; - if (y->size != 0x18) return E_INVALIDARG; + y->nScheme = URL_SCHEME_INVALID; + if (y->cbSize != sizeof(*y)) return E_INVALIDARG; /* FIXME: leading white space generates error of 0x80041001 which * is undefined */ if (*x <= ' ') return 0x80041001; cnt = 0; - y->sizep1 = 0; - y->ap1 = x; + y->cchProtocol = 0; + y->pszProtocol = x; while (*x) { if (*x == ':') { - y->sizep1 = cnt; + y->cchProtocol = cnt; cnt = -1; - y->ap2 = x+1; + y->pszSuffix = x+1; break; } x++; @@ -303,21 +172,21 @@ DWORD WINAPI ParseURLA(LPCSTR x, UNKNOWN_SHLWAPI_1 *y) /* check for no scheme in string start */ /* (apparently schemes *must* be larger than a single character) */ - if ((*x == '\0') || (y->sizep1 <= 1)) { - y->ap1 = 0; + if ((*x == '\0') || (y->cchProtocol <= 1)) { + y->pszProtocol = NULL; return 0x80041001; } /* found scheme, set length of remainder */ - y->sizep2 = lstrlenA(y->ap2); + y->cchSuffix = lstrlenA(y->pszSuffix); /* see if known scheme and return indicator number */ - y->fcncde = URL_SCHEME_UNKNOWN; + y->nScheme = URL_SCHEME_UNKNOWN; inet_pro = shlwapi_schemes; while (inet_pro->scheme_name) { - if (!strncasecmp(inet_pro->scheme_name, y->ap1, - min(y->sizep1, lstrlenA(inet_pro->scheme_name)))) { - y->fcncde = inet_pro->scheme_number; + if (!strncasecmp(inet_pro->scheme_name, y->pszProtocol, + min(y->cchProtocol, lstrlenA(inet_pro->scheme_name)))) { + y->nScheme = inet_pro->scheme_number; break; } inet_pro++; @@ -330,27 +199,27 @@ DWORD WINAPI ParseURLA(LPCSTR x, UNKNOWN_SHLWAPI_1 *y) * * Unicode version of ParseURLA. */ -DWORD WINAPI ParseURLW(LPCWSTR x, UNKNOWN_SHLWAPI_2 *y) +HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y) { DWORD cnt; const SHL_2_inet_scheme *inet_pro; LPSTR cmpstr; INT len; - y->fcncde = URL_SCHEME_INVALID; - if (y->size != 0x18) return E_INVALIDARG; + y->nScheme = URL_SCHEME_INVALID; + if (y->cbSize != sizeof(*y)) return E_INVALIDARG; /* FIXME: leading white space generates error of 0x80041001 which * is undefined */ if (*x <= L' ') return 0x80041001; cnt = 0; - y->sizep1 = 0; - y->ap1 = x; + y->cchProtocol = 0; + y->pszProtocol = x; while (*x) { if (*x == L':') { - y->sizep1 = cnt; + y->cchProtocol = cnt; cnt = -1; - y->ap2 = x+1; + y->pszSuffix = x+1; break; } x++; @@ -359,24 +228,24 @@ DWORD WINAPI ParseURLW(LPCWSTR x, UNKNOWN_SHLWAPI_2 *y) /* check for no scheme in string start */ /* (apparently schemes *must* be larger than a single character) */ - if ((*x == L'\0') || (y->sizep1 <= 1)) { - y->ap1 = 0; + if ((*x == L'\0') || (y->cchProtocol <= 1)) { + y->pszProtocol = NULL; return 0x80041001; } /* found scheme, set length of remainder */ - y->sizep2 = lstrlenW(y->ap2); + y->cchSuffix = lstrlenW(y->pszSuffix); /* see if known scheme and return indicator number */ - len = WideCharToMultiByte(0, 0, y->ap1, y->sizep1, 0, 0, 0, 0); + len = WideCharToMultiByte(0, 0, y->pszProtocol, y->cchProtocol, 0, 0, 0, 0); cmpstr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len); - WideCharToMultiByte(0, 0, y->ap1, y->sizep1, cmpstr, len, 0, 0); - y->fcncde = URL_SCHEME_UNKNOWN; + WideCharToMultiByte(0, 0, y->pszProtocol, y->cchProtocol, cmpstr, len, 0, 0); + y->nScheme = URL_SCHEME_UNKNOWN; inet_pro = shlwapi_schemes; while (inet_pro->scheme_name) { if (!strncasecmp(inet_pro->scheme_name, cmpstr, min(len, lstrlenA(inet_pro->scheme_name)))) { - y->fcncde = inet_pro->scheme_number; + y->nScheme = inet_pro->scheme_number; break; } inet_pro++; @@ -459,7 +328,8 @@ HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, HRESULT hr = S_OK; DWORD EscapeFlags; LPWSTR lpszUrlCpy, wk1, wk2, mp, root; - INT nLen, nByteLen, state; + INT nByteLen, state; + DWORD nLen; TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszCanonicalized, pcchCanonicalized, dwFlags); @@ -684,7 +554,7 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, LPWSTR pszCombined, LPDWORD pcchCombined, DWORD dwFlags) { - UNKNOWN_SHLWAPI_2 base, relative; + PARSEDURLW base, relative; DWORD myflags, sizeloc = 0; DWORD len, res1, res2, process_case = 0; LPWSTR work, preliminary, mbase, mrelative; @@ -699,8 +569,8 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, if(!pszBase || !pszRelative || !pcchCombined) return E_INVALIDARG; - base.size = 24; - relative.size = 24; + base.cbSize = sizeof(base); + relative.cbSize = sizeof(relative); /* Get space for duplicates of the input and the output */ preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) * @@ -728,7 +598,7 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, else do { /* get size of location field (if it exists) */ - work = (LPWSTR)base.ap2; + work = (LPWSTR)base.pszSuffix; sizeloc = 0; if (*work++ == L'/') { if (*work++ == L'/') { @@ -736,23 +606,23 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, * it ends at next '/' or end of string. */ while(*work && (*work != L'/')) work++; - sizeloc = (DWORD)(work - base.ap2); + sizeloc = (DWORD)(work - base.pszSuffix); } } /* Change .sizep2 to not have the last leaf in it, * Note: we need to start after the location (if it exists) */ - work = strrchrW((base.ap2+sizeloc), L'/'); + work = strrchrW((base.pszSuffix+sizeloc), L'/'); if (work) { - len = (DWORD)(work - base.ap2 + 1); - base.sizep2 = len; + len = (DWORD)(work - base.pszSuffix + 1); + base.cchSuffix = len; } /* * At this point: - * .ap2 points to location (starting with '//') - * .sizep2 length of location (above) and rest less the last - * leaf (if any) + * .pszSuffix points to location (starting with '//') + * .cchSuffix length of location (above) and rest less the last + * leaf (if any) * sizeloc length of location (above) up to but not including * the last '/' */ @@ -761,8 +631,8 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, if (res2) { /* no scheme in pszRelative */ TRACE("no scheme detected in Relative\n"); - relative.ap2 = mrelative; /* case 3,4,5 depends on this */ - relative.sizep2 = strlenW(mrelative); + relative.pszSuffix = mrelative; /* case 3,4,5 depends on this */ + relative.cchSuffix = strlenW(mrelative); if (*pszRelative == L':') { /* case that is either left alone or uses pszBase */ if (dwFlags & URL_PLUGGABLE_PROTOCOL) { @@ -788,21 +658,21 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, process_case = 4; break; } - process_case = (*base.ap2 == L'/') ? 5 : 3; + process_case = (*base.pszSuffix == L'/') ? 5 : 3; break; } /* handle cases where pszRelative has scheme */ - if ((base.sizep1 == relative.sizep1) && - (strncmpW(base.ap1, relative.ap1, base.sizep1) == 0)) { + if ((base.cchProtocol == relative.cchProtocol) && + (strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) { /* since the schemes are the same */ - if ((*relative.ap2 == L'/') && (*(relative.ap2+1) == L'/')) { + if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) { /* case where pszRelative replaces location and following */ process_case = 3; break; } - if (*relative.ap2 == L'/') { + if (*relative.pszSuffix == L'/') { /* case where pszRelative is root to location */ process_case = 4; break; @@ -811,7 +681,7 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, process_case = 5; break; } - if ((*relative.ap2 == L'/') && (*(relative.ap2+1) == L'/')) { + if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) { /* case where pszRelative replaces scheme, location, * and following and handles PLUGGABLE */ @@ -839,7 +709,7 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, */ strcpyW(preliminary, mrelative); if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) && - URL_JustLocation(relative.ap2)) + URL_JustLocation(relative.pszSuffix)) strcatW(preliminary, single_slash); break; @@ -847,11 +717,11 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, * Return the pszBase scheme with pszRelative. Basically * keeps the scheme and replaces the domain and following. */ - strncpyW(preliminary, base.ap1, base.sizep1 + 1); - work = preliminary + base.sizep1 + 1; - strcpyW(work, relative.ap2); + strncpyW(preliminary, base.pszProtocol, base.cchProtocol + 1); + work = preliminary + base.cchProtocol + 1; + strcpyW(work, relative.pszSuffix); if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) && - URL_JustLocation(relative.ap2)) + URL_JustLocation(relative.pszSuffix)) strcatW(work, single_slash); break; @@ -860,22 +730,22 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, * after the location is pszRelative. (Replace document * from root on.) */ - strncpyW(preliminary, base.ap1, base.sizep1+1+sizeloc); - work = preliminary + base.sizep1 + 1 + sizeloc; + strncpyW(preliminary, base.pszProtocol, base.cchProtocol+1+sizeloc); + work = preliminary + base.cchProtocol + 1 + sizeloc; if (dwFlags & URL_PLUGGABLE_PROTOCOL) *(work++) = L'/'; - strcpyW(work, relative.ap2); + strcpyW(work, relative.pszSuffix); break; case 5: /* * Return the pszBase without its document (if any) and * append pszRelative after its scheme. */ - strncpyW(preliminary, base.ap1, base.sizep1+1+base.sizep2); - work = preliminary + base.sizep1+1+base.sizep2 - 1; + strncpyW(preliminary, base.pszProtocol, base.cchProtocol+1+base.cchSuffix); + work = preliminary + base.cchProtocol+1+base.cchSuffix - 1; if (*work++ != L'/') *(work++) = L'/'; - strcpyW(work, relative.ap2); + strcpyW(work, relative.pszSuffix); break; default: @@ -898,6 +768,107 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, /************************************************************************* * UrlEscapeA [SHLWAPI.@] + */ + +HRESULT WINAPI UrlEscapeA( + LPCSTR pszUrl, + LPSTR pszEscaped, + LPDWORD pcchEscaped, + DWORD dwFlags) +{ + WCHAR bufW[INTERNET_MAX_URL_LENGTH]; + WCHAR *escapedW = bufW; + UNICODE_STRING urlW; + HRESULT ret; + DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; + + if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) + return E_INVALIDARG; + if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) { + escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); + ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags); + } + if(ret == S_OK) { + RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR)); + if(*pcchEscaped > lenA) { + RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR)); + pszEscaped[lenA] = 0; + *pcchEscaped = lenA; + } else { + *pcchEscaped = lenA + 1; + ret = E_POINTER; + } + } + if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW); + RtlFreeUnicodeString(&urlW); + return ret; +} + +#define WINE_URL_BASH_AS_SLASH 0x01 +#define WINE_URL_COLLAPSE_SLASHES 0x02 +#define WINE_URL_ESCAPE_SLASH 0x04 +#define WINE_URL_ESCAPE_HASH 0x08 +#define WINE_URL_ESCAPE_QUESTION 0x10 +#define WINE_URL_STOP_ON_HASH 0x20 +#define WINE_URL_STOP_ON_QUESTION 0x40 + +static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags, DWORD int_flags) +{ + + if (isalnumW(ch)) + return FALSE; + + if(dwFlags & URL_ESCAPE_SPACES_ONLY) { + if(ch == ' ') + return TRUE; + else + return FALSE; + } + + if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%')) + return TRUE; + + if (ch <= 31 || ch >= 127) + return TRUE; + + else { + switch (ch) { + case ' ': + case '<': + case '>': + case '\"': + case '{': + case '}': + case '|': + case '\\': + case '^': + case ']': + case '[': + case '`': + case '&': + return TRUE; + + case '/': + if (int_flags & WINE_URL_ESCAPE_SLASH) return TRUE; + return FALSE; + + case '?': + if (int_flags & WINE_URL_ESCAPE_QUESTION) return TRUE; + return FALSE; + + case '#': + if (int_flags & WINE_URL_ESCAPE_HASH) return TRUE; + return FALSE; + + default: + return FALSE; + } + } +} + + +/************************************************************************* + * UrlEscapeW [SHLWAPI.@] * * Converts unsafe characters in a Url into escape sequences. * @@ -912,12 +883,12 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, * contains its length. * Failure: E_POINTER, if pszEscaped is not large enough. In this case * pcchEscaped is set to the required length. - + * * Converts unsafe characters into their escape sequences. * * NOTES * - By default this function stops converting at the first '?' or - * '#' character (MSDN does not document this). + * '#' character. * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are * converted, but the conversion continues past a '?' or '#'. * - Note that this function did not work well (or at all) in shlwapi version 4. @@ -929,82 +900,6 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, *| URL_ESCAPE_SEGMENT_ONLY *| URL_ESCAPE_PERCENT */ -HRESULT WINAPI UrlEscapeA( - LPCSTR pszUrl, - LPSTR pszEscaped, - LPDWORD pcchEscaped, - DWORD dwFlags) -{ - LPCSTR src; - DWORD needed = 0, ret; - BOOL stop_escaping = FALSE; - char next[3], *dst = pszEscaped; - INT len; - - TRACE("(%s %p %lx 0x%08lx)\n", debugstr_a(pszUrl), pszEscaped, - pcchEscaped?*pcchEscaped:0, dwFlags); - - if(!pszUrl || !pszEscaped || !pcchEscaped) - return E_INVALIDARG; - - if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY | - URL_ESCAPE_SEGMENT_ONLY | - URL_DONT_ESCAPE_EXTRA_INFO | - URL_ESCAPE_PERCENT)) - FIXME("Unimplemented flags: %08lx\n", dwFlags); - - /* fix up flags */ - if (dwFlags & URL_ESCAPE_SPACES_ONLY) - /* if SPACES_ONLY specified, reset the other controls */ - dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO | - URL_ESCAPE_PERCENT | - URL_ESCAPE_SEGMENT_ONLY); - - else - /* if SPACES_ONLY *not* specified then assume DONT_ESCAPE_EXTRA_INFO */ - dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO; - - for(src = pszUrl; *src; src++) { - if(!(dwFlags & URL_ESCAPE_SEGMENT_ONLY) && - (dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) && - (*src == '#' || *src == '?')) - stop_escaping = TRUE; - - if(URL_NeedEscapeA(*src, dwFlags) && stop_escaping == FALSE) { - /* TRACE("escaping %c\n", *src); */ - next[0] = '%'; - next[1] = hexDigits[(*src >> 4) & 0xf]; - next[2] = hexDigits[*src & 0xf]; - len = 3; - } else { - /* TRACE("passing %c\n", *src); */ - next[0] = *src; - len = 1; - } - - if(needed + len <= *pcchEscaped) { - memcpy(dst, next, len); - dst += len; - } - needed += len; - } - - if(needed < *pcchEscaped) { - *dst = '\0'; - ret = S_OK; - } else { - needed++; /* add one for the '\0' */ - ret = E_POINTER; - } - *pcchEscaped = needed; - return ret; -} - -/************************************************************************* - * UrlEscapeW [SHLWAPI.@] - * - * See UrlEscapeA. - */ HRESULT WINAPI UrlEscapeW( LPCWSTR pszUrl, LPWSTR pszEscaped, @@ -1016,6 +911,10 @@ HRESULT WINAPI UrlEscapeW( BOOL stop_escaping = FALSE; WCHAR next[5], *dst = pszEscaped; INT len; + PARSEDURLW parsed_url; + DWORD int_flags; + DWORD slashes = 0; + static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0}; TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped, pcchEscaped, dwFlags); @@ -1040,39 +939,101 @@ HRESULT WINAPI UrlEscapeW( /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */ dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO; - for(src = pszUrl; *src; src++) { - /* - * if(!(dwFlags & URL_ESCAPE_SPACES_ONLY) && - * (*src == L'#' || *src == L'?')) - * stop_escaping = TRUE; - */ - if(!(dwFlags & URL_ESCAPE_SEGMENT_ONLY) && - (dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) && - (*src == L'#' || *src == L'?')) - stop_escaping = TRUE; - if(URL_NeedEscapeW(*src, dwFlags) && stop_escaping == FALSE) { - /* TRACE("escaping %c\n", *src); */ - next[0] = L'%'; - /* - * I would have assumed that the W form would escape - * the character with 4 hex digits (or even 8), - * however, experiments show that native shlwapi escapes - * with only 2 hex digits. - * next[1] = hexDigits[(*src >> 12) & 0xf]; - * next[2] = hexDigits[(*src >> 8) & 0xf]; - * next[3] = hexDigits[(*src >> 4) & 0xf]; - * next[4] = hexDigits[*src & 0xf]; - * len = 5; - */ - next[1] = hexDigits[(*src >> 4) & 0xf]; - next[2] = hexDigits[*src & 0xf]; - len = 3; - } else { - /* TRACE("passing %c\n", *src); */ - next[0] = *src; - len = 1; - } + int_flags = 0; + if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) { + int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH; + } else { + parsed_url.cbSize = sizeof(parsed_url); + if(ParseURLW(pszUrl, &parsed_url) != S_OK) + parsed_url.nScheme = URL_SCHEME_INVALID; + + TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol)); + + if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) + int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION; + + switch(parsed_url.nScheme) { + case URL_SCHEME_FILE: + int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH; + int_flags &= ~WINE_URL_STOP_ON_HASH; + break; + + case URL_SCHEME_HTTP: + case URL_SCHEME_HTTPS: + int_flags |= WINE_URL_BASH_AS_SLASH; + if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\') + int_flags |= WINE_URL_ESCAPE_SLASH; + break; + + case URL_SCHEME_MAILTO: + int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH; + int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH); + break; + + case URL_SCHEME_INVALID: + break; + + case URL_SCHEME_FTP: + default: + if(parsed_url.pszSuffix[0] != '/') + int_flags |= WINE_URL_ESCAPE_SLASH; + break; + } + } + + for(src = pszUrl; *src; ) { + WCHAR cur = *src; + len = 0; + + if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) { + int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1; + while(cur == '/' || cur == '\\') { + slashes++; + cur = *++src; + } + if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */ + if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\') + src += localhost_len + 1; + slashes = 3; + } + + switch(slashes) { + case 1: + case 3: + next[0] = next[1] = next[2] = '/'; + len = 3; + break; + case 0: + len = 0; + break; + default: + next[0] = next[1] = '/'; + len = 2; + break; + } + } + if(len == 0) { + + if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH)) + stop_escaping = TRUE; + + if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION)) + stop_escaping = TRUE; + + if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/'; + + if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) { + next[0] = L'%'; + next[1] = hexDigits[(cur >> 4) & 0xf]; + next[2] = hexDigits[cur & 0xf]; + len = 3; + } else { + next[0] = cur; + len = 1; + } + src++; + } if(needed + len <= *pcchEscaped) { memcpy(dst, next, len*sizeof(WCHAR)); @@ -1082,7 +1043,7 @@ HRESULT WINAPI UrlEscapeW( } if(needed < *pcchEscaped) { - *dst = L'\0'; + *dst = '\0'; ret = S_OK; } else { needed++; /* add one for the '\0' */ @@ -1211,10 +1172,10 @@ HRESULT WINAPI UrlUnescapeW( } else if(*src == L'%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2)) && stop_unescaping == FALSE) { INT ih; - WCHAR buf[3]; - memcpy(buf, src + 1, 2*sizeof(WCHAR)); - buf[2] = L'\0'; - ih = StrToIntW(buf); + WCHAR buf[5] = {'0','x',0}; + memcpy(buf + 2, src + 1, 2*sizeof(WCHAR)); + buf[4] = 0; + StrToIntExW(buf, STIF_SUPPORT_HEX, &ih); next = (WCHAR) ih; src += 2; /* Advance to end of escape */ } else @@ -1271,18 +1232,18 @@ HRESULT WINAPI UrlUnescapeW( LPCSTR WINAPI UrlGetLocationA( LPCSTR pszUrl) { - UNKNOWN_SHLWAPI_1 base; + PARSEDURLA base; DWORD res1; - base.size = 24; + base.cbSize = sizeof(base); res1 = ParseURLA(pszUrl, &base); if (res1) return NULL; /* invalid scheme */ /* if scheme is file: then never return pointer */ - if (strncmp(base.ap1, "file", min(4,base.sizep1)) == 0) return NULL; + if (strncmp(base.pszProtocol, "file", min(4,base.cchProtocol)) == 0) return NULL; /* Look for '#' and return its addr */ - return strchr(base.ap2, '#'); + return strchr(base.pszSuffix, '#'); } /************************************************************************* @@ -1293,18 +1254,18 @@ LPCSTR WINAPI UrlGetLocationA( LPCWSTR WINAPI UrlGetLocationW( LPCWSTR pszUrl) { - UNKNOWN_SHLWAPI_2 base; + PARSEDURLW base; DWORD res1; - base.size = 24; + base.cbSize = sizeof(base); res1 = ParseURLW(pszUrl, &base); if (res1) return NULL; /* invalid scheme */ /* if scheme is file: then never return pointer */ - if (strncmpW(base.ap1, fileW, min(4,base.sizep1)) == 0) return NULL; + if (strncmpW(base.pszProtocol, fileW, min(4,base.cchProtocol)) == 0) return NULL; /* Look for '#' and return its addr */ - return strchrW(base.ap2, L'#'); + return strchrW(base.pszSuffix, L'#'); } /************************************************************************* @@ -1590,7 +1551,7 @@ static HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) */ HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) { - UNKNOWN_SHLWAPI_2 in_scheme; + PARSEDURLW in_scheme; DWORD res1; HRESULT ret; @@ -1605,7 +1566,7 @@ HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DW return S_FALSE; } - in_scheme.size = 24; + in_scheme.cbSize = sizeof(in_scheme); /* See if the base has a scheme */ res1 = ParseURLW(pszIn, &in_scheme); if (res1) { @@ -1617,7 +1578,7 @@ HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DW } else { /* we have a scheme, see if valid (known scheme) */ - if (in_scheme.fcncde) { + if (in_scheme.nScheme) { /* have valid scheme, so just copy and exit */ if (strlenW(pszIn) + 1 > *pcchOut) { *pcchOut = strlenW(pszIn) + 1; @@ -1666,17 +1627,17 @@ HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DW */ BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis) { - UNKNOWN_SHLWAPI_1 base; + PARSEDURLA base; DWORD res1; LPCSTR last; switch (Urlis) { case URLIS_OPAQUE: - base.size = 24; + base.cbSize = sizeof(base); res1 = ParseURLA(pszUrl, &base); if (res1) return FALSE; /* invalid scheme */ - if ((*base.ap2 == '/') && (*(base.ap2+1) == '/')) + if ((*base.pszSuffix == '/') && (*(base.pszSuffix+1) == '/')) /* has scheme followed by 2 '/' */ return FALSE; return TRUE; @@ -1706,17 +1667,17 @@ BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis) BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis) { static const WCHAR stemp[] = { 'f','i','l','e',':','/','/',0 }; - UNKNOWN_SHLWAPI_2 base; + PARSEDURLW base; DWORD res1; LPCWSTR last; switch (Urlis) { case URLIS_OPAQUE: - base.size = 24; + base.cbSize = sizeof(base); res1 = ParseURLW(pszUrl, &base); if (res1) return FALSE; /* invalid scheme */ - if ((*base.ap2 == '/') && (*(base.ap2+1) == '/')) + if ((*base.pszSuffix == '/') && (*(base.pszSuffix+1) == '/')) /* has scheme followed by 2 '/' */ return FALSE; return TRUE; @@ -2109,15 +2070,15 @@ HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, */ BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) { - UNKNOWN_SHLWAPI_1 base; + PARSEDURLA base; DWORD res1; if (!lpstrPath || !*lpstrPath) return FALSE; /* get protocol */ - base.size = sizeof(base); + base.cbSize = sizeof(base); res1 = ParseURLA(lpstrPath, &base); - return (base.fcncde > 0); + return (base.nScheme != URL_SCHEME_INVALID); } /************************************************************************* @@ -2127,20 +2088,55 @@ BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) */ BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) { - UNKNOWN_SHLWAPI_2 base; + PARSEDURLW base; DWORD res1; if (!lpstrPath || !*lpstrPath) return FALSE; /* get protocol */ - base.size = sizeof(base); + base.cbSize = sizeof(base); res1 = ParseURLW(lpstrPath, &base); - return (base.fcncde > 0); + return (base.nScheme != URL_SCHEME_INVALID); } /************************************************************************* * UrlCreateFromPathA [SHLWAPI.@] * + * See UrlCreateFromPathW + */ +HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) +{ + WCHAR bufW[INTERNET_MAX_URL_LENGTH]; + WCHAR *urlW = bufW; + UNICODE_STRING pathW; + HRESULT ret; + DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; + + if(!RtlCreateUnicodeStringFromAsciiz(&pathW, pszPath)) + return E_INVALIDARG; + if((ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved)) == E_POINTER) { + urlW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); + ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved); + } + if(ret == S_OK || ret == S_FALSE) { + RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR)); + if(*pcchUrl > lenA) { + RtlUnicodeToMultiByteN(pszUrl, *pcchUrl - 1, &lenA, urlW, lenW * sizeof(WCHAR)); + pszUrl[lenA] = 0; + *pcchUrl = lenA; + } else { + *pcchUrl = lenA + 1; + ret = E_POINTER; + } + } + if(urlW != bufW) HeapFree(GetProcessHeap(), 0, urlW); + RtlFreeUnicodeString(&pathW); + return ret; +} + +/************************************************************************* + * UrlCreateFromPathW [SHLWAPI.@] + * * Create a Url from a file path. * * PARAMS @@ -2150,206 +2146,51 @@ BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) * dwReserved [I] Reserved, must be 0 * * RETURNS - * Success: S_OK. pszUrl contains the converted path. + * Success: S_OK pszUrl contains the converted path, S_FALSE if the path is already a Url * Failure: An HRESULT error code. */ -HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) -{ - DWORD nCharBeforeColon = 0; - DWORD nSlashes = 0; - DWORD dwChRequired = 0; - LPSTR pszNewUrl = NULL; - LPCSTR pszConstPointer = NULL; - LPSTR pszPointer = NULL; - DWORD i; - HRESULT ret; - - TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_a(pszPath), pszUrl, pcchUrl, dwReserved); - - /* Validate arguments */ - if (dwReserved != 0) - { - FIXME("dwReserved should be 0: 0x%08lx\n", dwReserved); - return E_INVALIDARG; - } - if (!pszUrl || !pcchUrl || !pszUrl) - { - ERR("Invalid argument\n"); - return E_INVALIDARG; - } - - for (pszConstPointer = pszPath; *pszConstPointer; pszConstPointer++) - { - if (isalpha(*pszConstPointer) || isdigit(*pszConstPointer) || - *pszConstPointer == '.' || *pszConstPointer == '-') - nCharBeforeColon++; - else break; - } - if (*pszConstPointer == ':') /* then already in URL format, so copy */ - { - dwChRequired = lstrlenA(pszPath); - if (dwChRequired > *pcchUrl) - { - *pcchUrl = dwChRequired; - return E_POINTER; - } - else - { - *pcchUrl = dwChRequired; - StrCpyA(pszUrl, pszPath); - return S_FALSE; - } - } - /* then must need converting to file: format */ - - /* Strip off leading slashes */ - while (*pszPath == '\\' || *pszPath == '/') - { - pszPath++; - nSlashes++; - } - - dwChRequired = *pcchUrl; /* UrlEscape will fill this in with the correct amount */ - TRACE("pszUrl: %s\n", debugstr_a(pszPath)); - pszNewUrl = HeapAlloc(GetProcessHeap(), 0, dwChRequired + 1); - ret = UrlEscapeA(pszPath, pszNewUrl, &dwChRequired, URL_ESCAPE_PERCENT); - TRACE("ret: 0x%08lx, pszUrl: %s\n", ret, debugstr_a(pszNewUrl)); - TRACE("%ld\n", dwChRequired); - if (ret != E_POINTER && FAILED(ret)) - return ret; - dwChRequired += 5; /* "file:" */ - if ((lstrlenA(pszUrl) > 1) && isalpha(pszUrl[0]) && (pszUrl[1] == ':')) - { - dwChRequired += 3; /* "///" */ - nSlashes = 3; - } - else - switch (nSlashes) - { - case 0: /* no slashes */ - break; - case 2: /* two slashes */ - case 4: - case 5: - case 6: - dwChRequired += 2; - nSlashes = 2; - break; - default: /* three slashes */ - dwChRequired += 3; - nSlashes = 3; - } - - if (dwChRequired > *pcchUrl) - return E_POINTER; - *pcchUrl = dwChRequired; /* Return number of chars required (not including termination) */ - StrCpyA(pszUrl, "file:"); - pszPointer = pszUrl + lstrlenA(pszUrl); - for (i=0; i < nSlashes; i++) - { - *pszPointer = '/'; - pszPointer++; - } - StrCpyA(pszPointer, pszNewUrl); - TRACE("<- %s\n", debugstr_a(pszUrl)); - return S_OK; -} - -/************************************************************************* - * UrlCreateFromPathW [SHLWAPI.@] - * - * See UrlCreateFromPathA. - */ HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) { - DWORD nCharBeforeColon = 0; - DWORD nSlashes = 0; - DWORD dwChRequired = 0; - LPWSTR pszNewUrl = NULL; - LPCWSTR pszConstPointer = NULL; - LPWSTR pszPointer = NULL; - DWORD i; - HRESULT ret; + DWORD needed; + HRESULT ret; + WCHAR *pszNewUrl; + WCHAR file_colonW[] = {'f','i','l','e',':',0}; + WCHAR three_slashesW[] = {'/','/','/',0}; + PARSEDURLW parsed_url; - TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved); + TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved); - /* Validate arguments */ - if (dwReserved != 0) - return E_INVALIDARG; - if (!pszUrl || !pcchUrl || !pszUrl) - return E_INVALIDARG; + /* Validate arguments */ + if (dwReserved != 0) + return E_INVALIDARG; + if (!pszUrl || !pcchUrl) + return E_INVALIDARG; - for (pszConstPointer = pszPath; *pszConstPointer; pszConstPointer++) - { - if (isalphaW(*pszConstPointer) || isdigitW(*pszConstPointer) || - *pszConstPointer == '.' || *pszConstPointer == '-') - nCharBeforeColon++; - else break; + + parsed_url.cbSize = sizeof(parsed_url); + if(ParseURLW(pszPath, &parsed_url) == S_OK) { + if(parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1) { + needed = strlenW(pszPath); + if (needed >= *pcchUrl) { + *pcchUrl = needed + 1; + return E_POINTER; + } else { + *pcchUrl = needed; + strcpyW(pszUrl, pszPath); + return S_FALSE; + } } - if (*pszConstPointer == ':') /* then already in URL format, so copy */ - { - dwChRequired = lstrlenW(pszPath); - *pcchUrl = dwChRequired; - if (dwChRequired > *pcchUrl) - return E_POINTER; - else - { - StrCpyW(pszUrl, pszPath); - return S_FALSE; - } - } - /* then must need converting to file: format */ + } - /* Strip off leading slashes */ - while (*pszPath == '\\' || *pszPath == '/') - { - pszPath++; - nSlashes++; - } + pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath) + 9) * sizeof(WCHAR)); /* "file:///" + pszPath_len + 1 */ + strcpyW(pszNewUrl, file_colonW); + if(isalphaW(pszPath[0]) && pszPath[1] == ':') + strcatW(pszNewUrl, three_slashesW); + strcatW(pszNewUrl, pszPath); + ret = UrlEscapeW(pszNewUrl, pszUrl, pcchUrl, URL_ESCAPE_PERCENT); - dwChRequired = *pcchUrl; /* UrlEscape will fill this in with the correct amount */ - ret = UrlEscapeW(pszPath, pszUrl, &dwChRequired, URL_ESCAPE_PERCENT); - if (ret != E_POINTER && FAILED(ret)) - return ret; - dwChRequired += 5; /* "file:" */ - if ((lstrlenW(pszUrl) > 1) && isalphaW(pszUrl[0]) && (pszUrl[1] == ':')) - { - dwChRequired += 3; /* "///" */ - nSlashes = 3; - } - else - switch (nSlashes) - { - case 0: /* no slashes */ - break; - case 2: /* two slashes */ - case 4: - case 5: - case 6: - dwChRequired += 2; - nSlashes = 2; - break; - default: /* three slashes */ - dwChRequired += 3; - nSlashes = 3; - } - - *pcchUrl = dwChRequired; /* Return number of chars required (not including termination) */ - if (dwChRequired > *pcchUrl) - return E_POINTER; - pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (dwChRequired + 1) * sizeof(WCHAR)); - StrCpyW(pszNewUrl, fileW); - pszPointer = pszNewUrl + 4; - *pszPointer = ':'; - pszPointer++; - for (i=0; i < nSlashes; i++) - { - *pszPointer = '/'; - pszPointer++; - } - StrCpyW(pszPointer, pszPath); - StrCpyW(pszUrl, pszNewUrl); - return S_OK; + HeapFree(GetProcessHeap(), 0, pszNewUrl); + return ret; } /************************************************************************* diff --git a/reactos/lib/shlwapi/winehq2ros.patch b/reactos/lib/shlwapi/winehq2ros.patch index 50cbdef795a..835b64d4a61 100644 --- a/reactos/lib/shlwapi/winehq2ros.patch +++ b/reactos/lib/shlwapi/winehq2ros.patch @@ -1,25 +1,160 @@ +Index: ordinal.c +=================================================================== +RCS file: /home/wine/wine/dlls/shlwapi/ordinal.c,v +retrieving revision 1.98 +diff -u -r1.98 ordinal.c +--- ordinal.c 25 Sep 2004 00:29:30 -0000 1.98 ++++ ordinal.c 20 Oct 2004 16:50:41 -0000 +@@ -1549,16 +1549,17 @@ + LPVOID *p2) /* [out] ptr for call results */ + { + DWORD ret, aa; ++ IUnknown *iobjectwithsite; + + if (!p1) return E_FAIL; + + /* see if SetSite interface exists for IObjectWithSite object */ +- ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id1, (LPVOID *)&p1); +- TRACE("first IU_QI ret=%08lx, p1=%p\n", ret, p1); ++ ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id1, (LPVOID *)&iobjectwithsite); ++ TRACE("first IU_QI ret=%08lx, iobjectwithsite=%p\n", ret, iobjectwithsite); + if (ret) { + + /* see if GetClassId interface exists for IPersistMoniker object */ +- ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id2, (LPVOID *)&aa); ++ ret = IUnknown_QueryInterface(p1, (REFIID)id2, (LPVOID *)&aa); + TRACE("second IU_QI ret=%08lx, aa=%08lx\n", ret, aa); + if (ret) return ret; + +@@ -1570,10 +1571,10 @@ + } + else { + /* fake a SetSite call */ +- ret = IOleWindow_GetWindow((IOleWindow *)p1, (HWND*)p2); ++ ret = IOleWindow_GetWindow((IOleWindow *)iobjectwithsite, (HWND*)p2); + TRACE("first IU_QI doing 0x0c ret=%08lx, *p2=%08lx\n", ret, + *(LPDWORD)p2); +- IUnknown_Release((IUnknown *)p1); ++ IUnknown_Release((IUnknown *)iobjectwithsite); + } + return ret; + } Index: path.c =================================================================== RCS file: /home/wine/wine/dlls/shlwapi/path.c,v -retrieving revision 1.42 -diff -u -r1.42 path.c ---- path.c 20 Apr 2004 00:34:52 -0000 1.42 -+++ path.c 20 Aug 2004 07:09:34 -0000 -@@ -32,6 +32,7 @@ - #include "wingdi.h" - #include "winuser.h" - #include "winreg.h" -+#include "winnls.h" - #define NO_SHLWAPI_STREAM - #include "shlwapi.h" - #include "wine/debug.h" +retrieving revision 1.48 +diff -u -r1.48 path.c +--- path.c 5 Oct 2004 18:07:14 -0000 1.48 ++++ path.c 20 Oct 2004 16:50:42 -0000 +@@ -3989,3 +3989,101 @@ + return S_OK; + return E_FAIL; + } ++ ++#define PATH_CHAR_CLASS_LETTER 0x0001 ++#define PATH_CHAR_CLASS_ASTERIX 0x0002 ++#define PATH_CHAR_CLASS_DOT 0x0004 ++#define PATH_CHAR_CLASS_BACKSLASH 0x0008 ++#define PATH_CHAR_CLASS_COLON 0x0010 ++#define PATH_CHAR_CLASS_SEMICOLON 0x0020 ++#define PATH_CHAR_CLASS_COMMA 0x0040 ++#define PATH_CHAR_CLASS_SPACE 0x0080 ++#define PATH_CHAR_CLASS_OTHER_VALID 0x0100 ++#define PATH_CHAR_CLASS_DOUBLEQUOTE 0x0200 ++ ++/************************************************************************* ++ * PathIsValidCharAW [internal] ++ * ++ * Check if a char is of a certain class ++ */ ++static BOOL WINAPI PathIsValidCharAW(unsigned Ch, DWORD Class) ++{ ++ static struct ++ { ++ char Ch; ++ DWORD Class; ++ } CharClass[] = ++ { ++ { ' ', PATH_CHAR_CLASS_SPACE }, ++ { '!', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '"', PATH_CHAR_CLASS_DOUBLEQUOTE }, ++ { '#', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '$', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '%', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '&', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '\'', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '(', PATH_CHAR_CLASS_OTHER_VALID }, ++ { ')', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '*', PATH_CHAR_CLASS_ASTERIX }, ++ { '+', PATH_CHAR_CLASS_OTHER_VALID }, ++ { ',', PATH_CHAR_CLASS_COMMA }, ++ { '-', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '.', PATH_CHAR_CLASS_DOT }, ++ { ':', PATH_CHAR_CLASS_COLON }, ++ { ';', PATH_CHAR_CLASS_SEMICOLON }, ++ { '=', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '?', PATH_CHAR_CLASS_LETTER }, ++ { '@', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '[', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '\\', PATH_CHAR_CLASS_BACKSLASH }, ++ { ']', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '^', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '_', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '`', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '{', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '}', PATH_CHAR_CLASS_OTHER_VALID }, ++ { '~', PATH_CHAR_CLASS_OTHER_VALID }, ++ { 0x7f, PATH_CHAR_CLASS_OTHER_VALID } ++ }; ++ unsigned Index; ++ ++ if (('A' <= Ch && Ch <= 'Z') || ('a' <= Ch && Ch <= 'z')) ++ { ++ return (Class & PATH_CHAR_CLASS_LETTER); ++ } ++ ++ if (('0' <= Ch && Ch <= '9') || 0x80 <= Ch) ++ { ++ return (Class & PATH_CHAR_CLASS_OTHER_VALID); ++ } ++ ++ for (Index = 0; Index < sizeof(CharClass) / sizeof(CharClass[0]); Index++) ++ { ++ if (Ch == CharClass[Index].Ch) ++ { ++ return (Class & CharClass[Index].Class); ++ } ++ } ++ ++ return FALSE; ++} ++ ++/************************************************************************* ++ * @ [SHLWAPI.455] ++ * ++ * Check if an Ascii char is of a certain class ++ */ ++BOOL WINAPI PathIsValidCharA(char Ch, DWORD Class) ++{ ++ return PathIsValidCharAW((unsigned) Ch, Class); ++} ++ ++/************************************************************************* ++ * @ [SHLWAPI.456] ++ * ++ * Check if an Unicode char is of a certain class ++ */ ++BOOL WINAPI PathIsValidCharW(WCHAR Ch, DWORD Class) ++{ ++ return PathIsValidCharAW((unsigned) Ch, Class); ++} Index: shlwapi.spec =================================================================== RCS file: /home/wine/wine/dlls/shlwapi/shlwapi.spec,v -retrieving revision 1.93 -diff -u -r1.93 shlwapi.spec ---- shlwapi.spec 19 Jul 2004 19:32:51 -0000 1.93 -+++ shlwapi.spec 20 Aug 2004 07:09:34 -0000 +retrieving revision 1.96 +diff -u -r1.96 shlwapi.spec +--- shlwapi.spec 25 Sep 2004 00:29:30 -0000 1.96 ++++ shlwapi.spec 20 Oct 2004 16:50:42 -0000 @@ -368,9 +368,9 @@ 368 stdcall @(wstr wstr ptr long wstr) kernel32.GetPrivateProfileStructW 369 stdcall @(wstr wstr ptr ptr long long ptr wstr ptr ptr) kernel32.CreateProcessW @@ -42,24 +177,30 @@ diff -u -r1.93 shlwapi.spec 393 stdcall @(long ptr long ptr long) user32.CreateDialogIndirectParamW 394 stdcall @(long ptr long ptr long) user32.CreateDialogIndirectParamA 395 stub -noname MLWinHelpA -@@ -456,8 +456,8 @@ - 456 stub -noname PathIsValidCharW +@@ -452,12 +452,12 @@ + 452 stub -noname CharUpperNoDBCSW + 453 stub -noname CharLowerNoDBCSA + 454 stub -noname CharLowerNoDBCSW +-455 stub -noname PathIsValidCharA +-456 stub -noname PathIsValidCharW ++455 stdcall -noname PathIsValidCharA(long long) ++456 stdcall -noname PathIsValidCharW(long long) 457 stub -noname GetLongPathNameWrapW 458 stub -noname GetLongPathNameWrapA -459 stdcall -noname SHExpandEnvironmentStringsA(str ptr long) kernel32.ExpandEnvironmentStringsA -460 stdcall -noname SHExpandEnvironmentStringsW(wstr ptr long) kernel32.ExpandEnvironmentStringsW +459 stdcall SHExpandEnvironmentStringsA(str ptr long) kernel32.ExpandEnvironmentStringsA +460 stdcall SHExpandEnvironmentStringsW(wstr ptr long) kernel32.ExpandEnvironmentStringsW - 461 stdcall -noname SHGetAppCompatFlags() + 461 stdcall -noname SHGetAppCompatFlags(long) 462 stub -noname UrlFixupW 463 stub -noname SHExpandEnvironmentStringsForUserA Index: string.c =================================================================== RCS file: /home/wine/wine/dlls/shlwapi/string.c,v -retrieving revision 1.47 -diff -u -r1.47 string.c ---- string.c 21 Jul 2004 03:12:16 -0000 1.47 -+++ string.c 20 Aug 2004 07:09:35 -0000 +retrieving revision 1.49 +diff -u -r1.49 string.c +--- string.c 13 Sep 2004 18:11:56 -0000 1.49 ++++ string.c 20 Oct 2004 16:50:43 -0000 @@ -528,7 +528,7 @@ { TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); @@ -81,11 +222,11 @@ diff -u -r1.47 string.c Index: url.c =================================================================== RCS file: /home/wine/wine/dlls/shlwapi/url.c,v -retrieving revision 1.35 -diff -u -r1.35 url.c ---- url.c 4 Jul 2004 00:06:29 -0000 1.35 -+++ url.c 20 Aug 2004 07:09:36 -0000 -@@ -1386,8 +1386,8 @@ +retrieving revision 1.43 +diff -u -r1.43 url.c +--- url.c 5 Oct 2004 18:31:41 -0000 1.43 ++++ url.c 20 Oct 2004 16:50:44 -0000 +@@ -1347,8 +1347,8 @@ * Success: TRUE. lpDest is filled with the computed hash value. * Failure: FALSE, if any argument is invalid. */