1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_dbaccess.hxx"
26 
27 #include "dbmm_global.hrc"
28 #include "dbmm_module.hxx"
29 #include "dbmm_types.hxx"
30 #include "docinteraction.hxx"
31 #include "migrationengine.hxx"
32 #include "migrationerror.hxx"
33 #include "migrationprogress.hxx"
34 #include "migrationlog.hxx"
35 #include "progresscapture.hxx"
36 #include "progressmixer.hxx"
37 
38 /** === begin UNO includes === **/
39 #include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
40 #include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
41 #include <com/sun/star/util/XCloseable.hpp>
42 #include <com/sun/star/frame/XModel.hpp>
43 #include <com/sun/star/frame/XComponentLoader.hpp>
44 #include <com/sun/star/ucb/XCommandProcessor.hpp>
45 #include <com/sun/star/ucb/XContent.hpp>
46 #include <com/sun/star/embed/XComponentSupplier.hpp>
47 #include <com/sun/star/embed/ElementModes.hpp>
48 #include <com/sun/star/document/XStorageBasedDocument.hpp>
49 #include <com/sun/star/embed/XTransactedObject.hpp>
50 #include <com/sun/star/frame/XStorable.hpp>
51 #include <com/sun/star/embed/XEmbedPersist.hpp>
52 #include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
53 #include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
54 #include <com/sun/star/document/XEmbeddedScripts.hpp>
55 #include <com/sun/star/document/XEventsSupplier.hpp>
56 #include <com/sun/star/uri/UriReferenceFactory.hpp>
57 #include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
58 #include <com/sun/star/form/XFormsSupplier.hpp>
59 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
60 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
61 #include <com/sun/star/script/XEventAttacherManager.hpp>
62 #include <com/sun/star/script/XLibraryContainerPassword.hpp>
63 #include <com/sun/star/io/WrongFormatException.hpp>
64 #include <com/sun/star/script/XScriptEventsSupplier.hpp>
65 #include <com/sun/star/io/XInputStreamProvider.hpp>
66 /** === end UNO includes === **/
67 
68 #include <comphelper/documentinfo.hxx>
69 #include <comphelper/interaction.hxx>
70 #include <comphelper/namedvaluecollection.hxx>
71 #include <comphelper/storagehelper.hxx>
72 #include <comphelper/string.hxx>
73 #include <comphelper/types.hxx>
74 #include <cppuhelper/exc_hlp.hxx>
75 #include <tools/string.hxx>
76 #include <tools/diagnose_ex.h>
77 #include <rtl/ustrbuf.hxx>
78 #include <rtl/ref.hxx>
79 #include <unotools/sharedunocomponent.hxx>
80 #include <xmlscript/xmldlg_imexp.hxx>
81 
82 #include <vector>
83 #include <set>
84 
85 #define DEFAULT_DOC_PROGRESS_RANGE  100000
86 
87 //........................................................................
88 namespace dbmm
89 {
90 //........................................................................
91 
92 	/** === begin UNO using === **/
93 	using ::com::sun::star::uno::Reference;
94 	using ::com::sun::star::uno::XInterface;
95 	using ::com::sun::star::uno::UNO_QUERY;
96 	using ::com::sun::star::uno::UNO_QUERY_THROW;
97 	using ::com::sun::star::uno::UNO_SET_THROW;
98 	using ::com::sun::star::uno::Exception;
99 	using ::com::sun::star::uno::RuntimeException;
100 	using ::com::sun::star::uno::Any;
101 	using ::com::sun::star::uno::makeAny;
102     using ::com::sun::star::sdb::XOfficeDatabaseDocument;
103     using ::com::sun::star::sdb::XFormDocumentsSupplier;
104     using ::com::sun::star::sdb::XReportDocumentsSupplier;
105     using ::com::sun::star::container::XNameAccess;
106     using ::com::sun::star::uno::Sequence;
107     using ::com::sun::star::util::XCloseable;
108     using ::com::sun::star::util::CloseVetoException;
109     using ::com::sun::star::lang::XComponent;
110     using ::com::sun::star::frame::XModel;
111     using ::com::sun::star::frame::XComponentLoader;
112     using ::com::sun::star::ucb::XCommandProcessor;
113     using ::com::sun::star::ucb::XContent;
114     using ::com::sun::star::ucb::Command;
115     using ::com::sun::star::embed::XComponentSupplier;
116     using ::com::sun::star::task::XStatusIndicator;
117     using ::com::sun::star::embed::XStorage;
118     using ::com::sun::star::document::XStorageBasedDocument;
119     using ::com::sun::star::embed::XTransactedObject;
120     using ::com::sun::star::frame::XStorable;
121     using ::com::sun::star::embed::XEmbedPersist;
122     using ::com::sun::star::script::DocumentDialogLibraryContainer;
123     using ::com::sun::star::script::DocumentScriptLibraryContainer;
124     using ::com::sun::star::script::XStorageBasedLibraryContainer;
125     using ::com::sun::star::document::XEmbeddedScripts;
126     using ::com::sun::star::container::XNameContainer;
127     using ::com::sun::star::document::XEventsSupplier;
128     using ::com::sun::star::container::XNameReplace;
129     using com::sun::star::uri::UriReferenceFactory;
130     using com::sun::star::uri::XUriReferenceFactory;
131     using com::sun::star::uri::XVndSunStarScriptUrlReference;
132     using ::com::sun::star::form::XFormsSupplier;
133     using ::com::sun::star::drawing::XDrawPageSupplier;
134     using ::com::sun::star::drawing::XDrawPagesSupplier;
135     using ::com::sun::star::drawing::XDrawPage;
136     using ::com::sun::star::drawing::XDrawPages;
137     using ::com::sun::star::container::XIndexAccess;
138     using ::com::sun::star::script::XEventAttacherManager;
139     using ::com::sun::star::script::ScriptEventDescriptor;
140     using ::com::sun::star::script::XLibraryContainerPassword;
141     using ::com::sun::star::io::WrongFormatException;
142     using ::com::sun::star::script::XScriptEventsSupplier;
143     using ::com::sun::star::io::XInputStreamProvider;
144     using ::com::sun::star::io::XInputStream;
145     /** === end UNO using === **/
146     namespace ElementModes = ::com::sun::star::embed::ElementModes;
147 
148 // migration phases whose progresses are to be mixed into one progress
149 #define PHASE_JAVASCRIPT    1
150 #define PHASE_BEANSHELL     2
151 #define PHASE_PYTHON        3
152 #define PHASE_JAVA          4
153 #define PHASE_BASIC         5
154 #define PHASE_DIALOGS       6
155 
156     //====================================================================
157     //= SubDocument
158     //====================================================================
159     struct SubDocument
160     {
161         Reference< XCommandProcessor >  xCommandProcessor;
162         Reference< XModel >             xDocument;          // valid only temporarily
163         ::rtl::OUString                 sHierarchicalName;
164         SubDocumentType                 eType;
165         size_t                          nNumber;
166 
SubDocumentdbmm::SubDocument167         SubDocument( const Reference< XCommandProcessor >& _rxCommandProcessor, const ::rtl::OUString& _rName,
168                 const SubDocumentType _eType, const size_t _nNumber )
169             :xCommandProcessor( _rxCommandProcessor )
170             ,xDocument()
171             ,sHierarchicalName( _rName )
172             ,eType( _eType )
173             ,nNumber( _nNumber )
174         {
175         }
176     };
177 
178     typedef ::std::vector< SubDocument >    SubDocuments;
179 
180     //====================================================================
181 	//= helper
182 	//====================================================================
183     //--------------------------------------------------------------------
184     typedef ::utl::SharedUNOComponent< XStorage >   SharedStorage;
185 
186     namespace
187     {
188 	    //----------------------------------------------------------------
lcl_getScriptsStorageName()189         static const ::rtl::OUString& lcl_getScriptsStorageName()
190         {
191             static const ::rtl::OUString s_sScriptsStorageName( RTL_CONSTASCII_USTRINGPARAM( "Scripts" ) );
192             return s_sScriptsStorageName;
193         }
194 
195 	    //----------------------------------------------------------------
lcl_getScriptsSubStorageName(const ScriptType _eType)196         static const ::rtl::OUString& lcl_getScriptsSubStorageName( const ScriptType _eType )
197         {
198             static const ::rtl::OUString s_sBeanShell ( RTL_CONSTASCII_USTRINGPARAM( "beanshell" ) );
199             static const ::rtl::OUString s_sJavaScript( RTL_CONSTASCII_USTRINGPARAM( "javascript" ) );
200             static const ::rtl::OUString s_sPython    ( RTL_CONSTASCII_USTRINGPARAM( "python" ) );      // TODO: is this correct?
201             static const ::rtl::OUString s_sJava      ( RTL_CONSTASCII_USTRINGPARAM( "java" ) );
202 
203             switch ( _eType )
204             {
205             case eBeanShell:    return s_sBeanShell;
206             case eJavaScript:   return s_sJavaScript;
207             case ePython:       return s_sPython;
208             case eJava:         return s_sJava;
209             default:
210                 break;
211             }
212 
213             OSL_ENSURE( false, "lcl_getScriptsSubStorageName: illegal type!" );
214             static ::rtl::OUString s_sEmpty;
215             return s_sEmpty;
216         }
217 
218 	    //----------------------------------------------------------------
lcl_getScriptTypeFromLanguage(const::rtl::OUString & _rLanguage,ScriptType & _out_rScriptType)219         static bool lcl_getScriptTypeFromLanguage( const ::rtl::OUString& _rLanguage, ScriptType& _out_rScriptType )
220         {
221             struct LanguageMapping
222             {
223                 const sal_Char*     pAsciiLanguage;
224                 const ScriptType    eScriptType;
225 
226                 LanguageMapping( const sal_Char* _pAsciiLanguage, const ScriptType _eScriptType )
227                     :pAsciiLanguage( _pAsciiLanguage )
228                     ,eScriptType( _eScriptType )
229                 {
230                 }
231             }
232             aLanguageMapping[] =
233             {
234                 LanguageMapping( "JavaScript", eJavaScript ),
235                 LanguageMapping( "BeanShell",  eBeanShell ),
236                 LanguageMapping( "Java",       eJava ),
237                 LanguageMapping( "Python",     ePython ),          // TODO: is this correct?
238                 LanguageMapping( "Basic",      eBasic )
239             };
240             for ( size_t i=0; i < sizeof( aLanguageMapping ) / sizeof( aLanguageMapping[0] ); ++i )
241             {
242                 if ( _rLanguage.equalsAscii( aLanguageMapping[i].pAsciiLanguage ) )
243                 {
244                     _out_rScriptType = aLanguageMapping[i].eScriptType;
245                     return true;
246                 }
247             }
248             OSL_ENSURE( false, "lcl_getScriptTypeFromLanguage: unknown language!" );
249             return false;
250         }
251 
252         //----------------------------------------------------------------
lcl_getSubDocumentDescription(const SubDocument & _rDocument)253         ::rtl::OUString lcl_getSubDocumentDescription( const SubDocument& _rDocument )
254         {
255             ::rtl::OUString sObjectName = String( MacroMigrationResId( _rDocument.eType == eForm ? STR_FORM : STR_REPORT ) );
256             ::comphelper::string::searchAndReplaceAsciiI( sObjectName, "$name$", _rDocument.sHierarchicalName );
257             return sObjectName;
258         }
259 
260         //----------------------------------------------------------------
lcl_executeCommand_throw(const Reference<XCommandProcessor> & _rxCommandProc,const sal_Char * _pAsciiCommand)261         static Any lcl_executeCommand_throw( const Reference< XCommandProcessor >& _rxCommandProc,
262             const sal_Char* _pAsciiCommand )
263         {
264             OSL_PRECOND( _rxCommandProc.is(), "lcl_executeCommand_throw: illegal object!" );
265             if ( !_rxCommandProc.is() )
266                 return Any();
267 
268             Command aCommand;
269             aCommand.Name = ::rtl::OUString::createFromAscii( _pAsciiCommand );
270             return _rxCommandProc->execute(
271                 aCommand, _rxCommandProc->createCommandIdentifier(), NULL );
272         }
273 
274         //----------------------------------------------------------------
lcl_getMimeType_nothrow(const Reference<XCommandProcessor> & _rxContent)275         ::rtl::OUString lcl_getMimeType_nothrow( const Reference< XCommandProcessor >& _rxContent )
276         {
277             ::rtl::OUString sMimeType;
278             try
279             {
280                 Reference< XContent > xContent( _rxContent, UNO_QUERY_THROW );
281                 sMimeType = xContent->getContentType();
282             }
283             catch( const Exception& )
284             {
285             	DBG_UNHANDLED_EXCEPTION();
286             }
287             return sMimeType;
288         }
289 
290         //----------------------------------------------------------------
291         enum OpenDocResult
292         {
293             eOpenedDoc,
294             eIgnoreDoc,
295             eFailure
296         };
297 
298         //----------------------------------------------------------------
lcl_loadSubDocument_nothrow(SubDocument & _rDocument,const Reference<XStatusIndicator> & _rxProgress,MigrationLog & _rLogger)299         static OpenDocResult lcl_loadSubDocument_nothrow( SubDocument& _rDocument,
300             const Reference< XStatusIndicator >& _rxProgress, MigrationLog& _rLogger )
301         {
302             OSL_PRECOND( !_rDocument.xDocument.is(), "lcl_loadSubDocument_nothrow: already loaded!" );
303 
304             try
305             {
306                 ::comphelper::NamedValueCollection aLoadArgs;
307                 aLoadArgs.put( "Hidden", (sal_Bool)sal_True );
308                 aLoadArgs.put( "StatusIndicator", _rxProgress );
309 
310                 Reference< XCommandProcessor > xCommandProcessor( _rDocument.xCommandProcessor, UNO_SET_THROW );
311                 Command aCommand;
312                 aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "openDesign" ) );
313                 aCommand.Argument <<= aLoadArgs.getPropertyValues();
314                 Reference< XComponent > xDocComponent(
315                     xCommandProcessor->execute(
316                         aCommand, xCommandProcessor->createCommandIdentifier(), NULL
317                     ),
318                     UNO_QUERY
319                 );
320                 OSL_ENSURE( xDocComponent.is(), "lcl_loadSubDocument_nothrow: no component loaded!" );
321 
322                 _rDocument.xDocument.set( xDocComponent, UNO_QUERY_THROW );
323             }
324             catch( const Exception& )
325             {
326                 Any aError( ::cppu::getCaughtException() );
327 
328                 bool bCausedByNewStyleReport =
329                         ( _rDocument.eType == eReport )
330                     &&  ( aError.isExtractableTo( ::cppu::UnoType< WrongFormatException >::get() ) )
331                     &&  ( lcl_getMimeType_nothrow( _rDocument.xCommandProcessor ).equalsAscii( "application/vnd.sun.xml.report" ) );
332 
333                 if ( bCausedByNewStyleReport )
334                 {
335                     _rLogger.logRecoverable( MigrationError(
336                         ERR_NEW_STYLE_REPORT,
337                         lcl_getSubDocumentDescription( _rDocument )
338                     ) );
339                     return eIgnoreDoc;
340                 }
341                 else
342                 {
343                     _rLogger.logFailure( MigrationError(
344                         ERR_OPENING_SUB_DOCUMENT_FAILED,
345                         lcl_getSubDocumentDescription( _rDocument ),
346                         aError
347                     ) );
348                 }
349             }
350             return _rDocument.xDocument.is() ? eOpenedDoc : eFailure;
351         }
352 
353 	    //----------------------------------------------------------------
lcl_unloadSubDocument_nothrow(SubDocument & _rDocument,MigrationLog & _rLogger)354         static bool lcl_unloadSubDocument_nothrow( SubDocument& _rDocument, MigrationLog& _rLogger )
355         {
356             bool bSuccess = false;
357             Any aException;
358             try
359             {
360                 OSL_VERIFY( lcl_executeCommand_throw( _rDocument.xCommandProcessor, "close" ) >>= bSuccess );
361             }
362             catch( const Exception& )
363             {
364                 aException = ::cppu::getCaughtException();
365             }
366 
367             // log the failure, if any
368             if ( !bSuccess )
369             {
370                 _rLogger.logFailure( MigrationError(
371                     ERR_CLOSING_SUB_DOCUMENT_FAILED,
372                     lcl_getSubDocumentDescription( _rDocument ),
373                     aException
374                 ) );
375             }
376 
377             _rDocument.xDocument.clear();
378             return bSuccess;
379         }
380 
381         //----------------------------------------------------------------
lcl_commitStorage_nothrow(const Reference<XStorage> & _rxStorage)382         bool lcl_commitStorage_nothrow( const Reference< XStorage >& _rxStorage )
383         {
384             try
385             {
386                 Reference< XTransactedObject > xTrans( _rxStorage, UNO_QUERY_THROW );
387                 xTrans->commit();
388             }
389             catch( const Exception& )
390             {
391             	return false;
392             }
393             return true;
394         }
395 
396         //----------------------------------------------------------------
lcl_commitDocumentStorage_nothrow(const Reference<XModel> & _rxDocument,MigrationLog & _rLogger)397         bool lcl_commitDocumentStorage_nothrow( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger )
398         {
399             bool bSuccess = false;
400             Any aException;
401             try
402             {
403                 Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW );
404                 Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW );
405                 bSuccess = lcl_commitStorage_nothrow( xDocStorage );
406             }
407             catch( const Exception& )
408             {
409                 aException = ::cppu::getCaughtException();
410             }
411 
412             // log the failure, if any
413             if ( !bSuccess )
414             {
415                 _rLogger.logFailure( MigrationError(
416                     ERR_STORAGE_COMMIT_FAILED,
417                     ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ),
418                     aException
419                 ) );
420             }
421         	return bSuccess;
422         }
423 
424         //----------------------------------------------------------------
lcl_storeDocument_nothrow(const Reference<XModel> & _rxDocument,MigrationLog & _rLogger)425         bool lcl_storeDocument_nothrow( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger )
426         {
427             bool bSuccess = false;
428             Any aException;
429             try
430             {
431                 Reference< XStorable > xStorable( _rxDocument, UNO_QUERY_THROW );
432                 xStorable->store();
433                 bSuccess = true;
434             }
435             catch( const Exception& )
436             {
437                 aException = ::cppu::getCaughtException();
438             }
439 
440             // log the failure, if any
441             if ( !bSuccess )
442             {
443                 _rLogger.logFailure( MigrationError(
444                     ERR_STORING_DATABASEDOC_FAILED,
445                     aException
446                 ) );
447             }
448         	return bSuccess;
449         }
450 
451         //----------------------------------------------------------------
lcl_storeEmbeddedDocument_nothrow(const SubDocument & _rDocument)452         bool lcl_storeEmbeddedDocument_nothrow( const SubDocument& _rDocument )
453         {
454             try
455             {
456                 lcl_executeCommand_throw( _rDocument.xCommandProcessor, "store" );
457             }
458             catch( const Exception& )
459             {
460             	DBG_UNHANDLED_EXCEPTION();
461                 return false;
462             }
463             return true;
464         }
465     }
466 
467     //====================================================================
468 	//= DrawPageIterator
469 	//====================================================================
470     class DrawPageIterator
471     {
472     public:
DrawPageIterator(const Reference<XModel> & _rxDocument)473         DrawPageIterator( const Reference< XModel >& _rxDocument )
474             :m_xDocument( _rxDocument )
475             ,m_nPageCount( 0 )
476             ,m_nCurrentPage( 0 )
477         {
478             Reference< XDrawPageSupplier > xSingle( _rxDocument, UNO_QUERY );
479             Reference< XDrawPagesSupplier > xMulti( _rxDocument, UNO_QUERY );
480             if ( xSingle.is() )
481             {
482                 m_xSinglePage.set( xSingle->getDrawPage(), UNO_SET_THROW );
483                 m_nPageCount = 1;
484             }
485             else if ( xMulti.is() )
486             {
487                 m_xMultiPages.set( xMulti->getDrawPages(), UNO_SET_THROW );
488                 m_nPageCount = m_xMultiPages->getCount();
489             }
490         }
491 
hasMore() const492         bool hasMore() const
493         {
494             return m_nCurrentPage < m_nPageCount;
495         }
496 
next()497         Reference< XDrawPage > next()
498         {
499             Reference< XDrawPage > xNextPage;
500 
501             if ( m_xSinglePage.is() )
502             {
503                 xNextPage = m_xSinglePage;
504             }
505             else if ( m_xMultiPages.is() )
506             {
507                 xNextPage.set( m_xMultiPages->getByIndex( m_nCurrentPage ), UNO_QUERY_THROW );
508             }
509             ++m_nCurrentPage;
510             return xNextPage;
511         }
512 
513     private:
514         const Reference< XModel >   m_xDocument;
515         Reference< XDrawPage >      m_xSinglePage;
516         Reference< XDrawPages >     m_xMultiPages;
517         sal_Int32                   m_nPageCount;
518         sal_Int32                   m_nCurrentPage;
519     };
520 
521     //====================================================================
522 	//= FormComponentScripts
523 	//====================================================================
524     class FormComponentScripts
525     {
526     public:
FormComponentScripts(const Reference<XInterface> & _rxComponent,const Reference<XEventAttacherManager> & _rxManager,const sal_Int32 _nIndex)527         FormComponentScripts(
528                 const Reference< XInterface >& _rxComponent,
529                 const Reference< XEventAttacherManager >& _rxManager,
530                 const sal_Int32 _nIndex
531             )
532             :m_xComponent( _rxComponent, UNO_SET_THROW )
533             ,m_xManager( _rxManager, UNO_SET_THROW )
534             ,m_nIndex( _nIndex )
535         {
536         }
537 
getEvents() const538         Sequence< ScriptEventDescriptor > getEvents() const
539         {
540             return m_xManager->getScriptEvents( m_nIndex );
541         }
542 
setEvents(const Sequence<ScriptEventDescriptor> & _rEvents) const543         void setEvents( const Sequence< ScriptEventDescriptor >& _rEvents  ) const
544         {
545             m_xManager->registerScriptEvents( m_nIndex, _rEvents );
546         }
547 
getComponent() const548         const Reference< XInterface >& getComponent() const
549         {
550             return m_xComponent;
551         }
552 
553     private:
554         const Reference< XInterface >               m_xComponent;
555         const Reference< XEventAttacherManager >    m_xManager;
556         const sal_Int32                             m_nIndex;
557     };
558 
559     //====================================================================
560 	//= FormComponentIterator
561 	//====================================================================
562     class FormComponentIterator
563     {
564     public:
FormComponentIterator(const Reference<XIndexAccess> & _rxContainer)565         FormComponentIterator( const Reference< XIndexAccess >& _rxContainer )
566             :m_xContainer( _rxContainer, UNO_SET_THROW )
567             ,m_xEventManager( _rxContainer, UNO_QUERY_THROW )
568             ,m_nElementCount( _rxContainer->getCount() )
569             ,m_nCurrentElement( 0 )
570         {
571         }
572 
hasMore() const573         bool hasMore() const
574         {
575             return m_nCurrentElement < m_nElementCount;
576         }
577 
next()578         FormComponentScripts next()
579         {
580             FormComponentScripts aComponent(
581                 Reference< XInterface >( m_xContainer->getByIndex( m_nCurrentElement ), UNO_QUERY_THROW ),
582                 m_xEventManager,
583                 m_nCurrentElement
584             );
585             ++m_nCurrentElement;
586             return aComponent;
587         }
588 
589     private:
590         const Reference< XIndexAccess >             m_xContainer;
591         const Reference< XEventAttacherManager >    m_xEventManager;
592         const sal_Int32                             m_nElementCount;
593         sal_Int32                                   m_nCurrentElement;
594 
595     };
596 
597     //====================================================================
598 	//= ScriptsStorage - declaration
599 	//====================================================================
600     /** a helper class which encapsulates access to the storages for Java/Script, BeanShell, and Python scripts,
601         i.e. all script types which can be manipulated on storage level.
602     */
603     class ScriptsStorage
604     {
605     public:
606         ScriptsStorage( MigrationLog& _rLogger );
607         ScriptsStorage( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger );
608         ~ScriptsStorage();
609 
610         /** determines whether the instance is valid, i.e. refers to a valid root storage
611             for reading/storing scripts
612         */
isValid() const613         inline bool isValid() const { return m_xScriptsStorage.is(); }
614 
615         /** binds the instance to a new document. Only to be called when the instance is not yet
616             bound (i.e. isValid returns <FALSE/>).
617         */
618         void    bind( const Reference< XModel >& _rxDocument );
619 
620         /// determines whether scripts of the given type are present
621         bool    hasScripts( const ScriptType _eType ) const;
622 
623         /// returns the root storage for the scripts of the given type
624         SharedStorage
625                 getScriptsRoot( const ScriptType _eType ) const;
626 
627         /** returns the names of the elements in the "Scripts" storage
628         */
629         ::std::set< ::rtl::OUString >
630                 getElementNames() const;
631 
632         /** removes the sub storage for a given script type
633             @precond
634                 the respective storage is empty
635             @precond
636                 the ScriptsStorage instance was opened for writing
637         */
638         void    removeScriptTypeStorage( const ScriptType _eType ) const;
639 
640         /** commits the changes at our XStorage object
641         */
642         bool    commit();
643 
644         /** removes the "Scripts" sub storage from the given document's root storage
645             @precond
646                 the "Scripts" storage is empty
647         */
648         static bool
649                 removeFromDocument( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger );
650 
651     private:
652         MigrationLog&   m_rLogger;
653         SharedStorage   m_xScriptsStorage;
654     };
655 
656     //====================================================================
657 	//= ScriptsStorage - implementation
658 	//====================================================================
659 	//--------------------------------------------------------------------
ScriptsStorage(MigrationLog & _rLogger)660     ScriptsStorage::ScriptsStorage( MigrationLog& _rLogger )
661         :m_rLogger( _rLogger )
662         ,m_xScriptsStorage()
663     {
664     }
665 
666 	//--------------------------------------------------------------------
ScriptsStorage(const Reference<XModel> & _rxDocument,MigrationLog & _rLogger)667     ScriptsStorage::ScriptsStorage( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger )
668         :m_rLogger( _rLogger )
669         ,m_xScriptsStorage()
670     {
671         bind( _rxDocument );
672     }
673 
674 	//--------------------------------------------------------------------
~ScriptsStorage()675     ScriptsStorage::~ScriptsStorage()
676     {
677     }
678 
679     //--------------------------------------------------------------------
commit()680     bool ScriptsStorage::commit()
681     {
682         return lcl_commitStorage_nothrow( m_xScriptsStorage );
683     }
684 
685 	//--------------------------------------------------------------------
bind(const Reference<XModel> & _rxDocument)686     void ScriptsStorage::bind( const Reference< XModel >& _rxDocument )
687     {
688         OSL_PRECOND( !isValid(), "ScriptsStorage:bind: did not bother, yet, to check whether this is allowed!" );
689         try
690         {
691             Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW );
692             Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW );
693 
694             // the the "Scripts" storage exist, or if it does not (yet) exist and we are in write mode
695             // => open the storage
696             if  (   (   xDocStorage->hasByName( lcl_getScriptsStorageName() )
697                     &&  xDocStorage->isStorageElement( lcl_getScriptsStorageName() )
698                     )
699                 ||  !xDocStorage->hasByName( lcl_getScriptsStorageName() )
700                 )
701             {
702                 m_xScriptsStorage.set(
703                     xDocStorage->openStorageElement(
704                         lcl_getScriptsStorageName(), ElementModes::READWRITE
705                     ),
706                     UNO_QUERY_THROW
707                 );
708             }
709         }
710         catch( const Exception& )
711         {
712             m_rLogger.logFailure( MigrationError(
713                 ERR_BIND_SCRIPT_STORAGE_FAILED,
714                 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ),
715                 ::cppu::getCaughtException()
716             ) );
717         }
718     }
719 
720     //--------------------------------------------------------------------
hasScripts(const ScriptType _eType) const721     bool ScriptsStorage::hasScripts( const ScriptType _eType ) const
722     {
723         OSL_PRECOND( isValid(), "ScriptsStorage::hasScripts: illegal call!" );
724         if ( !isValid() )
725             return false;
726 
727         const ::rtl::OUString& rSubStorageName( lcl_getScriptsSubStorageName( _eType ) );
728         return  m_xScriptsStorage->hasByName( rSubStorageName )
729             &&  m_xScriptsStorage->isStorageElement( rSubStorageName );
730     }
731 
732     //--------------------------------------------------------------------
getScriptsRoot(const ScriptType _eType) const733     SharedStorage ScriptsStorage::getScriptsRoot( const ScriptType _eType ) const
734     {
735         SharedStorage xStorage;
736         if ( isValid() )
737         {
738             xStorage.reset( m_xScriptsStorage->openStorageElement(
739                 lcl_getScriptsSubStorageName( _eType ), ElementModes::READWRITE
740             ) );
741         }
742         return xStorage;
743     }
744 
745     //--------------------------------------------------------------------
getElementNames() const746     ::std::set< ::rtl::OUString > ScriptsStorage::getElementNames() const
747     {
748         Sequence< ::rtl::OUString > aElementNames;
749         if ( isValid() )
750             aElementNames = m_xScriptsStorage->getElementNames();
751 
752         ::std::set< ::rtl::OUString > aNames;
753         ::std::copy(
754             aElementNames.getConstArray(),
755             aElementNames.getConstArray() + aElementNames.getLength(),
756             ::std::insert_iterator< ::std::set< ::rtl::OUString > >( aNames, aNames.end() )
757         );
758         return aNames;
759     }
760 
761     //--------------------------------------------------------------------
removeScriptTypeStorage(const ScriptType _eType) const762     void ScriptsStorage::removeScriptTypeStorage( const ScriptType _eType ) const
763     {
764         ::rtl::OUString sSubStorageName( lcl_getScriptsSubStorageName( _eType ) );
765         if ( m_xScriptsStorage->hasByName( sSubStorageName ) )
766             m_xScriptsStorage->removeElement( sSubStorageName );
767     }
768 
769     //--------------------------------------------------------------------
removeFromDocument(const Reference<XModel> & _rxDocument,MigrationLog & _rLogger)770     bool ScriptsStorage::removeFromDocument( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger )
771     {
772         try
773         {
774             Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW );
775             Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW );
776             xDocStorage->removeElement( lcl_getScriptsStorageName() );
777         }
778         catch( const Exception& )
779         {
780             _rLogger.logFailure( MigrationError(
781                 ERR_REMOVE_SCRIPTS_STORAGE_FAILED,
782                 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ),
783                 ::cppu::getCaughtException()
784             ) ) ;
785             return false;
786         }
787         return true;
788     }
789 
790     //====================================================================
791     //= ProgressDelegator
792     //====================================================================
793     class ProgressDelegator : public IProgressConsumer
794     {
795     public:
ProgressDelegator(IMigrationProgress & _rDelegator,const::rtl::OUString & _rObjectName,const::rtl::OUString & _rAction)796         ProgressDelegator(  IMigrationProgress& _rDelegator,
797                             const ::rtl::OUString& _rObjectName,
798                             const ::rtl::OUString& _rAction
799                           )
800             :m_rDelegator( _rDelegator )
801             ,m_sObjectName( _rObjectName )
802             ,m_sAction( _rAction )
803         {
804         }
~ProgressDelegator()805         virtual ~ProgressDelegator()
806         {
807         }
808 
809         // IProgressConsumer
start(sal_uInt32 _nRange)810         virtual void    start( sal_uInt32 _nRange )
811         {
812             m_rDelegator.startObject( m_sObjectName, m_sAction, _nRange );
813         }
advance(sal_uInt32 _nValue)814         virtual void    advance( sal_uInt32 _nValue )
815         {
816             m_rDelegator.setObjectProgressValue( _nValue );
817         }
end()818         virtual void    end()
819         {
820             m_rDelegator.endObject();
821         }
822 
823     private:
824         IMigrationProgress& m_rDelegator;
825         ::rtl::OUString     m_sObjectName;
826         ::rtl::OUString     m_sAction;
827     };
828 
829 	//====================================================================
830 	//= PhaseGuard
831 	//====================================================================
832     class PhaseGuard
833     {
834     public:
PhaseGuard(ProgressMixer & _rMixer)835         PhaseGuard( ProgressMixer& _rMixer )
836             :m_rMixer( _rMixer )
837         {
838         }
839 
PhaseGuard(ProgressMixer & _rMixer,const PhaseID _nID,const sal_uInt32 _nPhaseRange)840         PhaseGuard( ProgressMixer& _rMixer, const PhaseID _nID, const sal_uInt32 _nPhaseRange )
841             :m_rMixer( _rMixer )
842         {
843             start( _nID, _nPhaseRange );
844         }
845 
~PhaseGuard()846         ~PhaseGuard()
847         {
848             m_rMixer.endPhase();
849         }
850 
start(const PhaseID _nID,const sal_uInt32 _nPhaseRange)851         void start( const PhaseID _nID, const sal_uInt32 _nPhaseRange )
852         {
853             m_rMixer.startPhase( _nID, _nPhaseRange );
854         }
855 
856     private:
857         ProgressMixer&  m_rMixer;
858     };
859 
860 	//====================================================================
861 	//= MigrationEngine_Impl - declaration
862 	//====================================================================
863     class MigrationEngine_Impl
864     {
865     public:
866         MigrationEngine_Impl(
867             const ::comphelper::ComponentContext& _rContext,
868             const Reference< XOfficeDatabaseDocument >& _rxDocument,
869             IMigrationProgress& _rProgress,
870             MigrationLog& _rLogger
871         );
872         ~MigrationEngine_Impl();
873 
getFormCount() const874         inline  size_t      getFormCount() const    { return m_nFormCount; }
getReportCount() const875         inline  size_t      getReportCount()const   { return m_nReportCount; }
876         bool    migrateAll();
877 
878     private:
879         ::comphelper::ComponentContext              m_aContext;
880         const Reference< XOfficeDatabaseDocument >  m_xDocument;
881         const Reference< XModel >                   m_xDocumentModel;
882         IMigrationProgress&                         m_rProgress;
883         MigrationLog&                               m_rLogger;
884         mutable DocumentID                          m_nCurrentDocumentID;
885         SubDocuments                                m_aSubDocs;
886         size_t                                      m_nFormCount;
887         size_t                                      m_nReportCount;
888 
889     private:
890         /** collects a description of all sub documents of our database document
891 
892             @return
893                 <TRUE/> if and only if collecting the documents was successful
894         */
895         bool    impl_collectSubDocuments_nothrow();
896 
897         /** migrates the macros/scripts of the given sub document
898         */
899         bool    impl_handleDocument_nothrow( const SubDocument& _rDocument ) const;
900 
901         /** checks the structure of the 'Scripts' folder of a sub document
902             for unknown elements
903 
904             @return
905                 <TRUE/> if and only if the 'Scripts' folder contains known elements only.
906         */
907         bool    impl_checkScriptStorageStructure_nothrow( const SubDocument& _rDocument ) const;
908 
909         /** migrates the scripts of the given "storage-based" script type
910         */
911         bool    impl_migrateScriptStorage_nothrow(
912                     const SubDocument& _rDocument,
913                     const ScriptType _eScriptType,
914                     ProgressMixer& _rProgress,
915                     const PhaseID _nPhaseID
916                 ) const;
917 
918         /** migrates the content of the given "container based" libraries (Basic/Dialogs)
919         */
920         bool    impl_migrateContainerLibraries_nothrow(
921                     const SubDocument& _rDocument,
922                     const ScriptType _eScriptType,
923                     ProgressMixer& _rProgress,
924                     const PhaseID _nPhaseID
925                 ) const;
926 
927         /** adjusts the events for the given dialog/element, taking into account the new names
928             of the moved libraries
929         */
930         void    impl_adjustDialogElementEvents_throw(
931                     const Reference< XInterface >& _rxElement
932                 ) const;
933 
934         /** adjusts the events in the given dialog, and its controls, taking into account the new names
935             of the moved libraries
936         */
937         bool    impl_adjustDialogEvents_nothrow(
938                     Any& _inout_rDialogLibraryElement,
939                     const ::rtl::OUString& _rDocName,
940                     const ::rtl::OUString& _rDialogLibName,
941                     const ::rtl::OUString& _rDialogName
942                 ) const;
943 
944         /** adjust the document-events which refer to macros/scripts in the document, taking into
945             account the new names of the moved libraries
946         */
947         bool    impl_adjustDocumentEvents_nothrow(
948                     const SubDocument& _rDocument
949                 ) const;
950 
951         /** adjusts the script references bound to form component events
952         */
953         bool    impl_adjustFormComponentEvents_nothrow(
954                     const SubDocument& _rDocument
955                 ) const;
956 
957         /** adjusts the script references for the elements of the given form component container
958         */
959         void    impl_adjustFormComponentEvents_throw(
960                     const Reference< XIndexAccess >& _rxComponentContainer
961                 ) const;
962 
963         /** adjusts the library name in the given script URL, so that it reflects
964             the new name of the library
965 
966             @return <TRUE/>
967                 if and only if adjustments to the script code have been made
968         */
969         bool    impl_adjustScriptLibrary_nothrow(
970                     const ::rtl::OUString& _rScriptType,
971                     ::rtl::OUString& _inout_rScriptCode
972                 ) const;
973 
974         bool    impl_adjustScriptLibrary_nothrow( Any& _inout_rScriptDescriptor ) const;
975         bool    impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor& _inout_rScriptEvent ) const;
976 
977         /** asks the user for a password for the given library, and unprotects the library
978 
979             @return <TRUE/>
980                 if and only if the library could be successfully unprotected
981         */
982         bool    impl_unprotectPasswordLibrary_throw(
983                     const Reference< XLibraryContainerPassword >& _rxPasswordManager,
984                     const ScriptType _eScriptType,
985                     const ::rtl::OUString& _rLibraryName
986                 ) const;
987     };
988 
989 	//====================================================================
990 	//= MigrationEngine_Impl - implementation
991 	//====================================================================
992 	//--------------------------------------------------------------------
MigrationEngine_Impl(const::comphelper::ComponentContext & _rContext,const Reference<XOfficeDatabaseDocument> & _rxDocument,IMigrationProgress & _rProgress,MigrationLog & _rLogger)993     MigrationEngine_Impl::MigrationEngine_Impl( const ::comphelper::ComponentContext& _rContext,
994             const Reference< XOfficeDatabaseDocument >& _rxDocument, IMigrationProgress& _rProgress, MigrationLog& _rLogger )
995         :m_aContext( _rContext )
996         ,m_xDocument( _rxDocument )
997         ,m_xDocumentModel( _rxDocument, UNO_QUERY_THROW )
998         ,m_rProgress( _rProgress )
999         ,m_rLogger( _rLogger )
1000         ,m_nCurrentDocumentID( - 1 )
1001         ,m_aSubDocs()
1002         ,m_nFormCount( 0 )
1003         ,m_nReportCount( 0 )
1004     {
1005         OSL_VERIFY( impl_collectSubDocuments_nothrow() );
1006     }
1007 
1008 	//--------------------------------------------------------------------
~MigrationEngine_Impl()1009     MigrationEngine_Impl::~MigrationEngine_Impl()
1010     {
1011     }
1012 
1013 	//--------------------------------------------------------------------
migrateAll()1014     bool MigrationEngine_Impl::migrateAll()
1015     {
1016         if  ( m_aSubDocs.empty() )
1017         {
1018             OSL_ENSURE( false, "MigrationEngine_Impl::migrateAll: no forms/reports found!" );
1019             // The whole migration wizard is not expected to be called when there are no forms/reports
1020             // with macros, not to mention when there are no forms/reports at all.
1021             return false;
1022         }
1023 
1024         // initialize global progress
1025         sal_Int32 nOverallRange( m_aSubDocs.size() );
1026         String sProgressSkeleton = String( MacroMigrationResId( STR_OVERALL_PROGRESS ) );
1027         sProgressSkeleton.SearchAndReplaceAscii( "$overall$", String::CreateFromInt32( nOverallRange ) );
1028 
1029         m_rProgress.start( nOverallRange );
1030 
1031         for (   SubDocuments::const_iterator doc = m_aSubDocs.begin();
1032                 doc != m_aSubDocs.end();
1033                 ++doc
1034             )
1035         {
1036             sal_Int32 nOverallProgressValue( doc - m_aSubDocs.begin() + 1 );
1037             // update overall progress text
1038             ::rtl::OUString sOverallProgress( sProgressSkeleton );
1039             ::comphelper::string::searchAndReplaceAsciiI( sOverallProgress, "$current$", ::rtl::OUString::valueOf( nOverallProgressValue ) );
1040             m_rProgress.setOverallProgressText( sOverallProgress );
1041 
1042             // migrate document
1043             if ( !impl_handleDocument_nothrow( *doc ) )
1044                 return false;
1045 
1046             // update overall progress vallue
1047             m_rProgress.setOverallProgressValue( nOverallProgressValue );
1048         }
1049 
1050         // commit the root storage of the database document, for all changes made so far to take effect
1051         if ( !lcl_commitDocumentStorage_nothrow( m_xDocumentModel, m_rLogger ) )
1052             return false;
1053 
1054         // save the document
1055         if ( !lcl_storeDocument_nothrow( m_xDocumentModel, m_rLogger ) )
1056             return false;
1057 
1058         return true;
1059     }
1060 
1061 	//--------------------------------------------------------------------
1062     namespace
1063     {
lcl_collectHierarchicalElementNames_throw(const Reference<XNameAccess> & _rxContainer,const::rtl::OUString & _rContainerLoc,SubDocuments & _out_rDocs,const SubDocumentType _eType,size_t & _io_counter)1064         void lcl_collectHierarchicalElementNames_throw(
1065             const Reference< XNameAccess >& _rxContainer, const ::rtl::OUString& _rContainerLoc,
1066             SubDocuments& _out_rDocs, const SubDocumentType _eType, size_t& _io_counter )
1067         {
1068             const ::rtl::OUString sHierarhicalBase(
1069                 _rContainerLoc.getLength()  ?   ::rtl::OUStringBuffer( _rContainerLoc ).appendAscii( "/" ).makeStringAndClear()
1070                                             :   ::rtl::OUString() );
1071 
1072             Sequence< ::rtl::OUString > aElementNames( _rxContainer->getElementNames() );
1073             for (   const ::rtl::OUString* elementName = aElementNames.getConstArray();
1074                     elementName != aElementNames.getConstArray() + aElementNames.getLength();
1075                     ++elementName
1076                 )
1077             {
1078                 Any aElement( _rxContainer->getByName( *elementName ) );
1079                 ::rtl::OUString sElementName( ::rtl::OUStringBuffer( sHierarhicalBase ).append( *elementName ) );
1080 
1081                 Reference< XNameAccess > xSubContainer( aElement, UNO_QUERY );
1082                 if ( xSubContainer.is() )
1083                 {
1084                     lcl_collectHierarchicalElementNames_throw( xSubContainer, sElementName, _out_rDocs, _eType, _io_counter );
1085                 }
1086                 else
1087                 {
1088                     Reference< XCommandProcessor > xCommandProcessor( aElement, UNO_QUERY );
1089                     OSL_ENSURE( xCommandProcessor.is(), "lcl_collectHierarchicalElementNames_throw: no container, and no comand processor? What *is* it, then?!" );
1090                     if ( xCommandProcessor.is() )
1091                     {
1092                         _out_rDocs.push_back( SubDocument( xCommandProcessor, sElementName, _eType, ++_io_counter ) );
1093                     }
1094                 }
1095             }
1096         }
1097     }
1098 
1099     //--------------------------------------------------------------------
impl_collectSubDocuments_nothrow()1100     bool MigrationEngine_Impl::impl_collectSubDocuments_nothrow()
1101     {
1102         OSL_PRECOND( m_xDocument.is(), "MigrationEngine_Impl::impl_collectSubDocuments_nothrow: invalid document!" );
1103         if ( !m_xDocument.is() )
1104             return false;
1105 
1106         try
1107         {
1108             Reference< XNameAccess > xDocContainer( m_xDocument->getFormDocuments(), UNO_SET_THROW );
1109             m_nFormCount = 0;
1110             lcl_collectHierarchicalElementNames_throw( xDocContainer, ::rtl::OUString(), m_aSubDocs, eForm, m_nFormCount );
1111 
1112             xDocContainer.set( m_xDocument->getReportDocuments(), UNO_SET_THROW );
1113             m_nReportCount = 0;
1114             lcl_collectHierarchicalElementNames_throw( xDocContainer, ::rtl::OUString(), m_aSubDocs, eReport, m_nReportCount );
1115         }
1116         catch( const Exception& )
1117         {
1118             m_rLogger.logFailure( MigrationError(
1119                 ERR_COLLECTING_DOCUMENTS_FAILED,
1120                 ::cppu::getCaughtException()
1121             ) );
1122             return false;
1123         }
1124         return true;
1125     }
1126 
1127 	//--------------------------------------------------------------------
impl_handleDocument_nothrow(const SubDocument & _rDocument) const1128     bool MigrationEngine_Impl::impl_handleDocument_nothrow( const SubDocument& _rDocument ) const
1129     {
1130         OSL_ENSURE( m_nCurrentDocumentID == -1,
1131             "MigrationEngine_Impl::impl_handleDocument_nothrow: there already is a current document!");
1132         m_nCurrentDocumentID = m_rLogger.startedDocument( _rDocument.eType, _rDocument.sHierarchicalName );
1133 
1134         // start the progress
1135         ::rtl::OUString sObjectName( lcl_getSubDocumentDescription( _rDocument ) );
1136         m_rProgress.startObject( sObjectName, ::rtl::OUString(), DEFAULT_DOC_PROGRESS_RANGE );
1137 
1138         // -----------------
1139         // load the document
1140         ::rtl::Reference< ProgressCapture > pStatusIndicator( new ProgressCapture( sObjectName, m_rProgress ) );
1141         SubDocument aSubDocument( _rDocument );
1142         OpenDocResult eResult = lcl_loadSubDocument_nothrow( aSubDocument, pStatusIndicator.get(), m_rLogger );
1143         if ( eResult != eOpenedDoc )
1144         {
1145             pStatusIndicator->dispose();
1146             m_rProgress.endObject();
1147             m_rLogger.finishedDocument( m_nCurrentDocumentID );
1148 			m_nCurrentDocumentID = -1;
1149             return ( eResult == eIgnoreDoc );
1150         }
1151 
1152         // -----------------
1153         // migrate the libraries
1154         ProgressDelegator aDelegator( m_rProgress, sObjectName, String( MacroMigrationResId( STR_MIGRATING_LIBS ) ) );
1155         ProgressMixer aProgressMixer( aDelegator );
1156         aProgressMixer.registerPhase( PHASE_JAVASCRIPT, 1 );
1157         aProgressMixer.registerPhase( PHASE_BEANSHELL, 1 );
1158         aProgressMixer.registerPhase( PHASE_PYTHON, 1 );
1159         aProgressMixer.registerPhase( PHASE_JAVA, 1 );
1160         aProgressMixer.registerPhase( PHASE_BASIC, 5 );
1161             // more weight than then others, assuming that usually, there are much more Basic macros than any other scripts
1162         aProgressMixer.registerPhase( PHASE_DIALOGS, 1 );
1163 
1164         bool bSuccess = impl_checkScriptStorageStructure_nothrow( aSubDocument );
1165 
1166         // migrate storage-based script libraries (which can be handled by mere storage operations)
1167         bSuccess = bSuccess
1168             &&  impl_migrateScriptStorage_nothrow( aSubDocument, eJavaScript, aProgressMixer, PHASE_JAVASCRIPT )
1169             &&  impl_migrateScriptStorage_nothrow( aSubDocument, eBeanShell, aProgressMixer, PHASE_BEANSHELL )
1170             &&  impl_migrateScriptStorage_nothrow( aSubDocument, ePython, aProgressMixer, PHASE_PYTHON )
1171             &&  impl_migrateScriptStorage_nothrow( aSubDocument, eJava, aProgressMixer, PHASE_JAVA );
1172 
1173         // migrate Basic and dialog libraries
1174         bSuccess =  bSuccess
1175                 &&  impl_migrateContainerLibraries_nothrow( aSubDocument, eBasic, aProgressMixer, PHASE_BASIC )
1176                 &&  impl_migrateContainerLibraries_nothrow( aSubDocument, eDialog, aProgressMixer, PHASE_DIALOGS );
1177                 // order matters: First Basic scripts, then dialogs. So we can adjust references from the latter
1178                 // to the former
1179 
1180         // adjust the events in the document
1181         // (note that errors are ignored here - failure to convert a script reference
1182         // is not considered a critical error)
1183         if ( bSuccess )
1184         {
1185             impl_adjustDocumentEvents_nothrow( aSubDocument );
1186             impl_adjustFormComponentEvents_nothrow( aSubDocument );
1187         }
1188 
1189         // -----------------
1190         // clean up
1191         // store the sub document, including removal of the (now obsolete) "Scripts" sub folder
1192         if ( m_rLogger.movedAnyLibrary( m_nCurrentDocumentID ) )
1193         {
1194             bSuccess =  bSuccess
1195                     &&  ScriptsStorage::removeFromDocument( aSubDocument.xDocument, m_rLogger )
1196                     &&  lcl_commitDocumentStorage_nothrow( aSubDocument.xDocument, m_rLogger )
1197                     &&  lcl_storeEmbeddedDocument_nothrow( aSubDocument );
1198         }
1199 
1200         // unload in any case, even if we were not successful
1201         bSuccess =  lcl_unloadSubDocument_nothrow( aSubDocument, m_rLogger )
1202                 &&  bSuccess;
1203 
1204         pStatusIndicator->dispose();
1205 
1206         // end the progress, just in case the ProgressCapture didn't receive the XStatusIndicator::end event
1207         m_rProgress.endObject();
1208 
1209         m_rLogger.finishedDocument( m_nCurrentDocumentID );
1210         m_nCurrentDocumentID = -1;
1211         return bSuccess;
1212     }
1213 
1214 	//--------------------------------------------------------------------
1215     namespace
1216     {
lcl_createTargetLibName(const SubDocument & _rDocument,const::rtl::OUString & _rSourceLibName,const Reference<XNameAccess> & _rxTargetContainer)1217         static ::rtl::OUString lcl_createTargetLibName( const SubDocument& _rDocument,
1218             const ::rtl::OUString& _rSourceLibName, const Reference< XNameAccess >& _rxTargetContainer )
1219         {
1220             // The new library name is composed from the prefix, the base name, and the old library name.
1221             const ::rtl::OUString sPrefix( ::rtl::OUString::createFromAscii( _rDocument.eType == eForm ? "Form_" : "Report_" ) );
1222 
1223             ::rtl::OUString sBaseName( _rDocument.sHierarchicalName.copy(
1224                 _rDocument.sHierarchicalName.lastIndexOf( '/' ) + 1 ) );
1225             // Normalize this name. In our current storage implementation (and script containers in a document
1226             // are finally mapped to sub storages of the document storage), not all characters are allowed.
1227             // The bug requesting to change this is #i95409#.
1228             // Unfortunately, the storage implementation does not complain if you use invalid characters/names, but instead
1229             // it silently accepts them, and produces garbage in the file (#i95408).
1230             // So, until especially the former is fixed, we need to strip the name from all invalid characters.
1231             // #i95865# / 2008-11-06 / frank.schoenheit@sun.com
1232 
1233             // The general idea is to replace invalid characters with '_'. However, since "valid" essentially means
1234             // ASCII only, this implies that for a lot of languages, we would simply replace everything with '_',
1235             // which of course is not desired.
1236             // So, we use a heuristics: If the name contains at most 3 invalid characters, and as many valid as invalid
1237             // characters, then we use the replacement. Otherwise, we just use a unambiguous number for the sub document.
1238             sal_Int32 nValid=0, nInvalid=0;
1239             const sal_Unicode* pBaseName = sBaseName.getStr();
1240             const sal_Int32 nBaseNameLen = sBaseName.getLength();
1241             for ( sal_Int32 i=0; i<nBaseNameLen; ++i )
1242             {
1243                 if ( ::comphelper::OStorageHelper::IsValidZipEntryFileName( pBaseName + i, 1, sal_False ) )
1244                     ++nValid;
1245                 else
1246                     ++nInvalid;
1247             }
1248             if ( ( nInvalid <= 3 ) && ( nInvalid * 2 <= nValid ) )
1249             {   // not "too many" invalid => replace them
1250                 ::rtl::OUStringBuffer aReplacement;
1251                 aReplacement.ensureCapacity( nBaseNameLen );
1252                 aReplacement.append( sBaseName );
1253                 const sal_Unicode* pReplacement = aReplacement.getStr();
1254                 for ( sal_Int32 i=0; i<nBaseNameLen; ++i )
1255                 {
1256                     if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( pReplacement + i, 1, sal_False ) )
1257                         aReplacement.setCharAt( i, '_' );
1258                 }
1259                 sBaseName = aReplacement.makeStringAndClear();
1260 
1261                 ::rtl::OUStringBuffer aNewLibNameAttempt;
1262                 aNewLibNameAttempt.append( sPrefix );
1263                 aNewLibNameAttempt.append( sBaseName );
1264                 aNewLibNameAttempt.appendAscii( "_" );
1265                 aNewLibNameAttempt.append( _rSourceLibName );
1266                 ::rtl::OUString sTargetName( aNewLibNameAttempt.makeStringAndClear() );
1267                 if ( !_rxTargetContainer->hasByName( sTargetName ) )
1268                     return sTargetName;
1269             }
1270 
1271             // "too many" invalid characters, or the name composed with the base name was already used.
1272             // (The latter is valid, since there can be multiple sub documents with the same base name,
1273             // in different levels in the hierarchy.)
1274             // In this case, just use the umambiguous sub document number.
1275             ::rtl::OUStringBuffer aNewLibName;
1276             aNewLibName.append( sPrefix );
1277             aNewLibName.append( ::rtl::OUString::valueOf( sal_Int64( _rDocument.nNumber ) ) );
1278             aNewLibName.appendAscii( "_" );
1279             aNewLibName.append( _rSourceLibName );
1280             return aNewLibName.makeStringAndClear();
1281         }
1282     }
1283 
1284     //--------------------------------------------------------------------
impl_checkScriptStorageStructure_nothrow(const SubDocument & _rDocument) const1285     bool MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow( const SubDocument& _rDocument ) const
1286     {
1287         OSL_PRECOND( _rDocument.xDocument.is(), "MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow: invalid document!" );
1288         if ( !_rDocument.xDocument.is() )
1289             return false;
1290 
1291         try
1292         {
1293             // the root storage of the document whose scripts are to be migrated
1294             ScriptsStorage aDocStorage( _rDocument.xDocument, m_rLogger );
1295             if  ( !aDocStorage.isValid() )
1296             {   // no scripts at all, or no scripts of the given type
1297                 return !m_rLogger.hadFailure();
1298             }
1299             ::std::set< ::rtl::OUString > aElementNames( aDocStorage.getElementNames() );
1300 
1301             ScriptType aKnownStorageBasedTypes[] = {
1302                 eBeanShell, eJavaScript, ePython, eJava
1303             };
1304             for ( size_t i=0; i<sizeof( aKnownStorageBasedTypes ) / sizeof( aKnownStorageBasedTypes[0] ); ++i )
1305                 aElementNames.erase( lcl_getScriptsSubStorageName( aKnownStorageBasedTypes[i] ) );
1306 
1307             if ( !aElementNames.empty() )
1308             {
1309                 m_rLogger.logFailure( MigrationError(
1310                     ERR_UNKNOWN_SCRIPT_FOLDER,
1311                     lcl_getSubDocumentDescription( _rDocument ),
1312                     *aElementNames.begin()
1313                 ) );
1314                 return false;
1315             }
1316         }
1317         catch( const Exception& )
1318         {
1319             m_rLogger.logFailure( MigrationError(
1320                 ERR_EXAMINING_SCRIPTS_FOLDER_FAILED,
1321                 lcl_getSubDocumentDescription( _rDocument ),
1322                 ::cppu::getCaughtException()
1323             ) );
1324             return false;
1325         }
1326         return true;
1327     }
1328 
1329     //--------------------------------------------------------------------
impl_migrateScriptStorage_nothrow(const SubDocument & _rDocument,const ScriptType _eScriptType,ProgressMixer & _rProgress,const PhaseID _nPhaseID) const1330     bool MigrationEngine_Impl::impl_migrateScriptStorage_nothrow( const SubDocument& _rDocument,
1331         const ScriptType _eScriptType, ProgressMixer& _rProgress, const PhaseID _nPhaseID ) const
1332     {
1333         OSL_PRECOND( _rDocument.xDocument.is(), "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: invalid document!" );
1334         if ( !_rDocument.xDocument.is() )
1335             return false;
1336 
1337         ScriptsStorage aDatabaseScripts( m_rLogger );
1338             // the scripts of our complete database document - created on demand only
1339         SharedStorage xTargetStorage;
1340             // the target for moving the scripts storages - created on demand only
1341 
1342         PhaseGuard aPhase( _rProgress );
1343         bool bSuccess = false;
1344         Any aException;
1345         try
1346         {
1347             // the root storage of the document whose scripts are to be migrated
1348             ScriptsStorage aDocStorage( _rDocument.xDocument, m_rLogger );
1349             if  (   !aDocStorage.isValid()
1350                 ||  !aDocStorage.hasScripts( _eScriptType )
1351                 )
1352             {
1353                 // no scripts at all, or no scripts of the given type
1354                 _rProgress.startPhase( _nPhaseID, 1 );
1355                 _rProgress.endPhase();
1356                 return !m_rLogger.hadFailure();
1357             }
1358 
1359             SharedStorage xScriptsRoot( aDocStorage.getScriptsRoot( _eScriptType ) );
1360             if ( !xScriptsRoot.is() )
1361                 throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "internal error" ) ), NULL );
1362 
1363             // loop through the script libraries
1364             Sequence< ::rtl::OUString > aStorageElements( xScriptsRoot->getElementNames() );
1365             aPhase.start( _nPhaseID, aStorageElements.getLength() );
1366 
1367             for (   const ::rtl::OUString* element = aStorageElements.getConstArray();
1368                     element != aStorageElements.getConstArray() + aStorageElements.getLength();
1369                     ++element
1370                 )
1371             {
1372                 bool bIsScriptLibrary = xScriptsRoot->isStorageElement( *element );
1373                 OSL_ENSURE( bIsScriptLibrary,
1374                     "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: warning: unknown scripts storage structure!" );
1375                     // we cannot handle this. We would need to copy this stream to the respective scripts storage
1376                     // of the database document, but we cannot guarantee that the name is not used, yet, and we cannot
1377                     // simply rename the thing.
1378                 if ( !bIsScriptLibrary )
1379                 {
1380                     m_rLogger.logFailure( MigrationError(
1381                         ERR_UNEXPECTED_LIBSTORAGE_ELEMENT,
1382                         lcl_getSubDocumentDescription( _rDocument ),
1383                         getScriptTypeDisplayName( _eScriptType ),
1384                         *element
1385                     ) );
1386                     return false;
1387                 }
1388 
1389                 // ensure we have access to the DBDoc's scripts storage
1390                 if ( !aDatabaseScripts.isValid() )
1391                 {   // not needed 'til now
1392                     aDatabaseScripts.bind( m_xDocumentModel );
1393                     if ( aDatabaseScripts.isValid() )
1394                         xTargetStorage = aDatabaseScripts.getScriptsRoot( _eScriptType );
1395 
1396                     if ( !xTargetStorage.is() )
1397                     {
1398                         m_rLogger.logFailure( MigrationError(
1399                             ERR_CREATING_DBDOC_SCRIPT_STORAGE_FAILED,
1400                             getScriptTypeDisplayName( _eScriptType )
1401                         ) );
1402                         return false;
1403                     }
1404                 }
1405 
1406                 // move the library to the DBDoc's scripts library, under the new name
1407                 ::rtl::OUString sNewLibName( lcl_createTargetLibName( _rDocument, *element, xTargetStorage.getTyped().get() ) );
1408                 xScriptsRoot->moveElementTo( *element, xTargetStorage, sNewLibName );
1409 
1410                 // log the fact that we moved the library
1411                 m_rLogger.movedLibrary( m_nCurrentDocumentID, _eScriptType, *element, sNewLibName );
1412 
1413                 // progress
1414                 _rProgress.advancePhase( element - aStorageElements.getConstArray() );
1415             }
1416 
1417             // commit the storages, so the changes we made persist
1418             if  (   !lcl_commitStorage_nothrow( xScriptsRoot )
1419                 ||  ( xTargetStorage.is() && !lcl_commitStorage_nothrow( xTargetStorage ) )
1420                 )
1421             {
1422                 m_rLogger.logFailure( MigrationError(
1423                     ERR_COMMITTING_SCRIPT_STORAGES_FAILED,
1424                     getScriptTypeDisplayName( _eScriptType ),
1425                     lcl_getSubDocumentDescription( _rDocument )
1426                 ) );
1427                 return false;
1428             }
1429 
1430             // now that the concrete scripts storage does not have any elements anymore,
1431             // remove it
1432             xScriptsRoot.reset( NULL ); // need to reset the storage to be allowed to remove it
1433             aDocStorage.removeScriptTypeStorage( _eScriptType );
1434 
1435             // done so far
1436             bSuccess =  aDocStorage.commit()
1437                     &&  aDatabaseScripts.commit();
1438         }
1439         catch( const Exception& )
1440         {
1441             aException = ::cppu::getCaughtException();
1442             bSuccess = false;
1443         }
1444 
1445         // log the error, if any
1446         if ( !bSuccess )
1447         {
1448             m_rLogger.logFailure( MigrationError(
1449                 ERR_GENERAL_SCRIPT_MIGRATION_FAILURE,
1450                 getScriptTypeDisplayName( _eScriptType ),
1451                 lcl_getSubDocumentDescription( _rDocument ),
1452                 aException
1453             ) );
1454         }
1455 
1456         return bSuccess;
1457     }
1458 
1459 	//--------------------------------------------------------------------
impl_migrateContainerLibraries_nothrow(const SubDocument & _rDocument,const ScriptType _eScriptType,ProgressMixer & _rProgress,const PhaseID _nPhaseID) const1460     bool MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow( const SubDocument& _rDocument,
1461             const ScriptType _eScriptType, ProgressMixer& _rProgress, const PhaseID _nPhaseID ) const
1462     {
1463 		OSL_PRECOND( ( _eScriptType == eBasic ) || ( _eScriptType == eDialog ),
1464             "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: illegal script type!" );
1465 
1466         bool bSuccess = false;
1467         PhaseGuard aPhase( _rProgress );
1468         Any aException;
1469         do  // artificial loop for flow control only
1470         {
1471         try
1472         {
1473             // access library container of the sub document
1474             Reference< XEmbeddedScripts > xSubDocScripts( _rDocument.xDocument, UNO_QUERY );
1475             if ( !xSubDocScripts.is() )
1476             {   // no script support in the sub document -> nothing to migrate
1477                 // (though ... this is suspicious, at least ...)
1478                 bSuccess = true;
1479                 break;
1480             }
1481 
1482             Reference< XStorageBasedLibraryContainer > xSourceLibraries(
1483                 _eScriptType == eBasic ? xSubDocScripts->getBasicLibraries() : xSubDocScripts->getDialogLibraries(),
1484                 UNO_QUERY_THROW
1485             );
1486             Reference< XLibraryContainerPassword > xSourcePasswords( xSourceLibraries, UNO_QUERY );
1487             OSL_ENSURE( xSourcePasswords.is(),
1488                 "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: suspicious: no password management for the source libraries!" );
1489 
1490             Sequence< ::rtl::OUString > aSourceLibNames( xSourceLibraries->getElementNames() );
1491             aPhase.start( _nPhaseID, aSourceLibNames.getLength() );
1492 
1493             if ( !xSourceLibraries->hasElements() )
1494             {
1495                 bSuccess = true;
1496                 break;
1497             }
1498 
1499             // create library containers for the document - those will be the target for the migration
1500             Reference< XStorageBasedDocument > xStorageDoc( m_xDocument, UNO_QUERY_THROW );
1501             Reference< XStorageBasedLibraryContainer > xTargetLibraries;
1502             if ( _eScriptType == eBasic )
1503             {
1504                 xTargetLibraries.set( DocumentScriptLibraryContainer::create(
1505                     m_aContext.getUNOContext(), xStorageDoc ), UNO_QUERY_THROW );
1506             }
1507             else
1508             {
1509                 xTargetLibraries.set( DocumentDialogLibraryContainer::create(
1510                     m_aContext.getUNOContext(), xStorageDoc ), UNO_QUERY_THROW );
1511             }
1512 
1513             // copy all libs to the target, with potentially renaming them
1514             const ::rtl::OUString* pSourceLibBegin = aSourceLibNames.getConstArray();
1515             const ::rtl::OUString* pSourceLibEnd = pSourceLibBegin + aSourceLibNames.getLength();
1516             for (   const ::rtl::OUString* pSourceLibName = pSourceLibBegin;
1517                     pSourceLibName != pSourceLibEnd;
1518                     ++pSourceLibName
1519                 )
1520             {
1521                 // if the library is password-protected, ask the user to unprotect it
1522                 if  (   xSourcePasswords.is()
1523                     &&  xSourcePasswords->isLibraryPasswordProtected( *pSourceLibName )
1524                     &&  !xSourcePasswords->isLibraryPasswordVerified( *pSourceLibName )
1525                     )
1526                 {
1527                     if ( !impl_unprotectPasswordLibrary_throw( xSourcePasswords, _eScriptType, *pSourceLibName ) )
1528                     {
1529                         m_rLogger.logFailure( MigrationError(
1530                             ERR_PASSWORD_VERIFICATION_FAILED,
1531                             _rDocument.sHierarchicalName,
1532                             getScriptTypeDisplayName( _eScriptType ),
1533                             *pSourceLibName
1534                         ) );
1535                         return false;
1536                     }
1537                 }
1538 
1539                 ::rtl::OUString sNewLibName( lcl_createTargetLibName( _rDocument, *pSourceLibName, xTargetLibraries.get() ) );
1540 
1541                 if ( xSourceLibraries->isLibraryLink( *pSourceLibName ) )
1542                 {
1543                     // just re-create the link in the target library
1544                     xTargetLibraries->createLibraryLink(
1545                         sNewLibName,
1546                         xSourceLibraries->getLibraryLinkURL( *pSourceLibName ),
1547                         xSourceLibraries->isLibraryReadOnly( *pSourceLibName )
1548                     );
1549                 }
1550                 else
1551                 {
1552                     if ( !xSourceLibraries->isLibraryLoaded( *pSourceLibName ) )
1553                         xSourceLibraries->loadLibrary( *pSourceLibName );
1554 
1555                     // copy the content of this particular libary
1556                     Reference< XNameAccess > xSourceLib( xSourceLibraries->getByName( *pSourceLibName ), UNO_QUERY_THROW );
1557                     Reference< XNameContainer > xTargetLib( xTargetLibraries->createLibrary( sNewLibName ), UNO_QUERY_THROW );
1558 
1559                     Sequence< ::rtl::OUString > aLibElementNames( xSourceLib->getElementNames() );
1560                     for (   const ::rtl::OUString* pSourceElementName = aLibElementNames.getConstArray();
1561                             pSourceElementName != aLibElementNames.getConstArray() + aLibElementNames.getLength();
1562                             ++pSourceElementName
1563                         )
1564                     {
1565                         Any aElement = xSourceLib->getByName( *pSourceElementName );
1566                         OSL_ENSURE( aElement.hasValue(),
1567                             "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: invalid (empty) lib element!" );
1568 
1569                         // if this is a dialog, adjust the references to scripts
1570                         if ( _eScriptType == eDialog )
1571                         {
1572                             impl_adjustDialogEvents_nothrow( aElement, lcl_getSubDocumentDescription( _rDocument ),
1573                                 *pSourceLibName, *pSourceElementName );
1574                         }
1575 
1576                         xTargetLib->insertByName( *pSourceElementName, aElement );
1577                     }
1578 
1579                     // transfer the read-only flag
1580                     xTargetLibraries->setLibraryReadOnly(
1581                         sNewLibName, xSourceLibraries->isLibraryReadOnly( *pSourceLibName ) );
1582                 }
1583 
1584                 // remove the source lib
1585                 xSourceLibraries->removeLibrary( *pSourceLibName );
1586 
1587                 // tell the logger
1588                 m_rLogger.movedLibrary( m_nCurrentDocumentID, _eScriptType, *pSourceLibName, sNewLibName );
1589 
1590                 // tell the progress
1591                 _rProgress.advancePhase( pSourceLibName - pSourceLibBegin );
1592             }
1593 
1594             // clean up
1595             xSourceLibraries->storeLibraries();
1596 
1597             xTargetLibraries->storeLibraries();
1598             Reference< XStorage > xTargetRoot( xTargetLibraries->getRootLocation(), UNO_QUERY_THROW );
1599             bSuccess = lcl_commitStorage_nothrow( xTargetRoot );
1600         }
1601         catch( const Exception& )
1602         {
1603             aException = ::cppu::getCaughtException();
1604             bSuccess = false;
1605         }
1606         } while ( false );
1607 
1608         // log the error, if any
1609         if ( !bSuccess )
1610         {
1611             m_rLogger.logFailure( MigrationError(
1612                 ERR_GENERAL_MACRO_MIGRATION_FAILURE,
1613                 lcl_getSubDocumentDescription( _rDocument ),
1614                 aException
1615             ) );
1616         }
1617 
1618         return bSuccess;
1619     }
1620 
1621 	//--------------------------------------------------------------------
impl_adjustScriptLibrary_nothrow(const::rtl::OUString & _rScriptType,::rtl::OUString & _inout_rScriptCode) const1622     bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( const ::rtl::OUString& _rScriptType,
1623             ::rtl::OUString& _inout_rScriptCode ) const
1624     {
1625         OSL_PRECOND( _inout_rScriptCode.getLength(), "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid script!" );
1626         if ( !_inout_rScriptCode.getLength() )
1627             return false;
1628 
1629         bool bSuccess = false;
1630         Any aException;
1631         try
1632         {
1633             if  (   !_rScriptType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Script" ) )
1634                 ||  !_rScriptType.getLength()
1635                 )
1636             {
1637                 OSL_ENSURE( false,
1638                     "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: no or unknown script type!" );
1639                 m_rLogger.logRecoverable( MigrationError(
1640                     ERR_UNKNOWN_SCRIPT_TYPE,
1641                     _rScriptType
1642                 ) );
1643                 return false;
1644             }
1645 
1646             // analyze the script URI
1647             Reference< XUriReferenceFactory > xUriRefFac = UriReferenceFactory::create( m_aContext.getUNOContext() );
1648             Reference< XVndSunStarScriptUrlReference > xUri( xUriRefFac->parse( _inout_rScriptCode ), UNO_QUERY_THROW );
1649 
1650             ::rtl::OUString sScriptLanguage = xUri->getParameter(
1651                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "language" ) ) );
1652             ScriptType eScriptType = eBasic;
1653             if ( !lcl_getScriptTypeFromLanguage( sScriptLanguage, eScriptType ) )
1654             {
1655                 OSL_ENSURE( false,
1656                     "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: unknown script language!" );
1657                 m_rLogger.logRecoverable( MigrationError(
1658                     ERR_UNKNOWN_SCRIPT_LANGUAGE,
1659                     sScriptLanguage
1660                 ) );
1661                 return false;
1662             }
1663 
1664             ::rtl::OUString sLocation = xUri->getParameter(
1665                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "location" ) ) );
1666             if ( !sLocation.equalsAscii( "document" ) )
1667             {
1668                 // only document libraries must be migrated, of course
1669                 return false;
1670             }
1671 
1672             ::rtl::OUString sScriptName = xUri->getName();
1673             sal_Int32 nLibModuleSeparator = sScriptName.indexOf( '.' );
1674             if ( nLibModuleSeparator < 0 )
1675             {
1676                 OSL_ENSURE( false,
1677                     "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid/unknown location format!" );
1678                 m_rLogger.logRecoverable( MigrationError(
1679                     ERR_UNKNOWN_SCRIPT_NAME_FORMAT,
1680                     sScriptName
1681                 ) );
1682                 return false;
1683             }
1684 
1685             // replace the library name
1686             ::rtl::OUString sLibrary = sScriptName.copy( 0, nLibModuleSeparator );
1687             ::rtl::OUString sNewLibName = m_rLogger.getNewLibraryName(
1688                 m_nCurrentDocumentID, eScriptType, sLibrary );
1689             OSL_ENSURE( sLibrary != sNewLibName,
1690                 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: a library which has not been migrated?" );
1691 
1692             ::rtl::OUStringBuffer aNewLocation;
1693             aNewLocation.append( sNewLibName );
1694             aNewLocation.append( sScriptName.copy( nLibModuleSeparator ) );
1695             xUri->setName( aNewLocation.makeStringAndClear() );
1696 
1697             // update the new script URL
1698             _inout_rScriptCode = xUri->getUriReference();
1699             bSuccess = true;
1700         }
1701         catch( const Exception& )
1702         {
1703             aException = ::cppu::getCaughtException();
1704             bSuccess = false;
1705         }
1706 
1707         // log the failure, if any
1708         if ( !bSuccess )
1709         {
1710             m_rLogger.logRecoverable( MigrationError(
1711                 ERR_SCRIPT_TRANSLATION_FAILURE,
1712                 _rScriptType,
1713                 _inout_rScriptCode,
1714                 aException
1715             ) );
1716         }
1717 
1718         return bSuccess;
1719     }
1720 
1721 	//--------------------------------------------------------------------
impl_adjustScriptLibrary_nothrow(ScriptEventDescriptor & _inout_rScriptEvent) const1722     bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor& _inout_rScriptEvent ) const
1723     {
1724         if ( _inout_rScriptEvent.ScriptType.getLength() && _inout_rScriptEvent.ScriptCode.getLength() )
1725             return impl_adjustScriptLibrary_nothrow( _inout_rScriptEvent.ScriptType, _inout_rScriptEvent.ScriptCode );
1726         return false;
1727     }
1728 
1729 	//--------------------------------------------------------------------
impl_adjustScriptLibrary_nothrow(Any & _inout_rScriptDescriptor) const1730     bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( Any& _inout_rScriptDescriptor ) const
1731     {
1732         ::comphelper::NamedValueCollection aScriptDesc( _inout_rScriptDescriptor );
1733 
1734         ::rtl::OUString sScriptType;
1735         ::rtl::OUString sScript;
1736         try
1737         {
1738             OSL_VERIFY( aScriptDesc.get_ensureType( "EventType", sScriptType ) );
1739             OSL_VERIFY( aScriptDesc.get_ensureType( "Script", sScript ) );
1740         }
1741         catch( const Exception& )
1742         {
1743             m_rLogger.logRecoverable( MigrationError(
1744                 ERR_INVALID_SCRIPT_DESCRIPTOR_FORMAT,
1745                 ::cppu::getCaughtException()
1746             ) );
1747         }
1748 
1749         if ( sScriptType.getLength() && sScript.getLength() )
1750             if ( !impl_adjustScriptLibrary_nothrow( sScriptType, sScript ) )
1751                 return false;
1752 
1753         aScriptDesc.put( "Script", sScript );
1754         _inout_rScriptDescriptor <<= aScriptDesc.getPropertyValues();
1755         return true;
1756     }
1757 
1758 	//--------------------------------------------------------------------
impl_adjustDocumentEvents_nothrow(const SubDocument & _rDocument) const1759     bool MigrationEngine_Impl::impl_adjustDocumentEvents_nothrow( const SubDocument& _rDocument ) const
1760     {
1761         try
1762         {
1763             Reference< XEventsSupplier > xSuppEvents( _rDocument.xDocument, UNO_QUERY );
1764             if ( !xSuppEvents.is() )
1765                 // this is allowed. E.g. new-style reports currently do not support this
1766                 return true;
1767 
1768             Reference< XNameReplace > xEvents( xSuppEvents->getEvents(), UNO_SET_THROW );
1769             Sequence< ::rtl::OUString > aEventNames = xEvents->getElementNames();
1770 
1771             Any aEvent;
1772             for (   const ::rtl::OUString* eventName = aEventNames.getConstArray();
1773                     eventName != aEventNames.getConstArray() + aEventNames.getLength();
1774                     ++eventName
1775                 )
1776             {
1777                 aEvent = xEvents->getByName( *eventName );
1778                 if ( !aEvent.hasValue() )
1779                     continue;
1780 
1781                 // translate
1782                 if ( !impl_adjustScriptLibrary_nothrow( aEvent ) )
1783                     continue;
1784 
1785                 // put back
1786                 xEvents->replaceByName( *eventName, aEvent );
1787             }
1788         }
1789         catch( const Exception& )
1790         {
1791             m_rLogger.logRecoverable( MigrationError(
1792                 ERR_ADJUSTING_DOCUMENT_EVENTS_FAILED,
1793                 lcl_getSubDocumentDescription( _rDocument ),
1794                 ::cppu::getCaughtException()
1795             ) );
1796             return false;
1797         }
1798         return true;
1799     }
1800 
1801 	//--------------------------------------------------------------------
impl_adjustDialogElementEvents_throw(const Reference<XInterface> & _rxElement) const1802     void MigrationEngine_Impl::impl_adjustDialogElementEvents_throw( const Reference< XInterface >& _rxElement ) const
1803     {
1804         Reference< XScriptEventsSupplier > xEventsSupplier( _rxElement, UNO_QUERY_THROW );
1805         Reference< XNameReplace > xEvents( xEventsSupplier->getEvents(), UNO_QUERY_THROW );
1806         Sequence< ::rtl::OUString > aEventNames( xEvents->getElementNames() );
1807 
1808         const ::rtl::OUString* eventName = aEventNames.getArray();
1809         const ::rtl::OUString* eventNamesEnd = eventName + aEventNames.getLength();
1810 
1811         ScriptEventDescriptor aScriptEvent;
1812         for ( ; eventName != eventNamesEnd; ++eventName )
1813         {
1814             OSL_VERIFY( xEvents->getByName( *eventName ) >>= aScriptEvent );
1815 
1816             if ( !impl_adjustScriptLibrary_nothrow( aScriptEvent ) )
1817                 continue;
1818 
1819             xEvents->replaceByName( *eventName, makeAny( aScriptEvent ) );
1820         }
1821     }
1822 
1823 	//--------------------------------------------------------------------
impl_adjustDialogEvents_nothrow(Any & _inout_rDialogLibraryElement,const::rtl::OUString & _rDocName,const::rtl::OUString & _rDialogLibName,const::rtl::OUString & _rDialogName) const1824     bool MigrationEngine_Impl::impl_adjustDialogEvents_nothrow( Any& _inout_rDialogLibraryElement,
1825         const ::rtl::OUString& _rDocName, const ::rtl::OUString& _rDialogLibName, const ::rtl::OUString& _rDialogName ) const
1826     {
1827         try
1828         {
1829             // load a dialog model from the stream describing it
1830             Reference< XInputStreamProvider > xISP( _inout_rDialogLibraryElement, UNO_QUERY_THROW );
1831             Reference< XInputStream > xInput( xISP->createInputStream(), UNO_QUERY_THROW );
1832 
1833             Reference< XNameContainer > xDialogModel( m_aContext.createComponent( "com.sun.star.awt.UnoControlDialogModel" ), UNO_QUERY_THROW );
1834             ::xmlscript::importDialogModel( xInput, xDialogModel, m_aContext.getUNOContext() );
1835 
1836             // adjust the events of the dialog
1837             impl_adjustDialogElementEvents_throw( xDialogModel );
1838 
1839             // adjust the events of the controls
1840             Sequence< ::rtl::OUString > aControlNames( xDialogModel->getElementNames() );
1841             const ::rtl::OUString* controlName = aControlNames.getConstArray();
1842             const ::rtl::OUString* controlNamesEnd = controlName + aControlNames.getLength();
1843             for ( ; controlName != controlNamesEnd; ++controlName )
1844             {
1845                 impl_adjustDialogElementEvents_throw( Reference< XInterface >( xDialogModel->getByName( *controlName ), UNO_QUERY ) );
1846             }
1847 
1848             // export dialog model
1849             xISP = ::xmlscript::exportDialogModel( xDialogModel, m_aContext.getUNOContext() );
1850             _inout_rDialogLibraryElement <<= xISP;
1851         }
1852         catch( const Exception& )
1853         {
1854             m_rLogger.logRecoverable( MigrationError(
1855                 ERR_ADJUSTING_DIALOG_EVENTS_FAILED,
1856                 _rDocName,
1857                 _rDialogLibName,
1858                 _rDialogName,
1859                 ::cppu::getCaughtException()
1860             ) );
1861             return false;
1862         }
1863         return true;
1864     }
1865 
1866 	//--------------------------------------------------------------------
impl_adjustFormComponentEvents_throw(const Reference<XIndexAccess> & _rxComponentContainer) const1867     void MigrationEngine_Impl::impl_adjustFormComponentEvents_throw( const Reference< XIndexAccess >& _rxComponentContainer ) const
1868     {
1869         FormComponentIterator aCompIter( _rxComponentContainer );
1870         while ( aCompIter.hasMore() )
1871         {
1872             // 1. adjust the component's scripts of the current component
1873             FormComponentScripts aComponent( aCompIter.next() );
1874             Sequence< ScriptEventDescriptor > aEvents( aComponent.getEvents() );
1875 
1876             bool bChangedComponentEvents = false;
1877             for (   ScriptEventDescriptor* scriptEvent = aEvents.getArray();
1878                     scriptEvent != aEvents.getArray() + aEvents.getLength();
1879                     ++scriptEvent
1880                 )
1881             {
1882                 if ( !impl_adjustScriptLibrary_nothrow( *scriptEvent ) )
1883                     continue;
1884 
1885                 bChangedComponentEvents = true;
1886             }
1887 
1888             if ( bChangedComponentEvents )
1889                 aComponent.setEvents( aEvents );
1890 
1891             // 2. step down if the component is a container itself
1892             Reference< XIndexAccess > xContainer( aComponent.getComponent(), UNO_QUERY );
1893             if ( xContainer.is() )
1894                 impl_adjustFormComponentEvents_throw( xContainer );
1895         }
1896     }
1897 
1898 	//--------------------------------------------------------------------
impl_adjustFormComponentEvents_nothrow(const SubDocument & _rDocument) const1899     bool MigrationEngine_Impl::impl_adjustFormComponentEvents_nothrow( const SubDocument& _rDocument ) const
1900     {
1901         try
1902         {
1903             DrawPageIterator aPageIter( _rDocument.xDocument );
1904             while ( aPageIter.hasMore() )
1905             {
1906                 Reference< XFormsSupplier > xSuppForms( aPageIter.next(), UNO_QUERY_THROW );
1907                 Reference< XIndexAccess > xForms( xSuppForms->getForms(), UNO_QUERY_THROW );
1908                 impl_adjustFormComponentEvents_throw( xForms );
1909             }
1910         }
1911         catch( const Exception& )
1912         {
1913             m_rLogger.logRecoverable( MigrationError(
1914                 ERR_ADJUSTING_FORMCOMP_EVENTS_FAILED,
1915                 lcl_getSubDocumentDescription( _rDocument ),
1916                 ::cppu::getCaughtException()
1917             ) );
1918             return false;
1919         }
1920         return true;
1921     }
1922 
1923 	//--------------------------------------------------------------------
impl_unprotectPasswordLibrary_throw(const Reference<XLibraryContainerPassword> & _rxPasswordManager,const ScriptType _eScriptType,const::rtl::OUString & _rLibraryName) const1924     bool MigrationEngine_Impl::impl_unprotectPasswordLibrary_throw( const Reference< XLibraryContainerPassword >& _rxPasswordManager,
1925             const ScriptType _eScriptType, const ::rtl::OUString& _rLibraryName ) const
1926     {
1927         // a human-readable description of the affected library
1928         ::rtl::OUString sLibraryDescription( String(
1929             MacroMigrationResId( STR_LIBRARY_TYPE_AND_NAME ) ) );
1930         ::comphelper::string::searchAndReplaceAsciiI( sLibraryDescription, "$type$",
1931             getScriptTypeDisplayName( _eScriptType ) );
1932         ::comphelper::string::searchAndReplaceAsciiI( sLibraryDescription, "$library$",
1933             _rLibraryName );
1934 
1935         InteractionHandler aHandler( m_aContext, m_xDocumentModel );
1936         ::rtl::OUString sPassword;
1937         while ( true )
1938         {
1939             if ( !aHandler.requestDocumentPassword( sLibraryDescription, sPassword ) )
1940                 // aborted by the user
1941                 return false;
1942 
1943             bool bSuccessVerification = _rxPasswordManager->verifyLibraryPassword( _rLibraryName, sPassword );
1944             if ( bSuccessVerification )
1945                 return true;
1946         }
1947 
1948     }
1949 
1950 	//====================================================================
1951 	//= MigrationEngine
1952 	//====================================================================
1953 	//--------------------------------------------------------------------
MigrationEngine(const::comphelper::ComponentContext & _rContext,const Reference<XOfficeDatabaseDocument> & _rxDocument,IMigrationProgress & _rProgress,MigrationLog & _rLogger)1954     MigrationEngine::MigrationEngine( const ::comphelper::ComponentContext& _rContext,
1955             const Reference< XOfficeDatabaseDocument >& _rxDocument, IMigrationProgress& _rProgress,
1956             MigrationLog& _rLogger )
1957         :m_pImpl( new MigrationEngine_Impl( _rContext, _rxDocument, _rProgress, _rLogger ) )
1958     {
1959     }
1960 
1961 	//--------------------------------------------------------------------
~MigrationEngine()1962     MigrationEngine::~MigrationEngine()
1963     {
1964     }
1965 
1966 	//--------------------------------------------------------------------
getFormCount() const1967     sal_Int32 MigrationEngine::getFormCount() const
1968     {
1969         return m_pImpl->getFormCount();
1970     }
1971 
1972 	//--------------------------------------------------------------------
getReportCount() const1973     sal_Int32 MigrationEngine::getReportCount() const
1974     {
1975         return m_pImpl->getReportCount();
1976     }
1977 
1978 	//--------------------------------------------------------------------
migrateAll()1979     bool MigrationEngine::migrateAll()
1980     {
1981         return m_pImpl->migrateAll();
1982     }
1983 
1984 //........................................................................
1985 } // namespace dbmm
1986 //........................................................................
1987