1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 #if defined(_MSC_VER) && (_MSC_VER > 1310) 28 #pragma warning(disable : 4917 4555) 29 #endif 30 31 #include "embeddoc.hxx" 32 #include <com/sun/star/uno/Any.h> 33 #include <com/sun/star/uno/Exception.hpp> 34 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 35 #include <com/sun/star/lang/XComponent.hpp> 36 #include <com/sun/star/io/XInputStream.hpp> 37 #include <com/sun/star/io/XOutputStream.hpp> 38 #include <com/sun/star/io/XSeekable.hpp> 39 #include <com/sun/star/frame/XModel.hpp> 40 #include <com/sun/star/frame/XLoadable.hpp> 41 #include <com/sun/star/util/XModifiable.hpp> 42 #include <com/sun/star/frame/XStorable.hpp> 43 #include <com/sun/star/frame/XComponentLoader.hpp> 44 #include <com/sun/star/util/XUrlTransformer.hpp> 45 46 47 #include <osl/mutex.hxx> 48 #include <osl/diagnose.h> 49 50 #include <string.h> 51 52 #define EXT_STREAM_LENGTH 16 53 54 using namespace ::com::sun::star; 55 56 extern ::rtl::OUString getStorageTypeFromGUID_Impl( GUID* guid ); 57 extern ::rtl::OUString getServiceNameFromGUID_Impl( GUID* ); 58 extern ::rtl::OUString getFilterNameFromGUID_Impl( GUID* ); 59 // extern CLIPFORMAT getClipFormatFromGUID_Impl( GUID* ); 60 ::rtl::OUString getTestFileURLFromGUID_Impl( GUID* guid ); 61 62 const ::rtl::OUString aOfficeEmbedStreamName( RTL_CONSTASCII_USTRINGPARAM ( "package_stream" ) ); 63 const ::rtl::OUString aExtentStreamName( RTL_CONSTASCII_USTRINGPARAM ( "properties_stream" ) ); 64 65 uno::Reference< io::XInputStream > createTempXInStreamFromIStream( 66 uno::Reference< lang::XMultiServiceFactory > xFactory, 67 IStream *pStream ) 68 { 69 uno::Reference< io::XInputStream > xResult; 70 71 if ( !pStream ) 72 return xResult; 73 74 const ::rtl::OUString aServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); 75 uno::Reference < io::XOutputStream > xTempOut = uno::Reference < io::XOutputStream > ( 76 xFactory->createInstance ( aServiceName ), 77 uno::UNO_QUERY ); 78 if ( xTempOut.is() ) 79 { 80 ULARGE_INTEGER nNewPos; 81 LARGE_INTEGER aZero = { 0L, 0L }; 82 HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); 83 if ( FAILED( hr ) ) return xResult; 84 85 STATSTG aStat; 86 hr = pStream->Stat( &aStat, STATFLAG_NONAME ); 87 if ( FAILED( hr ) ) return xResult; 88 89 sal_uInt32 nSize = (sal_uInt32)aStat.cbSize.QuadPart; 90 sal_uInt32 nCopied = 0; 91 uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize ); 92 try 93 { 94 sal_uInt32 nRead = 0; 95 do 96 { 97 pStream->Read( (void*)aBuffer.getArray(), nConstBufferSize, &nRead ); 98 99 if ( nRead < nConstBufferSize ) 100 aBuffer.realloc( nRead ); 101 102 xTempOut->writeBytes( aBuffer ); 103 nCopied += nRead; 104 } while( nRead == nConstBufferSize ); 105 106 if ( nCopied == nSize ) 107 { 108 uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY ); 109 if ( xTempSeek.is() ) 110 { 111 xTempSeek->seek ( 0 ); 112 xResult = uno::Reference< io::XInputStream >( xTempOut, uno::UNO_QUERY ); 113 } 114 } 115 } 116 catch( uno::Exception& ) 117 { 118 } 119 } 120 121 return xResult; 122 } 123 124 HRESULT copyXTempOutToIStream( uno::Reference< io::XOutputStream > xTempOut, IStream* pStream ) 125 { 126 if ( !xTempOut.is() || !pStream ) 127 return E_FAIL; 128 129 uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY ); 130 if ( !xTempSeek.is() ) 131 return E_FAIL; 132 133 xTempSeek->seek ( 0 ); 134 135 uno::Reference< io::XInputStream > xTempIn ( xTempOut, uno::UNO_QUERY ); 136 if ( !xTempSeek.is() ) 137 return E_FAIL; 138 139 // Seek to zero and truncate the stream 140 ULARGE_INTEGER nNewPos; 141 LARGE_INTEGER aZero = { 0L, 0L }; 142 HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); 143 if ( FAILED( hr ) ) return E_FAIL; 144 ULARGE_INTEGER aUZero = { 0L, 0L }; 145 hr = pStream->SetSize( aUZero ); 146 if ( FAILED( hr ) ) return E_FAIL; 147 148 uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize ); 149 sal_uInt32 nReadBytes = 0; 150 151 do 152 { 153 try { 154 nReadBytes = xTempIn->readBytes( aBuffer, nConstBufferSize ); 155 } 156 catch( uno::Exception& ) 157 { 158 return E_FAIL; 159 } 160 161 sal_uInt32 nWritten = 0; 162 HRESULT hr = pStream->Write( (void*)aBuffer.getArray(), nReadBytes, &nWritten ); 163 if ( !SUCCEEDED( hr ) || nWritten != nReadBytes ) 164 return E_FAIL; 165 166 } while( nReadBytes == nConstBufferSize ); 167 168 return S_OK; 169 } 170 171 172 //=============================================================================== 173 // EmbedDocument_Impl 174 //=============================================================================== 175 176 EmbedDocument_Impl::EmbedDocument_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory, const GUID* guid ) 177 : m_refCount( 0L ) 178 , m_xFactory( xFactory ) 179 , m_guid( *guid ) 180 , m_bIsDirty( sal_False ) 181 , m_nAdviseNum( 0 ) 182 , m_bIsInVerbHandling( sal_False ) 183 //, m_bLoadedFromFile( sal_False ) 184 { 185 m_xOwnAccess = new EmbeddedDocumentInstanceAccess_Impl( this ); 186 m_pDocHolder = new DocumentHolder( xFactory, m_xOwnAccess ); 187 m_pDocHolder->acquire(); 188 } 189 190 EmbedDocument_Impl::~EmbedDocument_Impl() 191 { 192 m_pDocHolder->FreeOffice(); 193 194 if ( m_pDocHolder->HasFrame() && m_pDocHolder->IsLink() ) 195 { 196 // a link with frame should be only disconnected, not closed 197 m_pDocHolder->DisconnectFrameDocument( sal_True ); 198 } 199 else 200 { 201 m_pDocHolder->CloseDocument(); 202 m_pDocHolder->CloseFrame(); 203 } 204 205 m_pDocHolder->release(); 206 } 207 208 uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForLoading_Impl( uno::Reference< io::XInputStream > xStream, DWORD /*nStreamMode*/, LPCOLESTR pFilePath ) 209 { 210 uno::Sequence< beans::PropertyValue > aArgs( 3 ); 211 212 sal_Int32 nInd = 0; // must not be bigger than the preset size 213 aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "FilterName" ) ); 214 aArgs[nInd++].Value <<= getFilterNameFromGUID_Impl( &m_guid ); 215 216 if ( xStream.is() ) 217 { 218 aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "InputStream" ) ); 219 aArgs[nInd++].Value <<= xStream; 220 aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "URL" ) ); 221 aArgs[nInd++].Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "private:stream" ) ); 222 } 223 else 224 { 225 aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "URL" ) ); 226 227 rtl::OUString sDocUrl; 228 if ( pFilePath ) 229 { 230 ::rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.util.URLTransformer" ) ); 231 uno::Reference< util::XURLTransformer > aTransformer( m_xFactory->createInstance( aServiceName ), 232 uno::UNO_QUERY ); 233 if ( aTransformer.is() ) 234 { 235 util::URL aURL; 236 237 aURL.Complete = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pFilePath) ); 238 239 if ( aTransformer->parseSmart( aURL, ::rtl::OUString() ) ) 240 sDocUrl = aURL.Complete; 241 } 242 } 243 244 aArgs[nInd++].Value <<= sDocUrl; 245 } 246 247 aArgs.realloc( nInd ); 248 249 // aArgs[].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "ReadOnly" ) ); 250 // aArgs[].Value <<= sal_False; //( ( nStreamMode & ( STGM_READWRITE | STGM_WRITE ) ) ? sal_True : sal_False ); 251 252 return aArgs; 253 } 254 255 uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForStoring_Impl( uno::Reference< io::XOutputStream > xStream) 256 { 257 uno::Sequence< beans::PropertyValue > aArgs( xStream.is() ? 2 : 1 ); 258 259 aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "FilterName" ) ); 260 aArgs[0].Value <<= getFilterNameFromGUID_Impl( &m_guid ); 261 262 if ( xStream.is() ) 263 { 264 aArgs[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "OutputStream" ) ); 265 aArgs[1].Value <<= xStream; 266 } 267 268 return aArgs; 269 } 270 271 HRESULT EmbedDocument_Impl::SaveTo_Impl( IStorage* pStg ) 272 { 273 if ( !pStg || pStg == m_pMasterStorage ) 274 return E_FAIL; 275 276 // for saveto operation the master storage 277 // should not enter NoScribble mode 278 CComPtr< IStream > pOrigOwn = m_pOwnStream; 279 CComPtr< IStream > pOrigExt = m_pExtStream; 280 HRESULT hr = Save( pStg, sal_False ); 281 pStg->Commit( STGC_ONLYIFCURRENT ); 282 m_pOwnStream = pOrigOwn; 283 m_pExtStream = pOrigExt; 284 285 return hr; 286 } 287 288 //------------------------------------------------------------------------------- 289 // IUnknown 290 291 STDMETHODIMP EmbedDocument_Impl::QueryInterface( REFIID riid, void FAR* FAR* ppv ) 292 { 293 if(IsEqualIID(riid, IID_IUnknown)) 294 { 295 AddRef(); 296 *ppv = (IUnknown*) (IPersistStorage*) this; 297 return S_OK; 298 } 299 else if (IsEqualIID(riid, IID_IPersist)) 300 { 301 AddRef(); 302 *ppv = (IPersist*) (IPersistStorage*) this; 303 return S_OK; 304 } 305 else if (IsEqualIID(riid, IID_IExternalConnection)) 306 { 307 AddRef(); 308 *ppv = (IExternalConnection*) this; 309 return S_OK; 310 } 311 else if (IsEqualIID(riid, IID_IPersistStorage)) 312 { 313 AddRef(); 314 *ppv = (IPersistStorage*) this; 315 return S_OK; 316 } 317 else if (IsEqualIID(riid, IID_IDataObject)) 318 { 319 AddRef(); 320 *ppv = (IDataObject*) this; 321 return S_OK; 322 } 323 else if (IsEqualIID(riid, IID_IOleObject)) 324 { 325 AddRef(); 326 *ppv = (IOleObject*) this; 327 return S_OK; 328 } 329 else if (IsEqualIID(riid, IID_IOleWindow)) 330 { 331 AddRef(); 332 *ppv = (IOleWindow*) this; 333 return S_OK; 334 } 335 else if (IsEqualIID(riid, IID_IOleInPlaceObject)) 336 { 337 AddRef(); 338 *ppv = (IOleInPlaceObject*) this; 339 return S_OK; 340 } 341 else if (IsEqualIID(riid, IID_IPersistFile)) 342 { 343 AddRef(); 344 *ppv = (IPersistFile*) this; 345 return S_OK; 346 } 347 else if (IsEqualIID(riid, IID_IDispatch)) 348 { 349 AddRef(); 350 *ppv = (IDispatch*) this; 351 return S_OK; 352 } 353 354 *ppv = NULL; 355 return ResultFromScode(E_NOINTERFACE); 356 } 357 358 STDMETHODIMP_(ULONG) EmbedDocument_Impl::AddRef() 359 { 360 return osl_incrementInterlockedCount( &m_refCount); 361 } 362 363 STDMETHODIMP_(ULONG) EmbedDocument_Impl::Release() 364 { 365 // if there is a time when the last reference is destructed, that means that only internal pointers are alive 366 // after the following call either the refcount is increased or the pointers are empty 367 if ( m_refCount == 1 ) 368 m_xOwnAccess->ClearEmbedDocument(); 369 370 sal_Int32 nCount = osl_decrementInterlockedCount( &m_refCount ); 371 if ( nCount == 0 ) 372 delete this; 373 return nCount; 374 } 375 376 //------------------------------------------------------------------------------- 377 // IPersist 378 379 STDMETHODIMP EmbedDocument_Impl::GetClassID( CLSID* pClassId ) 380 { 381 *pClassId = *&m_guid; 382 return S_OK; 383 } 384 385 //------------------------------------------------------------------------------- 386 // IPersistStorage 387 388 STDMETHODIMP EmbedDocument_Impl::IsDirty() 389 { 390 // the link modified state is controlled by the document 391 if ( m_bIsDirty && !m_aFileName.getLength() ) 392 return S_OK; 393 394 uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); 395 if ( xMod.is() ) 396 return xMod->isModified() ? S_OK : S_FALSE; 397 return S_FALSE; 398 } 399 400 STDMETHODIMP EmbedDocument_Impl::InitNew( IStorage *pStg ) 401 { 402 HRESULT hr = CO_E_ALREADYINITIALIZED; 403 404 if ( !m_pDocHolder->GetDocument().is() ) 405 { 406 407 STATSTG aStat; 408 hr = pStg->Stat( &aStat, STATFLAG_NONAME ); 409 if ( FAILED( hr ) ) return E_FAIL; 410 411 DWORD nStreamMode = aStat.grfMode; 412 413 hr = E_FAIL; 414 if ( m_xFactory.is() && pStg ) 415 { 416 uno::Reference< frame::XModel > aDocument( 417 m_xFactory->createInstance( getServiceNameFromGUID_Impl( &m_guid ) ), 418 uno::UNO_QUERY ); 419 if ( aDocument.is() ) 420 { 421 m_pDocHolder->SetDocument( aDocument ); 422 423 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); 424 if( xLoadable.is() ) 425 { 426 try 427 { 428 xLoadable->initNew(); 429 // xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), nStreamMode ) ); 430 hr = S_OK; 431 } 432 catch( uno::Exception& ) 433 { 434 } 435 } 436 437 if ( hr == S_OK ) 438 { 439 ::rtl::OUString aCurType = getStorageTypeFromGUID_Impl( &m_guid ); // ??? 440 CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" ); 441 hr = WriteFmtUserTypeStg( pStg, 442 cf, // ??? 443 reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) ); 444 445 if ( hr == S_OK ) 446 { 447 hr = pStg->CreateStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), 448 STGM_CREATE | ( nStreamMode & 0x73 ), 449 0, 450 0, 451 &m_pOwnStream ); 452 453 if ( hr == S_OK && m_pOwnStream ) 454 { 455 hr = pStg->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), 456 STGM_CREATE | ( nStreamMode & 0x73 ), 457 0, 458 0, 459 &m_pExtStream ); 460 461 if ( hr == S_OK && m_pExtStream ) 462 { 463 464 m_pMasterStorage = pStg; 465 m_bIsDirty = sal_True; 466 } 467 else 468 hr = E_FAIL; 469 } 470 else 471 hr = E_FAIL; 472 } 473 else 474 hr = E_FAIL; 475 } 476 477 if ( hr != S_OK ) 478 m_pDocHolder->CloseDocument(); 479 } 480 } 481 } 482 483 return hr; 484 } 485 486 STDMETHODIMP EmbedDocument_Impl::Load( IStorage *pStg ) 487 { 488 if ( m_pDocHolder->GetDocument().is() ) 489 return CO_E_ALREADYINITIALIZED; 490 491 if ( !m_xFactory.is() || !pStg ) 492 return E_FAIL; 493 494 HRESULT hr = E_FAIL; 495 496 STATSTG aStat; 497 hr = pStg->Stat( &aStat, STATFLAG_NONAME ); 498 if ( FAILED( hr ) ) return E_FAIL; 499 500 DWORD nStreamMode = aStat.grfMode; 501 hr = pStg->OpenStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), 502 0, 503 nStreamMode & 0x73, 504 0, 505 &m_pOwnStream ); 506 if ( !m_pOwnStream ) hr = E_FAIL; 507 508 if ( SUCCEEDED( hr ) ) 509 { 510 hr = pStg->OpenStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), 511 0, 512 nStreamMode & 0x73, 513 0, 514 &m_pExtStream ); 515 if ( !m_pExtStream ) hr = E_FAIL; 516 } 517 518 // RECTL aRectToSet; 519 SIZEL aSizeToSet; 520 if ( SUCCEEDED( hr ) ) 521 { 522 ULARGE_INTEGER nNewPos; 523 LARGE_INTEGER aZero = { 0L, 0L }; 524 hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); 525 if ( SUCCEEDED( hr ) ) 526 { 527 sal_uInt32 nRead; 528 sal_Int8 aInf[EXT_STREAM_LENGTH]; 529 hr = m_pExtStream->Read( (void*)aInf, EXT_STREAM_LENGTH, &nRead ); 530 if ( nRead != EXT_STREAM_LENGTH ) hr = E_FAIL; 531 532 if ( SUCCEEDED( hr ) ) 533 { 534 // aRectToSet.left = *((sal_Int32*)aInf); 535 // aRectToSet.top = *((sal_Int32*)&aInf[4]); 536 // aRectToSet.right = *((sal_Int32*)&aInf[8]); 537 // aRectToSet.bottom = *((sal_Int32*)&aInf[12]); 538 aSizeToSet.cx = *((sal_Int32*)&aInf[8]) - *((sal_Int32*)aInf); 539 aSizeToSet.cy = *((sal_Int32*)&aInf[12]) - *((sal_Int32*)&aInf[4]); 540 } 541 } 542 } 543 544 if ( SUCCEEDED( hr ) ) 545 { 546 hr = E_FAIL; 547 548 uno::Reference < io::XInputStream > xTempIn = createTempXInStreamFromIStream( m_xFactory, m_pOwnStream ); 549 if ( xTempIn.is() ) 550 { 551 uno::Reference< frame::XModel > aDocument( 552 m_xFactory->createInstance( getServiceNameFromGUID_Impl( &m_guid ) ), 553 uno::UNO_QUERY ); 554 if ( aDocument.is() ) 555 { 556 m_pDocHolder->SetDocument( aDocument ); 557 558 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); 559 if( xLoadable.is() ) 560 { 561 try 562 { 563 xLoadable->load( fillArgsForLoading_Impl( xTempIn, nStreamMode ) ); 564 m_pMasterStorage = pStg; 565 hr = m_pDocHolder->SetExtent( &aSizeToSet ); 566 // hr = m_pDocHolder->SetVisArea( &aRectToSet ); 567 } 568 catch( uno::Exception& ) 569 { 570 } 571 } 572 573 if ( FAILED( hr ) ) 574 m_pDocHolder->CloseDocument(); 575 } 576 } 577 } 578 579 if ( FAILED( hr ) ) 580 { 581 m_pOwnStream = CComPtr< IStream >(); 582 m_pExtStream = CComPtr< IStream >(); 583 hr = pStg->DestroyElement( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()) ); 584 hr = pStg->DestroyElement( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()) ); 585 586 OSL_ENSURE( SUCCEEDED( hr ), "Can not destroy created stream!\n" ); 587 if ( FAILED( hr ) ) 588 hr = E_FAIL; 589 } 590 591 return hr; 592 } 593 594 STDMETHODIMP EmbedDocument_Impl::Save( IStorage *pStgSave, BOOL fSameAsLoad ) 595 { 596 if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() || !pStgSave || !m_pOwnStream || !m_pExtStream ) 597 return E_FAIL; 598 599 CComPtr< IStream > pTargetStream; 600 CComPtr< IStream > pNewExtStream; 601 602 if ( !fSameAsLoad && pStgSave != m_pMasterStorage ) 603 { 604 OSL_ENSURE( m_pMasterStorage, "How could the document be initialized without storage!??\n" ); 605 HRESULT hr = m_pMasterStorage->CopyTo( NULL, NULL, NULL, pStgSave ); 606 if ( FAILED( hr ) ) return E_FAIL; 607 608 STATSTG aStat; 609 hr = pStgSave->Stat( &aStat, STATFLAG_NONAME ); 610 if ( FAILED( hr ) ) return E_FAIL; 611 612 DWORD nStreamMode = aStat.grfMode; 613 hr = pStgSave->CreateStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), 614 STGM_CREATE | ( nStreamMode & 0x73 ), 615 0, 616 0, 617 &pTargetStream ); 618 if ( FAILED( hr ) || !pTargetStream ) return E_FAIL; 619 620 hr = pStgSave->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), 621 STGM_CREATE | ( nStreamMode & 0x73 ), 622 0, 623 0, 624 &pNewExtStream ); 625 if ( FAILED( hr ) || !pNewExtStream ) return E_FAIL; 626 } 627 else 628 { 629 pTargetStream = m_pOwnStream; 630 pNewExtStream = m_pExtStream; 631 } 632 633 HRESULT hr = E_FAIL; 634 635 const ::rtl::OUString aServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); 636 uno::Reference < io::XOutputStream > xTempOut = uno::Reference < io::XOutputStream > ( 637 m_xFactory->createInstance ( aServiceName ), 638 uno::UNO_QUERY ); 639 640 if ( xTempOut.is() ) 641 { 642 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); 643 if( xStorable.is() ) 644 { 645 try 646 { 647 xStorable->storeToURL( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "private:stream" ) ), 648 fillArgsForStoring_Impl( xTempOut ) ); 649 hr = copyXTempOutToIStream( xTempOut, pTargetStream ); 650 if ( SUCCEEDED( hr ) ) 651 { 652 // no need to truncate the stream, the size of the stream is always the same 653 ULARGE_INTEGER nNewPos; 654 LARGE_INTEGER aZero = { 0L, 0L }; 655 hr = pNewExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); 656 if ( SUCCEEDED( hr ) ) 657 { 658 SIZEL aSize; 659 hr = m_pDocHolder->GetExtent( &aSize ); 660 661 if ( SUCCEEDED( hr ) ) 662 { 663 sal_uInt32 nWritten; 664 sal_Int8 aInf[EXT_STREAM_LENGTH]; 665 *((sal_Int32*)aInf) = 0; 666 *((sal_Int32*)&aInf[4]) = 0; 667 *((sal_Int32*)&aInf[8]) = aSize.cx; 668 *((sal_Int32*)&aInf[12]) = aSize.cy; 669 670 hr = pNewExtStream->Write( (void*)aInf, EXT_STREAM_LENGTH, &nWritten ); 671 if ( nWritten != EXT_STREAM_LENGTH ) hr = E_FAIL; 672 673 if ( SUCCEEDED( hr ) ) 674 { 675 m_pOwnStream = CComPtr< IStream >(); 676 m_pExtStream = CComPtr< IStream >(); 677 if ( fSameAsLoad || pStgSave == m_pMasterStorage ) 678 { 679 uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); 680 if ( xMod.is() ) 681 xMod->setModified( sal_False ); 682 m_bIsDirty = sal_False; 683 } 684 } 685 } 686 } 687 } 688 } 689 catch( uno::Exception& ) 690 { 691 } 692 } 693 } 694 695 return hr; 696 } 697 698 STDMETHODIMP EmbedDocument_Impl::SaveCompleted( IStorage *pStgNew ) 699 { 700 // m_pOwnStream == NULL && m_pMasterStorage != NULL means the object is in NoScribble mode 701 // m_pOwnStream == NULL && m_pMasterStorage == NULL means the object is in HandsOff mode 702 703 if ( m_pOwnStream || m_pExtStream ) 704 return E_UNEXPECTED; 705 706 if ( !m_pMasterStorage && !pStgNew ) 707 return E_INVALIDARG; 708 709 if ( pStgNew ) 710 m_pMasterStorage = pStgNew; 711 712 STATSTG aStat; 713 HRESULT hr = m_pMasterStorage->Stat( &aStat, STATFLAG_NONAME ); 714 if ( FAILED( hr ) ) return E_OUTOFMEMORY; 715 716 DWORD nStreamMode = aStat.grfMode; 717 hr = m_pMasterStorage->OpenStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), 718 0, 719 nStreamMode & 0x73, 720 0, 721 &m_pOwnStream ); 722 if ( FAILED( hr ) || !m_pOwnStream ) return E_OUTOFMEMORY; 723 724 hr = m_pMasterStorage->OpenStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), 725 0, 726 nStreamMode & 0x73, 727 0, 728 &m_pExtStream ); 729 if ( FAILED( hr ) || !m_pExtStream ) return E_OUTOFMEMORY; 730 731 sal_Bool bModified = sal_False; 732 uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); 733 if ( xMod.is() ) 734 bModified = xMod->isModified(); 735 736 for ( AdviseSinkHashMapIterator iAdvise = m_aAdviseHashMap.begin(); iAdvise != m_aAdviseHashMap.end(); iAdvise++ ) 737 { 738 if ( iAdvise->second ) 739 iAdvise->second->OnSave(); 740 } 741 742 if ( xMod.is() ) 743 bModified = xMod->isModified(); 744 745 return S_OK; 746 } 747 748 STDMETHODIMP EmbedDocument_Impl::HandsOffStorage() 749 { 750 m_pMasterStorage = CComPtr< IStorage >(); 751 m_pOwnStream = CComPtr< IStream >(); 752 m_pExtStream = CComPtr< IStream >(); 753 754 return S_OK; 755 } 756 757 //------------------------------------------------------------------------------- 758 // IPersistFile 759 760 STDMETHODIMP EmbedDocument_Impl::Load( LPCOLESTR pszFileName, DWORD /*dwMode*/ ) 761 { 762 if ( m_pDocHolder->GetDocument().is() ) 763 return CO_E_ALREADYINITIALIZED; 764 765 if ( !m_xFactory.is() ) 766 return E_FAIL; 767 768 DWORD nStreamMode = STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE | STGM_SHARE_EXCLUSIVE; 769 HRESULT hr = StgCreateDocfile( NULL, 770 nStreamMode , 771 0, 772 &m_pMasterStorage ); 773 774 if ( FAILED( hr ) || !m_pMasterStorage ) return E_FAIL; 775 776 ::rtl::OUString aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ??? 777 CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" ); 778 hr = WriteFmtUserTypeStg( m_pMasterStorage, 779 cf, // ??? 780 reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) ); 781 if ( FAILED( hr ) ) return E_FAIL; 782 783 hr = m_pMasterStorage->SetClass( m_guid ); 784 if ( FAILED( hr ) ) return E_FAIL; 785 786 hr = m_pMasterStorage->CreateStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), 787 STGM_CREATE | ( nStreamMode & 0x73 ), 788 0, 789 0, 790 &m_pOwnStream ); 791 if ( FAILED( hr ) || !m_pOwnStream ) return E_FAIL; 792 793 hr = m_pMasterStorage->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), 794 STGM_CREATE | ( nStreamMode & 0x73 ), 795 0, 796 0, 797 &m_pExtStream ); 798 if ( FAILED( hr ) || !m_pExtStream ) return E_FAIL; 799 800 801 uno::Reference< frame::XModel > aDocument( 802 m_xFactory->createInstance( getServiceNameFromGUID_Impl( &m_guid ) ), 803 uno::UNO_QUERY ); 804 if ( aDocument.is() ) 805 { 806 m_pDocHolder->SetDocument( aDocument, sal_True ); 807 808 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); 809 if( xLoadable.is() ) 810 { 811 try 812 { 813 xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), 814 STGM_READWRITE, 815 pszFileName ) ); 816 hr = S_OK; 817 818 m_aFileName = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pszFileName) ); 819 } 820 catch( uno::Exception& ) 821 { 822 } 823 } 824 825 if ( hr == S_OK ) 826 { 827 ::rtl::OUString aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ??? 828 CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" ); 829 hr = WriteFmtUserTypeStg( m_pMasterStorage, 830 cf, // ??? 831 reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) ); 832 833 if ( SUCCEEDED( hr ) ) 834 { 835 // no need to truncate the stream, the size of the stream is always the same 836 ULARGE_INTEGER nNewPos; 837 LARGE_INTEGER aZero = { 0L, 0L }; 838 hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); 839 if ( SUCCEEDED( hr ) ) 840 { 841 SIZEL aSize; 842 hr = m_pDocHolder->GetExtent( &aSize ); 843 844 if ( SUCCEEDED( hr ) ) 845 { 846 sal_uInt32 nWritten; 847 sal_Int8 aInf[EXT_STREAM_LENGTH]; 848 *((sal_Int32*)aInf) = 0; 849 *((sal_Int32*)&aInf[4]) = 0; 850 *((sal_Int32*)&aInf[8]) = aSize.cx; 851 *((sal_Int32*)&aInf[12]) = aSize.cy; 852 853 hr = m_pExtStream->Write( (void*)aInf, EXT_STREAM_LENGTH, &nWritten ); 854 if ( nWritten != EXT_STREAM_LENGTH ) hr = E_FAIL; 855 } 856 } 857 } 858 859 if ( SUCCEEDED( hr ) ) 860 m_bIsDirty = sal_True; 861 else 862 hr = E_FAIL; 863 } 864 865 if ( FAILED( hr ) ) 866 { 867 m_pDocHolder->CloseDocument(); 868 m_pOwnStream = NULL; 869 m_pExtStream = NULL; 870 m_pMasterStorage = NULL; 871 } 872 } 873 874 return hr; 875 } 876 877 STDMETHODIMP EmbedDocument_Impl::Save( LPCOLESTR pszFileName, BOOL fRemember ) 878 { 879 if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() ) 880 return E_FAIL; 881 882 HRESULT hr = E_FAIL; 883 884 // TODO/LATER: currently there is no hands off state implemented 885 try 886 { 887 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY_THROW ); 888 889 if ( !pszFileName ) 890 xStorable->store(); 891 else 892 { 893 util::URL aURL; 894 aURL.Complete = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>( pszFileName ) ); 895 896 ::rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.util.URLTransformer" ) ); 897 uno::Reference< util::XURLTransformer > aTransformer( m_xFactory->createInstance( aServiceName ), 898 uno::UNO_QUERY_THROW ); 899 900 if ( aTransformer->parseSmart( aURL, ::rtl::OUString() ) && aURL.Complete.getLength() ) 901 { 902 if ( fRemember ) 903 { 904 xStorable->storeAsURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) ); 905 m_aFileName = aURL.Complete; 906 } 907 else 908 xStorable->storeToURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) ); 909 } 910 } 911 912 hr = S_OK; 913 } 914 catch( uno::Exception& ) 915 { 916 } 917 918 return hr; 919 } 920 921 STDMETHODIMP EmbedDocument_Impl::SaveCompleted( LPCOLESTR pszFileName ) 922 { 923 // the different file name would mean error here 924 m_aFileName = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pszFileName) ); 925 return S_OK; 926 } 927 928 STDMETHODIMP EmbedDocument_Impl::GetCurFile( LPOLESTR *ppszFileName ) 929 { 930 CComPtr<IMalloc> pMalloc; 931 932 HRESULT hr = CoGetMalloc( 1, &pMalloc ); 933 if ( FAILED( hr ) || !pMalloc ) return E_FAIL; 934 935 *ppszFileName = (LPOLESTR)( pMalloc->Alloc( sizeof( sal_Unicode ) * ( m_aFileName.getLength() + 1 ) ) ); 936 wcsncpy( *ppszFileName, reinterpret_cast<LPCWSTR>(m_aFileName.getStr()), m_aFileName.getLength() + 1 ); 937 938 return m_aFileName.getLength() ? S_OK : S_FALSE; 939 } 940 941 // =============================================== 942 943 LockedEmbedDocument_Impl EmbeddedDocumentInstanceAccess_Impl::GetEmbedDocument() 944 { 945 ::osl::MutexGuard aGuard( m_aMutex ); 946 return LockedEmbedDocument_Impl( m_pEmbedDocument ); 947 } 948 949 void EmbeddedDocumentInstanceAccess_Impl::ClearEmbedDocument() 950 { 951 ::osl::MutexGuard aGuard( m_aMutex ); 952 m_pEmbedDocument = NULL; 953 } 954 955 // =============================================== 956 957 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl() 958 : m_pEmbedDocument( NULL ) 959 {} 960 961 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( EmbedDocument_Impl* pEmbedDocument ) 962 : m_pEmbedDocument( pEmbedDocument ) 963 { 964 if ( m_pEmbedDocument ) 965 m_pEmbedDocument->AddRef(); 966 } 967 968 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( const LockedEmbedDocument_Impl& aDocLock ) 969 : m_pEmbedDocument( aDocLock.m_pEmbedDocument ) 970 { 971 if ( m_pEmbedDocument ) 972 m_pEmbedDocument->AddRef(); 973 } 974 975 LockedEmbedDocument_Impl& LockedEmbedDocument_Impl::operator=( const LockedEmbedDocument_Impl& aDocLock ) 976 { 977 if ( m_pEmbedDocument ) 978 m_pEmbedDocument->Release(); 979 980 m_pEmbedDocument = aDocLock.m_pEmbedDocument; 981 if ( m_pEmbedDocument ) 982 m_pEmbedDocument->AddRef(); 983 984 return *this; 985 } 986 987 LockedEmbedDocument_Impl::~LockedEmbedDocument_Impl() 988 { 989 if ( m_pEmbedDocument ) 990 m_pEmbedDocument->Release(); 991 } 992 993 void LockedEmbedDocument_Impl::ExecuteMethod( sal_Int16 nId ) 994 { 995 if ( m_pEmbedDocument ) 996 { 997 if ( nId == OLESERV_SAVEOBJECT ) 998 m_pEmbedDocument->SaveObject(); 999 else if ( nId == OLESERV_CLOSE ) 1000 m_pEmbedDocument->Close( 0 ); 1001 else if ( nId == OLESERV_NOTIFY ) 1002 m_pEmbedDocument->notify(); 1003 else if ( nId == OLESERV_NOTIFYCLOSING ) 1004 m_pEmbedDocument->OLENotifyClosing(); 1005 else if ( nId == OLESERV_SHOWOBJECT ) 1006 m_pEmbedDocument->ShowObject(); 1007 else if ( nId == OLESERV_DEACTIVATE ) 1008 m_pEmbedDocument->Deactivate(); 1009 } 1010 } 1011 1012 // Fix strange warnings about some 1013 // ATL::CAxHostWindow::QueryInterface|AddRef|Releae functions. 1014 // warning C4505: 'xxx' : unreferenced local function has been removed 1015 #if defined(_MSC_VER) 1016 #pragma warning(disable: 4505) 1017 #endif 1018 1019