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