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