persist.c 23 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
 */

#include "config.h"

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

#define COBJMACROS
25 26
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
27 28 29 30 31

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"
32
#include "shlguid.h"
33
#include "idispids.h"
34 35

#include "wine/debug.h"
36
#include "wine/unicode.h"
37 38 39 40 41

#include "mshtml_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(mshtml);

42 43 44 45 46
#define USER_AGENT "User-Agent:"
#define CONTENT_TYPE "Content-Type:"

static int fix_headers(char *buf, DWORD post_len)
{
47
    char *ptr = buf, *ptr2;
48

49 50
    while(*ptr && (ptr[0] != '\r' || ptr[1] != '\n')) {
        for(ptr2=ptr+1; *ptr2 && (ptr2[0] != '\r' || ptr2[1] != '\n'); ptr2++);
51

52 53
        if(*ptr2)
            ptr2 += 2;
54

55 56
        if(!strncasecmp(ptr, USER_AGENT, sizeof(USER_AGENT)-1)) {
            FIXME("Ignoring User-Agent header\n");
57
            memmove(ptr, ptr2, strlen(ptr2)+1);
58
        }else if(!post_len && !strncasecmp(ptr, CONTENT_TYPE, sizeof(CONTENT_TYPE)-1)) {
59
            TRACE("Ignoring Content-Type header\n");
60 61 62
            memmove(ptr, ptr2, strlen(ptr2)+1);
        }else {
            ptr = ptr2;
63 64 65
        }
    }

66 67
    *ptr = 0;
    return ptr-buf;
68 69
}

70 71 72
static nsIInputStream *get_post_data_stream(IBindCtx *bctx)
{
    nsIInputStream *ret = NULL;
73
    IUnknown *unk;
74
    IBindStatusCallback *callback;
75
    IServiceProvider *service_provider;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
    BINDINFO bindinfo;
    DWORD bindf = 0;
    DWORD post_len = 0, headers_len = 0;
    LPWSTR headers = NULL;
    WCHAR emptystr[] = {0};
    char *data;
    HRESULT hres;

    static WCHAR _BSCB_Holder_[] =
        {'_','B','S','C','B','_','H','o','l','d','e','r','_',0};


    /* FIXME: This should be done in URLMoniker */
    if(!bctx)
        return NULL;

92
    hres = IBindCtx_GetObjectParam(bctx, _BSCB_Holder_, &unk);
93 94 95
    if(FAILED(hres))
        return NULL;

96 97 98 99 100 101 102 103
    hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)&callback);
    if(FAILED(hres)) {
        IUnknown_Release(unk);
        return NULL;
    }

    hres = IUnknown_QueryInterface(unk, &IID_IServiceProvider, (void**)&service_provider);
    IUnknown_Release(unk);
104
    if(SUCCEEDED(hres)) {
105 106 107 108 109 110 111 112 113 114 115 116
        IHttpNegotiate *http_negotiate;

        hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate, &IID_IHttpNegotiate,
                                             (void**)&http_negotiate);
        if(SUCCEEDED(hres)) {
            hres = IHttpNegotiate_BeginningTransaction(http_negotiate, emptystr,
                                                       emptystr, 0, &headers);
            IHttpNegotiate_Release(http_negotiate);

            if(SUCCEEDED(hres) && headers)
                headers_len = WideCharToMultiByte(CP_ACP, 0, headers, -1, NULL, 0, NULL, NULL);
        }
117

118
        IServiceProvider_Release(service_provider);
119 120 121 122 123 124 125 126
    }

    memset(&bindinfo, 0, sizeof(bindinfo));
    bindinfo.cbSize = sizeof(bindinfo);

    hres = IBindStatusCallback_GetBindInfo(callback, &bindf, &bindinfo);

    if(SUCCEEDED(hres) && bindinfo.dwBindVerb == BINDVERB_POST)
127
        post_len = bindinfo.cbstgmedData;
128 129

    if(headers_len || post_len) {
130
        int len = 0;
131

132
        static const char content_length[] = "Content-Length: %u\r\n\r\n";
133

134
        data = heap_alloc(headers_len+post_len+sizeof(content_length)+10);
135 136

        if(headers_len) {
137
            WideCharToMultiByte(CP_ACP, 0, headers, -1, data, headers_len, NULL, NULL);
138
            len = fix_headers(data, post_len);
139 140 141 142
            if(len >= 2 && (data[len-1] != '\n' || data[len-2] != '\r')) {
                data[len++] = '\r';
                data[len++] = '\n';
            }
143 144 145
        }

        if(post_len) {
146
            sprintf(data+len, content_length, post_len);
147
            len += strlen(data+len);
148 149 150 151 152 153

            memcpy(data+len, bindinfo.stgmedData.u.hGlobal, post_len);
        }

        TRACE("data = %s\n", debugstr_an(data, len+post_len));

154 155
        if(len)
            ret = create_nsstream(data, len+post_len);
156 157
    }

