Bump version to 5.0-43
[LibreOffice.git] / basic / source / uno / scriptcont.cxx
blob8805c38b982ea8471d6357df18493ae25d0169d2
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 <filefmt.hxx>
22 #include <com/sun/star/container/XNameContainer.hpp>
23 #include <com/sun/star/xml/sax/Parser.hpp>
24 #include <com/sun/star/xml/sax/InputSource.hpp>
25 #include <com/sun/star/xml/sax/Writer.hpp>
26 #include <com/sun/star/io/XOutputStream.hpp>
27 #include <com/sun/star/io/XInputStream.hpp>
28 #include <com/sun/star/io/XActiveDataSource.hpp>
29 #include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
30 #include <com/sun/star/embed/ElementModes.hpp>
31 #include <com/sun/star/embed/XEncryptionProtectedSource.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/embed/XTransactedObject.hpp>
34 #include <com/sun/star/task/ErrorCodeIOException.hpp>
35 #include <com/sun/star/script/ModuleType.hpp>
36 #include <comphelper/processfactory.hxx>
37 #include <comphelper/storagehelper.hxx>
38 #include <unotools/streamwrap.hxx>
39 #include <unotools/ucbstreamhelper.hxx>
40 #include <osl/mutex.hxx>
41 #include <osl/thread.h>
42 #include <rtl/digest.h>
43 #include <rtl/strbuf.hxx>
45 // For password functionality
46 #include <tools/urlobj.hxx>
49 #include <unotools/pathoptions.hxx>
50 #include <svtools/sfxecode.hxx>
51 #include <svtools/ehdl.hxx>
52 #include <basic/basmgr.hxx>
53 #include <basic/sbmod.hxx>
54 #include <basic/basicmanagerrepository.hxx>
55 #include <basic/modsizeexceeded.hxx>
56 #include <xmlscript/xmlmod_imexp.hxx>
57 #include <cppuhelper/factory.hxx>
58 #include <com/sun/star/util/VetoException.hpp>
59 #include <com/sun/star/script/XLibraryQueryExecutable.hpp>
60 #include <cppuhelper/implbase1.hxx>
61 #include <boost/scoped_ptr.hpp>
63 namespace basic
66 using namespace com::sun::star::document;
67 using namespace com::sun::star::container;
68 using namespace com::sun::star::io;
69 using namespace com::sun::star::uno;
70 using namespace com::sun::star::ucb;
71 using namespace com::sun::star::lang;
72 using namespace com::sun::star::script;
73 using namespace com::sun::star::xml::sax;
74 using namespace com::sun::star;
75 using namespace cppu;
76 using namespace osl;
79 // Implementation class SfxScriptLibraryContainer
81 const sal_Char* SAL_CALL SfxScriptLibraryContainer::getInfoFileName() const { return "script"; }
82 const sal_Char* SAL_CALL SfxScriptLibraryContainer::getOldInfoFileName() const { return "script"; }
83 const sal_Char* SAL_CALL SfxScriptLibraryContainer::getLibElementFileExtension() const { return "xba"; }
84 const sal_Char* SAL_CALL SfxScriptLibraryContainer::getLibrariesDir() const { return "Basic"; }
86 // OldBasicPassword interface
87 void SfxScriptLibraryContainer::setLibraryPassword( const OUString& rLibraryName, const OUString& rPassword )
89 try
91 SfxLibrary* pImplLib = getImplLib( rLibraryName );
92 if( !rPassword.isEmpty() )
94 pImplLib->mbDoc50Password = true;
95 pImplLib->mbPasswordProtected = true;
96 pImplLib->maPassword = rPassword;
97 SfxScriptLibrary *const pSL(dynamic_cast<SfxScriptLibrary *>(pImplLib));
98 if (pSL && pSL->mbLoaded)
100 pSL->mbLoadedSource = true; // must store source code now!
104 catch(const NoSuchElementException& ) {}
107 OUString SfxScriptLibraryContainer::getLibraryPassword( const OUString& rLibraryName )
109 SfxLibrary* pImplLib = getImplLib( rLibraryName );
110 OUString aPassword;
111 if( pImplLib->mbPasswordVerified )
113 aPassword = pImplLib->maPassword;
115 return aPassword;
118 void SfxScriptLibraryContainer::clearLibraryPassword( const OUString& rLibraryName )
122 SfxLibrary* pImplLib = getImplLib( rLibraryName );
123 pImplLib->mbDoc50Password = false;
124 pImplLib->mbPasswordProtected = false;
125 pImplLib->maPassword.clear();
127 catch(const NoSuchElementException& ) {}
130 bool SfxScriptLibraryContainer::hasLibraryPassword( const OUString& rLibraryName )
132 SfxLibrary* pImplLib = getImplLib( rLibraryName );
133 return pImplLib->mbPasswordProtected;
136 // Ctor for service
137 SfxScriptLibraryContainer::SfxScriptLibraryContainer()
138 :maScriptLanguage( "StarBasic" )
140 // all initialisation has to be done
141 // by calling XInitialization::initialize
144 SfxScriptLibraryContainer::SfxScriptLibraryContainer( const uno::Reference< embed::XStorage >& xStorage )
145 :maScriptLanguage( "StarBasic" )
147 init( OUString(), xStorage );
150 // Methods to get library instances of the correct type
151 SfxLibrary* SfxScriptLibraryContainer::implCreateLibrary( const OUString& aName )
153 (void)aName; // Only needed for SfxDialogLibrary
154 SfxLibrary* pRet = new SfxScriptLibrary( maModifiable, mxContext, mxSFI );
155 return pRet;
158 SfxLibrary* SfxScriptLibraryContainer::implCreateLibraryLink( const OUString& aName,
159 const OUString& aLibInfoFileURL,
160 const OUString& StorageURL,
161 bool ReadOnly )
163 (void)aName; // Only needed for SfxDialogLibrary
164 SfxLibrary* pRet = new SfxScriptLibrary( maModifiable, mxContext, mxSFI,
165 aLibInfoFileURL, StorageURL, ReadOnly );
166 return pRet;
169 Any SAL_CALL SfxScriptLibraryContainer::createEmptyLibraryElement()
171 OUString aMod;
172 Any aRetAny;
173 aRetAny <<= aMod;
174 return aRetAny;
177 bool SAL_CALL SfxScriptLibraryContainer::isLibraryElementValid(const Any& rElement) const
179 return SfxScriptLibrary::containsValidModule(rElement);
182 void SAL_CALL SfxScriptLibraryContainer::writeLibraryElement( const Reference < XNameContainer >& xLib,
183 const OUString& aElementName,
184 const Reference< XOutputStream >& xOutput)
185 throw(Exception)
187 // Create sax writer
188 Reference< XWriter > xWriter = xml::sax::Writer::create(mxContext);
190 Reference< XTruncate > xTruncate( xOutput, UNO_QUERY );
191 OSL_ENSURE( xTruncate.is(), "Currently only the streams that can be truncated are expected!" );
192 if ( xTruncate.is() )
194 xTruncate->truncate();
196 xWriter->setOutputStream( xOutput );
198 xmlscript::ModuleDescriptor aMod;
199 aMod.aName = aElementName;
200 aMod.aLanguage = maScriptLanguage;
201 Any aElement = xLib->getByName( aElementName );
202 aElement >>= aMod.aCode;
204 Reference< script::vba::XVBAModuleInfo > xModInfo( xLib, UNO_QUERY );
205 if( xModInfo.is() && xModInfo->hasModuleInfo( aElementName ) )
207 script::ModuleInfo aModInfo = xModInfo->getModuleInfo( aElementName );
208 switch( aModInfo.ModuleType )
210 case ModuleType::NORMAL:
211 aMod.aModuleType = "normal";
212 break;
213 case ModuleType::CLASS:
214 aMod.aModuleType ="class";
215 break;
216 case ModuleType::FORM:
217 aMod.aModuleType = "form";
218 break;
219 case ModuleType::DOCUMENT:
220 aMod.aModuleType = "document";
221 break;
222 case ModuleType::UNKNOWN:
223 // nothing
224 break;
228 xmlscript::exportScriptModule( xWriter, aMod );
232 Any SAL_CALL SfxScriptLibraryContainer::importLibraryElement
233 ( const Reference < XNameContainer >& xLib,
234 const OUString& aElementName, const OUString& aFile,
235 const uno::Reference< io::XInputStream >& xInStream )
237 Any aRetAny;
239 Reference< XParser > xParser = xml::sax::Parser::create( mxContext );
241 // Read from storage?
242 bool bStorage = xInStream.is();
243 Reference< XInputStream > xInput;
245 if( bStorage )
247 xInput = xInStream;
249 else
253 xInput = mxSFI->openFileRead( aFile );
255 catch(const Exception& )
256 //catch( Exception& e )
258 // TODO:
259 //throw WrappedTargetException( e );
263 if( !xInput.is() )
264 return aRetAny;
266 InputSource source;
267 source.aInputStream = xInput;
268 source.sSystemId = aFile;
270 // start parsing
271 xmlscript::ModuleDescriptor aMod;
275 xParser->setDocumentHandler( ::xmlscript::importScriptModule( aMod ) );
276 xParser->parseStream( source );
278 catch(const Exception& )
280 SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aFile );
281 ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
284 aRetAny <<= aMod.aCode;
286 // TODO: Check language
287 // aMod.aLanguage
288 // aMod.aName ignored
289 if( !aMod.aModuleType.isEmpty() )
291 /* If in VBA compatibility mode, force creation of the VBA Globals
292 object. Each application will create an instance of its own
293 implementation and store it in its Basic manager. Implementations
294 will do all necessary additional initialization, such as
295 registering the global "This***Doc" UNO constant, starting the
296 document events processor etc.
298 if( getVBACompatibilityMode() ) try
300 Reference< frame::XModel > xModel( mxOwnerDocument ); // weak-ref -> ref
301 Reference< XMultiServiceFactory > xFactory( xModel, UNO_QUERY_THROW );
302 xFactory->createInstance("ooo.vba.VBAGlobals");
304 catch(const Exception& )
308 script::ModuleInfo aModInfo;
309 aModInfo.ModuleType = ModuleType::UNKNOWN;
310 if( aMod.aModuleType == "normal" )
312 aModInfo.ModuleType = ModuleType::NORMAL;
314 else if( aMod.aModuleType == "class" )
316 aModInfo.ModuleType = ModuleType::CLASS;
318 else if( aMod.aModuleType == "form" )
320 aModInfo.ModuleType = ModuleType::FORM;
321 aModInfo.ModuleObject = mxOwnerDocument;
323 else if( aMod.aModuleType == "document" )
325 aModInfo.ModuleType = ModuleType::DOCUMENT;
327 // #163691# use the same codename access instance for all document modules
328 if( !mxCodeNameAccess.is() ) try
330 Reference<frame::XModel > xModel( mxOwnerDocument );
331 Reference< XMultiServiceFactory> xSF( xModel, UNO_QUERY_THROW );
332 mxCodeNameAccess.set( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), UNO_QUERY );
334 catch(const Exception& ) {}
336 if( mxCodeNameAccess.is() )
340 aModInfo.ModuleObject.set( mxCodeNameAccess->getByName( aElementName), uno::UNO_QUERY );
342 catch(const uno::Exception&)
344 OSL_TRACE("Failed to get documument object for %s", OUStringToOString( aElementName, RTL_TEXTENCODING_UTF8 ).getStr() );
349 Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY );
350 if( xVBAModuleInfo.is() )
352 if( xVBAModuleInfo->hasModuleInfo( aElementName ) )
354 xVBAModuleInfo->removeModuleInfo( aElementName );
356 xVBAModuleInfo->insertModuleInfo( aElementName, aModInfo );
360 return aRetAny;
363 SfxLibraryContainer* SfxScriptLibraryContainer::createInstanceImpl()
365 return new SfxScriptLibraryContainer();
368 void SAL_CALL SfxScriptLibraryContainer::importFromOldStorage( const OUString& aFile )
370 // TODO: move loading from old storage to binary filters?
371 tools::SvRef<SotStorage> xStorage = new SotStorage( false, aFile );
372 if( xStorage.Is() && xStorage->GetError() == ERRCODE_NONE )
374 BasicManager* pBasicManager = new BasicManager( *(SotStorage*)xStorage, aFile );
376 // Set info
377 LibraryContainerInfo aInfo( this, NULL, static_cast< OldBasicPassword* >( this ) );
378 pBasicManager->SetLibraryContainerInfo( aInfo );
380 // Now the libraries should be copied to this SfxScriptLibraryContainer
381 BasicManager::LegacyDeleteBasicManager( pBasicManager );
386 // Storing with password encryption
388 // Methods XLibraryContainerPassword
389 sal_Bool SAL_CALL SfxScriptLibraryContainer::isLibraryPasswordProtected( const OUString& Name )
390 throw (NoSuchElementException, RuntimeException, std::exception)
392 LibraryContainerMethodGuard aGuard( *this );
393 SfxLibrary* pImplLib = getImplLib( Name );
394 bool bRet = pImplLib->mbPasswordProtected;
395 return bRet;
398 sal_Bool SAL_CALL SfxScriptLibraryContainer::isLibraryPasswordVerified( const OUString& Name )
399 throw (IllegalArgumentException, NoSuchElementException, RuntimeException, std::exception)
401 LibraryContainerMethodGuard aGuard( *this );
402 SfxLibrary* pImplLib = getImplLib( Name );
403 if( !pImplLib->mbPasswordProtected )
405 throw IllegalArgumentException();
407 bool bRet = pImplLib->mbPasswordVerified;
408 return bRet;
411 sal_Bool SAL_CALL SfxScriptLibraryContainer::verifyLibraryPassword
412 ( const OUString& Name, const OUString& Password )
413 throw (IllegalArgumentException, NoSuchElementException, RuntimeException, std::exception)
415 LibraryContainerMethodGuard aGuard( *this );
416 SfxLibrary* pImplLib = getImplLib( Name );
417 if( !pImplLib->mbPasswordProtected || pImplLib->mbPasswordVerified )
419 throw IllegalArgumentException();
421 // Test password
422 bool bSuccess = false;
423 if( pImplLib->mbDoc50Password )
425 bSuccess = ( Password == pImplLib->maPassword );
426 if( bSuccess )
428 pImplLib->mbPasswordVerified = true;
431 else
433 pImplLib->maPassword = Password;
434 bSuccess = implLoadPasswordLibrary( pImplLib, Name, true );
435 if( bSuccess )
437 // The library gets modified by verifying the password, because other-
438 // wise for saving the storage would be copied and that doesn't work
439 // with mtg's storages when the password is verified
440 pImplLib->implSetModified( true );
441 pImplLib->mbPasswordVerified = true;
443 // Reload library to get source
444 if( pImplLib->mbLoaded )
446 implLoadPasswordLibrary( pImplLib, Name );
450 return bSuccess;
453 void SAL_CALL SfxScriptLibraryContainer::changeLibraryPassword( const OUString& Name,
454 const OUString& OldPassword,
455 const OUString& NewPassword )
456 throw (IllegalArgumentException, NoSuchElementException, RuntimeException, std::exception)
458 LibraryContainerMethodGuard aGuard( *this );
459 SfxLibrary* pImplLib = getImplLib( Name );
460 if( OldPassword == NewPassword )
462 return;
464 bool bOldPassword = !OldPassword.isEmpty();
465 bool bNewPassword = !NewPassword.isEmpty();
466 bool bStorage = mxStorage.is() && !pImplLib->mbLink;
468 if( pImplLib->mbReadOnly || (bOldPassword && !pImplLib->mbPasswordProtected) )
470 throw IllegalArgumentException();
472 // Library must be loaded
473 loadLibrary( Name );
475 bool bKillCryptedFiles = false;
476 bool bKillUncryptedFiles = false;
478 // Remove or change password?
479 if( bOldPassword )
481 if( isLibraryPasswordVerified( Name ) )
483 if( pImplLib->maPassword != OldPassword )
485 throw IllegalArgumentException();
488 else
490 if( !verifyLibraryPassword( Name, OldPassword ) )
492 throw IllegalArgumentException();
494 // Reload library to get source
495 // Should be done in verifyLibraryPassword loadLibrary( Name );
498 if( !bNewPassword )
500 pImplLib->mbPasswordProtected = false;
501 pImplLib->mbPasswordVerified = false;
502 pImplLib->maPassword.clear();
504 maModifiable.setModified( true );
505 pImplLib->implSetModified( true );
507 if( !bStorage && !pImplLib->mbDoc50Password )
509 // Store application basic uncrypted
510 uno::Reference< embed::XStorage > xStorage;
511 storeLibraries_Impl( xStorage, false );
512 bKillCryptedFiles = true;
517 // Set new password?
518 if( bNewPassword )
520 pImplLib->mbPasswordProtected = true;
521 pImplLib->mbPasswordVerified = true;
522 pImplLib->maPassword = NewPassword;
523 SfxScriptLibrary *const pSL(dynamic_cast<SfxScriptLibrary *>(pImplLib));
524 if (pSL && pSL->mbLoaded)
526 pSL->mbLoadedSource = true; // must store source code now!
529 maModifiable.setModified( true );
530 pImplLib->implSetModified( true );
532 if( !bStorage && !pImplLib->mbDoc50Password )
534 // Store application basic crypted
535 uno::Reference< embed::XStorage > xStorage;
536 storeLibraries_Impl( xStorage, false );
537 bKillUncryptedFiles = true;
541 if( bKillCryptedFiles || bKillUncryptedFiles )
543 Sequence< OUString > aElementNames = pImplLib->getElementNames();
544 sal_Int32 nNameCount = aElementNames.getLength();
545 const OUString* pNames = aElementNames.getConstArray();
546 OUString aLibDirPath = createAppLibraryFolder( pImplLib, Name );
549 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
551 OUString aElementName = pNames[ i ];
553 INetURLObject aElementInetObj( aLibDirPath );
554 aElementInetObj.insertName( aElementName, false,
555 INetURLObject::LAST_SEGMENT, true,
556 INetURLObject::ENCODE_ALL );
557 if( bKillUncryptedFiles )
559 aElementInetObj.setExtension( maLibElementFileExtension );
561 else
563 aElementInetObj.setExtension( OUString( "pba" ) );
565 OUString aElementPath( aElementInetObj.GetMainURL( INetURLObject::NO_DECODE ) );
567 if( mxSFI->exists( aElementPath ) )
569 mxSFI->kill( aElementPath );
573 catch(const Exception& ) {}
578 void setStreamKey( uno::Reference< io::XStream > xStream, const OUString& aPass )
580 uno::Reference< embed::XEncryptionProtectedSource > xEncrStream( xStream, uno::UNO_QUERY );
581 if ( xEncrStream.is() )
583 xEncrStream->setEncryptionPassword( aPass );
588 // Impl methods
589 bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary* pLib,
590 const OUString& aName,
591 const uno::Reference< embed::XStorage >& xStorage,
592 const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xHandler )
594 OUString aDummyLocation;
595 Reference< XSimpleFileAccess3 > xDummySFA;
596 return implStorePasswordLibrary( pLib, aName, xStorage, aDummyLocation, xDummySFA, xHandler );
599 bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary* pLib, const OUString& aName,
600 const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage,
601 const OUString& aTargetURL,
602 const Reference< XSimpleFileAccess3 >& rToUseSFI,
603 const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xHandler )
605 bool bExport = !aTargetURL.isEmpty();
607 BasicManager* pBasicMgr = getBasicManager();
608 OSL_ENSURE( pBasicMgr, "SfxScriptLibraryContainer::implStorePasswordLibrary: cannot do this without a BasicManager!" );
609 if ( !pBasicMgr )
611 return false;
613 // Only need to handle the export case here,
614 // save/saveas etc are handled in sfxbasemodel::storeSelf &
615 // sfxbasemodel::impl_store
616 uno::Sequence<OUString> aNames;
617 if ( bExport && pBasicMgr->LegacyPsswdBinaryLimitExceeded(aNames) )
619 if ( xHandler.is() )
621 ModuleSizeExceeded* pReq = new ModuleSizeExceeded( aNames );
622 uno::Reference< task::XInteractionRequest > xReq( pReq );
623 xHandler->handle( xReq );
624 if ( pReq->isAbort() )
626 throw util::VetoException();
631 StarBASIC* pBasicLib = pBasicMgr->GetLib( aName );
632 if( !pBasicLib )
634 return false;
636 Sequence< OUString > aElementNames = pLib->getElementNames();
637 sal_Int32 nNameCount = aElementNames.getLength();
638 const OUString* pNames = aElementNames.getConstArray();
640 bool bLink = pLib->mbLink;
641 bool bStorage = xStorage.is() && !bLink;
642 if( bStorage )
644 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
646 OUString aElementName = pNames[ i ];
648 // Write binary image stream
649 SbModule* pMod = pBasicLib->FindModule( aElementName );
650 if( pMod )
652 OUString aCodeStreamName = aElementName;
653 aCodeStreamName += ".bin";
657 uno::Reference< io::XStream > xCodeStream = xStorage->openStreamElement(
658 aCodeStreamName,
659 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
661 if ( !xCodeStream.is() )
663 throw uno::RuntimeException();
665 SvMemoryStream aMemStream;
666 /*sal_Bool bStore = */pMod->StoreBinaryData( aMemStream, B_CURVERSION );
668 sal_Size nSize = aMemStream.Tell();
669 Sequence< sal_Int8 > aBinSeq( nSize );
670 sal_Int8* pData = aBinSeq.getArray();
671 memcpy( pData, aMemStream.GetData(), nSize );
673 Reference< XOutputStream > xOut = xCodeStream->getOutputStream();
674 if ( !xOut.is() )
676 throw io::IOException(); // access denied because the stream is readonly
678 xOut->writeBytes( aBinSeq );
679 xOut->closeOutput();
681 catch(const uno::Exception& )
683 // TODO: handle error
687 if( pLib->mbPasswordVerified || pLib->mbDoc50Password )
689 if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
691 #if OSL_DEBUG_LEVEL > 0
692 OString aMessage = "invalid library element '" +
693 OUStringToOString( aElementName, osl_getThreadTextEncoding() ) +
694 "'.";
695 OSL_FAIL( aMessage.getStr());
696 #endif
697 continue;
700 OUString aSourceStreamName = aElementName;
701 aSourceStreamName += ".xml";
705 uno::Reference< io::XStream > xSourceStream = xStorage->openStreamElement(
706 aSourceStreamName,
707 embed::ElementModes::READWRITE );
708 uno::Reference< beans::XPropertySet > xProps( xSourceStream, uno::UNO_QUERY );
709 if ( !xProps.is() )
711 throw uno::RuntimeException();
713 OUString aMime( "text/xml" );
714 xProps->setPropertyValue("MediaType", uno::makeAny( aMime ) );
716 // Set encryption key
717 setStreamKey( xSourceStream, pLib->maPassword );
719 Reference< XOutputStream > xOutput = xSourceStream->getOutputStream();
720 Reference< XNameContainer > xLib( pLib );
721 writeLibraryElement( xLib, aElementName, xOutput );
723 catch(const uno::Exception& )
725 OSL_FAIL( "Problem on storing of password library!\n" );
726 // TODO: error handling
729 else // !mbPasswordVerified
731 // TODO
732 // What to do if not verified?! In any case it's already loaded here
737 // Application libraries have only to be saved if the password
738 // is verified because otherwise they can't be modified
739 else if( pLib->mbPasswordVerified || bExport )
743 Reference< XSimpleFileAccess3 > xSFI = mxSFI;
744 if( rToUseSFI.is() )
746 xSFI = rToUseSFI;
748 OUString aLibDirPath;
749 if( bExport )
751 INetURLObject aInetObj( aTargetURL );
752 aInetObj.insertName( aName, true, INetURLObject::LAST_SEGMENT, true,
753 INetURLObject::ENCODE_ALL );
754 aLibDirPath = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
756 if( !xSFI->isFolder( aLibDirPath ) )
758 xSFI->createFolder( aLibDirPath );
761 else
763 aLibDirPath = createAppLibraryFolder( pLib, aName );
766 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
768 OUString aElementName = pNames[ i ];
770 INetURLObject aElementInetObj( aLibDirPath );
771 aElementInetObj.insertName( aElementName, false,
772 INetURLObject::LAST_SEGMENT, true,
773 INetURLObject::ENCODE_ALL );
774 aElementInetObj.setExtension( OUString( "pba" ) );
775 OUString aElementPath = aElementInetObj.GetMainURL( INetURLObject::NO_DECODE );
777 if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
779 #if OSL_DEBUG_LEVEL > 0
780 OString aMessage = "invalid library element '" +
781 OUStringToOString( aElementName, osl_getThreadTextEncoding() ) +
782 "'.";
783 OSL_FAIL( aMessage.getStr());
784 #endif
785 continue;
790 uno::Reference< embed::XStorage > xElementRootStorage =
791 ::comphelper::OStorageHelper::GetStorageFromURL(
792 aElementPath,
793 embed::ElementModes::READWRITE );
794 if ( !xElementRootStorage.is() )
796 throw uno::RuntimeException();
798 // Write binary image stream
799 SbModule* pMod = pBasicLib->FindModule( aElementName );
800 if( pMod )
802 OUString aCodeStreamName( "code.bin" );
804 uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
805 aCodeStreamName,
806 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
808 SvMemoryStream aMemStream;
809 /*sal_Bool bStore = */pMod->StoreBinaryData( aMemStream, B_CURVERSION );
811 sal_Size nSize = aMemStream.Tell();
812 Sequence< sal_Int8 > aBinSeq( nSize );
813 sal_Int8* pData = aBinSeq.getArray();
814 memcpy( pData, aMemStream.GetData(), nSize );
816 Reference< XOutputStream > xOut = xCodeStream->getOutputStream();
817 if ( xOut.is() )
819 xOut->writeBytes( aBinSeq );
820 xOut->closeOutput();
824 // Write encrypted source stream
825 OUString aSourceStreamName( "source.xml" );
827 uno::Reference< io::XStream > xSourceStream;
830 xSourceStream = xElementRootStorage->openStreamElement(
831 aSourceStreamName,
832 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
834 // #87671 Allow encryption
835 uno::Reference< embed::XEncryptionProtectedSource > xEncr( xSourceStream, uno::UNO_QUERY );
836 OSL_ENSURE( xEncr.is(),
837 "StorageStream opened for writing must implement XEncryptionProtectedSource!\n" );
838 if ( !xEncr.is() )
840 throw uno::RuntimeException();
842 xEncr->setEncryptionPassword( pLib->maPassword );
844 catch(const ::com::sun::star::packages::WrongPasswordException& )
846 xSourceStream = xElementRootStorage->openEncryptedStreamElement(
847 aSourceStreamName,
848 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE,
849 pLib->maPassword );
852 uno::Reference< beans::XPropertySet > xProps( xSourceStream, uno::UNO_QUERY );
853 if ( !xProps.is() )
855 throw uno::RuntimeException();
857 OUString aMime( "text/xml" );
858 xProps->setPropertyValue("MediaType", uno::makeAny( aMime ) );
860 Reference< XOutputStream > xOut = xSourceStream->getOutputStream();
861 Reference< XNameContainer > xLib( pLib );
862 writeLibraryElement( xLib, aElementName, xOut );
863 // i50568: sax writer already closes stream
864 // xOut->closeOutput();
866 uno::Reference< embed::XTransactedObject > xTransact( xElementRootStorage, uno::UNO_QUERY );
867 OSL_ENSURE( xTransact.is(), "The storage must implement XTransactedObject!\n" );
868 if ( !xTransact.is() )
870 throw uno::RuntimeException();
873 xTransact->commit();
875 catch(const uno::Exception& )
877 // TODO: handle error
882 catch(const Exception& )
886 return true;
889 bool SfxScriptLibraryContainer::implLoadPasswordLibrary
890 ( SfxLibrary* pLib, const OUString& Name, bool bVerifyPasswordOnly )
891 throw(WrappedTargetException, RuntimeException)
893 bool bRet = true;
895 bool bLink = pLib->mbLink;
896 bool bStorage = mxStorage.is() && !bLink;
898 // Already loaded? Then only verifiedPassword can change something
899 SfxScriptLibrary* pScriptLib = static_cast< SfxScriptLibrary* >( pLib );
900 if( pScriptLib->mbLoaded )
902 if( pScriptLib->mbLoadedBinary && !bVerifyPasswordOnly &&
903 (pScriptLib->mbLoadedSource || !pLib->mbPasswordVerified) )
905 return false;
909 StarBASIC* pBasicLib = NULL;
910 bool bLoadBinary = false;
911 if( !pScriptLib->mbLoadedBinary && !bVerifyPasswordOnly && !pLib->mbPasswordVerified )
913 BasicManager* pBasicMgr = getBasicManager();
914 OSL_ENSURE( pBasicMgr, "SfxScriptLibraryContainer::implLoadPasswordLibrary: cannot do this without a BasicManager!" );
915 bool bLoaded = pScriptLib->mbLoaded;
916 pScriptLib->mbLoaded = true; // Necessary to get lib
917 pBasicLib = pBasicMgr ? pBasicMgr->GetLib( Name ) : NULL;
918 pScriptLib->mbLoaded = bLoaded; // Restore flag
919 if( !pBasicLib )
921 return false;
923 bLoadBinary = true;
924 pScriptLib->mbLoadedBinary = true;
927 bool bLoadSource = false;
928 if( !pScriptLib->mbLoadedSource && pLib->mbPasswordVerified && !bVerifyPasswordOnly )
930 bLoadSource = true;
931 pScriptLib->mbLoadedSource = true;
934 Sequence< OUString > aElementNames = pLib->getElementNames();
935 sal_Int32 nNameCount = aElementNames.getLength();
936 const OUString* pNames = aElementNames.getConstArray();
938 if( bStorage )
940 uno::Reference< embed::XStorage > xLibrariesStor;
941 uno::Reference< embed::XStorage > xLibraryStor;
942 if( bStorage )
944 try {
945 xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
946 if ( !xLibrariesStor.is() )
948 throw uno::RuntimeException();
950 xLibraryStor = xLibrariesStor->openStorageElement( Name, embed::ElementModes::READ );
951 if ( !xLibraryStor.is() )
953 throw uno::RuntimeException();
956 catch(const uno::Exception& )
958 OSL_FAIL( "### couldn't open sub storage for library\n" );
959 return false;
963 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
965 OUString aElementName = pNames[ i ];
967 // Load binary
968 if( bLoadBinary )
970 SbModule* pMod = pBasicLib->FindModule( aElementName );
971 if( !pMod )
973 pMod = pBasicLib->MakeModule( aElementName, OUString() );
974 pBasicLib->SetModified( false );
977 OUString aCodeStreamName= aElementName;
978 aCodeStreamName += ".bin";
982 uno::Reference< io::XStream > xCodeStream = xLibraryStor->openStreamElement(
983 aCodeStreamName,
984 embed::ElementModes::READ );
985 if ( !xCodeStream.is() )
987 throw uno::RuntimeException();
989 boost::scoped_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( xCodeStream ));
990 if ( !pStream || pStream->GetError() )
992 sal_Int32 nError = pStream ? pStream->GetError() : ERRCODE_IO_GENERAL;
993 throw task::ErrorCodeIOException(
994 ("utl::UcbStreamHelper::CreateStream failed for \""
995 + aCodeStreamName + "\": 0x"
996 + OUString::number(nError, 16)),
997 uno::Reference< uno::XInterface >(), nError);
1000 /*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
1001 // TODO: Check return value
1003 catch(const uno::Exception& )
1005 // TODO: error handling
1009 // Load source
1010 if( bLoadSource || bVerifyPasswordOnly )
1012 // Access encrypted source stream
1013 OUString aSourceStreamName = aElementName;
1014 aSourceStreamName += ".xml";
1018 uno::Reference< io::XStream > xSourceStream = xLibraryStor->openEncryptedStreamElement(
1019 aSourceStreamName,
1020 embed::ElementModes::READ,
1021 pLib->maPassword );
1022 if ( !xSourceStream.is() )
1024 throw uno::RuntimeException();
1026 // if this point is reached then the password is correct
1027 if ( !bVerifyPasswordOnly )
1029 uno::Reference< io::XInputStream > xInStream = xSourceStream->getInputStream();
1030 if ( !xInStream.is() )
1032 throw io::IOException(); // read access denied, seems to be impossible
1034 Reference< XNameContainer > xLib( pLib );
1035 Any aAny = importLibraryElement( xLib,
1036 aElementName, aSourceStreamName,
1037 xInStream );
1038 if( pLib->hasByName( aElementName ) )
1040 if( aAny.hasValue() )
1042 pLib->maNameContainer.replaceByName( aElementName, aAny );
1045 else
1047 pLib->maNameContainer.insertByName( aElementName, aAny );
1051 catch(const uno::Exception& )
1053 bRet = false;
1058 else
1062 OUString aLibDirPath = createAppLibraryFolder( pLib, Name );
1064 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
1066 OUString aElementName = pNames[ i ];
1068 INetURLObject aElementInetObj( aLibDirPath );
1069 aElementInetObj.insertName( aElementName, false,
1070 INetURLObject::LAST_SEGMENT, true, INetURLObject::ENCODE_ALL );
1071 aElementInetObj.setExtension( OUString( "pba" ) );
1072 OUString aElementPath = aElementInetObj.GetMainURL( INetURLObject::NO_DECODE );
1074 uno::Reference< embed::XStorage > xElementRootStorage;
1077 xElementRootStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
1078 aElementPath,
1079 embed::ElementModes::READ );
1080 } catch(const uno::Exception& )
1082 // TODO: error handling
1085 if ( xElementRootStorage.is() )
1087 // Load binary
1088 if( bLoadBinary )
1090 SbModule* pMod = pBasicLib->FindModule( aElementName );
1091 if( !pMod )
1093 pMod = pBasicLib->MakeModule( aElementName, OUString() );
1094 pBasicLib->SetModified( false );
1099 OUString aCodeStreamName( "code.bin" );
1100 uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
1101 aCodeStreamName,
1102 embed::ElementModes::READ );
1104 boost::scoped_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( xCodeStream ));
1105 if ( !pStream || pStream->GetError() )
1107 sal_Int32 nError = pStream ? pStream->GetError() : ERRCODE_IO_GENERAL;
1108 throw task::ErrorCodeIOException(
1109 ("utl::UcbStreamHelper::CreateStream failed"
1110 " for code.bin: 0x"
1111 + OUString::number(nError, 16)),
1112 uno::Reference< uno::XInterface >(),
1113 nError);
1116 /*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
1117 // TODO: Check return value
1119 catch(const uno::Exception& )
1121 // TODO: error handling
1125 // Load source
1126 if( bLoadSource || bVerifyPasswordOnly )
1128 // Access encrypted source stream
1129 OUString aSourceStreamName( "source.xml" );
1132 uno::Reference< io::XStream > xSourceStream = xElementRootStorage->openEncryptedStreamElement(
1133 aSourceStreamName,
1134 embed::ElementModes::READ,
1135 pLib->maPassword );
1136 if ( !xSourceStream.is() )
1138 throw uno::RuntimeException();
1140 if ( !bVerifyPasswordOnly )
1142 uno::Reference< io::XInputStream > xInStream = xSourceStream->getInputStream();
1143 if ( !xInStream.is() )
1145 throw io::IOException(); // read access denied, seems to be impossible
1147 Reference< XNameContainer > xLib( pLib );
1148 Any aAny = importLibraryElement( xLib,
1149 aElementName,
1150 aSourceStreamName,
1151 xInStream );
1152 if( pLib->hasByName( aElementName ) )
1154 if( aAny.hasValue() )
1156 pLib->maNameContainer.replaceByName( aElementName, aAny );
1159 else
1161 pLib->maNameContainer.insertByName( aElementName, aAny );
1165 catch (const uno::Exception& )
1167 bRet = false;
1173 catch(const Exception& )
1175 // TODO
1176 //throw e;
1180 return bRet;
1184 void SfxScriptLibraryContainer::onNewRootStorage()
1188 sal_Bool SAL_CALL SfxScriptLibraryContainer:: HasExecutableCode( const OUString& Library )
1189 throw (uno::RuntimeException, std::exception)
1191 BasicManager* pBasicMgr = getBasicManager();
1192 OSL_ENSURE( pBasicMgr, "we need a basicmanager, really we do" );
1193 if ( pBasicMgr )
1195 return pBasicMgr->HasExeCode( Library ); // need to change this to take name
1197 // default to it has code if we can't decide
1198 return sal_True;
1202 // Service
1203 OUString SAL_CALL SfxScriptLibraryContainer::getImplementationName( )
1204 throw (RuntimeException, std::exception)
1206 return OUString("com.sun.star.comp.sfx2.ScriptLibraryContainer" );
1209 Sequence< OUString > SAL_CALL SfxScriptLibraryContainer::getSupportedServiceNames( )
1210 throw (RuntimeException, std::exception)
1212 Sequence< OUString > aServiceNames( 2 );
1213 aServiceNames[0] = "com.sun.star.script.DocumentScriptLibraryContainer";
1214 // plus, for compatibility:
1215 aServiceNames[1] = "com.sun.star.script.ScriptLibraryContainer";
1216 return aServiceNames;
1219 // Implementation class SfxScriptLibrary
1221 // Ctor
1222 SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper& _rModifiable,
1223 const Reference< XComponentContext >& xContext,
1224 const Reference< XSimpleFileAccess3 >& xSFI )
1225 : SfxLibrary( _rModifiable, cppu::UnoType<OUString>::get(), xContext, xSFI )
1226 , mbLoadedSource( false )
1227 , mbLoadedBinary( false )
1231 SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper& _rModifiable,
1232 const Reference< XComponentContext >& xContext,
1233 const Reference< XSimpleFileAccess3 >& xSFI,
1234 const OUString& aLibInfoFileURL,
1235 const OUString& aStorageURL,
1236 bool ReadOnly )
1237 : SfxLibrary( _rModifiable, cppu::UnoType<OUString>::get(), xContext, xSFI,
1238 aLibInfoFileURL, aStorageURL, ReadOnly)
1239 , mbLoadedSource( false )
1240 , mbLoadedBinary( false )
1244 bool SfxScriptLibrary::isLoadedStorable()
1246 // note: mbLoadedSource can only be true for password-protected lib!
1247 return SfxLibrary::isLoadedStorable() && (!mbPasswordProtected || mbLoadedSource);
1250 // Provide modify state including resources
1251 bool SfxScriptLibrary::isModified()
1253 return implIsModified(); // No resources
1256 void SfxScriptLibrary::storeResources()
1258 // No resources
1261 void SfxScriptLibrary::storeResourcesToURL( const OUString& URL,
1262 const Reference< task::XInteractionHandler >& Handler )
1264 (void)URL;
1265 (void)Handler;
1268 void SfxScriptLibrary::storeResourcesAsURL
1269 ( const OUString& URL, const OUString& NewName )
1271 (void)URL;
1272 (void)NewName;
1275 void SfxScriptLibrary::storeResourcesToStorage( const ::com::sun::star::uno::Reference
1276 < ::com::sun::star::embed::XStorage >& xStorage )
1278 // No resources
1279 (void)xStorage;
1282 bool SfxScriptLibrary::containsValidModule(const Any& rElement)
1284 OUString sModuleText;
1285 rElement >>= sModuleText;
1286 return ( !sModuleText.isEmpty() );
1289 bool SAL_CALL SfxScriptLibrary::isLibraryElementValid(const css::uno::Any& rElement) const
1291 return SfxScriptLibrary::containsValidModule(rElement);
1294 IMPLEMENT_FORWARD_XINTERFACE2( SfxScriptLibrary, SfxLibrary, SfxScriptLibrary_BASE );
1295 IMPLEMENT_FORWARD_XTYPEPROVIDER2( SfxScriptLibrary, SfxLibrary, SfxScriptLibrary_BASE );
1297 script::ModuleInfo SAL_CALL SfxScriptLibrary::getModuleInfo( const OUString& ModuleName )
1298 throw (NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
1300 if ( !hasModuleInfo( ModuleName ) )
1302 throw NoSuchElementException();
1304 return mModuleInfos[ ModuleName ];
1307 sal_Bool SAL_CALL SfxScriptLibrary::hasModuleInfo( const OUString& ModuleName )
1308 throw (RuntimeException, std::exception)
1310 bool bRes = false;
1311 ModuleInfoMap::iterator it = mModuleInfos.find( ModuleName );
1313 if ( it != mModuleInfos.end() )
1315 bRes = true;
1317 return bRes;
1320 void SAL_CALL SfxScriptLibrary::insertModuleInfo( const OUString& ModuleName, const script::ModuleInfo& ModuleInfo )
1321 throw (IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException, std::exception)
1323 if ( hasModuleInfo( ModuleName ) )
1325 throw ElementExistException();
1327 mModuleInfos[ ModuleName ] = ModuleInfo;
1330 void SAL_CALL SfxScriptLibrary::removeModuleInfo( const OUString& ModuleName )
1331 throw (NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
1333 // #FIXME add NoSuchElementException to the spec
1334 if ( !hasModuleInfo( ModuleName ) )
1336 throw NoSuchElementException();
1338 mModuleInfos.erase( mModuleInfos.find( ModuleName ) );
1341 } // namespace basic
1344 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
1345 com_sun_star_comp_sfx2_ScriptLibraryContainer_get_implementation(::com::sun::star::uno::XComponentContext*,
1346 ::com::sun::star::uno::Sequence<css::uno::Any> const &)
1348 return cppu::acquire(new basic::SfxScriptLibraryContainer());
1352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */