xref: /AOO41X/main/embedserv/source/embed/ed_ipersiststr.cxx (revision 79aad27f7f29270c03e208e3d687e8e3850af11d)
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