158
    CoTaskMemFree(headers);
159 160 161 162 163 164
    ReleaseBindInfo(&bindinfo);
    IBindStatusCallback_Release(callback);

    return ret;
}

165 166 167 168 169 170
static BOOL use_gecko_script(LPCWSTR url)
{
    static const WCHAR fileW[] = {'f','i','l','e',':'};
    return strncmpiW(fileW, url, sizeof(fileW)/sizeof(WCHAR));
}

171 172
void set_current_mon(HTMLDocument *This, IMoniker *mon)
{
173 174 175
    HRESULT hres;

    if(This->mon) {
176
        IMoniker_Release(This->mon);
177 178 179 180
        This->mon = NULL;
    }

    if(This->url) {
181
        CoTaskMemFree(This->url);
182 183 184 185 186 187 188
        This->url = NULL;
    }

    if(!mon)
        return;

    IMoniker_AddRef(mon);
189
    This->mon = mon;
190 191 192 193

    hres = IMoniker_GetDisplayName(mon, NULL, NULL, &This->url);
    if(FAILED(hres))
        WARN("GetDisplayName failed: %08x\n", hres);
194 195

    set_script_mode(This, use_gecko_script(This->url) ? SCRIPTMODE_GECKO : SCRIPTMODE_ACTIVESCRIPT);
196 197
}

198
static HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, BOOL *bind_complete)
199
{
200
    nsChannelBSC *bscallback;
201
    LPOLESTR url = NULL;
202
    task_t *task;
203 204 205
    HRESULT hres;
    nsresult nsres;

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    if(pibc) {
        IUnknown *unk = NULL;

        /* FIXME:
         * Use params:
         * "__PrecreatedObject"
         * "BIND_CONTEXT_PARAM"
         * "__HTMLLOADOPTIONS"
         * "__DWNBINDINFO"
         * "URL Context"
         * "CBinding Context"
         * "_ITransData_Object_"
         * "_EnumFORMATETC_"
         */

221
        IBindCtx_GetObjectParam(pibc, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM, &unk);
222 223 224 225 226 227 228 229 230 231 232 233 234
        if(unk) {
            IOleClientSite *client = NULL;

            hres = IUnknown_QueryInterface(unk, &IID_IOleClientSite, (void**)&client);
            if(SUCCEEDED(hres)) {
                TRACE("Got client site %p\n", client);
                IOleObject_SetClientSite(OLEOBJ(This), client);
                IOleClientSite_Release(client);
            }

            IUnknown_Release(unk);
        }
    }
235

236
    This->readystate = READYSTATE_LOADING;
237
    call_property_onchanged(&This->cp_propnotif, DISPID_READYSTATE);
238
    update_doc(This, UPDATE_TITLE);
239

240
    HTMLDocument_LockContainer(This, TRUE);
241
    
242
    hres = IMoniker_GetDisplayName(mon, pibc, NULL, &url);
243
    if(FAILED(hres)) {
244
        WARN("GetDiaplayName failed: %08x\n", hres);
245 246
        return hres;
    }
247

248 249
    TRACE("got url: %s\n", debugstr_w(url));

250 251
    set_current_mon(This, mon);

252 253
    if(This->client) {
        VARIANT silent, offline;
254
        IOleCommandTarget *cmdtrg = NULL;
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271

        hres = get_client_disp_property(This->client, DISPID_AMBIENT_SILENT, &silent);
        if(SUCCEEDED(hres)) {
            if(V_VT(&silent) != VT_BOOL)
                WARN("V_VT(silent) = %d\n", V_VT(&silent));
            else if(V_BOOL(&silent))
                FIXME("silent == true\n");
        }

        hres = get_client_disp_property(This->client,
                DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, &offline);
        if(SUCCEEDED(hres)) {
            if(V_VT(&silent) != VT_BOOL)
                WARN("V_VT(offline) = %d\n", V_VT(&silent));
            else if(V_BOOL(&silent))
                FIXME("offline == true\n");
        }
272 273 274 275 276 277 278 279 280 281 282 283

        hres = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
                (void**)&cmdtrg);
        if(SUCCEEDED(hres)) {
            VARIANT var;

            V_VT(&var) = VT_I4;
            V_I4(&var) = 0;
            IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);

            IOleCommandTarget_Release(cmdtrg);
        }
