protocol.c 28.2 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
 */

#include "config.h"

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

#define COBJMACROS

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

#include "wine/debug.h"
Jacek Caban's avatar
Jacek Caban committed
32
#include "wine/unicode.h"
33 34 35 36 37 38 39 40 41

#include "mshtml_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(mshtml);

/********************************************************************
 * common ProtocolFactory implementation
 */

42
#define CLASSFACTORY(x) (&(x)->lpClassFactoryVtbl)
43
#define PROTOCOL(x)     ((IInternetProtocol*)     &(x)->lpInternetProtocolVtbl)
44
#define PROTOCOLINFO(x) ((IInternetProtocolInfo*) &(x)->lpInternetProtocolInfoVtbl)
45 46 47 48 49 50

typedef struct {
    const IInternetProtocolInfoVtbl *lpInternetProtocolInfoVtbl;
    const IClassFactoryVtbl         *lpClassFactoryVtbl;
} ProtocolFactory;

51
#define PROTOCOLINFO_THIS(iface) DEFINE_THIS(ProtocolFactory, InternetProtocolInfo, iface)
52 53 54

static HRESULT WINAPI InternetProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
{
Jacek Caban's avatar
Jacek Caban committed
55
    ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

    *ppv = NULL;
    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
        *ppv = PROTOCOLINFO(This);
    }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
        TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv);
        *ppv = PROTOCOLINFO(This);
    }else if(IsEqualGUID(&IID_IClassFactory, riid)) {
        TRACE("(%p)->(IID_IClassFactory %p)\n", This, ppv);
        *ppv = CLASSFACTORY(This);
    }

    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)
{
80
    TRACE("(%p)\n", iface);
81 82 83 84 85
    return 2;
}

static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface)
{
86
    TRACE("(%p)\n", iface);
87 88 89
    return 1;
}

90 91 92 93
static HRESULT WINAPI InternetProtocolInfo_CombineUrl(IInternetProtocolInfo *iface,
        LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult,
        DWORD cchResult, DWORD* pcchResult, DWORD dwReserved)
{
94
    TRACE("%p)->(%s %s %08x %p %d %p %d)\n", iface, debugstr_w(pwzBaseUrl),
95 96 97 98 99 100
            debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult,
            pcchResult, dwReserved);

    return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
}

101 102 103 104 105 106 107
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;
}

Jacek Caban's avatar
Jacek Caban committed
108 109
#undef PROTOCOLINFO_THIS

110
#define CLASSFACTORY_THIS(iface) DEFINE_THIS(ProtocolFactory, ClassFactory, iface)
111 112 113

static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
{
Jacek Caban's avatar
Jacek Caban committed
114
    ProtocolFactory *This = CLASSFACTORY_THIS(iface);
115 116 117 118 119
    return IInternetProtocolInfo_QueryInterface(PROTOCOLINFO(This), riid, ppv);
}

static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
{
Jacek Caban's avatar
Jacek Caban committed
120
    ProtocolFactory *This = CLASSFACTORY_THIS(iface);
121 122 123 124 125
    return IInternetProtocolInfo_AddRef(PROTOCOLINFO(This));
}

static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
{
Jacek Caban's avatar
Jacek Caban committed
126
    ProtocolFactory *This = CLASSFACTORY_THIS(iface);
127 128 129 130 131
    return IInternetProtocolInfo_Release(PROTOCOLINFO(This));
}

static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
{
132
    TRACE("(%p)->(%x)\n", iface, dolock);
133 134 135
    return S_OK;
}

Jacek Caban's avatar
Jacek Caban committed
136 137
#undef CLASSFACTORY_THIS

138 139 140 141 142 143
/********************************************************************
 * AboutProtocol implementation
 */

typedef struct {
    const IInternetProtocolVtbl *lpInternetProtocolVtbl;
144

145
    LONG ref;
146 147 148 149

    BYTE *data;
    ULONG data_len;
    ULONG cur;
150 151

    IUnknown *pUnkOuter;
152 153
} AboutProtocol;

