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