protocol.c 27.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright 2005 Jacek Caban
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 */

#include <stdarg.h>
#include <stdio.h>

#define COBJMACROS

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"

#include "wine/debug.h"

#include "mshtml_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(mshtml);

35
typedef struct {
36
    IUnknown          IUnknown_inner;
37 38 39 40 41 42 43 44
    IInternetProtocol IInternetProtocol_iface;

    LONG ref;

    BYTE *data;
    ULONG data_len;
    ULONG cur;

45
    IUnknown *outer;
46 47
} InternetProtocol;

48 49 50 51 52
/********************************************************************
 * common ProtocolFactory implementation
 */

typedef struct {
53 54
    IInternetProtocolInfo IInternetProtocolInfo_iface;
    IClassFactory         IClassFactory_iface;
55 56
} ProtocolFactory;

57 58 59 60
static inline ProtocolFactory *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface)
{
    return CONTAINING_RECORD(iface, ProtocolFactory, IInternetProtocolInfo_iface);
}
61 62 63

static HRESULT WINAPI InternetProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
{
64
    ProtocolFactory *This = impl_from_IInternetProtocolInfo(iface);
65 66 67 68

    *ppv = NULL;
    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
69
        *ppv = &This->IInternetProtocolInfo_iface;
70 71
    }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
        TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv);
72
        *ppv = &This->IInternetProtocolInfo_iface;
73 74
    }else if(IsEqualGUID(&IID_IClassFactory, riid)) {
        TRACE("(%p)->(IID_IClassFactory %p)\n", This, ppv);
75
        *ppv = &This->IClassFactory_iface;
76 77 78 79 80 81 82 83 84 85 86 87 88
    }

    if(!*ppv) {
        WARN("unknown interface %s\n", debugstr_guid(riid));
        return E_NOINTERFACE;
    }

    IInternetProtocolInfo_AddRef(iface);
    return S_OK;
}

static ULONG WINAPI InternetProtocolInfo_AddRef(IInternetProtocolInfo *iface)
{
89
    TRACE("(%p)\n", iface);
90 91 92 93 94
    return 2;
}

static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface)
{
95
    TRACE("(%p)\n", iface);
96 97 98
    return 1;
}

99 100 101 102
static HRESULT WINAPI InternetProtocolInfo_CombineUrl(IInternetProtocolInfo *iface,
        LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult,
        DWORD cchResult, DWORD* pcchResult, DWORD dwReserved)
{
103
    TRACE("%p)->(%s %s %08x %p %d %p %d)\n", iface, debugstr_w(pwzBaseUrl),
104 105 106 107 108 109
            debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult,
            pcchResult, dwReserved);

    return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
}

110 111 112 113 114 115 116
static HRESULT WINAPI InternetProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
        LPCWSTR pwzUrl2, DWORD dwCompareFlags)
{
    TRACE("%p)->(%s %s %08x)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
    return E_NOTIMPL;
}

117 118 119 120
static inline ProtocolFactory *impl_from_IClassFactory(IClassFactory *iface)
{
    return CONTAINING_RECORD(iface, ProtocolFactory, IClassFactory_iface);
}
121 122 123

static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
{
124 125
    ProtocolFactory *This = impl_from_IClassFactory(iface);
    return IInternetProtocolInfo_QueryInterface(&This->IInternetProtocolInfo_iface, riid, ppv);
126 127 128 129
}

static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
{
130 131
    ProtocolFactory *This = impl_from_IClassFactory(iface);
    return IInternetProtocolInfo_AddRef(&This->IInternetProtocolInfo_iface);
132 133 134 135
}

static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
{
136 137
    ProtocolFactory *This = impl_from_IClassFactory(iface);
    return IInternetProtocolInfo_Release(&This->IInternetProtocolInfo_iface);
138 139 140 141
}

static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
{
142
    TRACE("(%p)->(%x)\n", iface, dolock);
143 144 145
    return S_OK;
}

146 147 148 149 150
static inline InternetProtocol *impl_from_IUnknown(IUnknown *iface)
{
    return CONTAINING_RECORD(iface, InternetProtocol, IUnknown_inner);
}

151
static inline InternetProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
152
{
153
    return CONTAINING_RECORD(iface, InternetProtocol, IInternetProtocol_iface);
154
}
155

156
static HRESULT WINAPI Protocol_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
157
{
158
    InternetProtocol *This = impl_from_IUnknown(iface);
159

160
    TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
161 162

    if(IsEqualGUID(&IID_IUnknown, riid)) {
163
        *ppv = &This->IUnknown_inner;
164
    }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
165
        *ppv = &This->IInternetProtocol_iface;
166
    }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
167
        *ppv = &This->IInternetProtocol_iface;
168 169 170 171
    }else {
        if(IsEqualGUID(&IID_IServiceProvider, riid))
            FIXME("IServiceProvider is not implemented\n");
        *ppv = NULL;
172 173 174
        return E_NOINTERFACE;
    }