154 155
#define PROTOCOL_THIS(iface) DEFINE_THIS(AboutProtocol, InternetProtocol, iface)

156 157
static HRESULT WINAPI AboutProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
{
158
    AboutProtocol *This = PROTOCOL_THIS(iface);
159

160 161 162 163
    *ppv = NULL;

    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
164 165 166
        if(This->pUnkOuter)
            return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
        *ppv = PROTOCOL(This);
167 168
    }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
        TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
169
        *ppv = PROTOCOL(This);
170 171
    }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
        TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
172
        *ppv = PROTOCOL(This);
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
        FIXME("IServiceProvider is not implemented\n");
        return E_NOINTERFACE;
    }

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

    IInternetProtocol_AddRef(iface);
    return S_OK;
}

static ULONG WINAPI AboutProtocol_AddRef(IInternetProtocol *iface)
{
189
    AboutProtocol *This = PROTOCOL_THIS(iface);
190
    ULONG ref = InterlockedIncrement(&This->ref);
191
    TRACE("(%p) ref=%d\n", iface, ref);
192
    return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
193 194 195 196
}

static ULONG WINAPI AboutProtocol_Release(IInternetProtocol *iface)
{
197 198
    AboutProtocol *This = PROTOCOL_THIS(iface);
    IUnknown *pUnkOuter = This->pUnkOuter;
199 200
    ULONG ref = InterlockedDecrement(&This->ref);

201
    TRACE("(%p) ref=%x\n", iface, ref);
202

203
    if(!ref) {
204 205
        heap_free(This->data);
        heap_free(This);
206
    }
207

208
    return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
209 210 211 212
}

static HRESULT WINAPI AboutProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
        IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
213
        DWORD grfPI, HANDLE_PTR dwReserved)
214
{
215
    AboutProtocol *This = PROTOCOL_THIS(iface);
216 217 218 219 220 221 222 223
    BINDINFO bindinfo;
    DWORD grfBINDF = 0;
    LPCWSTR text = NULL;

    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',':'};
224
    static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
225 226 227 228 229 230 231 232

    /* 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.
     */

233
    TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
234
            pOIBindInfo, grfPI, dwReserved);
235 236 237 238

    memset(&bindinfo, 0, sizeof(bindinfo));
    bindinfo.cbSize = sizeof(BINDINFO);
    IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
239
    ReleaseBindInfo(&bindinfo);
240

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

243 244 245 246 247 248 249 250
    if(strlenW(szUrl)>=sizeof(wszAbout)/sizeof(WCHAR) && !memcmp(wszAbout, szUrl, sizeof(wszAbout))) {
        text = szUrl + sizeof(wszAbout)/sizeof(WCHAR);
        if(!strcmpW(wszBlank, text))
            text = NULL;
    }

    This->data_len = sizeof(html_begin)+sizeof(html_end)-sizeof(WCHAR) 
        + (text ? strlenW(text)*sizeof(WCHAR) : 0);
251
    This->data = heap_alloc(This->data_len);
252 253 254 255 256 257 258 259

    memcpy(This->data, html_begin, sizeof(html_begin));
    if(text)
        strcatW((LPWSTR)This->data, text);
    strcatW((LPWSTR)This->data, html_end);
    
    This->cur = 0;

260 261
    IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);

262 263 264 265 266 267 268
    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;
269 270 271 272
}

static HRESULT WINAPI AboutProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
{
273
    AboutProtocol *This = PROTOCOL_THIS(iface);
274 275 276 277 278 279 280
    FIXME("(%p)->(%p)\n", This, pProtocolData);
    return E_NOTIMPL;
}

static HRESULT WINAPI AboutProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
        DWORD dwOptions)
{
281
    AboutProtocol *This = PROTOCOL_THIS(iface);
282
    FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
283 284 285 286 287
    return E_NOTIMPL;
}

