Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / uno / scriptcont.cxx
blob18f2dfd3baa0e7619ce372d1f831824bcd7d3b4e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
49 #include <memory>
51 namespace basic
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;
63 using namespace cppu;
64 using namespace osl;
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 )
77 try
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& ) {}
95 // Ctor for service
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 );
111 return pRet;
114 SfxLibrary* SfxScriptLibraryContainer::implCreateLibraryLink( const OUString&,
115 const OUString& aLibInfoFileURL,
116 const OUString& StorageURL,
117 bool ReadOnly )
119 SfxLibrary* pRet = new SfxScriptLibrary( maModifiable, mxSFI,
120 aLibInfoFileURL, StorageURL, ReadOnly );
121 return pRet;
124 Any SfxScriptLibraryContainer::createEmptyLibraryElement()
126 Any aRetAny;
127 aRetAny <<= OUString();
128 return aRetAny;
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)
140 // Create sax writer
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";
165 break;
166 case ModuleType::CLASS:
167 aMod.aModuleType ="class";
168 break;
169 case ModuleType::FORM:
170 aMod.aModuleType = "form";
171 break;
172 case ModuleType::DOCUMENT:
173 aMod.aModuleType = "document";
174 break;
175 case ModuleType::UNKNOWN:
176 // nothing
177 break;
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 )
190 Any aRetAny;
192 Reference< XParser > xParser = xml::sax::Parser::create( mxContext );
194 // Read from storage?
195 bool bStorage = xInStream.is();
196 Reference< XInputStream > xInput;
198 if( bStorage )
200 xInput = xInStream;
202 else
206 xInput = mxSFI->openFileRead( aFile );
208 catch(const Exception& )
209 //catch( Exception& e )
211 // TODO:
212 //throw WrappedTargetException( e );
216 if( !xInput.is() )
217 return aRetAny;
219 InputSource source;
220 source.aInputStream = xInput;
221 source.sSystemId = aFile;
223 // start parsing
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
240 // aMod.aLanguage
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 );
313 return aRetAny;
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 ));
329 // Set info
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;
344 return bRet;
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;
356 return bRet;
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();
368 // Test password
369 bool bSuccess = false;
370 if( pImplLib->mbDoc50Password )
372 bSuccess = ( Password == pImplLib->maPassword );
373 if( bSuccess )
375 pImplLib->mbPasswordVerified = true;
378 else
380 pImplLib->maPassword = Password;
381 bSuccess = implLoadPasswordLibrary( pImplLib, Name, true );
382 if( bSuccess )
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 );
397 return bSuccess;
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 )
408 return;
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
419 loadLibrary( Name );
421 bool bKillCryptedFiles = false;
422 bool bKillUncryptedFiles = false;
424 // Remove or change password?
425 if( bOldPassword )
427 if( isLibraryPasswordVerified( Name ) )
429 if( pImplLib->maPassword != OldPassword )
431 throw IllegalArgumentException();
434 else
436 if( !verifyLibraryPassword( Name, OldPassword ) )
438 throw IllegalArgumentException();
440 // Reload library to get source
441 // Should be done in verifyLibraryPassword loadLibrary( Name );
444 if( !bNewPassword )
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;
463 // Set new password?
464 if( bNewPassword )
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 );
507 else
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 );
534 // Impl methods
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!" );
554 if ( !pBasicMgr )
556 return false;
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) )
564 if ( xHandler.is() )
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 );
577 if( !pBasicLib )
579 return false;
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;
587 if( bStorage )
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 );
595 if( pMod )
597 OUString aCodeStreamName = aElementName + ".bin";
600 uno::Reference< io::XStream > xCodeStream = xStorage->openStreamElement(
601 aCodeStreamName,
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();
618 if ( !xOut.is() )
620 throw io::IOException(); // access denied because the stream is readonly
622 xOut->writeBytes( aBinSeq );
623 xOut->closeOutput();
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 << "'.");
636 continue;
639 OUString aSourceStreamName = aElementName + ".xml";
642 uno::Reference< io::XStream > xSourceStream = xStorage->openStreamElement(
643 aSourceStreamName,
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
663 // TODO
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;
676 if( rToUseSFI.is() )
678 xSFI = rToUseSFI;
680 OUString aLibDirPath;
681 if( bExport )
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 );
693 else
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 << "'.");
712 continue;
717 uno::Reference< embed::XStorage > xElementRootStorage =
718 ::comphelper::OStorageHelper::GetStorageFromURL(
719 aElementPath,
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 );
727 if( pMod )
729 uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
730 "code.bin",
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();
743 if ( xOut.is() )
745 xOut->writeBytes( aBinSeq );
746 xOut->closeOutput();
750 // Write encrypted source stream
751 OUString aSourceStreamName( "source.xml" );
753 uno::Reference< io::XStream > xSourceStream;
756 xSourceStream = xElementRootStorage->openStreamElement(
757 aSourceStreamName,
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(
767 aSourceStreamName,
768 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE,
769 pLib->maPassword );
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 );
782 xTransact->commit();
784 catch(const uno::Exception& )
786 // TODO: handle error
791 catch(const Exception& )
795 return true;
798 bool SfxScriptLibraryContainer::implLoadPasswordLibrary
799 ( SfxLibrary* pLib, const OUString& Name, bool bVerifyPasswordOnly )
801 bool bRet = true;
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) )
813 return false;
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
827 if( !pBasicLib )
829 return false;
831 bLoadBinary = true;
832 pScriptLib->mbLoadedBinary = true;
835 bool bLoadSource = false;
836 if( !pScriptLib->mbLoadedSource && pLib->mbPasswordVerified && !bVerifyPasswordOnly )
838 bLoadSource = true;
839 pScriptLib->mbLoadedSource = true;
842 Sequence< OUString > aElementNames = pLib->getElementNames();
843 sal_Int32 nNameCount = aElementNames.getLength();
844 const OUString* pNames = aElementNames.getConstArray();
846 if( bStorage )
848 uno::Reference< embed::XStorage > xLibrariesStor;
849 uno::Reference< embed::XStorage > xLibraryStor;
850 try {
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" );
865 return false;
868 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
870 OUString aElementName = pNames[ i ];
872 // Load binary
873 if( bLoadBinary )
875 SbModule* pMod = pBasicLib->FindModule( aElementName );
876 if( !pMod )
878 pMod = pBasicLib->MakeModule( aElementName, OUString() );
879 pBasicLib->SetModified( false );
882 OUString aCodeStreamName= aElementName + ".bin";
885 uno::Reference< io::XStream > xCodeStream = xLibraryStor->openStreamElement(
886 aCodeStreamName,
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
912 // Load source
913 if( bLoadSource || bVerifyPasswordOnly )
915 // Access encrypted source stream
916 OUString aSourceStreamName = aElementName + ".xml";
919 uno::Reference< io::XStream > xSourceStream = xLibraryStor->openEncryptedStreamElement(
920 aSourceStreamName,
921 embed::ElementModes::READ,
922 pLib->maPassword );
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,
938 xInStream );
939 if( pLib->hasByName( aElementName ) )
941 if( aAny.hasValue() )
943 pLib->maNameContainer->replaceByName( aElementName, aAny );
946 else
948 pLib->maNameContainer->insertByName( aElementName, aAny );
952 catch(const uno::Exception& )
954 bRet = false;
959 else
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(
979 aElementPath,
980 embed::ElementModes::READ );
981 } catch(const uno::Exception& )
983 // TODO: error handling
986 if ( xElementRootStorage.is() )
988 // Load binary
989 if( bLoadBinary )
991 SbModule* pMod = pBasicLib->FindModule( aElementName );
992 if( !pMod )
994 pMod = pBasicLib->MakeModule( aElementName, OUString() );
995 pBasicLib->SetModified( false );
1000 uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
1001 "code.bin",
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"
1010 " for code.bin: 0x"
1011 + OUString::number(nError, 16)),
1012 uno::Reference< uno::XInterface >(),
1013 nError);
1016 /*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
1017 // TODO: Check return value
1019 catch(const uno::Exception& )
1021 // TODO: error handling
1025 // Load source
1026 if( bLoadSource || bVerifyPasswordOnly )
1028 // Access encrypted source stream
1029 OUString aSourceStreamName( "source.xml" );
1032 uno::Reference< io::XStream > xSourceStream = xElementRootStorage->openEncryptedStreamElement(
1033 aSourceStreamName,
1034 embed::ElementModes::READ,
1035 pLib->maPassword );
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,
1049 aElementName,
1050 aSourceStreamName,
1051 xInStream );
1052 if( pLib->hasByName( aElementName ) )
1054 if( aAny.hasValue() )
1056 pLib->maNameContainer->replaceByName( aElementName, aAny );
1059 else
1061 pLib->maNameContainer->insertByName( aElementName, aAny );
1065 catch (const uno::Exception& )
1067 bRet = false;
1073 catch(const Exception& )
1075 // TODO
1076 //throw e;
1080 return bRet;
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" );
1092 if ( pBasicMgr )
1094 return pBasicMgr->HasExeCode( Library ); // need to change this to take name
1096 // default to it has code if we can't decide
1097 return true;
1101 // Service
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
1115 // Ctor
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,
1128 bool ReadOnly )
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()
1150 // No resources
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 >& )
1164 // No resources
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 )
1193 bool bRes = false;
1194 ModuleInfoMap::iterator it = mModuleInfo.find( ModuleName );
1196 if ( it != mModuleInfo.end() )
1198 bRes = true;
1200 return bRes;
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: */