175
    IUnknown_AddRef((IUnknown*)*ppv);
176 177 178
    return S_OK;
}

179
static ULONG WINAPI Protocol_AddRef(IUnknown *iface)
180
{
181
    InternetProtocol *This = impl_from_IUnknown(iface);
182
    ULONG ref = InterlockedIncrement(&This->ref);
183
    TRACE("(%p) ref=%d\n", iface, ref);
184
    return ref;
185 186
}

187
static ULONG WINAPI Protocol_Release(IUnknown *iface)
188
{
189
    InternetProtocol *This = impl_from_IUnknown(iface);
190 191
    ULONG ref = InterlockedDecrement(&This->ref);

192
    TRACE("(%p) ref=%x\n", iface, ref);
193

194
    if(!ref) {
195 196
        heap_free(This->data);
        heap_free(This);
197
    }
198

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
    return ref;
}

static const IUnknownVtbl ProtocolUnkVtbl = {
    Protocol_QueryInterface,
    Protocol_AddRef,
    Protocol_Release
};

static HRESULT WINAPI InternetProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
{
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
    return IUnknown_QueryInterface(This->outer, riid, ppv);
}

static ULONG WINAPI InternetProtocol_AddRef(IInternetProtocol *iface)
{
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
    return IUnknown_AddRef(This->outer);
}

static ULONG WINAPI InternetProtocol_Release(IInternetProtocol *iface)
{
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
    return IUnknown_Release(This->outer);
224 225
}

226
static HRESULT WINAPI InternetProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
227
{
228
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
229 230 231 232
    FIXME("(%p)->(%p)\n", This, pProtocolData);
    return E_NOTIMPL;
}

233
static HRESULT WINAPI InternetProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
234 235
        DWORD dwOptions)
{
236
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
237
    FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
238 239 240
    return E_NOTIMPL;
}

241
static HRESULT WINAPI InternetProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
242
{
243
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
244
    TRACE("(%p)->(%08x)\n", This, dwOptions);
245
    return S_OK;
246 247
}