284 285
    }

286
    bscallback = create_channelbsc(mon);
287

288
    if(This->frame) {
289
        task = heap_alloc(sizeof(task_t));
290 291 292 293 294 295 296 297

        task->doc = This;
        task->task_id = TASK_SETPROGRESS;
        task->next = NULL;

        push_task(task);
    }

298
    task = heap_alloc(sizeof(task_t));
299 300 301 302 303 304 305

    task->doc = This;
    task->task_id = TASK_SETDOWNLOADSTATE;
    task->next = NULL;

    push_task(task);

306
    if(This->nscontainer) {
307
        nsIInputStream *post_data_stream = get_post_data_stream(pibc);
308

309
        This->nscontainer->bscallback = bscallback;
310
        nsres = nsIWebNavigation_LoadURI(This->nscontainer->navigation, url,
311
                LOAD_FLAGS_NONE, NULL, post_data_stream, NULL);
312
        This->nscontainer->bscallback = NULL;
313

314 315 316 317
        if(post_data_stream)
            nsIInputStream_Release(post_data_stream);

        if(NS_SUCCEEDED(nsres)) {
318 319
            /* FIXME: don't return here (URL Moniker needs to be good enough) */

320
            IUnknown_Release((IUnknown*)bscallback);
321
            CoTaskMemFree(url);
322 323 324

            if(bind_complete)
                *bind_complete = TRUE;
325
            return S_OK;
326
        }else if(nsres != WINE_NS_LOAD_FROM_MONIKER) {
327
            WARN("LoadURI failed: %08x\n", nsres);
328
        }
329
    }
330

331
    set_document_bscallback(This, bscallback);
332
    IUnknown_Release((IUnknown*)bscallback);
333 334
    CoTaskMemFree(url);

335 336
    if(bind_complete)
        *bind_complete = FALSE;
337 338 339 340 341 342 343 344 345 346
    return S_OK;
}

static HRESULT get_doc_string(HTMLDocument *This, char **str, DWORD *len)
{
    nsIDOMNode *nsnode;
    LPCWSTR strw;
    nsAString nsstr;
    nsresult nsres;

347 348 349
    if(!This->nsdoc) {
        WARN("NULL nsdoc\n");
        return E_UNEXPECTED;
350 351
    }

352
    nsres = nsIDOMHTMLDocument_QueryInterface(This->nsdoc, &IID_nsIDOMNode, (void**)&nsnode);
353 354 355 356 357 358 359 360 361
    if(NS_FAILED(nsres)) {
        ERR("Could not get nsIDOMNode failed: %08x\n", nsres);
        return E_FAIL;
    }

    nsAString_Init(&nsstr, NULL);
    nsnode_to_nsstring(nsnode, &nsstr);
    nsIDOMNode_Release(nsnode);

362
    nsAString_GetData(&nsstr, &strw);
363 364 365
    TRACE("%s\n", debugstr_w(strw));

    *len = WideCharToMultiByte(CP_ACP, 0, strw, -1, NULL, 0, NULL, NULL);
366
    *str = heap_alloc(*len);
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
    WideCharToMultiByte(CP_ACP, 0, strw, -1, *str, *len, NULL, NULL);

    nsAString_Finish(&nsstr);

    return S_OK;
}


/**********************************************************
 * IPersistMoniker implementation
 */

#define PERSISTMON_THIS(iface) DEFINE_THIS(HTMLDocument, PersistMoniker, iface)

static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid,
                                                            void **ppvObject)
{
    HTMLDocument *This = PERSISTMON_THIS(iface);
    return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
}

static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
{
    HTMLDocument *This = PERSISTMON_THIS(iface);
    return IHTMLDocument2_AddRef(HTMLDOC(This));
}

static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
{
    HTMLDocument *This = PERSISTMON_THIS(iface);
    return IHTMLDocument2_Release(HTMLDOC(This));
}

static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
{
    HTMLDocument *This = PERSISTMON_THIS(iface);
    return IPersist_GetClassID(PERSIST(This), pClassID);
}

