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