248
static HRESULT WINAPI InternetProtocol_Suspend(IInternetProtocol *iface)
249
{
250
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
251 252 253 254
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

255
static HRESULT WINAPI InternetProtocol_Resume(IInternetProtocol *iface)
256
{
257
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
258 259 260 261
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

262
static HRESULT WINAPI InternetProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
263
{
264
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
265

266
    TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
267 268 269 270 271 272 273 274 275

    if(!This->data)
        return E_FAIL;

    *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);

    if(!*pcbRead)
        return S_FALSE;

276
    memcpy(pv, This->data+This->cur, *pcbRead);
277 278 279
    This->cur += *pcbRead;

    return S_OK;
280 281
}

282
static HRESULT WINAPI InternetProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
283 284
        DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
{
285
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
286
    FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
287 288 289
    return E_NOTIMPL;
}

290
static HRESULT WINAPI InternetProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
291
{
292
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
293

294
    TRACE("(%p)->(%d)\n", This, dwOptions);
295 296

    return S_OK;
297 298
}

299
static HRESULT WINAPI InternetProtocol_UnlockRequest(IInternetProtocol *iface)
300
{
301
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
302 303 304 305

    TRACE("(%p)\n", This);

    return S_OK;
306 307
}

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
static HRESULT create_protocol_instance(const IInternetProtocolVtbl *protocol_vtbl,
                                        IUnknown *outer, REFIID riid, void **ppv)
{
    InternetProtocol *protocol;
    HRESULT hres;

    if(outer && !IsEqualGUID(&IID_IUnknown, riid)) {
        *ppv = NULL;
        return E_INVALIDARG;
    }

    protocol = heap_alloc_zero(sizeof(InternetProtocol));
    protocol->IUnknown_inner.lpVtbl = &ProtocolUnkVtbl;
    protocol->IInternetProtocol_iface.lpVtbl = protocol_vtbl;
    protocol->outer = outer ? outer : &protocol->IUnknown_inner;
    protocol->ref = 1;

    hres = IUnknown_QueryInterface(&protocol->IUnknown_inner, riid, ppv);
    IUnknown_Release(&protocol->IUnknown_inner);
    return hres;
}

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
/********************************************************************
 * about protocol implementation
 */

static HRESULT WINAPI AboutProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
        IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
        DWORD grfPI, HANDLE_PTR dwReserved)
{
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
    BINDINFO bindinfo;
    DWORD grfBINDF = 0;
    LPCWSTR text = NULL;
    DWORD data_len;
    BYTE *data;
    HRESULT hres;

    static const WCHAR html_begin[] = {0xfeff,'<','H','T','M','L','>',0};
    static const WCHAR html_end[] = {'<','/','H','T','M','L','>',0};
    static const WCHAR wszBlank[] = {'b','l','a','n','k',0};
    static const WCHAR wszAbout[] = {'a','b','o','u','t',':'};
    static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};

    /* NOTE:
     * the about protocol seems not to work as I would expect. It creates html document
     * for a given url, eg. about:some_text -> <HTML>some_text</HTML> except for the case when
     * some_text = "blank", when document is blank (<HTML></HMTL>). The same happens
     * when the url does not have "about:" in the beginning.
     */

    TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
            pOIBindInfo, grfPI, dwReserved);

    memset(&bindinfo, 0, sizeof(bindinfo));
    bindinfo.cbSize = sizeof(BINDINFO);
    hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
    if(FAILED(hres))
        return hres;
    ReleaseBindInfo(&bindinfo);

    TRACE("bindf %x\n", grfBINDF);

371
    if(lstrlenW(szUrl) >= ARRAY_SIZE(wszAbout) && !memcmp(wszAbout, szUrl, sizeof(wszAbout))) {
372
        text = szUrl + ARRAY_SIZE(wszAbout);
373
        if(!wcscmp(wszBlank, text))
374 375 376 377
            text = NULL;
    }

    data_len = sizeof(html_begin)+sizeof(html_end)-sizeof(WCHAR)
378
        + (text ? lstrlenW(text)*sizeof(WCHAR) : 0);
379 380 381 382 383 384 385 386 387 388
    data = heap_alloc(data_len);
    if(!data)
        return E_OUTOFMEMORY;

    heap_free(This->data);
    This->data = data;
    This->data_len = data_len;

    memcpy(This->data, html_begin, sizeof(html_begin));
    if(text)
389 390
        lstrcatW((LPWSTR)This->data, text);
    lstrcatW((LPWSTR)This->data, html_end);
391 392 393 394 395 396 397 398 399 400 401 402 403 404

    This->cur = 0;

    IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);

    IInternetProtocolSink_ReportData(pOIProtSink,
            BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
            This->data_len, This->data_len);

    IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);

    return S_OK;
}

405
static const IInternetProtocolVtbl AboutProtocolVtbl = {
406 407 408
    InternetProtocol_QueryInterface,
    InternetProtocol_AddRef,
    InternetProtocol_Release,
409
    AboutProtocol_Start,
410 411 412 413 414 415 416 417 418
    InternetProtocol_Continue,
    InternetProtocol_Abort,
    InternetProtocol_Terminate,
    InternetProtocol_Suspend,
    InternetProtocol_Resume,
    InternetProtocol_Read,
    InternetProtocol_Seek,
    InternetProtocol_LockRequest,
    InternetProtocol_UnlockRequest
419 420 421 422 423
};

static HRESULT WINAPI AboutProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
        REFIID riid, void **ppv)
{
424
    TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
425

426
    return create_protocol_instance(&AboutProtocolVtbl, pUnkOuter, riid, ppv);
427 428 429 430 431 432
}

