1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include "scriptcont.hxx"
21#include "sbmodule.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>
44
45// For password functionality
46#include <tools/urlobj.hxx>
47
48
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>
61namespace basic
62{
63
64using namespace com::sun::star::document;
65using namespace com::sun::star::container;
66using namespace com::sun::star::io;
67using namespace com::sun::star::uno;
68using namespace com::sun::star::ucb;
69using namespace com::sun::star::lang;
70using namespace com::sun::star::script;
71using namespace com::sun::star::xml::sax;
72using namespace com::sun::star;
73using namespace cppu;
74using namespace osl;
75
76//============================================================================
77// Implementation class SfxScriptLibraryContainer
78
79const sal_Char* SAL_CALL SfxScriptLibraryContainer::getInfoFileName() const { return "script"; }
80const sal_Char* SAL_CALL SfxScriptLibraryContainer::getOldInfoFileName() const { return "script"; }
81const sal_Char* SAL_CALL SfxScriptLibraryContainer::getLibElementFileExtension() const { return "xba"; }
82const sal_Char* SAL_CALL SfxScriptLibraryContainer::getLibrariesDir() const { return "Basic"; }
83
84// OldBasicPassword interface
85void SfxScriptLibraryContainer::setLibraryPassword( const OUString& rLibraryName, const OUString& rPassword )
86{
87 try
88 {
89 SfxLibrary* pImplLib = getImplLib( rLibraryName );
90 if( !rPassword.isEmpty() )
91 {
92 pImplLib->mbDoc50Password = true;
93 pImplLib->mbPasswordProtected = sal_True;
94 pImplLib->maPassword = rPassword;
95 }
96 }
97 catch(const NoSuchElementException& ) {}
98}
99
100OUString SfxScriptLibraryContainer::getLibraryPassword( const OUString& rLibraryName )
101{
102 SfxLibrary* pImplLib = getImplLib( rLibraryName );
103 OUString aPassword;
104 if( pImplLib->mbPasswordVerified )
105 {
106 aPassword = pImplLib->maPassword;
107 }
108 return aPassword;
109}
110
111void SfxScriptLibraryContainer::clearLibraryPassword( const OUString& rLibraryName )
112{
113 try
114 {
115 SfxLibrary* pImplLib = getImplLib( rLibraryName );
116 pImplLib->mbDoc50Password = false;
117 pImplLib->mbPasswordProtected = sal_False;
118 pImplLib->maPassword = "";
119 }
120 catch(const NoSuchElementException& ) {}
121}
122
123sal_Bool SfxScriptLibraryContainer::hasLibraryPassword( const OUString& rLibraryName )
124{
125 SfxLibrary* pImplLib = getImplLib( rLibraryName );
126 return pImplLib->mbPasswordProtected;
127}
128
129// Ctor for service
130SfxScriptLibraryContainer::SfxScriptLibraryContainer( void )
131 :maScriptLanguage( "StarBasic" )
132{
133 // all initialisation has to be done
134 // by calling XInitialization::initialize
135}
136
137SfxScriptLibraryContainer::SfxScriptLibraryContainer( const uno::Reference< embed::XStorage >& xStorage )
138 :maScriptLanguage( "StarBasic" )
139{
140 init( OUString(), xStorage );
141}
142
143// Methods to get library instances of the correct type
144SfxLibrary* SfxScriptLibraryContainer::implCreateLibrary( const OUString& aName )
145{
146 (void)aName; // Only needed for SfxDialogLibrary
147 SfxLibrary* pRet = new SfxScriptLibrary( maModifiable, mxContext, mxSFI );
148 return pRet;
149}
150
151SfxLibrary* SfxScriptLibraryContainer::implCreateLibraryLink( const OUString& aName,
152 const OUString& aLibInfoFileURL,
153 const OUString& StorageURL,
154 sal_Bool ReadOnly )
155{
156 (void)aName; // Only needed for SfxDialogLibrary
157 SfxLibrary* pRet = new SfxScriptLibrary( maModifiable, mxContext, mxSFI,
158 aLibInfoFileURL, StorageURL, ReadOnly );
159 return pRet;
160}
161
162Any SAL_CALL SfxScriptLibraryContainer::createEmptyLibraryElement( void )
163{
164 OUString aMod;
165 Any aRetAny;
166 aRetAny <<= aMod;
167 return aRetAny;
168}
169
170bool SAL_CALL SfxScriptLibraryContainer::isLibraryElementValid( Any aElement ) const
171{
172 return SfxScriptLibrary::containsValidModule( aElement );
173}
174
175void SAL_CALL SfxScriptLibraryContainer::writeLibraryElement( const Reference < XNameContainer >& xLib,
176 const OUString& aElementName,
177 const Reference< XOutputStream >& xOutput)
178 throw(Exception)
179{
180 // Create sax writer
181 Reference< XWriter > xWriter = xml::sax::Writer::create(mxContext);
182
183 Reference< XTruncate > xTruncate( xOutput, UNO_QUERY );
184 OSL_ENSURE( xTruncate.is(), "Currently only the streams that can be truncated are expected!" );
185 if ( xTruncate.is() )
186 {
187 xTruncate->truncate();
188 }
189 xWriter->setOutputStream( xOutput );
190
191 xmlscript::ModuleDescriptor aMod;
192 aMod.aName = aElementName;
193 aMod.aLanguage = maScriptLanguage;
194 Any aElement = xLib->getByName( aElementName );
195 aElement >>= aMod.aCode;
196
197 Reference< script::vba::XVBAModuleInfo > xModInfo( xLib, UNO_QUERY );
198 if( xModInfo.is() && xModInfo->hasModuleInfo( aElementName ) )
199 {
200 script::ModuleInfo aModInfo = xModInfo->getModuleInfo( aElementName );
201 switch( aModInfo.ModuleType )
202 {
203 case ModuleType::NORMAL:
204 aMod.aModuleType = "normal";
205 break;
206 case ModuleType::CLASS:
207 aMod.aModuleType ="class";
208 break;
209 case ModuleType::FORM:
210 aMod.aModuleType = "form";
211 break;
212 case ModuleType::DOCUMENT:
213 aMod.aModuleType = "document";
214 break;
215 case ModuleType::UNKNOWN:
216 // nothing
217 break;
218 }
219 }
220
221 xmlscript::exportScriptModule( xWriter, aMod );
222}
223
224
225Any SAL_CALL SfxScriptLibraryContainer::importLibraryElement
226 ( const Reference < XNameContainer >& xLib,
227 const OUString& aElementName, const OUString& aFile,
228 const uno::Reference< io::XInputStream >& xInStream )
229{
230 Any aRetAny;
231
232 Reference< XParser > xParser = xml::sax::Parser::create( mxContext );
233
234 // Read from storage?
235 sal_Bool bStorage = xInStream.is();
236 Reference< XInputStream > xInput;
237
238 if( bStorage )
239 {
240 xInput = xInStream;
241 }
242 else
243 {
244 try
245 {
246 xInput = mxSFI->openFileRead( aFile );
247 }
248 catch(const Exception& )
249 //catch( Exception& e )
250 {
251 // TODO:
252 //throw WrappedTargetException( e );
253 }
254 }
255
256 if( !xInput.is() )
257 return aRetAny;
258
259 InputSource source;
260 source.aInputStream = xInput;
261 source.sSystemId = aFile;
262
263 // start parsing
264 xmlscript::ModuleDescriptor aMod;
265
266 try
267 {
268 xParser->setDocumentHandler( ::xmlscript::importScriptModule( aMod ) );
269 xParser->parseStream( source );
270 }
271 catch(const Exception& )
272 {
273 SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aFile );
274 sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
275 ErrorHandler::HandleError( nErrorCode );
276 }
277
278 aRetAny <<= aMod.aCode;
279
280 // TODO: Check language
281 // aMod.aLanguage
282 // aMod.aName ignored
283 if( !aMod.aModuleType.isEmpty() )
284 {
285 /* If in VBA compatibility mode, force creation of the VBA Globals
286 object. Each application will create an instance of its own
287 implementation and store it in its Basic manager. Implementations
288 will do all necessary additional initialization, such as
289 registering the global "This***Doc" UNO constant, starting the
290 document events processor etc.
291 */
292 if( getVBACompatibilityMode() ) try
293 {
294 Reference< frame::XModel > xModel( mxOwnerDocument ); // weak-ref -> ref
295 Reference< XMultiServiceFactory > xFactory( xModel, UNO_QUERY_THROW );
296 xFactory->createInstance("ooo.vba.VBAGlobals");
297 }
298 catch(const Exception& )
299 {
300 }
301
302 script::ModuleInfo aModInfo;
303 aModInfo.ModuleType = ModuleType::UNKNOWN;
304 if( aMod.aModuleType == "normal" )
305 {
306 aModInfo.ModuleType = ModuleType::NORMAL;
307 }
308 else if( aMod.aModuleType == "class" )
309 {
310 aModInfo.ModuleType = ModuleType::CLASS;
311 }
312 else if( aMod.aModuleType == "form" )
313 {
314 aModInfo.ModuleType = ModuleType::FORM;
315 aModInfo.ModuleObject = mxOwnerDocument;
316 }
317 else if( aMod.aModuleType == "document" )
318 {
319 aModInfo.ModuleType = ModuleType::DOCUMENT;
320
321 // #163691# use the same codename access instance for all document modules
322 if( !mxCodeNameAccess.is() ) try
323 {
324 Reference<frame::XModel > xModel( mxOwnerDocument );
325 Reference< XMultiServiceFactory> xSF( xModel, UNO_QUERY_THROW );
326 mxCodeNameAccess.set( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), UNO_QUERY );
327 }
328 catch(const Exception& ) {}
329
330 if( mxCodeNameAccess.is() )
331 {
332 try
333 {
334 aModInfo.ModuleObject.set( mxCodeNameAccess->getByName( aElementName), uno::UNO_QUERY );
335 }
336 catch(const uno::Exception&)
337 {
338 OSL_TRACE("Failed to get documument object for %s", OUStringToOString( aElementName, RTL_TEXTENCODING_UTF8 ).getStr() );
339 }
340 }
341 }
342
343 Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY );
344 if( xVBAModuleInfo.is() )
345 {
346 if( xVBAModuleInfo->hasModuleInfo( aElementName ) )
347 {
348 xVBAModuleInfo->removeModuleInfo( aElementName );
349 }
350 xVBAModuleInfo->insertModuleInfo( aElementName, aModInfo );
351 }
352 }
353
354 return aRetAny;
355}
356
357SfxLibraryContainer* SfxScriptLibraryContainer::createInstanceImpl( void )
358{
359 return new SfxScriptLibraryContainer();
360}
361
362void SAL_CALL SfxScriptLibraryContainer::importFromOldStorage( const OUString& aFile )
363{
364 // TODO: move loading from old storage to binary filters?
365 SotStorageRef xStorage = new SotStorage( false, aFile );
366 if( xStorage.Is() && xStorage->GetError() == ERRCODE_NONE )
367 {
368 BasicManager* pBasicManager = new BasicManager( *(SotStorage*)xStorage, aFile );
369
370 // Set info
371 LibraryContainerInfo aInfo( this, NULL, static_cast< OldBasicPassword* >( this ) );
372 pBasicManager->SetLibraryContainerInfo( aInfo );
373
374 // Now the libraries should be copied to this SfxScriptLibraryContainer
375 BasicManager::LegacyDeleteBasicManager( pBasicManager );
376 }
377}
378
379
380// Storing with password encryption
381
382// Methods XLibraryContainerPassword
383sal_Bool SAL_CALL SfxScriptLibraryContainer::isLibraryPasswordProtected( const OUString& Name )
384 throw (NoSuchElementException, RuntimeException)
385{
386 LibraryContainerMethodGuard aGuard( *this );
387 SfxLibrary* pImplLib = getImplLib( Name );
388 sal_Bool bRet = pImplLib->mbPasswordProtected;
389 return bRet;
390}
391
392sal_Bool SAL_CALL SfxScriptLibraryContainer::isLibraryPasswordVerified( const OUString& Name )
393 throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
394{
395 LibraryContainerMethodGuard aGuard( *this );
396 SfxLibrary* pImplLib = getImplLib( Name );
397 if( !pImplLib->mbPasswordProtected )
398 {
399 throw IllegalArgumentException();
400 }
401 sal_Bool bRet = pImplLib->mbPasswordVerified;
402 return bRet;
403}
404
405sal_Bool SAL_CALL SfxScriptLibraryContainer::verifyLibraryPassword
406 ( const OUString& Name, const OUString& Password )
407 throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
408{
409 LibraryContainerMethodGuard aGuard( *this );
410 SfxLibrary* pImplLib = getImplLib( Name );
411 if( !pImplLib->mbPasswordProtected || pImplLib->mbPasswordVerified )
412 {
413 throw IllegalArgumentException();
414 }
415 // Test password
416 sal_Bool bSuccess = sal_False;
417 if( pImplLib->mbDoc50Password )
418 {
419 bSuccess = ( Password == pImplLib->maPassword );
420 if( bSuccess )
421 {
422 pImplLib->mbPasswordVerified = sal_True;
423 }
424 }
425 else
426 {
427 pImplLib->maPassword = Password;
428 bSuccess = implLoadPasswordLibrary( pImplLib, Name, sal_True );
429 if( bSuccess )
430 {
431 // The library gets modified by verifiying the password, because other-
432 // wise for saving the storage would be copied and that doesn't work
433 // with mtg's storages when the password is verified
434 pImplLib->implSetModified( sal_True );
435 pImplLib->mbPasswordVerified = sal_True;
436
437 // Reload library to get source
438 if( pImplLib->mbLoaded )
439 {
440 implLoadPasswordLibrary( pImplLib, Name );
441 }
442 }
443 }
444 return bSuccess;
445}
446
447void SAL_CALL SfxScriptLibraryContainer::changeLibraryPassword( const OUString& Name,
448 const OUString& OldPassword,
449 const OUString& NewPassword )
450 throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
451{
452 LibraryContainerMethodGuard aGuard( *this );
453 SfxLibrary* pImplLib = getImplLib( Name );
454 if( OldPassword == NewPassword )
455 {
456 return;
457 }
458 sal_Bool bOldPassword = !OldPassword.isEmpty();
459 sal_Bool bNewPassword = !NewPassword.isEmpty();
460 sal_Bool bStorage = mxStorage.is() && !pImplLib->mbLink;
461
462 if( pImplLib->mbReadOnly || (bOldPassword && !pImplLib->mbPasswordProtected) )
463 {
464 throw IllegalArgumentException();
465 }
466 // Library must be loaded
467 loadLibrary( Name );
468
469 bool bKillCryptedFiles = false;
470 bool bKillUncryptedFiles = false;
471
472 // Remove or change password?
473 if( bOldPassword )
474 {
475 if( isLibraryPasswordVerified( Name ) )
476 {
477 if( pImplLib->maPassword != OldPassword )
478 {
479 throw IllegalArgumentException();
480 }
481 }
482 else
483 {
484 if( !verifyLibraryPassword( Name, OldPassword ) )
485 {
486 throw IllegalArgumentException();
487 }
488 // Reload library to get source
489 // Should be done in verifyLibraryPassword loadLibrary( Name );
490 }
491
492 if( !bNewPassword )
493 {
494 pImplLib->mbPasswordProtected = sal_False;
495 pImplLib->mbPasswordVerified = sal_False;
496 pImplLib->maPassword = "";
497
498 maModifiable.setModified( sal_True );
499 pImplLib->implSetModified( sal_True );
500
501 if( !bStorage && !pImplLib->mbDoc50Password )
502 {
503 // Store application basic uncrypted
504 uno::Reference< embed::XStorage > xStorage;
505 storeLibraries_Impl( xStorage, false );
506 bKillCryptedFiles = true;
507 }
508 }
509 }
510
511 // Set new password?
512 if( bNewPassword )
513 {
514 pImplLib->mbPasswordProtected = sal_True;
515 pImplLib->mbPasswordVerified = sal_True;
516 pImplLib->maPassword = NewPassword;
517
518 maModifiable.setModified( sal_True );
519 pImplLib->implSetModified( sal_True );
520
521 if( !bStorage && !pImplLib->mbDoc50Password )
522 {
523 // Store applictaion basic crypted
524 uno::Reference< embed::XStorage > xStorage;
525 storeLibraries_Impl( xStorage, false );
526 bKillUncryptedFiles = true;
527 }
528 }
529
530 if( bKillCryptedFiles || bKillUncryptedFiles )
531 {
532 Sequence< OUString > aElementNames = pImplLib->getElementNames();
533 sal_Int32 nNameCount = aElementNames.getLength();
534 const OUString* pNames = aElementNames.getConstArray();
535 OUString aLibDirPath = createAppLibraryFolder( pImplLib, Name );
536 try
537 {
538 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
539 {
540 OUString aElementName = pNames[ i ];
541
542 INetURLObject aElementInetObj( aLibDirPath );
543 aElementInetObj.insertName( aElementName, false,
544 INetURLObject::LAST_SEGMENT, true,
545 INetURLObject::ENCODE_ALL );
546 if( bKillUncryptedFiles )
547 {
548 aElementInetObj.setExtension( maLibElementFileExtension );
549 }
550 else
551 {
552 aElementInetObj.setExtension( OUString( "pba" ) );
553 }
554 OUString aElementPath( aElementInetObj.GetMainURL( INetURLObject::NO_DECODE ) );
555
556 if( mxSFI->exists( aElementPath ) )
557 {
558 mxSFI->kill( aElementPath );
559 }
560 }
561 }
562 catch(const Exception& ) {}
563 }
564}
565
566
567void setStreamKey( uno::Reference< io::XStream > xStream, const OUString& aPass )
568{
569 uno::Reference< embed::XEncryptionProtectedSource > xEncrStream( xStream, uno::UNO_QUERY );
570 if ( xEncrStream.is() )
571 {
572 xEncrStream->setEncryptionPassword( aPass );
573 }
574}
575
576
577// Impl methods
578sal_Bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary* pLib,
579 const OUString& aName,
580 const uno::Reference< embed::XStorage >& xStorage,
581 const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xHandler )
582{
583 OUString aDummyLocation;
584 Reference< XSimpleFileAccess3 > xDummySFA;
585 return implStorePasswordLibrary( pLib, aName, xStorage, aDummyLocation, xDummySFA, xHandler );
586}
587
588sal_Bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary* pLib, const OUString& aName,
589 const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage,
590 const OUString& aTargetURL,
591 const Reference< XSimpleFileAccess3 > xToUseSFI,
592 const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xHandler )
593{
594 bool bExport = !aTargetURL.isEmpty();
595
596 BasicManager* pBasicMgr = getBasicManager();
597 OSL_ENSURE( pBasicMgr, "SfxScriptLibraryContainer::implStorePasswordLibrary: cannot do this without a BasicManager!" );
598 if ( !pBasicMgr )
599 {
600 return sal_False;
601 }
602 // Only need to handle the export case here,
603 // save/saveas etc are handled in sfxbasemodel::storeSelf &
604 // sfxbasemodel::impl_store
605 uno::Sequence<OUString> aNames;
606 if ( bExport && pBasicMgr->LegacyPsswdBinaryLimitExceeded(aNames) )
607 {
608 if ( xHandler.is() )
609 {
610 ModuleSizeExceeded* pReq = new ModuleSizeExceeded( aNames );
611 uno::Reference< task::XInteractionRequest > xReq( pReq );
612 xHandler->handle( xReq );
613 if ( pReq->isAbort() )
614 {
615 throw util::VetoException();
616 }
617 }
618 }
619
620 StarBASIC* pBasicLib = pBasicMgr->GetLib( aName );
621 if( !pBasicLib )
622 {
623 return sal_False;
624 }
625 Sequence< OUString > aElementNames = pLib->getElementNames();
626 sal_Int32 nNameCount = aElementNames.getLength();
627 const OUString* pNames = aElementNames.getConstArray();
628
629 sal_Bool bLink = pLib->mbLink;
630 sal_Bool bStorage = xStorage.is() && !bLink;
631 if( bStorage )
632 {
633 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
634 {
635 OUString aElementName = pNames[ i ];
636
637 // Write binary image stream
638 SbModule* pMod = pBasicLib->FindModule( aElementName );
639 if( pMod )
640 {
641 OUString aCodeStreamName = aElementName;
642 aCodeStreamName += ".bin";
643
644 try
645 {
646 uno::Reference< io::XStream > xCodeStream = xStorage->openStreamElement(
647 aCodeStreamName,
648 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
649
650 if ( !xCodeStream.is() )
651 {
652 throw uno::RuntimeException();
653 }
654 SvMemoryStream aMemStream;
655 /*sal_Bool bStore = */pMod->StoreBinaryData( aMemStream );
656
657 sal_Int32 nSize = (sal_Int32)aMemStream.Tell();
658 Sequence< sal_Int8 > aBinSeq( nSize );
659 sal_Int8* pData = aBinSeq.getArray();
660 memcpy( pData, aMemStream.GetData(), nSize );
661
662 Reference< XOutputStream > xOut = xCodeStream->getOutputStream();
663 if ( !xOut.is() )
664 {
665 throw io::IOException(); // access denied because the stream is readonly
666 }
667 xOut->writeBytes( aBinSeq );
668 xOut->closeOutput();
669 }
670 catch(const uno::Exception& )
671 {
672 // TODO: handle error
673 }
674 }
675
676 if( pLib->mbPasswordVerified || pLib->mbDoc50Password )
677 {
678 if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
679 {
680 #if OSL_DEBUG_LEVEL > 0
681 OString aMessage = "invalid library element '" +
682 OUStringToOString( aElementName, osl_getThreadTextEncoding() ) +
683 "'.";
684 OSL_FAIL( aMessage.getStr());
685 #endif
686 continue;
687 }
688
689 OUString aSourceStreamName = aElementName;
690 aSourceStreamName += ".xml";
691
692 try
693 {
694 uno::Reference< io::XStream > xSourceStream = xStorage->openStreamElement(
695 aSourceStreamName,
696 embed::ElementModes::READWRITE );
697 uno::Reference< beans::XPropertySet > xProps( xSourceStream, uno::UNO_QUERY );
698 if ( !xProps.is() )
699 {
700 throw uno::RuntimeException();
701 }
702 OUString aMime( "text/xml" );
703 xProps->setPropertyValue("MediaType", uno::makeAny( aMime ) );
704
705 // Set encryption key
706 setStreamKey( xSourceStream, pLib->maPassword );
707
708 Reference< XOutputStream > xOutput = xSourceStream->getOutputStream();
709 Reference< XNameContainer > xLib( pLib );
710 writeLibraryElement( xLib, aElementName, xOutput );
711 }
712 catch(const uno::Exception& )
713 {
714 OSL_FAIL( "Problem on storing of password library!\n" );
715 // TODO: error handling
716 }
717 }
718 else // !mbPasswordVerified
719 {
720 // TODO
721 // What to do if not verified?! In any case it's already loaded here
722 }
723 }
724
725 }
726 // Application libraries have only to be saved if the password
727 // is verified because otherwise they can't be modified
728 else if( pLib->mbPasswordVerified || bExport )
729 {
730 try
731 {
732 Reference< XSimpleFileAccess3 > xSFI = mxSFI;
733 if( xToUseSFI.is() )
734 {
735 xSFI = xToUseSFI;
736 }
737 OUString aLibDirPath;
738 if( bExport )
739 {
740 INetURLObject aInetObj( aTargetURL );
741 aInetObj.insertName( aName, true, INetURLObject::LAST_SEGMENT, true,
742 INetURLObject::ENCODE_ALL );
743 aLibDirPath = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
744
745 if( !xSFI->isFolder( aLibDirPath ) )
746 {
747 xSFI->createFolder( aLibDirPath );
748 }
749 }
750 else
751 {
752 aLibDirPath = createAppLibraryFolder( pLib, aName );
753 }
754
755 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
756 {
757 OUString aElementName = pNames[ i ];
758
759 INetURLObject aElementInetObj( aLibDirPath );
760 aElementInetObj.insertName( aElementName, false,
761 INetURLObject::LAST_SEGMENT, true,
762 INetURLObject::ENCODE_ALL );
763 aElementInetObj.setExtension( OUString( "pba" ) );
764 OUString aElementPath = aElementInetObj.GetMainURL( INetURLObject::NO_DECODE );
765
766 if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
767 {
768 #if OSL_DEBUG_LEVEL > 0
769 OString aMessage = "invalid library element '" +
770 OUStringToOString( aElementName, osl_getThreadTextEncoding() ) +
771 "'.";
772 OSL_FAIL( aMessage.getStr());
773 #endif
774 continue;
775 }
776
777 try
778 {
779 uno::Reference< embed::XStorage > xElementRootStorage =
780 ::comphelper::OStorageHelper::GetStorageFromURL(
781 aElementPath,
782 embed::ElementModes::READWRITE );
783 if ( !xElementRootStorage.is() )
784 {
785 throw uno::RuntimeException();
786 }
787 // Write binary image stream
788 SbModule* pMod = pBasicLib->FindModule( aElementName );
789 if( pMod )
790 {
791 OUString aCodeStreamName( "code.bin" );
792
793 uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
794 aCodeStreamName,
795 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
796
797 SvMemoryStream aMemStream;
798 /*sal_Bool bStore = */pMod->StoreBinaryData( aMemStream );
799
800 sal_Int32 nSize = (sal_Int32)aMemStream.Tell();
801 Sequence< sal_Int8 > aBinSeq( nSize );
802 sal_Int8* pData = aBinSeq.getArray();
803 memcpy( pData, aMemStream.GetData(), nSize );
804
805 Reference< XOutputStream > xOut = xCodeStream->getOutputStream();
806 if ( xOut.is() )
807 {
808 xOut->writeBytes( aBinSeq );
809 xOut->closeOutput();
810 }
811 }
812
813 // Write encrypted source stream
814 OUString aSourceStreamName( "source.xml" );
815
816 uno::Reference< io::XStream > xSourceStream;
817 try
818 {
819 xSourceStream = xElementRootStorage->openStreamElement(
820 aSourceStreamName,
821 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
822
823 // #87671 Allow encryption
824 uno::Reference< embed::XEncryptionProtectedSource > xEncr( xSourceStream, uno::UNO_QUERY );
825 OSL_ENSURE( xEncr.is(),
826 "StorageStream opened for writing must implement XEncryptionProtectedSource!\n" );
827 if ( !xEncr.is() )
828 {
829 throw uno::RuntimeException();
830 }
831 xEncr->setEncryptionPassword( pLib->maPassword );
832 }
833 catch(const ::com::sun::star::packages::WrongPasswordException& )
834 {
835 xSourceStream = xElementRootStorage->openEncryptedStreamElement(
836 aSourceStreamName,
837 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE,
838 pLib->maPassword );
839 }
840
841 uno::Reference< beans::XPropertySet > xProps( xSourceStream, uno::UNO_QUERY );
842 if ( !xProps.is() )
843 {
844 throw uno::RuntimeException();
845 }
846 OUString aMime( "text/xml" );
847 xProps->setPropertyValue("MediaType", uno::makeAny( aMime ) );
848
849 Reference< XOutputStream > xOut = xSourceStream->getOutputStream();
850 Reference< XNameContainer > xLib( pLib );
851 writeLibraryElement( xLib, aElementName, xOut );
852 // i50568: sax writer already closes stream
853 // xOut->closeOutput();
854
855 uno::Reference< embed::XTransactedObject > xTransact( xElementRootStorage, uno::UNO_QUERY );
856 OSL_ENSURE( xTransact.is(), "The storage must implement XTransactedObject!\n" );
857 if ( !xTransact.is() )
858 {
859 throw uno::RuntimeException();
860 }
861
862 xTransact->commit();
863 }
864 catch(const uno::Exception& )
865 {
866 // TODO: handle error
867 }
868
869 }
870 }
871 catch(const Exception& )
872 {
873 }
874 }
875 return sal_True;
876}
877
878sal_Bool SfxScriptLibraryContainer::implLoadPasswordLibrary
879 ( SfxLibrary* pLib, const OUString& Name, sal_Bool bVerifyPasswordOnly )
880 throw(WrappedTargetException, RuntimeException)
881{
882 sal_Bool bRet = sal_True;
883
884 sal_Bool bLink = pLib->mbLink;
885 sal_Bool bStorage = mxStorage.is() && !bLink;
886
887 // Already loaded? Then only verifiedPassword can change something
888 SfxScriptLibrary* pScriptLib = static_cast< SfxScriptLibrary* >( pLib );
889 if( pScriptLib->mbLoaded )
890 {
891 if( pScriptLib->mbLoadedBinary && !bVerifyPasswordOnly &&
892 (pScriptLib->mbLoadedSource || !pLib->mbPasswordVerified) )
893 {
894 return sal_False;
895 }
896 }
897
898 StarBASIC* pBasicLib = NULL;
899 sal_Bool bLoadBinary = sal_False;
900 if( !pScriptLib->mbLoadedBinary && !bVerifyPasswordOnly && !pLib->mbPasswordVerified )
901 {
902 BasicManager* pBasicMgr = getBasicManager();
903 OSL_ENSURE( pBasicMgr, "SfxScriptLibraryContainer::implLoadPasswordLibrary: cannot do this without a BasicManager!" );
904 sal_Bool bLoaded = pScriptLib->mbLoaded;
905 pScriptLib->mbLoaded = sal_True; // Necessary to get lib
906 pBasicLib = pBasicMgr ? pBasicMgr->GetLib( Name ) : NULL;
907 pScriptLib->mbLoaded = bLoaded; // Restore flag
908 if( !pBasicLib )
909 {
910 return sal_False;
911 }
912 bLoadBinary = sal_True;
913 pScriptLib->mbLoadedBinary = true;
914 }
915
916 bool bLoadSource = false;
917 if( !pScriptLib->mbLoadedSource && pLib->mbPasswordVerified && !bVerifyPasswordOnly )
918 {
919 bLoadSource = true;
920 pScriptLib->mbLoadedSource = true;
921 }
922
923 Sequence< OUString > aElementNames = pLib->getElementNames();
924 sal_Int32 nNameCount = aElementNames.getLength();
925 const OUString* pNames = aElementNames.getConstArray();
926
927 if( bStorage )
928 {
929 uno::Reference< embed::XStorage > xLibrariesStor;
930 uno::Reference< embed::XStorage > xLibraryStor;
931 if( bStorage )
932 {
933 try {
934 xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
935 if ( !xLibrariesStor.is() )
936 {
937 throw uno::RuntimeException();
938 }
939 xLibraryStor = xLibrariesStor->openStorageElement( Name, embed::ElementModes::READ );
940 if ( !xLibraryStor.is() )
941 {
942 throw uno::RuntimeException();
943 }
944 }
945 catch(const uno::Exception& )
946 {
947 OSL_FAIL( "### couldn't open sub storage for library\n" );
948 return sal_False;
949 }
950 }
951
952 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
953 {
954 OUString aElementName = pNames[ i ];
955
956 // Load binary
957 if( bLoadBinary )
958 {
959 SbModule* pMod = pBasicLib->FindModule( aElementName );
960 if( !pMod )
961 {
962 pMod = pBasicLib->MakeModule( aElementName, OUString() );
963 pBasicLib->SetModified( sal_False );
964 }
965
966 OUString aCodeStreamName= aElementName;
967 aCodeStreamName += ".bin";
968
969 try
970 {
971 uno::Reference< io::XStream > xCodeStream = xLibraryStor->openStreamElement(
972 aCodeStreamName,
973 embed::ElementModes::READ );
974 if ( !xCodeStream.is() )
975 {
976 throw uno::RuntimeException();
977 }
978 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( xCodeStream );
979 if ( !pStream || pStream->GetError() )
980 {
981 sal_Int32 nError = pStream ? pStream->GetError() : ERRCODE_IO_GENERAL;
982 delete pStream;
983 throw task::ErrorCodeIOException(
984 ("utl::UcbStreamHelper::CreateStream failed for \""
985 + aCodeStreamName + "\": 0x"
986 + OUString::number(nError, 16)),
987 uno::Reference< uno::XInterface >(), nError);
988 }
989
990 /*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
991 // TODO: Check return value
992
993 delete pStream;
994 }
995 catch(const uno::Exception& )
996 {
997 // TODO: error handling
998 }
999 }
1000
1001 // Load source
1002 if( bLoadSource || bVerifyPasswordOnly )
1003 {
1004 // Access encrypted source stream
1005 OUString aSourceStreamName = aElementName;
1006 aSourceStreamName += ".xml";
1007
1008 try
1009 {
1010 uno::Reference< io::XStream > xSourceStream = xLibraryStor->openEncryptedStreamElement(
1011 aSourceStreamName,
1012 embed::ElementModes::READ,
1013 pLib->maPassword );
1014 if ( !xSourceStream.is() )
1015 {
1016 throw uno::RuntimeException();
1017 }
1018 // if this point is reached then the password is correct
1019 if ( !bVerifyPasswordOnly )
1020 {
1021 uno::Reference< io::XInputStream > xInStream = xSourceStream->getInputStream();
1022 if ( !xInStream.is() )
1023 {
1024 throw io::IOException(); // read access denied, seems to be impossible
1025 }
1026 Reference< XNameContainer > xLib( pLib );
1027 Any aAny = importLibraryElement( xLib,
1028 aElementName, aSourceStreamName,
1029 xInStream );
1030 if( pLib->hasByName( aElementName ) )
1031 {
1032 if( aAny.hasValue() )
1033 {
1034 pLib->maNameContainer.replaceByName( aElementName, aAny );
1035 }
1036 }
1037 else
1038 {
1039 pLib->maNameContainer.insertByName( aElementName, aAny );
1040 }
1041 }
1042 }
1043 catch(const uno::Exception& )
1044 {
1045 bRet = sal_False;
1046 }
1047 }
1048 }
1049 }
1050 else
1051 {
1052 try
1053 {
1054 OUString aLibDirPath = createAppLibraryFolder( pLib, Name );
1055
1056 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
1057 {
1058 OUString aElementName = pNames[ i ];
1059
1060 INetURLObject aElementInetObj( aLibDirPath );
1061 aElementInetObj.insertName( aElementName, false,
1062 INetURLObject::LAST_SEGMENT, true, INetURLObject::ENCODE_ALL );
1063 aElementInetObj.setExtension( OUString( "pba" ) );
1064 OUString aElementPath = aElementInetObj.GetMainURL( INetURLObject::NO_DECODE );
1065
1066 uno::Reference< embed::XStorage > xElementRootStorage;
1067 try
1068 {
1069 xElementRootStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
1070 aElementPath,
1071 embed::ElementModes::READ );
1072 } catch(const uno::Exception& )
1073 {
1074 // TODO: error handling
1075 }
1076
1077 if ( xElementRootStorage.is() )
1078 {
1079 // Load binary
1080 if( bLoadBinary )
1081 {
1082 SbModule* pMod = pBasicLib->FindModule( aElementName );
1083 if( !pMod )
1084 {
1085 pMod = pBasicLib->MakeModule( aElementName, OUString() );
1086 pBasicLib->SetModified( sal_False );
1087 }
1088
1089 try
1090 {
1091 OUString aCodeStreamName( "code.bin" );
1092 uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
1093 aCodeStreamName,
1094 embed::ElementModes::READ );
1095
1096 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( xCodeStream );
1097 if ( !pStream || pStream->GetError() )
1098 {
1099 sal_Int32 nError = pStream ? pStream->GetError() : ERRCODE_IO_GENERAL;
1100 delete pStream;
1101 throw task::ErrorCodeIOException(
1102 ("utl::UcbStreamHelper::CreateStream failed"
1103 " for code.bin: 0x"
1104 + OUString::number(nError, 16)),
1105 uno::Reference< uno::XInterface >(),
1106 nError);
1107 }
1108
1109 /*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
1110 // TODO: Check return value
1111
1112 delete pStream;
1113 }
1114 catch(const uno::Exception& )
1115 {
1116 // TODO: error handling
1117 }
1118 }
1119
1120 // Load source
1121 if( bLoadSource || bVerifyPasswordOnly )
1122 {
1123 // Access encrypted source stream
1124 OUString aSourceStreamName( "source.xml" );
1125 try
1126 {
1127 uno::Reference< io::XStream > xSourceStream = xElementRootStorage->openEncryptedStreamElement(
1128 aSourceStreamName,
1129 embed::ElementModes::READ,
1130 pLib->maPassword );
1131 if ( !xSourceStream.is() )
1132 {
1133 throw uno::RuntimeException();
1134 }
1135 if ( !bVerifyPasswordOnly )
1136 {
1137 uno::Reference< io::XInputStream > xInStream = xSourceStream->getInputStream();
1138 if ( !xInStream.is() )
1139 {
1140 throw io::IOException(); // read access denied, seems to be impossible
1141 }
1142 Reference< XNameContainer > xLib( pLib );
1143 Any aAny = importLibraryElement( xLib,
1144 aElementName,
1145 aSourceStreamName,
1146 xInStream );
1147 if( pLib->hasByName( aElementName ) )
1148 {
1149 if( aAny.hasValue() )
1150 {
1151 pLib->maNameContainer.replaceByName( aElementName, aAny );
1152 }
1153 }
1154 else
1155 {
1156 pLib->maNameContainer.insertByName( aElementName, aAny );
1157 }
1158 }
1159 }
1160 catch (const uno::Exception& )
1161 {
1162 bRet = sal_False;
1163 }
1164 }
1165 }
1166 }
1167 }
1168 catch(const Exception& )
1169 {
1170 // TODO
1171 //throw e;
1172 }
1173 }
1174
1175 return bRet;
1176}
1177
1178
1179void SfxScriptLibraryContainer::onNewRootStorage()
1180{
1181}
1182
1183sal_Bool SAL_CALL SfxScriptLibraryContainer:: HasExecutableCode( const OUString& Library )
1184 throw (uno::RuntimeException)
1185{
1186 BasicManager* pBasicMgr = getBasicManager();
1187 OSL_ENSURE( pBasicMgr, "we need a basicmanager, really we do" );
1188 if ( pBasicMgr )
1189 {
1190 return pBasicMgr->HasExeCode( Library ); // need to change this to take name
1191 }
1192 // default to it has code if we can't decide
1193 return sal_True;
1194}
1195
1196//============================================================================
1197// Service
1198void createRegistryInfo_SfxScriptLibraryContainer()
1199{
1200 static OAutoRegistration< SfxScriptLibraryContainer > aAutoRegistration;
1201}
1202
1203OUString SAL_CALL SfxScriptLibraryContainer::getImplementationName( )
1204 throw (RuntimeException)
1205{
1206 return getImplementationName_static();
1207}
1208
1209Sequence< OUString > SAL_CALL SfxScriptLibraryContainer::getSupportedServiceNames( )
1210 throw (RuntimeException)
1211{
1212 return getSupportedServiceNames_static();
1213}
1214
1215Sequence< OUString > SfxScriptLibraryContainer::getSupportedServiceNames_static()
1216{
1217 Sequence< OUString > aServiceNames( 2 );
1218 aServiceNames[0] = "com.sun.star.script.DocumentScriptLibraryContainer";
1219 // plus, for compatibility:
1220 aServiceNames[1] = "com.sun.star.script.ScriptLibraryContainer";
1221 return aServiceNames;
1222}
1223
1224OUString SfxScriptLibraryContainer::getImplementationName_static()
1225{
1226 return OUString("com.sun.star.comp.sfx2.ScriptLibraryContainer" );
1227}
1228
1229Reference< XInterface > SAL_CALL SfxScriptLibraryContainer::Create( const Reference< XComponentContext >& )
1230 throw( Exception )
1231{
1232 Reference< XInterface > xRet = static_cast< XInterface* >( static_cast< OWeakObject* >(new SfxScriptLibraryContainer()) );
1233 return xRet;
1234}
1235
1236//============================================================================
1237// Implementation class SfxScriptLibrary
1238
1239// Ctor
1240SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper& _rModifiable,
1241 const Reference< XComponentContext >& xContext,
1242 const Reference< XSimpleFileAccess3 >& xSFI )
1243 : SfxLibrary( _rModifiable, getCppuType( (const OUString *)0 ), xContext, xSFI )
1244 , mbLoadedSource( false )
1245 , mbLoadedBinary( false )
1246{
1247}
1248
1249SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper& _rModifiable,
1250 const Reference< XComponentContext >& xContext,
1251 const Reference< XSimpleFileAccess3 >& xSFI,
1252 const OUString& aLibInfoFileURL,
1253 const OUString& aStorageURL,
1254 sal_Bool ReadOnly )
1255 : SfxLibrary( _rModifiable, getCppuType( (const OUString *)0 ), xContext, xSFI,
1256 aLibInfoFileURL, aStorageURL, ReadOnly)
1257 , mbLoadedSource( false )
1258 , mbLoadedBinary( false )
1259{
1260}
1261
1262// Provide modify state including resources
1263sal_Bool SfxScriptLibrary::isModified( void )
1264{
1265 return implIsModified(); // No resources
1266}
1267
1268void SfxScriptLibrary::storeResources( void )
1269{
1270 // No resources
1271}
1272
1273void SfxScriptLibrary::storeResourcesToURL( const OUString& URL,
1274 const Reference< task::XInteractionHandler >& Handler )
1275{
1276 (void)URL;
1277 (void)Handler;
1278}
1279
1280void SfxScriptLibrary::storeResourcesAsURL
1281 ( const OUString& URL, const OUString& NewName )
1282{
1283 (void)URL;
1284 (void)NewName;
1285}
1286
1287void SfxScriptLibrary::storeResourcesToStorage( const ::com::sun::star::uno::Reference
1288 < ::com::sun::star::embed::XStorage >& xStorage )
1289{
1290 // No resources
1291 (void)xStorage;
1292}
1293
1294bool SfxScriptLibrary::containsValidModule( const Any& aElement )
1295{
1296 OUString sModuleText;
1297 aElement >>= sModuleText;
1298 return ( !sModuleText.isEmpty() );
1299}
1300
1301bool SAL_CALL SfxScriptLibrary::isLibraryElementValid( ::com::sun::star::uno::Any aElement ) const
1302{
1303 return SfxScriptLibrary::containsValidModule( aElement );
1304}
1305
1306IMPLEMENT_FORWARD_XINTERFACE2( SfxScriptLibrary, SfxLibrary, SfxScriptLibrary_BASE );
1307IMPLEMENT_FORWARD_XTYPEPROVIDER2( SfxScriptLibrary, SfxLibrary, SfxScriptLibrary_BASE );
1308
1309script::ModuleInfo SAL_CALL SfxScriptLibrary::getModuleInfo( const OUString& ModuleName )
1310 throw (NoSuchElementException, WrappedTargetException, RuntimeException)
1311{
1312 if ( !hasModuleInfo( ModuleName ) )
1313 {
1314 throw NoSuchElementException();
1315 }
1316 return mModuleInfos[ ModuleName ];
1317}
1318
1319sal_Bool SAL_CALL SfxScriptLibrary::hasModuleInfo( const OUString& ModuleName )
1320 throw (RuntimeException)
1321{
1322 sal_Bool bRes = sal_False;
1323 ModuleInfoMap::iterator it = mModuleInfos.find( ModuleName );
1324
1325 if ( it != mModuleInfos.end() )
1326 {
1327 bRes = sal_True;
1328 }
1329 return bRes;
1330}
1331
1332void SAL_CALL SfxScriptLibrary::insertModuleInfo( const OUString& ModuleName, const script::ModuleInfo& ModuleInfo )
1333 throw (IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException)
1334{
1335 if ( hasModuleInfo( ModuleName ) )
1336 {
1337 throw ElementExistException();
1338 }
1339 mModuleInfos[ ModuleName ] = ModuleInfo;
1340}
1341
1342void SAL_CALL SfxScriptLibrary::removeModuleInfo( const OUString& ModuleName )
1343 throw (NoSuchElementException, WrappedTargetException, RuntimeException)
1344{
1345 // #FIXME add NoSuchElementException to the spec
1346 if ( !hasModuleInfo( ModuleName ) )
1347 {
1348 throw NoSuchElementException();
1349 }
1350 mModuleInfos.erase( mModuleInfos.find( ModuleName ) );
1351}
1352
1353
1354//============================================================================
1355
1356} // namespace basic
1357
1358/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1359