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