static HRESULT WINAPI AboutProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
        PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
        DWORD* pcchResult, DWORD dwReserved)
{
433
    TRACE("%p)->(%s %d %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction,
434
            dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
435 436

    if(ParseAction == PARSE_SECURITY_URL) {
437
        unsigned int len = lstrlenW(pwzUrl)+1;
438

439 440
        *pcchResult = len;
        if(len > cchResult)
441 442
            return S_FALSE;

443
        memcpy(pwzResult, pwzUrl, len*sizeof(WCHAR));
444 445 446 447
        return S_OK;
    }

    if(ParseAction == PARSE_DOMAIN) {
448 449 450 451
        if(!pcchResult)
            return E_POINTER;

        if(pwzUrl)
452
            *pcchResult = lstrlenW(pwzUrl)+1;
453 454 455
        else
            *pcchResult = 1;
        return E_FAIL;
456 457 458
    }

    return INET_E_DEFAULT_ACTION;
459 460 461 462 463 464
}

static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
        QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
        DWORD dwReserved)
{
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
    TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
          cbBuffer, pcbBuf, dwReserved);

    switch(QueryOption) {
    case QUERY_CAN_NAVIGATE:
        return INET_E_USE_DEFAULT_PROTOCOLHANDLER;

    case QUERY_USES_NETWORK:
        if(!pBuffer || cbBuffer < sizeof(DWORD))
            return E_FAIL;

        *(DWORD*)pBuffer = 0;
        if(pcbBuf)
            *pcbBuf = sizeof(DWORD);

        break;

    case QUERY_IS_CACHED:
        FIXME("Unsupported option QUERY_IS_CACHED\n");
        return E_NOTIMPL;
    case QUERY_IS_INSTALLEDENTRY:
        FIXME("Unsupported option QUERY_IS_INSTALLEDENTRY\n");
        return E_NOTIMPL;
    case QUERY_IS_CACHED_OR_MAPPED:
        FIXME("Unsupported option QUERY_IS_CACHED_OR_MAPPED\n");
        return E_NOTIMPL;
    case QUERY_IS_SECURE:
        FIXME("Unsupported option QUERY_IS_SECURE\n");
        return E_NOTIMPL;
    case QUERY_IS_SAFE:
        FIXME("Unsupported option QUERY_IS_SAFE\n");
        return E_NOTIMPL;
497 498 499
    case QUERY_USES_HISTORYFOLDER:
        FIXME("Unsupported option QUERY_USES_HISTORYFOLDER\n");
        return E_FAIL;
500 501 502
    case QUERY_IS_CACHED_AND_USABLE_OFFLINE:
        FIXME("Unsupported option QUERY_IS_CACHED_AND_USABLE_OFFLINE\n");
        return E_NOTIMPL;
503 504 505 506 507
    default:
        return E_FAIL;
    }

    return S_OK;
508 509 510 511 512 513 514
}

static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = {
    InternetProtocolInfo_QueryInterface,
    InternetProtocolInfo_AddRef,
    InternetProtocolInfo_Release,
    AboutProtocolInfo_ParseUrl,
515
    InternetProtocolInfo_CombineUrl,
516
    InternetProtocolInfo_CompareUrl,
517 518 519 520 521 522 523 524 525 526 527 528
    AboutProtocolInfo_QueryInfo
};

static const IClassFactoryVtbl AboutProtocolFactoryVtbl = {
    ClassFactory_QueryInterface,
    ClassFactory_AddRef,
    ClassFactory_Release,
    AboutProtocolFactory_CreateInstance,
    ClassFactory_LockServer
};

static ProtocolFactory AboutProtocolFactory = {
529 530
    { &AboutProtocolInfoVtbl },
    { &AboutProtocolFactoryVtbl }
531 532 533
};

/********************************************************************
534
 * res protocol implementation
535 536 537 538
 */

static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
        IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
539
        DWORD grfPI, HANDLE_PTR dwReserved)
540
{
541
    InternetProtocol *This = impl_from_IInternetProtocol(iface);
542
    WCHAR *url_dll, *url_file, *url, *mime, *res_type = (LPWSTR)RT_HTML, *ptr;
543
    DWORD grfBINDF = 0, len;
Jacek Caban's avatar
Jacek Caban committed
544 545 546
    BINDINFO bindinfo;
    HMODULE hdll;
    HRSRC src;
547
    HRESULT hres;
Jacek Caban's avatar
Jacek Caban committed
548 549 550

    static const WCHAR wszRes[] = {'r','e','s',':','/','/'};

551
    TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
552
            pOIBindInfo, grfPI, dwReserved);
Jacek Caban's avatar
Jacek Caban committed
553 554 555

    memset(&bindinfo, 0, sizeof(bindinfo));
    bindinfo.cbSize = sizeof(BINDINFO);