static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
{
    HTMLDocument *This = PERSISTMON_THIS(iface);
409 410 411 412

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

    return IPersistStreamInit_IsDirty(PERSTRINIT(This));
413 414 415 416 417 418
}

static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
        IMoniker *pimkName, LPBC pibc, DWORD grfMode)
{
    HTMLDocument *This = PERSISTMON_THIS(iface);
419
    BOOL bind_complete = FALSE;
420 421 422 423
    HRESULT hres;

    TRACE("(%p)->(%x %p %p %08x)\n", This, fFullyAvailable, pimkName, pibc, grfMode);

424
    hres = set_moniker(This, pimkName, pibc, &bind_complete);
425 426 427
    if(FAILED(hres))
        return hres;

428
    if(!bind_complete)
429
        return start_binding(This, (BSCallback*)This->bscallback, pibc);
430 431

    return S_OK;
432 433 434 435 436
}

static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
        LPBC pbc, BOOL fRemember)
{
437 438
    HTMLDocument *This = PERSISTMON_THIS(iface);
    FIXME("(%p)->(%p %p %x)\n", This, pimkName, pbc, fRemember);
439 440 441 442 443
    return E_NOTIMPL;
}

static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
{
444 445
    HTMLDocument *This = PERSISTMON_THIS(iface);
    FIXME("(%p)->(%p %p)\n", This, pimkName, pibc);
446 447 448 449 450
    return E_NOTIMPL;
}

static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **ppimkName)
{
451
    HTMLDocument *This = PERSISTMON_THIS(iface);
452 453 454 455 456 457 458 459 460

    TRACE("(%p)->(%p)\n", This, ppimkName);

    if(!This->mon)
        return E_UNEXPECTED;

    IMoniker_AddRef(This->mon);
    *ppimkName = This->mon;
    return S_OK;
461 462
}

463
static const IPersistMonikerVtbl PersistMonikerVtbl = {
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
    PersistMoniker_QueryInterface,
    PersistMoniker_AddRef,
    PersistMoniker_Release,
    PersistMoniker_GetClassID,
    PersistMoniker_IsDirty,
    PersistMoniker_Load,
    PersistMoniker_Save,
    PersistMoniker_SaveCompleted,
    PersistMoniker_GetCurMoniker
};

/**********************************************************
 * IMonikerProp implementation
 */

479
#define MONPROP_THIS(iface) DEFINE_THIS(HTMLDocument, MonikerProp, iface)
480 481 482

static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppvObject)
{
483
    HTMLDocument *This = MONPROP_THIS(iface);
484 485 486 487 488
    return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
}

static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
{
489
    HTMLDocument *This = MONPROP_THIS(iface);
490 491 492 493 494
    return IHTMLDocument2_AddRef(HTMLDOC(This));
}

static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
{
495
    HTMLDocument *This = MONPROP_THIS(iface);
496 497 498 499 500
    return IHTMLDocument_Release(HTMLDOC(This));
}

static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
{
501
    HTMLDocument *This = MONPROP_THIS(iface);
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519

    TRACE("(%p)->(%d %s)\n", This, mkp, debugstr_w(val));

    switch(mkp) {
    case MIMETYPEPROP:
        heap_free(This->mime);
        This->mime = heap_strdupW(val);
        break;

    case CLASSIDPROP:
        break;

    default:
        FIXME("mkp %d\n", mkp);
        return E_NOTIMPL;
    }

    return S_OK;
520 521
}

522
static const IMonikerPropVtbl MonikerPropVtbl = {
523 524 525 526 527 528 529 530 531 532
    MonikerProp_QueryInterface,
    MonikerProp_AddRef,
    MonikerProp_Release,
    MonikerProp_PutProperty
};

/**********************************************************
 * IPersistFile implementation
 */

533
#define PERSISTFILE_THIS(iface) DEFINE_THIS(HTMLDocument, PersistFile, iface)
534 535 536

static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppvObject)
{
537
    HTMLDocument *This = PERSISTFILE_THIS(iface);
538 539 540 541 542
    return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
}

static ULONG WINAPI PersistFile_AddRef(IPersistFile *iface)
{
543
    HTMLDocument *This = PERSISTFILE_THIS(iface);
544 545 546 547 548
    return IHTMLDocument2_AddRef(HTMLDOC(This));
}

static ULONG WINAPI PersistFile_Release(IPersistFile *iface)
{
549
    HTMLDocument *This = PERSISTFILE_THIS(iface);
550 551 552 553 554
    return IHTMLDocument2_Release(HTMLDOC(This));
}

