- Implement URL_ESCAPE_SEGEMENT_ONLY, URL_ESCAPE_PERCENT,
and URL_DONT_ESCAPE_EXTRA_INFO in the UrlEscape{A|W} routines. - Make UrlCanonicalizeA use UrlCanonicalizeW. - Implement full functionality in UrlCanonicalizeW. - Implement UrlCombine{A|W}.
This commit is contained in:
parent
46780b009c
commit
8014f85dc2
|
@ -10,8 +10,11 @@
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
#include "wininet.h"
|
||||||
|
#include "winreg.h"
|
||||||
#include "shlwapi.h"
|
#include "shlwapi.h"
|
||||||
#include "debugtools.h"
|
#include "debugtools.h"
|
||||||
|
#include "ordinal.h"
|
||||||
|
|
||||||
DEFAULT_DEBUG_CHANNEL(shell);
|
DEFAULT_DEBUG_CHANNEL(shell);
|
||||||
|
|
||||||
|
@ -50,6 +53,9 @@ static BOOL URL_NeedEscapeA(CHAR ch, DWORD dwFlags)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%'))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
if (ch <= 31 || ch >= 127)
|
if (ch <= 31 || ch >= 127)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -70,6 +76,9 @@ static BOOL URL_NeedEscapeA(CHAR ch, DWORD dwFlags)
|
||||||
case '&':
|
case '&':
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
case '/':
|
||||||
|
case '?':
|
||||||
|
if (dwFlags & URL_ESCAPE_SEGMENT_ONLY) return TRUE;
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +88,7 @@ static BOOL URL_NeedEscapeA(CHAR ch, DWORD dwFlags)
|
||||||
static BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags)
|
static BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isalnum(ch))
|
if (iswalnum(ch))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
|
if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
|
||||||
|
@ -89,6 +98,9 @@ static BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == L'%'))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
if (ch <= 31 || ch >= 127)
|
if (ch <= 31 || ch >= 127)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -109,70 +121,90 @@ static BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags)
|
||||||
case L'&':
|
case L'&':
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
case L'/':
|
||||||
|
case L'?':
|
||||||
|
if (dwFlags & URL_ESCAPE_SEGMENT_ONLY) return TRUE;
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL URL_JustLocation(LPCWSTR str)
|
||||||
|
{
|
||||||
|
while(*str && (*str == L'/')) str++;
|
||||||
|
if (*str) {
|
||||||
|
while (*str && ((*str == L'-') ||
|
||||||
|
(*str == L'.') ||
|
||||||
|
iswalnum(*str))) str++;
|
||||||
|
if (*str == L'/') return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* UrlCanonicalizeA [SHLWAPI.@]
|
* UrlCanonicalizeA [SHLWAPI.@]
|
||||||
|
*
|
||||||
|
* Uses the W version to do job.
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized,
|
HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized,
|
||||||
LPDWORD pcchCanonicalized, DWORD dwFlags)
|
LPDWORD pcchCanonicalized, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
LPWSTR base, canonical;
|
||||||
|
DWORD ret, len, len2;
|
||||||
|
|
||||||
LPSTR lpszUrlCpy;
|
TRACE("(%s %p %p 0x%08lx) using W version\n",
|
||||||
INT nLen;
|
debugstr_a(pszUrl), pszCanonicalized,
|
||||||
|
|
||||||
TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl), pszCanonicalized,
|
|
||||||
pcchCanonicalized, dwFlags);
|
pcchCanonicalized, dwFlags);
|
||||||
|
|
||||||
nLen = strlen(pszUrl);
|
base = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
|
||||||
lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, nLen + 1);
|
(2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
|
||||||
|
canonical = base + INTERNET_MAX_URL_LENGTH;
|
||||||
|
|
||||||
if (dwFlags & URL_DONT_SIMPLIFY)
|
MultiByteToWideChar(0, 0, pszUrl, -1, base, INTERNET_MAX_URL_LENGTH);
|
||||||
memcpy(lpszUrlCpy, pszUrl, nLen + 1);
|
len = INTERNET_MAX_URL_LENGTH;
|
||||||
else {
|
|
||||||
FIXME("Simplify path\n");
|
ret = UrlCanonicalizeW(base, canonical, &len, dwFlags);
|
||||||
memcpy(lpszUrlCpy, pszUrl, nLen + 1);
|
if (ret != S_OK) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, base);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dwFlags & URL_UNESCAPE)
|
len2 = WideCharToMultiByte(0, 0, canonical, len, 0, 0, 0, 0);
|
||||||
UrlUnescapeA(lpszUrlCpy, NULL, NULL, URL_UNESCAPE_INPLACE);
|
if (len2 > *pcchCanonicalized) {
|
||||||
|
*pcchCanonicalized = len;
|
||||||
if(dwFlags & (URL_ESCAPE_UNSAFE | URL_ESCAPE_SPACES_ONLY)) {
|
HeapFree(GetProcessHeap(), 0, base);
|
||||||
DWORD EscapeFlags = dwFlags & (URL_ESCAPE_SPACES_ONLY
|
return E_POINTER;
|
||||||
/* | URL_ESCAPE_PERCENT */);
|
|
||||||
hr = UrlEscapeA(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
|
|
||||||
EscapeFlags);
|
|
||||||
} else { /* No escapping needed, just copy the string */
|
|
||||||
nLen = strlen(lpszUrlCpy);
|
|
||||||
if(nLen < *pcchCanonicalized)
|
|
||||||
memcpy(pszCanonicalized, lpszUrlCpy, nLen + 1);
|
|
||||||
else {
|
|
||||||
hr = E_POINTER;
|
|
||||||
nLen++;
|
|
||||||
}
|
|
||||||
*pcchCanonicalized = nLen;
|
|
||||||
}
|
}
|
||||||
|
WideCharToMultiByte(0, 0, canonical, len+1, pszCanonicalized,
|
||||||
HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
|
*pcchCanonicalized, 0, 0);
|
||||||
|
*pcchCanonicalized = len2;
|
||||||
return hr;
|
HeapFree(GetProcessHeap(), 0, base);
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* UrlCanonicalizeW [SHLWAPI.@]
|
* UrlCanonicalizeW [SHLWAPI.@]
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* MSDN is wrong (at 10/30/01 - go figure). This should support the
|
||||||
|
* following flags: GLA
|
||||||
|
* URL_DONT_ESCAPE_EXTRA_INFO 0x02000000
|
||||||
|
* URL_ESCAPE_SPACES_ONLY 0x04000000
|
||||||
|
* URL_ESCAPE_PERCENT 0x00001000
|
||||||
|
* URL_ESCAPE_UNSAFE 0x10000000
|
||||||
|
* URL_UNESCAPE 0x10000000
|
||||||
|
* URL_DONT_SIMPLIFY 0x08000000
|
||||||
|
* URL_ESCAPE_SEGMENT_ONLY 0x00002000
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized,
|
HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized,
|
||||||
LPDWORD pcchCanonicalized, DWORD dwFlags)
|
LPDWORD pcchCanonicalized, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
DWORD EscapeFlags;
|
||||||
LPWSTR lpszUrlCpy;
|
LPWSTR lpszUrlCpy, wk1, wk2, mp, root;
|
||||||
INT nLen, nByteLen;
|
INT nLen, nByteLen, state;
|
||||||
|
|
||||||
TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszCanonicalized,
|
TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszCanonicalized,
|
||||||
pcchCanonicalized, dwFlags);
|
pcchCanonicalized, dwFlags);
|
||||||
|
@ -183,16 +215,121 @@ HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized,
|
||||||
if (dwFlags & URL_DONT_SIMPLIFY)
|
if (dwFlags & URL_DONT_SIMPLIFY)
|
||||||
memcpy(lpszUrlCpy, pszUrl, nByteLen);
|
memcpy(lpszUrlCpy, pszUrl, nByteLen);
|
||||||
else {
|
else {
|
||||||
FIXME("Simplify path\n");
|
|
||||||
memcpy(lpszUrlCpy, pszUrl, nByteLen);
|
/*
|
||||||
|
* state =
|
||||||
|
* 0 initial 1,3
|
||||||
|
* 1 have 2[+] alnum 2,3
|
||||||
|
* 2 have scheme (found :) 4,6,3
|
||||||
|
* 3 failed (no location)
|
||||||
|
* 4 have // 5,3
|
||||||
|
* 5 have 1[+] alnum 6,3
|
||||||
|
* 6 have location (found /) save root location
|
||||||
|
*/
|
||||||
|
|
||||||
|
wk1 = (LPWSTR)pszUrl;
|
||||||
|
wk2 = lpszUrlCpy;
|
||||||
|
state = 0;
|
||||||
|
while (*wk1) {
|
||||||
|
switch (state) {
|
||||||
|
case 0:
|
||||||
|
if (!iswalnum(*wk1)) {state = 3; break;}
|
||||||
|
*wk2++ = *wk1++;
|
||||||
|
if (!iswalnum(*wk1)) {state = 3; break;}
|
||||||
|
*wk2++ = *wk1++;
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*wk2++ = *wk1;
|
||||||
|
if (*wk1++ == L':') state = 2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (*wk1 != L'/') {state = 3; break;}
|
||||||
|
*wk2++ = *wk1++;
|
||||||
|
if (*wk1 != L'/') {state = 6; break;}
|
||||||
|
*wk2++ = *wk1++;
|
||||||
|
state = 4;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
strcpyW(wk2, wk1);
|
||||||
|
wk1 += strlenW(wk1);
|
||||||
|
wk2 += strlenW(wk2);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (!iswalnum(*wk1) && (*wk1 != L'-')) {state = 3; break;}
|
||||||
|
while(iswalnum(*wk1) || (*wk1 == L'-')) *wk2++ = *wk1++;
|
||||||
|
state = 5;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (*wk1 != L'/') {state = 3; break;}
|
||||||
|
*wk2++ = *wk1++;
|
||||||
|
state = 6;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
/* Now at root location, cannot back up any more. */
|
||||||
|
/* "root" will point at the '/' */
|
||||||
|
root = wk2-1;
|
||||||
|
while (*wk1) {
|
||||||
|
TRACE("wk1=%c\n", (CHAR)*wk1);
|
||||||
|
mp = strchrW(wk1, L'/');
|
||||||
|
if (!mp) {
|
||||||
|
strcpyW(wk2, wk1);
|
||||||
|
wk1 += strlenW(wk1);
|
||||||
|
wk2 += strlenW(wk2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nLen = mp - wk1 + 1;
|
||||||
|
strncpyW(wk2, wk1, nLen);
|
||||||
|
wk2 += nLen;
|
||||||
|
wk1 += nLen;
|
||||||
|
if (*wk1 == L'.') {
|
||||||
|
TRACE("found '/.'\n");
|
||||||
|
if (*(wk1+1) == L'/') {
|
||||||
|
/* case of /./ -> skip the ./ */
|
||||||
|
wk1 += 2;
|
||||||
|
}
|
||||||
|
else if (*(wk1+1) == L'.') {
|
||||||
|
/* found /.. look for next / */
|
||||||
|
TRACE("found '/..'\n");
|
||||||
|
if (*(wk1+2) == L'/') {
|
||||||
|
/* case /../ -> need to backup wk2 */
|
||||||
|
TRACE("found '/../'\n");
|
||||||
|
*(wk2-1) = L'\0'; /* set end of string */
|
||||||
|
mp = strrchrW(root, L'/');
|
||||||
|
if (mp && (mp >= root)) {
|
||||||
|
/* found valid backup point */
|
||||||
|
wk2 = mp + 1;
|
||||||
|
wk1 += 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* did not find point, restore '/' */
|
||||||
|
*(wk2-1) = L'/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*wk2 = L'\0';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FIXME("how did we get here - state=%d\n", state);
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*wk2 = L'\0';
|
||||||
|
TRACE("Simplified, orig <%s>, simple <%s>\n",
|
||||||
|
debugstr_w(pszUrl), debugstr_w(lpszUrlCpy));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dwFlags & URL_UNESCAPE)
|
if(dwFlags & URL_UNESCAPE)
|
||||||
UrlUnescapeW(lpszUrlCpy, NULL, NULL, URL_UNESCAPE_INPLACE);
|
UrlUnescapeW(lpszUrlCpy, NULL, NULL, URL_UNESCAPE_INPLACE);
|
||||||
|
|
||||||
if(dwFlags & (URL_ESCAPE_UNSAFE | URL_ESCAPE_SPACES_ONLY)) {
|
if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE |
|
||||||
DWORD EscapeFlags = dwFlags & (URL_ESCAPE_SPACES_ONLY
|
URL_ESCAPE_SPACES_ONLY |
|
||||||
/* | URL_ESCAPE_PERCENT */);
|
URL_ESCAPE_PERCENT |
|
||||||
|
URL_DONT_ESCAPE_EXTRA_INFO |
|
||||||
|
URL_ESCAPE_SEGMENT_ONLY ))) {
|
||||||
|
EscapeFlags &= ~URL_ESCAPE_UNSAFE;
|
||||||
hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
|
hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
|
||||||
EscapeFlags);
|
EscapeFlags);
|
||||||
} else { /* No escapping needed, just copy the string */
|
} else { /* No escapping needed, just copy the string */
|
||||||
|
@ -216,35 +353,46 @@ HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized,
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* UrlCombineA [SHLWAPI.@]
|
* UrlCombineA [SHLWAPI.@]
|
||||||
|
*
|
||||||
|
* Uses the W version to do job.
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative,
|
HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative,
|
||||||
LPSTR pszCombined, LPDWORD pcchCombined,
|
LPSTR pszCombined, LPDWORD pcchCombined,
|
||||||
DWORD dwFlags)
|
DWORD dwFlags)
|
||||||
{
|
{
|
||||||
FIXME("(base %s, Relative %s, Combine size %ld, flags %08lx):stub\n",
|
LPWSTR base, relative, combined;
|
||||||
|
DWORD ret, len, len2;
|
||||||
|
|
||||||
|
TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx) using W version\n",
|
||||||
debugstr_a(pszBase),debugstr_a(pszRelative),
|
debugstr_a(pszBase),debugstr_a(pszRelative),
|
||||||
*pcchCombined,dwFlags);
|
*pcchCombined,dwFlags);
|
||||||
return E_INVALIDARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
base = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
|
||||||
* Helper for UrlCombineW
|
(3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
|
||||||
*/
|
relative = base + INTERNET_MAX_URL_LENGTH;
|
||||||
DWORD URL_LocateSchemeW(LPCWSTR p)
|
combined = relative + INTERNET_MAX_URL_LENGTH;
|
||||||
{
|
|
||||||
DWORD len = 0;
|
|
||||||
|
|
||||||
while (*p) {
|
MultiByteToWideChar(0, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH);
|
||||||
if (*p == L':') break;
|
MultiByteToWideChar(0, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH);
|
||||||
if (!((get_char_typeW(*p) & (C1_ALPHA|C1_DIGIT)) != 0) && !(*p == L'-')) {
|
len = INTERNET_MAX_URL_LENGTH;
|
||||||
|
|
||||||
len = -1;
|
ret = UrlCombineW(base, relative, combined, &len, dwFlags);
|
||||||
break;
|
if (ret != S_OK) {
|
||||||
}
|
HeapFree(GetProcessHeap(), 0, base);
|
||||||
p++;
|
return ret;
|
||||||
len++;
|
|
||||||
}
|
}
|
||||||
return len;
|
|
||||||
|
len2 = WideCharToMultiByte(0, 0, combined, len, 0, 0, 0, 0);
|
||||||
|
if (len2 > *pcchCombined) {
|
||||||
|
*pcchCombined = len;
|
||||||
|
HeapFree(GetProcessHeap(), 0, base);
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
WideCharToMultiByte(0, 0, combined, len+1, pszCombined, *pcchCombined,
|
||||||
|
0, 0);
|
||||||
|
*pcchCombined = len2;
|
||||||
|
HeapFree(GetProcessHeap(), 0, base);
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
@ -254,89 +402,254 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
|
||||||
LPWSTR pszCombined, LPDWORD pcchCombined,
|
LPWSTR pszCombined, LPDWORD pcchCombined,
|
||||||
DWORD dwFlags)
|
DWORD dwFlags)
|
||||||
{
|
{
|
||||||
DWORD s1len, s2len, len, len2;
|
UNKNOWN_SHLWAPI_2 base, relative;
|
||||||
LPWSTR p1;
|
DWORD myflags, sizeloc = 0;
|
||||||
|
DWORD len, res1, res2, process_case = 0;
|
||||||
|
LPWSTR work, preliminary, mbase, mrelative;
|
||||||
|
WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'};
|
||||||
|
WCHAR single_slash[] = {'/','\0'};
|
||||||
|
HRESULT ret;
|
||||||
|
|
||||||
TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx)\n",
|
TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx)\n",
|
||||||
debugstr_w(pszBase),debugstr_w(pszRelative),
|
debugstr_w(pszBase),debugstr_w(pszRelative),
|
||||||
*pcchCombined,dwFlags);
|
*pcchCombined,dwFlags);
|
||||||
|
|
||||||
s1len = URL_LocateSchemeW(pszBase);
|
base.size = 24;
|
||||||
s2len = URL_LocateSchemeW(pszRelative);
|
relative.size = 24;
|
||||||
|
|
||||||
if ((s1len == s2len) && (strncmpiW(pszBase, pszRelative, s1len) == 0)) {
|
/* Get space for duplicates of the input and the output */
|
||||||
/* same protocol, see if can combine */
|
preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) *
|
||||||
|
sizeof(WCHAR));
|
||||||
|
mbase = preliminary + INTERNET_MAX_URL_LENGTH;
|
||||||
|
mrelative = mbase + INTERNET_MAX_URL_LENGTH;
|
||||||
|
*preliminary = L'\0';
|
||||||
|
|
||||||
/* first copy the base without the document (if it exists) */
|
/* Canonicalize the base input prior to looking for the scheme */
|
||||||
len = strlenW(pszBase);
|
myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE);
|
||||||
p1 = strrchrW(pszBase, L'/');
|
len = INTERNET_MAX_URL_LENGTH;
|
||||||
if (p1) {
|
ret = UrlCanonicalizeW(pszBase, mbase, &len, myflags);
|
||||||
len = p1 - pszBase + 1;
|
|
||||||
|
/* Canonicalize the relative input prior to looking for the scheme */
|
||||||
|
len = INTERNET_MAX_URL_LENGTH;
|
||||||
|
ret = UrlCanonicalizeW(pszRelative, mrelative, &len, myflags);
|
||||||
|
|
||||||
|
/* See if the base has a scheme */
|
||||||
|
res1 = SHLWAPI_2(mbase, &base);
|
||||||
|
if (res1) {
|
||||||
|
/* if pszBase has no scheme, then return pszRelative */
|
||||||
|
TRACE("no scheme detected in Base\n");
|
||||||
|
process_case = 1;
|
||||||
|
}
|
||||||
|
else do {
|
||||||
|
|
||||||
|
/* get size of location field (if it exists) */
|
||||||
|
work = (LPWSTR)base.ap2;
|
||||||
|
sizeloc = 0;
|
||||||
|
if (*work++ == L'/') {
|
||||||
|
if (*work++ == L'/') {
|
||||||
|
/* At this point have start of location and
|
||||||
|
* it ends at next '/' or end of string.
|
||||||
|
*/
|
||||||
|
while(*work && (*work != L'/')) work++;
|
||||||
|
sizeloc = work - base.ap2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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'/');
|
||||||
|
if (work) {
|
||||||
|
len = work - base.ap2 + 1;
|
||||||
|
base.sizep2 = len;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* At this point:
|
||||||
|
* .ap2 points to location (starting with '//')
|
||||||
|
* .sizep2 length of location (above) and rest less the last
|
||||||
|
* leaf (if any)
|
||||||
|
* sizeloc length of location (above) up to but not including
|
||||||
|
* the last '/'
|
||||||
|
*/
|
||||||
|
|
||||||
|
res2 = SHLWAPI_2(mrelative, &relative);
|
||||||
|
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);
|
||||||
|
if (*pszRelative == L':') {
|
||||||
|
/* case that is either left alone or uses pszBase */
|
||||||
|
if (dwFlags & URL_PLUGGABLE_PROTOCOL) {
|
||||||
|
process_case = 5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
process_case = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isalnum(*mrelative) && (*(mrelative + 1) == L':')) {
|
||||||
|
/* case that becomes "file:///" */
|
||||||
|
strcpyW(preliminary, myfilestr);
|
||||||
|
process_case = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((*mrelative == L'/') && (*(mrelative+1) == L'/')) {
|
||||||
|
/* pszRelative has location and rest */
|
||||||
|
process_case = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*mrelative == L'/') {
|
||||||
|
/* case where pszRelative is root to location */
|
||||||
|
process_case = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
process_case = (*base.ap2 == L'/') ? 5 : 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle cases where pszRelative has scheme */
|
||||||
|
if ((base.sizep1 == relative.sizep1) &&
|
||||||
|
(strncmpW(base.ap1, relative.ap1, base.sizep1) == 0)) {
|
||||||
|
|
||||||
|
/* since the schemes are the same */
|
||||||
|
if ((*relative.ap2 == L'/') && (*(relative.ap2+1) == L'/')) {
|
||||||
|
/* case where pszRelative replaces location and following */
|
||||||
|
process_case = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*relative.ap2 == L'/') {
|
||||||
|
/* case where pszRelative is root to location */
|
||||||
|
process_case = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* case where scheme is followed by document path */
|
||||||
|
process_case = 5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((*relative.ap2 == L'/') && (*(relative.ap2+1) == L'/')) {
|
||||||
|
/* case where pszRelative replaces scheme, location,
|
||||||
|
* and following and handles PLUGGABLE
|
||||||
|
*/
|
||||||
|
process_case = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
process_case = 1;
|
||||||
|
break;
|
||||||
|
} while(FALSE); /* a litte trick to allow easy exit from nested if's */
|
||||||
|
|
||||||
|
|
||||||
|
ret = S_OK;
|
||||||
|
switch (process_case) {
|
||||||
|
|
||||||
|
case 1: /*
|
||||||
|
* Return pszRelative appended to what ever is in pszCombined,
|
||||||
|
* (which may the string "file:///"
|
||||||
|
*/
|
||||||
|
len = strlenW(mrelative) + strlenW(preliminary);
|
||||||
if (len+1 > *pcchCombined) {
|
if (len+1 > *pcchCombined) {
|
||||||
*pcchCombined = len;
|
*pcchCombined = len;
|
||||||
return E_POINTER;
|
ret = E_POINTER;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
strncpyW(pszCombined, pszBase, len);
|
strcatW(preliminary, mrelative);
|
||||||
*(pszCombined+len) = L'\0';
|
break;
|
||||||
|
|
||||||
/* second locate the document in the relative */
|
case 2: /*
|
||||||
len2 = strlenW(pszRelative);
|
* Same as case 1, but if URL_PLUGGABLE_PROTOCOL was specified
|
||||||
p1 = strrchrW(pszRelative, L'/');
|
* and pszRelative starts with "//", then append a "/"
|
||||||
if (p1) {
|
*/
|
||||||
p1++;
|
len = strlenW(mrelative) + 1;
|
||||||
len2 -= p1 - pszRelative;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
p1 = (LPWSTR)pszRelative;
|
|
||||||
if (len2+len+1 > *pcchCombined) {
|
|
||||||
*pcchCombined = len2 + len;
|
|
||||||
return E_POINTER;
|
|
||||||
}
|
|
||||||
strcatW(pszCombined, p1);
|
|
||||||
*pcchCombined = len2 + len;
|
|
||||||
TRACE("return-1 len=%ld, %s\n",
|
|
||||||
*pcchCombined, debugstr_w(pszCombined));
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((s1len > 0) && (strlenW(pszRelative) == 0)) {
|
|
||||||
/* remove "document" from base */
|
|
||||||
len = strlenW(pszBase);
|
|
||||||
p1 = strrchrW(pszBase, L'/');
|
|
||||||
if (p1) {
|
|
||||||
len = p1 - pszBase + 1;
|
|
||||||
}
|
|
||||||
if (len+1 > *pcchCombined) {
|
if (len+1 > *pcchCombined) {
|
||||||
*pcchCombined = len;
|
*pcchCombined = len;
|
||||||
return E_POINTER;
|
ret = E_POINTER;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
strncpyW(pszCombined, pszBase, len);
|
strcpyW(preliminary, mrelative);
|
||||||
*(pszCombined+len) = L'\0';
|
if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) &&
|
||||||
*pcchCombined = len;
|
URL_JustLocation(relative.ap2))
|
||||||
TRACE("return-2 len=%ld, %s\n",
|
strcatW(preliminary, single_slash);
|
||||||
*pcchCombined, debugstr_w(pszCombined));
|
break;
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s2len > 0) {
|
case 3: /*
|
||||||
/* pszRelative is a protocol itself so return it only */
|
* Return the pszBase scheme with pszRelative. Basicly
|
||||||
len = strlenW(pszRelative);
|
* keeps the scheme and replaces the domain and following.
|
||||||
|
*/
|
||||||
|
len = base.sizep1 + 1 + relative.sizep2 + 1;
|
||||||
if (len+1 > *pcchCombined) {
|
if (len+1 > *pcchCombined) {
|
||||||
*pcchCombined = len;
|
*pcchCombined = len;
|
||||||
return E_POINTER;
|
ret = E_POINTER;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
strcpyW(pszCombined, pszRelative);
|
strncpyW(preliminary, base.ap1, base.sizep1 + 1);
|
||||||
*pcchCombined = len;
|
work = preliminary + base.sizep1 + 1;
|
||||||
TRACE("return-3 len=%ld, %s\n",
|
strcpyW(work, relative.ap2);
|
||||||
*pcchCombined, debugstr_w(pszCombined));
|
if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) &&
|
||||||
return S_OK;
|
URL_JustLocation(relative.ap2))
|
||||||
|
strcatW(work, single_slash);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: /*
|
||||||
|
* Return the pszBase scheme and location but everything
|
||||||
|
* after the location is pszRelative. (Replace document
|
||||||
|
* from root on.)
|
||||||
|
*/
|
||||||
|
len = base.sizep1 + 1 + sizeloc + relative.sizep2 + 1;
|
||||||
|
if (len+1 > *pcchCombined) {
|
||||||
|
*pcchCombined = len;
|
||||||
|
ret = E_POINTER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strncpyW(preliminary, base.ap1, base.sizep1+1+sizeloc);
|
||||||
|
work = preliminary + base.sizep1 + 1 + sizeloc;
|
||||||
|
if (dwFlags & URL_PLUGGABLE_PROTOCOL)
|
||||||
|
*(work++) = L'/';
|
||||||
|
strcpyW(work, relative.ap2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: /*
|
||||||
|
* Return the pszBase without its document (if any) and
|
||||||
|
* append pszRelative after its scheme.
|
||||||
|
*/
|
||||||
|
len = base.sizep1 + 1 + base.sizep2 + relative.sizep2;
|
||||||
|
if (len+1 > *pcchCombined) {
|
||||||
|
*pcchCombined = len;
|
||||||
|
ret = E_POINTER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strncpyW(preliminary, base.ap1, base.sizep1+1+base.sizep2);
|
||||||
|
work = preliminary + base.sizep1+1+base.sizep2 - 1;
|
||||||
|
if (*work++ != L'/')
|
||||||
|
*(work++) = L'/';
|
||||||
|
strcpyW(work, relative.ap2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
FIXME("How did we get here????? process_case=%ld\n", process_case);
|
||||||
|
ret = E_INVALIDARG;
|
||||||
}
|
}
|
||||||
FIXME("(base %s, Relative %s, Combine size %ld, flags %08lx) unknown case\n",
|
|
||||||
debugstr_w(pszBase),debugstr_w(pszRelative),
|
if (ret == S_OK) {
|
||||||
*pcchCombined,dwFlags);
|
/*
|
||||||
FIXME(" s1len=%ld, s2len=%ld\n", s1len, s2len);
|
* Now that the combining is done, process the escape options if
|
||||||
return E_INVALIDARG;
|
* necessary, otherwise just copy the string.
|
||||||
|
*/
|
||||||
|
myflags = dwFlags & (URL_ESCAPE_PERCENT |
|
||||||
|
URL_ESCAPE_SPACES_ONLY |
|
||||||
|
URL_DONT_ESCAPE_EXTRA_INFO |
|
||||||
|
URL_ESCAPE_SEGMENT_ONLY);
|
||||||
|
if (myflags)
|
||||||
|
ret = UrlEscapeW(preliminary, pszCombined,
|
||||||
|
pcchCombined, myflags);
|
||||||
|
else {
|
||||||
|
len = (strlenW(preliminary) + 1) * sizeof(WCHAR);
|
||||||
|
memcpy(pszCombined, preliminary, len);
|
||||||
|
*pcchCombined = strlenW(preliminary);
|
||||||
|
}
|
||||||
|
TRACE("return-%ld len=%ld, %s\n",
|
||||||
|
process_case, *pcchCombined, debugstr_w(pszCombined));
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, preliminary);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
@ -357,15 +670,15 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
|
||||||
* '?' or '#'.
|
* '?' or '#'.
|
||||||
*
|
*
|
||||||
* BUGS:
|
* BUGS:
|
||||||
|
* Have now implemented the following flags:
|
||||||
|
* URL_ESCAPE_SPACES_ONLY
|
||||||
|
* URL_DONT_ESCAPE_EXTRA_INFO
|
||||||
|
* URL_ESCAPE_SEGMENT_ONLY
|
||||||
|
* URL_ESCAPE_PERCENT
|
||||||
|
* Initial testing seems to indicate that this is now working like
|
||||||
|
* native shlwapi version 5. Note that these functions did not work
|
||||||
|
* well (or at all) in shlwapi version 4.
|
||||||
*
|
*
|
||||||
* None of the URL_ define values are documented, so they were
|
|
||||||
* determined by trial and error. MSDN mentions URL_ESCAPE_PERCENT
|
|
||||||
* but I can't find a value that does this under win2000.
|
|
||||||
* URL_DONT_ESCAPE_EXTRA_INFO appears to be the default which is what
|
|
||||||
* we assume here. URL_ESCAPE_SEGMENT_ONLY is not implemented
|
|
||||||
* (value??). A value of 0x2000 for dwFlags seems to escape
|
|
||||||
* '/'s too - this is neither documented on MSDN nor implemented here.
|
|
||||||
* For character values that are converted see URL_NeedEscape.
|
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI UrlEscapeA(
|
HRESULT WINAPI UrlEscapeA(
|
||||||
LPCSTR pszUrl,
|
LPCSTR pszUrl,
|
||||||
|
@ -383,20 +696,37 @@ HRESULT WINAPI UrlEscapeA(
|
||||||
TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl), pszEscaped,
|
TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl), pszEscaped,
|
||||||
pcchEscaped, dwFlags);
|
pcchEscaped, dwFlags);
|
||||||
|
|
||||||
if(dwFlags & ~URL_ESCAPE_SPACES_ONLY)
|
if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY |
|
||||||
|
URL_ESCAPE_SEGMENT_ONLY |
|
||||||
|
URL_DONT_ESCAPE_EXTRA_INFO |
|
||||||
|
URL_ESCAPE_PERCENT))
|
||||||
FIXME("Unimplemented flags: %08lx\n", dwFlags);
|
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 the assume DONT_ESCAPE_EXTRA_INFO */
|
||||||
|
dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO;
|
||||||
|
|
||||||
for(src = pszUrl; *src; src++) {
|
for(src = pszUrl; *src; src++) {
|
||||||
if(!(dwFlags & URL_ESCAPE_SPACES_ONLY) &&
|
if(!(dwFlags & URL_ESCAPE_SEGMENT_ONLY) &&
|
||||||
|
(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) &&
|
||||||
(*src == '#' || *src == '?'))
|
(*src == '#' || *src == '?'))
|
||||||
stop_escapping = TRUE;
|
stop_escapping = TRUE;
|
||||||
|
|
||||||
if(URL_NeedEscapeA(*src, dwFlags) && stop_escapping == FALSE) {
|
if(URL_NeedEscapeA(*src, dwFlags) && stop_escapping == FALSE) {
|
||||||
|
/* TRACE("escaping %c\n", *src); */
|
||||||
next[0] = '%';
|
next[0] = '%';
|
||||||
next[1] = hex[(*src >> 4) & 0xf];
|
next[1] = hex[(*src >> 4) & 0xf];
|
||||||
next[2] = hex[*src & 0xf];
|
next[2] = hex[*src & 0xf];
|
||||||
len = 3;
|
len = 3;
|
||||||
} else {
|
} else {
|
||||||
|
/* TRACE("passing %c\n", *src); */
|
||||||
next[0] = *src;
|
next[0] = *src;
|
||||||
len = 1;
|
len = 1;
|
||||||
}
|
}
|
||||||
|
@ -440,22 +770,53 @@ HRESULT WINAPI UrlEscapeW(
|
||||||
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);
|
||||||
|
|
||||||
if(dwFlags & ~URL_ESCAPE_SPACES_ONLY)
|
if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY |
|
||||||
|
URL_ESCAPE_SEGMENT_ONLY |
|
||||||
|
URL_DONT_ESCAPE_EXTRA_INFO |
|
||||||
|
URL_ESCAPE_PERCENT))
|
||||||
FIXME("Unimplemented flags: %08lx\n", dwFlags);
|
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 the assume DONT_ESCAPE_EXTRA_INFO */
|
||||||
|
dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO;
|
||||||
|
|
||||||
for(src = pszUrl; *src; src++) {
|
for(src = pszUrl; *src; src++) {
|
||||||
if(!(dwFlags & URL_ESCAPE_SPACES_ONLY) &&
|
/*
|
||||||
|
* if(!(dwFlags & URL_ESCAPE_SPACES_ONLY) &&
|
||||||
|
* (*src == L'#' || *src == L'?'))
|
||||||
|
* stop_escapping = TRUE;
|
||||||
|
*/
|
||||||
|
if(!(dwFlags & URL_ESCAPE_SEGMENT_ONLY) &&
|
||||||
|
(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) &&
|
||||||
(*src == L'#' || *src == L'?'))
|
(*src == L'#' || *src == L'?'))
|
||||||
stop_escapping = TRUE;
|
stop_escapping = TRUE;
|
||||||
|
|
||||||
if(URL_NeedEscapeW(*src, dwFlags) && stop_escapping == FALSE) {
|
if(URL_NeedEscapeW(*src, dwFlags) && stop_escapping == FALSE) {
|
||||||
|
/* TRACE("escaping %c\n", *src); */
|
||||||
next[0] = L'%';
|
next[0] = L'%';
|
||||||
next[1] = hex[(*src >> 12) & 0xf];
|
/*
|
||||||
next[2] = hex[(*src >> 8) & 0xf];
|
* I would have assumed that the W form would escape
|
||||||
next[3] = hex[(*src >> 4) & 0xf];
|
* the character with 4 hex digits (or even 8),
|
||||||
next[4] = hex[*src & 0xf];
|
* however, experiments show that native shlwapi escapes
|
||||||
len = 5;
|
* with only 2 hex digits.
|
||||||
|
* next[1] = hex[(*src >> 12) & 0xf];
|
||||||
|
* next[2] = hex[(*src >> 8) & 0xf];
|
||||||
|
* next[3] = hex[(*src >> 4) & 0xf];
|
||||||
|
* next[4] = hex[*src & 0xf];
|
||||||
|
* len = 5;
|
||||||
|
*/
|
||||||
|
next[1] = hex[(*src >> 4) & 0xf];
|
||||||
|
next[2] = hex[*src & 0xf];
|
||||||
|
len = 3;
|
||||||
} else {
|
} else {
|
||||||
|
/* TRACE("passing %c\n", *src); */
|
||||||
next[0] = *src;
|
next[0] = *src;
|
||||||
len = 1;
|
len = 1;
|
||||||
}
|
}
|
||||||
|
@ -508,7 +869,7 @@ HRESULT WINAPI UrlUnescapeA(
|
||||||
DWORD needed;
|
DWORD needed;
|
||||||
BOOL stop_unescapping = FALSE;
|
BOOL stop_unescapping = FALSE;
|
||||||
|
|
||||||
TRACE("(%s, %p, %p, 0x%08lx): stub\n", debugstr_a(pszUrl), pszUnescaped,
|
TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_a(pszUrl), pszUnescaped,
|
||||||
pcchUnescaped, dwFlags);
|
pcchUnescaped, dwFlags);
|
||||||
|
|
||||||
if(dwFlags & URL_UNESCAPE_INPLACE)
|
if(dwFlags & URL_UNESCAPE_INPLACE)
|
||||||
|
@ -572,7 +933,7 @@ HRESULT WINAPI UrlUnescapeW(
|
||||||
DWORD needed;
|
DWORD needed;
|
||||||
BOOL stop_unescapping = FALSE;
|
BOOL stop_unescapping = FALSE;
|
||||||
|
|
||||||
TRACE("(%s, %p, %p, 0x%08lx): stub\n", debugstr_w(pszUrl), pszUnescaped,
|
TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszUrl), pszUnescaped,
|
||||||
pcchUnescaped, dwFlags);
|
pcchUnescaped, dwFlags);
|
||||||
|
|
||||||
if(dwFlags & URL_UNESCAPE_INPLACE)
|
if(dwFlags & URL_UNESCAPE_INPLACE)
|
||||||
|
|
Loading…
Reference in New Issue