static HRESULT WINAPI AboutProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
{
288
    AboutProtocol *This = PROTOCOL_THIS(iface);
289
    TRACE("(%p)->(%08x)\n", This, dwOptions);
290
    return S_OK;
291 292 293 294
}

static HRESULT WINAPI AboutProtocol_Suspend(IInternetProtocol *iface)
{
295
    AboutProtocol *This = PROTOCOL_THIS(iface);
296 297 298 299 300 301
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

static HRESULT WINAPI AboutProtocol_Resume(IInternetProtocol *iface)
{
302
    AboutProtocol *This = PROTOCOL_THIS(iface);
303 304 305 306 307 308
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

static HRESULT WINAPI AboutProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
{
309
    AboutProtocol *This = PROTOCOL_THIS(iface);
310

311
    TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
312 313 314 315 316 317 318 319 320

    if(!This->data)
        return E_FAIL;

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

    if(!*pcbRead)
        return S_FALSE;

321
    memcpy(pv, This->data+This->cur, *pcbRead);
322 323 324
    This->cur += *pcbRead;

    return S_OK;
325 326 327 328 329
}

static HRESULT WINAPI AboutProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
        DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
{
330
    AboutProtocol *This = PROTOCOL_THIS(iface);
331
    FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
332 333 334 335 336
    return E_NOTIMPL;
}

static HRESULT WINAPI AboutProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
{
337
    AboutProtocol *This = PROTOCOL_THIS(iface);
338

339
    TRACE("(%p)->(%d)\n", This, dwOptions);
340 341

    return S_OK;
342 343 344 345
}

static HRESULT WINAPI AboutProtocol_UnlockRequest(IInternetProtocol *iface)
{
346
    AboutProtocol *This = PROTOCOL_THIS(iface);
347 348 349 350

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

    return S_OK;
351 352
}

353 354
#undef PROTOCOL_THIS

355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
static const IInternetProtocolVtbl AboutProtocolVtbl = {
    AboutProtocol_QueryInterface,
    AboutProtocol_AddRef,
    AboutProtocol_Release,
    AboutProtocol_Start,
    AboutProtocol_Continue,
    AboutProtocol_Abort,
    AboutProtocol_Terminate,
    AboutProtocol_Suspend,
    AboutProtocol_Resume,
    AboutProtocol_Read,
    AboutProtocol_Seek,
    AboutProtocol_LockRequest,
    AboutProtocol_UnlockRequest
};

static HRESULT WINAPI AboutProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
        REFIID riid, void **ppv)
{
    AboutProtocol *ret;
375
    HRESULT hres = S_OK;
376

377
    TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
378

379
    ret = heap_alloc(sizeof(AboutProtocol));
380 381 382
    ret->lpInternetProtocolVtbl = &AboutProtocolVtbl;
    ret->ref = 0;

383 384 385
    ret->data = NULL;
    ret->data_len = 0;
    ret->cur = 0;
386 387 388 389 390 391 392 393 394 395 396
    ret->pUnkOuter = pUnkOuter;

    if(pUnkOuter) {
        ret->ref = 1;
        if(IsEqualGUID(&IID_IUnknown, riid))
            *ppv = PROTOCOL(ret);
        else
            hres = E_INVALIDARG;
    }else {
        hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
    }
397

398
    if(FAILED(hres))
399
        heap_free(ret);
400 401 402 403 404 405 406 407

    return hres;
}

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

    if(ParseAction == PARSE_SECURITY_URL) {
412
        unsigned int len = strlenW(pwzUrl);
413 414 415 416 417 418 419 420 421

        if(len >= cchResult)
            return S_FALSE;

        memcpy(pwzResult, pwzUrl, (len+1)*sizeof(WCHAR));
        return S_OK;
    }

    if(ParseAction == PARSE_DOMAIN) {
422 423 424 425 426 427 428 429
        if(!pcchResult)
            return E_POINTER;

        if(pwzUrl)
            *pcchResult = strlenW(pwzUrl)+1;
        else
            *pcchResult = 1;
        return E_FAIL;
430 431 432
    }

    return INET_E_DEFAULT_ACTION;
433 434 435 436 437 438
}

