Thomas Mullaly : urlmon: Implemented case when relative URI has a path that doesn't start with '/'.
Alexandre Julliard
julliard at winehq.org
Wed Nov 3 11:37:06 CDT 2010
Module: wine
Branch: master
Commit: 290aca1b19b8ae962fd33d27d4d5a8ae3e575aed
URL: http://source.winehq.org/git/wine.git/?a=commit;h=290aca1b19b8ae962fd33d27d4d5a8ae3e575aed
Author: Thomas Mullaly <thomas.mullaly at gmail.com>
Date: Sun Oct 31 21:31:30 2010 -0400
urlmon: Implemented case when relative URI has a path that doesn't start with '/'.
---
dlls/urlmon/tests/uri.c | 39 ++++++++++++++++---
dlls/urlmon/uri.c | 98 +++++++++++++++++++++++++++++++++++++++--------
2 files changed, 115 insertions(+), 22 deletions(-)
diff --git a/dlls/urlmon/tests/uri.c b/dlls/urlmon/tests/uri.c
index 7dd58d8..7b59e7f 100644
--- a/dlls/urlmon/tests/uri.c
+++ b/dlls/urlmon/tests/uri.c
@@ -5612,7 +5612,7 @@ typedef struct _uri_combine_test {
static const uri_combine_test uri_combine_tests[] = {
{ "http://google.com/fun/stuff",0,
"../not/fun/stuff",Uri_CREATE_ALLOW_RELATIVE,
- 0,S_OK,TRUE,
+ 0,S_OK,FALSE,
{
{"http://google.com/not/fun/stuff",S_OK},
{"google.com",S_OK},
@@ -5747,7 +5747,7 @@ static const uri_combine_test uri_combine_tests[] = {
},
{ "http://winehq.org/test/abc",0,
"testing/abc/../test",Uri_CREATE_ALLOW_RELATIVE,
- 0,S_OK,TRUE,
+ 0,S_OK,FALSE,
{
{"http://winehq.org/test/testing/test",S_OK},
{"winehq.org",S_OK},
@@ -5774,7 +5774,7 @@ static const uri_combine_test uri_combine_tests[] = {
},
{ "http://winehq.org/test/abc",0,
"testing/abc/../test",Uri_CREATE_ALLOW_RELATIVE,
- URL_DONT_SIMPLIFY,S_OK,TRUE,
+ URL_DONT_SIMPLIFY,S_OK,FALSE,
{
{"http://winehq.org:80/test/testing/abc/../test",S_OK},
/* Default port is hidden in the authority. */
@@ -5802,7 +5802,7 @@ static const uri_combine_test uri_combine_tests[] = {
},
{ "http://winehq.org/test?query",0,
"testing",Uri_CREATE_ALLOW_RELATIVE,
- 0,S_OK,TRUE,
+ 0,S_OK,FALSE,
{
{"http://winehq.org/testing",S_OK},
{"winehq.org",S_OK},
@@ -5829,7 +5829,7 @@ static const uri_combine_test uri_combine_tests[] = {
},
{ "http://winehq.org/test#frag",0,
"testing",Uri_CREATE_ALLOW_RELATIVE,
- 0,S_OK,TRUE,
+ 0,S_OK,FALSE,
{
{"http://winehq.org/testing",S_OK},
{"winehq.org",S_OK},
@@ -5856,7 +5856,7 @@ static const uri_combine_test uri_combine_tests[] = {
},
{ "testing?query#frag",Uri_CREATE_ALLOW_RELATIVE,
"test",Uri_CREATE_ALLOW_RELATIVE,
- 0,S_OK,TRUE,
+ 0,S_OK,FALSE,
{
{"test",S_OK},
{"",S_FALSE},
@@ -6253,6 +6253,33 @@ static const uri_combine_test uri_combine_tests[] = {
{URL_SCHEME_UNKNOWN,S_OK},
{URLZONE_INVALID,E_NOTIMPL}
}
+ },
+ { "file:///c:/",0,
+ "../testing/test",Uri_CREATE_ALLOW_RELATIVE,
+ 0,S_OK,FALSE,
+ {
+ {"file:///c:/testing/test",S_OK},
+ {"",S_FALSE},
+ {"file:///c:/testing/test",S_OK},
+ {"",S_FALSE},
+ {"",S_FALSE},
+ {"",S_FALSE},
+ {"",S_FALSE},
+ {"",S_FALSE},
+ {"/c:/testing/test",S_OK},
+ {"/c:/testing/test",S_OK},
+ {"",S_FALSE},
+ {"file:///c:/testing/test",S_OK},
+ {"file",S_OK},
+ {"",S_FALSE},
+ {"",S_FALSE}
+ },
+ {
+ {Uri_HOST_UNKNOWN,S_OK},
+ {0,S_FALSE},
+ {URL_SCHEME_FILE,S_OK},
+ {URLZONE_INVALID,E_NOTIMPL}
+ }
}
};
diff --git a/dlls/urlmon/uri.c b/dlls/urlmon/uri.c
index 7eaadb4..3bbe54f 100644
--- a/dlls/urlmon/uri.c
+++ b/dlls/urlmon/uri.c
@@ -5679,6 +5679,51 @@ HRESULT WINAPI CreateIUriBuilder(IUri *pIUri, DWORD dwFlags, DWORD_PTR dwReserve
return S_OK;
}
+/* Merges the base path with the relative path and stores the resulting path
+ * and path len in 'result' and 'result_len'.
+ */
+static HRESULT merge_paths(parse_data *data, const WCHAR *base, DWORD base_len, const WCHAR *relative,
+ DWORD relative_len, WCHAR **result, DWORD *result_len, DWORD flags)
+{
+ const WCHAR *end = NULL;
+ DWORD base_copy_len = 0;
+ WCHAR *ptr;
+
+ if(base_len) {
+ /* Find the characters the will be copied over from
+ * the base path.
+ */
+ end = str_last_of(base, base+(base_len-1), '/');
+ if(!end && data->scheme_type == URL_SCHEME_FILE)
+ /* Try looking for a '\\'. */
+ end = str_last_of(base, base+(base_len-1), '\\');
+ }
+
+ if(end) {
+ base_copy_len = (end+1)-base;
+ *result = heap_alloc((base_copy_len+relative_len+1)*sizeof(WCHAR));
+ } else
+ *result = heap_alloc((relative_len+1)*sizeof(WCHAR));
+
+ if(!(*result)) {
+ *result_len = 0;
+ return E_OUTOFMEMORY;
+ }
+
+ ptr = *result;
+ if(end) {
+ memcpy(ptr, base, base_copy_len*sizeof(WCHAR));
+ ptr += base_copy_len;
+ }
+
+ memcpy(ptr, relative, relative_len*sizeof(WCHAR));
+ ptr += relative_len;
+ *ptr = '\0';
+
+ *result_len = (ptr-*result);
+ return S_OK;
+}
+
static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result) {
Uri *ret;
HRESULT hr;
@@ -5777,10 +5822,16 @@ static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result)
data.query_len = base->query_len;
}
} else {
+ const WCHAR *ptr, **pptr;
DWORD path_offset = 0, path_len = 0;
+ /* There's two possibilities on what will happen to the path component
+ * of the result IUri. First, if the relative path begins with a '/'
+ * then the resulting path will just be the relative path. Second, if
+ * relative path doesn't begin with a '/' then the base path and relative
+ * path are merged together.
+ */
if(relative->path_len && *(relative->canon_uri+relative->path_start) == '/') {
- const WCHAR *ptr, **pptr;
WCHAR *tmp = NULL;
BOOL copy_drive_path = FALSE;
@@ -5815,19 +5866,25 @@ static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result)
memcpy(tmp, relative->canon_uri+relative->path_start, relative->path_len*sizeof(WCHAR));
path[path_len] = '\0';
-
- ptr = path;
- pptr = &ptr;
- if((data.is_opaque && !parse_path_opaque(pptr, &data, 0)) ||
- (!data.is_opaque && !parse_path_hierarchical(pptr, &data, 0))) {
- heap_free(path);
+ } else {
+ /* Merge the base path with the relative path. */
+ hr = merge_paths(&data, base->canon_uri+base->path_start, base->path_len,
+ relative->canon_uri+relative->path_start, relative->path_len,
+ &path, &path_len, flags);
+ if(FAILED(hr)) {
*result = NULL;
- return E_INVALIDARG;
+ return hr;
+ }
+
+ /* If the resulting IUri is a file URI, the drive path isn't
+ * reduced out when the dot segments are removed.
+ */
+ if(path_len >= 3 && data.scheme_type == URL_SCHEME_FILE && !data.host) {
+ if(*path == '/' && is_drive_path(path+1))
+ path_offset = 2;
+ else if(is_drive_path(path))
+ path_offset = 1;
}
- } else {
- FIXME("Path merging not implemented yet!\n");
- *result = NULL;
- return E_NOTIMPL;
}
/* Check if the dot segments need to be removed from the path. */
@@ -5836,19 +5893,28 @@ static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result)
DWORD new_len = remove_dot_segments(path+offset,path_len-offset);
if(new_len != path_len) {
- WCHAR *tmp = heap_realloc(path, (new_len+1)*sizeof(WCHAR));
+ WCHAR *tmp = heap_realloc(path, (path_offset+new_len+1)*sizeof(WCHAR));
if(!tmp) {
heap_free(path);
*result = NULL;
return E_OUTOFMEMORY;
}
- tmp[new_len] = '\0';
- data.path = tmp;
- data.path_len = new_len;
+ tmp[new_len+offset] = '\0';
path = tmp;
+ path_len = new_len+offset;
}
}
+
+ /* Make sure the path component is valid. */
+ ptr = path;
+ pptr = &ptr;
+ if((data.is_opaque && !parse_path_opaque(pptr, &data, 0)) ||
+ (!data.is_opaque && !parse_path_hierarchical(pptr, &data, 0))) {
+ heap_free(path);
+ *result = NULL;
+ return E_INVALIDARG;
+ }
}
if(relative->fragment_start > -1) {
More information about the wine-cvs
mailing list