- 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:
Guy Albertelli 2001-11-06 22:29:38 +00:00 committed by Alexandre Julliard
parent 46780b009c
commit 8014f85dc2
1 changed files with 503 additions and 142 deletions

View File

@ -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,
} *pcchCanonicalized, 0, 0);
*pcchCanonicalized = len2;
HeapFree(GetProcessHeap(), 0, lpszUrlCpy); HeapFree(GetProcessHeap(), 0, base);
return S_OK;
return hr;
} }
/************************************************************************* /*************************************************************************
* 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,
(3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
relative = base + INTERNET_MAX_URL_LENGTH;
combined = relative + INTERNET_MAX_URL_LENGTH;
MultiByteToWideChar(0, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH);
MultiByteToWideChar(0, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH);
len = INTERNET_MAX_URL_LENGTH;
ret = UrlCombineW(base, relative, combined, &len, dwFlags);
if (ret != S_OK) {
HeapFree(GetProcessHeap(), 0, base);
return ret;
} }
/************************************************************************* len2 = WideCharToMultiByte(0, 0, combined, len, 0, 0, 0, 0);
* Helper for UrlCombineW if (len2 > *pcchCombined) {
*/ *pcchCombined = len;
DWORD URL_LocateSchemeW(LPCWSTR p) HeapFree(GetProcessHeap(), 0, base);
{ return E_POINTER;
DWORD len = 0;
while (*p) {
if (*p == L':') break;
if (!((get_char_typeW(*p) & (C1_ALPHA|C1_DIGIT)) != 0) && !(*p == L'-')) {
len = -1;
break;
} }
p++; WideCharToMultiByte(0, 0, combined, len+1, pszCombined, *pcchCombined,
len++; 0, 0);
} *pcchCombined = len2;
return len; 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);
*(pszCombined+len) = L'\0';
*pcchCombined = len;
TRACE("return-2 len=%ld, %s\n",
*pcchCombined, debugstr_w(pszCombined));
return S_OK;
} }
strcpyW(preliminary, mrelative);
if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) &&
URL_JustLocation(relative.ap2))
strcatW(preliminary, single_slash);
break;
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);
work = preliminary + base.sizep1 + 1;
strcpyW(work, relative.ap2);
if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) &&
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; *pcchCombined = len;
TRACE("return-3 len=%ld, %s\n", ret = E_POINTER;
*pcchCombined, debugstr_w(pszCombined)); break;
return S_OK;
} }
FIXME("(base %s, Relative %s, Combine size %ld, flags %08lx) unknown case\n", strncpyW(preliminary, base.ap1, base.sizep1+1+sizeloc);
debugstr_w(pszBase),debugstr_w(pszRelative), work = preliminary + base.sizep1 + 1 + sizeloc;
*pcchCombined,dwFlags); if (dwFlags & URL_PLUGGABLE_PROTOCOL)
FIXME(" s1len=%ld, s2len=%ld\n", s1len, s2len); *(work++) = L'/';
return E_INVALIDARG; 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;
}
if (ret == S_OK) {
/*
* Now that the combining is done, process the escape options if
* 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)