static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
        QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
        DWORD dwReserved)
{
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
    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;
471 472 473
    case QUERY_USES_HISTORYFOLDER:
        FIXME("Unsupported option QUERY_USES_HISTORYFOLDER\n");
        return E_FAIL;
474 475 476 477 478
    default:
        return E_FAIL;
    }

    return S_OK;
479 480 481 482 483 484 485
}

static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = {
    InternetProtocolInfo_QueryInterface,
    InternetProtocolInfo_AddRef,
    InternetProtocolInfo_Release,
    AboutProtocolInfo_ParseUrl,
486
    InternetProtocolInfo_CombineUrl,
487
    InternetProtocolInfo_CompareUrl,
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
    AboutProtocolInfo_QueryInfo
};

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

static ProtocolFactory AboutProtocolFactory = {
    &AboutProtocolInfoVtbl,
    &AboutProtocolFactoryVtbl
};

/********************************************************************
 * ResProtocol implementation
 */

typedef struct {
    const IInternetProtocolVtbl *lpInternetProtocolVtbl;
510
    LONG ref;
Jacek Caban's avatar
Jacek Caban committed
511 512 513 514

    BYTE *data;
    ULONG data_len;
    ULONG cur;
515 516

    IUnknown *pUnkOuter;
517 518
} ResProtocol;

519 520
#define PROTOCOL_THIS(iface) DEFINE_THIS(ResProtocol, InternetProtocol, iface)

521 522
static HRESULT WINAPI ResProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
{
523 524
    ResProtocol *This = PROTOCOL_THIS(iface);

525 526 527 528
    *ppv = NULL;

    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
529 530 531
        if(This->pUnkOuter)
            return IUnknown_QueryInterface(This->pUnkOuter, &IID_IUnknown, ppv);
        *ppv = PROTOCOL(This);
532 533
    }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
        TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
534
        *ppv = PROTOCOL(This);
535 536
    }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
        TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
537
        *ppv = PROTOCOL(This);
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
    }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
        FIXME("IServiceProvider is not implemented\n");
        return E_NOINTERFACE;
    }

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

    IInternetProtocol_AddRef(iface);
    return S_OK;
}

static ULONG WINAPI ResProtocol_AddRef(IInternetProtocol *iface)
{
554
    ResProtocol *This = PROTOCOL_THIS(iface);
555
    ULONG ref = InterlockedIncrement(&This->ref);
556
    TRACE("(%p) ref=%d\n", iface, ref);
557
    return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
558 559 560 561 562
}

static ULONG WINAPI ResProtocol_Release(IInternetProtocol *iface)
{
    ResProtocol *This = (ResProtocol*)iface;
563
    IUnknown *pUnkOuter = This->pUnkOuter;
564 565
    ULONG ref = InterlockedDecrement(&This->ref);

566
    TRACE("(%p) ref=%x\n", iface, ref);
567

Jacek Caban's avatar
Jacek Caban committed
568
    if(!ref) {
569 570
        heap_free(This->data);
        heap_free(This);
Jacek Caban's avatar
Jacek Caban committed
571
    }
572

573
    return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
574 575 576 577
}

static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
        IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
578
        DWORD grfPI, HANDLE_PTR dwReserved)
579
{
580
    ResProtocol *This = PROTOCOL_THIS(iface);
581
    DWORD grfBINDF = 0, len;
Jacek Caban's avatar
Jacek Caban committed
582
    BINDINFO bindinfo;
583
    LPWSTR url_dll, url_file, url, mime, res_type = (LPWSTR)RT_HTML;
Jacek Caban's avatar
Jacek Caban committed
584 585
    HMODULE hdll;
    HRSRC src;
586
    HRESULT hres;
Jacek Caban's avatar
Jacek Caban committed
587 588 589

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

590
    TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
591
            pOIBindInfo, grfPI, dwReserved);