556 557 558
    hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
    if(FAILED(hres))
        return hres;
559
    ReleaseBindInfo(&bindinfo);
Jacek Caban's avatar
Jacek Caban committed
560

561
    len = lstrlenW(szUrl)+16;
562
    url = heap_alloc(len*sizeof(WCHAR));
563 564
    hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0);
    if(FAILED(hres)) {
565
        WARN("CoInternetParseUrl failed: %08x\n", hres);
566
        heap_free(url);
567 568 569 570
        IInternetProtocolSink_ReportResult(pOIProtSink, hres, 0, NULL);
        return hres;
    }

571
    if(len < ARRAY_SIZE(wszRes) || memcmp(url, wszRes, sizeof(wszRes))) {
572
        WARN("Wrong protocol of url: %s\n", debugstr_w(url));
573
        IInternetProtocolSink_ReportResult(pOIProtSink, E_INVALIDARG, 0, NULL);
574
        heap_free(url);
575
        return E_INVALIDARG;
Jacek Caban's avatar
Jacek Caban committed
576 577
    }

578
    url_dll = url + ARRAY_SIZE(wszRes);
579
    if(!(res_type = wcschr(url_dll, '/'))) {
580
        WARN("wrong url: %s\n", debugstr_w(url));
Jacek Caban's avatar
Jacek Caban committed
581
        IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
582
        heap_free(url);
Jacek Caban's avatar
Jacek Caban committed
583 584 585
        return MK_E_SYNTAX;
    }

586
    *res_type++ = 0;
587
    if ((url_file = wcschr(res_type, '/'))) {
588 589 590
        *url_file++ = 0;
    }else {
        url_file = res_type;
591
        res_type = (LPWSTR)RT_HTML;
592 593
    }

594
    /* Ignore query and hash parts. */
595
    if((ptr = wcschr(url_file, '?')))
596
        *ptr = 0;
597
    if(*url_file && (ptr = wcschr(url_file+1, '#')))
598 599
        *ptr = 0;

600
    hdll = LoadLibraryExW(url_dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
Jacek Caban's avatar
Jacek Caban committed
601
    if(!hdll) {
602 603 604 605
        WARN("Could not open dll: %s\n", debugstr_w(url_dll));
        IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
        heap_free(url);
        return HRESULT_FROM_WIN32(GetLastError());
Jacek Caban's avatar
Jacek Caban committed
606 607
    }

608 609 610
    TRACE("trying to find resource type %s, name %s\n", debugstr_w(res_type), debugstr_w(url_file));

    src = FindResourceW(hdll, url_file, res_type);
Jacek Caban's avatar
Jacek Caban committed
611
    if(!src) {
612
        LPWSTR endpoint = NULL;
613 614
        DWORD file_id = wcstol(url_file, &endpoint, 10);
        if(endpoint == url_file+lstrlenW(url_file))
615
            src = FindResourceW(hdll, MAKEINTRESOURCEW(file_id), res_type);
616 617 618 619 620

        if(!src) {
            WARN("Could not find resource\n");
            IInternetProtocolSink_ReportResult(pOIProtSink,
                    HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
621
            heap_free(url);
622 623
            return HRESULT_FROM_WIN32(GetLastError());
        }
Jacek Caban's avatar
Jacek Caban committed
624 625 626 627
    }

    if(This->data) {
        WARN("data already loaded\n");
628
        heap_free(This->data);
Jacek Caban's avatar
Jacek Caban committed
629 630 631
    }

    This->data_len = SizeofResource(hdll, src);
632
    This->data = heap_alloc(This->data_len);
Jacek Caban's avatar
Jacek Caban committed
633 634 635 636 637
    memcpy(This->data, LoadResource(hdll, src), This->data_len);
    This->cur = 0;

    FreeLibrary(hdll);

638
    hres = FindMimeFromData(NULL, url_file, This->data, This->data_len, NULL, 0, &mime, 0);
639
    heap_free(url);
640 641 642 643 644
    if(SUCCEEDED(hres)) {
        IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
        CoTaskMemFree(mime);
    }

Jacek Caban's avatar
Jacek Caban committed
645 646 647 648 649 650 651
    IInternetProtocolSink_ReportData(pOIProtSink,
            BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
            This->data_len, This->data_len);

    IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
    
    return S_OK;
652 653 654
}

static const IInternetProtocolVtbl ResProtocolVtbl = {
655 656 657
    InternetProtocol_QueryInterface,
    InternetProtocol_AddRef,
    InternetProtocol_Release,
658
    ResProtocol_Start,
659 660 661 662 663 664 665 666 667
    InternetProtocol_Continue,
    InternetProtocol_Abort,
    InternetProtocol_Terminate,
    InternetProtocol_Suspend,
    InternetProtocol_Resume,
    InternetProtocol_Read,
    InternetProtocol_Seek,
    InternetProtocol_LockRequest,
    InternetProtocol_UnlockRequest
668 669 670 671 672
};

static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
        REFIID riid, void **ppv)
{
673
    TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
674

675
    return create_protocol_instance(&ResProtocolVtbl, pUnkOuter, riid, ppv);
676 677 678 679 680 681
}

