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