static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *iface, CLSID *pClassID)
{
555 556 557
    HTMLDocument *This = PERSISTFILE_THIS(iface);

    TRACE("(%p)->(%p)\n", This, pClassID);
558 559 560 561

    if(!pClassID)
        return E_INVALIDARG;

562
    *pClassID = CLSID_HTMLDocument;
563 564 565 566 567
    return S_OK;
}

static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *iface)
{
568
    HTMLDocument *This = PERSISTFILE_THIS(iface);
569 570 571 572

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

    return IPersistStreamInit_IsDirty(PERSTRINIT(This));
573 574 575 576
}

static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
{
577
    HTMLDocument *This = PERSISTFILE_THIS(iface);
578
    FIXME("(%p)->(%s %08x)\n", This, debugstr_w(pszFileName), dwMode);
579 580 581 582 583
    return E_NOTIMPL;
}

static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
{
584
    HTMLDocument *This = PERSISTFILE_THIS(iface);
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
    char *str;
    DWORD len, written=0;
    HANDLE file;
    HRESULT hres;

    TRACE("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember);

    file = CreateFileW(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
                       FILE_ATTRIBUTE_NORMAL, NULL);
    if(file == INVALID_HANDLE_VALUE) {
        WARN("Could not create file: %u\n", GetLastError());
        return E_FAIL;
    }

    hres = get_doc_string(This, &str, &len);
600 601
    if(SUCCEEDED(hres))
        WriteFile(file, str, len, &written, NULL);
602 603

    CloseHandle(file);
604
    return hres;
605 606 607 608
}

static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
{
609 610
    HTMLDocument *This = PERSISTFILE_THIS(iface);
    FIXME("(%p)->(%s)\n", This, debugstr_w(pszFileName));
611 612 613 614 615
    return E_NOTIMPL;
}

static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *pszFileName)
{
616 617
    HTMLDocument *This = PERSISTFILE_THIS(iface);
    FIXME("(%p)->(%p)\n", This, pszFileName);
618 619 620
    return E_NOTIMPL;
}

621
static const IPersistFileVtbl PersistFileVtbl = {
622 623 624 625 626 627 628 629 630 631 632
    PersistFile_QueryInterface,
    PersistFile_AddRef,
    PersistFile_Release,
    PersistFile_GetClassID,
    PersistFile_IsDirty,
    PersistFile_Load,
    PersistFile_Save,
    PersistFile_SaveCompleted,
    PersistFile_GetCurFile
};

633
#define PERSTRINIT_THIS(iface) DEFINE_THIS(HTMLDocument, PersistStreamInit, iface)
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650

static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface,
                                                       REFIID riid, void **ppv)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
    return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
}

static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
    return IHTMLDocument2_AddRef(HTMLDOC(This));
}

static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
651
    return IHTMLDocument2_Release(HTMLDOC(This));
652 653 654 655 656 657 658 659 660 661 662
}

static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
    return IPersist_GetClassID(PERSIST(This), pClassID);
}

static HRESULT WINAPI PersistStreamInit_IsDirty(IPersistStreamInit *iface)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
663 664 665 666

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

    if(This->usermode == EDITMODE)
667
        return editor_is_dirty(This);
668 669

    return S_FALSE;
670 671 672 673 674
}

static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM pStm)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
675 676 677 678 679 680 681 682 683 684 685 686 687
    IMoniker *mon;
    HRESULT hres;

    static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};

    TRACE("(%p)->(%p)\n", This, pStm);

    hres = CreateURLMoniker(NULL, about_blankW, &mon);
    if(FAILED(hres)) {
        WARN("CreateURLMoniker failed: %08x\n", hres);
        return hres;
    }

688
    hres = set_moniker(This, mon, NULL, NULL);
689 690 691 692
    IMoniker_Release(mon);
    if(FAILED(hres))
        return hres;

693
    return channelbsc_load_stream(This->bscallback, pStm);
694 695 696 697 698 699
}

static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
                                             BOOL fClearDirty)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
700 701 702 703
    char *str;
    DWORD len, written=0;
    HRESULT hres;

704
    TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
705

706 707 708
    hres = get_doc_string(This, &str, &len);
    if(FAILED(hres))
        return hres;
709 710 711

    hres = IStream_Write(pStm, str, len, &written);
    if(FAILED(hres))
712
        FIXME("Write failed: %08x\n", hres);
713

714
    heap_free(str);
