Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <oleembobj.hxx>
21 : #include <com/sun/star/embed/EmbedStates.hpp>
22 : #include <com/sun/star/embed/EmbedVerbs.hpp>
23 : #include <com/sun/star/embed/EntryInitModes.hpp>
24 : #include <com/sun/star/embed/XStorage.hpp>
25 : #include <com/sun/star/embed/XTransactedObject.hpp>
26 : #include <com/sun/star/embed/ElementModes.hpp>
27 : #include <com/sun/star/embed/EmbedUpdateModes.hpp>
28 : #include <com/sun/star/embed/Aspects.hpp>
29 : #include <com/sun/star/embed/XOptimizedStorage.hpp>
30 : #include <com/sun/star/lang/XComponent.hpp>
31 : #include <com/sun/star/lang/DisposedException.hpp>
32 : #include <com/sun/star/container/XNameAccess.hpp>
33 : #include <com/sun/star/container/XNameContainer.hpp>
34 : #include <com/sun/star/io/TempFile.hpp>
35 : #include <com/sun/star/io/XSeekable.hpp>
36 : #include <com/sun/star/io/XTruncate.hpp>
37 : #include <com/sun/star/beans/XPropertySet.hpp>
38 : #include <com/sun/star/ucb/SimpleFileAccess.hpp>
39 :
40 : #include <rtl/logfile.hxx>
41 :
42 : #include <comphelper/processfactory.hxx>
43 : #include <comphelper/storagehelper.hxx>
44 : #include <comphelper/mimeconfighelper.hxx>
45 : #include <comphelper/classids.hxx>
46 :
47 :
48 : #include <olecomponent.hxx>
49 : #include <closepreventer.hxx>
50 :
51 : using namespace ::com::sun::star;
52 : using namespace ::comphelper;
53 :
54 : //-------------------------------------------------------------------------
55 0 : sal_Bool KillFile_Impl( const ::rtl::OUString& aURL, const uno::Reference< lang::XMultiServiceFactory >& xFactory )
56 : {
57 0 : if ( !xFactory.is() )
58 0 : return sal_False;
59 :
60 0 : sal_Bool bRet = sal_False;
61 :
62 : try
63 : {
64 : uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
65 0 : ucb::SimpleFileAccess::create( comphelper::getComponentContext(xFactory) ) );
66 :
67 0 : xAccess->kill( aURL );
68 0 : bRet = sal_True;
69 : }
70 0 : catch( const uno::Exception& )
71 : {
72 : }
73 :
74 0 : return bRet;
75 : }
76 :
77 : //----------------------------------------------
78 0 : ::rtl::OUString GetNewTempFileURL_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory )
79 : {
80 : OSL_ENSURE( xFactory.is(), "No factory is provided!\n" );
81 :
82 0 : ::rtl::OUString aResult;
83 :
84 : uno::Reference < beans::XPropertySet > xTempFile(
85 : io::TempFile::create(comphelper::getComponentContext(xFactory)),
86 0 : uno::UNO_QUERY_THROW );
87 :
88 : try {
89 0 : xTempFile->setPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "RemoveFile" )), uno::makeAny( sal_False ) );
90 0 : uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri" ) ));
91 0 : aUrl >>= aResult;
92 : }
93 0 : catch ( const uno::Exception& )
94 : {
95 : }
96 :
97 0 : if ( aResult.isEmpty() )
98 0 : throw uno::RuntimeException(); // TODO: can not create tempfile
99 :
100 0 : return aResult;
101 : }
102 :
103 : //-----------------------------------------------
104 0 : ::rtl::OUString GetNewFilledTempFile_Impl( const uno::Reference< io::XInputStream >& xInStream,
105 : const uno::Reference< lang::XMultiServiceFactory >& xFactory )
106 : throw ( io::IOException,
107 : uno::RuntimeException )
108 : {
109 : OSL_ENSURE( xInStream.is() && xFactory.is(), "Wrong parameters are provided!\n" );
110 :
111 0 : ::rtl::OUString aResult = GetNewTempFileURL_Impl( xFactory );
112 :
113 0 : if ( !aResult.isEmpty() )
114 : {
115 : try {
116 : uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
117 0 : ucb::SimpleFileAccess::create( comphelper::getComponentContext(xFactory) ) );
118 :
119 0 : uno::Reference< io::XOutputStream > xTempOutStream = xTempAccess->openFileWrite( aResult );
120 0 : if ( xTempOutStream.is() )
121 : {
122 : // copy stream contents to the file
123 0 : ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOutStream );
124 0 : xTempOutStream->closeOutput();
125 0 : xTempOutStream = uno::Reference< io::XOutputStream >();
126 : }
127 : else
128 0 : throw io::IOException(); // TODO:
129 : }
130 0 : catch( const packages::WrongPasswordException& )
131 : {
132 0 : KillFile_Impl( aResult, xFactory );
133 0 : throw io::IOException(); //TODO:
134 : }
135 0 : catch( const io::IOException& )
136 : {
137 0 : KillFile_Impl( aResult, xFactory );
138 0 : throw;
139 : }
140 0 : catch( const uno::RuntimeException& )
141 : {
142 0 : KillFile_Impl( aResult, xFactory );
143 0 : throw;
144 : }
145 0 : catch( const uno::Exception& )
146 : {
147 0 : KillFile_Impl( aResult, xFactory );
148 0 : aResult = ::rtl::OUString();
149 : }
150 : }
151 :
152 0 : return aResult;
153 : }
154 : #ifdef WNT
155 : ::rtl::OUString GetNewFilledTempFile_Impl( const uno::Reference< embed::XOptimizedStorage >& xParentStorage, const ::rtl::OUString& aEntryName, const uno::Reference< lang::XMultiServiceFactory >& xFactory )
156 : throw( io::IOException, uno::RuntimeException )
157 : {
158 : ::rtl::OUString aResult;
159 :
160 : try
161 : {
162 : uno::Reference < beans::XPropertySet > xTempFile(
163 : io::TempFile::create(comphelper::getComponentContext(xFactory)),
164 : uno::UNO_QUERY );
165 : uno::Reference < io::XStream > xTempStream( xTempFile, uno::UNO_QUERY_THROW );
166 :
167 : xParentStorage->copyStreamElementData( aEntryName, xTempStream );
168 :
169 : xTempFile->setPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "RemoveFile" )), uno::makeAny( sal_False ) );
170 : uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri" ) ));
171 : aUrl >>= aResult;
172 : }
173 : catch( const uno::RuntimeException& )
174 : {
175 : throw;
176 : }
177 : catch( const uno::Exception& )
178 : {
179 : }
180 :
181 : if ( aResult.isEmpty() )
182 : throw io::IOException();
183 :
184 : return aResult;
185 : }
186 :
187 : //------------------------------------------------------
188 : void SetStreamMediaType_Impl( const uno::Reference< io::XStream >& xStream, const ::rtl::OUString& aMediaType )
189 : {
190 : uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY );
191 : if ( !xPropSet.is() )
192 : throw uno::RuntimeException(); // TODO: all the storage streams must support XPropertySet
193 :
194 : xPropSet->setPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "MediaType" )), uno::makeAny( aMediaType ) );
195 : }
196 : #endif
197 : //------------------------------------------------------
198 0 : void LetCommonStoragePassBeUsed_Impl( const uno::Reference< io::XStream >& xStream )
199 : {
200 0 : uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY );
201 0 : if ( !xPropSet.is() )
202 0 : throw uno::RuntimeException(); // Only StorageStreams must be provided here, they must implement the interface
203 :
204 0 : xPropSet->setPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" )),
205 0 : uno::makeAny( (sal_Bool)sal_True ) );
206 0 : }
207 : #ifdef WNT
208 : //------------------------------------------------------
209 : void VerbExecutionController::StartControlExecution()
210 : {
211 : osl::MutexGuard aGuard( m_aVerbExecutionMutex );
212 :
213 : // the class is used to detect STAMPIT object, that can never be active
214 : if ( !m_bVerbExecutionInProgress && !m_bWasEverActive )
215 : {
216 : m_bVerbExecutionInProgress = sal_True;
217 : m_nVerbExecutionThreadIdentifier = osl_getThreadIdentifier( NULL );
218 : m_bChangedOnVerbExecution = sal_False;
219 : }
220 : }
221 :
222 : //------------------------------------------------------
223 : sal_Bool VerbExecutionController::EndControlExecution_WasModified()
224 : {
225 : osl::MutexGuard aGuard( m_aVerbExecutionMutex );
226 :
227 : sal_Bool bResult = sal_False;
228 : if ( m_bVerbExecutionInProgress && m_nVerbExecutionThreadIdentifier == osl_getThreadIdentifier( NULL ) )
229 : {
230 : bResult = m_bChangedOnVerbExecution;
231 : m_bVerbExecutionInProgress = sal_False;
232 : }
233 :
234 : return bResult;
235 : }
236 :
237 : //------------------------------------------------------
238 : void VerbExecutionController::ModificationNotificationIsDone()
239 : {
240 : osl::MutexGuard aGuard( m_aVerbExecutionMutex );
241 :
242 : if ( m_bVerbExecutionInProgress && osl_getThreadIdentifier( NULL ) == m_nVerbExecutionThreadIdentifier )
243 : m_bChangedOnVerbExecution = sal_True;
244 : }
245 : #endif
246 : //-----------------------------------------------
247 0 : void VerbExecutionController::LockNotification()
248 : {
249 0 : osl::MutexGuard aGuard( m_aVerbExecutionMutex );
250 0 : if ( m_nNotificationLock < SAL_MAX_INT32 )
251 0 : m_nNotificationLock++;
252 0 : }
253 :
254 : //-----------------------------------------------
255 0 : void VerbExecutionController::UnlockNotification()
256 : {
257 0 : osl::MutexGuard aGuard( m_aVerbExecutionMutex );
258 0 : if ( m_nNotificationLock > 0 )
259 0 : m_nNotificationLock--;
260 0 : }
261 :
262 : //-----------------------------------------------
263 0 : uno::Reference< io::XStream > OleEmbeddedObject::GetNewFilledTempStream_Impl( const uno::Reference< io::XInputStream >& xInStream )
264 : throw( io::IOException )
265 : {
266 : OSL_ENSURE( xInStream.is(), "Wrong parameter is provided!\n" );
267 :
268 : uno::Reference < io::XStream > xTempFile(
269 : io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
270 0 : uno::UNO_QUERY_THROW );
271 :
272 0 : uno::Reference< io::XOutputStream > xTempOutStream = xTempFile->getOutputStream();
273 0 : if ( xTempOutStream.is() )
274 : {
275 0 : ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOutStream );
276 0 : xTempOutStream->flush();
277 : }
278 : else
279 0 : throw io::IOException(); // TODO:
280 :
281 0 : return xTempFile;
282 : }
283 :
284 : //------------------------------------------------------
285 0 : uno::Reference< io::XStream > OleEmbeddedObject::TryToGetAcceptableFormat_Impl( const uno::Reference< io::XStream >& xStream )
286 : throw ( uno::Exception )
287 : {
288 : // TODO/LATER: Actually this should be done by a centralized component ( may be a graphical filter )
289 0 : if ( !m_xFactory.is() )
290 0 : throw uno::RuntimeException();
291 :
292 0 : uno::Reference< io::XInputStream > xInStream = xStream->getInputStream();
293 0 : if ( !xInStream.is() )
294 0 : throw uno::RuntimeException();
295 :
296 0 : uno::Reference< io::XSeekable > xSeek( xStream, uno::UNO_QUERY_THROW );
297 0 : xSeek->seek( 0 );
298 :
299 0 : uno::Sequence< sal_Int8 > aData( 8 );
300 0 : sal_Int32 nRead = xInStream->readBytes( aData, 8 );
301 0 : xSeek->seek( 0 );
302 :
303 0 : if ( ( nRead >= 2 && aData[0] == 'B' && aData[1] == 'M' )
304 0 : || ( nRead >= 4 && aData[0] == 1 && aData[1] == 0 && aData[2] == 9 && aData[3] == 0 ) )
305 : {
306 : // it should be a bitmap or a Metafile
307 0 : return xStream;
308 : }
309 :
310 :
311 0 : sal_uInt32 nHeaderOffset = 0;
312 0 : if ( ( nRead >= 8 && aData[0] == -1 && aData[1] == -1 && aData[2] == -1 && aData[3] == -1 )
313 0 : && ( aData[4] == 2 || aData[4] == 3 || aData[4] == 14 ) && aData[5] == 0 && aData[6] == 0 && aData[7] == 0 )
314 : {
315 0 : nHeaderOffset = 40;
316 0 : xSeek->seek( 8 );
317 :
318 : // TargetDevice might be used in future, currently the cache has specified NULL
319 0 : uno::Sequence< sal_Int8 > aHeadData( 4 );
320 0 : nRead = xInStream->readBytes( aHeadData, 4 );
321 0 : sal_uInt32 nLen = 0;
322 0 : if ( nRead == 4 && aHeadData.getLength() == 4 )
323 0 : nLen = ( ( ( (sal_uInt32)aHeadData[3] * 0x100 + (sal_uInt32)aHeadData[2] ) * 0x100 ) + (sal_uInt32)aHeadData[1] ) * 0x100 + (sal_uInt32)aHeadData[0];
324 0 : if ( nLen > 4 )
325 : {
326 0 : xInStream->skipBytes( nLen - 4 );
327 0 : nHeaderOffset += nLen - 4;
328 0 : }
329 :
330 : }
331 0 : else if ( nRead > 4 )
332 : {
333 : // check whether the first bytes represent the size
334 0 : sal_uInt32 nSize = 0;
335 0 : for ( sal_Int32 nInd = 3; nInd >= 0; nInd-- )
336 0 : nSize = ( nSize << 8 ) + (sal_uInt8)aData[nInd];
337 :
338 0 : if ( nSize == xSeek->getLength() - 4 )
339 0 : nHeaderOffset = 4;
340 : }
341 :
342 0 : if ( nHeaderOffset )
343 : {
344 : // this is either a bitmap or a metafile clipboard format, retrieve the pure stream
345 : uno::Reference < io::XStream > xResult(
346 : io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
347 0 : uno::UNO_QUERY_THROW );
348 0 : uno::Reference < io::XSeekable > xResultSeek( xResult, uno::UNO_QUERY_THROW );
349 0 : uno::Reference < io::XOutputStream > xResultOut = xResult->getOutputStream();
350 0 : uno::Reference < io::XInputStream > xResultIn = xResult->getInputStream();
351 0 : if ( !xResultOut.is() || !xResultIn.is() )
352 0 : throw uno::RuntimeException();
353 :
354 0 : xSeek->seek( nHeaderOffset ); // header size for these formats
355 0 : ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xResultOut );
356 0 : xResultOut->closeOutput();
357 0 : xResultSeek->seek( 0 );
358 0 : xSeek->seek( 0 );
359 :
360 0 : return xResult;
361 : }
362 :
363 0 : return uno::Reference< io::XStream >();
364 : }
365 :
366 : //------------------------------------------------------
367 0 : void OleEmbeddedObject::InsertVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream,
368 : const uno::Reference< io::XStream >& xCachedVisualRepresentation )
369 : throw ( uno::Exception )
370 : {
371 : OSL_ENSURE( xTargetStream.is() && xCachedVisualRepresentation.is(), "Invalid argumants!\n" );
372 :
373 0 : if ( !xTargetStream.is() || !xCachedVisualRepresentation.is() )
374 0 : throw uno::RuntimeException();
375 :
376 0 : uno::Sequence< uno::Any > aArgs( 2 );
377 0 : aArgs[0] <<= xTargetStream;
378 0 : aArgs[1] <<= (sal_Bool)sal_True; // do not create copy
379 :
380 : uno::Reference< container::XNameContainer > xNameContainer(
381 0 : m_xFactory->createInstanceWithArguments(
382 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.OLESimpleStorage" )),
383 0 : aArgs ),
384 0 : uno::UNO_QUERY );
385 :
386 0 : if ( !xNameContainer.is() )
387 0 : throw uno::RuntimeException();
388 :
389 0 : uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY_THROW );
390 0 : if ( xCachedSeek.is() )
391 0 : xCachedSeek->seek( 0 );
392 :
393 : uno::Reference < io::XStream > xTempFile(
394 : io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
395 0 : uno::UNO_QUERY_THROW );
396 :
397 0 : uno::Reference< io::XSeekable > xTempSeek( xTempFile, uno::UNO_QUERY_THROW );
398 0 : uno::Reference< io::XOutputStream > xTempOutStream = xTempFile->getOutputStream();
399 0 : if ( xTempOutStream.is() )
400 : {
401 : // the OlePres stream must have additional header
402 : // TODO/LATER: might need to be extended in future ( actually makes sence only for SO7 format )
403 0 : uno::Reference< io::XInputStream > xInCacheStream = xCachedVisualRepresentation->getInputStream();
404 0 : if ( !xInCacheStream.is() )
405 0 : throw uno::RuntimeException();
406 :
407 : // write 0xFFFFFFFF at the beginning
408 0 : uno::Sequence< sal_Int8 > aData( 4 );
409 0 : *( (sal_uInt32*)aData.getArray() ) = 0xFFFFFFFF;
410 :
411 0 : xTempOutStream->writeBytes( aData );
412 :
413 : // write clipboard format
414 0 : uno::Sequence< sal_Int8 > aSigData( 2 );
415 0 : xInCacheStream->readBytes( aSigData, 2 );
416 0 : if ( aSigData.getLength() < 2 )
417 0 : throw io::IOException();
418 :
419 0 : if ( aSigData[0] == 'B' && aSigData[1] == 'M' )
420 : {
421 : // it's a bitmap
422 0 : aData[0] = 0x02; aData[1] = 0; aData[2] = 0; aData[3] = 0;
423 : }
424 : else
425 : {
426 : // treat it as a metafile
427 0 : aData[0] = 0x03; aData[1] = 0; aData[2] = 0; aData[3] = 0;
428 : }
429 0 : xTempOutStream->writeBytes( aData );
430 :
431 : // write job related information
432 0 : aData[0] = 0x04; aData[1] = 0; aData[2] = 0; aData[3] = 0;
433 0 : xTempOutStream->writeBytes( aData );
434 :
435 : // write aspect
436 0 : aData[0] = 0x01; aData[1] = 0; aData[2] = 0; aData[3] = 0;
437 0 : xTempOutStream->writeBytes( aData );
438 :
439 : // write l-index
440 0 : *( (sal_uInt32*)aData.getArray() ) = 0xFFFFFFFF;
441 0 : xTempOutStream->writeBytes( aData );
442 :
443 : // write adv. flags
444 0 : aData[0] = 0x02; aData[1] = 0; aData[2] = 0; aData[3] = 0;
445 0 : xTempOutStream->writeBytes( aData );
446 :
447 : // write compression
448 0 : *( (sal_uInt32*)aData.getArray() ) = 0x0;
449 0 : xTempOutStream->writeBytes( aData );
450 :
451 : // get the size
452 0 : awt::Size aSize = getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
453 0 : sal_Int32 nIndex = 0;
454 :
455 : // write width
456 0 : for ( nIndex = 0; nIndex < 4; nIndex++ )
457 : {
458 0 : aData[nIndex] = (sal_Int8)( aSize.Width % 0x100 );
459 0 : aSize.Width /= 0x100;
460 : }
461 0 : xTempOutStream->writeBytes( aData );
462 :
463 : // write height
464 0 : for ( nIndex = 0; nIndex < 4; nIndex++ )
465 : {
466 0 : aData[nIndex] = (sal_Int8)( aSize.Height % 0x100 );
467 0 : aSize.Height /= 0x100;
468 : }
469 0 : xTempOutStream->writeBytes( aData );
470 :
471 : // write garbage, it will be overwritten by the size
472 0 : xTempOutStream->writeBytes( aData );
473 :
474 : // write first bytes that was used to detect the type
475 0 : xTempOutStream->writeBytes( aSigData );
476 :
477 : // write the rest of the stream
478 0 : ::comphelper::OStorageHelper::CopyInputToOutput( xInCacheStream, xTempOutStream );
479 :
480 : // write the size of the stream
481 0 : sal_Int64 nLength = xTempSeek->getLength() - 40;
482 0 : if ( nLength < 0 || nLength >= 0xFFFFFFFF )
483 : {
484 : OSL_FAIL( "Length is not acceptable!" );
485 0 : return;
486 : }
487 0 : for ( sal_Int32 nInd = 0; nInd < 4; nInd++ )
488 : {
489 0 : aData[nInd] = (sal_Int8)( ( (sal_uInt64) nLength ) % 0x100 );
490 0 : nLength /= 0x100;
491 : }
492 0 : xTempSeek->seek( 36 );
493 0 : xTempOutStream->writeBytes( aData );
494 :
495 0 : xTempOutStream->flush();
496 :
497 0 : xTempSeek->seek( 0 );
498 0 : if ( xCachedSeek.is() )
499 0 : xCachedSeek->seek( 0 );
500 : }
501 : else
502 0 : throw io::IOException(); // TODO:
503 :
504 : // insert the result file as replacement image
505 0 : ::rtl::OUString aCacheName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "\002OlePres000" ));
506 0 : if ( xNameContainer->hasByName( aCacheName ) )
507 0 : xNameContainer->replaceByName( aCacheName, uno::makeAny( xTempFile ) );
508 : else
509 0 : xNameContainer->insertByName( aCacheName, uno::makeAny( xTempFile ) );
510 :
511 0 : uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY );
512 0 : if ( !xTransacted.is() )
513 0 : throw uno::RuntimeException();
514 :
515 0 : xTransacted->commit();
516 : }
517 :
518 : //------------------------------------------------------
519 0 : void OleEmbeddedObject::RemoveVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream )
520 : throw ( uno::Exception )
521 : {
522 : OSL_ENSURE( xTargetStream.is(), "Invalid argumant!\n" );
523 0 : if ( !xTargetStream.is() )
524 0 : throw uno::RuntimeException();
525 :
526 0 : uno::Sequence< uno::Any > aArgs( 2 );
527 0 : aArgs[0] <<= xTargetStream;
528 0 : aArgs[1] <<= (sal_Bool)sal_True; // do not create copy
529 : uno::Reference< container::XNameContainer > xNameContainer(
530 0 : m_xFactory->createInstanceWithArguments(
531 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.OLESimpleStorage" )),
532 0 : aArgs ),
533 0 : uno::UNO_QUERY );
534 :
535 0 : if ( !xNameContainer.is() )
536 0 : throw uno::RuntimeException();
537 :
538 0 : for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
539 : {
540 0 : ::rtl::OUString aStreamName(RTL_CONSTASCII_USTRINGPARAM( "\002OlePres00" ));
541 0 : aStreamName += ::rtl::OUString::valueOf( (sal_Int32)nInd );
542 0 : if ( xNameContainer->hasByName( aStreamName ) )
543 0 : xNameContainer->removeByName( aStreamName );
544 0 : }
545 :
546 0 : uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY );
547 0 : if ( !xTransacted.is() )
548 0 : throw uno::RuntimeException();
549 :
550 0 : xTransacted->commit();
551 0 : }
552 :
553 : //------------------------------------------------------
554 0 : void OleEmbeddedObject::SetVisReplInStream( sal_Bool bExists )
555 : {
556 0 : m_bVisReplInitialized = sal_True;
557 0 : m_bVisReplInStream = bExists;
558 0 : }
559 :
560 : //------------------------------------------------------
561 0 : sal_Bool OleEmbeddedObject::HasVisReplInStream()
562 : {
563 0 : if ( !m_bVisReplInitialized )
564 : {
565 0 : if ( m_xCachedVisualRepresentation.is() )
566 0 : SetVisReplInStream( sal_True );
567 : else
568 : {
569 : RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::HasVisualReplInStream, analizing" );
570 :
571 0 : uno::Reference< io::XInputStream > xStream;
572 :
573 : OSL_ENSURE( !m_pOleComponent || !m_aTempURL.isEmpty(), "The temporary file must exist if there is a component!\n" );
574 0 : if ( !m_aTempURL.isEmpty() )
575 : {
576 : try
577 : {
578 : // open temporary file for reading
579 : uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
580 0 : ucb::SimpleFileAccess::create( comphelper::getComponentContext(m_xFactory) ) );
581 :
582 0 : xStream = xTempAccess->openFileRead( m_aTempURL );
583 : }
584 0 : catch( const uno::Exception& )
585 : {}
586 : }
587 :
588 0 : if ( !xStream.is() )
589 0 : xStream = m_xObjectStream->getInputStream();
590 :
591 0 : if ( xStream.is() )
592 : {
593 0 : sal_Bool bExists = sal_False;
594 :
595 0 : uno::Sequence< uno::Any > aArgs( 2 );
596 0 : aArgs[0] <<= xStream;
597 0 : aArgs[1] <<= (sal_Bool)sal_True; // do not create copy
598 : uno::Reference< container::XNameContainer > xNameContainer(
599 0 : m_xFactory->createInstanceWithArguments(
600 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.OLESimpleStorage" )),
601 0 : aArgs ),
602 0 : uno::UNO_QUERY );
603 :
604 0 : if ( xNameContainer.is() )
605 : {
606 0 : for ( sal_uInt8 nInd = 0; nInd < 10 && !bExists; nInd++ )
607 : {
608 0 : ::rtl::OUString aStreamName(RTL_CONSTASCII_USTRINGPARAM( "\002OlePres00" ));
609 0 : aStreamName += ::rtl::OUString::valueOf( (sal_Int32)nInd );
610 : try
611 : {
612 0 : bExists = xNameContainer->hasByName( aStreamName );
613 : }
614 0 : catch( const uno::Exception& )
615 : {}
616 0 : }
617 : }
618 :
619 0 : SetVisReplInStream( bExists );
620 0 : }
621 : }
622 : }
623 :
624 0 : return m_bVisReplInStream;
625 : }
626 :
627 : //------------------------------------------------------
628 0 : uno::Reference< io::XStream > OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation_Impl(
629 : const uno::Reference< io::XStream >& xStream,
630 : sal_Bool bAllowToRepair50 )
631 : throw ()
632 : {
633 0 : uno::Reference< io::XStream > xResult;
634 :
635 0 : if ( xStream.is() )
636 : {
637 : RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation, retrieving" );
638 :
639 0 : uno::Reference< container::XNameContainer > xNameContainer;
640 0 : uno::Sequence< uno::Any > aArgs( 2 );
641 0 : aArgs[0] <<= xStream;
642 0 : aArgs[1] <<= (sal_Bool)sal_True; // do not create copy
643 : try
644 : {
645 : xNameContainer = uno::Reference< container::XNameContainer >(
646 0 : m_xFactory->createInstanceWithArguments(
647 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.OLESimpleStorage" )),
648 0 : aArgs ),
649 0 : uno::UNO_QUERY );
650 : }
651 0 : catch( const uno::Exception& )
652 : {}
653 :
654 0 : if ( xNameContainer.is() )
655 : {
656 0 : for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
657 : {
658 0 : ::rtl::OUString aStreamName(RTL_CONSTASCII_USTRINGPARAM( "\002OlePres00" ));
659 0 : aStreamName += ::rtl::OUString::valueOf( (sal_Int32)nInd );
660 0 : uno::Reference< io::XStream > xCachedCopyStream;
661 : try
662 : {
663 0 : if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
664 : {
665 0 : xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
666 0 : if ( xResult.is() )
667 : break;
668 : }
669 : }
670 0 : catch( const uno::Exception& )
671 : {}
672 :
673 0 : if ( nInd == 0 )
674 : {
675 : // to be compatible with the old versions Ole10Native is checked after OlePress000
676 0 : aStreamName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "\001Ole10Native" ) );
677 : try
678 : {
679 0 : if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
680 : {
681 0 : xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
682 0 : if ( xResult.is() )
683 : break;
684 : }
685 : }
686 0 : catch( const uno::Exception& )
687 : {}
688 : }
689 0 : }
690 :
691 : try
692 : {
693 0 : if ( bAllowToRepair50 && !xResult.is() )
694 : {
695 0 : ::rtl::OUString aOrigContName( RTL_CONSTASCII_USTRINGPARAM( "Ole-Object" ) );
696 0 : if ( xNameContainer->hasByName( aOrigContName ) )
697 : {
698 0 : uno::Reference< embed::XClassifiedObject > xClassified( xNameContainer, uno::UNO_QUERY_THROW );
699 0 : uno::Sequence< sal_Int8 > aClassID;
700 0 : if ( MimeConfigurationHelper::ClassIDsEqual( xClassified->getClassID(), MimeConfigurationHelper::GetSequenceClassID( SO3_OUT_CLASSID ) ) )
701 : {
702 : // this is an OLE object wrongly stored in 5.0 format
703 : // this object must be repaired since SO7 has done it
704 :
705 0 : uno::Reference< io::XOutputStream > xOutputStream = xStream->getOutputStream();
706 0 : uno::Reference< io::XTruncate > xTruncate( xOutputStream, uno::UNO_QUERY_THROW );
707 :
708 0 : uno::Reference< io::XInputStream > xOrigInputStream;
709 0 : if ( ( xNameContainer->getByName( aOrigContName ) >>= xOrigInputStream )
710 0 : && xOrigInputStream.is() )
711 : {
712 : // the provided input stream must be based on temporary medium and must be independent
713 : // from the stream the storage is based on
714 0 : uno::Reference< io::XSeekable > xOrigSeekable( xOrigInputStream, uno::UNO_QUERY );
715 0 : if ( xOrigSeekable.is() )
716 0 : xOrigSeekable->seek( 0 );
717 :
718 0 : uno::Reference< lang::XComponent > xNameContDisp( xNameContainer, uno::UNO_QUERY_THROW );
719 0 : xNameContDisp->dispose(); // free the original stream
720 :
721 0 : xTruncate->truncate();
722 0 : ::comphelper::OStorageHelper::CopyInputToOutput( xOrigInputStream, xOutputStream );
723 0 : xOutputStream->flush();
724 :
725 0 : if ( xStream == m_xObjectStream )
726 : {
727 0 : if ( !m_aTempURL.isEmpty() )
728 : {
729 : // this is the own stream, so the temporary URL must be cleaned if it exists
730 0 : KillFile_Impl( m_aTempURL, m_xFactory );
731 0 : m_aTempURL = ::rtl::OUString();
732 : }
733 :
734 : #ifdef WNT
735 : // retry to create the component after recovering
736 : GetRidOfComponent();
737 :
738 : try
739 : {
740 : CreateOleComponentAndLoad_Impl( NULL );
741 : m_aClassID = m_pOleComponent->GetCLSID(); // was not set during consruction
742 : }
743 : catch( const uno::Exception& )
744 : {
745 : GetRidOfComponent();
746 : }
747 : #endif
748 : }
749 :
750 0 : xResult = TryToRetrieveCachedVisualRepresentation_Impl( xStream, sal_False );
751 0 : }
752 0 : }
753 0 : }
754 : }
755 : }
756 0 : catch( const uno::Exception& )
757 : {}
758 0 : }
759 : }
760 :
761 0 : return xResult;
762 : }
763 :
764 : //------------------------------------------------------
765 0 : void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
766 : const uno::Reference< io::XStream >& xNewObjectStream,
767 : const ::rtl::OUString& aNewName )
768 : {
769 0 : if ( xNewParentStorage == m_xParentStorage && aNewName.equals( m_aEntryName ) )
770 : {
771 : OSL_ENSURE( xNewObjectStream == m_xObjectStream, "The streams must be the same!\n" );
772 0 : return;
773 : }
774 :
775 : try {
776 0 : uno::Reference< lang::XComponent > xComponent( m_xObjectStream, uno::UNO_QUERY );
777 : OSL_ENSURE( !m_xObjectStream.is() || xComponent.is(), "Wrong stream implementation!" );
778 0 : if ( xComponent.is() )
779 0 : xComponent->dispose();
780 : }
781 0 : catch ( const uno::Exception& )
782 : {
783 : }
784 :
785 0 : m_xObjectStream = xNewObjectStream;
786 0 : m_xParentStorage = xNewParentStorage;
787 0 : m_aEntryName = aNewName;
788 : }
789 :
790 : //------------------------------------------------------
791 0 : void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
792 : const ::rtl::OUString& aNewName )
793 : {
794 0 : if ( xNewParentStorage == m_xParentStorage && aNewName.equals( m_aEntryName ) )
795 0 : return;
796 :
797 0 : sal_Int32 nStreamMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
798 :
799 0 : uno::Reference< io::XStream > xNewOwnStream = xNewParentStorage->openStreamElement( aNewName, nStreamMode );
800 : OSL_ENSURE( xNewOwnStream.is(), "The method can not return empty reference!" );
801 :
802 0 : SwitchOwnPersistence( xNewParentStorage, xNewOwnStream, aNewName );
803 : }
804 :
805 : #ifdef WNT
806 : //----------------------------------------------
807 : sal_Bool OleEmbeddedObject::SaveObject_Impl()
808 : {
809 : sal_Bool bResult = sal_False;
810 :
811 : if ( m_xClientSite.is() )
812 : {
813 : try
814 : {
815 : m_xClientSite->saveObject();
816 : bResult = sal_True;
817 : }
818 : catch( const uno::Exception& )
819 : {
820 : }
821 : }
822 :
823 : return bResult;
824 : }
825 :
826 : //----------------------------------------------
827 : sal_Bool OleEmbeddedObject::OnShowWindow_Impl( sal_Bool bShow )
828 : {
829 : ::osl::ResettableMutexGuard aGuard( m_aMutex );
830 :
831 : sal_Bool bResult = sal_False;
832 :
833 : OSL_ENSURE( m_nObjectState != -1, "The object has no persistence!\n" );
834 : OSL_ENSURE( m_nObjectState != embed::EmbedStates::LOADED, "The object get OnShowWindow in loaded state!\n" );
835 : if ( m_nObjectState == -1 || m_nObjectState == embed::EmbedStates::LOADED )
836 : return sal_False;
837 :
838 : // the object is either activated or deactivated
839 : sal_Int32 nOldState = m_nObjectState;
840 : if ( bShow && m_nObjectState == embed::EmbedStates::RUNNING )
841 : {
842 : m_nObjectState = embed::EmbedStates::ACTIVE;
843 : m_aVerbExecutionController.ObjectIsActive();
844 :
845 : aGuard.clear();
846 : StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
847 : }
848 : else if ( !bShow && m_nObjectState == embed::EmbedStates::ACTIVE )
849 : {
850 : m_nObjectState = embed::EmbedStates::RUNNING;
851 : aGuard.clear();
852 : StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
853 : }
854 :
855 : if ( m_xClientSite.is() )
856 : {
857 : try
858 : {
859 : m_xClientSite->visibilityChanged( bShow );
860 : bResult = sal_True;
861 : }
862 : catch( const uno::Exception& )
863 : {
864 : }
865 : }
866 :
867 : return bResult;
868 : }
869 :
870 : //------------------------------------------------------
871 : void OleEmbeddedObject::OnIconChanged_Impl()
872 : {
873 : // TODO/LATER: currently this notification seems to be impossible
874 : // MakeEventListenerNotification_Impl( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "OnIconChanged" )) );
875 : }
876 :
877 : //------------------------------------------------------
878 : void OleEmbeddedObject::OnViewChanged_Impl()
879 : {
880 : if ( m_bDisposed )
881 : throw lang::DisposedException();
882 :
883 : // For performance reasons the notification currently is ignored, STAMPIT object is the exception,
884 : // it can never be active and never call SaveObject, so it is the only way to detect that it is changed
885 :
886 : // ==== the STAMPIT related solution =============================
887 : // the following variable is used to detect whether the object was modified during verb execution
888 : m_aVerbExecutionController.ModificationNotificationIsDone();
889 :
890 : // The following things are controlled by VerbExecutionController:
891 : // - if the verb execution is in progress and the view is changed the object will be stored
892 : // after the execution, so there is no need to send the notification.
893 : // - the STAMPIT object can never be active.
894 : if ( m_aVerbExecutionController.CanDoNotification()
895 : && m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
896 : {
897 : OSL_ENSURE( MimeConfigurationHelper::ClassIDsEqual( m_aClassID, MimeConfigurationHelper::GetSequenceClassID( 0x852ee1c9, 0x9058, 0x44ba, 0x8c,0x6c,0x0c,0x5f,0xc6,0x6b,0xdb,0x8d ) )
898 : || MimeConfigurationHelper::ClassIDsEqual( m_aClassID, MimeConfigurationHelper::GetSequenceClassID( 0xcf1b4491, 0xbea3, 0x4c9f, 0xa7,0x0f,0x22,0x1b,0x1e,0xca,0xef,0x3e ) ),
899 : "Expected to be triggered for STAMPIT only! Please contact developers!\n" );
900 :
901 : // The view is changed while the object is in running state, save the new object
902 : m_xCachedVisualRepresentation = uno::Reference< io::XStream >();
903 : SaveObject_Impl();
904 : MakeEventListenerNotification_Impl( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "OnVisAreaChanged" )) );
905 : }
906 : // ===============================================================
907 : }
908 :
909 : //------------------------------------------------------
910 : void OleEmbeddedObject::OnClosed_Impl()
911 : {
912 : if ( m_bDisposed )
913 : throw lang::DisposedException();
914 :
915 : if ( m_nObjectState != embed::EmbedStates::LOADED )
916 : {
917 : sal_Int32 nOldState = m_nObjectState;
918 : m_nObjectState = embed::EmbedStates::LOADED;
919 : StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
920 : }
921 : }
922 :
923 : //------------------------------------------------------
924 : ::rtl::OUString OleEmbeddedObject::CreateTempURLEmpty_Impl()
925 : {
926 : OSL_ENSURE( m_aTempURL.isEmpty(), "The object has already the temporary file!" );
927 : m_aTempURL = GetNewTempFileURL_Impl( m_xFactory );
928 :
929 : return m_aTempURL;
930 : }
931 :
932 : //------------------------------------------------------
933 : ::rtl::OUString OleEmbeddedObject::GetTempURL_Impl()
934 : {
935 : if ( m_aTempURL.isEmpty() )
936 : {
937 : RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::GetTempURL_Impl, tempfile creation" );
938 :
939 : // if there is no temporary file, it will be created from the own entry
940 : uno::Reference< embed::XOptimizedStorage > xOptParStorage( m_xParentStorage, uno::UNO_QUERY );
941 : if ( xOptParStorage.is() )
942 : {
943 : m_aTempURL = GetNewFilledTempFile_Impl( xOptParStorage, m_aEntryName, m_xFactory );
944 : }
945 : else if ( m_xObjectStream.is() )
946 : {
947 : // load object from the stream
948 : uno::Reference< io::XInputStream > xInStream = m_xObjectStream->getInputStream();
949 : if ( !xInStream.is() )
950 : throw io::IOException(); // TODO: access denied
951 :
952 : m_aTempURL = GetNewFilledTempFile_Impl( xInStream, m_xFactory );
953 : }
954 : }
955 :
956 : return m_aTempURL;
957 : }
958 :
959 : //------------------------------------------------------
960 : void OleEmbeddedObject::CreateOleComponent_Impl( OleComponent* pOleComponent )
961 : {
962 : if ( !m_pOleComponent )
963 : {
964 : m_pOleComponent = pOleComponent ? pOleComponent : new OleComponent( m_xFactory, this );
965 : m_pOleComponent->acquire(); // TODO: needs holder?
966 :
967 : if ( !m_xClosePreventer.is() )
968 : m_xClosePreventer = uno::Reference< util::XCloseListener >(
969 : static_cast< ::cppu::OWeakObject* >( new OClosePreventer ),
970 : uno::UNO_QUERY );
971 :
972 : m_pOleComponent->addCloseListener( m_xClosePreventer );
973 : }
974 : }
975 :
976 : //------------------------------------------------------
977 : void OleEmbeddedObject::CreateOleComponentAndLoad_Impl( OleComponent* pOleComponent )
978 : {
979 : if ( !m_pOleComponent )
980 : {
981 : if ( !m_xObjectStream.is() )
982 : throw uno::RuntimeException();
983 :
984 : CreateOleComponent_Impl( pOleComponent );
985 :
986 : // after the loading the object can appear as a link
987 : // will be detected later by olecomponent
988 :
989 : GetTempURL_Impl();
990 : if ( m_aTempURL.isEmpty() )
991 : throw uno::RuntimeException(); // TODO
992 :
993 : m_pOleComponent->LoadEmbeddedObject( m_aTempURL );
994 : }
995 : }
996 :
997 : //------------------------------------------------------
998 : void OleEmbeddedObject::CreateOleComponentFromClipboard_Impl( OleComponent* pOleComponent )
999 : {
1000 : if ( !m_pOleComponent )
1001 : {
1002 : if ( !m_xObjectStream.is() )
1003 : throw uno::RuntimeException();
1004 :
1005 : CreateOleComponent_Impl( pOleComponent );
1006 :
1007 : // after the loading the object can appear as a link
1008 : // will be detected later by olecomponent
1009 : m_pOleComponent->CreateObjectFromClipboard();
1010 : }
1011 : }
1012 :
1013 : //------------------------------------------------------
1014 : uno::Reference< io::XOutputStream > OleEmbeddedObject::GetStreamForSaving()
1015 : {
1016 : if ( !m_xObjectStream.is() )
1017 : throw uno::RuntimeException(); //TODO:
1018 :
1019 : uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
1020 : if ( !xOutStream.is() )
1021 : throw io::IOException(); //TODO: access denied
1022 :
1023 : uno::Reference< io::XTruncate > xTruncate( xOutStream, uno::UNO_QUERY );
1024 : if ( !xTruncate.is() )
1025 : throw uno::RuntimeException(); //TODO:
1026 :
1027 : xTruncate->truncate();
1028 :
1029 : return xOutStream;
1030 : }
1031 :
1032 : //----------------------------------------------
1033 : void OleEmbeddedObject::StoreObjectToStream( uno::Reference< io::XOutputStream > xOutStream )
1034 : throw ( uno::Exception )
1035 : {
1036 : // this method should be used only on windows
1037 : if ( m_pOleComponent )
1038 : m_pOleComponent->StoreOwnTmpIfNecessary();
1039 :
1040 : // now all the changes should be in temporary location
1041 : if ( m_aTempURL.isEmpty() )
1042 : throw uno::RuntimeException();
1043 :
1044 : // open temporary file for reading
1045 : uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
1046 : ucb::SimpleFileAccess::create( comphelper::getComponentContext(m_xFactory) ) );
1047 :
1048 : uno::Reference< io::XInputStream > xTempInStream = xTempAccess->openFileRead( m_aTempURL );
1049 : OSL_ENSURE( xTempInStream.is(), "The object's temporary file can not be reopened for reading!\n" );
1050 :
1051 : // TODO: use bStoreVisReplace
1052 :
1053 : if ( xTempInStream.is() )
1054 : {
1055 : // write all the contents to XOutStream
1056 : uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY );
1057 : if ( !xTrunc.is() )
1058 : throw uno::RuntimeException(); //TODO:
1059 :
1060 : xTrunc->truncate();
1061 :
1062 : ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutStream );
1063 : }
1064 : else
1065 : throw io::IOException(); // TODO:
1066 :
1067 : // TODO: should the view replacement be in the stream ???
1068 : // probably it must be specified on storing
1069 : }
1070 : #endif
1071 : //------------------------------------------------------
1072 0 : void OleEmbeddedObject::StoreToLocation_Impl(
1073 : const uno::Reference< embed::XStorage >& xStorage,
1074 : const ::rtl::OUString& sEntName,
1075 : const uno::Sequence< beans::PropertyValue >& lObjArgs,
1076 : sal_Bool bSaveAs )
1077 : throw ( uno::Exception )
1078 : {
1079 : // TODO: use lObjArgs
1080 : // TODO: exchange StoreVisualReplacement by SO file format version?
1081 :
1082 0 : if ( m_nObjectState == -1 )
1083 : {
1084 : // the object is still not loaded
1085 : throw embed::WrongStateException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Can't store object without persistence!\n" )),
1086 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1087 : }
1088 :
1089 0 : if ( m_bWaitSaveCompleted )
1090 : throw embed::WrongStateException(
1091 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
1092 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1093 :
1094 : OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!\n" );
1095 :
1096 0 : sal_Bool bVisReplIsStored = sal_False;
1097 :
1098 0 : sal_Bool bTryOptimization = sal_False;
1099 0 : sal_Bool bStoreVis = m_bStoreVisRepl;
1100 0 : uno::Reference< io::XStream > xCachedVisualRepresentation;
1101 0 : for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1102 : {
1103 0 : if ( lObjArgs[nInd].Name == "StoreVisualReplacement" )
1104 0 : lObjArgs[nInd].Value >>= bStoreVis;
1105 0 : else if ( lObjArgs[nInd].Name == "VisualReplacement" )
1106 0 : lObjArgs[nInd].Value >>= xCachedVisualRepresentation;
1107 0 : else if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1108 0 : lObjArgs[nInd].Value >>= bTryOptimization;
1109 : }
1110 :
1111 : // ignore visual representation provided from outside if it should not be stored
1112 0 : if ( !bStoreVis )
1113 0 : xCachedVisualRepresentation = uno::Reference< io::XStream >();
1114 :
1115 0 : if ( bStoreVis && !HasVisReplInStream() && !xCachedVisualRepresentation.is() )
1116 0 : throw io::IOException(); // TODO: there is no cached visual representation and nothing is provided from outside
1117 :
1118 : // if the representation is provided from outside it should be copied to a local stream
1119 0 : sal_Bool bNeedLocalCache = xCachedVisualRepresentation.is();
1120 :
1121 0 : uno::Reference< io::XStream > xTargetStream;
1122 :
1123 0 : sal_Bool bStoreLoaded = sal_False;
1124 0 : if ( m_nObjectState == embed::EmbedStates::LOADED
1125 : #ifdef WNT
1126 : // if the object was NOT modified after storing it can be just copied
1127 : // as if it was in loaded state
1128 : || ( m_pOleComponent && !m_pOleComponent->IsDirty() )
1129 : #endif
1130 : )
1131 : {
1132 0 : sal_Bool bOptimizedCopyingDone = sal_False;
1133 :
1134 0 : if ( bTryOptimization && bStoreVis == HasVisReplInStream() )
1135 : {
1136 : try
1137 : {
1138 0 : uno::Reference< embed::XOptimizedStorage > xSourceOptStor( m_xParentStorage, uno::UNO_QUERY_THROW );
1139 0 : uno::Reference< embed::XOptimizedStorage > xTargetOptStor( xStorage, uno::UNO_QUERY_THROW );
1140 0 : xSourceOptStor->copyElementDirectlyTo( m_aEntryName, xTargetOptStor, sEntName );
1141 0 : bOptimizedCopyingDone = sal_True;
1142 : }
1143 0 : catch( const uno::Exception& )
1144 : {
1145 : }
1146 : }
1147 :
1148 0 : if ( !bOptimizedCopyingDone )
1149 : {
1150 : // if optimized copying fails a normal one should be tried
1151 0 : m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1152 : }
1153 :
1154 : // the locally retrieved representation is always preferable
1155 : // since the object is in loaded state the representation is unchanged
1156 0 : if ( m_xCachedVisualRepresentation.is() )
1157 : {
1158 0 : xCachedVisualRepresentation = m_xCachedVisualRepresentation;
1159 0 : bNeedLocalCache = sal_False;
1160 : }
1161 :
1162 0 : bVisReplIsStored = HasVisReplInStream();
1163 0 : bStoreLoaded = sal_True;
1164 : }
1165 : #ifdef WNT
1166 : else if ( m_pOleComponent )
1167 : {
1168 : xTargetStream =
1169 : xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
1170 : if ( !xTargetStream.is() )
1171 : throw io::IOException(); //TODO: access denied
1172 :
1173 : SetStreamMediaType_Impl( xTargetStream, ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.oleobject" ) ));
1174 : uno::Reference< io::XOutputStream > xOutStream = xTargetStream->getOutputStream();
1175 : if ( !xOutStream.is() )
1176 : throw io::IOException(); //TODO: access denied
1177 :
1178 : StoreObjectToStream( xOutStream );
1179 : bVisReplIsStored = sal_True;
1180 :
1181 : if ( bSaveAs )
1182 : {
1183 : // no need to do it on StoreTo since in this case the replacement is in the stream
1184 : // and there is no need to cache it even if it is thrown away because the object
1185 : // is not changed by StoreTo action
1186 :
1187 : uno::Reference< io::XStream > xTmpCVRepresentation =
1188 : TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
1189 :
1190 : // the locally retrieved representation is always preferable
1191 : if ( xTmpCVRepresentation.is() )
1192 : {
1193 : xCachedVisualRepresentation = xTmpCVRepresentation;
1194 : bNeedLocalCache = sal_False;
1195 : }
1196 : }
1197 : }
1198 : #endif
1199 : else
1200 : {
1201 0 : throw io::IOException(); // TODO
1202 : }
1203 :
1204 0 : if ( !xTargetStream.is() )
1205 : {
1206 : xTargetStream =
1207 0 : xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
1208 0 : if ( !xTargetStream.is() )
1209 0 : throw io::IOException(); //TODO: access denied
1210 : }
1211 :
1212 0 : LetCommonStoragePassBeUsed_Impl( xTargetStream );
1213 :
1214 0 : if ( bStoreVis != bVisReplIsStored )
1215 : {
1216 0 : if ( bStoreVis )
1217 : {
1218 0 : if ( !xCachedVisualRepresentation.is() )
1219 0 : xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
1220 :
1221 : OSL_ENSURE( xCachedVisualRepresentation.is(), "No representation is available!" );
1222 :
1223 : // the following copying will be done in case it is SaveAs anyway
1224 : // if it is not SaveAs the seekable access is not required currently
1225 : // TODO/LATER: may be required in future
1226 0 : if ( bSaveAs )
1227 : {
1228 0 : uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY );
1229 0 : if ( !xCachedSeek.is() )
1230 : {
1231 : xCachedVisualRepresentation
1232 0 : = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
1233 0 : bNeedLocalCache = sal_False;
1234 0 : }
1235 : }
1236 :
1237 0 : InsertVisualCache_Impl( xTargetStream, xCachedVisualRepresentation );
1238 : }
1239 : else
1240 : {
1241 : // the removed representation could be cached by this method
1242 0 : if ( !xCachedVisualRepresentation.is() )
1243 0 : xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
1244 :
1245 0 : RemoveVisualCache_Impl( xTargetStream );
1246 : }
1247 : }
1248 :
1249 0 : if ( bSaveAs )
1250 : {
1251 0 : m_bWaitSaveCompleted = sal_True;
1252 0 : m_xNewObjectStream = xTargetStream;
1253 0 : m_xNewParentStorage = xStorage;
1254 0 : m_aNewEntryName = sEntName;
1255 0 : m_bNewVisReplInStream = bStoreVis;
1256 0 : m_bStoreLoaded = bStoreLoaded;
1257 :
1258 0 : if ( xCachedVisualRepresentation.is() )
1259 : {
1260 0 : if ( bNeedLocalCache )
1261 0 : m_xNewCachedVisRepl = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
1262 : else
1263 0 : m_xNewCachedVisRepl = xCachedVisualRepresentation;
1264 : }
1265 :
1266 : // TODO: register listeners for storages above, in case they are disposed
1267 : // an exception will be thrown on saveCompleted( true )
1268 : }
1269 : else
1270 : {
1271 0 : uno::Reference< lang::XComponent > xComp( xTargetStream, uno::UNO_QUERY );
1272 0 : if ( xComp.is() )
1273 : {
1274 : try {
1275 0 : xComp->dispose();
1276 0 : } catch( const uno::Exception& )
1277 : {
1278 : }
1279 0 : }
1280 0 : }
1281 0 : }
1282 :
1283 : //------------------------------------------------------
1284 0 : void SAL_CALL OleEmbeddedObject::setPersistentEntry(
1285 : const uno::Reference< embed::XStorage >& xStorage,
1286 : const ::rtl::OUString& sEntName,
1287 : sal_Int32 nEntryConnectionMode,
1288 : const uno::Sequence< beans::PropertyValue >& lArguments,
1289 : const uno::Sequence< beans::PropertyValue >& lObjArgs )
1290 : throw ( lang::IllegalArgumentException,
1291 : embed::WrongStateException,
1292 : io::IOException,
1293 : uno::Exception,
1294 : uno::RuntimeException )
1295 : {
1296 : RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::setPersistentEntry" );
1297 :
1298 : // begin wrapping related part ====================
1299 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1300 0 : if ( xWrappedObject.is() )
1301 : {
1302 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1303 0 : xWrappedObject->setPersistentEntry( xStorage, sEntName, nEntryConnectionMode, lArguments, lObjArgs );
1304 0 : return;
1305 : }
1306 : // end wrapping related part ====================
1307 :
1308 : // TODO: use lObjArgs
1309 :
1310 : // the type of the object must be already set
1311 : // a kind of typedetection should be done in the factory;
1312 : // the only exception is object initialized from a stream,
1313 : // the class ID will be detected from the stream
1314 :
1315 0 : ::osl::MutexGuard aGuard( m_aMutex );
1316 0 : if ( m_bDisposed )
1317 0 : throw lang::DisposedException(); // TODO
1318 :
1319 0 : if ( !xStorage.is() )
1320 : throw lang::IllegalArgumentException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "No parent storage is provided!\n" )),
1321 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1322 0 : 1 );
1323 :
1324 0 : if ( sEntName.isEmpty() )
1325 : throw lang::IllegalArgumentException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Empty element name is provided!\n" )),
1326 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1327 0 : 2 );
1328 :
1329 : // May be LOADED should be forbidden here ???
1330 0 : if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1331 : && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
1332 : {
1333 : // if the object is not loaded
1334 : // it can not get persistant representation without initialization
1335 :
1336 : // if the object is loaded
1337 : // it can switch persistant representation only without initialization
1338 :
1339 : throw embed::WrongStateException(
1340 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Can't change persistant representation of activated object!\n" )),
1341 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1342 : }
1343 :
1344 0 : if ( m_bWaitSaveCompleted )
1345 : {
1346 0 : if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1347 0 : saveCompleted( ( m_xParentStorage != xStorage || !m_aEntryName.equals( sEntName ) ) );
1348 : else
1349 : throw embed::WrongStateException(
1350 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
1351 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1352 : }
1353 :
1354 0 : uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY );
1355 0 : if ( !xNameAccess.is() )
1356 0 : throw uno::RuntimeException(); //TODO
1357 :
1358 : // detect entry existence
1359 0 : sal_Bool bElExists = xNameAccess->hasByName( sEntName );
1360 :
1361 0 : m_bReadOnly = sal_False;
1362 0 : for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1363 0 : if ( lArguments[nInd].Name == "ReadOnly" )
1364 0 : lArguments[nInd].Value >>= m_bReadOnly;
1365 :
1366 : #ifdef WNT
1367 : sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1368 : #endif
1369 :
1370 0 : SwitchOwnPersistence( xStorage, sEntName );
1371 :
1372 0 : for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1373 0 : if ( lObjArgs[nInd].Name == "StoreVisualReplacement" )
1374 0 : lObjArgs[nInd].Value >>= m_bStoreVisRepl;
1375 :
1376 : #ifdef WNT
1377 : if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1378 : {
1379 : if ( m_bFromClipboard )
1380 : {
1381 : // the object should be initialized from clipboard
1382 : // inpossibility to initialize the object means error here
1383 : CreateOleComponentFromClipboard_Impl( NULL );
1384 : m_aClassID = m_pOleComponent->GetCLSID(); // was not set during consruction
1385 : m_pOleComponent->RunObject();
1386 : m_nObjectState = embed::EmbedStates::RUNNING;
1387 : }
1388 : else if ( bElExists )
1389 : {
1390 : // load object from the stream
1391 : // after the loading the object can appear as a link
1392 : // will be detected by olecomponent
1393 : try
1394 : {
1395 : CreateOleComponentAndLoad_Impl( NULL );
1396 : m_aClassID = m_pOleComponent->GetCLSID(); // was not set during consruction
1397 : }
1398 : catch( const uno::Exception& )
1399 : {
1400 : // TODO/LATER: detect classID of the object if possible
1401 : // means that the object inprocess server could not be successfuly instantiated
1402 : GetRidOfComponent();
1403 : }
1404 :
1405 : m_nObjectState = embed::EmbedStates::LOADED;
1406 : }
1407 : else
1408 : {
1409 : // create a new object
1410 : CreateOleComponent_Impl();
1411 : m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
1412 : m_pOleComponent->RunObject();
1413 : m_nObjectState = embed::EmbedStates::RUNNING;
1414 : }
1415 : }
1416 : else
1417 : {
1418 : if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1419 : throw io::IOException();
1420 :
1421 : if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1422 : {
1423 : // the document just already changed its stream to store to;
1424 : // the links to OLE documents switch their persistence in the same way
1425 : // as normal embedded objects
1426 : }
1427 : else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1428 : {
1429 : // create a new object, that will be stored in specified stream
1430 : CreateOleComponent_Impl();
1431 :
1432 : m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
1433 : m_pOleComponent->RunObject();
1434 : m_nObjectState = embed::EmbedStates::RUNNING;
1435 : }
1436 : else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1437 : {
1438 : // use URL ( may be content or stream later ) from MediaDescriptor to initialize object
1439 : ::rtl::OUString aURL;
1440 : for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1441 : if ( lArguments[nInd].Name == "URL" )
1442 : lArguments[nInd].Value >>= aURL;
1443 :
1444 : if ( aURL.isEmpty() )
1445 : throw lang::IllegalArgumentException(
1446 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Empty URL is provided in the media descriptor!\n" )),
1447 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1448 : 4 );
1449 :
1450 : CreateOleComponent_Impl();
1451 :
1452 : // TODO: the m_bIsLink value must be set already
1453 : if ( !m_bIsLink )
1454 : m_pOleComponent->CreateObjectFromFile( aURL );
1455 : else
1456 : m_pOleComponent->CreateLinkFromFile( aURL );
1457 :
1458 : m_pOleComponent->RunObject();
1459 : m_aClassID = m_pOleComponent->GetCLSID(); // was not set during consruction
1460 :
1461 : m_nObjectState = embed::EmbedStates::RUNNING;
1462 : }
1463 : //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1464 : //{
1465 : //TODO:
1466 : //}
1467 : else
1468 : throw lang::IllegalArgumentException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Wrong connection mode is provided!\n" )),
1469 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1470 : 3 );
1471 : }
1472 : #else
1473 : // On unix the ole object can not do anything except storing itself somewere
1474 0 : if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT && bElExists )
1475 : {
1476 : // TODO/LATER: detect classID of the object
1477 : // can be a real problem for the links
1478 :
1479 0 : m_nObjectState = embed::EmbedStates::LOADED;
1480 : }
1481 0 : else if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1482 : {
1483 : // do nothing, the object has already switched it's persistence
1484 : }
1485 : else
1486 : throw lang::IllegalArgumentException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Wrong connection mode is provided!\n" )),
1487 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1488 0 : 3 );
1489 :
1490 : #endif
1491 : }
1492 :
1493 : //------------------------------------------------------
1494 0 : void SAL_CALL OleEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1495 : const ::rtl::OUString& sEntName,
1496 : const uno::Sequence< beans::PropertyValue >& lArguments,
1497 : const uno::Sequence< beans::PropertyValue >& lObjArgs )
1498 : throw ( lang::IllegalArgumentException,
1499 : embed::WrongStateException,
1500 : io::IOException,
1501 : uno::Exception,
1502 : uno::RuntimeException )
1503 : {
1504 : RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::storeToEntry" );
1505 :
1506 : // begin wrapping related part ====================
1507 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1508 0 : if ( xWrappedObject.is() )
1509 : {
1510 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1511 0 : xWrappedObject->storeToEntry( xStorage, sEntName, lArguments, lObjArgs );
1512 0 : return;
1513 : }
1514 : // end wrapping related part ====================
1515 :
1516 0 : ::osl::MutexGuard aGuard( m_aMutex );
1517 0 : if ( m_bDisposed )
1518 0 : throw lang::DisposedException(); // TODO
1519 :
1520 0 : VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1521 :
1522 0 : StoreToLocation_Impl( xStorage, sEntName, lObjArgs, sal_False );
1523 :
1524 : // TODO: should the listener notification be done?
1525 : }
1526 :
1527 : //------------------------------------------------------
1528 0 : void SAL_CALL OleEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1529 : const ::rtl::OUString& sEntName,
1530 : const uno::Sequence< beans::PropertyValue >& lArguments,
1531 : const uno::Sequence< beans::PropertyValue >& lObjArgs )
1532 : throw ( lang::IllegalArgumentException,
1533 : embed::WrongStateException,
1534 : io::IOException,
1535 : uno::Exception,
1536 : uno::RuntimeException )
1537 : {
1538 : RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::storeAsEntry" );
1539 :
1540 : // begin wrapping related part ====================
1541 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1542 0 : if ( xWrappedObject.is() )
1543 : {
1544 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1545 0 : xWrappedObject->storeAsEntry( xStorage, sEntName, lArguments, lObjArgs );
1546 0 : return;
1547 : }
1548 : // end wrapping related part ====================
1549 :
1550 0 : ::osl::MutexGuard aGuard( m_aMutex );
1551 0 : if ( m_bDisposed )
1552 0 : throw lang::DisposedException(); // TODO
1553 :
1554 0 : VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1555 :
1556 0 : StoreToLocation_Impl( xStorage, sEntName, lObjArgs, sal_True );
1557 :
1558 : // TODO: should the listener notification be done here or in saveCompleted?
1559 : }
1560 :
1561 : //------------------------------------------------------
1562 0 : void SAL_CALL OleEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1563 : throw ( embed::WrongStateException,
1564 : uno::Exception,
1565 : uno::RuntimeException )
1566 : {
1567 : RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::saveCompleted" );
1568 :
1569 : // begin wrapping related part ====================
1570 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1571 0 : if ( xWrappedObject.is() )
1572 : {
1573 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1574 0 : xWrappedObject->saveCompleted( bUseNew );
1575 : return;
1576 : }
1577 : // end wrapping related part ====================
1578 :
1579 0 : ::osl::ResettableMutexGuard aGuard( m_aMutex );
1580 0 : if ( m_bDisposed )
1581 0 : throw lang::DisposedException(); // TODO
1582 :
1583 0 : if ( m_nObjectState == -1 )
1584 : {
1585 : // the object is still not loaded
1586 : throw embed::WrongStateException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Can't store object without persistence!\n" )),
1587 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1588 : }
1589 :
1590 : // it is allowed to call saveCompleted( false ) for nonstored objects
1591 0 : if ( !m_bWaitSaveCompleted && !bUseNew )
1592 : return;
1593 :
1594 : OSL_ENSURE( m_bWaitSaveCompleted, "Unexpected saveCompleted() call!\n" );
1595 0 : if ( !m_bWaitSaveCompleted )
1596 0 : throw io::IOException(); // TODO: illegal call
1597 :
1598 : OSL_ENSURE( m_xNewObjectStream.is() && m_xNewParentStorage.is() , "Internal object information is broken!\n" );
1599 0 : if ( !m_xNewObjectStream.is() || !m_xNewParentStorage.is() )
1600 0 : throw uno::RuntimeException(); // TODO: broken internal information
1601 :
1602 0 : if ( bUseNew )
1603 : {
1604 0 : SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStream, m_aNewEntryName );
1605 0 : m_bStoreVisRepl = m_bNewVisReplInStream;
1606 0 : SetVisReplInStream( m_bNewVisReplInStream );
1607 0 : m_xCachedVisualRepresentation = m_xNewCachedVisRepl;
1608 : }
1609 : else
1610 : {
1611 : // close remembered stream
1612 : try {
1613 0 : uno::Reference< lang::XComponent > xComponent( m_xNewObjectStream, uno::UNO_QUERY );
1614 : OSL_ENSURE( xComponent.is(), "Wrong storage implementation!" );
1615 0 : if ( xComponent.is() )
1616 0 : xComponent->dispose();
1617 : }
1618 0 : catch ( const uno::Exception& )
1619 : {
1620 : }
1621 : }
1622 :
1623 0 : sal_Bool bStoreLoaded = m_bStoreLoaded;
1624 :
1625 0 : m_xNewObjectStream = uno::Reference< io::XStream >();
1626 0 : m_xNewParentStorage = uno::Reference< embed::XStorage >();
1627 0 : m_aNewEntryName = ::rtl::OUString();
1628 0 : m_bWaitSaveCompleted = sal_False;
1629 0 : m_bNewVisReplInStream = sal_False;
1630 0 : m_xNewCachedVisRepl = uno::Reference< io::XStream >();
1631 0 : m_bStoreLoaded = sal_False;
1632 :
1633 0 : if ( bUseNew && m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded
1634 : && m_nObjectState != embed::EmbedStates::LOADED )
1635 : {
1636 : // the object replacement image should be updated, so the cached size as well
1637 0 : m_bHasCachedSize = sal_False;
1638 : try
1639 : {
1640 : // the call will cache the size in case of success
1641 : // probably it might need to be done earlier, while the object is in active state
1642 0 : getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1643 : }
1644 0 : catch( const uno::Exception& )
1645 : {}
1646 : }
1647 :
1648 0 : aGuard.clear();
1649 0 : if ( bUseNew )
1650 : {
1651 0 : MakeEventListenerNotification_Impl( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "OnSaveAsDone" ) ));
1652 :
1653 : // the object can be changed only on windows
1654 : // the notification should be done only if the object is not in loaded state
1655 0 : if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
1656 : {
1657 0 : MakeEventListenerNotification_Impl( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "OnVisAreaChanged" ) ));
1658 : }
1659 0 : }
1660 : }
1661 :
1662 : //------------------------------------------------------
1663 0 : sal_Bool SAL_CALL OleEmbeddedObject::hasEntry()
1664 : throw ( embed::WrongStateException,
1665 : uno::RuntimeException )
1666 : {
1667 : // begin wrapping related part ====================
1668 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1669 0 : if ( xWrappedObject.is() )
1670 : {
1671 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1672 0 : return xWrappedObject->hasEntry();
1673 : }
1674 : // end wrapping related part ====================
1675 :
1676 0 : ::osl::MutexGuard aGuard( m_aMutex );
1677 0 : if ( m_bDisposed )
1678 0 : throw lang::DisposedException(); // TODO
1679 :
1680 0 : if ( m_bWaitSaveCompleted )
1681 : throw embed::WrongStateException(
1682 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
1683 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1684 :
1685 0 : if ( m_xObjectStream.is() )
1686 0 : return sal_True;
1687 :
1688 0 : return sal_False;
1689 : }
1690 :
1691 : //------------------------------------------------------
1692 0 : ::rtl::OUString SAL_CALL OleEmbeddedObject::getEntryName()
1693 : throw ( embed::WrongStateException,
1694 : uno::RuntimeException )
1695 : {
1696 : // begin wrapping related part ====================
1697 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1698 0 : if ( xWrappedObject.is() )
1699 : {
1700 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1701 0 : return xWrappedObject->getEntryName();
1702 : }
1703 : // end wrapping related part ====================
1704 :
1705 0 : ::osl::MutexGuard aGuard( m_aMutex );
1706 0 : if ( m_bDisposed )
1707 0 : throw lang::DisposedException(); // TODO
1708 :
1709 0 : if ( m_nObjectState == -1 )
1710 : {
1711 : // the object is still not loaded
1712 : throw embed::WrongStateException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object persistence is not initialized!\n" )),
1713 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1714 : }
1715 :
1716 0 : if ( m_bWaitSaveCompleted )
1717 : throw embed::WrongStateException(
1718 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
1719 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1720 :
1721 0 : return m_aEntryName;
1722 : }
1723 :
1724 :
1725 : //------------------------------------------------------
1726 0 : void SAL_CALL OleEmbeddedObject::storeOwn()
1727 : throw ( embed::WrongStateException,
1728 : io::IOException,
1729 : uno::Exception,
1730 : uno::RuntimeException )
1731 : {
1732 : RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::storeOwn" );
1733 :
1734 : // begin wrapping related part ====================
1735 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1736 0 : if ( xWrappedObject.is() )
1737 : {
1738 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1739 0 : xWrappedObject->storeOwn();
1740 0 : return;
1741 : }
1742 : // end wrapping related part ====================
1743 :
1744 : // during switching from Activated to Running and from Running to Loaded states the object will
1745 : // ask container to store the object, the container has to make decision
1746 : // to do so or not
1747 :
1748 0 : ::osl::ResettableMutexGuard aGuard( m_aMutex );
1749 0 : if ( m_bDisposed )
1750 0 : throw lang::DisposedException(); // TODO
1751 :
1752 0 : VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1753 :
1754 0 : if ( m_nObjectState == -1 )
1755 : {
1756 : // the object is still not loaded
1757 : throw embed::WrongStateException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Can't store object without persistence!\n" )),
1758 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1759 : }
1760 :
1761 0 : if ( m_bWaitSaveCompleted )
1762 : throw embed::WrongStateException(
1763 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
1764 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1765 :
1766 0 : if ( m_bReadOnly )
1767 0 : throw io::IOException(); // TODO: access denied
1768 :
1769 0 : LetCommonStoragePassBeUsed_Impl( m_xObjectStream );
1770 :
1771 0 : sal_Bool bStoreLoaded = sal_True;
1772 :
1773 : #ifdef WNT
1774 : if ( m_nObjectState != embed::EmbedStates::LOADED && m_pOleComponent && m_pOleComponent->IsDirty() )
1775 : {
1776 : bStoreLoaded = sal_False;
1777 :
1778 : OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!\n" );
1779 :
1780 : if ( !m_xObjectStream.is() )
1781 : throw io::IOException(); //TODO: access denied
1782 :
1783 : SetStreamMediaType_Impl( m_xObjectStream, ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.oleobject" ) ));
1784 : uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
1785 : if ( !xOutStream.is() )
1786 : throw io::IOException(); //TODO: access denied
1787 :
1788 : // TODO: does this work for links too?
1789 : StoreObjectToStream( GetStreamForSaving() );
1790 :
1791 : // the replacement is changed probably, and it must be in the object stream
1792 : if ( !m_pOleComponent->IsWorkaroundActive() )
1793 : m_xCachedVisualRepresentation = uno::Reference< io::XStream >();
1794 : SetVisReplInStream( sal_True );
1795 : }
1796 : #endif
1797 :
1798 0 : if ( m_bStoreVisRepl != HasVisReplInStream() )
1799 : {
1800 0 : if ( m_bStoreVisRepl )
1801 : {
1802 : // the m_xCachedVisualRepresentation must be set or it should be already stored
1803 0 : if ( m_xCachedVisualRepresentation.is() )
1804 0 : InsertVisualCache_Impl( m_xObjectStream, m_xCachedVisualRepresentation );
1805 : else
1806 : {
1807 0 : m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
1808 : OSL_ENSURE( m_xCachedVisualRepresentation.is(), "No representation is available!" );
1809 : }
1810 : }
1811 : else
1812 : {
1813 0 : if ( !m_xCachedVisualRepresentation.is() )
1814 0 : m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
1815 0 : RemoveVisualCache_Impl( m_xObjectStream );
1816 : }
1817 :
1818 0 : SetVisReplInStream( m_bStoreVisRepl );
1819 : }
1820 :
1821 0 : if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
1822 : {
1823 : // the object replacement image should be updated, so the cached size as well
1824 0 : m_bHasCachedSize = sal_False;
1825 : try
1826 : {
1827 : // the call will cache the size in case of success
1828 : // probably it might need to be done earlier, while the object is in active state
1829 0 : getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1830 : }
1831 0 : catch( const uno::Exception& )
1832 : {}
1833 : }
1834 :
1835 0 : aGuard.clear();
1836 :
1837 0 : MakeEventListenerNotification_Impl( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "OnSaveDone" ) ));
1838 :
1839 : // the object can be changed only on Windows
1840 : // the notification should be done only if the object is not in loaded state
1841 0 : if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
1842 0 : MakeEventListenerNotification_Impl( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "OnVisAreaChanged" ) ));
1843 : }
1844 :
1845 : //------------------------------------------------------
1846 0 : sal_Bool SAL_CALL OleEmbeddedObject::isReadonly()
1847 : throw ( embed::WrongStateException,
1848 : uno::RuntimeException )
1849 : {
1850 : // begin wrapping related part ====================
1851 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1852 0 : if ( xWrappedObject.is() )
1853 : {
1854 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1855 0 : return xWrappedObject->isReadonly();
1856 : }
1857 : // end wrapping related part ====================
1858 :
1859 0 : ::osl::MutexGuard aGuard( m_aMutex );
1860 0 : if ( m_bDisposed )
1861 0 : throw lang::DisposedException(); // TODO
1862 :
1863 0 : if ( m_nObjectState == -1 )
1864 : {
1865 : // the object is still not loaded
1866 : throw embed::WrongStateException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object persistence is not initialized!\n" )),
1867 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1868 : }
1869 :
1870 0 : if ( m_bWaitSaveCompleted )
1871 : throw embed::WrongStateException(
1872 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
1873 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1874 :
1875 0 : return m_bReadOnly;
1876 : }
1877 :
1878 : //------------------------------------------------------
1879 0 : void SAL_CALL OleEmbeddedObject::reload(
1880 : const uno::Sequence< beans::PropertyValue >& lArguments,
1881 : const uno::Sequence< beans::PropertyValue >& lObjArgs )
1882 : throw ( lang::IllegalArgumentException,
1883 : embed::WrongStateException,
1884 : io::IOException,
1885 : uno::Exception,
1886 : uno::RuntimeException )
1887 : {
1888 : // begin wrapping related part ====================
1889 0 : uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1890 0 : if ( xWrappedObject.is() )
1891 : {
1892 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1893 0 : xWrappedObject->reload( lArguments, lObjArgs );
1894 0 : return;
1895 : }
1896 : // end wrapping related part ====================
1897 :
1898 : // TODO: use lObjArgs
1899 :
1900 0 : ::osl::MutexGuard aGuard( m_aMutex );
1901 0 : if ( m_bDisposed )
1902 0 : throw lang::DisposedException(); // TODO
1903 :
1904 0 : if ( m_nObjectState == -1 )
1905 : {
1906 : // the object is still not loaded
1907 : throw embed::WrongStateException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object persistence is not initialized!\n" )),
1908 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1909 : }
1910 :
1911 0 : if ( m_bWaitSaveCompleted )
1912 : throw embed::WrongStateException(
1913 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
1914 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1915 :
1916 : // TODO:
1917 : // throw away current document
1918 : // load new document from current storage
1919 : // use meaningfull part of lArguments
1920 : }
1921 :
1922 : //------------------------------------------------------
1923 0 : void SAL_CALL OleEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1924 : const ::rtl::OUString& sEntName )
1925 : throw ( lang::IllegalArgumentException,
1926 : embed::WrongStateException,
1927 : io::IOException,
1928 : uno::Exception,
1929 : uno::RuntimeException )
1930 : {
1931 : // begin wrapping related part ====================
1932 0 : uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1933 0 : if ( xWrappedObject.is() )
1934 : {
1935 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1936 0 : xWrappedObject->breakLink( xStorage, sEntName );
1937 0 : return;
1938 : }
1939 : // end wrapping related part ====================
1940 :
1941 0 : ::osl::MutexGuard aGuard( m_aMutex );
1942 0 : if ( m_bDisposed )
1943 0 : throw lang::DisposedException(); // TODO
1944 :
1945 0 : if ( !xStorage.is() )
1946 : throw lang::IllegalArgumentException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "No parent storage is provided!\n" )),
1947 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1948 0 : 1 );
1949 :
1950 0 : if ( sEntName.isEmpty() )
1951 : throw lang::IllegalArgumentException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Empty element name is provided!\n" )),
1952 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1953 0 : 2 );
1954 :
1955 : // TODO: The object must be at least in Running state;
1956 0 : if ( !m_bIsLink || m_nObjectState == -1 || !m_pOleComponent )
1957 : {
1958 : // it must be a linked initialized object
1959 : throw embed::WrongStateException(
1960 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object is not a valid linked object!\n" )),
1961 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1962 : }
1963 :
1964 0 : if ( m_bReadOnly )
1965 0 : throw io::IOException(); // TODO: Access denied
1966 :
1967 0 : if ( m_bWaitSaveCompleted )
1968 : throw embed::WrongStateException(
1969 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
1970 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1971 :
1972 :
1973 : #ifdef WNT
1974 : if ( m_pOleComponent )
1975 : {
1976 : // TODO: create an object based on the link
1977 :
1978 : // disconnect the old temporary URL
1979 : ::rtl::OUString aOldTempURL = m_aTempURL;
1980 : m_aTempURL = ::rtl::OUString();
1981 :
1982 : OleComponent* pNewOleComponent = new OleComponent( m_xFactory, this );
1983 : try {
1984 : pNewOleComponent->InitEmbeddedCopyOfLink( m_pOleComponent );
1985 : }
1986 : catch ( const uno::Exception& )
1987 : {
1988 : delete pNewOleComponent;
1989 : if ( !m_aTempURL.isEmpty() )
1990 : KillFile_Impl( m_aTempURL, m_xFactory );
1991 : m_aTempURL = aOldTempURL;
1992 : throw;
1993 : }
1994 :
1995 : try {
1996 : GetRidOfComponent();
1997 : }
1998 : catch( const uno::Exception& )
1999 : {
2000 : delete pNewOleComponent;
2001 : if ( !m_aTempURL.isEmpty() )
2002 : KillFile_Impl( m_aTempURL, m_xFactory );
2003 : m_aTempURL = aOldTempURL;
2004 : throw;
2005 : }
2006 :
2007 : KillFile_Impl( aOldTempURL, m_xFactory );
2008 :
2009 : CreateOleComponent_Impl( pNewOleComponent );
2010 :
2011 : if ( m_xParentStorage != xStorage || !m_aEntryName.equals( sEntName ) )
2012 : SwitchOwnPersistence( xStorage, sEntName );
2013 :
2014 : if ( m_nObjectState != embed::EmbedStates::LOADED )
2015 : {
2016 : // TODO: should we activate the new object if the link was activated?
2017 :
2018 : sal_Int32 nTargetState = m_nObjectState;
2019 : m_nObjectState = embed::EmbedStates::LOADED;
2020 :
2021 : if ( m_nObjectState == embed::EmbedStates::RUNNING )
2022 : m_pOleComponent->RunObject(); // the object already was in running state, the server must be installed
2023 : else // m_nObjectState == embed::EmbedStates::ACTIVE
2024 : {
2025 : m_pOleComponent->RunObject(); // the object already was in running state, the server must be installed
2026 : m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
2027 : }
2028 :
2029 : m_nObjectState = nTargetState;
2030 : }
2031 :
2032 : m_bIsLink = sal_False;
2033 : m_aLinkURL = ::rtl::OUString();
2034 : }
2035 : else
2036 : #endif
2037 : {
2038 0 : throw io::IOException(); //TODO:
2039 0 : }
2040 : }
2041 :
2042 : //------------------------------------------------------
2043 0 : sal_Bool SAL_CALL OleEmbeddedObject::isLink()
2044 : throw ( embed::WrongStateException,
2045 : uno::RuntimeException )
2046 : {
2047 : // begin wrapping related part ====================
2048 0 : uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
2049 0 : if ( xWrappedObject.is() )
2050 : {
2051 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
2052 0 : return xWrappedObject->isLink();
2053 : }
2054 : // end wrapping related part ====================
2055 :
2056 0 : ::osl::MutexGuard aGuard( m_aMutex );
2057 0 : if ( m_bDisposed )
2058 0 : throw lang::DisposedException(); // TODO
2059 :
2060 0 : return m_bIsLink;
2061 : }
2062 :
2063 : //------------------------------------------------------
2064 0 : ::rtl::OUString SAL_CALL OleEmbeddedObject::getLinkURL()
2065 : throw ( embed::WrongStateException,
2066 : uno::Exception,
2067 : uno::RuntimeException )
2068 : {
2069 : // begin wrapping related part ====================
2070 0 : uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
2071 0 : if ( xWrappedObject.is() )
2072 : {
2073 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
2074 0 : return xWrappedObject->getLinkURL();
2075 : }
2076 : // end wrapping related part ====================
2077 :
2078 0 : ::osl::MutexGuard aGuard( m_aMutex );
2079 0 : if ( m_bDisposed )
2080 0 : throw lang::DisposedException(); // TODO
2081 :
2082 0 : if ( m_bWaitSaveCompleted )
2083 : throw embed::WrongStateException(
2084 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object waits for saveCompleted() call!\n" )),
2085 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
2086 :
2087 0 : if ( !m_bIsLink )
2088 : throw embed::WrongStateException(
2089 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "The object is not a link object!\n" )),
2090 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
2091 :
2092 : // TODO: probably the link URL can be retrieved from OLE
2093 :
2094 0 : return m_aLinkURL;
2095 : }
2096 :
2097 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|