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