UrlEscape has different rules depending on the protocol.
Added a load of tests.
This commit is contained in:
parent
477aa4501b
commit
7458de56ce
|
@ -76,6 +76,77 @@ const TEST_URL_ESCAPE TEST_ESCAPE[] = {
|
||||||
{"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests4\r"},
|
{"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests4\r"},
|
||||||
{"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests5\r"},
|
{"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests5\r"},
|
||||||
{"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"},
|
{"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"},
|
||||||
|
|
||||||
|
{"file://////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
|
||||||
|
{"file://///foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
|
||||||
|
{"file:////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
|
||||||
|
{"file:///localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
|
||||||
|
{"file:///foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
|
||||||
|
{"file://loCalHost/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
|
||||||
|
{"file://foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
|
||||||
|
{"file:/localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
|
||||||
|
{"file:/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
|
||||||
|
{"file:foo/bar\\baz", 0, 0, S_OK, "file:foo/bar/baz"},
|
||||||
|
{"file:\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
|
||||||
|
{"file:\\\\foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
|
||||||
|
{"file:\\\\\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
|
||||||
|
{"file:\\\\localhost\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
|
||||||
|
{"file:///f oo/b?a r\\baz", 0, 0, S_OK, "file:///f%20oo/b?a r\\baz"},
|
||||||
|
{"file:///foo/b#a r\\baz", 0, 0, S_OK, "file:///foo/b%23a%20r/baz"},
|
||||||
|
{"file:///f o^&`{}|][\"<>\\%o/b#a r\\baz", 0, 0, S_OK, "file:///f%20o%5E%26%60%7B%7D%7C%5D%5B%22%3C%3E/%o/b%23a%20r/baz"},
|
||||||
|
{"file:///f o%o/b?a r\\b%az", URL_ESCAPE_PERCENT, 0, S_OK, "file:///f%20o%25o/b?a r\\b%az"},
|
||||||
|
{"file:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "file:%2Ffoo%2Fbar%5Cbaz"},
|
||||||
|
|
||||||
|
{"foo/b%ar\\ba?z\\", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%ar%5Cba%3Fz%5C"},
|
||||||
|
{"foo/b%ar\\ba?z\\", URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%25ar%5Cba%3Fz%5C"},
|
||||||
|
{"foo/bar\\ba?z\\", 0, 0, S_OK, "foo/bar%5Cba?z\\"},
|
||||||
|
{"/foo/bar\\ba?z\\", 0, 0, S_OK, "/foo/bar%5Cba?z\\"},
|
||||||
|
{"/foo/bar\\ba#z\\", 0, 0, S_OK, "/foo/bar%5Cba#z\\"},
|
||||||
|
{"/foo/%5C", 0, 0, S_OK, "/foo/%5C"},
|
||||||
|
{"/foo/%5C", URL_ESCAPE_PERCENT, 0, S_OK, "/foo/%255C"},
|
||||||
|
|
||||||
|
{"http://////foo/bar\\baz", 0, 0, S_OK, "http://////foo/bar/baz"},
|
||||||
|
{"http://///foo/bar\\baz", 0, 0, S_OK, "http://///foo/bar/baz"},
|
||||||
|
{"http:////foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
|
||||||
|
{"http:///foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
|
||||||
|
{"http://localhost/foo/bar\\baz", 0, 0, S_OK, "http://localhost/foo/bar/baz"},
|
||||||
|
{"http://foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
|
||||||
|
{"http:/foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
|
||||||
|
{"http:foo/bar\\ba?z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba?z\\"},
|
||||||
|
{"http:foo/bar\\ba#z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba#z\\"},
|
||||||
|
{"http:\\foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
|
||||||
|
{"http:\\\\foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
|
||||||
|
{"http:\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
|
||||||
|
{"http:\\\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
|
||||||
|
{"http:/fo ?o/b ar\\baz", 0, 0, S_OK, "http:/fo%20?o/b ar\\baz"},
|
||||||
|
{"http:fo ?o/b ar\\baz", 0, 0, S_OK, "http:fo%20?o/b ar\\baz"},
|
||||||
|
{"http:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "http:%2Ffoo%2Fbar%5Cbaz"},
|
||||||
|
|
||||||
|
{"https://foo/bar\\baz", 0, 0, S_OK, "https://foo/bar/baz"},
|
||||||
|
{"https:/foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
|
||||||
|
{"https:\\foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
|
||||||
|
|
||||||
|
{"foo:////foo/bar\\baz", 0, 0, S_OK, "foo:////foo/bar%5Cbaz"},
|
||||||
|
{"foo:///foo/bar\\baz", 0, 0, S_OK, "foo:///foo/bar%5Cbaz"},
|
||||||
|
{"foo://localhost/foo/bar\\baz", 0, 0, S_OK, "foo://localhost/foo/bar%5Cbaz"},
|
||||||
|
{"foo://foo/bar\\baz", 0, 0, S_OK, "foo://foo/bar%5Cbaz"},
|
||||||
|
{"foo:/foo/bar\\baz", 0, 0, S_OK, "foo:/foo/bar%5Cbaz"},
|
||||||
|
{"foo:foo/bar\\baz", 0, 0, S_OK, "foo:foo%2Fbar%5Cbaz"},
|
||||||
|
{"foo:\\foo/bar\\baz", 0, 0, S_OK, "foo:%5Cfoo%2Fbar%5Cbaz"},
|
||||||
|
{"foo:/foo/bar\\ba?\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba?\\z"},
|
||||||
|
{"foo:/foo/bar\\ba#\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba#\\z"},
|
||||||
|
|
||||||
|
{"mailto:/fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:%2Ffo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
|
||||||
|
{"mailto:fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:fo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
|
||||||
|
{"mailto:fo/o@b\\%a?\\r.b#\\az", URL_ESCAPE_PERCENT, 0, S_OK, "mailto:fo%2Fo@b%5C%25a%3F%5Cr.b%23%5Caz"},
|
||||||
|
|
||||||
|
{"ftp:fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:fo%2Fo@bar.baz%2Ffoo%2Fbar"},
|
||||||
|
{"ftp:/fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:/fo/o@bar.baz/foo/bar"},
|
||||||
|
{"ftp://fo/o@bar.baz/fo?o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo?o\\bar"},
|
||||||
|
{"ftp://fo/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo#o\\bar"},
|
||||||
|
{"ftp://localhost/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://localhost/o@bar.baz/fo#o\\bar"},
|
||||||
|
{"ftp:///fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:///fo/o@bar.baz/foo/bar"},
|
||||||
|
{"ftp:////fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:////fo/o@bar.baz/foo/bar"}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _TEST_URL_COMBINE {
|
typedef struct _TEST_URL_COMBINE {
|
||||||
|
@ -178,10 +249,22 @@ static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectRe
|
||||||
{
|
{
|
||||||
CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
|
CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
|
||||||
DWORD dwEscaped;
|
DWORD dwEscaped;
|
||||||
|
WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
|
||||||
|
WCHAR *urlW, *expected_urlW;
|
||||||
dwEscaped=INTERNET_MAX_URL_LENGTH;
|
dwEscaped=INTERNET_MAX_URL_LENGTH;
|
||||||
ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08lx\n", dwExpectReturn);
|
|
||||||
ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\"\n", szExpectUrl, szReturnUrl);
|
ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
|
||||||
|
ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", szExpectUrl, szReturnUrl, szUrl);
|
||||||
|
|
||||||
|
dwEscaped = INTERNET_MAX_URL_LENGTH;
|
||||||
|
urlW = GetWideString(szUrl);
|
||||||
|
expected_urlW = GetWideString(szExpectUrl);
|
||||||
|
ok(UrlEscapeW(urlW, ret_urlW, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeW didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
|
||||||
|
WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
|
||||||
|
ok(strcmpW(ret_urlW, expected_urlW)==0, "Expected \"%s\", but got \"%s\" from \"%s\" flags %08lx\n", szExpectUrl, szReturnUrl, szUrl, dwFlags);
|
||||||
|
FreeWideString(urlW);
|
||||||
|
FreeWideString(expected_urlW);
|
||||||
|
|
||||||
}
|
}
|
||||||
static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
|
static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
#include "wininet.h"
|
#include "wininet.h"
|
||||||
#include "winreg.h"
|
#include "winreg.h"
|
||||||
|
#include "winternl.h"
|
||||||
#define NO_SHLWAPI_STREAM
|
#define NO_SHLWAPI_STREAM
|
||||||
#include "shlwapi.h"
|
#include "shlwapi.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
@ -118,96 +119,6 @@ static const unsigned char HashDataLookup[256] = {
|
||||||
0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB,
|
0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB,
|
||||||
0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 };
|
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)
|
static BOOL URL_JustLocation(LPCWSTR str)
|
||||||
{
|
{
|
||||||
while(*str && (*str == L'/')) str++;
|
while(*str && (*str == L'/')) str++;
|
||||||
|
@ -857,6 +768,107 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* UrlEscapeA [SHLWAPI.@]
|
* 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.
|
* Converts unsafe characters in a Url into escape sequences.
|
||||||
*
|
*
|
||||||
|
@ -871,12 +883,12 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
|
||||||
* contains its length.
|
* contains its length.
|
||||||
* Failure: E_POINTER, if pszEscaped is not large enough. In this case
|
* Failure: E_POINTER, if pszEscaped is not large enough. In this case
|
||||||
* pcchEscaped is set to the required length.
|
* pcchEscaped is set to the required length.
|
||||||
|
*
|
||||||
* Converts unsafe characters into their escape sequences.
|
* Converts unsafe characters into their escape sequences.
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* - By default this function stops converting at the first '?' or
|
* - 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
|
* - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are
|
||||||
* converted, but the conversion continues past a '?' or '#'.
|
* converted, but the conversion continues past a '?' or '#'.
|
||||||
* - Note that this function did not work well (or at all) in shlwapi version 4.
|
* - Note that this function did not work well (or at all) in shlwapi version 4.
|
||||||
|
@ -888,82 +900,6 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
|
||||||
*| URL_ESCAPE_SEGMENT_ONLY
|
*| URL_ESCAPE_SEGMENT_ONLY
|
||||||
*| URL_ESCAPE_PERCENT
|
*| 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(
|
HRESULT WINAPI UrlEscapeW(
|
||||||
LPCWSTR pszUrl,
|
LPCWSTR pszUrl,
|
||||||
LPWSTR pszEscaped,
|
LPWSTR pszEscaped,
|
||||||
|
@ -975,6 +911,10 @@ HRESULT WINAPI UrlEscapeW(
|
||||||
BOOL stop_escaping = FALSE;
|
BOOL stop_escaping = FALSE;
|
||||||
WCHAR next[5], *dst = pszEscaped;
|
WCHAR next[5], *dst = pszEscaped;
|
||||||
INT len;
|
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,
|
TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped,
|
||||||
pcchEscaped, dwFlags);
|
pcchEscaped, dwFlags);
|
||||||
|
@ -999,39 +939,101 @@ HRESULT WINAPI UrlEscapeW(
|
||||||
/* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
|
/* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
|
||||||
dwFlags |= URL_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) {
|
int_flags = 0;
|
||||||
/* TRACE("escaping %c\n", *src); */
|
if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) {
|
||||||
next[0] = L'%';
|
int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH;
|
||||||
/*
|
} else {
|
||||||
* I would have assumed that the W form would escape
|
parsed_url.cbSize = sizeof(parsed_url);
|
||||||
* the character with 4 hex digits (or even 8),
|
if(ParseURLW(pszUrl, &parsed_url) != S_OK)
|
||||||
* however, experiments show that native shlwapi escapes
|
parsed_url.nScheme = URL_SCHEME_INVALID;
|
||||||
* with only 2 hex digits.
|
|
||||||
* next[1] = hexDigits[(*src >> 12) & 0xf];
|
TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol));
|
||||||
* next[2] = hexDigits[(*src >> 8) & 0xf];
|
|
||||||
* next[3] = hexDigits[(*src >> 4) & 0xf];
|
if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO)
|
||||||
* next[4] = hexDigits[*src & 0xf];
|
int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION;
|
||||||
* len = 5;
|
|
||||||
*/
|
switch(parsed_url.nScheme) {
|
||||||
next[1] = hexDigits[(*src >> 4) & 0xf];
|
case URL_SCHEME_FILE:
|
||||||
next[2] = hexDigits[*src & 0xf];
|
int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH;
|
||||||
len = 3;
|
int_flags &= ~WINE_URL_STOP_ON_HASH;
|
||||||
} else {
|
break;
|
||||||
/* TRACE("passing %c\n", *src); */
|
|
||||||
next[0] = *src;
|
case URL_SCHEME_HTTP:
|
||||||
len = 1;
|
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) {
|
if(needed + len <= *pcchEscaped) {
|
||||||
memcpy(dst, next, len*sizeof(WCHAR));
|
memcpy(dst, next, len*sizeof(WCHAR));
|
||||||
|
@ -1041,7 +1043,7 @@ HRESULT WINAPI UrlEscapeW(
|
||||||
}
|
}
|
||||||
|
|
||||||
if(needed < *pcchEscaped) {
|
if(needed < *pcchEscaped) {
|
||||||
*dst = L'\0';
|
*dst = '\0';
|
||||||
ret = S_OK;
|
ret = S_OK;
|
||||||
} else {
|
} else {
|
||||||
needed++; /* add one for the '\0' */
|
needed++; /* add one for the '\0' */
|
||||||
|
|
Loading…
Reference in New Issue