Jacek Caban's avatar
Jacek Caban committed
592 593 594 595

    memset(&bindinfo, 0, sizeof(bindinfo));
    bindinfo.cbSize = sizeof(BINDINFO);
    IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
596
    ReleaseBindInfo(&bindinfo);
Jacek Caban's avatar
Jacek Caban committed
597

598
    len = strlenW(szUrl)+16;
599
    url = heap_alloc(len*sizeof(WCHAR));
600 601
    hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0);
    if(FAILED(hres)) {
602
        WARN("CoInternetParseUrl failed: %08x\n", hres);
603
        heap_free(url);
604 605 606 607 608 609
        IInternetProtocolSink_ReportResult(pOIProtSink, hres, 0, NULL);
        return hres;
    }

    if(len < sizeof(wszRes)/sizeof(wszRes[0]) || memcmp(url, wszRes, sizeof(wszRes))) {
        WARN("Wrong protocol of url: %s\n", debugstr_w(url));
610
        IInternetProtocolSink_ReportResult(pOIProtSink, E_INVALIDARG, 0, NULL);
611
        heap_free(url);
612
        return E_INVALIDARG;
Jacek Caban's avatar
Jacek Caban committed
613 614
    }

615
    url_dll = url + sizeof(wszRes)/sizeof(wszRes[0]);
616
    if(!(url_file = strrchrW(url_dll, '/'))) {
617
        WARN("wrong url: %s\n", debugstr_w(url));
Jacek Caban's avatar
Jacek Caban committed
618
        IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
619
        heap_free(url);
Jacek Caban's avatar
Jacek Caban committed
620 621 622
        return MK_E_SYNTAX;
    }