715 716 717 718

    if(fClearDirty)
        set_dirty(This, VARIANT_FALSE);

719
    return S_OK;
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
}

static HRESULT WINAPI PersistStreamInit_GetSizeMax(IPersistStreamInit *iface,
                                                   ULARGE_INTEGER *pcbSize)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
    FIXME("(%p)->(%p)\n", This, pcbSize);
    return E_NOTIMPL;
}

static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
{
    HTMLDocument *This = PERSTRINIT_THIS(iface);
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

#undef PERSTRINIT_THIS

static const IPersistStreamInitVtbl PersistStreamInitVtbl = {
    PersistStreamInit_QueryInterface,
    PersistStreamInit_AddRef,
    PersistStreamInit_Release,
    PersistStreamInit_GetClassID,
    PersistStreamInit_IsDirty,
    PersistStreamInit_Load,
    PersistStreamInit_Save,
    PersistStreamInit_GetSizeMax,
    PersistStreamInit_InitNew
};

751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
/**********************************************************
 * IPersistHistory implementation
 */

#define PERSISTHIST_THIS(iface) DEFINE_THIS(HTMLDocument, PersistHistory, iface)

static HRESULT WINAPI PersistHistory_QueryInterface(IPersistHistory *iface, REFIID riid, void **ppvObject)
{
    HTMLDocument *This = PERSISTHIST_THIS(iface);
    return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
}

static ULONG WINAPI PersistHistory_AddRef(IPersistHistory *iface)
{
    HTMLDocument *This = PERSISTHIST_THIS(iface);
    return IHTMLDocument2_AddRef(HTMLDOC(This));
}

static ULONG WINAPI PersistHistory_Release(IPersistHistory *iface)
{
    HTMLDocument *This = PERSISTHIST_THIS(iface);
    return IHTMLDocument2_Release(HTMLDOC(This));
}

static HRESULT WINAPI PersistHistory_GetClassID(IPersistHistory *iface, CLSID *pClassID)
{
    HTMLDocument *This = PERSISTHIST_THIS(iface);
    return IPersist_GetClassID(PERSIST(This), pClassID);
}

static HRESULT WINAPI PersistHistory_LoadHistory(IPersistHistory *iface, IStream *pStream, IBindCtx *pbc)
{
    HTMLDocument *This = PERSISTHIST_THIS(iface);
    FIXME("(%p)->(%p %p)\n", This, pStream, pbc);
    return E_NOTIMPL;
}

static HRESULT WINAPI PersistHistory_SaveHistory(IPersistHistory *iface, IStream *pStream)
{
    HTMLDocument *This = PERSISTHIST_THIS(iface);
    FIXME("(%p)->(%p)\n", This, pStream);
    return E_NOTIMPL;
}

static HRESULT WINAPI PersistHistory_SetPositionCookie(IPersistHistory *iface, DWORD dwPositioncookie)
{
    HTMLDocument *This = PERSISTHIST_THIS(iface);
    FIXME("(%p)->(%x)\n", This, dwPositioncookie);
    return E_NOTIMPL;
}

static HRESULT WINAPI PersistHistory_GetPositionCookie(IPersistHistory *iface, DWORD *pdwPositioncookie)
{
    HTMLDocument *This = PERSISTHIST_THIS(iface);
    FIXME("(%p)->(%p)\n", This, pdwPositioncookie);
    return E_NOTIMPL;
}

#undef PERSISTHIST_THIS

static const IPersistHistoryVtbl PersistHistoryVtbl = {
    PersistHistory_QueryInterface,
    PersistHistory_AddRef,
    PersistHistory_Release,
    PersistHistory_GetClassID,
    PersistHistory_LoadHistory,
    PersistHistory_SaveHistory,
    PersistHistory_SetPositionCookie,
    PersistHistory_GetPositionCookie
};

822 823 824 825 826
void HTMLDocument_Persist_Init(HTMLDocument *This)
{
    This->lpPersistMonikerVtbl = &PersistMonikerVtbl;
    This->lpPersistFileVtbl = &PersistFileVtbl;
    This->lpMonikerPropVtbl = &MonikerPropVtbl;
827
    This->lpPersistStreamInitVtbl = &PersistStreamInitVtbl;
828
    This->lpPersistHistoryVtbl = &PersistHistoryVtbl;
829 830

    This->bscallback = NULL;
831
    This->mon = NULL;
832
    This->url = NULL;
833
    This->mime = NULL;
834
}