xref: /reactos/dll/win32/mshtml/htmllocation.c (revision 845faec4)
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "mshtml_private.h"
20 
21 static HRESULT get_url(HTMLLocation *This, const WCHAR **ret)
22 {
23     if(!This->window || !This->window->base.outer_window || !This->window->base.outer_window->url) {
24         FIXME("No current URL\n");
25         return E_NOTIMPL;
26     }
27 
28     *ret = This->window->base.outer_window->url;
29     return S_OK;
30 }
31 
32 static IUri *get_uri(HTMLLocation *This)
33 {
34     if(!This->window || !This->window->base.outer_window)
35         return NULL;
36     return This->window->base.outer_window->uri;
37 }
38 
39 static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url)
40 {
41     const WCHAR *doc_url;
42     HRESULT hres;
43 
44     hres = get_url(This, &doc_url);
45     if(FAILED(hres))
46         return hres;
47 
48     if(!InternetCrackUrlW(doc_url, 0, 0, url)) {
49         FIXME("InternetCrackUrlW failed: 0x%08x\n", GetLastError());
50         SetLastError(0);
51         return E_FAIL;
52     }
53 
54     return S_OK;
55 }
56 
57 static inline HTMLLocation *impl_from_IHTMLLocation(IHTMLLocation *iface)
58 {
59     return CONTAINING_RECORD(iface, HTMLLocation, IHTMLLocation_iface);
60 }
61 
62 static HRESULT WINAPI HTMLLocation_QueryInterface(IHTMLLocation *iface, REFIID riid, void **ppv)
63 {
64     HTMLLocation *This = impl_from_IHTMLLocation(iface);
65 
66     TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
67 
68     if(IsEqualGUID(&IID_IUnknown, riid)) {
69         *ppv = &This->IHTMLLocation_iface;
70     }else if(IsEqualGUID(&IID_IHTMLLocation, riid)) {
71         *ppv = &This->IHTMLLocation_iface;
72     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
73         return *ppv ? S_OK : E_NOINTERFACE;
74     }else {
75         *ppv = NULL;
76         WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
77         return E_NOINTERFACE;
78     }
79 
80     IUnknown_AddRef((IUnknown*)*ppv);
81     return S_OK;
82 }
83 
84 static ULONG WINAPI HTMLLocation_AddRef(IHTMLLocation *iface)
85 {
86     HTMLLocation *This = impl_from_IHTMLLocation(iface);
87     LONG ref = InterlockedIncrement(&This->ref);
88 
89     TRACE("(%p) ref=%d\n", This, ref);
90 
91     return ref;
92 }
93 
94 static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface)
95 {
96     HTMLLocation *This = impl_from_IHTMLLocation(iface);
97     LONG ref = InterlockedDecrement(&This->ref);
98 
99     TRACE("(%p) ref=%d\n", This, ref);
100 
101     if(!ref) {
102         if(This->window)
103             This->window->location = NULL;
104         release_dispex(&This->dispex);
105         heap_free(This);
106     }
107 
108     return ref;
109 }
110 
111 static HRESULT WINAPI HTMLLocation_GetTypeInfoCount(IHTMLLocation *iface, UINT *pctinfo)
112 {
113     HTMLLocation *This = impl_from_IHTMLLocation(iface);
114     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
115 }
116 
117 static HRESULT WINAPI HTMLLocation_GetTypeInfo(IHTMLLocation *iface, UINT iTInfo,
118                                               LCID lcid, ITypeInfo **ppTInfo)
119 {
120     HTMLLocation *This = impl_from_IHTMLLocation(iface);
121     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
122 }
123 
124 static HRESULT WINAPI HTMLLocation_GetIDsOfNames(IHTMLLocation *iface, REFIID riid,
125                                                 LPOLESTR *rgszNames, UINT cNames,
126                                                 LCID lcid, DISPID *rgDispId)
127 {
128     HTMLLocation *This = impl_from_IHTMLLocation(iface);
129     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
130             lcid, rgDispId);
131 }
132 
133 static HRESULT WINAPI HTMLLocation_Invoke(IHTMLLocation *iface, DISPID dispIdMember,
134                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
135                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
136 {
137     HTMLLocation *This = impl_from_IHTMLLocation(iface);
138     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
139             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
140 }
141 
142 static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v)
143 {
144     HTMLLocation *This = impl_from_IHTMLLocation(iface);
145 
146     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
147 
148     if(!This->window || !This->window->base.outer_window) {
149         FIXME("No window available\n");
150         return E_FAIL;
151     }
152 
153     return navigate_url(This->window->base.outer_window, v, This->window->base.outer_window->uri, BINDING_NAVIGATED);
154 }
155 
156 static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p)
157 {
158     HTMLLocation *This = impl_from_IHTMLLocation(iface);
159     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
160     WCHAR *buf = NULL, *url_path = NULL;
161     HRESULT hres, ret;
162     DWORD len = 0;
163     int i;
164 
165     TRACE("(%p)->(%p)\n", This, p);
166 
167     if(!p)
168         return E_POINTER;
169 
170     url.dwSchemeLength = 1;
171     url.dwHostNameLength = 1;
172     url.dwUrlPathLength = 1;
173     url.dwExtraInfoLength = 1;
174     hres = get_url_components(This, &url);
175     if(FAILED(hres))
176         return hres;
177 
178     switch(url.nScheme) {
179     case INTERNET_SCHEME_FILE:
180         {
181             /* prepend a slash */
182             url_path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));
183             if(!url_path)
184                 return E_OUTOFMEMORY;
185             url_path[0] = '/';
186             memcpy(url_path + 1, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
187             url.lpszUrlPath = url_path;
188             url.dwUrlPathLength = url.dwUrlPathLength + 1;
189         }
190         break;
191 
192     case INTERNET_SCHEME_HTTP:
193     case INTERNET_SCHEME_HTTPS:
194     case INTERNET_SCHEME_FTP:
195         if(!url.dwUrlPathLength) {
196             /* add a slash if it's blank */
197             url_path = url.lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, 1 * sizeof(WCHAR));
198             if(!url.lpszUrlPath)
199                 return E_OUTOFMEMORY;
200             url.lpszUrlPath[0] = '/';
201             url.dwUrlPathLength = 1;
202         }
203         break;
204 
205     default:
206         break;
207     }
208 
209     /* replace \ with / */
210     for(i = 0; i < url.dwUrlPathLength; ++i)
211         if(url.lpszUrlPath[i] == '\\')
212             url.lpszUrlPath[i] = '/';
213 
214     if(InternetCreateUrlW(&url, ICU_ESCAPE, NULL, &len)) {
215         FIXME("InternetCreateUrl succeeded with NULL buffer?\n");
216         ret = E_FAIL;
217         goto cleanup;
218     }
219 
220     if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
221         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
222         SetLastError(0);
223         ret = E_FAIL;
224         goto cleanup;
225     }
226     SetLastError(0);
227 
228     buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
229     if(!buf) {
230         ret = E_OUTOFMEMORY;
231         goto cleanup;
232     }
233 
234     if(!InternetCreateUrlW(&url, ICU_ESCAPE, buf, &len)) {
235         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
236         SetLastError(0);
237         ret = E_FAIL;
238         goto cleanup;
239     }
240 
241     *p = SysAllocStringLen(buf, len);
242     if(!*p) {
243         ret = E_OUTOFMEMORY;
244         goto cleanup;
245     }
246 
247     ret = S_OK;
248 
249 cleanup:
250     HeapFree(GetProcessHeap(), 0, buf);
251     HeapFree(GetProcessHeap(), 0, url_path);
252 
253     return ret;
254 }
255 
256 static HRESULT WINAPI HTMLLocation_put_protocol(IHTMLLocation *iface, BSTR v)
257 {
258     HTMLLocation *This = impl_from_IHTMLLocation(iface);
259     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
260     return E_NOTIMPL;
261 }
262 
263 static HRESULT WINAPI HTMLLocation_get_protocol(IHTMLLocation *iface, BSTR *p)
264 {
265     HTMLLocation *This = impl_from_IHTMLLocation(iface);
266     BSTR protocol, ret;
267     unsigned len;
268     IUri *uri;
269     HRESULT hres;
270 
271     TRACE("(%p)->(%p)\n", This, p);
272 
273     if(!p)
274         return E_POINTER;
275 
276     if(!(uri = get_uri(This))) {
277         FIXME("No current URI\n");
278         return E_NOTIMPL;
279     }
280 
281     hres = IUri_GetSchemeName(uri, &protocol);
282     if(FAILED(hres))
283         return hres;
284     if(hres == S_FALSE) {
285         SysFreeString(protocol);
286         *p = NULL;
287         return S_OK;
288     }
289 
290     len = SysStringLen(protocol);
291     ret = SysAllocStringLen(protocol, len+1);
292     SysFreeString(protocol);
293     if(!ret)
294         return E_OUTOFMEMORY;
295 
296     ret[len] = ':';
297     *p = ret;
298     return S_OK;
299 }
300 
301 static HRESULT WINAPI HTMLLocation_put_host(IHTMLLocation *iface, BSTR v)
302 {
303     HTMLLocation *This = impl_from_IHTMLLocation(iface);
304     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
305     return E_NOTIMPL;
306 }
307 
308 static HRESULT WINAPI HTMLLocation_get_host(IHTMLLocation *iface, BSTR *p)
309 {
310     HTMLLocation *This = impl_from_IHTMLLocation(iface);
311     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
312     HRESULT hres;
313 
314     TRACE("(%p)->(%p)\n", This, p);
315 
316     if(!p)
317         return E_POINTER;
318 
319     url.dwHostNameLength = 1;
320     hres = get_url_components(This, &url);
321     if(FAILED(hres))
322         return hres;
323 
324     if(!url.dwHostNameLength){
325         *p = NULL;
326         return S_OK;
327     }
328 
329     if(url.nPort) {
330         /* <hostname>:<port> */
331         const WCHAR format[] = {'%','u',0};
332         DWORD len = url.dwHostNameLength + 1 + 5;
333         WCHAR *buf;
334 
335         buf = *p = SysAllocStringLen(NULL, len);
336         memcpy(buf, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
337         buf[url.dwHostNameLength] = ':';
338         snprintfW(buf + url.dwHostNameLength + 1, 6, format, url.nPort);
339     }else
340         *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength);
341 
342     if(!*p)
343         return E_OUTOFMEMORY;
344     return S_OK;
345 }
346 
347 static HRESULT WINAPI HTMLLocation_put_hostname(IHTMLLocation *iface, BSTR v)
348 {
349     HTMLLocation *This = impl_from_IHTMLLocation(iface);
350     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
351     return E_NOTIMPL;
352 }
353 
354 static HRESULT WINAPI HTMLLocation_get_hostname(IHTMLLocation *iface, BSTR *p)
355 {
356     HTMLLocation *This = impl_from_IHTMLLocation(iface);
357     BSTR hostname;
358     IUri *uri;
359     HRESULT hres;
360 
361     TRACE("(%p)->(%p)\n", This, p);
362 
363     if(!p)
364         return E_POINTER;
365 
366     if(!(uri = get_uri(This))) {
367         FIXME("No current URI\n");
368         return E_NOTIMPL;
369     }
370 
371     hres = IUri_GetHost(uri, &hostname);
372     if(hres == S_OK) {
373         *p = hostname;
374     }else if(hres == S_FALSE) {
375         SysFreeString(hostname);
376         *p = NULL;
377     }else {
378         return hres;
379     }
380 
381     return S_OK;
382 }
383 
384 static HRESULT WINAPI HTMLLocation_put_port(IHTMLLocation *iface, BSTR v)
385 {
386     HTMLLocation *This = impl_from_IHTMLLocation(iface);
387     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
388     return E_NOTIMPL;
389 }
390 
391 static HRESULT WINAPI HTMLLocation_get_port(IHTMLLocation *iface, BSTR *p)
392 {
393     HTMLLocation *This = impl_from_IHTMLLocation(iface);
394     DWORD port;
395     IUri *uri;
396     HRESULT hres;
397 
398     TRACE("(%p)->(%p)\n", This, p);
399 
400     if(!p)
401         return E_POINTER;
402 
403     if(!(uri = get_uri(This))) {
404         FIXME("No current URI\n");
405         return E_NOTIMPL;
406     }
407 
408     hres = IUri_GetPort(uri, &port);
409     if(FAILED(hres))
410         return hres;
411 
412     if(hres == S_OK) {
413         static const WCHAR formatW[] = {'%','u',0};
414         WCHAR buf[12];
415 
416         sprintfW(buf, formatW, port);
417         *p = SysAllocString(buf);
418     }else {
419         *p = SysAllocStringLen(NULL, 0);
420     }
421 
422     if(!*p)
423         return E_OUTOFMEMORY;
424     return S_OK;
425 }
426 
427 static HRESULT WINAPI HTMLLocation_put_pathname(IHTMLLocation *iface, BSTR v)
428 {
429     HTMLLocation *This = impl_from_IHTMLLocation(iface);
430     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
431     return E_NOTIMPL;
432 }
433 
434 static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p)
435 {
436     HTMLLocation *This = impl_from_IHTMLLocation(iface);
437     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
438     HRESULT hres;
439 
440     TRACE("(%p)->(%p)\n", This, p);
441 
442     if(!p)
443         return E_POINTER;
444 
445     url.dwUrlPathLength = 1;
446     url.dwExtraInfoLength = 1;
447     hres = get_url_components(This, &url);
448     if(FAILED(hres))
449         return hres;
450 
451     if(url.dwUrlPathLength && url.lpszUrlPath[0] == '/')
452         *p = SysAllocStringLen(url.lpszUrlPath + 1, url.dwUrlPathLength - 1);
453     else
454         *p = SysAllocStringLen(url.lpszUrlPath, url.dwUrlPathLength);
455 
456     if(!*p)
457         return E_OUTOFMEMORY;
458     return S_OK;
459 }
460 
461 static HRESULT WINAPI HTMLLocation_put_search(IHTMLLocation *iface, BSTR v)
462 {
463     HTMLLocation *This = impl_from_IHTMLLocation(iface);
464     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
465     return E_NOTIMPL;
466 }
467 
468 static HRESULT WINAPI HTMLLocation_get_search(IHTMLLocation *iface, BSTR *p)
469 {
470     HTMLLocation *This = impl_from_IHTMLLocation(iface);
471     BSTR query;
472     IUri *uri;
473     HRESULT hres;
474 
475     TRACE("(%p)->(%p)\n", This, p);
476 
477     if(!p)
478         return E_POINTER;
479 
480     if(!(uri = get_uri(This))) {
481         FIXME("No current URI\n");
482         return E_NOTIMPL;
483     }
484 
485     hres = IUri_GetQuery(uri, &query);
486     if(hres == S_OK) {
487         *p = query;
488     }else if(hres == S_FALSE) {
489         SysFreeString(query);
490         *p = NULL;
491     }else {
492         return hres;
493     }
494 
495     return S_OK;
496 }
497 
498 static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v)
499 {
500     HTMLLocation *This = impl_from_IHTMLLocation(iface);
501 
502     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
503 
504     if(!This->window || !This->window->base.outer_window) {
505         FIXME("No window available\n");
506         return E_FAIL;
507     }
508 
509     return navigate_url(This->window->base.outer_window, v, This->window->base.outer_window->uri, 0);
510 }
511 
512 static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p)
513 {
514     HTMLLocation *This = impl_from_IHTMLLocation(iface);
515     BSTR hash;
516     IUri *uri;
517     HRESULT hres;
518 
519     TRACE("(%p)->(%p)\n", This, p);
520 
521     if(!p)
522         return E_POINTER;
523 
524     if(!(uri = get_uri(This))) {
525         FIXME("No current URI\n");
526         return E_NOTIMPL;
527     }
528 
529     hres = IUri_GetFragment(uri, &hash);
530     if(hres == S_OK) {
531         *p = hash;
532     }else if(hres == S_FALSE) {
533         SysFreeString(hash);
534         *p = NULL;
535     }else {
536         return hres;
537     }
538 
539     return S_OK;
540 }
541 
542 static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL flag)
543 {
544     HTMLLocation *This = impl_from_IHTMLLocation(iface);
545     FIXME("(%p)->(%x)\n", This, flag);
546     return E_NOTIMPL;
547 }
548 
549 static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr)
550 {
551     HTMLLocation *This = impl_from_IHTMLLocation(iface);
552 
553     TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
554 
555     if(!This->window || !This->window->base.outer_window) {
556         FIXME("No window available\n");
557         return E_FAIL;
558     }
559 
560     return navigate_url(This->window->base.outer_window, bstr, This->window->base.outer_window->uri,
561             BINDING_NAVIGATED|BINDING_REPLACE);
562 }
563 
564 static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr)
565 {
566     HTMLLocation *This = impl_from_IHTMLLocation(iface);
567     TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
568     return IHTMLLocation_put_href(iface, bstr);
569 }
570 
571 static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String)
572 {
573     HTMLLocation *This = impl_from_IHTMLLocation(iface);
574 
575     TRACE("(%p)->(%p)\n", This, String);
576 
577     return IHTMLLocation_get_href(&This->IHTMLLocation_iface, String);
578 }
579 
580 static const IHTMLLocationVtbl HTMLLocationVtbl = {
581     HTMLLocation_QueryInterface,
582     HTMLLocation_AddRef,
583     HTMLLocation_Release,
584     HTMLLocation_GetTypeInfoCount,
585     HTMLLocation_GetTypeInfo,
586     HTMLLocation_GetIDsOfNames,
587     HTMLLocation_Invoke,
588     HTMLLocation_put_href,
589     HTMLLocation_get_href,
590     HTMLLocation_put_protocol,
591     HTMLLocation_get_protocol,
592     HTMLLocation_put_host,
593     HTMLLocation_get_host,
594     HTMLLocation_put_hostname,
595     HTMLLocation_get_hostname,
596     HTMLLocation_put_port,
597     HTMLLocation_get_port,
598     HTMLLocation_put_pathname,
599     HTMLLocation_get_pathname,
600     HTMLLocation_put_search,
601     HTMLLocation_get_search,
602     HTMLLocation_put_hash,
603     HTMLLocation_get_hash,
604     HTMLLocation_reload,
605     HTMLLocation_replace,
606     HTMLLocation_assign,
607     HTMLLocation_toString
608 };
609 
610 static const tid_t HTMLLocation_iface_tids[] = {
611     IHTMLLocation_tid,
612     0
613 };
614 static dispex_static_data_t HTMLLocation_dispex = {
615     NULL,
616     DispHTMLLocation_tid,
617     NULL,
618     HTMLLocation_iface_tids
619 };
620 
621 
622 HRESULT HTMLLocation_Create(HTMLInnerWindow *window, HTMLLocation **ret)
623 {
624     HTMLLocation *location;
625 
626     location = heap_alloc(sizeof(*location));
627     if(!location)
628         return E_OUTOFMEMORY;
629 
630     location->IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl;
631     location->ref = 1;
632     location->window = window;
633 
634     init_dispex(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex);
635 
636     *ret = location;
637     return S_OK;
638 }
639