623 624
    *url_file++ = 0;
    hdll = LoadLibraryExW(url_dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
Jacek Caban's avatar
Jacek Caban committed
625
    if(!hdll) {
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
        if (!(res_type = strrchrW(url_dll, '/'))) {
            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());
        }
        *res_type++ = 0;

        hdll = LoadLibraryExW(url_dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
        if(!hdll) {
            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
641 642
    }

643 644 645
    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
646
    if(!src) {
647 648 649
        LPWSTR endpoint = NULL;
        DWORD file_id = strtolW(url_file, &endpoint, 10);
        if(endpoint == url_file+strlenW(url_file))
650
            src = FindResourceW(hdll, MAKEINTRESOURCEW(file_id), MAKEINTRESOURCEW(RT_HTML));
651 652 653 654 655

        if(!src) {
            WARN("Could not find resource\n");
            IInternetProtocolSink_ReportResult(pOIProtSink,
                    HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
656
            heap_free(url);
657 658
            return HRESULT_FROM_WIN32(GetLastError());
        }
Jacek Caban's avatar
Jacek Caban committed
659 660 661 662
    }

    if(This->data) {
        WARN("data already loaded\n");
663
        heap_free(This->data);
Jacek Caban's avatar
Jacek Caban committed
664 665 666
    }

    This->data_len = SizeofResource(hdll, src);
667
    This->data = heap_alloc(This->data_len);
Jacek Caban's avatar
Jacek Caban committed
668 669 670 671 672
    memcpy(This->data, LoadResource(hdll, src), This->data_len);
    This->cur = 0;

    FreeLibrary(hdll);

673
    hres = FindMimeFromData(NULL, url_file, NULL, 0, NULL, 0, &mime, 0);
674
    heap_free(url);
675 676 677 678 679
    if(SUCCEEDED(hres)) {
        IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
        CoTaskMemFree(mime);
    }

Jacek Caban's avatar
Jacek Caban committed
680 681 682 683 684 685 686
    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;
687 688 689 690
}

static HRESULT WINAPI ResProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
{
691
    ResProtocol *This = PROTOCOL_THIS(iface);
692 693 694 695 696 697 698
    FIXME("(%p)->(%p)\n", This, pProtocolData);
    return E_NOTIMPL;
}

static HRESULT WINAPI ResProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
        DWORD dwOptions)
{
699
    ResProtocol *This = PROTOCOL_THIS(iface);
700
    FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
701 702 703 704 705
    return E_NOTIMPL;
}

static HRESULT WINAPI ResProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
{
706
    ResProtocol *This = PROTOCOL_THIS(iface);
Jacek Caban's avatar
Jacek Caban committed
707

708
    TRACE("(%p)->(%08x)\n", This, dwOptions);
Jacek Caban's avatar
Jacek Caban committed
709 710 711

    /* test show that we don't have to do anything here */
    return S_OK;
712 713 714 715
}

static HRESULT WINAPI ResProtocol_Suspend(IInternetProtocol *iface)
{
716
    ResProtocol *This = PROTOCOL_THIS(iface);
717 718 719 720 721 722
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

static HRESULT WINAPI ResProtocol_Resume(IInternetProtocol *iface)
{
723
    ResProtocol *This = PROTOCOL_THIS(iface);
724 725 726 727 728 729
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

static HRESULT WINAPI ResProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
{
730
    ResProtocol *This = PROTOCOL_THIS(iface);
Jacek Caban's avatar
Jacek Caban committed
731

732
    TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
Jacek Caban's avatar
Jacek Caban committed
733 734 735 736 737 738 739 740 741

    if(!This->data)
        return E_FAIL;

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

    if(!*pcbRead)
        return S_FALSE;

742
    memcpy(pv, This->data+This->cur, *pcbRead);
Jacek Caban's avatar
Jacek Caban committed
743 744 745
    This->cur += *pcbRead;

    return S_OK;
746 747 748 749 750
}

static HRESULT WINAPI ResProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
        DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
{
751
    ResProtocol *This = PROTOCOL_THIS(iface);
752
    FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
753 754 755 756 757
    return E_NOTIMPL;
}

static HRESULT WINAPI ResProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
{
758
    ResProtocol *This = PROTOCOL_THIS(iface);
Jacek Caban's avatar
Jacek Caban committed
759

760
    TRACE("(%p)->(%d)\n", This, dwOptions);
Jacek Caban's avatar
Jacek Caban committed
761 762 763

    /* test show that we don't have to do anything here */
    return S_OK;
764 765 766 767
}

static HRESULT WINAPI ResProtocol_UnlockRequest(IInternetProtocol *iface)
{
768
    ResProtocol *This = PROTOCOL_THIS(iface);
Jacek Caban's avatar
Jacek Caban committed
769 770 771 772 773

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

    /* test show that we don't have to do anything here */
    return S_OK;
774 775
}

776 777
#undef PROTOCOL_THIS

778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
static const IInternetProtocolVtbl ResProtocolVtbl = {
    ResProtocol_QueryInterface,
    ResProtocol_AddRef,
    ResProtocol_Release,
    ResProtocol_Start,
    ResProtocol_Continue,
    ResProtocol_Abort,
    ResProtocol_Terminate,
    ResProtocol_Suspend,
    ResProtocol_Resume,
    ResProtocol_Read,
    ResProtocol_Seek,
    ResProtocol_LockRequest,
    ResProtocol_UnlockRequest
};

static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
        REFIID riid, void **ppv)
{
    ResProtocol *ret;
798
    HRESULT hres = S_OK;
799

800
    TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
801

802
    ret = heap_alloc(sizeof(ResProtocol));
803 804
    ret->lpInternetProtocolVtbl = &ResProtocolVtbl;
    ret->ref = 0;
Jacek Caban's avatar
Jacek Caban committed
805 806 807
    ret->data = NULL;
    ret->data_len = 0;
    ret->cur = 0;
808
    ret->pUnkOuter = pUnkOuter;
809

810 811 812 813 814 815 816 817 818
    if(pUnkOuter) {
        ret->ref = 1;
        if(IsEqualGUID(&IID_IUnknown, riid))
            *ppv = PROTOCOL(ret);
        else
            hres = E_FAIL;
    }else {
        hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
    }
819

820
    if(FAILED(hres))
821
        heap_free(ret);
822 823 824 825 826 827 828 829

    return hres;
}

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

    if(ParseAction == PARSE_SECURITY_URL) {
834
        WCHAR file_part[MAX_PATH], full_path[MAX_PATH];
835
        WCHAR *ptr;
836
        DWORD size, len;
837 838 839 840 841

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

        if(strlenW(pwzUrl) <= sizeof(wszRes)/sizeof(WCHAR) || memcmp(pwzUrl, wszRes, sizeof(wszRes)))
842
            return E_INVALIDARG;
843 844 845

        ptr = strchrW(pwzUrl + sizeof(wszRes)/sizeof(WCHAR), '/');
        if(!ptr)
846
            return E_INVALIDARG;
847

848
        len = ptr - (pwzUrl + sizeof(wszRes)/sizeof(WCHAR));
849
        if(len >= sizeof(file_part)/sizeof(WCHAR)) {
850 851 852
            FIXME("Too long URL\n");
            return MK_E_SYNTAX;
        }
853

854 855 856 857 858 859 860 861
        memcpy(file_part, pwzUrl + sizeof(wszRes)/sizeof(WCHAR), len*sizeof(WCHAR));
        file_part[len] = 0;

        len = SearchPathW(NULL, file_part, NULL, sizeof(full_path)/sizeof(WCHAR), full_path, NULL);
        if(!len) {
            WARN("Could not find file %s\n", debugstr_w(file_part));
            return MK_E_SYNTAX;
        }
862

863
        size = sizeof(wszFile)/sizeof(WCHAR) + len + 1;
864 865
        if(pcchResult)
            *pcchResult = size;
866 867 868 869 870
        if(size >= cchResult)
            return S_FALSE;

        memcpy(pwzResult, wszFile, sizeof(wszFile));
        memcpy(pwzResult + sizeof(wszFile)/sizeof(WCHAR), full_path, (len+1)*sizeof(WCHAR));
871 872 873 874
        return S_OK;
    }

    if(ParseAction == PARSE_DOMAIN) {
875 876 877 878 879 880 881 882
        if(!pcchResult)
            return E_POINTER;

        if(pwzUrl)
            *pcchResult = strlenW(pwzUrl)+1;
        else
            *pcchResult = 1;
        return E_FAIL;
883 884 885
    }

    return INET_E_DEFAULT_ACTION;
886 887 888 889 890 891
}

static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
        QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
        DWORD dwReserved)
{
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
    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:
        FIXME("not supporte QUERY_IS_SECURE\n");
        return E_NOTIMPL;
    case QUERY_IS_SAFE:
        FIXME("not supporte QUERY_IS_SAFE\n");
        return E_NOTIMPL;
    default:
        return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
    }

    return S_OK;
916 917 918 919 920 921 922
}

static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = {
    InternetProtocolInfo_QueryInterface,
    InternetProtocolInfo_AddRef,
    InternetProtocolInfo_Release,
    ResProtocolInfo_ParseUrl,
923
    InternetProtocolInfo_CombineUrl,
924
    InternetProtocolInfo_CompareUrl,
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
    ResProtocolInfo_QueryInfo
};

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

static ProtocolFactory ResProtocolFactory = {
    &ResProtocolInfoVtbl,
    &ResProtocolFactoryVtbl
};

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;

    if(!cf) {
        FIXME("not implemented protocol %s\n", debugstr_guid(rclsid));
        return CLASS_E_CLASSNOTAVAILABLE;
    }
954
 
955 956
    return IUnknown_QueryInterface((IUnknown*)cf, riid, ppv);
}