Revert r66580 and r66579.
[reactos.git] / reactos / dll / win32 / mshtml / htmllocation.c
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 FIXME("(%p)->(%s)\n", This, debugstr_w(v));
502 return E_NOTIMPL;
503 }
504
505 static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p)
506 {
507 HTMLLocation *This = impl_from_IHTMLLocation(iface);
508 BSTR hash;
509 IUri *uri;
510 HRESULT hres;
511
512 TRACE("(%p)->(%p)\n", This, p);
513
514 if(!p)
515 return E_POINTER;
516
517 if(!(uri = get_uri(This))) {
518 FIXME("No current URI\n");
519 return E_NOTIMPL;
520 }
521
522 hres = IUri_GetFragment(uri, &hash);
523 if(hres == S_OK) {
524 *p = hash;
525 }else if(hres == S_FALSE) {
526 SysFreeString(hash);
527 *p = NULL;
528 }else {
529 return hres;
530 }
531
532 return S_OK;
533 }
534
535 static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL flag)
536 {
537 HTMLLocation *This = impl_from_IHTMLLocation(iface);
538 FIXME("(%p)->(%x)\n", This, flag);
539 return E_NOTIMPL;
540 }
541
542 static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr)
543 {
544 HTMLLocation *This = impl_from_IHTMLLocation(iface);
545
546 TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
547
548 if(!This->window || !This->window->base.outer_window) {
549 FIXME("No window available\n");
550 return E_FAIL;
551 }
552
553 return navigate_url(This->window->base.outer_window, bstr, This->window->base.outer_window->uri,
554 BINDING_NAVIGATED|BINDING_REPLACE);
555 }
556
557 static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr)
558 {
559 HTMLLocation *This = impl_from_IHTMLLocation(iface);
560 TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
561 return IHTMLLocation_put_href(iface, bstr);
562 }
563
564 static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String)
565 {
566 HTMLLocation *This = impl_from_IHTMLLocation(iface);
567
568 TRACE("(%p)->(%p)\n", This, String);
569
570 return IHTMLLocation_get_href(&This->IHTMLLocation_iface, String);
571 }
572
573 static const IHTMLLocationVtbl HTMLLocationVtbl = {
574 HTMLLocation_QueryInterface,
575 HTMLLocation_AddRef,
576 HTMLLocation_Release,
577 HTMLLocation_GetTypeInfoCount,
578 HTMLLocation_GetTypeInfo,
579 HTMLLocation_GetIDsOfNames,
580 HTMLLocation_Invoke,
581 HTMLLocation_put_href,
582 HTMLLocation_get_href,
583 HTMLLocation_put_protocol,
584 HTMLLocation_get_protocol,
585 HTMLLocation_put_host,
586 HTMLLocation_get_host,
587 HTMLLocation_put_hostname,
588 HTMLLocation_get_hostname,
589 HTMLLocation_put_port,
590 HTMLLocation_get_port,
591 HTMLLocation_put_pathname,
592 HTMLLocation_get_pathname,
593 HTMLLocation_put_search,
594 HTMLLocation_get_search,
595 HTMLLocation_put_hash,
596 HTMLLocation_get_hash,
597 HTMLLocation_reload,
598 HTMLLocation_replace,
599 HTMLLocation_assign,
600 HTMLLocation_toString
601 };
602
603 static const tid_t HTMLLocation_iface_tids[] = {
604 IHTMLLocation_tid,
605 0
606 };
607 static dispex_static_data_t HTMLLocation_dispex = {
608 NULL,
609 DispHTMLLocation_tid,
610 NULL,
611 HTMLLocation_iface_tids
612 };
613
614
615 HRESULT HTMLLocation_Create(HTMLInnerWindow *window, HTMLLocation **ret)
616 {
617 HTMLLocation *location;
618
619 location = heap_alloc(sizeof(*location));
620 if(!location)
621 return E_OUTOFMEMORY;
622
623 location->IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl;
624 location->ref = 1;
625 location->window = window;
626
627 init_dispex(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex);
628
629 *ret = location;
630 return S_OK;
631 }