static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
        PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
        DWORD* pcchResult, DWORD dwReserved)
{
682
    TRACE("%p)->(%s %d %x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction,
683
            dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
684 685

    if(ParseAction == PARSE_SECURITY_URL) {
686
        WCHAR file_part[MAX_PATH], full_path[MAX_PATH];
687
        WCHAR *ptr;
688
        DWORD size, len;
689 690 691 692

        static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'};
        static const WCHAR wszRes[] = {'r','e','s',':','/','/'};

693
        if(lstrlenW(pwzUrl) <= ARRAY_SIZE(wszRes) || memcmp(pwzUrl, wszRes, sizeof(wszRes)))
694
            return E_INVALIDARG;
695

696
        ptr = wcschr(pwzUrl + ARRAY_SIZE(wszRes), '/');
697
        if(!ptr)
698
            return E_INVALIDARG;
699

700 701
        len = ptr - (pwzUrl + ARRAY_SIZE(wszRes));
        if(len >= ARRAY_SIZE(file_part)) {
702 703 704
            FIXME("Too long URL\n");
            return MK_E_SYNTAX;
        }
705

706
        memcpy(file_part, pwzUrl + ARRAY_SIZE(wszRes), len*sizeof(WCHAR));
707 708
        file_part[len] = 0;

709
        len = SearchPathW(NULL, file_part, NULL, ARRAY_SIZE(full_path), full_path, NULL);
710
        if(!len) {
711 712 713 714 715 716 717 718 719 720
            HMODULE module;

            /* SearchPath does not work well with winelib files (like our test executable),
             * so we also try to load the library here */
            module = LoadLibraryExW(file_part, NULL, LOAD_LIBRARY_AS_DATAFILE);
            if(!module) {
                WARN("Could not find file %s\n", debugstr_w(file_part));
                return MK_E_SYNTAX;
            }

721
            len = GetModuleFileNameW(module, full_path, ARRAY_SIZE(full_path));
722 723 724
            FreeLibrary(module);
            if(!len)
                return E_FAIL;
725
        }
726

727
        size = ARRAY_SIZE(wszFile) + len + 1;
728 729
        if(pcchResult)
            *pcchResult = size;
730
        if(size > cchResult)
731 732 733
            return S_FALSE;

        memcpy(pwzResult, wszFile, sizeof(wszFile));
734
        memcpy(pwzResult + ARRAY_SIZE(wszFile), full_path, (len+1)*sizeof(WCHAR));
735 736 737 738
        return S_OK;
    }

    if(ParseAction == PARSE_DOMAIN) {
739 740 741 742
        if(!pcchResult)
            return E_POINTER;

        if(pwzUrl)
743
            *pcchResult = lstrlenW(pwzUrl)+1;
744 745 746
        else
            *pcchResult = 1;
        return E_FAIL;
747 748 749
    }

    return INET_E_DEFAULT_ACTION;
750 751 752 753 754 755
}

static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
        QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
        DWORD dwReserved)
{
756 757 758 759 760 761 762 763 764 765 766 767 768 769
    TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
          cbBuffer, pcbBuf, dwReserved);

    switch(QueryOption) {
    case QUERY_USES_NETWORK:
        if(!pBuffer || cbBuffer < sizeof(DWORD))
            return E_FAIL;

        *(DWORD*)pBuffer = 0;
        if(pcbBuf)
            *pcbBuf = sizeof(DWORD);
        break;

    case QUERY_IS_SECURE:
770
        FIXME("QUERY_IS_SECURE not supported\n");
771 772
        return E_NOTIMPL;
    case QUERY_IS_SAFE:
773
        FIXME("QUERY_IS_SAFE not supported\n");
774 775 776 777 778 779
        return E_NOTIMPL;
    default:
        return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
    }

    return S_OK;
