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 "sal/config.h"
21 :
22 : #include <cassert>
23 :
24 : #include <vcl/msgbox.hxx>
25 : #include <svl/eitem.hxx>
26 : #include <svl/stritem.hxx>
27 : #include <svl/intitem.hxx>
28 : #include <com/sun/star/frame/GlobalEventBroadcaster.hpp>
29 : #include <com/sun/star/frame/XStorable.hpp>
30 : #include <com/sun/star/frame/XModel.hpp>
31 : #include <com/sun/star/frame/XFrame.hpp>
32 : #include <com/sun/star/document/XFilter.hpp>
33 : #include <com/sun/star/document/XImporter.hpp>
34 : #include <com/sun/star/document/XExporter.hpp>
35 : #include <com/sun/star/document/FilterOptionsRequest.hpp>
36 : #include <com/sun/star/document/XInteractionFilterOptions.hpp>
37 : #include <com/sun/star/packages/zip/ZipIOException.hpp>
38 : #include <com/sun/star/task/XInteractionHandler.hpp>
39 : #include <com/sun/star/task/XInteractionAskLater.hpp>
40 : #include <com/sun/star/task/FutureDocumentVersionProductUpdateRequest.hpp>
41 : #include <com/sun/star/task/InteractionClassification.hpp>
42 : #include <com/sun/star/lang/XInitialization.hpp>
43 : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
44 : #include <com/sun/star/document/MacroExecMode.hpp>
45 : #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
46 : #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
47 : #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
48 : #include <com/sun/star/beans/XPropertySetInfo.hpp>
49 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 : #include <com/sun/star/beans/XPropertyAccess.hpp>
51 : #include <com/sun/star/beans/PropertyValue.hpp>
52 : #include <com/sun/star/beans/XPropertySet.hpp>
53 : #include <com/sun/star/container/XNameAccess.hpp>
54 : #include <com/sun/star/container/XSet.hpp>
55 : #include <com/sun/star/embed/ElementModes.hpp>
56 : #include <com/sun/star/embed/EmbedStates.hpp>
57 : #include <com/sun/star/embed/Aspects.hpp>
58 : #include <com/sun/star/embed/XTransactedObject.hpp>
59 : #include <com/sun/star/embed/XEmbedPersist.hpp>
60 : #include <com/sun/star/embed/XLinkageSupport.hpp>
61 : #include <com/sun/star/embed/EntryInitModes.hpp>
62 : #include <com/sun/star/embed/XOptimizedStorage.hpp>
63 : #include <com/sun/star/embed/XEncryptionProtectedStorage.hpp>
64 : #include <com/sun/star/io/XTruncate.hpp>
65 : #include <com/sun/star/util/XModifiable.hpp>
66 : #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
67 : #include <com/sun/star/xml/crypto/CipherID.hpp>
68 : #include <com/sun/star/xml/crypto/DigestID.hpp>
69 :
70 : #include <com/sun/star/document/XDocumentProperties.hpp>
71 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
72 : #include <comphelper/processfactory.hxx>
73 : #include <comphelper/configurationhelper.hxx>
74 : #include <comphelper/interaction.hxx>
75 : #include <svtools/sfxecode.hxx>
76 : #include <unotools/securityoptions.hxx>
77 : #include <cppuhelper/weak.hxx>
78 : #include <unotools/streamwrap.hxx>
79 :
80 : #include <unotools/saveopt.hxx>
81 : #include <unotools/useroptions.hxx>
82 : #include <unotools/pathoptions.hxx>
83 : #include <tools/urlobj.hxx>
84 : #include <tools/diagnose_ex.h>
85 : #include <unotools/localfilehelper.hxx>
86 : #include <unotools/ucbhelper.hxx>
87 : #include <unotools/tempfile.hxx>
88 : #include <unotools/docinfohelper.hxx>
89 : #include <ucbhelper/content.hxx>
90 : #include <sot/storinfo.hxx>
91 : #include <sot/exchange.hxx>
92 : #include <sot/formats.hxx>
93 : #include <comphelper/storagehelper.hxx>
94 : #include <comphelper/seqstream.hxx>
95 : #include <comphelper/documentconstants.hxx>
96 : #include <comphelper/string.hxx>
97 : #include <vcl/bitmapex.hxx>
98 : #include <svtools/embedhlp.hxx>
99 : #include <rtl/logfile.hxx>
100 : #include <basic/modsizeexceeded.hxx>
101 : #include <osl/file.hxx>
102 :
103 : #include <sfx2/signaturestate.hxx>
104 : #include <sfx2/app.hxx>
105 : #include <sfx2/objsh.hxx>
106 : #include <sfx2/childwin.hxx>
107 : #include <sfx2/request.hxx>
108 : #include "sfx2/sfxresid.hxx"
109 : #include <sfx2/docfile.hxx>
110 : #include "fltfnc.hxx"
111 : #include <sfx2/docfilt.hxx>
112 : #include <sfx2/docfac.hxx>
113 : #include "objshimp.hxx"
114 : #include "sfxtypes.hxx"
115 : #include "doc.hrc"
116 : #include <sfx2/sfxsids.hrc>
117 : #include <sfx2/module.hxx>
118 : #include <sfx2/dispatch.hxx>
119 : #include "openflag.hxx"
120 : #include "helper.hxx"
121 : #include <sfx2/event.hxx>
122 : #include "fltoptint.hxx"
123 : #include <sfx2/viewfrm.hxx>
124 : #include "graphhelp.hxx"
125 : #include "appbaslib.hxx"
126 : #include "appdata.hxx"
127 :
128 : #include "../appl/app.hrc"
129 :
130 : extern sal_uInt32 CheckPasswd_Impl( SfxObjectShell*, SfxItemPool&, SfxMedium* );
131 :
132 : using namespace ::com::sun::star;
133 : using namespace ::com::sun::star::container;
134 : using namespace ::com::sun::star::lang;
135 : using namespace ::com::sun::star::ui::dialogs;
136 : using namespace ::com::sun::star::uno;
137 : using namespace ::com::sun::star::beans;
138 : using namespace ::com::sun::star::ucb;
139 : using namespace ::com::sun::star::task;
140 : using namespace ::com::sun::star::document;
141 : using namespace ::rtl;
142 : using namespace ::cppu;
143 :
144 : //=========================================================================
145 504 : void impl_addToModelCollection(const css::uno::Reference< css::frame::XModel >& xModel)
146 : {
147 504 : if (!xModel.is())
148 504 : return;
149 :
150 504 : css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
151 : css::uno::Reference< css::frame::XGlobalEventBroadcaster > xModelCollection =
152 504 : css::frame::GlobalEventBroadcaster::create(xContext);
153 : try
154 : {
155 504 : xModelCollection->insert(css::uno::makeAny(xModel));
156 : }
157 0 : catch ( uno::Exception& )
158 : {
159 : OSL_FAIL( "The document seems to be in the collection already!\n" );
160 504 : }
161 : }
162 :
163 : //=========================================================================
164 :
165 0 : sal_Bool SfxObjectShell::Save()
166 : {
167 0 : return SaveChildren();
168 : }
169 :
170 : //--------------------------------------------------------------------------
171 :
172 290 : sal_Bool SfxObjectShell::SaveAs( SfxMedium& rMedium )
173 : {
174 290 : return SaveAsChildren( rMedium );
175 : }
176 :
177 : //-------------------------------------------------------------------------
178 :
179 0 : sal_Bool SfxObjectShell::QuerySlotExecutable( sal_uInt16 /*nSlotId*/ )
180 : {
181 0 : return sal_True;
182 : }
183 :
184 : //-------------------------------------------------------------------------
185 :
186 219 : bool GetEncryptionData_Impl( const SfxItemSet* pSet, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
187 : {
188 219 : bool bResult = false;
189 219 : if ( pSet )
190 : {
191 219 : SFX_ITEMSET_ARG( pSet, pEncryptionDataItem, SfxUnoAnyItem, SID_ENCRYPTIONDATA, sal_False);
192 219 : if ( pEncryptionDataItem )
193 : {
194 6 : pEncryptionDataItem->GetValue() >>= o_rEncryptionData;
195 6 : bResult = true;
196 : }
197 : else
198 : {
199 213 : SFX_ITEMSET_ARG( pSet, pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False);
200 213 : if ( pPasswordItem )
201 : {
202 3 : ::rtl::OUString aPassword = pPasswordItem->GetValue();
203 3 : o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( aPassword );
204 3 : bResult = true;
205 : }
206 : }
207 : }
208 :
209 219 : return bResult;
210 : }
211 :
212 : //-------------------------------------------------------------------------
213 0 : sal_Bool SfxObjectShell::PutURLContentsToVersionStream_Impl(
214 : ::rtl::OUString aURL,
215 : const uno::Reference< embed::XStorage >& xDocStorage,
216 : ::rtl::OUString aStreamName )
217 : {
218 0 : sal_Bool bResult = sal_False;
219 : try
220 : {
221 0 : uno::Reference< embed::XStorage > xVersion = xDocStorage->openStorageElement(
222 : ::rtl::OUString("Versions"),
223 0 : embed::ElementModes::READWRITE );
224 :
225 : DBG_ASSERT( xVersion.is(),
226 : "The method must throw an exception if the storage can not be opened!\n" );
227 0 : if ( !xVersion.is() )
228 0 : throw uno::RuntimeException();
229 :
230 0 : uno::Reference< io::XStream > xVerStream = xVersion->openStreamElement(
231 : aStreamName,
232 0 : embed::ElementModes::READWRITE );
233 : DBG_ASSERT( xVerStream.is(), "The method must throw an exception if the storage can not be opened!\n" );
234 0 : if ( !xVerStream.is() )
235 0 : throw uno::RuntimeException();
236 :
237 0 : uno::Reference< io::XOutputStream > xOutStream = xVerStream->getOutputStream();
238 0 : uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY );
239 :
240 : DBG_ASSERT( xTrunc.is(), "The output stream must exist and implement XTruncate interface!\n" );
241 0 : if ( !xTrunc.is() )
242 0 : throw RuntimeException();
243 :
244 : uno::Reference< io::XInputStream > xTmpInStream =
245 : ::comphelper::OStorageHelper::GetInputStreamFromURL(
246 0 : aURL, comphelper::getProcessComponentContext() );
247 : assert( xTmpInStream.is() );
248 :
249 0 : xTrunc->truncate();
250 0 : ::comphelper::OStorageHelper::CopyInputToOutput( xTmpInStream, xOutStream );
251 0 : xOutStream->closeOutput();
252 :
253 0 : uno::Reference< embed::XTransactedObject > xTransact( xVersion, uno::UNO_QUERY );
254 : DBG_ASSERT( xTransact.is(), "The storage must implement XTransacted interface!\n" );
255 0 : if ( xTransact.is() )
256 0 : xTransact->commit();
257 :
258 0 : bResult = sal_True;
259 : }
260 0 : catch( uno::Exception& )
261 : {
262 : // TODO/LATER: handle the error depending on exception
263 0 : SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
264 : }
265 :
266 0 : return bResult;
267 : }
268 :
269 : //-------------------------------------------------------------------------
270 0 : ::rtl::OUString SfxObjectShell::CreateTempCopyOfStorage_Impl( const uno::Reference< embed::XStorage >& xStorage )
271 : {
272 0 : ::rtl::OUString aTempURL = ::utl::TempFile().GetURL();
273 :
274 : DBG_ASSERT( !aTempURL.isEmpty(), "Can't create a temporary file!\n" );
275 0 : if ( !aTempURL.isEmpty() )
276 : {
277 : try
278 : {
279 : uno::Reference< embed::XStorage > xTempStorage =
280 0 : ::comphelper::OStorageHelper::GetStorageFromURL( aTempURL, embed::ElementModes::READWRITE );
281 :
282 : // the password will be transfered from the xStorage to xTempStorage by storage implemetation
283 0 : xStorage->copyToStorage( xTempStorage );
284 :
285 : // the temporary storage was commited by the previous method and it will die by refcount
286 : }
287 0 : catch ( uno::Exception& )
288 : {
289 : OSL_FAIL( "Creation of a storage copy is failed!" );
290 0 : ::utl::UCBContentHelper::Kill( aTempURL );
291 :
292 0 : aTempURL = ::rtl::OUString();
293 :
294 : // TODO/LATER: may need error code setting based on exception
295 0 : SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
296 : }
297 : }
298 :
299 0 : return aTempURL;
300 : }
301 :
302 : //-------------------------------------------------------------------------
303 0 : SvGlobalName SfxObjectShell::GetClassName() const
304 : {
305 0 : return GetFactory().GetClassId();
306 : }
307 :
308 : //-------------------------------------------------------------------------
309 992 : void SfxObjectShell::SetupStorage( const uno::Reference< embed::XStorage >& xStorage,
310 : sal_Int32 nVersion,
311 : sal_Bool bTemplate ) const
312 : {
313 992 : uno::Reference< beans::XPropertySet > xProps( xStorage, uno::UNO_QUERY );
314 :
315 992 : if ( xProps.is() )
316 : {
317 992 : SvGlobalName aName;
318 992 : String aFullTypeName, aShortTypeName, aAppName;
319 992 : sal_uInt32 nClipFormat=0;
320 :
321 992 : FillClass( &aName, &nClipFormat, &aAppName, &aFullTypeName, &aShortTypeName, nVersion, bTemplate );
322 992 : if ( nClipFormat )
323 : {
324 : // basic doesn't have a ClipFormat
325 : // without MediaType the storage is not really usable, but currently the BasicIDE still
326 : // is an SfxObjectShell and so we can't take this as an error
327 992 : datatransfer::DataFlavor aDataFlavor;
328 992 : SotExchange::GetFormatDataFlavor( nClipFormat, aDataFlavor );
329 992 : if ( !aDataFlavor.MimeType.isEmpty() )
330 : {
331 : try
332 : {
333 992 : xProps->setPropertyValue( ::rtl::OUString("MediaType"), uno::makeAny( aDataFlavor.MimeType ) );
334 : }
335 0 : catch( uno::Exception& )
336 : {
337 0 : const_cast<SfxObjectShell*>( this )->SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
338 : }
339 :
340 992 : SvtSaveOptions aSaveOpt;
341 992 : SvtSaveOptions::ODFDefaultVersion nDefVersion = aSaveOpt.GetODFDefaultVersion();
342 :
343 992 : uno::Sequence< beans::NamedValue > aEncryptionAlgs( 3 );
344 992 : aEncryptionAlgs[0].Name = ::rtl::OUString( "StartKeyGenerationAlgorithm" );
345 992 : aEncryptionAlgs[1].Name = ::rtl::OUString( "EncryptionAlgorithm" );
346 992 : aEncryptionAlgs[2].Name = ::rtl::OUString( "ChecksumAlgorithm" );
347 : // the default values, that should be used for ODF1.1 and older formats
348 992 : aEncryptionAlgs[0].Value <<= xml::crypto::DigestID::SHA1;
349 992 : aEncryptionAlgs[1].Value <<= xml::crypto::CipherID::BLOWFISH_CFB_8;
350 992 : aEncryptionAlgs[2].Value <<= xml::crypto::DigestID::SHA1_1K;
351 :
352 992 : if ( nDefVersion >= SvtSaveOptions::ODFVER_012 )
353 : {
354 : try
355 : {
356 : // older versions can not have this property set, it exists only starting from ODF1.2
357 992 : xProps->setPropertyValue( ::rtl::OUString("Version" ), uno::makeAny( ODFVER_012_TEXT ) );
358 : }
359 0 : catch( uno::Exception& )
360 : {
361 : }
362 :
363 992 : if ( !aSaveOpt.IsUseSHA1InODF12() && nDefVersion != SvtSaveOptions::ODFVER_012_EXT_COMPAT )
364 : {
365 992 : aEncryptionAlgs[0].Value <<= xml::crypto::DigestID::SHA256;
366 992 : aEncryptionAlgs[2].Value <<= xml::crypto::DigestID::SHA256_1K;
367 : }
368 992 : if ( !aSaveOpt.IsUseBlowfishInODF12() && nDefVersion != SvtSaveOptions::ODFVER_012_EXT_COMPAT )
369 992 : aEncryptionAlgs[1].Value <<= xml::crypto::CipherID::AES_CBC_W3C_PADDING;
370 : }
371 :
372 : try
373 : {
374 : // set the encryption algorithms accordingly;
375 : // the setting does not trigger encryption,
376 : // it just provides the format for the case that contents should be encrypted
377 992 : uno::Reference< embed::XEncryptionProtectedStorage > xEncr( xStorage, uno::UNO_QUERY_THROW );
378 420 : xEncr->setEncryptionAlgorithms( aEncryptionAlgs );
379 : }
380 572 : catch( uno::Exception& )
381 : {
382 572 : const_cast<SfxObjectShell*>( this )->SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
383 992 : }
384 :
385 992 : }
386 992 : }
387 992 : }
388 992 : }
389 :
390 : //-------------------------------------------------------------------------
391 0 : void SfxObjectShell::PrepareSecondTryLoad_Impl()
392 : {
393 : // only for internal use
394 0 : pImp->m_xDocStorage = uno::Reference< embed::XStorage >();
395 0 : pImp->m_bIsInit = sal_False;
396 0 : ResetError();
397 0 : }
398 :
399 : //-------------------------------------------------------------------------
400 506 : sal_Bool SfxObjectShell::GeneralInit_Impl( const uno::Reference< embed::XStorage >& xStorage,
401 : sal_Bool bTypeMustBeSetAlready )
402 : {
403 506 : if ( pImp->m_bIsInit )
404 1 : return sal_False;
405 :
406 505 : pImp->m_bIsInit = sal_True;
407 505 : if ( xStorage.is() )
408 : {
409 : // no notification is required the storage is set the first time
410 41 : pImp->m_xDocStorage = xStorage;
411 :
412 : try {
413 41 : uno::Reference < beans::XPropertySet > xPropSet( xStorage, uno::UNO_QUERY_THROW );
414 41 : Any a = xPropSet->getPropertyValue( ::rtl::OUString("MediaType" ) );
415 41 : ::rtl::OUString aMediaType;
416 41 : if ( !(a>>=aMediaType) || aMediaType.isEmpty() )
417 : {
418 0 : if ( bTypeMustBeSetAlready )
419 : {
420 0 : SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( OSL_LOG_PREFIX ) );
421 0 : return sal_False;
422 : }
423 :
424 0 : SetupStorage( xStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False );
425 41 : }
426 : }
427 0 : catch ( uno::Exception& )
428 : {
429 : OSL_FAIL( "Can't check storage's mediatype!\n" );
430 : }
431 : }
432 : else
433 464 : pImp->m_bCreateTempStor = sal_True;
434 :
435 505 : return sal_True;
436 : }
437 :
438 : //-------------------------------------------------------------------------
439 465 : sal_Bool SfxObjectShell::InitNew( const uno::Reference< embed::XStorage >& xStorage )
440 : {
441 465 : return GeneralInit_Impl( xStorage, sal_False );
442 : }
443 :
444 : //-------------------------------------------------------------------------
445 41 : sal_Bool SfxObjectShell::Load( SfxMedium& rMedium )
446 : {
447 41 : return GeneralInit_Impl( rMedium.GetStorage(), sal_True );
448 : }
449 :
450 162 : sal_Bool SfxObjectShell::DoInitNew( SfxMedium* pMed )
451 : /* [Description]
452 :
453 : This from SvPersist inherited virtual method is called to initialize
454 : the SfxObjectShell instance from a storage (PStore! = 0) or (PStore == 0)
455 :
456 : Like with all Do...-methods there is a from a control, the actual
457 : implementation is done by the virtual method in which also the
458 : InitNew(SvStorate *) from the SfxObjectShell-Subclass is implemented.
459 :
460 : For pStore == 0 the SfxObjectShell-instance is connected to an empty
461 : SfxMedium, otherwise a SfxMedium, which refers to the SvStorage
462 : passed as a parameter.
463 :
464 : The object is only initialized correctly after InitNew() or Load().
465 :
466 : [Return value]
467 : sal_True The object has been initialized.
468 : sal_False The object could not be initialized
469 : */
470 :
471 : {
472 162 : ModifyBlocker_Impl aBlock( this );
473 162 : pMedium = pMed;
474 162 : if ( !pMedium )
475 : {
476 158 : bIsTmp = sal_True;
477 158 : pMedium = new SfxMedium;
478 : }
479 :
480 162 : pMedium->CanDisposeStorage_Impl( sal_True );
481 :
482 162 : if ( InitNew( pMed ? pMed->GetStorage() : uno::Reference < embed::XStorage >() ) )
483 : {
484 : // empty documents always get their macros from the user, so there is no reason to restrict access
485 161 : pImp->aMacroMode.allowMacroExecution();
486 161 : if ( SFX_CREATE_MODE_EMBEDDED == eCreateMode )
487 154 : SetTitle(SfxResId(STR_NONAME).toString());
488 :
489 161 : uno::Reference< frame::XModel > xModel ( GetModel(), uno::UNO_QUERY );
490 161 : if ( xModel.is() )
491 : {
492 161 : SfxItemSet *pSet = GetMedium()->GetItemSet();
493 161 : uno::Sequence< beans::PropertyValue > aArgs;
494 161 : TransformItems( SID_OPENDOC, *pSet, aArgs );
495 161 : sal_Int32 nLength = aArgs.getLength();
496 161 : aArgs.realloc( nLength + 1 );
497 161 : aArgs[nLength].Name = DEFINE_CONST_UNICODE("Title");
498 161 : aArgs[nLength].Value <<= ::rtl::OUString( GetTitle( SFX_TITLE_DETECT ) );
499 161 : xModel->attachResource( ::rtl::OUString(), aArgs );
500 161 : impl_addToModelCollection(xModel);
501 : }
502 :
503 161 : SetInitialized_Impl( true );
504 161 : return sal_True;
505 : }
506 :
507 1 : return sal_False;
508 : }
509 :
510 : //-------------------------------------------------------------------------
511 :
512 0 : sal_Bool SfxObjectShell::ImportFromGeneratedStream_Impl(
513 : const uno::Reference< io::XStream >& xStream,
514 : const uno::Sequence< beans::PropertyValue >& aMediaDescr )
515 : {
516 0 : if ( !xStream.is() )
517 0 : return sal_False;
518 :
519 0 : if ( pMedium && pMedium->HasStorage_Impl() )
520 0 : pMedium->CloseStorage();
521 :
522 0 : sal_Bool bResult = sal_False;
523 :
524 : try
525 : {
526 : uno::Reference< embed::XStorage > xStorage =
527 0 : ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE );
528 :
529 0 : if ( !xStorage.is() )
530 0 : throw uno::RuntimeException();
531 :
532 0 : if ( !pMedium )
533 0 : pMedium = new SfxMedium( xStorage, String() );
534 : else
535 0 : pMedium->SetStorage_Impl( xStorage );
536 :
537 0 : SfxAllItemSet aSet( SFX_APP()->GetPool() );
538 0 : TransformParameters( SID_OPENDOC, aMediaDescr, aSet );
539 0 : pMedium->GetItemSet()->Put( aSet );
540 0 : pMedium->CanDisposeStorage_Impl( sal_False );
541 :
542 : // allow the subfilter to reinit the model
543 0 : if ( pImp->m_bIsInit )
544 0 : pImp->m_bIsInit = sal_False;
545 :
546 0 : if ( LoadOwnFormat( *pMedium ) )
547 : {
548 0 : bHasName = sal_True;
549 0 : if ( !IsReadOnly() && IsLoadReadonly() )
550 0 : SetReadOnlyUI();
551 :
552 0 : bResult = sal_True;
553 : OSL_ENSURE( pImp->m_xDocStorage == xStorage, "Wrong storage is used!\n" );
554 : }
555 :
556 : // now the medium can be disconnected from the storage
557 : // the medium is not allowed to dispose the storage so CloseStorage() can be used
558 0 : pMedium->CloseStorage();
559 : }
560 0 : catch( uno::Exception& )
561 : {
562 : }
563 :
564 0 : return bResult;
565 : }
566 :
567 : //-------------------------------------------------------------------------
568 :
569 344 : sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed )
570 : {
571 344 : ModifyBlocker_Impl aBlock( this );
572 :
573 344 : pMedium = pMed;
574 344 : pMedium->CanDisposeStorage_Impl( sal_True );
575 :
576 344 : sal_Bool bOk = sal_False;
577 344 : const SfxFilter* pFilter = pMed->GetFilter();
578 344 : SfxItemSet* pSet = pMedium->GetItemSet();
579 344 : if( !pImp->nEventId )
580 : {
581 344 : SFX_ITEMSET_ARG(
582 : pSet, pTemplateItem, SfxBoolItem,
583 : SID_TEMPLATE, sal_False);
584 : SetActivateEvent_Impl(
585 1 : ( pTemplateItem && pTemplateItem->GetValue() )
586 345 : ? SFX_EVENT_CREATEDOC : SFX_EVENT_OPENDOC );
587 : }
588 :
589 :
590 344 : SFX_ITEMSET_ARG( pSet, pBaseItem, SfxStringItem,
591 : SID_BASEURL, sal_False);
592 344 : rtl::OUString aBaseURL;
593 344 : SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
594 344 : if( pBaseItem )
595 0 : aBaseURL = pBaseItem->GetValue();
596 : else
597 : {
598 344 : if ( pSalvageItem )
599 : {
600 0 : rtl::OUString aName( pMed->GetPhysicalName() );
601 0 : ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aBaseURL );
602 : }
603 : else
604 344 : aBaseURL = pMed->GetBaseURL();
605 : }
606 344 : pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, aBaseURL ) );
607 :
608 344 : pImp->nLoadedFlags = 0;
609 344 : pImp->bModelInitialized = sal_False;
610 :
611 : //TODO/LATER: make a clear strategy how to handle "UsesStorage" etc.
612 344 : sal_Bool bOwnStorageFormat = IsOwnStorageFormat_Impl( *pMedium );
613 344 : sal_Bool bHasStorage = IsPackageStorageFormat_Impl( *pMedium );
614 344 : if ( pMedium->GetFilter() )
615 : {
616 344 : sal_uInt32 nError = HandleFilter( pMedium, this );
617 344 : if ( nError != ERRCODE_NONE )
618 0 : SetError( nError, ::rtl::OUString( OSL_LOG_PREFIX ) );
619 :
620 344 : if (pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARTPRESENTATION)
621 0 : pSet->Put( SfxBoolItem( SID_DOC_STARTPRESENTATION, sal_True) );
622 : }
623 :
624 344 : EnableSetModified( sal_False );
625 :
626 344 : pMedium->LockOrigFileOnDemand( sal_True, sal_False );
627 344 : if ( GetError() == ERRCODE_NONE && bOwnStorageFormat && ( !pFilter || !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) ) )
628 : {
629 41 : uno::Reference< embed::XStorage > xStorage;
630 41 : if ( pMedium->GetError() == ERRCODE_NONE )
631 41 : xStorage = pMedium->GetStorage();
632 :
633 41 : if( xStorage.is() && pMedium->GetLastStorageCreationState() == ERRCODE_NONE )
634 : {
635 : DBG_ASSERT( pFilter, "No filter for storage found!" );
636 :
637 : try
638 : {
639 41 : sal_Bool bWarnMediaTypeFallback = sal_False;
640 41 : SFX_ITEMSET_ARG( pMedium->GetItemSet(), pRepairPackageItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False);
641 :
642 : // treat the package as broken if the mediatype was retrieved as a fallback
643 41 : uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW );
644 41 : xStorProps->getPropertyValue( ::rtl::OUString( "MediaTypeFallbackUsed" ) )
645 41 : >>= bWarnMediaTypeFallback;
646 :
647 41 : if ( pRepairPackageItem && pRepairPackageItem->GetValue() )
648 : {
649 : // the macros in repaired documents should be disabled
650 0 : pMedium->GetItemSet()->Put( SfxUInt16Item( SID_MACROEXECMODE, document::MacroExecMode::NEVER_EXECUTE ) );
651 :
652 : // the mediatype was retrieved by using fallback solution but this is a repairing mode
653 : // so it is acceptable to open the document if there is no contents that required manifest.xml
654 0 : bWarnMediaTypeFallback = sal_False;
655 : }
656 :
657 41 : if ( bWarnMediaTypeFallback || !xStorage->getElementNames().getLength() )
658 0 : SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( OSL_LOG_PREFIX ) );
659 : }
660 0 : catch( uno::Exception& )
661 : {
662 : // TODO/LATER: may need error code setting based on exception
663 0 : SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
664 : }
665 :
666 : // Load
667 41 : if ( !GetError() )
668 : {
669 41 : pImp->nLoadedFlags = 0;
670 41 : pImp->bModelInitialized = sal_False;
671 41 : bOk = xStorage.is() && LoadOwnFormat( *pMed );
672 41 : if ( bOk )
673 : {
674 : // the document loaded from template has no name
675 40 : SFX_ITEMSET_ARG( pMedium->GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False);
676 40 : if ( !pTemplateItem || !pTemplateItem->GetValue() )
677 39 : bHasName = sal_True;
678 : }
679 : else
680 1 : SetError( ERRCODE_ABORT, ::rtl::OUString( OSL_LOG_PREFIX ) );
681 : }
682 : }
683 : else
684 0 : SetError( pMed->GetLastStorageCreationState(), ::rtl::OUString( OSL_LOG_PREFIX ) );
685 : }
686 303 : else if ( GetError() == ERRCODE_NONE && InitNew(0) )
687 : {
688 : // Name vor ConvertFrom setzen, damit GetSbxObject() schon funktioniert
689 303 : bHasName = sal_True;
690 303 : SetName( SfxResId(STR_NONAME).toString() );
691 :
692 303 : if( !bHasStorage )
693 277 : pMedium->GetInStream();
694 : else
695 26 : pMedium->GetStorage();
696 :
697 303 : if ( GetError() == ERRCODE_NONE )
698 : {
699 303 : pImp->nLoadedFlags = 0;
700 303 : pImp->bModelInitialized = sal_False;
701 303 : if ( pMedium->GetFilter() && ( pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
702 : {
703 227 : uno::Reference < beans::XPropertySet > xSet( GetModel(), uno::UNO_QUERY );
704 227 : ::rtl::OUString sLockUpdates("LockUpdates");
705 227 : bool bSetProperty = true;
706 : try
707 : {
708 231 : xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_True ) );
709 : }
710 8 : catch(const beans::UnknownPropertyException& )
711 : {
712 4 : bSetProperty = false;
713 : }
714 227 : bOk = ImportFrom( *pMedium, false );
715 227 : if(bSetProperty)
716 : {
717 : try
718 : {
719 223 : xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_False ) );
720 : }
721 0 : catch(const beans::UnknownPropertyException& )
722 : {}
723 : }
724 227 : UpdateLinks();
725 227 : FinishedLoading( SFX_LOADED_ALL );
726 : }
727 : else
728 : {
729 76 : bOk = ConvertFrom(*pMedium);
730 76 : InitOwnModel_Impl();
731 : }
732 : }
733 : }
734 :
735 344 : if ( bOk )
736 : {
737 336 : if ( IsReadOnlyMedium() || IsLoadReadonly() )
738 98 : SetReadOnlyUI();
739 :
740 : try
741 : {
742 337 : ::ucbhelper::Content aContent( pMedium->GetName(), com::sun::star::uno::Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
743 335 : com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties();
744 335 : if ( xProps.is() )
745 : {
746 335 : ::rtl::OUString aAuthor( "Author" );
747 335 : ::rtl::OUString aKeywords( "Keywords" );
748 335 : ::rtl::OUString aSubject( "Subject" );
749 335 : Any aAny;
750 335 : ::rtl::OUString aValue;
751 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
752 335 : GetModel(), uno::UNO_QUERY_THROW);
753 : uno::Reference<document::XDocumentProperties> xDocProps
754 335 : = xDPS->getDocumentProperties();
755 335 : if ( xProps->hasPropertyByName( aAuthor ) )
756 : {
757 0 : aAny = aContent.getPropertyValue( aAuthor );
758 0 : if ( ( aAny >>= aValue ) )
759 0 : xDocProps->setAuthor(aValue);
760 : }
761 335 : if ( xProps->hasPropertyByName( aKeywords ) )
762 : {
763 0 : aAny = aContent.getPropertyValue( aKeywords );
764 0 : if ( ( aAny >>= aValue ) )
765 0 : xDocProps->setKeywords(
766 0 : ::comphelper::string::convertCommaSeparated(aValue));
767 : ;
768 : }
769 335 : if ( xProps->hasPropertyByName( aSubject ) )
770 : {
771 0 : aAny = aContent.getPropertyValue( aSubject );
772 0 : if ( ( aAny >>= aValue ) ) {
773 0 : xDocProps->setSubject(aValue);
774 : }
775 335 : }
776 335 : }
777 : }
778 1 : catch( Exception& )
779 : {
780 : }
781 :
782 : // If not loaded asynchronously call FinishedLoading
783 338 : if ( !( pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) &&
784 2 : ( !pMedium->GetFilter() || pMedium->GetFilter()->UsesStorage() )
785 : )
786 1 : FinishedLoading( SFX_LOADED_MAINDOCUMENT );
787 :
788 336 : if( IsOwnStorageFormat_Impl(*pMed) && pMed->GetFilter() )
789 : {
790 : }
791 336 : Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) );
792 :
793 336 : if ( SFX_CREATE_MODE_EMBEDDED != eCreateMode )
794 : {
795 236 : SFX_ITEMSET_ARG( pMedium->GetItemSet(), pAsTempItem, SfxBoolItem, SID_TEMPLATE, sal_False);
796 236 : SFX_ITEMSET_ARG( pMedium->GetItemSet(), pPreviewItem, SfxBoolItem, SID_PREVIEW, sal_False);
797 236 : SFX_ITEMSET_ARG( pMedium->GetItemSet(), pHiddenItem, SfxBoolItem, SID_HIDDEN, sal_False);
798 941 : if( bOk && !pMedium->GetOrigURL().isEmpty()
799 0 : && !( pAsTempItem && pAsTempItem->GetValue() )
800 0 : && !( pPreviewItem && pPreviewItem->GetValue() )
801 0 : && !( pHiddenItem && pHiddenItem->GetValue() ) )
802 : {
803 235 : AddToRecentlyUsedList();
804 : }
805 : }
806 :
807 : const SfxBoolItem* pDdeReconnectItem = static_cast<const SfxBoolItem*>(
808 336 : SfxRequest::GetItem(pMedium->GetItemSet(), SID_DDE_RECONNECT_ONLOAD, false, TYPE(SfxBoolItem)));
809 :
810 336 : bool bReconnectDde = true; // by default, we try to auto-connect DDE connections.
811 336 : if (pDdeReconnectItem)
812 0 : bReconnectDde = pDdeReconnectItem->GetValue();
813 :
814 336 : if (bReconnectDde)
815 336 : ReconnectDdeLinks(*this);
816 : }
817 :
818 344 : return bOk;
819 : }
820 :
821 0 : bool SfxObjectShell::DoLoadExternal(SfxMedium *pMed, const OUString& rProvider)
822 : {
823 0 : pMedium = pMed;
824 0 : return LoadExternal(*pMedium, rProvider);
825 : }
826 :
827 344 : sal_uInt32 SfxObjectShell::HandleFilter( SfxMedium* pMedium, SfxObjectShell* pDoc )
828 : {
829 344 : sal_uInt32 nError = ERRCODE_NONE;
830 344 : SfxItemSet* pSet = pMedium->GetItemSet();
831 344 : SFX_ITEMSET_ARG( pSet, pOptions, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False );
832 344 : SFX_ITEMSET_ARG( pSet, pData, SfxUnoAnyItem, SID_FILTER_DATA, sal_False );
833 344 : if ( !pData && !pOptions )
834 : {
835 341 : com::sun::star::uno::Reference< XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
836 341 : com::sun::star::uno::Reference< XNameAccess > xFilterCFG;
837 341 : if( xServiceManager.is() )
838 : {
839 : xFilterCFG = com::sun::star::uno::Reference< XNameAccess >(
840 341 : xServiceManager->createInstance( ::rtl::OUString("com.sun.star.document.FilterFactory") ),
841 341 : UNO_QUERY );
842 : }
843 :
844 341 : if( xFilterCFG.is() )
845 : {
846 313 : sal_Bool bAbort = sal_False;
847 : try {
848 313 : const SfxFilter* pFilter = pMedium->GetFilter();
849 313 : Sequence < PropertyValue > aProps;
850 313 : Any aAny = xFilterCFG->getByName( pFilter->GetName() );
851 313 : if ( aAny >>= aProps )
852 : {
853 313 : sal_Int32 nPropertyCount = aProps.getLength();
854 3387 : for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty )
855 3387 : if( aProps[nProperty].Name == "UIComponent" )
856 : {
857 313 : ::rtl::OUString aServiceName;
858 313 : aProps[nProperty].Value >>= aServiceName;
859 313 : if( !aServiceName.isEmpty() )
860 : {
861 4 : com::sun::star::uno::Reference< XInteractionHandler > rHandler = pMedium->GetInteractionHandler();
862 4 : if( rHandler.is() )
863 : {
864 : // we need some properties in the media descriptor, so we have to make sure that they are in
865 0 : Any aStreamAny;
866 0 : aStreamAny <<= pMedium->GetInputStream();
867 0 : if ( pSet->GetItemState( SID_INPUTSTREAM ) < SFX_ITEM_SET )
868 0 : pSet->Put( SfxUnoAnyItem( SID_INPUTSTREAM, aStreamAny ) );
869 0 : if ( pSet->GetItemState( SID_FILE_NAME ) < SFX_ITEM_SET )
870 0 : pSet->Put( SfxStringItem( SID_FILE_NAME, pMedium->GetName() ) );
871 0 : if ( pSet->GetItemState( SID_FILTER_NAME ) < SFX_ITEM_SET )
872 0 : pSet->Put( SfxStringItem( SID_FILTER_NAME, pFilter->GetName() ) );
873 :
874 0 : Sequence< PropertyValue > rProperties;
875 0 : TransformItems( SID_OPENDOC, *pSet, rProperties, NULL );
876 0 : RequestFilterOptions* pFORequest = new RequestFilterOptions( pDoc->GetModel(), rProperties );
877 :
878 0 : com::sun::star::uno::Reference< XInteractionRequest > rRequest( pFORequest );
879 0 : rHandler->handle( rRequest );
880 :
881 0 : if ( !pFORequest->isAbort() )
882 : {
883 0 : SfxAllItemSet aNewParams( pDoc->GetPool() );
884 : TransformParameters( SID_OPENDOC,
885 : pFORequest->getFilterOptions(),
886 : aNewParams,
887 0 : NULL );
888 :
889 0 : SFX_ITEMSET_ARG( &aNewParams,
890 : pFilterOptions,
891 : SfxStringItem,
892 : SID_FILE_FILTEROPTIONS,
893 : sal_False );
894 0 : if ( pFilterOptions )
895 0 : pSet->Put( *pFilterOptions );
896 :
897 0 : SFX_ITEMSET_ARG( &aNewParams,
898 : pFilterData,
899 : SfxUnoAnyItem,
900 : SID_FILTER_DATA,
901 : sal_False );
902 0 : if ( pFilterData )
903 0 : pSet->Put( *pFilterData );
904 : }
905 : else
906 0 : bAbort = sal_True;
907 4 : }
908 : }
909 :
910 313 : break;
911 : }
912 : }
913 :
914 313 : if( bAbort )
915 : {
916 : // filter options were not entered
917 0 : nError = ERRCODE_ABORT;
918 313 : }
919 : }
920 0 : catch( NoSuchElementException& )
921 : {
922 : // the filter name is unknown
923 0 : nError = ERRCODE_IO_INVALIDPARAMETER;
924 : }
925 0 : catch( Exception& )
926 : {
927 0 : nError = ERRCODE_ABORT;
928 : }
929 341 : }
930 : }
931 :
932 344 : return nError;
933 : }
934 :
935 : //-------------------------------------------------------------------------
936 :
937 1139 : sal_Bool SfxObjectShell::IsOwnStorageFormat_Impl(const SfxMedium &rMedium) const
938 : {
939 1139 : return !rMedium.GetFilter() || // Embedded
940 1136 : ( rMedium.GetFilter()->IsOwnFormat() &&
941 136 : rMedium.GetFilter()->UsesStorage() &&
942 2411 : rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 );
943 : }
944 :
945 : //-------------------------------------------------------------------------
946 :
947 949 : sal_Bool SfxObjectShell::IsPackageStorageFormat_Impl(const SfxMedium &rMedium) const
948 : {
949 949 : return !rMedium.GetFilter() || // Embedded
950 946 : ( rMedium.GetFilter()->UsesStorage() &&
951 1895 : rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 );
952 : }
953 :
954 : //-------------------------------------------------------------------------
955 :
956 0 : sal_Bool SfxObjectShell::DoSave()
957 : // DoSave is only invoked for OLE. Save your own documents in the SFX through
958 : // DoSave_Impl order to allow for the creation of backups.
959 : // Save in your own format again.
960 : {
961 0 : sal_Bool bOk = sal_False ;
962 : {
963 0 : ModifyBlocker_Impl aBlock( this );
964 :
965 0 : pImp->bIsSaving = sal_True;
966 :
967 0 : uno::Sequence< beans::NamedValue > aEncryptionData;
968 0 : if ( IsPackageStorageFormat_Impl( *GetMedium() ) )
969 : {
970 0 : if ( GetEncryptionData_Impl( GetMedium()->GetItemSet(), aEncryptionData ) )
971 : {
972 : try
973 : {
974 : //TODO/MBA: GetOutputStorage?! Special mode, because it's "Save"?!
975 0 : ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( GetMedium()->GetStorage(), aEncryptionData );
976 0 : bOk = sal_True;
977 : }
978 0 : catch( uno::Exception& )
979 : {
980 0 : SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
981 : }
982 :
983 : DBG_ASSERT( bOk, "The root storage must allow to set common password!\n" );
984 : }
985 : else
986 0 : bOk = sal_True;
987 : #ifndef DISABLE_SCRIPTING
988 0 : if ( HasBasic() )
989 : {
990 : try
991 : {
992 : // The basic and dialogs related contents are still not able to proceed with save operation ( saveTo only )
993 : // so since the document storage is locked a workaround has to be used
994 :
995 0 : uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
996 : DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" );
997 0 : if ( !xTmpStorage.is() )
998 0 : throw uno::RuntimeException();
999 :
1000 0 : ::rtl::OUString aBasicStorageName( "Basic" );
1001 0 : ::rtl::OUString aDialogsStorageName( "Dialogs" );
1002 0 : if ( GetMedium()->GetStorage()->hasByName( aBasicStorageName ) )
1003 0 : GetMedium()->GetStorage()->copyElementTo( aBasicStorageName, xTmpStorage, aBasicStorageName );
1004 0 : if ( GetMedium()->GetStorage()->hasByName( aDialogsStorageName ) )
1005 0 : GetMedium()->GetStorage()->copyElementTo( aDialogsStorageName, xTmpStorage, aDialogsStorageName );
1006 :
1007 0 : GetBasicManager();
1008 :
1009 : // disconnect from the current storage
1010 0 : pImp->pBasicManager->setStorage( xTmpStorage );
1011 :
1012 : // store to the current storage
1013 0 : pImp->pBasicManager->storeLibrariesToStorage( GetMedium()->GetStorage() );
1014 :
1015 : // connect to the current storage back
1016 0 : pImp->pBasicManager->setStorage( GetMedium()->GetStorage() );
1017 : }
1018 0 : catch( uno::Exception& )
1019 : {
1020 0 : SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1021 0 : bOk = sal_False;
1022 : }
1023 : }
1024 : #endif
1025 : }
1026 :
1027 0 : if ( bOk )
1028 0 : bOk = Save();
1029 :
1030 0 : bOk = pMedium->Commit();
1031 : }
1032 :
1033 0 : return bOk;
1034 : }
1035 :
1036 118 : void Lock_Impl( SfxObjectShell* pDoc, sal_Bool bLock )
1037 : {
1038 118 : SfxViewFrame *pFrame= SfxViewFrame::GetFirst( pDoc );
1039 346 : while ( pFrame )
1040 : {
1041 110 : pFrame->GetDispatcher()->Lock( bLock );
1042 110 : pFrame->Enable( !bLock );
1043 110 : pFrame = SfxViewFrame::GetNext( *pFrame, pDoc );
1044 : }
1045 :
1046 118 : }
1047 :
1048 : //-------------------------------------------------------------------------
1049 :
1050 59 : sal_Bool SfxObjectShell::SaveTo_Impl
1051 : (
1052 : SfxMedium &rMedium, // Medium, in which it will be stored
1053 : const SfxItemSet* pSet
1054 : )
1055 :
1056 : /* [Description]
1057 :
1058 : Writes the current contents to the medium rMedium. If the target medium is
1059 : no storage, then saving to a temporary storage, or directly if the medium
1060 : is transacted, if we ourselves have opened it, and if we are a server
1061 : either the container a transacted storage provides or created a
1062 : temporary storage by one self.
1063 : */
1064 :
1065 : {
1066 59 : RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::SaveTo_Impl" );
1067 59 : if( RTL_LOGFILE_HASLOGFILE() )
1068 : {
1069 : rtl::OString aString(
1070 0 : rtl::OUStringToOString(rMedium.GetName(), RTL_TEXTENCODING_ASCII_US));
1071 0 : RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1(aLog, "saving \"%s\"", aString.getStr());
1072 : }
1073 :
1074 59 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Begin" ) );
1075 :
1076 59 : ModifyBlocker_Impl aMod(this);
1077 :
1078 59 : const SfxFilter *pFilter = rMedium.GetFilter();
1079 59 : if ( !pFilter )
1080 : {
1081 : // if no filter was set, use the default filter
1082 : // this should be changed in the feature, it should be an error!
1083 : OSL_FAIL("No filter set!");
1084 0 : pFilter = GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT );
1085 0 : rMedium.SetFilter(pFilter);
1086 : }
1087 :
1088 59 : sal_Bool bStorageBasedSource = IsPackageStorageFormat_Impl( *pMedium );
1089 59 : sal_Bool bStorageBasedTarget = IsPackageStorageFormat_Impl( rMedium );
1090 59 : sal_Bool bOwnSource = IsOwnStorageFormat_Impl( *pMedium );
1091 59 : sal_Bool bOwnTarget = IsOwnStorageFormat_Impl( rMedium );
1092 :
1093 : // Examine target format to determine whether to query if any password
1094 : // protected libraries exceed the size we can handler
1095 59 : if ( bOwnTarget && !QuerySaveSizeExceededModules_Impl( rMedium.GetInteractionHandler() ) )
1096 : {
1097 0 : SetError( ERRCODE_IO_ABORT, ::rtl::OUString( OSL_LOG_PREFIX ) );
1098 0 : return sal_False;
1099 : }
1100 :
1101 59 : sal_Bool bNeedsDisconnectionOnFail = sal_False;
1102 :
1103 59 : sal_Bool bStoreToSameLocation = sal_False;
1104 :
1105 : // the detection whether the script is changed should be done before saving
1106 59 : sal_Bool bTryToPreserveScriptSignature = sal_False;
1107 : // no way to detect whether a filter is oasis format, have to wait for saving process
1108 59 : sal_Bool bNoPreserveForOasis = sal_False;
1109 59 : if ( bOwnSource && bOwnTarget
1110 : && ( pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_OK
1111 : || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED
1112 : || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_INVALID ) )
1113 : {
1114 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "MacroSignaturePreserving" ) );
1115 :
1116 : // the checking of the library modified state iterates over the libraries, should be done only when required
1117 : // currently the check is commented out since it is broken, we have to check the signature every time we save
1118 : // TODO/LATER: let isAnyContainerModified() work!
1119 0 : bTryToPreserveScriptSignature = sal_True; // !pImp->pBasicManager->isAnyContainerModified();
1120 0 : if ( bTryToPreserveScriptSignature )
1121 : {
1122 : // check that the storage format stays the same
1123 0 : SvtSaveOptions aSaveOpt;
1124 0 : SvtSaveOptions::ODFDefaultVersion nVersion = aSaveOpt.GetODFDefaultVersion();
1125 :
1126 0 : ::rtl::OUString aODFVersion;
1127 : try
1128 : {
1129 0 : uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW );
1130 0 : xPropSet->getPropertyValue( ::rtl::OUString( "Version" ) ) >>= aODFVersion;
1131 : }
1132 0 : catch( uno::Exception& )
1133 : {}
1134 :
1135 : // preserve only if the same filter has been used
1136 0 : bTryToPreserveScriptSignature = pMedium->GetFilter() && pFilter && pMedium->GetFilter()->GetFilterName() == pFilter->GetFilterName();
1137 :
1138 : bNoPreserveForOasis = (
1139 0 : (aODFVersion.equals( ODFVER_012_TEXT ) && nVersion == SvtSaveOptions::ODFVER_011) ||
1140 0 : (aODFVersion.isEmpty() && nVersion >= SvtSaveOptions::ODFVER_012)
1141 0 : );
1142 : }
1143 : }
1144 :
1145 59 : sal_Bool bCopyTo = sal_False;
1146 59 : SfxItemSet *pMedSet = rMedium.GetItemSet();
1147 59 : if( pMedSet )
1148 : {
1149 59 : SFX_ITEMSET_ARG( pMedSet, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
1150 59 : bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ||
1151 59 : (pSaveToItem && pSaveToItem->GetValue());
1152 : }
1153 :
1154 : // use UCB for case sensitive/insensitive file name comparison
1155 236 : if ( pMedium
1156 59 : && !pMedium->GetName().equalsIgnoreAsciiCaseAscii("private:stream")
1157 59 : && !rMedium.GetName().equalsIgnoreAsciiCaseAscii("private:stream")
1158 59 : && ::utl::UCBContentHelper::EqualURLs( pMedium->GetName(), rMedium.GetName() ) )
1159 : {
1160 0 : bStoreToSameLocation = sal_True;
1161 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save" ) );
1162 :
1163 0 : if ( pMedium->DocNeedsFileDateCheck() )
1164 0 : rMedium.CheckFileDate( pMedium->GetInitFileDate( sal_False ) );
1165 :
1166 0 : if ( bCopyTo && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED )
1167 : {
1168 : // export to the same location is forbidden
1169 0 : SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( OSL_LOG_PREFIX ) );
1170 : }
1171 : else
1172 : {
1173 : // before we overwrite the original file, we will make a backup if there is a demand for that
1174 : // if the backup is not created here it will be created internally and will be removed in case of successful saving
1175 0 : const sal_Bool bDoBackup = SvtSaveOptions().IsBackup();
1176 0 : if ( bDoBackup )
1177 : {
1178 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "DoBackup" ) );
1179 0 : rMedium.DoBackup_Impl();
1180 0 : if ( rMedium.GetError() )
1181 : {
1182 0 : SetError( rMedium.GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
1183 0 : rMedium.ResetError();
1184 : }
1185 : }
1186 :
1187 0 : if ( bStorageBasedSource && bStorageBasedTarget )
1188 : {
1189 : // The active storage must be switched. The simple saving is not enough.
1190 : // The problem is that the target medium contains target MediaDescriptor.
1191 :
1192 : // In future the switch of the persistance could be done on stream level:
1193 : // a new wrapper service will be implemented that allows to exchange
1194 : // persistance on the fly. So the real persistance will be set
1195 : // to that stream only after successful commit of the storage.
1196 : // TODO/LATER:
1197 : // create wrapper stream based on the URL
1198 : // create a new storage based on this stream
1199 : // store to this new storage
1200 : // commit the new storage
1201 : // call saveCompleted based with this new storage ( get rid of old storage and "frees" URL )
1202 : // commit the wrapper stream ( the stream will connect the URL only on commit, after that it will hold it )
1203 : // if the last step is failed the stream should stay to be transacted and should be commited on any flush
1204 : // so we can forget the stream in any way and the next storage commit will flush it
1205 :
1206 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save: Own to Own" ) );
1207 :
1208 : bNeedsDisconnectionOnFail = DisconnectStorage_Impl(
1209 0 : *pMedium, rMedium );
1210 0 : if ( bNeedsDisconnectionOnFail
1211 0 : || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1212 : {
1213 0 : pMedium->CloseAndRelease();
1214 :
1215 : // TODO/LATER: for now the medium must be closed since it can already contain streams from old medium
1216 : // in future those streams should not be copied in case a valid target url is provided,
1217 : // if the url is not provided ( means the document is based on a stream ) this code is not
1218 : // reachable.
1219 0 : rMedium.CloseAndRelease();
1220 0 : rMedium.GetOutputStorage();
1221 : }
1222 : }
1223 0 : else if ( !bStorageBasedSource && !bStorageBasedTarget )
1224 : {
1225 : // the source and the target formats are alien
1226 : // just disconnect the stream from the source format
1227 : // so that the target medium can use it
1228 :
1229 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save: Alien to Alien" ) );
1230 :
1231 0 : pMedium->CloseAndRelease();
1232 0 : rMedium.CloseAndRelease();
1233 0 : rMedium.CreateTempFileNoCopy();
1234 0 : rMedium.GetOutStream();
1235 : }
1236 0 : else if ( !bStorageBasedSource && bStorageBasedTarget )
1237 : {
1238 : // the source format is an alien one but the target
1239 : // format is an own one so just disconnect the source
1240 : // medium
1241 :
1242 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save: Alien to Own" ) );
1243 :
1244 0 : pMedium->CloseAndRelease();
1245 0 : rMedium.CloseAndRelease();
1246 0 : rMedium.GetOutputStorage();
1247 : }
1248 : else // means if ( bStorageBasedSource && !bStorageBasedTarget )
1249 : {
1250 : // the source format is an own one but the target is
1251 : // an alien format, just connect the source to temporary
1252 : // storage
1253 :
1254 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save: Own to Alien" ) );
1255 :
1256 : bNeedsDisconnectionOnFail = DisconnectStorage_Impl(
1257 0 : *pMedium, rMedium );
1258 0 : if ( bNeedsDisconnectionOnFail
1259 0 : || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1260 : {
1261 0 : pMedium->CloseAndRelease();
1262 0 : rMedium.CloseAndRelease();
1263 0 : rMedium.CreateTempFileNoCopy();
1264 0 : rMedium.GetOutStream();
1265 : }
1266 : }
1267 : }
1268 : }
1269 : else
1270 : {
1271 : // This is SaveAs or export action, prepare the target medium
1272 : // the alien filters still might write directly to the file, that is of course a bug,
1273 : // but for now the framework has to be ready for it
1274 : // TODO/LATER: let the medium be prepared for alien formats as well
1275 :
1276 59 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "SaveAs/Export" ) );
1277 :
1278 59 : rMedium.CloseAndRelease();
1279 59 : if ( bStorageBasedTarget )
1280 : {
1281 5 : rMedium.GetOutputStorage();
1282 : }
1283 : }
1284 :
1285 : // TODO/LATER: error handling
1286 59 : if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() )
1287 0 : return sal_False;
1288 :
1289 59 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Locking" ) );
1290 :
1291 59 : rMedium.LockOrigFileOnDemand( sal_False, sal_False );
1292 :
1293 59 : if ( bStorageBasedTarget )
1294 : {
1295 5 : if ( rMedium.GetErrorCode() )
1296 0 : return sal_False;
1297 :
1298 : // If the filter is a "cross export" filter ( f.e. a filter for exporting an impress document from
1299 : // a draw document ), the ClassId of the destination storage is different from the ClassId of this
1300 : // document. It can be retrieved from the default filter for the desired target format
1301 5 : long nFormat = rMedium.GetFilter()->GetFormat();
1302 5 : SfxFilterMatcher& rMatcher = SFX_APP()->GetFilterMatcher();
1303 5 : const SfxFilter *pFilt = rMatcher.GetFilter4ClipBoardId( nFormat );
1304 5 : if ( pFilt )
1305 : {
1306 5 : if ( pFilt->GetServiceName() != rMedium.GetFilter()->GetServiceName() )
1307 : {
1308 3 : datatransfer::DataFlavor aDataFlavor;
1309 3 : SotExchange::GetFormatDataFlavor( nFormat, aDataFlavor );
1310 :
1311 : try
1312 : {
1313 3 : uno::Reference< beans::XPropertySet > xProps( rMedium.GetStorage(), uno::UNO_QUERY );
1314 : DBG_ASSERT( xProps.is(), "The storage implementation must implement XPropertySet!" );
1315 3 : if ( !xProps.is() )
1316 0 : throw uno::RuntimeException();
1317 :
1318 3 : xProps->setPropertyValue( ::rtl::OUString("MediaType"),
1319 3 : uno::makeAny( aDataFlavor.MimeType ) );
1320 : }
1321 0 : catch( uno::Exception& )
1322 : {
1323 3 : }
1324 : }
1325 : }
1326 : }
1327 :
1328 : // TODO/LATER: error handling
1329 59 : if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() )
1330 0 : return sal_False;
1331 :
1332 59 : sal_Bool bOldStat = pImp->bForbidReload;
1333 59 : pImp->bForbidReload = sal_True;
1334 :
1335 : // lock user interface while saving the document
1336 59 : Lock_Impl( this, sal_True );
1337 :
1338 59 : sal_Bool bOk = sal_False;
1339 : // TODO/LATER: get rid of bOk
1340 :
1341 59 : if( bOwnTarget && !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
1342 : {
1343 4 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing in own format." ) );
1344 4 : uno::Reference< embed::XStorage > xMedStorage = rMedium.GetStorage();
1345 4 : if ( !xMedStorage.is() )
1346 : {
1347 : // no saving without storage, unlock UI and return
1348 0 : Lock_Impl( this, sal_False );
1349 0 : pImp->bForbidReload = bOldStat;
1350 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing failed, still no error set." ) );
1351 0 : return sal_False;
1352 : }
1353 :
1354 : // transfer password from the parameters to the storage
1355 4 : uno::Sequence< beans::NamedValue > aEncryptionData;
1356 4 : sal_Bool bPasswdProvided = sal_False;
1357 4 : if ( GetEncryptionData_Impl( rMedium.GetItemSet(), aEncryptionData ) )
1358 : {
1359 1 : bPasswdProvided = sal_True;
1360 : try {
1361 1 : ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xMedStorage, aEncryptionData );
1362 1 : bOk = sal_True;
1363 : }
1364 0 : catch( uno::Exception& )
1365 : {
1366 : OSL_FAIL( "Setting of common encryption key failed!" );
1367 0 : SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1368 : }
1369 : }
1370 : else
1371 3 : bOk = sal_True;
1372 :
1373 4 : pFilter = rMedium.GetFilter();
1374 :
1375 4 : const SfxStringItem *pVersionItem = ( !rMedium.IsInCheckIn( ) && pSet ) ? (const SfxStringItem*)
1376 4 : SfxRequest::GetItem( pSet, SID_DOCINFO_COMMENTS, sal_False, TYPE(SfxStringItem) ) : NULL;
1377 4 : ::rtl::OUString aTmpVersionURL;
1378 :
1379 4 : if ( bOk )
1380 : {
1381 4 : bOk = sal_False;
1382 : // currently the case that the storage is the same should be impossible
1383 4 : if ( xMedStorage == GetStorage() )
1384 : {
1385 : OSL_ENSURE( !pVersionItem, "This scenario is impossible currently!\n" );
1386 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Should be impossible." ) );
1387 : // usual save procedure
1388 0 : bOk = Save();
1389 : }
1390 : else
1391 : {
1392 : // save to target
1393 4 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save as own format." ) );
1394 4 : bOk = SaveAsOwnFormat( rMedium );
1395 4 : if ( bOk && pVersionItem )
1396 : {
1397 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "pVersionItem != NULL" ) );
1398 0 : aTmpVersionURL = CreateTempCopyOfStorage_Impl( xMedStorage );
1399 0 : bOk = !aTmpVersionURL.isEmpty();
1400 : }
1401 : }
1402 : }
1403 :
1404 :
1405 4 : if ( bOk && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED && !bPasswdProvided )
1406 : {
1407 : // store the thumbnail representation image
1408 : // the thumbnail is not stored in case of encrypted document
1409 3 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Thumbnail creation." ) );
1410 3 : if ( !GenerateAndStoreThumbnail( bPasswdProvided,
1411 : sal_False,
1412 3 : pFilter->IsOwnTemplateFormat(),
1413 3 : xMedStorage ) )
1414 : {
1415 : // TODO: error handling
1416 : OSL_FAIL( "Couldn't store thumbnail representation!" );
1417 : }
1418 : }
1419 :
1420 4 : if ( bOk )
1421 : {
1422 4 : if ( pImp->bIsSaving || pImp->bPreserveVersions )
1423 : {
1424 4 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Preserve versions." ) );
1425 : try
1426 : {
1427 4 : Sequence < util::RevisionTag > aVersions = rMedium.GetVersionList();
1428 4 : if ( aVersions.getLength() )
1429 : {
1430 : // copy the version streams
1431 0 : ::rtl::OUString aVersionsName( "Versions" );
1432 0 : uno::Reference< embed::XStorage > xNewVerStor = xMedStorage->openStorageElement(
1433 : aVersionsName,
1434 0 : embed::ElementModes::READWRITE );
1435 0 : uno::Reference< embed::XStorage > xOldVerStor = GetStorage()->openStorageElement(
1436 : aVersionsName,
1437 0 : embed::ElementModes::READ );
1438 0 : if ( !xNewVerStor.is() || !xOldVerStor.is() )
1439 0 : throw uno::RuntimeException();
1440 :
1441 0 : for ( sal_Int32 n=0; n<aVersions.getLength(); n++ )
1442 : {
1443 0 : if ( xOldVerStor->hasByName( aVersions[n].Identifier ) )
1444 0 : xOldVerStor->copyElementTo( aVersions[n].Identifier, xNewVerStor, aVersions[n].Identifier );
1445 : }
1446 :
1447 0 : uno::Reference< embed::XTransactedObject > xTransact( xNewVerStor, uno::UNO_QUERY );
1448 0 : if ( xTransact.is() )
1449 0 : xTransact->commit();
1450 4 : }
1451 : }
1452 0 : catch( uno::Exception& )
1453 : {
1454 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Preserve versions has failed." ) );
1455 : OSL_FAIL( "Couldn't copy versions!\n" );
1456 0 : bOk = sal_False;
1457 : // TODO/LATER: a specific error could be set
1458 : }
1459 : }
1460 :
1461 4 : if ( bOk && pVersionItem && !rMedium.IsInCheckIn() )
1462 : {
1463 : // store a version also
1464 : const SfxStringItem *pAuthorItem = pSet ? (const SfxStringItem*)
1465 0 : SfxRequest::GetItem( pSet, SID_DOCINFO_AUTHOR, sal_False, TYPE(SfxStringItem) ) : NULL;
1466 :
1467 : // version comment
1468 0 : util::RevisionTag aInfo;
1469 0 : aInfo.Comment = pVersionItem->GetValue();
1470 :
1471 : // version author
1472 0 : if ( pAuthorItem )
1473 0 : aInfo.Author = pAuthorItem->GetValue();
1474 : else
1475 : // if not transferred as a parameter, get it from user settings
1476 0 : aInfo.Author = SvtUserOptions().GetFullName();
1477 :
1478 0 : DateTime aTime( DateTime::SYSTEM );
1479 0 : aInfo.TimeStamp.Day = aTime.GetDay();
1480 0 : aInfo.TimeStamp.Month = aTime.GetMonth();
1481 0 : aInfo.TimeStamp.Year = aTime.GetYear();
1482 0 : aInfo.TimeStamp.Hours = aTime.GetHour();
1483 0 : aInfo.TimeStamp.Minutes = aTime.GetMin();
1484 0 : aInfo.TimeStamp.Seconds = aTime.GetSec();
1485 :
1486 0 : if ( bOk )
1487 : {
1488 : // add new version information into the versionlist and save the versionlist
1489 : // the version list must have been transferred from the "old" medium before
1490 0 : rMedium.AddVersion_Impl( aInfo );
1491 0 : rMedium.SaveVersionList_Impl( sal_True );
1492 0 : bOk = PutURLContentsToVersionStream_Impl( aTmpVersionURL, xMedStorage, aInfo.Identifier );
1493 0 : }
1494 : }
1495 4 : else if ( bOk && ( pImp->bIsSaving || pImp->bPreserveVersions ) )
1496 : {
1497 4 : rMedium.SaveVersionList_Impl( sal_True );
1498 : }
1499 : }
1500 :
1501 4 : if ( !aTmpVersionURL.isEmpty() )
1502 0 : ::utl::UCBContentHelper::Kill( aTmpVersionURL );
1503 : }
1504 : else
1505 : {
1506 55 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing in alien format." ) );
1507 : // it's a "SaveAs" in an alien format
1508 55 : if ( rMedium.GetFilter() && ( rMedium.GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
1509 54 : bOk = ExportTo( rMedium );
1510 : else
1511 1 : bOk = ConvertTo( rMedium );
1512 :
1513 : // after saving the document, the temporary object storage must be updated
1514 : // if the old object storage was not a temporary one, it will be updated also, because it will be used
1515 : // as a source for copying the objects into the new temporary storage that will be created below
1516 : // updating means: all child objects must be stored into it
1517 : // ( same as on loading, where these objects are copied to the temporary storage )
1518 : // but don't commit these changes, because in the case when the old object storage is not a temporary one,
1519 : // all changes will be written into the original file !
1520 :
1521 55 : if( bOk && !bCopyTo )
1522 : // we also don't touch any graphical replacements here
1523 0 : bOk = SaveChildren( sal_True );
1524 : }
1525 :
1526 59 : if ( bOk )
1527 : {
1528 : // if ODF version of oasis format changes on saving the signature should not be preserved
1529 59 : if ( bOk && bTryToPreserveScriptSignature && bNoPreserveForOasis )
1530 0 : bTryToPreserveScriptSignature = ( SotStorage::GetVersion( rMedium.GetStorage() ) == SOFFICE_FILEFORMAT_60 );
1531 :
1532 59 : uno::Reference< security::XDocumentDigitalSignatures > xDDSigns;
1533 59 : if ( bOk && bTryToPreserveScriptSignature )
1534 : {
1535 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Copying scripting signature." ) );
1536 :
1537 : // if the scripting code was not changed and it is signed the signature should be preserved
1538 : // unfortunately at this point we have only information whether the basic code has changed or not
1539 : // so the only way is to check the signature if the basic was not changed
1540 : try
1541 : {
1542 : // get the ODF version of the new medium
1543 0 : OUString aVersion;
1544 : try
1545 : {
1546 0 : uno::Reference < beans::XPropertySet > xPropSet( rMedium.GetStorage(), uno::UNO_QUERY_THROW );
1547 0 : xPropSet->getPropertyValue( ::rtl::OUString( "Version" ) ) >>= aVersion;
1548 : }
1549 0 : catch( uno::Exception& )
1550 : {
1551 : }
1552 :
1553 0 : xDDSigns = security::DocumentDigitalSignatures::createWithVersion(comphelper::getProcessComponentContext(), aVersion);
1554 :
1555 0 : ::rtl::OUString aScriptSignName = xDDSigns->getScriptingContentSignatureDefaultStreamName();
1556 :
1557 0 : if ( !aScriptSignName.isEmpty() )
1558 : {
1559 0 : pMedium->Close();
1560 :
1561 : // target medium is still not commited, it should not be closed
1562 : // commit the package storage and close it, but leave the streams open
1563 0 : rMedium.StorageCommit_Impl();
1564 0 : rMedium.CloseStorage();
1565 :
1566 0 : uno::Reference< embed::XStorage > xReadOrig = pMedium->GetZipStorageToSign_Impl();
1567 0 : if ( !xReadOrig.is() )
1568 0 : throw uno::RuntimeException();
1569 0 : uno::Reference< embed::XStorage > xMetaInf = xReadOrig->openStorageElement(
1570 : ::rtl::OUString( "META-INF" ),
1571 0 : embed::ElementModes::READ );
1572 :
1573 0 : uno::Reference< embed::XStorage > xTarget = rMedium.GetZipStorageToSign_Impl( sal_False );
1574 0 : if ( !xTarget.is() )
1575 0 : throw uno::RuntimeException();
1576 0 : uno::Reference< embed::XStorage > xTargetMetaInf = xTarget->openStorageElement(
1577 : ::rtl::OUString( "META-INF" ),
1578 0 : embed::ElementModes::READWRITE );
1579 :
1580 0 : if ( xMetaInf.is() && xTargetMetaInf.is() )
1581 : {
1582 0 : xMetaInf->copyElementTo( aScriptSignName, xTargetMetaInf, aScriptSignName );
1583 :
1584 0 : uno::Reference< embed::XTransactedObject > xTransact( xTargetMetaInf, uno::UNO_QUERY );
1585 0 : if ( xTransact.is() )
1586 0 : xTransact->commit();
1587 :
1588 0 : xTargetMetaInf->dispose();
1589 :
1590 : // now check the copied signature
1591 : uno::Sequence< security::DocumentSignatureInformation > aInfos =
1592 0 : xDDSigns->verifyScriptingContentSignatures( xTarget,
1593 0 : uno::Reference< io::XInputStream >() );
1594 0 : sal_uInt16 nState = ImplCheckSignaturesInformation( aInfos );
1595 0 : if ( nState == SIGNATURESTATE_SIGNATURES_OK || nState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED
1596 : || nState == SIGNATURESTATE_SIGNATURES_PARTIAL_OK)
1597 : {
1598 0 : rMedium.SetCachedSignatureState_Impl( nState );
1599 :
1600 : // commit the ZipStorage from target medium
1601 0 : xTransact.set( xTarget, uno::UNO_QUERY );
1602 0 : if ( xTransact.is() )
1603 0 : xTransact->commit();
1604 : }
1605 : else
1606 : {
1607 : // it should not happen, the copies signature is invalid!
1608 : // throw the changes away
1609 : OSL_FAIL( "An invalid signature was copied!" );
1610 0 : }
1611 0 : }
1612 0 : }
1613 : }
1614 0 : catch( uno::Exception& )
1615 : {
1616 : }
1617 :
1618 0 : pMedium->Close();
1619 0 : rMedium.CloseZipStorage_Impl();
1620 : }
1621 :
1622 59 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Medium commit." ) );
1623 :
1624 59 : rtl::OUString sName( rMedium.GetName( ) );
1625 59 : bOk = rMedium.Commit();
1626 59 : rtl::OUString sNewName( rMedium.GetName( ) );
1627 :
1628 59 : if ( sName != sNewName )
1629 0 : GetMedium( )->SwitchDocumentToFile( sNewName );
1630 :
1631 59 : if ( bOk )
1632 : {
1633 59 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing is successful." ) );
1634 :
1635 : // if the target medium is an alien format and the "old" medium was an own format and the "old" medium
1636 : // has a name, the object storage must be exchanged, because now we need a new temporary storage
1637 : // as object storage
1638 59 : if ( !bCopyTo && bStorageBasedSource && !bStorageBasedTarget )
1639 : {
1640 0 : if ( bStoreToSameLocation )
1641 : {
1642 : // if the old medium already disconnected from document storage, the storage still must
1643 : // be switched if backup file is used
1644 0 : if ( bNeedsDisconnectionOnFail )
1645 0 : ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
1646 : }
1647 0 : else if (!pMedium->GetName().isEmpty()
1648 0 : || ( pMedium->HasStorage_Impl() && pMedium->WillDisposeStorageOnClose_Impl() ) )
1649 : {
1650 : OSL_ENSURE(!pMedium->GetName().isEmpty(), "Fallback is used, the medium without name should not dispose the storage!\n");
1651 : // copy storage of old medium to new temporary storage and take this over
1652 0 : if( !ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1653 : {
1654 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Process after storing has failed." ) );
1655 0 : bOk = sal_False;
1656 : }
1657 : }
1658 : }
1659 : }
1660 : else
1661 : {
1662 0 : AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing has failed." ) );
1663 :
1664 : // in case the document storage was connected to backup temporarely it must be disconnected now
1665 0 : if ( bNeedsDisconnectionOnFail )
1666 0 : ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
1667 59 : }
1668 : }
1669 :
1670 : // unlock user interface
1671 59 : Lock_Impl( this, sal_False );
1672 59 : pImp->bForbidReload = bOldStat;
1673 :
1674 59 : if ( bOk )
1675 : {
1676 : try
1677 : {
1678 59 : ::ucbhelper::Content aContent( rMedium.GetName(), com::sun::star::uno::Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
1679 59 : com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties();
1680 59 : if ( xProps.is() )
1681 : {
1682 59 : ::rtl::OUString aAuthor( "Author" );
1683 59 : ::rtl::OUString aKeywords( "Keywords" );
1684 59 : ::rtl::OUString aSubject( "Subject" );
1685 59 : Any aAny;
1686 :
1687 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1688 59 : GetModel(), uno::UNO_QUERY_THROW);
1689 : uno::Reference<document::XDocumentProperties> xDocProps
1690 59 : = xDPS->getDocumentProperties();
1691 :
1692 59 : if ( xProps->hasPropertyByName( aAuthor ) )
1693 : {
1694 0 : aAny <<= xDocProps->getAuthor();
1695 0 : aContent.setPropertyValue( aAuthor, aAny );
1696 : }
1697 59 : if ( xProps->hasPropertyByName( aKeywords ) )
1698 : {
1699 : aAny <<= ::comphelper::string::convertCommaSeparated(
1700 0 : xDocProps->getKeywords());
1701 0 : aContent.setPropertyValue( aKeywords, aAny );
1702 : }
1703 59 : if ( xProps->hasPropertyByName( aSubject ) )
1704 : {
1705 0 : aAny <<= xDocProps->getSubject();
1706 0 : aContent.setPropertyValue( aSubject, aAny );
1707 59 : }
1708 59 : }
1709 : }
1710 0 : catch( Exception& )
1711 : {
1712 : }
1713 : }
1714 :
1715 59 : return bOk;
1716 : }
1717 :
1718 : //------------------------------------------------------------------------
1719 0 : sal_Bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& rTargetMedium )
1720 : {
1721 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DisconnectStorage_Impl" );
1722 :
1723 : // this method disconnects the storage from source medium, and attaches it to the backup created by the target medium
1724 :
1725 0 : uno::Reference< embed::XStorage > xStorage = rSrcMedium.GetStorage();
1726 :
1727 0 : sal_Bool bResult = sal_False;
1728 0 : if ( xStorage == pImp->m_xDocStorage )
1729 : {
1730 : try
1731 : {
1732 0 : uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW );
1733 0 : ::rtl::OUString aBackupURL = rTargetMedium.GetBackup_Impl();
1734 0 : if ( aBackupURL.isEmpty() )
1735 : {
1736 : // the backup could not be created, try to disconnect the storage and close the source SfxMedium
1737 : // in this case the optimization is not possible, connect storage to a temporary file
1738 0 : rTargetMedium.ResetError();
1739 0 : xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() );
1740 0 : rSrcMedium.CanDisposeStorage_Impl( sal_False );
1741 0 : rSrcMedium.Close();
1742 :
1743 : // now try to create the backup
1744 0 : rTargetMedium.GetBackup_Impl();
1745 : }
1746 : else
1747 : {
1748 : // the following call will only compare stream sizes
1749 : // TODO/LATER: this is a very risky part, since if the URL contents are different from the storage
1750 : // contents, the storag will be broken
1751 0 : xOptStorage->attachToURL( aBackupURL, sal_True );
1752 :
1753 : // the storage is successfuly attached to backup, thus it it owned by the document not by the medium
1754 0 : rSrcMedium.CanDisposeStorage_Impl( sal_False );
1755 0 : bResult = sal_True;
1756 0 : }
1757 : }
1758 0 : catch ( uno::Exception& )
1759 : {}
1760 : }
1761 :
1762 : OSL_ENSURE( bResult, "Storage disconnecting has failed - affects performance!" );
1763 :
1764 0 : return bResult;
1765 : }
1766 :
1767 : //------------------------------------------------------------------------
1768 :
1769 0 : sal_Bool SfxObjectShell::ConnectTmpStorage_Impl(
1770 : const uno::Reference< embed::XStorage >& xStorage,
1771 : SfxMedium* pMediumArg )
1772 :
1773 : /* [Description]
1774 :
1775 : If the application operates on a temporary storage, then it may not take
1776 : the temporary storage from the SaveCompleted. Therefore the new storage
1777 : is connected already here in this case and SaveCompleted then does nothing.
1778 : */
1779 :
1780 : {
1781 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::ConnectTmpStorage_Impl" );
1782 :
1783 0 : sal_Bool bResult = sal_False;
1784 :
1785 0 : if ( xStorage.is() )
1786 : {
1787 : try
1788 : {
1789 : // the empty argument means that the storage will create temporary stream itself
1790 0 : uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW );
1791 0 : xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() );
1792 :
1793 : // the storage is successfuly disconnected from the original sources, thus the medium must not dispose it
1794 0 : if ( pMediumArg )
1795 0 : pMediumArg->CanDisposeStorage_Impl( sal_False );
1796 :
1797 0 : bResult = sal_True;
1798 : }
1799 0 : catch( uno::Exception& )
1800 : {
1801 : }
1802 :
1803 : // if switching of the storage does not work for any reason ( nonroot storage for example ) use the old method
1804 0 : if ( !bResult ) try
1805 : {
1806 0 : uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1807 :
1808 : DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" );
1809 0 : if ( !xTmpStorage.is() )
1810 0 : throw uno::RuntimeException();
1811 :
1812 : // TODO/LATER: may be it should be done in SwitchPersistence also
1813 : // TODO/LATER: find faster way to copy storage; perhaps sharing with backup?!
1814 0 : xStorage->copyToStorage( xTmpStorage );
1815 0 : bResult = SaveCompleted( xTmpStorage );
1816 :
1817 0 : if ( bResult )
1818 : {
1819 0 : pImp->pBasicManager->setStorage( xTmpStorage );
1820 :
1821 : // Get rid of this workaround after issue i113914 is fixed
1822 : try
1823 : {
1824 0 : uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries( pImp->xBasicLibraries, uno::UNO_QUERY_THROW );
1825 0 : xBasicLibraries->setRootStorage( xTmpStorage );
1826 : }
1827 0 : catch( uno::Exception& )
1828 : {}
1829 : try
1830 : {
1831 0 : uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries( pImp->xDialogLibraries, uno::UNO_QUERY_THROW );
1832 0 : xDialogLibraries->setRootStorage( xTmpStorage );
1833 : }
1834 0 : catch( uno::Exception& )
1835 : {}
1836 0 : }
1837 : }
1838 0 : catch( uno::Exception& )
1839 : {}
1840 :
1841 0 : if ( !bResult )
1842 : {
1843 : // TODO/LATER: may need error code setting based on exception
1844 0 : SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1845 : }
1846 : }
1847 :
1848 0 : return bResult;
1849 : }
1850 :
1851 : //-------------------------------------------------------------------------
1852 :
1853 286 : sal_Bool SfxObjectShell::DoSaveObjectAs( SfxMedium& rMedium, sal_Bool bCommit )
1854 : {
1855 286 : sal_Bool bOk = sal_False;
1856 : {
1857 286 : ModifyBlocker_Impl aBlock( this );
1858 :
1859 286 : uno::Reference < embed::XStorage > xNewStor = rMedium.GetStorage();
1860 286 : if ( !xNewStor.is() )
1861 0 : return sal_False;
1862 :
1863 286 : uno::Reference < beans::XPropertySet > xPropSet( xNewStor, uno::UNO_QUERY );
1864 286 : if ( xPropSet.is() )
1865 : {
1866 286 : Any a = xPropSet->getPropertyValue( ::rtl::OUString("MediaType" ) );
1867 286 : ::rtl::OUString aMediaType;
1868 286 : if ( !(a>>=aMediaType) || aMediaType.isEmpty() )
1869 : {
1870 : OSL_FAIL( "The mediatype must be set already!\n" );
1871 0 : SetupStorage( xNewStor, SOFFICE_FILEFORMAT_CURRENT, sal_False );
1872 : }
1873 :
1874 286 : pImp->bIsSaving = sal_False;
1875 286 : bOk = SaveAsOwnFormat( rMedium );
1876 :
1877 286 : if ( bCommit )
1878 : {
1879 : try {
1880 286 : uno::Reference< embed::XTransactedObject > xTransact( xNewStor, uno::UNO_QUERY_THROW );
1881 286 : xTransact->commit();
1882 : }
1883 0 : catch( uno::Exception& )
1884 : {
1885 : OSL_FAIL( "The strotage was not commited on DoSaveAs!\n" );
1886 : }
1887 286 : }
1888 286 : }
1889 : }
1890 :
1891 286 : return bOk;
1892 : }
1893 :
1894 : //-------------------------------------------------------------------------
1895 : // TODO/LATER: may be the call must be removed completelly
1896 4 : sal_Bool SfxObjectShell::DoSaveAs( SfxMedium& rMedium )
1897 : {
1898 : // here only root storages are included, which are stored via temp file
1899 4 : rMedium.CreateTempFileNoCopy();
1900 4 : SetError(rMedium.GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
1901 4 : if ( GetError() )
1902 0 : return sal_False;
1903 :
1904 : // copy version list from "old" medium to target medium, so it can be used on saving
1905 4 : if ( pImp->bPreserveVersions )
1906 4 : rMedium.TransferVersionList_Impl( *pMedium );
1907 :
1908 4 : sal_Bool bRet = SaveTo_Impl( rMedium, NULL );
1909 4 : if ( !bRet )
1910 0 : SetError(rMedium.GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
1911 4 : return bRet;
1912 : }
1913 :
1914 : //-------------------------------------------------------------------------
1915 :
1916 629 : sal_Bool SfxObjectShell::DoSaveCompleted( SfxMedium* pNewMed )
1917 : {
1918 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DoSaveCompleted" );
1919 :
1920 629 : sal_Bool bOk = sal_True;
1921 629 : sal_Bool bMedChanged = pNewMed && pNewMed!=pMedium;
1922 :
1923 : DBG_ASSERT( !pNewMed || pNewMed->GetError() == ERRCODE_NONE, "DoSaveCompleted: Medium has error!" );
1924 :
1925 : // delete Medium (and Storage!) after all notifications
1926 629 : SfxMedium* pOld = pMedium;
1927 629 : if ( bMedChanged )
1928 : {
1929 288 : pMedium = pNewMed;
1930 288 : pMedium->CanDisposeStorage_Impl( sal_True );
1931 : }
1932 :
1933 629 : const SfxFilter *pFilter = pMedium ? pMedium->GetFilter() : 0;
1934 629 : if ( pNewMed )
1935 : {
1936 288 : if( bMedChanged )
1937 : {
1938 288 : if (!pNewMed->GetName().isEmpty())
1939 1 : bHasName = sal_True;
1940 288 : Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) );
1941 576 : getDocProperties()->setGenerator(
1942 288 : ::utl::DocInfoHelper::GetGeneratorString() );
1943 : }
1944 :
1945 288 : uno::Reference< embed::XStorage > xStorage;
1946 288 : if ( !pFilter || IsPackageStorageFormat_Impl( *pMedium ) )
1947 : {
1948 287 : uno::Reference < embed::XStorage > xOld = GetStorage();
1949 :
1950 : // when the package based medium is broken and has no storage or if the storage
1951 : // is the same as the document storage the current document storage should be preserved
1952 287 : xStorage = pMedium->GetStorage();
1953 287 : bOk = SaveCompleted( xStorage );
1954 1146 : if ( bOk && xStorage.is() && xOld != xStorage
1955 859 : && (!pOld || !pOld->HasStorage_Impl() || xOld != pOld->GetStorage() ) )
1956 : {
1957 : // old own storage was not controlled by old Medium -> dispose it
1958 : try {
1959 144 : xOld->dispose();
1960 0 : } catch( uno::Exception& )
1961 : {
1962 : // the storage is disposed already
1963 : // can happen during reload scenario when the medium has
1964 : // disposed it during the closing
1965 : // will be fixed in one of the next milestones
1966 : }
1967 287 : }
1968 : }
1969 : else
1970 : {
1971 1 : if( pMedium->GetOpenMode() & STREAM_WRITE )
1972 1 : pMedium->GetInStream();
1973 1 : xStorage = GetStorage();
1974 : }
1975 :
1976 : // TODO/LATER: may be this code will be replaced, but not sure
1977 : // Set storage in document library containers
1978 288 : pImp->pBasicManager->setStorage( xStorage );
1979 :
1980 : // Get rid of this workaround after issue i113914 is fixed
1981 : try
1982 : {
1983 288 : uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries( pImp->xBasicLibraries, uno::UNO_QUERY_THROW );
1984 287 : xBasicLibraries->setRootStorage( xStorage );
1985 : }
1986 1 : catch( uno::Exception& )
1987 : {}
1988 : try
1989 : {
1990 288 : uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries( pImp->xDialogLibraries, uno::UNO_QUERY_THROW );
1991 286 : xDialogLibraries->setRootStorage( xStorage );
1992 : }
1993 2 : catch( uno::Exception& )
1994 288 : {}
1995 : }
1996 : else
1997 : {
1998 341 : if( pMedium )
1999 : {
2000 341 : if( pFilter && !IsPackageStorageFormat_Impl( *pMedium ) && (pMedium->GetOpenMode() & STREAM_WRITE ))
2001 : {
2002 48 : pMedium->ReOpen();
2003 48 : bOk = SaveCompletedChildren( sal_False );
2004 : }
2005 : else
2006 293 : bOk = SaveCompleted( NULL );
2007 : }
2008 : // either Save or ConvertTo
2009 : else
2010 0 : bOk = SaveCompleted( NULL );
2011 : }
2012 :
2013 629 : if ( bOk && pNewMed )
2014 : {
2015 288 : if( bMedChanged )
2016 : {
2017 288 : delete pOld;
2018 :
2019 288 : uno::Reference< frame::XModel > xModel = GetModel();
2020 288 : if ( xModel.is() )
2021 : {
2022 288 : ::rtl::OUString aURL = pNewMed->GetOrigURL();
2023 288 : uno::Sequence< beans::PropertyValue > aMediaDescr;
2024 288 : TransformItems( SID_OPENDOC, *pNewMed->GetItemSet(), aMediaDescr );
2025 : try
2026 : {
2027 288 : xModel->attachResource( aURL, aMediaDescr );
2028 : }
2029 0 : catch( uno::Exception& )
2030 288 : {}
2031 : }
2032 :
2033 : // before the title regenerated the document must loose the signatures
2034 288 : pImp->nDocumentSignatureState = SIGNATURESTATE_NOSIGNATURES;
2035 288 : pImp->nScriptingSignatureState = pNewMed->GetCachedSignatureState_Impl();
2036 : OSL_ENSURE( pImp->nScriptingSignatureState != SIGNATURESTATE_SIGNATURES_BROKEN, "The signature must not be broken at this place" );
2037 288 : pImp->bSignatureErrorIsShown = sal_False;
2038 :
2039 : // TODO/LATER: in future the medium must control own signature state, not the document
2040 288 : pNewMed->SetCachedSignatureState_Impl( SIGNATURESTATE_NOSIGNATURES ); // set the default value back
2041 :
2042 : // Set new title
2043 288 : if (!pNewMed->GetName().isEmpty() && SFX_CREATE_MODE_EMBEDDED != eCreateMode)
2044 0 : InvalidateName();
2045 288 : SetModified(sal_False); // reset only by set medium
2046 288 : Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
2047 :
2048 : // this is the end of the saving process, it is possible that
2049 : // the file was changed
2050 : // between medium commit and this step (attributes change and so on)
2051 : // so get the file date again
2052 288 : if ( pNewMed->DocNeedsFileDateCheck() )
2053 1 : pNewMed->GetInitFileDate( sal_True );
2054 : }
2055 : }
2056 :
2057 629 : pMedium->ClearBackup_Impl();
2058 629 : pMedium->LockOrigFileOnDemand( sal_True, sal_False );
2059 :
2060 629 : AddToRecentlyUsedList();
2061 :
2062 629 : return bOk;
2063 : }
2064 :
2065 864 : void SfxObjectShell::AddToRecentlyUsedList()
2066 : {
2067 864 : INetURLObject aUrl( pMedium->GetOrigURL() );
2068 :
2069 864 : if ( aUrl.GetProtocol() == INET_PROT_FILE )
2070 : {
2071 291 : const SfxFilter* pOrgFilter = pMedium->GetOrigFilter();
2072 : Application::AddToRecentDocumentList( aUrl.GetURLNoPass( INetURLObject::NO_DECODE ),
2073 291 : (pOrgFilter) ? pOrgFilter->GetMimeType() : ::rtl::OUString() );
2074 864 : }
2075 864 : }
2076 :
2077 : //-------------------------------------------------------------------------
2078 :
2079 0 : sal_Bool SfxObjectShell::ConvertFrom
2080 : (
2081 : SfxMedium& /*rMedium*/ /* <SfxMedium>, which describes the source file
2082 : (for example file name, <SfxFilter>,
2083 : Open-Modi and so on) */
2084 : )
2085 :
2086 : /* [Description]
2087 :
2088 : This method is called for loading of documents over all filters which are
2089 : not SFX_FILTER_OWN or for which no clipboard format has been registered
2090 : (thus no storage format that is used). In other words, whith this method
2091 : it is imported.
2092 :
2093 : Files which are to be opened here should be opened through 'rMedium'
2094 : to guarantee the right open modes. Especially if the format is retained
2095 : (only possible with SFX_FILTER_SIMULATE or SFX_FILTER_ONW) file which must
2096 : be opened STREAM_SHARE_DENYWRITE.
2097 :
2098 : [Return value]
2099 :
2100 : sal_Bool sal_True
2101 : The document could be loaded.
2102 :
2103 : sal_False
2104 : The document could not be loaded, an error code
2105 : received through <SvMedium::GetError()const>
2106 :
2107 : [Example]
2108 :
2109 : sal_Bool DocSh::ConvertFrom( SfxMedium &rMedium )
2110 : {
2111 : SvStreamRef xStream = rMedium.GetInStream();
2112 : if( xStream.is() )
2113 : {
2114 : xStream->SetBufferSize(4096);
2115 : *xStream >> ...;
2116 :
2117 : // Do not call 'rMedium.CloseInStream()'! Keep File locked!
2118 : return SVSTREAM_OK == rMedium.GetError();
2119 : }
2120 :
2121 : return sal_False;
2122 : }
2123 :
2124 : [Cross-references]
2125 :
2126 : <SfxObjectShell::ConvertTo(SfxMedium&)>
2127 : <SFX_FILTER_REGISTRATION>
2128 : */
2129 : {
2130 0 : return sal_False;
2131 : }
2132 :
2133 227 : sal_Bool SfxObjectShell::ImportFrom( SfxMedium& rMedium, bool bInsert )
2134 : {
2135 227 : ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2136 :
2137 227 : uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2138 : uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2139 227 : xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY );
2140 :
2141 227 : uno::Sequence < beans::PropertyValue > aProps;
2142 227 : uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2143 227 : if ( xFilters->hasByName( aFilterName ) )
2144 : {
2145 227 : xFilters->getByName( aFilterName ) >>= aProps;
2146 227 : rMedium.GetItemSet()->Put( SfxStringItem( SID_FILTER_NAME, aFilterName ) );
2147 : }
2148 :
2149 227 : ::rtl::OUString aFilterImplName;
2150 227 : sal_Int32 nFilterProps = aProps.getLength();
2151 1347 : for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2152 : {
2153 1347 : const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2154 1347 : if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2155 : {
2156 227 : rFilterProp.Value >>= aFilterImplName;
2157 227 : break;
2158 : }
2159 : }
2160 :
2161 227 : uno::Reference< document::XFilter > xLoader;
2162 227 : if ( !aFilterImplName.isEmpty() )
2163 : {
2164 : try{
2165 : xLoader = uno::Reference< document::XFilter >
2166 227 : ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2167 0 : }catch(const uno::Exception&)
2168 0 : { xLoader.clear(); }
2169 : }
2170 227 : if ( xLoader.is() )
2171 : {
2172 : // it happens that xLoader does not support xImporter!
2173 : try{
2174 227 : uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2175 227 : uno::Reference< document::XImporter > xImporter( xLoader, uno::UNO_QUERY_THROW );
2176 227 : xImporter->setTargetDocument( xComp );
2177 :
2178 227 : uno::Sequence < beans::PropertyValue > lDescriptor;
2179 227 : rMedium.GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, rMedium.GetName() ) );
2180 227 : TransformItems( SID_OPENDOC, *rMedium.GetItemSet(), lDescriptor );
2181 :
2182 227 : com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( lDescriptor.getLength() );
2183 227 : com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2184 227 : const com::sun::star::beans::PropertyValue * pOldValue = lDescriptor.getConstArray();
2185 227 : const OUString sInputStream ( "InputStream" );
2186 :
2187 227 : sal_Bool bHasInputStream = sal_False;
2188 227 : sal_Bool bHasBaseURL = sal_False;
2189 : sal_Int32 i;
2190 227 : sal_Int32 nEnd = lDescriptor.getLength();
2191 :
2192 2619 : for ( i = 0; i < nEnd; i++ )
2193 : {
2194 2392 : pNewValue[i] = pOldValue[i];
2195 2392 : if ( pOldValue [i].Name == sInputStream )
2196 212 : bHasInputStream = sal_True;
2197 2180 : else if ( pOldValue[i].Name == "DocumentBaseURL" )
2198 227 : bHasBaseURL = sal_True;
2199 : }
2200 :
2201 227 : if ( !bHasInputStream )
2202 : {
2203 15 : aArgs.realloc ( ++nEnd );
2204 15 : aArgs[nEnd-1].Name = sInputStream;
2205 15 : aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XInputStream > ( new utl::OSeekableInputStreamWrapper ( *rMedium.GetInStream() ) );
2206 : }
2207 :
2208 227 : if ( !bHasBaseURL )
2209 : {
2210 0 : aArgs.realloc ( ++nEnd );
2211 0 : aArgs[nEnd-1].Name = ::rtl::OUString( "DocumentBaseURL" );
2212 0 : aArgs[nEnd-1].Value <<= rMedium.GetBaseURL();
2213 : }
2214 :
2215 227 : if ( bInsert ) {
2216 0 : aArgs.realloc( ++nEnd );
2217 0 : aArgs[nEnd-1].Name = ::rtl::OUString( "InsertMode" );
2218 0 : aArgs[nEnd-1].Value <<= (sal_Bool) sal_True;
2219 : }
2220 :
2221 227 : return xLoader->filter( aArgs );
2222 : }
2223 0 : catch (const packages::zip::ZipIOException&)
2224 : {
2225 0 : SetError( ERRCODE_IO_BROKENPACKAGE, "Badness in the underlying package format." );
2226 : }
2227 0 : catch (const lang::WrappedTargetRuntimeException& rWrapped)
2228 : {
2229 0 : io::WrongFormatException e;
2230 0 : if (rWrapped.TargetException >>= e)
2231 : {
2232 : SetError(*new StringErrorInfo(ERRCODE_SFX_FORMAT_ROWCOL,
2233 0 : e.Message, ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR ), "");
2234 0 : }
2235 : }
2236 0 : catch(...)
2237 : {}
2238 : }
2239 :
2240 0 : return sal_False;
2241 : }
2242 :
2243 54 : sal_Bool SfxObjectShell::ExportTo( SfxMedium& rMedium )
2244 : {
2245 54 : ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2246 54 : uno::Reference< document::XExporter > xExporter;
2247 :
2248 : {
2249 54 : uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2250 : uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2251 54 : xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY );
2252 :
2253 54 : uno::Sequence < beans::PropertyValue > aProps;
2254 54 : uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2255 54 : if ( xFilters->hasByName( aFilterName ) )
2256 54 : xFilters->getByName( aFilterName ) >>= aProps;
2257 :
2258 54 : ::rtl::OUString aFilterImplName;
2259 54 : sal_Int32 nFilterProps = aProps.getLength();
2260 323 : for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2261 : {
2262 323 : const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2263 323 : if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2264 : {
2265 54 : rFilterProp.Value >>= aFilterImplName;
2266 54 : break;
2267 : }
2268 : }
2269 :
2270 54 : if ( !aFilterImplName.isEmpty() )
2271 : {
2272 : try{
2273 : xExporter = uno::Reference< document::XExporter >
2274 54 : ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2275 0 : }catch(const uno::Exception&)
2276 0 : { xExporter.clear(); }
2277 54 : }
2278 : }
2279 :
2280 54 : if ( xExporter.is() )
2281 : {
2282 : try{
2283 54 : uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2284 54 : uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY_THROW );
2285 54 : xExporter->setSourceDocument( xComp );
2286 :
2287 54 : com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aOldArgs;
2288 54 : SfxItemSet* pItems = rMedium.GetItemSet();
2289 54 : TransformItems( SID_SAVEASDOC, *pItems, aOldArgs );
2290 :
2291 54 : const com::sun::star::beans::PropertyValue * pOldValue = aOldArgs.getConstArray();
2292 54 : com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( aOldArgs.getLength() );
2293 54 : com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2294 :
2295 : // put in the REAL file name, and copy all PropertyValues
2296 54 : const OUString sOutputStream ( "OutputStream" );
2297 54 : const OUString sStream ( "StreamForOutput" );
2298 54 : sal_Bool bHasOutputStream = sal_False;
2299 54 : sal_Bool bHasStream = sal_False;
2300 54 : sal_Bool bHasBaseURL = sal_False;
2301 : sal_Int32 i;
2302 54 : sal_Int32 nEnd = aOldArgs.getLength();
2303 :
2304 480 : for ( i = 0; i < nEnd; i++ )
2305 : {
2306 426 : pNewValue[i] = pOldValue[i];
2307 426 : if ( pOldValue[i].Name == "FileName" )
2308 0 : pNewValue[i].Value <<= OUString ( rMedium.GetName() );
2309 426 : else if ( pOldValue[i].Name == sOutputStream )
2310 0 : bHasOutputStream = sal_True;
2311 426 : else if ( pOldValue[i].Name == sStream )
2312 0 : bHasStream = sal_True;
2313 426 : else if ( pOldValue[i].Name == "DocumentBaseURL" )
2314 0 : bHasBaseURL = sal_True;
2315 : }
2316 :
2317 54 : if ( !bHasOutputStream )
2318 : {
2319 54 : aArgs.realloc ( ++nEnd );
2320 54 : aArgs[nEnd-1].Name = sOutputStream;
2321 54 : aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > ( new utl::OOutputStreamWrapper ( *rMedium.GetOutStream() ) );
2322 : }
2323 :
2324 : // add stream as well, for OOX export and maybe others
2325 54 : if ( !bHasStream )
2326 : {
2327 54 : aArgs.realloc ( ++nEnd );
2328 54 : aArgs[nEnd-1].Name = sStream;
2329 54 : aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XStream > ( new utl::OStreamWrapper ( *rMedium.GetOutStream() ) );
2330 : }
2331 :
2332 54 : if ( !bHasBaseURL )
2333 : {
2334 54 : aArgs.realloc ( ++nEnd );
2335 54 : aArgs[nEnd-1].Name = ::rtl::OUString( "DocumentBaseURL" );
2336 54 : aArgs[nEnd-1].Value <<= rMedium.GetBaseURL( sal_True );
2337 : }
2338 :
2339 54 : return xFilter->filter( aArgs );
2340 0 : }catch(const uno::Exception&)
2341 : {}
2342 : }
2343 :
2344 0 : return sal_False;
2345 : }
2346 :
2347 : //-------------------------------------------------------------------------
2348 :
2349 0 : sal_Bool SfxObjectShell::ConvertTo
2350 : (
2351 : SfxMedium& /*rMedium*/ /* <SfxMedium>, which describes the target file
2352 : (for example file name, <SfxFilter>,
2353 : Open-Modi and so on) */
2354 : )
2355 :
2356 : /* [Description]
2357 :
2358 : This method is called for saving of documents over all filters which are
2359 : not SFX_FILTER_OWN or for which no clipboard format has been registered
2360 : (thus no storage format that is used). In other words, with this method
2361 : it is exported.
2362 :
2363 : Files which are to be opened here should be opened through 'rMedium'
2364 : to guarantee the right open modes. Especially if the format is retained
2365 : (only possible with SFX_FILTER_SIMULATE or SFX_FILTER_ONW) file which must
2366 : be opened STREAM_SHARE_DENYWRITE.
2367 :
2368 : [Return value]
2369 :
2370 : sal_Bool sal_True
2371 : The document could be saved.
2372 :
2373 : sal_False
2374 : The document could not be saved, an error code is
2375 : received by <SvMedium::GetError()const>
2376 :
2377 :
2378 : [Example]
2379 :
2380 : sal_Bool DocSh::ConvertTo( SfxMedium &rMedium )
2381 : {
2382 : SvStreamRef xStream = rMedium.GetOutStream();
2383 : if ( xStream.is() )
2384 : {
2385 : xStream->SetBufferSize(4096);
2386 : *xStream << ...;
2387 :
2388 : rMedium.CloseOutStream(); // opens the InStream automatically
2389 : return SVSTREAM_OK == rMedium.GetError();
2390 : }
2391 : return sal_False ;
2392 : }
2393 :
2394 : [Cross-references]
2395 :
2396 : <SfxObjectShell::ConvertFrom(SfxMedium&)>
2397 : <SFX_FILTER_REGISTRATION>
2398 : */
2399 :
2400 : {
2401 0 : return sal_False;
2402 : }
2403 :
2404 : //-------------------------------------------------------------------------
2405 :
2406 0 : sal_Bool SfxObjectShell::DoSave_Impl( const SfxItemSet* pArgs )
2407 : {
2408 0 : SfxMedium* pRetrMedium = GetMedium();
2409 0 : const SfxFilter* pFilter = pRetrMedium->GetFilter();
2410 :
2411 : // copy the original itemset, but remove the "version" item, because pMediumTmp
2412 : // is a new medium "from scratch", so no version should be stored into it
2413 0 : SfxItemSet* pSet = new SfxAllItemSet(*pRetrMedium->GetItemSet());
2414 0 : pSet->ClearItem( SID_VERSION );
2415 0 : pSet->ClearItem( SID_DOC_BASEURL );
2416 :
2417 : // copy the version comment and major items for the checkin only
2418 0 : if ( pRetrMedium->IsInCheckIn( ) )
2419 : {
2420 0 : const SfxPoolItem* pMajor = pArgs->GetItem( SID_DOCINFO_MAJOR );
2421 0 : if ( pMajor )
2422 0 : pSet->Put( *pMajor );
2423 :
2424 0 : const SfxPoolItem* pComments = pArgs->GetItem( SID_DOCINFO_COMMENTS );
2425 0 : if ( pComments )
2426 0 : pSet->Put( *pComments );
2427 : }
2428 :
2429 : // create a medium as a copy; this medium is only for writingm, because it
2430 : // uses the same name as the original one writing is done through a copy,
2431 : // that will be transferred to the target (of course after calling HandsOff)
2432 0 : SfxMedium* pMediumTmp = new SfxMedium( pRetrMedium->GetName(), pRetrMedium->GetOpenMode(), pFilter, pSet );
2433 0 : pMediumTmp->SetInCheckIn( pRetrMedium->IsInCheckIn( ) );
2434 0 : pMediumTmp->SetLongName( pRetrMedium->GetLongName() );
2435 0 : if ( pMediumTmp->GetErrorCode() != ERRCODE_NONE )
2436 : {
2437 0 : SetError( pMediumTmp->GetError(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2438 0 : delete pMediumTmp;
2439 0 : return sal_False;
2440 : }
2441 :
2442 : // copy version list from "old" medium to target medium, so it can be used on saving
2443 0 : pMediumTmp->TransferVersionList_Impl( *pRetrMedium );
2444 :
2445 : // an interaction handler here can aquire only in case of GUI Saving
2446 : // and should be removed after the saving is done
2447 0 : com::sun::star::uno::Reference< XInteractionHandler > xInteract;
2448 0 : SFX_ITEMSET_ARG( pArgs, pxInteractionItem, SfxUnoAnyItem, SID_INTERACTIONHANDLER, sal_False );
2449 0 : if ( pxInteractionItem && ( pxInteractionItem->GetValue() >>= xInteract ) && xInteract.is() )
2450 0 : pMediumTmp->GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny( xInteract ) ) );
2451 :
2452 0 : sal_Bool bSaved = sal_False;
2453 0 : if( !GetError() && SaveTo_Impl( *pMediumTmp, pArgs ) )
2454 : {
2455 0 : bSaved = sal_True;
2456 :
2457 0 : if( pMediumTmp->GetItemSet() )
2458 : {
2459 0 : pMediumTmp->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER );
2460 0 : pMediumTmp->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2461 : }
2462 :
2463 0 : SetError(pMediumTmp->GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2464 :
2465 0 : sal_Bool bOpen( sal_False );
2466 0 : bOpen = DoSaveCompleted( pMediumTmp );
2467 :
2468 : DBG_ASSERT(bOpen,"Error handling for DoSaveCompleted not implemented");
2469 : (void)bOpen;
2470 : }
2471 : else
2472 : {
2473 : // transfer error code from medium to objectshell
2474 0 : SetError( pMediumTmp->GetError(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2475 :
2476 : // reconnect to object storage
2477 0 : DoSaveCompleted( 0 );
2478 :
2479 0 : if( pRetrMedium->GetItemSet() )
2480 : {
2481 0 : pRetrMedium->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER );
2482 0 : pRetrMedium->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2483 : }
2484 :
2485 0 : delete pMediumTmp;
2486 : }
2487 :
2488 0 : SetModified( !bSaved );
2489 0 : return bSaved;
2490 : }
2491 :
2492 : //-------------------------------------------------------------------------
2493 :
2494 0 : sal_Bool SfxObjectShell::Save_Impl( const SfxItemSet* pSet )
2495 : {
2496 0 : if ( IsReadOnly() )
2497 : {
2498 0 : SetError( ERRCODE_SFX_DOCUMENTREADONLY, ::rtl::OUString( OSL_LOG_PREFIX ) );
2499 0 : return sal_False;
2500 : }
2501 :
2502 : DBG_CHKTHIS(SfxObjectShell, 0);
2503 :
2504 0 : pImp->bIsSaving = sal_True;
2505 0 : sal_Bool bSaved = sal_False;
2506 0 : SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
2507 0 : if ( pSalvageItem )
2508 : {
2509 0 : SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False);
2510 0 : String aFilterName;
2511 0 : const SfxFilter *pFilter = NULL;
2512 0 : if ( pFilterItem )
2513 0 : pFilter = SfxFilterMatcher( rtl::OUString::createFromAscii( GetFactory().GetShortName()) ).GetFilter4FilterName( aFilterName );
2514 :
2515 : SfxMedium *pMed = new SfxMedium(
2516 0 : pSalvageItem->GetValue(), STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, pFilter );
2517 :
2518 0 : SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False );
2519 0 : if ( pPasswordItem )
2520 0 : pMed->GetItemSet()->Put( *pPasswordItem );
2521 :
2522 0 : bSaved = DoSaveAs( *pMed );
2523 0 : if ( bSaved )
2524 0 : bSaved = DoSaveCompleted( pMed );
2525 : else
2526 0 : delete pMed;
2527 : }
2528 : else
2529 0 : bSaved = DoSave_Impl( pSet );
2530 0 : return bSaved;
2531 : }
2532 :
2533 : //-------------------------------------------------------------------------
2534 :
2535 55 : sal_Bool SfxObjectShell::CommonSaveAs_Impl
2536 : (
2537 : const INetURLObject& aURL,
2538 : const String& aFilterName,
2539 : SfxItemSet* aParams
2540 : )
2541 : {
2542 55 : if( aURL.HasError() )
2543 : {
2544 0 : SetError( ERRCODE_IO_INVALIDPARAMETER, ::rtl::OUString( OSL_LOG_PREFIX ) );
2545 0 : return sal_False;
2546 : }
2547 :
2548 55 : if ( aURL != INetURLObject( ::rtl::OUString( "private:stream" ) ) )
2549 : {
2550 : // Is there already a Document with this name?
2551 55 : SfxObjectShell* pDoc = 0;
2552 793 : for ( SfxObjectShell* pTmp = SfxObjectShell::GetFirst();
2553 : pTmp && !pDoc;
2554 : pTmp = SfxObjectShell::GetNext(*pTmp) )
2555 : {
2556 738 : if( ( pTmp != this ) && pTmp->GetMedium() )
2557 : {
2558 683 : INetURLObject aCompare( pTmp->GetMedium()->GetName() );
2559 683 : if ( aCompare == aURL )
2560 0 : pDoc = pTmp;
2561 : }
2562 : }
2563 55 : if ( pDoc )
2564 : {
2565 : // Then error message: "already opened"
2566 0 : SetError(ERRCODE_SFX_ALREADYOPEN, ::rtl::OUString( OSL_LOG_PREFIX ));
2567 0 : return sal_False;
2568 : }
2569 : }
2570 :
2571 : DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "Illegal URL!" );
2572 : DBG_ASSERT( aParams->Count() != 0, "Incorrect Parameter");
2573 :
2574 55 : SFX_ITEMSET_ARG( aParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
2575 55 : sal_Bool bSaveTo = pSaveToItem ? pSaveToItem->GetValue() : sal_False;
2576 :
2577 55 : const SfxFilter* pFilter = GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName );
2578 110 : if ( !pFilter
2579 55 : || !pFilter->CanExport()
2580 0 : || (!bSaveTo && !pFilter->CanImport()) )
2581 : {
2582 0 : SetError( ERRCODE_IO_INVALIDPARAMETER, ::rtl::OUString( OSL_LOG_PREFIX ) );
2583 0 : return sal_False;
2584 : }
2585 :
2586 55 : SFX_ITEMSET_ARG( aParams, pCopyStreamItem, SfxBoolItem, SID_COPY_STREAM_IF_POSSIBLE, sal_False );
2587 55 : if ( bSaveTo && pCopyStreamItem && pCopyStreamItem->GetValue() && !IsModified() )
2588 : {
2589 0 : if ( pMedium->TryDirectTransfer( aURL.GetMainURL( INetURLObject::NO_DECODE ), *aParams ) )
2590 0 : return sal_True;
2591 : }
2592 55 : aParams->ClearItem( SID_COPY_STREAM_IF_POSSIBLE );
2593 :
2594 55 : pImp->bPasswd = aParams && SFX_ITEM_SET == aParams->GetItemState(SID_PASSWORD);
2595 :
2596 55 : SfxMedium *pActMed = GetMedium();
2597 55 : const INetURLObject aActName(pActMed->GetName());
2598 :
2599 55 : sal_Bool bWasReadonly = IsReadOnly();
2600 :
2601 55 : if ( aURL == aActName && aURL != INetURLObject( OUString("private:stream") )
2602 0 : && IsReadOnly() )
2603 : {
2604 0 : SetError(ERRCODE_SFX_DOCUMENTREADONLY, ::rtl::OUString( OSL_LOG_PREFIX ));
2605 0 : return sal_False;
2606 : }
2607 :
2608 55 : if( SFX_ITEM_SET != aParams->GetItemState(SID_UNPACK) && SvtSaveOptions().IsSaveUnpacked() )
2609 0 : aParams->Put( SfxBoolItem( SID_UNPACK, sal_False ) );
2610 :
2611 55 : ::rtl::OUString aTempFileURL;
2612 55 : if ( IsDocShared() )
2613 0 : aTempFileURL = pMedium->GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
2614 :
2615 55 : if ( PreDoSaveAs_Impl(aURL.GetMainURL( INetURLObject::NO_DECODE ),aFilterName,aParams))
2616 : {
2617 : // Update Data on media
2618 55 : SfxItemSet *pSet = GetMedium()->GetItemSet();
2619 55 : pSet->ClearItem( SID_INTERACTIONHANDLER );
2620 55 : pSet->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2621 55 : pSet->ClearItem( SID_STANDARD_DIR );
2622 55 : pSet->ClearItem( SID_PATH );
2623 :
2624 55 : if ( !bSaveTo )
2625 : {
2626 0 : pSet->ClearItem( SID_REFERER );
2627 0 : pSet->ClearItem( SID_POSTDATA );
2628 0 : pSet->ClearItem( SID_TEMPLATE );
2629 0 : pSet->ClearItem( SID_DOC_READONLY );
2630 0 : pSet->ClearItem( SID_CONTENTTYPE );
2631 0 : pSet->ClearItem( SID_CHARSET );
2632 0 : pSet->ClearItem( SID_FILTER_NAME );
2633 0 : pSet->ClearItem( SID_OPTIONS );
2634 0 : pSet->ClearItem( SID_VERSION );
2635 0 : pSet->ClearItem( SID_EDITDOC );
2636 0 : pSet->ClearItem( SID_OVERWRITE );
2637 0 : pSet->ClearItem( SID_DEFAULTFILEPATH );
2638 0 : pSet->ClearItem( SID_DEFAULTFILENAME );
2639 :
2640 0 : SFX_ITEMSET_GET( (*aParams), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False );
2641 0 : if ( pFilterItem )
2642 0 : pSet->Put( *pFilterItem );
2643 :
2644 0 : SFX_ITEMSET_GET( (*aParams), pOptionsItem, SfxStringItem, SID_OPTIONS, sal_False );
2645 0 : if ( pOptionsItem )
2646 0 : pSet->Put( *pOptionsItem );
2647 :
2648 0 : SFX_ITEMSET_GET( (*aParams), pFilterOptItem, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False );
2649 0 : if ( pFilterOptItem )
2650 0 : pSet->Put( *pFilterOptItem );
2651 :
2652 0 : if ( IsDocShared() && !aTempFileURL.isEmpty() )
2653 : {
2654 : // this is a shared document that has to be disconnected from the old location
2655 0 : FreeSharedFile( aTempFileURL );
2656 :
2657 0 : if ( pFilter->IsOwnFormat()
2658 0 : && pFilter->UsesStorage()
2659 0 : && pFilter->GetVersion() >= SOFFICE_FILEFORMAT_60 )
2660 : {
2661 : // the target format is the own format
2662 : // the target document must be shared
2663 0 : SwitchToShared( sal_True, sal_False );
2664 : }
2665 : }
2666 : }
2667 :
2668 55 : if ( bWasReadonly && !bSaveTo )
2669 0 : Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
2670 :
2671 55 : return sal_True;
2672 : }
2673 : else
2674 0 : return sal_False;
2675 : }
2676 :
2677 : //-------------------------------------------------------------------------
2678 :
2679 55 : sal_Bool SfxObjectShell::PreDoSaveAs_Impl
2680 : (
2681 : const String& rFileName,
2682 : const String& aFilterName,
2683 : SfxItemSet* pParams
2684 : )
2685 : {
2686 : // copy all items stored in the itemset of the current medium
2687 55 : SfxAllItemSet* pMergedParams = new SfxAllItemSet( *pMedium->GetItemSet() );
2688 :
2689 : // in "SaveAs" title and password will be cleared ( maybe the new itemset contains new values, otherwise they will be empty )
2690 55 : pMergedParams->ClearItem( SID_ENCRYPTIONDATA );
2691 55 : pMergedParams->ClearItem( SID_PASSWORD );
2692 55 : pMergedParams->ClearItem( SID_DOCINFO_TITLE );
2693 :
2694 55 : pMergedParams->ClearItem( SID_INPUTSTREAM );
2695 55 : pMergedParams->ClearItem( SID_STREAM );
2696 55 : pMergedParams->ClearItem( SID_CONTENT );
2697 55 : pMergedParams->ClearItem( SID_DOC_READONLY );
2698 55 : pMergedParams->ClearItem( SID_DOC_BASEURL );
2699 :
2700 55 : pMergedParams->ClearItem( SID_REPAIRPACKAGE );
2701 :
2702 : // "SaveAs" will never store any version information - it's a complete new file !
2703 55 : pMergedParams->ClearItem( SID_VERSION );
2704 :
2705 : // merge the new parameters into the copy
2706 : // all values present in both itemsets will be overwritten by the new parameters
2707 55 : if( pParams )
2708 55 : pMergedParams->Put( *pParams );
2709 :
2710 : #ifdef DBG_UTIL
2711 : if ( pMergedParams->GetItemState( SID_DOC_SALVAGE) >= SFX_ITEM_SET )
2712 : OSL_FAIL("Salvage item present in Itemset, check the parameters!");
2713 : #endif
2714 :
2715 : // should be unneccessary - too hot to handle!
2716 55 : pMergedParams->ClearItem( SID_DOC_SALVAGE );
2717 :
2718 : // take over the new merged itemset
2719 55 : pParams = pMergedParams;
2720 :
2721 : // create a medium for the target URL
2722 55 : SfxMedium *pNewFile = new SfxMedium( rFileName, STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, 0, pParams );
2723 :
2724 : // set filter; if no filter is given, take the default filter of the factory
2725 55 : if ( aFilterName.Len() )
2726 55 : pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) );
2727 : else
2728 0 : pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT ) );
2729 :
2730 55 : if ( pNewFile->GetErrorCode() != ERRCODE_NONE )
2731 : {
2732 : // creating temporary file failed ( f.e. floppy disk not inserted! )
2733 0 : SetError( pNewFile->GetError(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2734 0 : delete pNewFile;
2735 0 : return sal_False;
2736 : }
2737 :
2738 : // check if a "SaveTo" is wanted, no "SaveAs"
2739 55 : SFX_ITEMSET_ARG( pParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
2740 55 : sal_Bool bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED || (pSaveToItem && pSaveToItem->GetValue());
2741 :
2742 : // distinguish between "Save" and "SaveAs"
2743 55 : pImp->bIsSaving = sal_False;
2744 :
2745 : // copy version list from "old" medium to target medium, so it can be used on saving
2746 55 : if ( pImp->bPreserveVersions )
2747 55 : pNewFile->TransferVersionList_Impl( *pMedium );
2748 :
2749 : // Save the document ( first as temporary file, then transfer to the target URL by committing the medium )
2750 55 : sal_Bool bOk = sal_False;
2751 55 : if ( !pNewFile->GetErrorCode() && SaveTo_Impl( *pNewFile, NULL ) )
2752 : {
2753 55 : bOk = sal_True;
2754 :
2755 : // transfer a possible error from the medium to the document
2756 55 : SetError( pNewFile->GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2757 :
2758 : // notify the document that saving was done successfully
2759 55 : if ( !bCopyTo )
2760 : {
2761 0 : bOk = DoSaveCompleted( pNewFile );
2762 : }
2763 : else
2764 55 : bOk = DoSaveCompleted(0);
2765 :
2766 55 : if( bOk )
2767 : {
2768 55 : if( !bCopyTo )
2769 0 : SetModified( sal_False );
2770 : }
2771 : else
2772 : {
2773 : // TODO/LATER: the code below must be dead since the storage commit makes all the stuff
2774 : // and the DoSaveCompleted call should not be able to fail in general
2775 :
2776 : DBG_ASSERT( !bCopyTo, "Error while reconnecting to medium, can't be handled!");
2777 0 : SetError( pNewFile->GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2778 :
2779 0 : if ( !bCopyTo )
2780 : {
2781 : // reconnect to the old medium
2782 0 : sal_Bool bRet( sal_False );
2783 0 : bRet = DoSaveCompleted( pMedium );
2784 : DBG_ASSERT( bRet, "Error in DoSaveCompleted, can't be handled!");
2785 : (void)bRet;
2786 : }
2787 :
2788 : // TODO/LATER: disconnect the new file from the storage for the case when pure saving is done
2789 : // if storing has corrupted the file, probably it must be restored either here or
2790 : // by the storage
2791 0 : DELETEZ( pNewFile );
2792 : }
2793 : }
2794 : else
2795 : {
2796 0 : SetError( pNewFile->GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2797 :
2798 : // reconnect to the old storage
2799 0 : DoSaveCompleted( 0 );
2800 :
2801 0 : DELETEZ( pNewFile );
2802 : }
2803 :
2804 55 : if ( bCopyTo )
2805 55 : DELETEZ( pNewFile );
2806 0 : else if( !bOk )
2807 0 : SetModified( sal_True );
2808 :
2809 55 : return bOk;
2810 : }
2811 :
2812 : //------------------------------------------------------------------------
2813 :
2814 0 : sal_Bool SfxObjectShell::LoadFrom( SfxMedium& /*rMedium*/ )
2815 : {
2816 : OSL_FAIL( "Base implementation, must not be called in general!" );
2817 0 : return sal_True;
2818 : }
2819 :
2820 : //-------------------------------------------------------------------------
2821 0 : sal_Bool SfxObjectShell::IsInformationLost()
2822 : {
2823 0 : Sequence< PropertyValue > aProps = GetModel()->getArgs();
2824 0 : ::rtl::OUString aFilterName;
2825 0 : ::rtl::OUString aPreusedFilterName;
2826 0 : for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
2827 : {
2828 0 : if ( aProps[nInd].Name == "FilterName" )
2829 0 : aProps[nInd].Value >>= aFilterName;
2830 0 : else if ( aProps[nInd].Name == "PreusedFilterName" )
2831 0 : aProps[nInd].Value >>= aPreusedFilterName;
2832 : }
2833 :
2834 : // if current filter can lead to information loss and it was used
2835 : // for the latest store then the user should be asked to store in own format
2836 0 : if ( !aFilterName.isEmpty() && aFilterName.equals( aPreusedFilterName ) )
2837 : {
2838 0 : const SfxFilter *pFilt = GetMedium()->GetFilter();
2839 : DBG_ASSERT( pFilt && aFilterName.equals( pFilt->GetName() ), "MediaDescriptor contains wrong filter!\n" );
2840 0 : return ( pFilt && pFilt->IsAlienFormat() );
2841 : }
2842 :
2843 0 : return sal_False;
2844 : }
2845 :
2846 : //-------------------------------------------------------------------------
2847 0 : sal_Bool SfxObjectShell::CanReload_Impl()
2848 :
2849 : /* [Description]
2850 :
2851 : Internal method for determining whether a reload of the document
2852 : (as RevertToSaved or last known version) is possible.
2853 : */
2854 :
2855 : {
2856 0 : return pMedium && HasName() && !IsInModalMode() && !pImp->bForbidReload;
2857 : }
2858 :
2859 : //-------------------------------------------------------------------------
2860 :
2861 0 : sal_uInt16 SfxObjectShell::GetHiddenInformationState( sal_uInt16 nStates )
2862 : {
2863 0 : sal_uInt16 nState = 0;
2864 0 : if ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS )
2865 : {
2866 0 : if ( GetMedium()->GetVersionList().getLength() )
2867 0 : nState |= HIDDENINFORMATION_DOCUMENTVERSIONS;
2868 : }
2869 :
2870 0 : return nState;
2871 : }
2872 :
2873 0 : sal_Int16 SfxObjectShell::QueryHiddenInformation( HiddenWarningFact eFact, Window* pParent )
2874 : {
2875 0 : sal_Int16 nRet = RET_YES;
2876 0 : sal_uInt16 nResId = 0;
2877 0 : SvtSecurityOptions::EOption eOption = static_cast< SvtSecurityOptions::EOption >( -1 );
2878 :
2879 0 : switch ( eFact )
2880 : {
2881 : case WhenSaving :
2882 : {
2883 0 : nResId = STR_HIDDENINFO_CONTINUE_SAVING;
2884 0 : eOption = SvtSecurityOptions::E_DOCWARN_SAVEORSEND;
2885 0 : break;
2886 : }
2887 : case WhenPrinting :
2888 : {
2889 0 : nResId = STR_HIDDENINFO_CONTINUE_PRINTING;
2890 0 : eOption = SvtSecurityOptions::E_DOCWARN_PRINT;
2891 0 : break;
2892 : }
2893 : case WhenSigning :
2894 : {
2895 0 : nResId = STR_HIDDENINFO_CONTINUE_SIGNING;
2896 0 : eOption = SvtSecurityOptions::E_DOCWARN_SIGNING;
2897 0 : break;
2898 : }
2899 : case WhenCreatingPDF :
2900 : {
2901 0 : nResId = STR_HIDDENINFO_CONTINUE_CREATEPDF;
2902 0 : eOption = SvtSecurityOptions::E_DOCWARN_CREATEPDF;
2903 0 : break;
2904 : }
2905 : default:
2906 : {
2907 : SAL_WARN( "sfx2.doc", "SfxObjectShell::DetectHiddenInformation(): what fact?" );
2908 : }
2909 : }
2910 :
2911 0 : if ( eOption != -1 && SvtSecurityOptions().IsOptionSet( eOption ) )
2912 : {
2913 0 : String sMessage( SfxResId(STR_HIDDENINFO_CONTAINS).toString() );
2914 0 : sal_uInt16 nWantedStates = HIDDENINFORMATION_RECORDEDCHANGES | HIDDENINFORMATION_NOTES;
2915 0 : if ( eFact != WhenPrinting )
2916 0 : nWantedStates |= HIDDENINFORMATION_DOCUMENTVERSIONS;
2917 0 : sal_uInt16 nStates = GetHiddenInformationState( nWantedStates );
2918 0 : bool bWarning = false;
2919 :
2920 0 : if ( ( nStates & HIDDENINFORMATION_RECORDEDCHANGES ) == HIDDENINFORMATION_RECORDEDCHANGES )
2921 : {
2922 0 : sMessage += SfxResId(STR_HIDDENINFO_RECORDCHANGES).toString();
2923 0 : sMessage += '\n';
2924 0 : bWarning = true;
2925 : }
2926 0 : if ( ( nStates & HIDDENINFORMATION_NOTES ) == HIDDENINFORMATION_NOTES )
2927 : {
2928 0 : sMessage += SfxResId(STR_HIDDENINFO_NOTES).toString();
2929 0 : sMessage += '\n';
2930 0 : bWarning = true;
2931 : }
2932 0 : if ( ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS ) == HIDDENINFORMATION_DOCUMENTVERSIONS )
2933 : {
2934 0 : sMessage += SfxResId(STR_HIDDENINFO_DOCVERSIONS).toString();
2935 0 : sMessage += '\n';
2936 0 : bWarning = true;
2937 : }
2938 :
2939 0 : if ( bWarning )
2940 : {
2941 0 : sMessage += '\n';
2942 0 : sMessage += SfxResId(nResId).toString();
2943 0 : WarningBox aWBox( pParent, WB_YES_NO | WB_DEF_NO, sMessage );
2944 0 : nRet = aWBox.Execute();
2945 0 : }
2946 : }
2947 :
2948 0 : return nRet;
2949 : }
2950 :
2951 0 : sal_Bool SfxObjectShell::HasSecurityOptOpenReadOnly() const
2952 : {
2953 0 : return sal_True;
2954 : }
2955 :
2956 0 : sal_Bool SfxObjectShell::IsSecurityOptOpenReadOnly() const
2957 : {
2958 0 : return IsLoadReadonly();
2959 : }
2960 :
2961 0 : void SfxObjectShell::SetSecurityOptOpenReadOnly( sal_Bool _b )
2962 : {
2963 0 : SetLoadReadonly( _b );
2964 0 : }
2965 :
2966 41 : sal_Bool SfxObjectShell::LoadOwnFormat( SfxMedium& rMedium )
2967 : {
2968 41 : RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::LoadOwnFormat" );
2969 41 : if( RTL_LOGFILE_HASLOGFILE() )
2970 : {
2971 : rtl::OString aString(
2972 0 : rtl::OUStringToOString(rMedium.GetName(), RTL_TEXTENCODING_ASCII_US));
2973 0 : RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1(aLog, "loading \"%s\"", aString.getStr());
2974 : }
2975 :
2976 41 : uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage();
2977 41 : if ( xStorage.is() )
2978 : {
2979 : // Password
2980 41 : SFX_ITEMSET_ARG( rMedium.GetItemSet(), pPasswdItem, SfxStringItem, SID_PASSWORD, sal_False );
2981 41 : if ( pPasswdItem || ERRCODE_IO_ABORT != CheckPasswd_Impl( this, SFX_APP()->GetPool(), pMedium ) )
2982 : {
2983 41 : uno::Sequence< beans::NamedValue > aEncryptionData;
2984 41 : if ( GetEncryptionData_Impl(pMedium->GetItemSet(), aEncryptionData) )
2985 : {
2986 : try
2987 : {
2988 : // the following code must throw an exception in case of failure
2989 3 : ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xStorage, aEncryptionData );
2990 : }
2991 0 : catch( uno::Exception& )
2992 : {
2993 : // TODO/LATER: handle the error code
2994 : }
2995 : }
2996 :
2997 : // load document
2998 41 : return Load( rMedium );
2999 : }
3000 0 : return sal_False;
3001 : }
3002 : else
3003 0 : return sal_False;
3004 : }
3005 :
3006 290 : sal_Bool SfxObjectShell::SaveAsOwnFormat( SfxMedium& rMedium )
3007 : {
3008 290 : uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage();
3009 290 : if( xStorage.is() )
3010 : {
3011 290 : sal_Int32 nVersion = rMedium.GetFilter()->GetVersion();
3012 :
3013 : // OASIS templates have own mediatypes ( SO7 also actually, but it is to late to use them here )
3014 290 : sal_Bool bTemplate = ( rMedium.GetFilter()->IsOwnTemplateFormat() && nVersion > SOFFICE_FILEFORMAT_60 );
3015 :
3016 290 : SetupStorage( xStorage, nVersion, bTemplate );
3017 : #ifndef DISABLE_SCRIPTING
3018 290 : if ( HasBasic() )
3019 : {
3020 : // Initialize Basic
3021 288 : GetBasicManager();
3022 :
3023 : // Save dialog/script container
3024 288 : pImp->pBasicManager->storeLibrariesToStorage( xStorage );
3025 : }
3026 : #endif
3027 290 : return SaveAs( rMedium );
3028 : }
3029 0 : else return sal_False;
3030 : }
3031 :
3032 5478 : uno::Reference< embed::XStorage > SfxObjectShell::GetStorage()
3033 : {
3034 5478 : if ( !pImp->m_xDocStorage.is() )
3035 : {
3036 : OSL_ENSURE( pImp->m_bCreateTempStor, "The storage must exist already!\n" );
3037 : try {
3038 : // no notification is required the storage is set the first time
3039 668 : pImp->m_xDocStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3040 : OSL_ENSURE( pImp->m_xDocStorage.is(), "The method must either return storage or throw an exception!" );
3041 :
3042 416 : SetupStorage( pImp->m_xDocStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False );
3043 416 : pImp->m_bCreateTempStor = sal_False;
3044 416 : SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) );
3045 : }
3046 252 : catch( uno::Exception& )
3047 : {
3048 : // TODO/LATER: error handling?
3049 : DBG_UNHANDLED_EXCEPTION();
3050 : }
3051 : }
3052 :
3053 : OSL_ENSURE( pImp->m_xDocStorage.is(), "The document storage must be created!" );
3054 5478 : return pImp->m_xDocStorage;
3055 : }
3056 :
3057 :
3058 0 : sal_Bool SfxObjectShell::SaveChildren( sal_Bool bObjectsOnly )
3059 : {
3060 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveChildren" );
3061 :
3062 0 : sal_Bool bResult = sal_True;
3063 0 : if ( pImp->mpObjectContainer )
3064 : {
3065 0 : sal_Bool bOasis = ( SotStorage::GetVersion( GetStorage() ) > SOFFICE_FILEFORMAT_60 );
3066 0 : GetEmbeddedObjectContainer().StoreChildren(bOasis,bObjectsOnly);
3067 : }
3068 :
3069 0 : return bResult;
3070 : }
3071 :
3072 290 : sal_Bool SfxObjectShell::SaveAsChildren( SfxMedium& rMedium )
3073 : {
3074 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveAsChildren" );
3075 :
3076 290 : sal_Bool bResult = sal_True;
3077 :
3078 290 : uno::Reference < embed::XStorage > xStorage = rMedium.GetStorage();
3079 290 : if ( !xStorage.is() )
3080 0 : return sal_False;
3081 :
3082 290 : if ( xStorage == GetStorage() )
3083 0 : return SaveChildren();
3084 :
3085 290 : sal_Bool bOasis = sal_True;
3086 290 : if ( pImp->mpObjectContainer )
3087 : {
3088 145 : bOasis = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 );
3089 145 : GetEmbeddedObjectContainer().StoreAsChildren(bOasis,SFX_CREATE_MODE_EMBEDDED == eCreateMode,xStorage);
3090 : }
3091 :
3092 290 : if ( bResult )
3093 290 : bResult = CopyStoragesOfUnknownMediaType( GetStorage(), xStorage );
3094 :
3095 290 : return bResult;
3096 : }
3097 :
3098 341 : sal_Bool SfxObjectShell::SaveCompletedChildren( sal_Bool bSuccess )
3099 : {
3100 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompletedChildren" );
3101 :
3102 341 : sal_Bool bResult = sal_True;
3103 :
3104 341 : if ( pImp->mpObjectContainer )
3105 : {
3106 198 : uno::Sequence < ::rtl::OUString > aNames = GetEmbeddedObjectContainer().GetObjectNames();
3107 341 : for ( sal_Int32 n=0; n<aNames.getLength(); n++ )
3108 : {
3109 143 : uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObjectContainer().GetEmbeddedObject( aNames[n] );
3110 : OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
3111 143 : if ( xObj.is() )
3112 : {
3113 143 : uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
3114 143 : if ( xPersist.is() )
3115 : {
3116 : try
3117 : {
3118 143 : xPersist->saveCompleted( bSuccess );
3119 : }
3120 0 : catch( uno::Exception& )
3121 : {
3122 : // TODO/LATER: error handling
3123 0 : bResult = sal_False;
3124 : break;
3125 : }
3126 143 : }
3127 : }
3128 341 : }
3129 : }
3130 :
3131 341 : return bResult;
3132 : }
3133 :
3134 573 : sal_Bool SfxObjectShell::SwitchChildrenPersistance( const uno::Reference< embed::XStorage >& xStorage,
3135 : sal_Bool bForceNonModified )
3136 : {
3137 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchChildrenPersistence" );
3138 :
3139 573 : if ( !xStorage.is() )
3140 : {
3141 : // TODO/LATER: error handling
3142 0 : return sal_False;
3143 : }
3144 :
3145 573 : sal_Bool bResult = sal_True;
3146 :
3147 573 : if ( pImp->mpObjectContainer )
3148 287 : pImp->mpObjectContainer->SetPersistentEntries(xStorage,bForceNonModified);
3149 :
3150 573 : return bResult;
3151 : }
3152 :
3153 : // Never call this method directly, always use the DoSaveCompleted call
3154 580 : sal_Bool SfxObjectShell::SaveCompleted( const uno::Reference< embed::XStorage >& xStorage )
3155 : {
3156 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompleted" );
3157 :
3158 580 : sal_Bool bResult = sal_False;
3159 580 : sal_Bool bSendNotification = sal_False;
3160 580 : uno::Reference< embed::XStorage > xOldStorageHolder;
3161 :
3162 : #ifdef DBG_UTIL
3163 : // check for wrong creation of object container
3164 : sal_Bool bHasContainer = ( pImp->mpObjectContainer != 0 );
3165 : #endif
3166 :
3167 580 : if ( !xStorage.is() || xStorage == GetStorage() )
3168 : {
3169 : // no persistence change
3170 293 : bResult = SaveCompletedChildren( sal_False );
3171 : }
3172 : else
3173 : {
3174 287 : if ( pImp->mpObjectContainer )
3175 144 : GetEmbeddedObjectContainer().SwitchPersistence( xStorage );
3176 :
3177 287 : bResult = SwitchChildrenPersistance( xStorage, sal_True );
3178 : }
3179 :
3180 580 : if ( bResult )
3181 : {
3182 580 : if ( xStorage.is() && pImp->m_xDocStorage != xStorage )
3183 : {
3184 : // make sure that until the storage is assigned the object
3185 : // container is not created by accident!
3186 : DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" );
3187 287 : xOldStorageHolder = pImp->m_xDocStorage;
3188 287 : pImp->m_xDocStorage = xStorage;
3189 287 : bSendNotification = sal_True;
3190 :
3191 287 : if ( IsEnableSetModified() )
3192 287 : SetModified( sal_False );
3193 : }
3194 : }
3195 : else
3196 : {
3197 0 : if ( pImp->mpObjectContainer )
3198 0 : GetEmbeddedObjectContainer().SwitchPersistence( pImp->m_xDocStorage );
3199 :
3200 : // let already successfully connected objects be switched back
3201 0 : SwitchChildrenPersistance( pImp->m_xDocStorage, sal_True );
3202 : }
3203 :
3204 580 : if ( bSendNotification )
3205 : {
3206 287 : SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) );
3207 : }
3208 :
3209 580 : return bResult;
3210 : }
3211 :
3212 : #if OSL_DEBUG_LEVEL > 0
3213 : sal_Bool StoragesOfUnknownMediaTypeAreCopied_Impl( const uno::Reference< embed::XStorage >& xSource,
3214 : const uno::Reference< embed::XStorage >& xTarget )
3215 : {
3216 : OSL_ENSURE( xSource.is() && xTarget.is(), "Source and/or target storages are not available!\n" );
3217 : if ( !xSource.is() || !xTarget.is() || xSource == xTarget )
3218 : return sal_True;
3219 :
3220 : try
3221 : {
3222 : uno::Sequence< ::rtl::OUString > aSubElements = xSource->getElementNames();
3223 : for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ )
3224 : {
3225 : if ( xSource->isStorageElement( aSubElements[nInd] ) )
3226 : {
3227 : ::rtl::OUString aMediaType;
3228 : ::rtl::OUString aMediaTypePropName( "MediaType" );
3229 : sal_Bool bGotMediaType = sal_False;
3230 :
3231 : try
3232 : {
3233 : uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW );
3234 : bGotMediaType =
3235 : ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType );
3236 : }
3237 : catch( uno::Exception& )
3238 : {}
3239 :
3240 : if ( !bGotMediaType )
3241 : {
3242 : uno::Reference< embed::XStorage > xSubStorage;
3243 : try {
3244 : xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ );
3245 : } catch( uno::Exception& )
3246 : {}
3247 :
3248 : if ( !xSubStorage.is() )
3249 : {
3250 : xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3251 : xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage );
3252 : }
3253 :
3254 : uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW );
3255 : bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType );
3256 : }
3257 :
3258 : // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist
3259 : // probably it should be placed in the MimeType-ClassID table or in standalone table
3260 : if ( !aMediaType.isEmpty()
3261 : && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL )
3262 : {
3263 : ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
3264 : aDataFlavor.MimeType = aMediaType;
3265 : sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor );
3266 :
3267 : switch ( nFormat )
3268 : {
3269 : case SOT_FORMATSTR_ID_STARWRITER_60 :
3270 : case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
3271 : case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
3272 : case SOT_FORMATSTR_ID_STARDRAW_60 :
3273 : case SOT_FORMATSTR_ID_STARIMPRESS_60 :
3274 : case SOT_FORMATSTR_ID_STARCALC_60 :
3275 : case SOT_FORMATSTR_ID_STARCHART_60 :
3276 : case SOT_FORMATSTR_ID_STARMATH_60 :
3277 : case SOT_FORMATSTR_ID_STARWRITER_8:
3278 : case SOT_FORMATSTR_ID_STARWRITERWEB_8:
3279 : case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
3280 : case SOT_FORMATSTR_ID_STARDRAW_8:
3281 : case SOT_FORMATSTR_ID_STARIMPRESS_8:
3282 : case SOT_FORMATSTR_ID_STARCALC_8:
3283 : case SOT_FORMATSTR_ID_STARCHART_8:
3284 : case SOT_FORMATSTR_ID_STARMATH_8:
3285 : break;
3286 :
3287 : default:
3288 : {
3289 : if ( !xTarget->hasByName( aSubElements[nInd] ) )
3290 : return sal_False;
3291 : }
3292 : }
3293 : }
3294 : }
3295 : }
3296 : }
3297 : catch( uno::Exception& )
3298 : {
3299 : OSL_FAIL( "Cant check storage consistency!\n" );
3300 : }
3301 :
3302 : return sal_True;
3303 : }
3304 : #endif
3305 :
3306 286 : sal_Bool SfxObjectShell::SwitchPersistance( const uno::Reference< embed::XStorage >& xStorage )
3307 : {
3308 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchPersistance" );
3309 :
3310 286 : sal_Bool bResult = sal_False;
3311 : #ifdef DBG_UTIL
3312 : // check for wrong creation of object container
3313 : sal_Bool bHasContainer = ( pImp->mpObjectContainer != 0 );
3314 : #endif
3315 286 : if ( xStorage.is() )
3316 : {
3317 286 : if ( pImp->mpObjectContainer )
3318 143 : GetEmbeddedObjectContainer().SwitchPersistence( xStorage );
3319 286 : bResult = SwitchChildrenPersistance( xStorage );
3320 :
3321 : // TODO/LATER: substorages that have unknown mimetypes probably should be copied to the target storage here
3322 : OSL_ENSURE( StoragesOfUnknownMediaTypeAreCopied_Impl( pImp->m_xDocStorage, xStorage ),
3323 : "Some of substorages with unknown mimetypes is lost!" );
3324 : }
3325 :
3326 286 : if ( bResult )
3327 : {
3328 : // make sure that until the storage is assigned the object container is not created by accident!
3329 : DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" );
3330 286 : if ( pImp->m_xDocStorage != xStorage )
3331 286 : DoSaveCompleted( new SfxMedium( xStorage, GetMedium()->GetBaseURL() ) );
3332 :
3333 286 : if ( IsEnableSetModified() )
3334 286 : SetModified( sal_True ); // ???
3335 : }
3336 :
3337 286 : return bResult;
3338 : }
3339 :
3340 290 : sal_Bool SfxObjectShell::CopyStoragesOfUnknownMediaType( const uno::Reference< embed::XStorage >& xSource,
3341 : const uno::Reference< embed::XStorage >& xTarget )
3342 : {
3343 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::CopyStoragesOfUnknownMediaType" );
3344 :
3345 : // This method does not commit the target storage and should not do it
3346 290 : sal_Bool bResult = sal_True;
3347 :
3348 : try
3349 : {
3350 290 : uno::Sequence< ::rtl::OUString > aSubElements = xSource->getElementNames();
3351 1735 : for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ )
3352 : {
3353 1445 : if ( aSubElements[nInd] == "Configurations" )
3354 : {
3355 : // The workaround for compatibility with SO7, "Configurations" substorage must be preserved
3356 0 : if ( xSource->isStorageElement( aSubElements[nInd] ) )
3357 : {
3358 : OSL_ENSURE( !xTarget->hasByName( aSubElements[nInd] ),
3359 : "The target storage is an output storage, the element should not exist in the target!\n" );
3360 :
3361 0 : xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] );
3362 : }
3363 : }
3364 1445 : else if ( xSource->isStorageElement( aSubElements[nInd] ) )
3365 : {
3366 1148 : ::rtl::OUString aMediaType;
3367 1148 : ::rtl::OUString aMediaTypePropName( "MediaType" );
3368 1148 : sal_Bool bGotMediaType = sal_False;
3369 :
3370 : try
3371 : {
3372 1148 : uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW );
3373 : bGotMediaType =
3374 1148 : ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType );
3375 : }
3376 0 : catch( uno::Exception& )
3377 : {}
3378 :
3379 1148 : if ( !bGotMediaType )
3380 : {
3381 0 : uno::Reference< embed::XStorage > xSubStorage;
3382 : try {
3383 0 : xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ );
3384 0 : } catch( uno::Exception& )
3385 : {}
3386 :
3387 0 : if ( !xSubStorage.is() )
3388 : {
3389 : // TODO/LATER: as optimization in future a substorage of target storage could be used
3390 : // instead of the temporary storage; this substorage should be removed later
3391 : // if the MimeType is wrong
3392 0 : xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3393 0 : xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage );
3394 : }
3395 :
3396 0 : uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW );
3397 0 : bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType );
3398 : }
3399 :
3400 : // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist
3401 : // probably it should be placed in the MimeType-ClassID table or in standalone table
3402 1150 : if ( !aMediaType.isEmpty()
3403 2 : && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL )
3404 : {
3405 2 : ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
3406 2 : aDataFlavor.MimeType = aMediaType;
3407 2 : sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor );
3408 :
3409 2 : switch ( nFormat )
3410 : {
3411 : case SOT_FORMATSTR_ID_STARWRITER_60 :
3412 : case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
3413 : case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
3414 : case SOT_FORMATSTR_ID_STARDRAW_60 :
3415 : case SOT_FORMATSTR_ID_STARIMPRESS_60 :
3416 : case SOT_FORMATSTR_ID_STARCALC_60 :
3417 : case SOT_FORMATSTR_ID_STARCHART_60 :
3418 : case SOT_FORMATSTR_ID_STARMATH_60 :
3419 : case SOT_FORMATSTR_ID_STARWRITER_8:
3420 : case SOT_FORMATSTR_ID_STARWRITERWEB_8:
3421 : case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
3422 : case SOT_FORMATSTR_ID_STARDRAW_8:
3423 : case SOT_FORMATSTR_ID_STARIMPRESS_8:
3424 : case SOT_FORMATSTR_ID_STARCALC_8:
3425 : case SOT_FORMATSTR_ID_STARCHART_8:
3426 : case SOT_FORMATSTR_ID_STARMATH_8:
3427 0 : break;
3428 :
3429 : default:
3430 : {
3431 : OSL_ENSURE( aSubElements[nInd] == "Configurations2" || !xTarget->hasByName( aSubElements[nInd] ),
3432 : "The target storage is an output storage, the element should not exist in the target!\n" );
3433 :
3434 2 : if ( !xTarget->hasByName( aSubElements[nInd] ) )
3435 : {
3436 2 : xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] );
3437 : }
3438 : }
3439 2 : }
3440 1148 : }
3441 : }
3442 290 : }
3443 : }
3444 0 : catch( uno::Exception& )
3445 : {
3446 0 : bResult = sal_False;
3447 : // TODO/LATER: a specific error could be provided
3448 : }
3449 :
3450 290 : return bResult;
3451 : }
3452 :
3453 3 : sal_Bool SfxObjectShell::GenerateAndStoreThumbnail( sal_Bool bEncrypted,
3454 : sal_Bool bSigned,
3455 : sal_Bool bIsTemplate,
3456 : const uno::Reference< embed::XStorage >& xStor )
3457 : {
3458 : RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::GenerateAndStoreThumbnail" );
3459 :
3460 3 : sal_Bool bResult = sal_False;
3461 :
3462 : try {
3463 : uno::Reference< embed::XStorage > xThumbnailStor =
3464 3 : xStor->openStorageElement( ::rtl::OUString("Thumbnails"),
3465 3 : embed::ElementModes::READWRITE );
3466 3 : if ( xThumbnailStor.is() )
3467 : {
3468 3 : uno::Reference< io::XStream > xStream = xThumbnailStor->openStreamElement(
3469 : ::rtl::OUString("thumbnail.png"),
3470 3 : embed::ElementModes::READWRITE );
3471 :
3472 3 : if ( xStream.is() && WriteThumbnail( bEncrypted, bSigned, bIsTemplate, xStream ) )
3473 : {
3474 3 : uno::Reference< embed::XTransactedObject > xTransact( xThumbnailStor, uno::UNO_QUERY_THROW );
3475 3 : xTransact->commit();
3476 3 : bResult = sal_True;
3477 3 : }
3478 3 : }
3479 : }
3480 0 : catch( uno::Exception& )
3481 : {
3482 : }
3483 :
3484 3 : return bResult;
3485 : }
3486 :
3487 3 : sal_Bool SfxObjectShell::WriteThumbnail( sal_Bool bEncrypted,
3488 : sal_Bool bSigned,
3489 : sal_Bool bIsTemplate,
3490 : const uno::Reference< io::XStream >& xStream )
3491 : {
3492 3 : sal_Bool bResult = sal_False;
3493 :
3494 3 : if ( xStream.is() )
3495 : {
3496 : try {
3497 3 : uno::Reference< io::XTruncate > xTruncate( xStream->getOutputStream(), uno::UNO_QUERY_THROW );
3498 3 : xTruncate->truncate();
3499 :
3500 3 : uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
3501 3 : if ( xSet.is() )
3502 3 : xSet->setPropertyValue( ::rtl::OUString("MediaType"),
3503 3 : uno::makeAny( ::rtl::OUString("image/png") ) );
3504 3 : if ( bEncrypted )
3505 : {
3506 : sal_uInt16 nResID = GraphicHelper::getThumbnailReplacementIDByFactoryName_Impl(
3507 0 : ::rtl::OUString::createFromAscii( GetFactory().GetShortName() ),
3508 0 : bIsTemplate );
3509 0 : if ( nResID )
3510 : {
3511 0 : if ( !bSigned )
3512 : {
3513 0 : bResult = GraphicHelper::getThumbnailReplacement_Impl( nResID, xStream );
3514 : }
3515 : else
3516 : {
3517 : // retrieve the bitmap and write a signature bitmap over it
3518 0 : SfxResId aResId( nResID );
3519 0 : BitmapEx aThumbBitmap( aResId );
3520 0 : bResult = GraphicHelper::getSignedThumbnailFormatFromBitmap_Impl( aThumbBitmap, xStream );
3521 : }
3522 : }
3523 : }
3524 : else
3525 : {
3526 : ::boost::shared_ptr<GDIMetaFile> pMetaFile =
3527 3 : GetPreviewMetaFile( sal_False );
3528 3 : if ( pMetaFile )
3529 : {
3530 : bResult = GraphicHelper::getThumbnailFormatFromGDI_Impl(
3531 3 : pMetaFile.get(), bSigned, xStream );
3532 3 : }
3533 3 : }
3534 : }
3535 0 : catch( uno::Exception& )
3536 : {}
3537 : }
3538 :
3539 3 : return bResult;
3540 : }
3541 :
3542 4 : void SfxObjectShell::UpdateLinks()
3543 : {
3544 4 : }
3545 :
3546 0 : bool SfxObjectShell::LoadExternal(SfxMedium&, const OUString&)
3547 : {
3548 : // Not implemented. It's an error if the code path ever comes here.
3549 0 : return false;
3550 : }
3551 :
3552 0 : void SfxObjectShell::CheckConfigOptions()
3553 : {
3554 : // not handled. Each app's shell needs to overwrite this method to add handler.
3555 0 : SetConfigOptionsChecked(true);
3556 0 : }
3557 :
3558 0 : sal_Bool SfxObjectShell::IsConfigOptionsChecked() const
3559 : {
3560 0 : return pImp->m_bConfigOptionsChecked;
3561 : }
3562 :
3563 0 : void SfxObjectShell::SetConfigOptionsChecked( sal_Bool bChecked )
3564 : {
3565 0 : pImp->m_bConfigOptionsChecked = bChecked;
3566 0 : }
3567 :
3568 4 : sal_Bool SfxObjectShell::QuerySaveSizeExceededModules_Impl( const uno::Reference< task::XInteractionHandler >& xHandler )
3569 : {
3570 : #ifdef DISABLE_SCRIPTING
3571 : (void) xHandler;
3572 : #else
3573 4 : if ( !HasBasic() )
3574 2 : return sal_True;
3575 :
3576 2 : if ( !pImp->pBasicManager->isValid() )
3577 0 : GetBasicManager();
3578 2 : uno::Sequence< rtl::OUString > sModules;
3579 2 : if ( xHandler.is() )
3580 : {
3581 2 : if( pImp->pBasicManager->LegacyPsswdBinaryLimitExceeded( sModules ) )
3582 : {
3583 0 : ModuleSizeExceeded* pReq = new ModuleSizeExceeded( sModules );
3584 0 : uno::Reference< task::XInteractionRequest > xReq( pReq );
3585 0 : xHandler->handle( xReq );
3586 0 : return pReq->isApprove();
3587 : }
3588 : }
3589 : #endif
3590 : // No interaction handler, default is to continue to save
3591 2 : return sal_True;
3592 : }
3593 : // -----------------------------------------------------------------------------
3594 0 : uno::Reference< task::XInteractionHandler > SfxObjectShell::getInteractionHandler() const
3595 : {
3596 0 : uno::Reference< task::XInteractionHandler > xRet;
3597 0 : if ( GetMedium() )
3598 0 : xRet = GetMedium()->GetInteractionHandler();
3599 0 : return xRet;
3600 : }
3601 :
3602 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|