1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <scriptcont.hxx>
21 #include <com/sun/star/packages/WrongPasswordException.hpp>
22 #include <com/sun/star/xml/sax/Parser.hpp>
23 #include <com/sun/star/xml/sax/InputSource.hpp>
24 #include <com/sun/star/xml/sax/Writer.hpp>
25 #include <com/sun/star/io/XTruncate.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <com/sun/star/embed/XEncryptionProtectedSource.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/embed/XTransactedObject.hpp>
30 #include <com/sun/star/task/ErrorCodeIOException.hpp>
31 #include <com/sun/star/script/ModuleType.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <comphelper/storagehelper.hxx>
34 #include <unotools/ucbstreamhelper.hxx>
35 #include <sal/log.hxx>
36 #include <sot/storage.hxx>
38 // For password functionality
39 #include <tools/urlobj.hxx>
42 #include <svtools/sfxecode.hxx>
43 #include <svtools/ehdl.hxx>
44 #include <basic/basmgr.hxx>
45 #include <basic/sbmod.hxx>
46 #include <basic/modsizeexceeded.hxx>
47 #include <xmlscript/xmlmod_imexp.hxx>
48 #include <com/sun/star/util/VetoException.hpp>
54 using namespace com::sun::star::document
;
55 using namespace com::sun::star::container
;
56 using namespace com::sun::star::io
;
57 using namespace com::sun::star::uno
;
58 using namespace com::sun::star::ucb
;
59 using namespace com::sun::star::lang
;
60 using namespace com::sun::star::script
;
61 using namespace com::sun::star::xml::sax
;
62 using namespace com::sun::star
;
67 // Implementation class SfxScriptLibraryContainer
69 const sal_Char
* SfxScriptLibraryContainer::getInfoFileName() const { return "script"; }
70 const sal_Char
* SfxScriptLibraryContainer::getOldInfoFileName() const { return "script"; }
71 const sal_Char
* SfxScriptLibraryContainer::getLibElementFileExtension() const { return "xba"; }
72 const sal_Char
* SfxScriptLibraryContainer::getLibrariesDir() const { return "Basic"; }
74 // OldBasicPassword interface
75 void SfxScriptLibraryContainer::setLibraryPassword( const OUString
& rLibraryName
, const OUString
& rPassword
)
79 SfxLibrary
* pImplLib
= getImplLib( rLibraryName
);
80 if( !rPassword
.isEmpty() )
82 pImplLib
->mbDoc50Password
= true;
83 pImplLib
->mbPasswordProtected
= true;
84 pImplLib
->maPassword
= rPassword
;
85 SfxScriptLibrary
*const pSL(dynamic_cast<SfxScriptLibrary
*>(pImplLib
));
86 if (pSL
&& pSL
->mbLoaded
)
88 pSL
->mbLoadedSource
= true; // must store source code now!
92 catch(const NoSuchElementException
& ) {}
96 SfxScriptLibraryContainer::SfxScriptLibraryContainer()
98 // all initialisation has to be done
99 // by calling XInitialization::initialize
102 SfxScriptLibraryContainer::SfxScriptLibraryContainer( const uno::Reference
< embed::XStorage
>& xStorage
)
104 init( OUString(), xStorage
);
107 // Methods to get library instances of the correct type
108 SfxLibrary
* SfxScriptLibraryContainer::implCreateLibrary( const OUString
& )
110 SfxLibrary
* pRet
= new SfxScriptLibrary( maModifiable
, mxSFI
);
114 SfxLibrary
* SfxScriptLibraryContainer::implCreateLibraryLink( const OUString
&,
115 const OUString
& aLibInfoFileURL
,
116 const OUString
& StorageURL
,
119 SfxLibrary
* pRet
= new SfxScriptLibrary( maModifiable
, mxSFI
,
120 aLibInfoFileURL
, StorageURL
, ReadOnly
);
124 Any
SfxScriptLibraryContainer::createEmptyLibraryElement()
127 aRetAny
<<= OUString();
131 bool SfxScriptLibraryContainer::isLibraryElementValid(const Any
& rElement
) const
133 return SfxScriptLibrary::containsValidModule(rElement
);
136 void SfxScriptLibraryContainer::writeLibraryElement( const Reference
< XNameContainer
>& xLib
,
137 const OUString
& aElementName
,
138 const Reference
< XOutputStream
>& xOutput
)
141 Reference
< XWriter
> xWriter
= xml::sax::Writer::create(mxContext
);
143 Reference
< XTruncate
> xTruncate( xOutput
, UNO_QUERY
);
144 OSL_ENSURE( xTruncate
.is(), "Currently only the streams that can be truncated are expected!" );
145 if ( xTruncate
.is() )
147 xTruncate
->truncate();
149 xWriter
->setOutputStream( xOutput
);
151 xmlscript::ModuleDescriptor aMod
;
152 aMod
.aName
= aElementName
;
153 aMod
.aLanguage
= "StarBasic";
154 Any aElement
= xLib
->getByName( aElementName
);
155 aElement
>>= aMod
.aCode
;
157 Reference
< script::vba::XVBAModuleInfo
> xModInfo( xLib
, UNO_QUERY
);
158 if( xModInfo
.is() && xModInfo
->hasModuleInfo( aElementName
) )
160 script::ModuleInfo aModInfo
= xModInfo
->getModuleInfo( aElementName
);
161 switch( aModInfo
.ModuleType
)
163 case ModuleType::NORMAL
:
164 aMod
.aModuleType
= "normal";
166 case ModuleType::CLASS
:
167 aMod
.aModuleType
="class";
169 case ModuleType::FORM
:
170 aMod
.aModuleType
= "form";
172 case ModuleType::DOCUMENT
:
173 aMod
.aModuleType
= "document";
175 case ModuleType::UNKNOWN
:
181 xmlscript::exportScriptModule( xWriter
, aMod
);
185 Any
SfxScriptLibraryContainer::importLibraryElement
186 ( const Reference
< XNameContainer
>& xLib
,
187 const OUString
& aElementName
, const OUString
& aFile
,
188 const uno::Reference
< io::XInputStream
>& xInStream
)
192 Reference
< XParser
> xParser
= xml::sax::Parser::create( mxContext
);
194 // Read from storage?
195 bool bStorage
= xInStream
.is();
196 Reference
< XInputStream
> xInput
;
206 xInput
= mxSFI
->openFileRead( aFile
);
208 catch(const Exception
& )
209 //catch( Exception& e )
212 //throw WrappedTargetException( e );
220 source
.aInputStream
= xInput
;
221 source
.sSystemId
= aFile
;
224 xmlscript::ModuleDescriptor aMod
;
228 xParser
->setDocumentHandler( ::xmlscript::importScriptModule( aMod
) );
229 xParser
->parseStream( source
);
231 catch(const Exception
& )
233 SfxErrorContext
aEc( ERRCTX_SFX_LOADBASIC
, aFile
);
234 ErrorHandler::HandleError( ERRCODE_IO_GENERAL
);
237 aRetAny
<<= aMod
.aCode
;
239 // TODO: Check language
241 // aMod.aName ignored
242 if( !aMod
.aModuleType
.isEmpty() )
244 /* If in VBA compatibility mode, force creation of the VBA Globals
245 object. Each application will create an instance of its own
246 implementation and store it in its Basic manager. Implementations
247 will do all necessary additional initialization, such as
248 registering the global "This***Doc" UNO constant, starting the
249 document events processor etc.
251 if( getVBACompatibilityMode() ) try
253 Reference
< frame::XModel
> xModel( mxOwnerDocument
); // weak-ref -> ref
254 Reference
< XMultiServiceFactory
> xFactory( xModel
, UNO_QUERY_THROW
);
255 xFactory
->createInstance("ooo.vba.VBAGlobals");
257 catch(const Exception
& )
261 script::ModuleInfo aModInfo
;
262 aModInfo
.ModuleType
= ModuleType::UNKNOWN
;
263 if( aMod
.aModuleType
== "normal" )
265 aModInfo
.ModuleType
= ModuleType::NORMAL
;
267 else if( aMod
.aModuleType
== "class" )
269 aModInfo
.ModuleType
= ModuleType::CLASS
;
271 else if( aMod
.aModuleType
== "form" )
273 aModInfo
.ModuleType
= ModuleType::FORM
;
274 aModInfo
.ModuleObject
= mxOwnerDocument
;
276 else if( aMod
.aModuleType
== "document" )
278 aModInfo
.ModuleType
= ModuleType::DOCUMENT
;
280 // #163691# use the same codename access instance for all document modules
281 if( !mxCodeNameAccess
.is() ) try
283 Reference
<frame::XModel
> xModel( mxOwnerDocument
);
284 Reference
< XMultiServiceFactory
> xSF( xModel
, UNO_QUERY_THROW
);
285 mxCodeNameAccess
.set( xSF
->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), UNO_QUERY
);
287 catch(const Exception
& ) {}
289 if( mxCodeNameAccess
.is() )
293 aModInfo
.ModuleObject
.set( mxCodeNameAccess
->getByName( aElementName
), uno::UNO_QUERY
);
295 catch(const uno::Exception
&)
297 SAL_WARN("basic", "Failed to get document object for " << aElementName
);
302 Reference
< script::vba::XVBAModuleInfo
> xVBAModuleInfo( xLib
, UNO_QUERY
);
303 if( xVBAModuleInfo
.is() )
305 if( xVBAModuleInfo
->hasModuleInfo( aElementName
) )
307 xVBAModuleInfo
->removeModuleInfo( aElementName
);
309 xVBAModuleInfo
->insertModuleInfo( aElementName
, aModInfo
);
316 SfxLibraryContainer
* SfxScriptLibraryContainer::createInstanceImpl()
318 return new SfxScriptLibraryContainer();
321 void SfxScriptLibraryContainer::importFromOldStorage( const OUString
& aFile
)
323 // TODO: move loading from old storage to binary filters?
324 auto xStorage
= tools::make_ref
<SotStorage
>( false, aFile
);
325 if( xStorage
->GetError() == ERRCODE_NONE
)
327 std::unique_ptr
<BasicManager
> pBasicManager(new BasicManager( *xStorage
, aFile
));
330 LibraryContainerInfo
aInfo( this, nullptr, static_cast< OldBasicPassword
* >( this ) );
331 pBasicManager
->SetLibraryContainerInfo( aInfo
);
336 // Storing with password encryption
338 // Methods XLibraryContainerPassword
339 sal_Bool SAL_CALL
SfxScriptLibraryContainer::isLibraryPasswordProtected( const OUString
& Name
)
341 LibraryContainerMethodGuard
aGuard( *this );
342 SfxLibrary
* pImplLib
= getImplLib( Name
);
343 bool bRet
= pImplLib
->mbPasswordProtected
;
347 sal_Bool SAL_CALL
SfxScriptLibraryContainer::isLibraryPasswordVerified( const OUString
& Name
)
349 LibraryContainerMethodGuard
aGuard( *this );
350 SfxLibrary
* pImplLib
= getImplLib( Name
);
351 if( !pImplLib
->mbPasswordProtected
)
353 throw IllegalArgumentException();
355 bool bRet
= pImplLib
->mbPasswordVerified
;
359 sal_Bool SAL_CALL
SfxScriptLibraryContainer::verifyLibraryPassword
360 ( const OUString
& Name
, const OUString
& Password
)
362 LibraryContainerMethodGuard
aGuard( *this );
363 SfxLibrary
* pImplLib
= getImplLib( Name
);
364 if( !pImplLib
->mbPasswordProtected
|| pImplLib
->mbPasswordVerified
)
366 throw IllegalArgumentException();
369 bool bSuccess
= false;
370 if( pImplLib
->mbDoc50Password
)
372 bSuccess
= ( Password
== pImplLib
->maPassword
);
375 pImplLib
->mbPasswordVerified
= true;
380 pImplLib
->maPassword
= Password
;
381 bSuccess
= implLoadPasswordLibrary( pImplLib
, Name
, true );
384 // The library gets modified by verifying the password, because other-
385 // wise for saving the storage would be copied and that doesn't work
386 // with mtg's storages when the password is verified
387 pImplLib
->implSetModified( true );
388 pImplLib
->mbPasswordVerified
= true;
390 // Reload library to get source
391 if( pImplLib
->mbLoaded
)
393 implLoadPasswordLibrary( pImplLib
, Name
);
400 void SAL_CALL
SfxScriptLibraryContainer::changeLibraryPassword( const OUString
& Name
,
401 const OUString
& OldPassword
,
402 const OUString
& NewPassword
)
404 LibraryContainerMethodGuard
aGuard( *this );
405 SfxLibrary
* pImplLib
= getImplLib( Name
);
406 if( OldPassword
== NewPassword
)
410 bool bOldPassword
= !OldPassword
.isEmpty();
411 bool bNewPassword
= !NewPassword
.isEmpty();
412 bool bStorage
= mxStorage
.is() && !pImplLib
->mbLink
;
414 if( pImplLib
->mbReadOnly
|| (bOldPassword
&& !pImplLib
->mbPasswordProtected
) )
416 throw IllegalArgumentException();
418 // Library must be loaded
421 bool bKillCryptedFiles
= false;
422 bool bKillUncryptedFiles
= false;
424 // Remove or change password?
427 if( isLibraryPasswordVerified( Name
) )
429 if( pImplLib
->maPassword
!= OldPassword
)
431 throw IllegalArgumentException();
436 if( !verifyLibraryPassword( Name
, OldPassword
) )
438 throw IllegalArgumentException();
440 // Reload library to get source
441 // Should be done in verifyLibraryPassword loadLibrary( Name );
446 pImplLib
->mbPasswordProtected
= false;
447 pImplLib
->mbPasswordVerified
= false;
448 pImplLib
->maPassword
.clear();
450 maModifiable
.setModified( true );
451 pImplLib
->implSetModified( true );
453 if( !bStorage
&& !pImplLib
->mbDoc50Password
)
455 // Store application basic unencrypted
456 uno::Reference
< embed::XStorage
> xStorage
;
457 storeLibraries_Impl( xStorage
, false );
458 bKillCryptedFiles
= true;
466 pImplLib
->mbPasswordProtected
= true;
467 pImplLib
->mbPasswordVerified
= true;
468 pImplLib
->maPassword
= NewPassword
;
469 SfxScriptLibrary
*const pSL(dynamic_cast<SfxScriptLibrary
*>(pImplLib
));
470 if (pSL
&& pSL
->mbLoaded
)
472 pSL
->mbLoadedSource
= true; // must store source code now!
475 maModifiable
.setModified( true );
476 pImplLib
->implSetModified( true );
478 if( !bStorage
&& !pImplLib
->mbDoc50Password
)
480 // Store application basic crypted
481 uno::Reference
< embed::XStorage
> xStorage
;
482 storeLibraries_Impl( xStorage
, false );
483 bKillUncryptedFiles
= true;
487 if( bKillCryptedFiles
|| bKillUncryptedFiles
)
489 Sequence
< OUString
> aElementNames
= pImplLib
->getElementNames();
490 sal_Int32 nNameCount
= aElementNames
.getLength();
491 const OUString
* pNames
= aElementNames
.getConstArray();
492 OUString aLibDirPath
= createAppLibraryFolder( pImplLib
, Name
);
495 for( sal_Int32 i
= 0 ; i
< nNameCount
; i
++ )
497 OUString aElementName
= pNames
[ i
];
499 INetURLObject
aElementInetObj( aLibDirPath
);
500 aElementInetObj
.insertName( aElementName
, false,
501 INetURLObject::LAST_SEGMENT
,
502 INetURLObject::EncodeMechanism::All
);
503 if( bKillUncryptedFiles
)
505 aElementInetObj
.setExtension( maLibElementFileExtension
);
509 aElementInetObj
.setExtension( "pba" );
511 OUString
aElementPath( aElementInetObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
513 if( mxSFI
->exists( aElementPath
) )
515 mxSFI
->kill( aElementPath
);
519 catch(const Exception
& ) {}
524 static void setStreamKey( const uno::Reference
< io::XStream
>& xStream
, const OUString
& aPass
)
526 uno::Reference
< embed::XEncryptionProtectedSource
> xEncrStream( xStream
, uno::UNO_QUERY
);
527 if ( xEncrStream
.is() )
529 xEncrStream
->setEncryptionPassword( aPass
);
535 bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary
* pLib
,
536 const OUString
& aName
,
537 const uno::Reference
< embed::XStorage
>& xStorage
,
538 const css::uno::Reference
< css::task::XInteractionHandler
>& xHandler
)
540 Reference
< XSimpleFileAccess3
> xDummySFA
;
541 return implStorePasswordLibrary( pLib
, aName
, xStorage
, OUString(), xDummySFA
, xHandler
);
544 bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary
* pLib
, const OUString
& aName
,
545 const css::uno::Reference
< css::embed::XStorage
>& xStorage
,
546 const OUString
& aTargetURL
,
547 const Reference
< XSimpleFileAccess3
>& rToUseSFI
,
548 const css::uno::Reference
< css::task::XInteractionHandler
>& xHandler
)
550 bool bExport
= !aTargetURL
.isEmpty();
552 BasicManager
* pBasicMgr
= getBasicManager();
553 OSL_ENSURE( pBasicMgr
, "SfxScriptLibraryContainer::implStorePasswordLibrary: cannot do this without a BasicManager!" );
558 // Only need to handle the export case here,
559 // save/saveas etc are handled in sfxbasemodel::storeSelf &
560 // sfxbasemodel::impl_store
561 std::vector
<OUString
> aNames
;
562 if ( bExport
&& pBasicMgr
->LegacyPsswdBinaryLimitExceeded(aNames
) )
566 ModuleSizeExceeded
* pReq
= new ModuleSizeExceeded( aNames
);
567 uno::Reference
< task::XInteractionRequest
> xReq( pReq
);
568 xHandler
->handle( xReq
);
569 if ( pReq
->isAbort() )
571 throw util::VetoException();
576 StarBASIC
* pBasicLib
= pBasicMgr
->GetLib( aName
);
581 Sequence
< OUString
> aElementNames
= pLib
->getElementNames();
582 sal_Int32 nNameCount
= aElementNames
.getLength();
583 const OUString
* pNames
= aElementNames
.getConstArray();
585 bool bLink
= pLib
->mbLink
;
586 bool bStorage
= xStorage
.is() && !bLink
;
589 for( sal_Int32 i
= 0 ; i
< nNameCount
; i
++ )
591 OUString aElementName
= pNames
[ i
];
593 // Write binary image stream
594 SbModule
* pMod
= pBasicLib
->FindModule( aElementName
);
597 OUString aCodeStreamName
= aElementName
+ ".bin";
600 uno::Reference
< io::XStream
> xCodeStream
= xStorage
->openStreamElement(
602 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
604 if ( !xCodeStream
.is() )
606 throw uno::RuntimeException("null returned from openStreamElement");
608 SvMemoryStream aMemStream
;
609 /*sal_Bool bStore = */pMod
->StoreBinaryData( aMemStream
);
611 sal_Int32
const nSize
= aMemStream
.Tell();
612 if (nSize
< 0) { abort(); }
613 Sequence
< sal_Int8
> aBinSeq( nSize
);
614 sal_Int8
* pData
= aBinSeq
.getArray();
615 memcpy( pData
, aMemStream
.GetData(), nSize
);
617 Reference
< XOutputStream
> xOut
= xCodeStream
->getOutputStream();
620 throw io::IOException(); // access denied because the stream is readonly
622 xOut
->writeBytes( aBinSeq
);
625 catch(const uno::Exception
& )
627 // TODO: handle error
631 if( pLib
->mbPasswordVerified
|| pLib
->mbDoc50Password
)
633 if( !isLibraryElementValid( pLib
->getByName( aElementName
) ) )
635 SAL_WARN( "basic", "invalid library element '" << aElementName
<< "'.");
639 OUString aSourceStreamName
= aElementName
+ ".xml";
642 uno::Reference
< io::XStream
> xSourceStream
= xStorage
->openStreamElement(
644 embed::ElementModes::READWRITE
);
645 uno::Reference
< beans::XPropertySet
> xProps( xSourceStream
, uno::UNO_QUERY_THROW
);
646 xProps
->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
648 // Set encryption key
649 setStreamKey( xSourceStream
, pLib
->maPassword
);
651 Reference
< XOutputStream
> xOutput
= xSourceStream
->getOutputStream();
652 Reference
< XNameContainer
> xLib( pLib
);
653 writeLibraryElement( xLib
, aElementName
, xOutput
);
655 catch(const uno::Exception
& )
657 OSL_FAIL( "Problem on storing of password library!" );
658 // TODO: error handling
661 else // !mbPasswordVerified
664 // What to do if not verified?! In any case it's already loaded here
669 // Application libraries have only to be saved if the password
670 // is verified because otherwise they can't be modified
671 else if( pLib
->mbPasswordVerified
|| bExport
)
675 Reference
< XSimpleFileAccess3
> xSFI
= mxSFI
;
680 OUString aLibDirPath
;
683 INetURLObject
aInetObj( aTargetURL
);
684 aInetObj
.insertName( aName
, true, INetURLObject::LAST_SEGMENT
,
685 INetURLObject::EncodeMechanism::All
);
686 aLibDirPath
= aInetObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
688 if( !xSFI
->isFolder( aLibDirPath
) )
690 xSFI
->createFolder( aLibDirPath
);
695 aLibDirPath
= createAppLibraryFolder( pLib
, aName
);
698 for( sal_Int32 i
= 0 ; i
< nNameCount
; i
++ )
700 OUString aElementName
= pNames
[ i
];
702 INetURLObject
aElementInetObj( aLibDirPath
);
703 aElementInetObj
.insertName( aElementName
, false,
704 INetURLObject::LAST_SEGMENT
,
705 INetURLObject::EncodeMechanism::All
);
706 aElementInetObj
.setExtension( "pba" );
707 OUString aElementPath
= aElementInetObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
709 if( !isLibraryElementValid( pLib
->getByName( aElementName
) ) )
711 SAL_WARN( "basic", "invalid library element '" << aElementName
<< "'.");
717 uno::Reference
< embed::XStorage
> xElementRootStorage
=
718 ::comphelper::OStorageHelper::GetStorageFromURL(
720 embed::ElementModes::READWRITE
);
721 if ( !xElementRootStorage
.is() )
723 throw uno::RuntimeException("null returned from GetStorageFromURL");
725 // Write binary image stream
726 SbModule
* pMod
= pBasicLib
->FindModule( aElementName
);
729 uno::Reference
< io::XStream
> xCodeStream
= xElementRootStorage
->openStreamElement(
731 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
);
733 SvMemoryStream aMemStream
;
734 /*sal_Bool bStore = */pMod
->StoreBinaryData( aMemStream
);
736 sal_Int32
const nSize
= aMemStream
.Tell();
737 if (nSize
< 0) { abort(); }
738 Sequence
< sal_Int8
> aBinSeq( nSize
);
739 sal_Int8
* pData
= aBinSeq
.getArray();
740 memcpy( pData
, aMemStream
.GetData(), nSize
);
742 Reference
< XOutputStream
> xOut
= xCodeStream
->getOutputStream();
745 xOut
->writeBytes( aBinSeq
);
750 // Write encrypted source stream
751 OUString
aSourceStreamName( "source.xml" );
753 uno::Reference
< io::XStream
> xSourceStream
;
756 xSourceStream
= xElementRootStorage
->openStreamElement(
758 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
);
760 // #87671 Allow encryption
761 uno::Reference
< embed::XEncryptionProtectedSource
> xEncr( xSourceStream
, uno::UNO_QUERY_THROW
);
762 xEncr
->setEncryptionPassword( pLib
->maPassword
);
764 catch(const css::packages::WrongPasswordException
& )
766 xSourceStream
= xElementRootStorage
->openEncryptedStreamElement(
768 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
,
772 uno::Reference
< beans::XPropertySet
> xProps( xSourceStream
, uno::UNO_QUERY_THROW
);
773 xProps
->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
775 Reference
< XOutputStream
> xOut
= xSourceStream
->getOutputStream();
776 Reference
< XNameContainer
> xLib( pLib
);
777 writeLibraryElement( xLib
, aElementName
, xOut
);
778 // i50568: sax writer already closes stream
779 // xOut->closeOutput();
781 uno::Reference
< embed::XTransactedObject
> xTransact( xElementRootStorage
, uno::UNO_QUERY_THROW
);
784 catch(const uno::Exception
& )
786 // TODO: handle error
791 catch(const Exception
& )
798 bool SfxScriptLibraryContainer::implLoadPasswordLibrary
799 ( SfxLibrary
* pLib
, const OUString
& Name
, bool bVerifyPasswordOnly
)
803 bool bLink
= pLib
->mbLink
;
804 bool bStorage
= mxStorage
.is() && !bLink
;
806 // Already loaded? Then only verifiedPassword can change something
807 SfxScriptLibrary
* pScriptLib
= static_cast< SfxScriptLibrary
* >( pLib
);
808 if( pScriptLib
->mbLoaded
)
810 if( pScriptLib
->mbLoadedBinary
&& !bVerifyPasswordOnly
&&
811 (pScriptLib
->mbLoadedSource
|| !pLib
->mbPasswordVerified
) )
817 StarBASIC
* pBasicLib
= nullptr;
818 bool bLoadBinary
= false;
819 if( !pScriptLib
->mbLoadedBinary
&& !bVerifyPasswordOnly
&& !pLib
->mbPasswordVerified
)
821 BasicManager
* pBasicMgr
= getBasicManager();
822 OSL_ENSURE( pBasicMgr
, "SfxScriptLibraryContainer::implLoadPasswordLibrary: cannot do this without a BasicManager!" );
823 bool bLoaded
= pScriptLib
->mbLoaded
;
824 pScriptLib
->mbLoaded
= true; // Necessary to get lib
825 pBasicLib
= pBasicMgr
? pBasicMgr
->GetLib( Name
) : nullptr;
826 pScriptLib
->mbLoaded
= bLoaded
; // Restore flag
832 pScriptLib
->mbLoadedBinary
= true;
835 bool bLoadSource
= false;
836 if( !pScriptLib
->mbLoadedSource
&& pLib
->mbPasswordVerified
&& !bVerifyPasswordOnly
)
839 pScriptLib
->mbLoadedSource
= true;
842 Sequence
< OUString
> aElementNames
= pLib
->getElementNames();
843 sal_Int32 nNameCount
= aElementNames
.getLength();
844 const OUString
* pNames
= aElementNames
.getConstArray();
848 uno::Reference
< embed::XStorage
> xLibrariesStor
;
849 uno::Reference
< embed::XStorage
> xLibraryStor
;
851 xLibrariesStor
= mxStorage
->openStorageElement( maLibrariesDir
, embed::ElementModes::READ
);
852 if ( !xLibrariesStor
.is() )
854 throw uno::RuntimeException("null returned from openStorageElement");
856 xLibraryStor
= xLibrariesStor
->openStorageElement( Name
, embed::ElementModes::READ
);
857 if ( !xLibraryStor
.is() )
859 throw uno::RuntimeException("null returned from openStorageElement");
862 catch(const uno::Exception
& )
864 OSL_FAIL( "### couldn't open sub storage for library" );
868 for( sal_Int32 i
= 0 ; i
< nNameCount
; i
++ )
870 OUString aElementName
= pNames
[ i
];
875 SbModule
* pMod
= pBasicLib
->FindModule( aElementName
);
878 pMod
= pBasicLib
->MakeModule( aElementName
, OUString() );
879 pBasicLib
->SetModified( false );
882 OUString aCodeStreamName
= aElementName
+ ".bin";
885 uno::Reference
< io::XStream
> xCodeStream
= xLibraryStor
->openStreamElement(
887 embed::ElementModes::READ
);
888 if ( !xCodeStream
.is() )
890 throw uno::RuntimeException("null returned from openStreamElement");
892 std::unique_ptr
<SvStream
> pStream(::utl::UcbStreamHelper::CreateStream( xCodeStream
));
893 if ( !pStream
|| pStream
->GetError() )
895 sal_uInt32 nError
= sal_uInt32(pStream
? pStream
->GetError() : ERRCODE_IO_GENERAL
);
896 throw task::ErrorCodeIOException(
897 ("utl::UcbStreamHelper::CreateStream failed for \""
898 + aCodeStreamName
+ "\": 0x"
899 + OUString::number(nError
, 16)),
900 uno::Reference
< uno::XInterface
>(), nError
);
903 /*sal_Bool bRet = */pMod
->LoadBinaryData( *pStream
);
904 // TODO: Check return value
906 catch(const uno::Exception
& )
908 // TODO: error handling
913 if( bLoadSource
|| bVerifyPasswordOnly
)
915 // Access encrypted source stream
916 OUString aSourceStreamName
= aElementName
+ ".xml";
919 uno::Reference
< io::XStream
> xSourceStream
= xLibraryStor
->openEncryptedStreamElement(
921 embed::ElementModes::READ
,
923 if ( !xSourceStream
.is() )
925 throw uno::RuntimeException("null returned from openEncryptedStreamElement");
927 // if this point is reached then the password is correct
928 if ( !bVerifyPasswordOnly
)
930 uno::Reference
< io::XInputStream
> xInStream
= xSourceStream
->getInputStream();
931 if ( !xInStream
.is() )
933 throw io::IOException(); // read access denied, seems to be impossible
935 Reference
< XNameContainer
> xLib( pLib
);
936 Any aAny
= importLibraryElement( xLib
,
937 aElementName
, aSourceStreamName
,
939 if( pLib
->hasByName( aElementName
) )
941 if( aAny
.hasValue() )
943 pLib
->maNameContainer
->replaceByName( aElementName
, aAny
);
948 pLib
->maNameContainer
->insertByName( aElementName
, aAny
);
952 catch(const uno::Exception
& )
963 OUString aLibDirPath
= createAppLibraryFolder( pLib
, Name
);
965 for( sal_Int32 i
= 0 ; i
< nNameCount
; i
++ )
967 OUString aElementName
= pNames
[ i
];
969 INetURLObject
aElementInetObj( aLibDirPath
);
970 aElementInetObj
.insertName( aElementName
, false,
971 INetURLObject::LAST_SEGMENT
, INetURLObject::EncodeMechanism::All
);
972 aElementInetObj
.setExtension( "pba" );
973 OUString aElementPath
= aElementInetObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
975 uno::Reference
< embed::XStorage
> xElementRootStorage
;
978 xElementRootStorage
= ::comphelper::OStorageHelper::GetStorageFromURL(
980 embed::ElementModes::READ
);
981 } catch(const uno::Exception
& )
983 // TODO: error handling
986 if ( xElementRootStorage
.is() )
991 SbModule
* pMod
= pBasicLib
->FindModule( aElementName
);
994 pMod
= pBasicLib
->MakeModule( aElementName
, OUString() );
995 pBasicLib
->SetModified( false );
1000 uno::Reference
< io::XStream
> xCodeStream
= xElementRootStorage
->openStreamElement(
1002 embed::ElementModes::READ
);
1004 std::unique_ptr
<SvStream
> pStream(::utl::UcbStreamHelper::CreateStream( xCodeStream
));
1005 if ( !pStream
|| pStream
->GetError() )
1007 sal_uInt32 nError
= sal_uInt32(pStream
? pStream
->GetError() : ERRCODE_IO_GENERAL
);
1008 throw task::ErrorCodeIOException(
1009 ("utl::UcbStreamHelper::CreateStream failed"
1011 + OUString::number(nError
, 16)),
1012 uno::Reference
< uno::XInterface
>(),
1016 /*sal_Bool bRet = */pMod
->LoadBinaryData( *pStream
);
1017 // TODO: Check return value
1019 catch(const uno::Exception
& )
1021 // TODO: error handling
1026 if( bLoadSource
|| bVerifyPasswordOnly
)
1028 // Access encrypted source stream
1029 OUString
aSourceStreamName( "source.xml" );
1032 uno::Reference
< io::XStream
> xSourceStream
= xElementRootStorage
->openEncryptedStreamElement(
1034 embed::ElementModes::READ
,
1036 if ( !xSourceStream
.is() )
1038 throw uno::RuntimeException("null returned from openEncryptedStreamElement");
1040 if ( !bVerifyPasswordOnly
)
1042 uno::Reference
< io::XInputStream
> xInStream
= xSourceStream
->getInputStream();
1043 if ( !xInStream
.is() )
1045 throw io::IOException(); // read access denied, seems to be impossible
1047 Reference
< XNameContainer
> xLib( pLib
);
1048 Any aAny
= importLibraryElement( xLib
,
1052 if( pLib
->hasByName( aElementName
) )
1054 if( aAny
.hasValue() )
1056 pLib
->maNameContainer
->replaceByName( aElementName
, aAny
);
1061 pLib
->maNameContainer
->insertByName( aElementName
, aAny
);
1065 catch (const uno::Exception
& )
1073 catch(const Exception
& )
1084 void SfxScriptLibraryContainer::onNewRootStorage()
1088 sal_Bool SAL_CALL
SfxScriptLibraryContainer:: HasExecutableCode( const OUString
& Library
)
1090 BasicManager
* pBasicMgr
= getBasicManager();
1091 OSL_ENSURE( pBasicMgr
, "we need a basicmanager, really we do" );
1094 return pBasicMgr
->HasExeCode( Library
); // need to change this to take name
1096 // default to it has code if we can't decide
1102 OUString SAL_CALL
SfxScriptLibraryContainer::getImplementationName( )
1104 return "com.sun.star.comp.sfx2.ScriptLibraryContainer";
1107 Sequence
< OUString
> SAL_CALL
SfxScriptLibraryContainer::getSupportedServiceNames( )
1109 return {"com.sun.star.script.DocumentScriptLibraryContainer",
1110 "com.sun.star.script.ScriptLibraryContainer"}; // for compatibility
1113 // Implementation class SfxScriptLibrary
1116 SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper
& _rModifiable
,
1117 const Reference
< XSimpleFileAccess3
>& xSFI
)
1118 : SfxLibrary( _rModifiable
, cppu::UnoType
<OUString
>::get(), xSFI
)
1119 , mbLoadedSource( false )
1120 , mbLoadedBinary( false )
1124 SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper
& _rModifiable
,
1125 const Reference
< XSimpleFileAccess3
>& xSFI
,
1126 const OUString
& aLibInfoFileURL
,
1127 const OUString
& aStorageURL
,
1129 : SfxLibrary( _rModifiable
, cppu::UnoType
<OUString
>::get(), xSFI
,
1130 aLibInfoFileURL
, aStorageURL
, ReadOnly
)
1131 , mbLoadedSource( false )
1132 , mbLoadedBinary( false )
1136 bool SfxScriptLibrary::isLoadedStorable()
1138 // note: mbLoadedSource can only be true for password-protected lib!
1139 return SfxLibrary::isLoadedStorable() && (!mbPasswordProtected
|| mbLoadedSource
);
1142 // Provide modify state including resources
1143 bool SfxScriptLibrary::isModified()
1145 return implIsModified(); // No resources
1148 void SfxScriptLibrary::storeResources()
1153 void SfxScriptLibrary::storeResourcesToURL( const OUString
&,
1154 const Reference
< task::XInteractionHandler
>& )
1157 void SfxScriptLibrary::storeResourcesAsURL
1158 ( const OUString
&, const OUString
& )
1161 void SfxScriptLibrary::storeResourcesToStorage( const css::uno::Reference
1162 < css::embed::XStorage
>& )
1167 bool SfxScriptLibrary::containsValidModule(const Any
& rElement
)
1169 OUString sModuleText
;
1170 rElement
>>= sModuleText
;
1171 return ( !sModuleText
.isEmpty() );
1174 bool SfxScriptLibrary::isLibraryElementValid(const css::uno::Any
& rElement
) const
1176 return SfxScriptLibrary::containsValidModule(rElement
);
1179 IMPLEMENT_FORWARD_XINTERFACE2( SfxScriptLibrary
, SfxLibrary
, SfxScriptLibrary_BASE
);
1180 IMPLEMENT_FORWARD_XTYPEPROVIDER2( SfxScriptLibrary
, SfxLibrary
, SfxScriptLibrary_BASE
);
1182 script::ModuleInfo SAL_CALL
SfxScriptLibrary::getModuleInfo( const OUString
& ModuleName
)
1184 if ( !hasModuleInfo( ModuleName
) )
1186 throw NoSuchElementException();
1188 return mModuleInfo
[ ModuleName
];
1191 sal_Bool SAL_CALL
SfxScriptLibrary::hasModuleInfo( const OUString
& ModuleName
)
1194 ModuleInfoMap::iterator it
= mModuleInfo
.find( ModuleName
);
1196 if ( it
!= mModuleInfo
.end() )
1203 void SAL_CALL
SfxScriptLibrary::insertModuleInfo( const OUString
& ModuleName
, const script::ModuleInfo
& ModuleInfo
)
1205 if ( hasModuleInfo( ModuleName
) )
1207 throw ElementExistException();
1209 mModuleInfo
[ ModuleName
] = ModuleInfo
;
1212 void SAL_CALL
SfxScriptLibrary::removeModuleInfo( const OUString
& ModuleName
)
1214 // #FIXME add NoSuchElementException to the spec
1215 if ( mModuleInfo
.erase( ModuleName
) == 0 )
1216 throw NoSuchElementException();
1219 } // namespace basic
1222 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
1223 com_sun_star_comp_sfx2_ScriptLibraryContainer_get_implementation(css::uno::XComponentContext
*,
1224 css::uno::Sequence
<css::uno::Any
> const &)
1226 return cppu::acquire(new basic::SfxScriptLibraryContainer());
1230 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */