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
createTempXInStreamFromIStream(uno::Reference<lang::XMultiServiceFactory> xFactory,IStream * pStream)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
copyXTempOutToIStream(uno::Reference<io::XOutputStream> xTempOut,IStream * pStream)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
EmbedDocument_Impl(const uno::Reference<lang::XMultiServiceFactory> & xFactory,const GUID * guid)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
~EmbedDocument_Impl()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
fillArgsForLoading_Impl(uno::Reference<io::XInputStream> xStream,DWORD,LPCOLESTR pFilePath)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
fillArgsForStoring_Impl(uno::Reference<io::XOutputStream> xStream)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
SaveTo_Impl(IStorage * pStg)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
QueryInterface(REFIID riid,void FAR * FAR * ppv)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
STDMETHODIMP_(ULONG)354 STDMETHODIMP_(ULONG) EmbedDocument_Impl::AddRef()
355 {
356 return osl_incrementInterlockedCount( &m_refCount);
357 }
358
STDMETHODIMP_(ULONG)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
GetClassID(CLSID * pClassId)375 STDMETHODIMP EmbedDocument_Impl::GetClassID( CLSID* pClassId )
376 {
377 *pClassId = *&m_guid;
378 return S_OK;
379 }
380
381 //-------------------------------------------------------------------------------
382 // IPersistStorage
383
IsDirty()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
InitNew(IStorage * pStg)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
Load(IStorage * pStg)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
Save(IStorage * pStgSave,BOOL fSameAsLoad)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
SaveCompleted(IStorage * pStgNew)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
HandsOffStorage()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
Load(LPCOLESTR pszFileName,DWORD)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
Save(LPCOLESTR pszFileName,BOOL fRemember)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
SaveCompleted(LPCOLESTR pszFileName)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
GetCurFile(LPOLESTR * ppszFileName)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
GetEmbedDocument()939 LockedEmbedDocument_Impl EmbeddedDocumentInstanceAccess_Impl::GetEmbedDocument()
940 {
941 ::osl::MutexGuard aGuard( m_aMutex );
942 return LockedEmbedDocument_Impl( m_pEmbedDocument );
943 }
944
ClearEmbedDocument()945 void EmbeddedDocumentInstanceAccess_Impl::ClearEmbedDocument()
946 {
947 ::osl::MutexGuard aGuard( m_aMutex );
948 m_pEmbedDocument = NULL;
949 }
950
951 // ===============================================
952
LockedEmbedDocument_Impl()953 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl()
954 : m_pEmbedDocument( NULL )
955 {}
956
LockedEmbedDocument_Impl(EmbedDocument_Impl * pEmbedDocument)957 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( EmbedDocument_Impl* pEmbedDocument )
958 : m_pEmbedDocument( pEmbedDocument )
959 {
960 if ( m_pEmbedDocument )
961 m_pEmbedDocument->AddRef();
962 }
963
LockedEmbedDocument_Impl(const LockedEmbedDocument_Impl & aDocLock)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
operator =(const LockedEmbedDocument_Impl & aDocLock)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
~LockedEmbedDocument_Impl()983 LockedEmbedDocument_Impl::~LockedEmbedDocument_Impl()
984 {
985 if ( m_pEmbedDocument )
986 m_pEmbedDocument->Release();
987 }
988
ExecuteMethod(sal_Int16 nId)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