780 781 782 783 784 785 786
}

static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = {
    InternetProtocolInfo_QueryInterface,
    InternetProtocolInfo_AddRef,
    InternetProtocolInfo_Release,
    ResProtocolInfo_ParseUrl,
787
    InternetProtocolInfo_CombineUrl,
788
    InternetProtocolInfo_CompareUrl,
789 790 791 792 793 794 795 796 797 798 799 800
    ResProtocolInfo_QueryInfo
};

static const IClassFactoryVtbl ResProtocolFactoryVtbl = {
    ClassFactory_QueryInterface,
    ClassFactory_AddRef,
    ClassFactory_Release,
    ResProtocolFactory_CreateInstance,
    ClassFactory_LockServer
};

static ProtocolFactory ResProtocolFactory = {
801 802
    { &ResProtocolInfoVtbl },
    { &ResProtocolFactoryVtbl }
803 804
};

805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
/********************************************************************
 * JSProtocol implementation
 */

static HRESULT WINAPI JSProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
        REFIID riid, void **ppv)
{
    FIXME("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
    return E_NOTIMPL;
}

static HRESULT WINAPI JSProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
        PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
        DWORD* pcchResult, DWORD dwReserved)
{
820
    TRACE("%p)->(%s %d %x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction,
821
          dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
822 823 824 825 826 827 828 829 830 831 832 833 834

    switch(ParseAction) {
    case PARSE_SECURITY_URL:
        FIXME("PARSE_SECURITY_URL\n");
        return E_NOTIMPL;
    case PARSE_DOMAIN:
        FIXME("PARSE_DOMAIN\n");
        return E_NOTIMPL;
    default:
        return INET_E_DEFAULT_ACTION;
    }

    return S_OK;
835 836 837 838 839 840
}

static HRESULT WINAPI JSProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
        QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
        DWORD dwReserved)
{
841
    TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
842
          cbBuffer, pcbBuf, dwReserved);
843 844 845 846 847 848 849 850 851 852 853 854

    switch(QueryOption) {
    case QUERY_USES_NETWORK:
        if(!pBuffer || cbBuffer < sizeof(DWORD))
            return E_FAIL;

        *(DWORD*)pBuffer = 0;
        if(pcbBuf)
            *pcbBuf = sizeof(DWORD);
        break;

    case QUERY_IS_SECURE:
855
        FIXME("QUERY_IS_SECURE not supported\n");
856 857 858 859 860 861 862
        return E_NOTIMPL;

    default:
        return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
    }

    return S_OK;
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
}

static const IInternetProtocolInfoVtbl JSProtocolInfoVtbl = {
    InternetProtocolInfo_QueryInterface,
    InternetProtocolInfo_AddRef,
    InternetProtocolInfo_Release,
    JSProtocolInfo_ParseUrl,
    InternetProtocolInfo_CombineUrl,
    InternetProtocolInfo_CompareUrl,
    JSProtocolInfo_QueryInfo
};

static const IClassFactoryVtbl JSProtocolFactoryVtbl = {
    ClassFactory_QueryInterface,
    ClassFactory_AddRef,
    ClassFactory_Release,
    JSProtocolFactory_CreateInstance,
    ClassFactory_LockServer
};

static ProtocolFactory JSProtocolFactory = {
884 885
    { &JSProtocolInfoVtbl },
    { &JSProtocolFactoryVtbl }
886 887
};

888 889 890 891 892 893 894 895
HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv)
{
    ProtocolFactory *cf = NULL;

    if(IsEqualGUID(&CLSID_AboutProtocol, rclsid))
        cf = &AboutProtocolFactory;
    else if(IsEqualGUID(&CLSID_ResProtocol, rclsid))
        cf = &ResProtocolFactory;
896 897
    else if(IsEqualGUID(&CLSID_JSProtocol, rclsid))
        cf = &JSProtocolFactory;
898 899 900 901 902

    if(!cf) {
        FIXME("not implemented protocol %s\n", debugstr_guid(rclsid));
        return CLASS_E_CLASSNOTAVAILABLE;
    }
903
 
904
    return IInternetProtocolInfo_QueryInterface(&cf->IInternetProtocolInfo_iface, riid, ppv);
905
}