summaryrefslogtreecommitdiffstats
path: root/desktop/source/migration
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--desktop/source/migration/migration.cxx1111
-rw-r--r--desktop/source/migration/migration_impl.hxx198
-rw-r--r--desktop/source/migration/services/basicmigration.cxx202
-rw-r--r--desktop/source/migration/services/basicmigration.hxx71
-rw-r--r--desktop/source/migration/services/cppumaker.mk27
-rw-r--r--desktop/source/migration/services/jvmfwk.cxx395
-rw-r--r--desktop/source/migration/services/jvmfwk.hxx33
-rw-r--r--desktop/source/migration/services/migrationoo2.component30
-rw-r--r--desktop/source/migration/services/migrationoo3.component26
-rw-r--r--desktop/source/migration/services/misc.hxx39
-rw-r--r--desktop/source/migration/services/oo3extensionmigration.cxx409
-rw-r--r--desktop/source/migration/services/oo3extensionmigration.hxx117
-rw-r--r--desktop/source/migration/services/wordbookmigration.cxx231
-rw-r--r--desktop/source/migration/services/wordbookmigration.hxx72
14 files changed, 2961 insertions, 0 deletions
diff --git a/desktop/source/migration/migration.cxx b/desktop/source/migration/migration.cxx
new file mode 100644
index 000000000..524ca8615
--- /dev/null
+++ b/desktop/source/migration/migration.cxx
@@ -0,0 +1,1111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <set>
+
+#include <migration.hxx>
+#include "migration_impl.hxx"
+
+#include <sal/log.hxx>
+#include <unotools/textsearch.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <unotools/bootstrap.hxx>
+#include <rtl/uri.hxx>
+#include <i18nlangtag/lang.h>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <osl/file.hxx>
+#include <osl/security.hxx>
+#include <unotools/configmgr.hxx>
+
+#include <com/sun/star/configuration/Update.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/task/XJob.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XRefreshable.hpp>
+#include <com/sun/star/util/XChangesBatch.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/FileSystemStorageFactory.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/UIConfigurationManager.hpp>
+#include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
+#include <vcl/commandinfoprovider.hxx>
+
+using namespace osl;
+using namespace com::sun::star::task;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::util;
+using namespace com::sun::star::container;
+using com::sun::star::uno::Exception;
+using namespace com::sun::star;
+
+
+namespace desktop
+{
+
+constexpr OUStringLiteral ITEM_DESCRIPTOR_COMMANDURL = u"CommandURL";
+constexpr OUStringLiteral ITEM_DESCRIPTOR_CONTAINER = u"ItemDescriptorContainer";
+constexpr OUStringLiteral ITEM_DESCRIPTOR_LABEL = u"Label";
+
+static OUString mapModuleShortNameToIdentifier(std::u16string_view sShortName)
+{
+ OUString sIdentifier;
+
+ if ( sShortName == u"StartModule" )
+ sIdentifier = "com.sun.star.frame.StartModule";
+
+ else if ( sShortName == u"swriter" )
+ sIdentifier = "com.sun.star.text.TextDocument";
+
+ else if ( sShortName == u"scalc" )
+ sIdentifier = "com.sun.star.sheet.SpreadsheetDocument";
+
+ else if ( sShortName == u"sdraw" )
+ sIdentifier = "com.sun.star.drawing.DrawingDocument";
+
+ else if ( sShortName == u"simpress" )
+ sIdentifier = "com.sun.star.presentation.PresentationDocument";
+
+ else if ( sShortName == u"smath" )
+ sIdentifier = "com.sun.star.formula.FormulaProperties";
+
+ else if ( sShortName == u"schart" )
+ sIdentifier = "com.sun.star.chart2.ChartDocument";
+
+ else if ( sShortName == u"BasicIDE" )
+ sIdentifier = "com.sun.star.script.BasicIDE";
+
+ else if ( sShortName == u"dbapp" )
+ sIdentifier = "com.sun.star.sdb.OfficeDatabaseDocument";
+
+ else if ( sShortName == u"sglobal" )
+ sIdentifier = "com.sun.star.text.GlobalDocument";
+
+ else if ( sShortName == u"sweb" )
+ sIdentifier = "com.sun.star.text.WebDocument";
+
+ else if ( sShortName == u"swxform" )
+ sIdentifier = "com.sun.star.xforms.XMLFormDocument";
+
+ else if ( sShortName == u"sbibliography" )
+ sIdentifier = "com.sun.star.frame.Bibliography";
+
+ return sIdentifier;
+}
+
+bool MigrationImpl::alreadyMigrated()
+{
+ OUString aStr = m_aInfo.userdata + "/MIGRATED4";
+ File aFile(aStr);
+ // create migration stamp, and/or check its existence
+ bool bRet = aFile.open (osl_File_OpenFlag_Write | osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock) == FileBase::E_EXIST;
+ SAL_INFO( "desktop.migration", "File '" << aStr << "' exists? " << bRet );
+ return bRet;
+}
+
+bool MigrationImpl::initializeMigration()
+{
+ bool bRet = false;
+
+ if (!checkMigrationCompleted()) {
+ readAvailableMigrations(m_vMigrationsAvailable);
+ sal_Int32 nIndex = findPreferredMigrationProcess(m_vMigrationsAvailable);
+ // m_aInfo is now set to the preferred migration source
+ if ( nIndex >= 0 ) {
+ if (alreadyMigrated())
+ return false;
+ m_vrMigrations = readMigrationSteps(m_vMigrationsAvailable[nIndex].name);
+ }
+
+ bRet = !m_aInfo.userdata.isEmpty();
+ }
+
+ SAL_INFO( "desktop.migration", "Migration " << ( bRet ? "needed" : "not required" ) );
+
+ return bRet;
+}
+
+void Migration::migrateSettingsIfNecessary()
+{
+ MigrationImpl aImpl;
+
+ if (! aImpl.initializeMigration() )
+ return;
+
+ bool bResult = false;
+ try {
+ bResult = aImpl.doMigration();
+ } catch (const Exception&) {
+ TOOLS_WARN_EXCEPTION( "desktop", "doMigration()");
+ }
+ OSL_ENSURE(bResult, "Migration has not been successful");
+}
+
+MigrationImpl::MigrationImpl()
+{
+}
+
+MigrationImpl::~MigrationImpl()
+{
+}
+
+// The main entry point for migrating settings
+bool MigrationImpl::doMigration()
+{
+ // compile file list for migration
+ m_vrFileList = compileFileList();
+
+ bool result = false;
+ try {
+ NewVersionUIInfo aNewVersionUIInfo;
+ std::vector< MigrationModuleInfo > vModulesInfo = detectUIChangesForAllModules();
+ aNewVersionUIInfo.init(vModulesInfo);
+
+ copyFiles();
+
+ static const OUStringLiteral sMenubarResourceURL(u"private:resource/menubar/menubar");
+ static const OUStringLiteral sToolbarResourcePre(u"private:resource/toolbar/");
+ for (MigrationModuleInfo & i : vModulesInfo) {
+ OUString sModuleIdentifier = mapModuleShortNameToIdentifier(i.sModuleShortName);
+ if (sModuleIdentifier.isEmpty())
+ continue;
+
+
+ OUString aOldCfgDataPath = m_aInfo.userdata + "/user/config/soffice.cfg/modules/" + i.sModuleShortName;
+ uno::Sequence< uno::Any > lArgs {uno::Any(aOldCfgDataPath), uno::Any(embed::ElementModes::READ)};
+
+ uno::Reference< uno::XComponentContext > xContext(comphelper::getProcessComponentContext());
+ uno::Reference< lang::XSingleServiceFactory > xStorageFactory(embed::FileSystemStorageFactory::create(xContext));
+ uno::Reference< embed::XStorage > xModules(xStorageFactory->createInstanceWithArguments(lArgs), uno::UNO_QUERY);
+ uno::Reference< ui::XUIConfigurationManager2 > xOldCfgManager = ui::UIConfigurationManager::create(xContext);
+
+ if ( xModules.is() ) {
+ xOldCfgManager->setStorage( xModules );
+ xOldCfgManager->reload();
+ }
+
+ uno::Reference< ui::XUIConfigurationManager > xCfgManager = aNewVersionUIInfo.getConfigManager(i.sModuleShortName);
+
+ if (i.bHasMenubar) {
+ uno::Reference< container::XIndexContainer > xOldVersionMenuSettings(xOldCfgManager->getSettings(sMenubarResourceURL, true), uno::UNO_QUERY);
+ uno::Reference< container::XIndexContainer > xNewVersionMenuSettings = aNewVersionUIInfo.getNewMenubarSettings(i.sModuleShortName);
+ compareOldAndNewConfig(OUString(), xOldVersionMenuSettings, xNewVersionMenuSettings, sMenubarResourceURL);
+ mergeOldToNewVersion(xCfgManager, xNewVersionMenuSettings, sModuleIdentifier, sMenubarResourceURL);
+ }
+
+ sal_Int32 nToolbars = i.m_vToolbars.size();
+ if (nToolbars >0) {
+ for (sal_Int32 j=0; j<nToolbars; ++j) {
+ OUString sToolbarName = i.m_vToolbars[j];
+ OUString sToolbarResourceURL = sToolbarResourcePre + sToolbarName;
+
+ uno::Reference< container::XIndexContainer > xOldVersionToolbarSettings(xOldCfgManager->getSettings(sToolbarResourceURL, true), uno::UNO_QUERY);
+ uno::Reference< container::XIndexContainer > xNewVersionToolbarSettings = aNewVersionUIInfo.getNewToolbarSettings(i.sModuleShortName, sToolbarName);
+ compareOldAndNewConfig(OUString(), xOldVersionToolbarSettings, xNewVersionToolbarSettings, sToolbarResourceURL);
+ mergeOldToNewVersion(xCfgManager, xNewVersionToolbarSettings, sModuleIdentifier, sToolbarResourceURL);
+ }
+ }
+
+ m_aOldVersionItemsHashMap.clear();
+ }
+
+ // execute the migration items from Setup.xcu
+ copyConfig();
+
+ // execute custom migration services from Setup.xcu
+ // and refresh the cache
+ runServices();
+ uno::Reference< XRefreshable >(
+ configuration::theDefaultProvider::get(comphelper::getProcessComponentContext()),
+ uno::UNO_QUERY_THROW)->refresh();
+
+ result = true;
+ } catch (const css::uno::Exception &) {
+ TOOLS_WARN_EXCEPTION(
+ "desktop.migration",
+ "ignored Exception while migrating from version \"" << m_aInfo.productname
+ << "\" data \"" << m_aInfo.userdata << "\"");
+ }
+
+ // prevent running the migration multiple times
+ setMigrationCompleted();
+ return result;
+}
+
+void MigrationImpl::setMigrationCompleted()
+{
+ try {
+ uno::Reference< XPropertySet > aPropertySet(getConfigAccess("org.openoffice.Setup/Office", true), uno::UNO_QUERY_THROW);
+ aPropertySet->setPropertyValue("MigrationCompleted", uno::Any(true));
+ uno::Reference< XChangesBatch >(aPropertySet, uno::UNO_QUERY_THROW)->commitChanges();
+ } catch (...) {
+ // fail silently
+ }
+}
+
+bool MigrationImpl::checkMigrationCompleted()
+{
+ bool bMigrationCompleted = false;
+ try {
+ uno::Reference< XPropertySet > aPropertySet(
+ getConfigAccess("org.openoffice.Setup/Office"), uno::UNO_QUERY_THROW);
+ aPropertySet->getPropertyValue("MigrationCompleted") >>= bMigrationCompleted;
+
+ if( !bMigrationCompleted && getenv("SAL_DISABLE_USERMIGRATION" ) ) {
+ // migration prevented - fake its success
+ setMigrationCompleted();
+ bMigrationCompleted = true;
+ }
+ } catch (const Exception&) {
+ // just return false...
+ }
+ SAL_INFO( "desktop.migration", "Migration " << ( bMigrationCompleted ? "already completed" : "not done" ) );
+
+ return bMigrationCompleted;
+}
+
+static void insertSorted(migrations_available& rAvailableMigrations, supported_migration const & aSupportedMigration)
+{
+ migrations_available::iterator pIter = std::find_if(rAvailableMigrations.begin(), rAvailableMigrations.end(),
+ [&aSupportedMigration](const supported_migration& rMigration) { return rMigration.nPriority < aSupportedMigration.nPriority; });
+ if (pIter != rAvailableMigrations.end())
+ rAvailableMigrations.insert(pIter, aSupportedMigration );
+ else
+ rAvailableMigrations.push_back( aSupportedMigration );
+}
+
+void MigrationImpl::readAvailableMigrations(migrations_available& rAvailableMigrations)
+{
+ // get supported version names
+ uno::Reference< XNameAccess > aMigrationAccess(getConfigAccess("org.openoffice.Setup/Migration/SupportedVersions"), uno::UNO_SET_THROW);
+ const uno::Sequence< OUString > seqSupportedVersions = aMigrationAccess->getElementNames();
+
+ static const OUStringLiteral aVersionIdentifiers( u"VersionIdentifiers" );
+ static const OUStringLiteral aPriorityIdentifier( u"Priority" );
+
+ for (OUString const & supportedVersion :seqSupportedVersions) {
+ sal_Int32 nPriority( 0 );
+ uno::Sequence< OUString > seqVersions;
+ uno::Reference< XNameAccess > xMigrationData( aMigrationAccess->getByName(supportedVersion), uno::UNO_QUERY_THROW );
+ xMigrationData->getByName( aVersionIdentifiers ) >>= seqVersions;
+ xMigrationData->getByName( aPriorityIdentifier ) >>= nPriority;
+
+ supported_migration aSupportedMigration;
+ aSupportedMigration.name = supportedVersion;
+ aSupportedMigration.nPriority = nPriority;
+ for (OUString const & s : std::as_const(seqVersions))
+ aSupportedMigration.supported_versions.push_back(s.trim());
+ insertSorted( rAvailableMigrations, aSupportedMigration );
+ SAL_INFO( "desktop.migration", " available migration '" << aSupportedMigration.name << "'" );
+ }
+}
+
+migrations_vr MigrationImpl::readMigrationSteps(const OUString& rMigrationName)
+{
+ // get migration access
+ uno::Reference< XNameAccess > aMigrationAccess(getConfigAccess("org.openoffice.Setup/Migration/SupportedVersions"), uno::UNO_SET_THROW);
+ uno::Reference< XNameAccess > xMigrationData( aMigrationAccess->getByName(rMigrationName), uno::UNO_QUERY_THROW );
+
+ // get migration description from org.openoffice.Setup/Migration
+ // and build vector of migration steps
+ uno::Reference< XNameAccess > theNameAccess(xMigrationData->getByName("MigrationSteps"), uno::UNO_QUERY_THROW);
+ uno::Reference< XNameAccess > tmpAccess;
+ uno::Sequence< OUString > tmpSeq;
+ migrations_vr vrMigrations(new migrations_v);
+ const css::uno::Sequence<OUString> aMigrationSteps = theNameAccess->getElementNames();
+ for (const OUString& rMigrationStep : aMigrationSteps) {
+ // get current migration step
+ theNameAccess->getByName(rMigrationStep) >>= tmpAccess;
+ migration_step tmpStep;
+
+ // read included files from current step description
+ if (tmpAccess->getByName("IncludedFiles") >>= tmpSeq) {
+ for (const OUString& rSeqEntry : std::as_const(tmpSeq))
+ tmpStep.includeFiles.push_back(rSeqEntry);
+ }
+
+ // excluded files...
+ if (tmpAccess->getByName("ExcludedFiles") >>= tmpSeq) {
+ for (const OUString& rSeqEntry : std::as_const(tmpSeq))
+ tmpStep.excludeFiles.push_back(rSeqEntry);
+ }
+
+ // included nodes...
+ if (tmpAccess->getByName("IncludedNodes") >>= tmpSeq) {
+ for (const OUString& rSeqEntry : std::as_const(tmpSeq))
+ tmpStep.includeConfig.push_back(rSeqEntry);
+ }
+
+ // excluded nodes...
+ if (tmpAccess->getByName("ExcludedNodes") >>= tmpSeq) {
+ for (const OUString& rSeqEntry : std::as_const(tmpSeq))
+ tmpStep.excludeConfig.push_back(rSeqEntry);
+ }
+
+ // excluded extensions...
+ if (tmpAccess->getByName("ExcludedExtensions") >>= tmpSeq) {
+ for (const OUString& rSeqEntry : std::as_const(tmpSeq))
+ tmpStep.excludeExtensions.push_back(rSeqEntry);
+ }
+
+ // generic service
+ tmpAccess->getByName("MigrationService") >>= tmpStep.service;
+
+ vrMigrations->push_back(tmpStep);
+ }
+ return vrMigrations;
+}
+
+static FileBase::RC _checkAndCreateDirectory(INetURLObject const & dirURL)
+{
+ FileBase::RC result = Directory::create(dirURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri));
+ if (result == FileBase::E_NOENT) {
+ INetURLObject baseURL(dirURL);
+ baseURL.removeSegment();
+ _checkAndCreateDirectory(baseURL);
+ return Directory::create(dirURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri));
+ } else
+ return result;
+}
+
+#if defined UNX && ! defined MACOSX
+
+const char XDG_CONFIG_PART[] = "/.config/";
+
+OUString MigrationImpl::preXDGConfigDir(const OUString& rConfigDir)
+{
+ OUString aPreXDGConfigPath;
+ const char* pXDGCfgHome = getenv("XDG_CONFIG_HOME");
+
+ // cater for XDG_CONFIG_HOME change
+ // If XDG_CONFIG_HOME is set then we;
+ // assume the user knows what they are doing ( room for improvement here, we could
+ // of course search the default config dir etc. also - but this is more complex,
+ // we would need to weigh results from the current config dir against matches in
+ // the 'old' config dir etc. ) - currently we just use the returned config dir.
+ // If XDG_CONFIG_HOME is NOT set;
+ // assume then we should now using the default $HOME/.config config location for
+ // our user profiles, however *all* previous libreoffice and openoffice.org
+ // configurations will be in the 'old' config directory and that's where we need
+ // to search - we convert the returned config dir to the 'old' dir
+ if ( !pXDGCfgHome && rConfigDir.endsWith( XDG_CONFIG_PART ) )
+ // remove trailing '.config/' but leave the terminating '/'
+ aPreXDGConfigPath = rConfigDir.copy( 0, rConfigDir.getLength() - sizeof( XDG_CONFIG_PART ) + 2 );
+ else
+ aPreXDGConfigPath = rConfigDir;
+
+ // the application-specific config dir is no longer prefixed by '.' because it is hidden under ".config"
+ // we have to add the '.' for the pre-XDG directory names
+ aPreXDGConfigPath += ".";
+
+ return aPreXDGConfigPath;
+}
+#endif
+
+void MigrationImpl::setInstallInfoIfExist(
+ install_info& aInfo,
+ std::u16string_view rConfigDir,
+ const OUString& rVersion)
+{
+ OUString url(INetURLObject(rConfigDir).GetMainURL(INetURLObject::DecodeMechanism::NONE));
+ osl::DirectoryItem item;
+ osl::FileStatus stat(osl_FileStatus_Mask_Type);
+
+ if (osl::DirectoryItem::get(url, item) == osl::FileBase::E_None
+ && item.getFileStatus(stat) == osl::FileBase::E_None
+ && stat.getFileType() == osl::FileStatus::Directory) {
+ aInfo.userdata = url;
+ aInfo.productname = rVersion;
+ }
+}
+
+install_info MigrationImpl::findInstallation(const strings_v& rVersions)
+{
+
+ OUString aTopConfigDir;
+ osl::Security().getConfigDir( aTopConfigDir );
+ if ( !aTopConfigDir.isEmpty() && aTopConfigDir[ aTopConfigDir.getLength()-1 ] != '/' )
+ aTopConfigDir += "/";
+
+#if defined UNX && ! defined MACOSX
+ OUString aPreXDGTopConfigDir = preXDGConfigDir(aTopConfigDir);
+#endif
+
+ install_info aInfo;
+ for (auto const& elem : rVersions)
+ {
+ OUString aVersion, aProfileName;
+ sal_Int32 nSeparatorIndex = elem.indexOf('=');
+ if ( nSeparatorIndex != -1 ) {
+ aVersion = elem.copy( 0, nSeparatorIndex );
+ aProfileName = elem.copy( nSeparatorIndex+1 );
+ }
+
+ if ( !aVersion.isEmpty() && !aProfileName.isEmpty() &&
+ ( aInfo.userdata.isEmpty() ||
+ aProfileName.equalsIgnoreAsciiCase(
+ utl::ConfigManager::getProductName() ) ) ) {
+ setInstallInfoIfExist(aInfo, OUStringConcatenation(aTopConfigDir + aProfileName), aVersion);
+#if defined UNX && ! defined MACOSX
+ //try preXDG path if the new one does not exist
+ if ( aInfo.userdata.isEmpty())
+ setInstallInfoIfExist(aInfo, OUStringConcatenation(aPreXDGTopConfigDir + aProfileName), aVersion);
+#endif
+ }
+ }
+
+ return aInfo;
+}
+
+sal_Int32 MigrationImpl::findPreferredMigrationProcess(const migrations_available& rAvailableMigrations)
+{
+ sal_Int32 nIndex( -1 );
+ sal_Int32 i( 0 );
+
+ for (auto const& availableMigration : rAvailableMigrations)
+ {
+ install_info aInstallInfo = findInstallation(availableMigration.supported_versions);
+ if (!aInstallInfo.productname.isEmpty() ) {
+ m_aInfo = aInstallInfo;
+ nIndex = i;
+ break;
+ }
+ ++i;
+ }
+
+ SAL_INFO( "desktop.migration", " preferred migration is from product '" << m_aInfo.productname << "'");
+ SAL_INFO( "desktop.migration", " and settings directory '" << m_aInfo.userdata << "'");
+
+ return nIndex;
+}
+
+strings_vr MigrationImpl::applyPatterns(const strings_v& vSet, const strings_v& vPatterns)
+{
+ using namespace utl;
+ strings_vr vrResult(new strings_v);
+ for (auto const& pattern : vPatterns)
+ {
+ // find matches for this pattern in input set
+ // and copy them to the result
+ SearchParam param(pattern, SearchParam::SearchType::Regexp);
+ TextSearch ts(param, LANGUAGE_DONTKNOW);
+ sal_Int32 start = 0;
+ sal_Int32 end = 0;
+ for (auto const& elem : vSet)
+ {
+ end = elem.getLength();
+ if (ts.SearchForward(elem, &start, &end))
+ vrResult->push_back(elem);
+ }
+ }
+ return vrResult;
+}
+
+strings_vr MigrationImpl::getAllFiles(const OUString& baseURL) const
+{
+ strings_vr vrResult(new strings_v);
+
+ // get sub dirs
+ Directory dir(baseURL);
+ if (dir.open() == FileBase::E_None) {
+ strings_v vSubDirs;
+ strings_vr vrSubResult;
+
+ // work through directory contents...
+ DirectoryItem item;
+ FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL);
+ while (dir.getNextItem(item) == FileBase::E_None) {
+ if (item.getFileStatus(fs) == FileBase::E_None) {
+ if (fs.getFileType() == FileStatus::Directory)
+ vSubDirs.push_back(fs.getFileURL());
+ else
+ vrResult->push_back(fs.getFileURL());
+ }
+ }
+
+ // recurse subfolders
+ for (auto const& subDir : vSubDirs)
+ {
+ vrSubResult = getAllFiles(subDir);
+ vrResult->insert(vrResult->end(), vrSubResult->begin(), vrSubResult->end());
+ }
+ }
+ return vrResult;
+}
+
+namespace
+{
+
+// removes elements of vector 2 in vector 1
+strings_v subtract(strings_v && a, strings_v && b)
+{
+ std::sort(a.begin(), a.end());
+ strings_v::iterator ae(std::unique(a.begin(), a.end()));
+ std::sort(b.begin(), b.end());
+ strings_v::iterator be(std::unique(b.begin(), b.end()));
+ strings_v c;
+ std::set_difference(a.begin(), ae, b.begin(), be, std::back_inserter(c));
+ return c;
+}
+
+}
+
+strings_vr MigrationImpl::compileFileList()
+{
+
+ strings_vr vrResult(new strings_v);
+
+ // get a list of all files:
+ strings_vr vrFiles = getAllFiles(m_aInfo.userdata);
+
+ // get a file list result for each migration step
+ for (auto const& rMigration : *m_vrMigrations)
+ {
+ strings_vr vrInclude = applyPatterns(*vrFiles, rMigration.includeFiles);
+ strings_vr vrExclude = applyPatterns(*vrFiles, rMigration.excludeFiles);
+ strings_v sub(subtract(std::move(*vrInclude), std::move(*vrExclude)));
+ vrResult->insert(vrResult->end(), sub.begin(), sub.end());
+ }
+ return vrResult;
+}
+
+namespace
+{
+
+struct componentParts {
+ std::set< OUString > includedPaths;
+ std::set< OUString > excludedPaths;
+};
+
+typedef std::map< OUString, componentParts > Components;
+
+bool getComponent(OUString const & path, OUString * component)
+{
+ OSL_ASSERT(component != nullptr);
+ if (path.isEmpty() || path[0] != '/') {
+ SAL_INFO( "desktop.migration", "configuration migration in/exclude path " << path << " ignored (does not start with slash)" );
+ return false;
+ }
+ sal_Int32 i = path.indexOf('/', 1);
+ *component = i < 0 ? path.copy(1) : path.copy(1, i - 1);
+ return true;
+}
+
+}
+
+void MigrationImpl::copyConfig()
+{
+ Components comps;
+ for (auto const& rMigrationStep : *m_vrMigrations) {
+ for (const OUString& rIncludePath : rMigrationStep.includeConfig) {
+ OUString comp;
+ if (getComponent(rIncludePath, &comp)) {
+ comps[comp].includedPaths.insert(rIncludePath);
+ }
+ }
+ for (const OUString& rExcludePath : rMigrationStep.excludeConfig) {
+ OUString comp;
+ if (getComponent(rExcludePath, &comp)) {
+ comps[comp].excludedPaths.insert(rExcludePath);
+ }
+ }
+ }
+
+ // check if the shared registrymodifications.xcu file exists
+ bool bRegistryModificationsXcuExists = false;
+ OUString regFilePath = m_aInfo.userdata + "/user/registrymodifications.xcu";
+ File regFile(regFilePath);
+ ::osl::FileBase::RC nError = regFile.open(osl_File_OpenFlag_Read);
+ if ( nError == ::osl::FileBase::E_None ) {
+ bRegistryModificationsXcuExists = true;
+ regFile.close();
+ }
+
+ for (auto const& comp : comps)
+ {
+ if (!comp.second.includedPaths.empty()) {
+ if (!bRegistryModificationsXcuExists) {
+ // shared registrymodifications.xcu does not exists
+ // the configuration is split in many registry files
+ // determine the file names from the first element in included paths
+ OUStringBuffer buf(m_aInfo.userdata);
+ buf.append("/user/registry/data");
+ sal_Int32 n = 0;
+ do {
+ OUString seg(comp.first.getToken(0, '.', n));
+ OUString enc(
+ rtl::Uri::encode(
+ seg, rtl_UriCharClassPchar, rtl_UriEncodeStrict,
+ RTL_TEXTENCODING_UTF8));
+ if (enc.isEmpty() && !seg.isEmpty()) {
+ SAL_INFO( "desktop.migration", "configuration migration component " << comp.first << " ignored (cannot be encoded as file path)" );
+ goto next;
+ }
+ buf.append('/');
+ buf.append(enc);
+ } while (n >= 0);
+ buf.append(".xcu");
+ regFilePath = buf.makeStringAndClear();
+ }
+ configuration::Update::get(
+ comphelper::getProcessComponentContext())->
+ insertModificationXcuFile(
+ regFilePath,
+ comphelper::containerToSequence(comp.second.includedPaths),
+ comphelper::containerToSequence(comp.second.excludedPaths));
+ } else {
+ SAL_INFO( "desktop.migration", "configuration migration component " << comp.first << " ignored (only excludes, no includes)" );
+ }
+next:
+ ;
+ }
+}
+
+uno::Reference< XNameAccess > MigrationImpl::getConfigAccess(const char* pPath, bool bUpdate)
+{
+ uno::Reference< XNameAccess > xNameAccess;
+ try {
+ OUString sAccessSrvc;
+ if (bUpdate)
+ sAccessSrvc = "com.sun.star.configuration.ConfigurationUpdateAccess";
+ else
+ sAccessSrvc = "com.sun.star.configuration.ConfigurationAccess";
+
+ OUString sConfigURL = OUString::createFromAscii(pPath);
+
+ uno::Reference< XMultiServiceFactory > theConfigProvider(
+ configuration::theDefaultProvider::get(
+ comphelper::getProcessComponentContext()));
+
+ // access the provider
+ uno::Sequence< uno::Any > theArgs {uno::Any(sConfigURL)};
+ xNameAccess.set(
+ theConfigProvider->createInstanceWithArguments(
+ sAccessSrvc, theArgs ), uno::UNO_QUERY_THROW );
+ } catch (const css::uno::Exception&) {
+ TOOLS_WARN_EXCEPTION("desktop.migration", "ignoring");
+ }
+ return xNameAccess;
+}
+
+void MigrationImpl::copyFiles()
+{
+ OUString localName;
+ OUString destName;
+ OUString userInstall;
+ utl::Bootstrap::PathStatus aStatus;
+ aStatus = utl::Bootstrap::locateUserInstallation(userInstall);
+ if (aStatus == utl::Bootstrap::PATH_EXISTS) {
+ for (auto const& rFile : *m_vrFileList)
+ {
+ // remove installation prefix from file
+ localName = rFile.copy(m_aInfo.userdata.getLength());
+ if (localName.endsWith( "/autocorr/acor_.dat")) {
+ // Previous versions used an empty language tag for
+ // LANGUAGE_DONTKNOW with the "[All]" autocorrection entry.
+ // As of LibreOffice 4.0 it is 'und' for LANGUAGE_UNDETERMINED
+ // so the file name is "acor_und.dat".
+ localName = OUString::Concat(localName.subView( 0, localName.getLength() - 4)) + "und.dat";
+ }
+ destName = userInstall + localName;
+ INetURLObject aURL(destName);
+ // check whether destination directory exists
+ aURL.removeSegment();
+ _checkAndCreateDirectory(aURL);
+ FileBase::RC copyResult = File::copy(rFile, destName);
+ if (copyResult != FileBase::E_None) {
+ SAL_WARN( "desktop", "Cannot copy " << rFile << " to " << destName);
+ }
+ }
+ } else {
+ OSL_FAIL("copyFiles: UserInstall does not exist");
+ }
+}
+
+void MigrationImpl::runServices()
+{
+ // Build argument array
+ uno::Sequence< uno::Any > seqArguments(3);
+ auto pseqArguments = seqArguments.getArray();
+ pseqArguments[0] <<= NamedValue("Productname",
+ uno::Any(m_aInfo.productname));
+ pseqArguments[1] <<= NamedValue("UserData",
+ uno::Any(m_aInfo.userdata));
+
+
+ // create an instance of every migration service
+ // and execute the migration job
+ uno::Reference< XJob > xMigrationJob;
+
+ uno::Reference< uno::XComponentContext > xContext(comphelper::getProcessComponentContext());
+ for (auto const& rMigration : *m_vrMigrations)
+ {
+ if( !rMigration.service.isEmpty()) {
+
+ try {
+ // set black list for extension migration
+ uno::Sequence< OUString > seqExtDenyList;
+ sal_uInt32 nSize = rMigration.excludeExtensions.size();
+ if ( nSize > 0 )
+ seqExtDenyList = comphelper::arrayToSequence< OUString >(
+ rMigration.excludeExtensions.data(), nSize );
+ pseqArguments[2] <<= NamedValue("ExtensionDenyList",
+ uno::Any( seqExtDenyList ));
+
+ xMigrationJob.set(
+ xContext->getServiceManager()->createInstanceWithArgumentsAndContext(rMigration.service, seqArguments, xContext),
+ uno::UNO_QUERY_THROW);
+
+ xMigrationJob->execute(uno::Sequence< NamedValue >());
+
+
+ } catch (const Exception&) {
+ TOOLS_WARN_EXCEPTION( "desktop", "Execution of migration service failed. Service: "
+ << rMigration.service);
+ } catch (...) {
+ SAL_WARN( "desktop", "Execution of migration service failed (Exception caught).\nService: "
+ << rMigration.service << "\nNo message available");
+ }
+
+ }
+ }
+}
+
+std::vector< MigrationModuleInfo > MigrationImpl::detectUIChangesForAllModules() const
+{
+ std::vector< MigrationModuleInfo > vModulesInfo;
+ static const OUStringLiteral MENUBAR(u"menubar");
+ static const OUStringLiteral TOOLBAR(u"toolbar");
+
+ uno::Sequence< uno::Any > lArgs {uno::Any(m_aInfo.userdata + "/user/config/soffice.cfg/modules"),
+ uno::Any(embed::ElementModes::READ)};
+
+ uno::Reference< lang::XSingleServiceFactory > xStorageFactory(
+ embed::FileSystemStorageFactory::create(comphelper::getProcessComponentContext()));
+ uno::Reference< embed::XStorage > xModules;
+
+ xModules.set(xStorageFactory->createInstanceWithArguments(lArgs), uno::UNO_QUERY);
+ if (!xModules.is())
+ return vModulesInfo;
+
+ uno::Sequence< OUString > lNames = xModules->getElementNames();
+ sal_Int32 nLength = lNames.getLength();
+ for (sal_Int32 i=0; i<nLength; ++i) {
+ OUString sModuleShortName = lNames[i];
+ uno::Reference< embed::XStorage > xModule = xModules->openStorageElement(sModuleShortName, embed::ElementModes::READ);
+ if (xModule.is()) {
+ MigrationModuleInfo aModuleInfo;
+
+ uno::Reference< embed::XStorage > xMenubar = xModule->openStorageElement(MENUBAR, embed::ElementModes::READ);
+ if (xMenubar.is()) {
+ if (xMenubar->getElementNames().hasElements()) {
+ aModuleInfo.sModuleShortName = sModuleShortName;
+ aModuleInfo.bHasMenubar = true;
+ }
+ }
+
+ uno::Reference< embed::XStorage > xToolbar = xModule->openStorageElement(TOOLBAR, embed::ElementModes::READ);
+ if (xToolbar.is()) {
+ const ::uno::Sequence< OUString > lToolbars = xToolbar->getElementNames();
+ for (OUString const & sToolbarName : lToolbars) {
+ if (sToolbarName.startsWith("custom_"))
+ continue;
+
+ aModuleInfo.sModuleShortName = sModuleShortName;
+ sal_Int32 nIndex = sToolbarName.lastIndexOf('.');
+ if (nIndex > 0) {
+ std::u16string_view sExtension(sToolbarName.subView(nIndex));
+ OUString sToolbarResourceName(sToolbarName.copy(0, nIndex));
+ if (!sToolbarResourceName.isEmpty() && sExtension == u".xml")
+ aModuleInfo.m_vToolbars.push_back(sToolbarResourceName);
+ }
+ }
+ }
+
+ if (!aModuleInfo.sModuleShortName.isEmpty())
+ vModulesInfo.push_back(aModuleInfo);
+ }
+ }
+
+ return vModulesInfo;
+}
+
+void MigrationImpl::compareOldAndNewConfig(const OUString& sParent,
+ const uno::Reference< container::XIndexContainer >& xIndexOld,
+ const uno::Reference< container::XIndexContainer >& xIndexNew,
+ const OUString& sResourceURL)
+{
+ static const OUStringLiteral MENU_SEPARATOR(u" | ");
+
+ std::vector< MigrationItem > vOldItems;
+ std::vector< MigrationItem > vNewItems;
+ uno::Sequence< beans::PropertyValue > aProps;
+ sal_Int32 nOldCount = xIndexOld->getCount();
+ sal_Int32 nNewCount = xIndexNew->getCount();
+
+ for (int n=0; n<nOldCount; ++n) {
+ MigrationItem aMigrationItem;
+ if (xIndexOld->getByIndex(n) >>= aProps) {
+ for(beans::PropertyValue const & prop : std::as_const(aProps)) {
+ if ( prop.Name == ITEM_DESCRIPTOR_COMMANDURL )
+ prop.Value >>= aMigrationItem.m_sCommandURL;
+ else if ( prop.Name == ITEM_DESCRIPTOR_CONTAINER )
+ prop.Value >>= aMigrationItem.m_xPopupMenu;
+ }
+
+ if (!aMigrationItem.m_sCommandURL.isEmpty())
+ vOldItems.push_back(aMigrationItem);
+ }
+ }
+
+ for (int n=0; n<nNewCount; ++n) {
+ MigrationItem aMigrationItem;
+ if (xIndexNew->getByIndex(n) >>= aProps) {
+ for(beans::PropertyValue const & prop : std::as_const(aProps)) {
+ if ( prop.Name == ITEM_DESCRIPTOR_COMMANDURL )
+ prop.Value >>= aMigrationItem.m_sCommandURL;
+ else if ( prop.Name == ITEM_DESCRIPTOR_CONTAINER )
+ prop.Value >>= aMigrationItem.m_xPopupMenu;
+ }
+
+ if (!aMigrationItem.m_sCommandURL.isEmpty())
+ vNewItems.push_back(aMigrationItem);
+ }
+ }
+
+ OUString sSibling;
+ for (auto const& oldItem : vOldItems)
+ {
+ std::vector< MigrationItem >::iterator pFound = std::find(vNewItems.begin(), vNewItems.end(), oldItem);
+ if (pFound != vNewItems.end() && oldItem.m_xPopupMenu.is()) {
+ OUString sName;
+ if (!sParent.isEmpty())
+ sName = sParent + MENU_SEPARATOR + oldItem.m_sCommandURL;
+ else
+ sName = oldItem.m_sCommandURL;
+ compareOldAndNewConfig(sName, oldItem.m_xPopupMenu, pFound->m_xPopupMenu, sResourceURL);
+ } else if (pFound == vNewItems.end()) {
+ MigrationItem aMigrationItem(sParent, sSibling, oldItem.m_sCommandURL, oldItem.m_xPopupMenu);
+ if (m_aOldVersionItemsHashMap.find(sResourceURL)==m_aOldVersionItemsHashMap.end()) {
+ std::vector< MigrationItem > vMigrationItems;
+ m_aOldVersionItemsHashMap.emplace(sResourceURL, vMigrationItems);
+ m_aOldVersionItemsHashMap[sResourceURL].push_back(aMigrationItem);
+ } else {
+ if (std::find(m_aOldVersionItemsHashMap[sResourceURL].begin(), m_aOldVersionItemsHashMap[sResourceURL].end(), aMigrationItem)==m_aOldVersionItemsHashMap[sResourceURL].end())
+ m_aOldVersionItemsHashMap[sResourceURL].push_back(aMigrationItem);
+ }
+ }
+
+ sSibling = oldItem.m_sCommandURL;
+ }
+}
+
+void MigrationImpl::mergeOldToNewVersion(const uno::Reference< ui::XUIConfigurationManager >& xCfgManager,
+ const uno::Reference< container::XIndexContainer>& xIndexContainer,
+ const OUString& sModuleIdentifier,
+ const OUString& sResourceURL)
+{
+ MigrationHashMap::iterator pFound = m_aOldVersionItemsHashMap.find(sResourceURL);
+ if (pFound==m_aOldVersionItemsHashMap.end())
+ return;
+
+ for (auto const& elem : pFound->second)
+ {
+ uno::Reference< container::XIndexContainer > xTemp = xIndexContainer;
+
+ OUString sParentNodeName = elem.m_sParentNodeName;
+ sal_Int32 nIndex = 0;
+ do {
+ std::u16string_view sToken( o3tl::trim(o3tl::getToken(sParentNodeName, 0, '|', nIndex)) );
+ if (sToken.empty())
+ break;
+
+ sal_Int32 nCount = xTemp->getCount();
+ for (sal_Int32 i=0; i<nCount; ++i) {
+ OUString sCommandURL;
+ OUString sLabel;
+ uno::Reference< container::XIndexContainer > xChild;
+
+ uno::Sequence< beans::PropertyValue > aPropSeq;
+ xTemp->getByIndex(i) >>= aPropSeq;
+ for (beans::PropertyValue const & prop : std::as_const(aPropSeq)) {
+ OUString sPropName = prop.Name;
+ if ( sPropName == ITEM_DESCRIPTOR_COMMANDURL )
+ prop.Value >>= sCommandURL;
+ else if ( sPropName == ITEM_DESCRIPTOR_LABEL )
+ prop.Value >>= sLabel;
+ else if ( sPropName == ITEM_DESCRIPTOR_CONTAINER )
+ prop.Value >>= xChild;
+ }
+
+ if (sCommandURL == sToken) {
+ xTemp = xChild;
+ break;
+ }
+ }
+
+ } while (nIndex >= 0);
+
+ if (nIndex == -1) {
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(elem.m_sCommandURL, sModuleIdentifier);
+ uno::Sequence< beans::PropertyValue > aPropSeq {
+ beans::PropertyValue(ITEM_DESCRIPTOR_COMMANDURL, 0, uno::Any(elem.m_sCommandURL), beans::PropertyState_DIRECT_VALUE),
+ beans::PropertyValue(ITEM_DESCRIPTOR_LABEL, 0, uno::Any(vcl::CommandInfoProvider::GetLabelForCommand(aProperties)), beans::PropertyState_DIRECT_VALUE),
+ beans::PropertyValue(ITEM_DESCRIPTOR_CONTAINER, 0, uno::Any(elem.m_xPopupMenu), beans::PropertyState_DIRECT_VALUE)
+ };
+
+ if (elem.m_sPrevSibling.isEmpty())
+ xTemp->insertByIndex(0, uno::Any(aPropSeq));
+ else {
+ sal_Int32 nCount = xTemp->getCount();
+ sal_Int32 i = 0;
+ for (; i<nCount; ++i) {
+ OUString sCmd;
+ uno::Sequence< beans::PropertyValue > aTempPropSeq;
+ xTemp->getByIndex(i) >>= aTempPropSeq;
+ for (beans::PropertyValue const & prop : std::as_const(aTempPropSeq)) {
+ if ( prop.Name == ITEM_DESCRIPTOR_COMMANDURL ) {
+ prop.Value >>= sCmd;
+ break;
+ }
+ }
+
+ if (sCmd == elem.m_sPrevSibling)
+ break;
+ }
+
+ xTemp->insertByIndex(i+1, uno::Any(aPropSeq));
+ }
+ }
+ }
+
+ if (xIndexContainer.is())
+ xCfgManager->replaceSettings(sResourceURL, xIndexContainer);
+
+ uno::Reference< ui::XUIConfigurationPersistence > xUIConfigurationPersistence(xCfgManager, uno::UNO_QUERY);
+ if (xUIConfigurationPersistence.is())
+ xUIConfigurationPersistence->store();
+}
+
+uno::Reference< ui::XUIConfigurationManager > NewVersionUIInfo::getConfigManager(std::u16string_view sModuleShortName) const
+{
+ uno::Reference< ui::XUIConfigurationManager > xCfgManager;
+
+ for ( const css::beans::PropertyValue& rProp : m_lCfgManagerSeq) {
+ if (rProp.Name == sModuleShortName) {
+ rProp.Value >>= xCfgManager;
+ break;
+ }
+ }
+
+ return xCfgManager;
+}
+
+uno::Reference< container::XIndexContainer > NewVersionUIInfo::getNewMenubarSettings(std::u16string_view sModuleShortName) const
+{
+ uno::Reference< container::XIndexContainer > xNewMenuSettings;
+
+ for (auto const & prop : m_lNewVersionMenubarSettingsSeq) {
+ if (prop.Name == sModuleShortName) {
+ prop.Value >>= xNewMenuSettings;
+ break;
+ }
+ }
+
+ return xNewMenuSettings;
+}
+
+uno::Reference< container::XIndexContainer > NewVersionUIInfo::getNewToolbarSettings(std::u16string_view sModuleShortName, std::u16string_view sToolbarName) const
+{
+ uno::Reference< container::XIndexContainer > xNewToolbarSettings;
+
+ for (auto const & newProp : m_lNewVersionToolbarSettingsSeq) {
+ if (newProp.Name == sModuleShortName) {
+ uno::Sequence< beans::PropertyValue > lToolbarSettingsSeq;
+ newProp.Value >>= lToolbarSettingsSeq;
+ for (auto const & prop : std::as_const(lToolbarSettingsSeq)) {
+ if (prop.Name == sToolbarName) {
+ prop.Value >>= xNewToolbarSettings;
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+
+ return xNewToolbarSettings;
+}
+
+void NewVersionUIInfo::init(const std::vector< MigrationModuleInfo >& vModulesInfo)
+{
+ m_lCfgManagerSeq.resize(vModulesInfo.size());
+ m_lNewVersionMenubarSettingsSeq.realloc(vModulesInfo.size());
+ auto p_lNewVersionMenubarSettingsSeq = m_lNewVersionMenubarSettingsSeq.getArray();
+ m_lNewVersionToolbarSettingsSeq.realloc(vModulesInfo.size());
+ auto p_lNewVersionToolbarSettingsSeq = m_lNewVersionToolbarSettingsSeq.getArray();
+
+ static const OUStringLiteral sMenubarResourceURL(u"private:resource/menubar/menubar");
+ static const OUStringLiteral sToolbarResourcePre(u"private:resource/toolbar/");
+
+ uno::Reference< ui::XModuleUIConfigurationManagerSupplier > xModuleCfgSupplier = ui::theModuleUIConfigurationManagerSupplier::get( ::comphelper::getProcessComponentContext() );
+
+ for (size_t i=0; i<vModulesInfo.size(); ++i) {
+ OUString sModuleIdentifier = mapModuleShortNameToIdentifier(vModulesInfo[i].sModuleShortName);
+ if (!sModuleIdentifier.isEmpty()) {
+ uno::Reference< ui::XUIConfigurationManager > xCfgManager = xModuleCfgSupplier->getUIConfigurationManager(sModuleIdentifier);
+ m_lCfgManagerSeq[i].Name = vModulesInfo[i].sModuleShortName;
+ m_lCfgManagerSeq[i].Value <<= xCfgManager;
+
+ if (vModulesInfo[i].bHasMenubar) {
+ p_lNewVersionMenubarSettingsSeq[i].Name = vModulesInfo[i].sModuleShortName;
+ p_lNewVersionMenubarSettingsSeq[i].Value <<= xCfgManager->getSettings(sMenubarResourceURL, true);
+ }
+
+ sal_Int32 nToolbars = vModulesInfo[i].m_vToolbars.size();
+ if (nToolbars > 0) {
+ uno::Sequence< beans::PropertyValue > lPropSeq(nToolbars);
+ auto plPropSeq = lPropSeq.getArray();
+ for (sal_Int32 j=0; j<nToolbars; ++j) {
+ OUString sToolbarName = vModulesInfo[i].m_vToolbars[j];
+ OUString sToolbarResourceURL = sToolbarResourcePre + sToolbarName;
+
+ plPropSeq[j].Name = sToolbarName;
+ plPropSeq[j].Value <<= xCfgManager->getSettings(sToolbarResourceURL, true);
+ }
+
+ p_lNewVersionToolbarSettingsSeq[i].Name = vModulesInfo[i].sModuleShortName;
+ p_lNewVersionToolbarSettingsSeq[i].Value <<= lPropSeq;
+ }
+ }
+ }
+}
+
+} // namespace desktop
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/migration_impl.hxx b/desktop/source/migration/migration_impl.hxx
new file mode 100644
index 000000000..6b0923d29
--- /dev/null
+++ b/desktop/source/migration/migration_impl.hxx
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+#include <string_view>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <o3tl/string_view.hxx>
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/ui/XUIConfigurationManager.hpp>
+
+namespace desktop
+{
+
+struct install_info
+{
+ OUString productname; // human readable product name
+ OUString userdata; // file: url for user installation
+};
+
+typedef std::vector< OUString > strings_v;
+typedef std::unique_ptr< strings_v > strings_vr;
+
+struct migration_step
+{
+ strings_v includeFiles;
+ strings_v excludeFiles;
+ strings_v includeConfig;
+ strings_v excludeConfig;
+ strings_v excludeExtensions;
+ OUString service;
+};
+
+struct supported_migration
+{
+ OUString name;
+ sal_Int32 nPriority;
+ strings_v supported_versions;
+};
+
+typedef std::vector< migration_step > migrations_v;
+typedef std::unique_ptr< migrations_v > migrations_vr;
+typedef std::vector< supported_migration > migrations_available;
+
+inline bool areBothOpenFrom(std::u16string_view cmd1, std::u16string_view cmd2)
+{
+ return cmd1 == u".uno:Open" && o3tl::starts_with(cmd2, u".uno:OpenFrom");
+}
+
+/**
+ define the item, e.g.:menuitem, toolbaritem, to be migrated. we keep the information
+ of the command URL, the previous sibling node and the parent node of an item
+*/
+struct MigrationItem
+{
+ OUString m_sParentNodeName;
+ OUString m_sPrevSibling;
+ OUString m_sCommandURL;
+ css::uno::Reference< css::container::XIndexContainer > m_xPopupMenu;
+
+ MigrationItem()
+ {
+ }
+
+ MigrationItem(OUString sParentNodeName,
+ OUString sPrevSibling,
+ OUString sCommandURL,
+ css::uno::Reference< css::container::XIndexContainer > xPopupMenu)
+ : m_sParentNodeName(std::move(sParentNodeName)), m_sPrevSibling(std::move(sPrevSibling)),
+ m_sCommandURL(std::move(sCommandURL)), m_xPopupMenu(std::move(xPopupMenu))
+ {
+ }
+
+ bool operator==(const MigrationItem& aMigrationItem) const
+ {
+ return
+ (aMigrationItem.m_sCommandURL == m_sCommandURL
+ || areBothOpenFrom(aMigrationItem.m_sCommandURL, m_sCommandURL)
+ || areBothOpenFrom(m_sCommandURL, aMigrationItem.m_sCommandURL))
+ && aMigrationItem.m_sParentNodeName == m_sParentNodeName
+ && aMigrationItem.m_sPrevSibling == m_sPrevSibling
+ && aMigrationItem.m_xPopupMenu.is() == m_xPopupMenu.is();
+ }
+};
+
+typedef std::unordered_map< OUString, std::vector< MigrationItem > > MigrationHashMap;
+
+/**
+ information for the UI elements to be migrated for one module
+*/
+struct MigrationModuleInfo
+{
+ OUString sModuleShortName;
+ bool bHasMenubar;
+ std::vector< OUString > m_vToolbars;
+
+ MigrationModuleInfo() : bHasMenubar(false) {};
+};
+
+
+/**
+ get the information before copying the ui configuration files of old version to new version
+*/
+class NewVersionUIInfo
+{
+public:
+
+ css::uno::Reference< css::ui::XUIConfigurationManager > getConfigManager(std::u16string_view sModuleShortName) const;
+ css::uno::Reference< css::container::XIndexContainer > getNewMenubarSettings(std::u16string_view sModuleShortName) const;
+ css::uno::Reference< css::container::XIndexContainer > getNewToolbarSettings(std::u16string_view sModuleShortName, std::u16string_view sToolbarName) const;
+ void init(const std::vector< MigrationModuleInfo >& vModulesInfo);
+
+private:
+
+ std::vector< css::beans::PropertyValue > m_lCfgManagerSeq;
+ css::uno::Sequence< css::beans::PropertyValue > m_lNewVersionMenubarSettingsSeq;
+ css::uno::Sequence< css::beans::PropertyValue > m_lNewVersionToolbarSettingsSeq;
+};
+
+class MigrationImpl
+{
+
+private:
+ migrations_available m_vMigrationsAvailable; // list of all available migrations
+ migrations_vr m_vrMigrations; // list of all migration specs from config
+ install_info m_aInfo; // info about the version being migrated
+ strings_vr m_vrFileList; // final list of files to be copied
+ MigrationHashMap m_aOldVersionItemsHashMap;
+
+ // functions to control the migration process
+ static void readAvailableMigrations(migrations_available&);
+ bool alreadyMigrated();
+ static migrations_vr readMigrationSteps(const OUString& rMigrationName);
+ sal_Int32 findPreferredMigrationProcess(const migrations_available&);
+#if defined UNX && ! defined MACOSX
+ static OUString preXDGConfigDir(const OUString& rConfigDir);
+#endif
+ static void setInstallInfoIfExist(install_info& aInfo, std::u16string_view rConfigDir, const OUString& rVersion);
+ static install_info findInstallation(const strings_v& rVersions);
+ strings_vr compileFileList();
+
+ // helpers
+ strings_vr getAllFiles(const OUString& baseURL) const;
+ static strings_vr applyPatterns(const strings_v& vSet, const strings_v& vPatterns);
+ static css::uno::Reference< css::container::XNameAccess > getConfigAccess(const char* path, bool rw=false);
+
+ std::vector< MigrationModuleInfo > detectUIChangesForAllModules() const;
+ void compareOldAndNewConfig(const OUString& sParentNodeName,
+ const css::uno::Reference< css::container::XIndexContainer >& xOldIndexContainer,
+ const css::uno::Reference< css::container::XIndexContainer >& xNewIndexContainer,
+ const OUString& sToolbarName);
+ void mergeOldToNewVersion(const css::uno::Reference< css::ui::XUIConfigurationManager >& xCfgManager,
+ const css::uno::Reference< css::container::XIndexContainer>& xIndexContainer,
+ const OUString& sModuleIdentifier,
+ const OUString& sResourceURL);
+
+ // actual processing function that perform the migration steps
+ void copyFiles();
+ void copyConfig();
+ void runServices();
+
+ static void setMigrationCompleted();
+ static bool checkMigrationCompleted();
+
+public:
+ MigrationImpl();
+ ~MigrationImpl();
+ bool initializeMigration();
+ bool doMigration();
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/basicmigration.cxx b/desktop/source/migration/services/basicmigration.cxx
new file mode 100644
index 000000000..94e8677de
--- /dev/null
+++ b/desktop/source/migration/services/basicmigration.cxx
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "basicmigration.hxx"
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/bootstrap.hxx>
+#include <sal/log.hxx>
+#include <osl/file.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+
+namespace migration
+{
+
+
+ #define sSourceUserBasic "/user/basic"
+ #define sTargetUserBasic "/user/__basic_80"
+
+
+ // BasicMigration
+
+
+ BasicMigration::BasicMigration()
+ {
+ }
+
+
+ BasicMigration::~BasicMigration()
+ {
+ }
+
+
+ TStringVectorPtr BasicMigration::getFiles( const OUString& rBaseURL ) const
+ {
+ TStringVectorPtr aResult( new TStringVector );
+ ::osl::Directory aDir( rBaseURL);
+
+ if ( aDir.open() == ::osl::FileBase::E_None )
+ {
+ // iterate over directory content
+ TStringVector aSubDirs;
+ ::osl::DirectoryItem aItem;
+ while ( aDir.getNextItem( aItem ) == ::osl::FileBase::E_None )
+ {
+ ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL );
+ if ( aItem.getFileStatus( aFileStatus ) == ::osl::FileBase::E_None )
+ {
+ if ( aFileStatus.getFileType() == ::osl::FileStatus::Directory )
+ aSubDirs.push_back( aFileStatus.getFileURL() );
+ else
+ aResult->push_back( aFileStatus.getFileURL() );
+ }
+ }
+
+ // iterate recursive over subfolders
+ for (auto const& subDir : aSubDirs)
+ {
+ TStringVectorPtr aSubResult = getFiles(subDir);
+ aResult->insert( aResult->end(), aSubResult->begin(), aSubResult->end() );
+ }
+ }
+
+ return aResult;
+ }
+
+
+ void BasicMigration::checkAndCreateDirectory( INetURLObject const & rDirURL )
+ {
+ ::osl::FileBase::RC aResult = ::osl::Directory::create( rDirURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ) );
+ if ( aResult == ::osl::FileBase::E_NOENT )
+ {
+ INetURLObject aBaseURL( rDirURL );
+ aBaseURL.removeSegment();
+ checkAndCreateDirectory( aBaseURL );
+ ::osl::Directory::create( rDirURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ) );
+ }
+ }
+
+
+ void BasicMigration::copyFiles()
+ {
+ OUString sTargetDir;
+ ::utl::Bootstrap::PathStatus aStatus = ::utl::Bootstrap::locateUserInstallation( sTargetDir );
+ if ( aStatus == ::utl::Bootstrap::PATH_EXISTS )
+ {
+ sTargetDir += sTargetUserBasic;
+ TStringVectorPtr aFileList = getFiles( m_sSourceDir );
+ for (auto const& elem : *aFileList)
+ {
+ std::u16string_view sLocalName = elem.subView( m_sSourceDir.getLength() );
+ OUString sTargetName = sTargetDir + sLocalName;
+ INetURLObject aURL( sTargetName );
+ aURL.removeSegment();
+ checkAndCreateDirectory( aURL );
+ ::osl::FileBase::RC aResult = ::osl::File::copy( elem, sTargetName );
+ if ( aResult != ::osl::FileBase::E_None )
+ {
+ SAL_WARN( "desktop", "BasicMigration::copyFiles: cannot copy "
+ << elem << " to " << sTargetName );
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL( "BasicMigration::copyFiles: no user installation!" );
+ }
+ }
+
+
+ // XServiceInfo
+
+
+ OUString BasicMigration::getImplementationName()
+ {
+ return "com.sun.star.comp.desktop.migration.Basic";
+ }
+
+
+ sal_Bool BasicMigration::supportsService(OUString const & ServiceName)
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+
+ Sequence< OUString > BasicMigration::getSupportedServiceNames()
+ {
+ return { "com.sun.star.migration.Basic" };
+ }
+
+
+ // XInitialization
+
+
+ void BasicMigration::initialize( const Sequence< Any >& aArguments )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ const Any* pIter = aArguments.getConstArray();
+ const Any* pEnd = pIter + aArguments.getLength();
+ for ( ; pIter != pEnd ; ++pIter )
+ {
+ beans::NamedValue aValue;
+ *pIter >>= aValue;
+ if ( aValue.Name == "UserData" )
+ {
+ if ( !(aValue.Value >>= m_sSourceDir) )
+ {
+ OSL_FAIL( "BasicMigration::initialize: argument UserData has wrong type!" );
+ }
+ m_sSourceDir += sSourceUserBasic;
+ break;
+ }
+ }
+ }
+
+
+ // XJob
+
+
+ Any BasicMigration::execute( const Sequence< beans::NamedValue >& )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ copyFiles();
+
+ return Any();
+ }
+
+
+} // namespace migration
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+desktop_BasicMigration_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new migration::BasicMigration());
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/basicmigration.hxx b/desktop/source/migration/services/basicmigration.hxx
new file mode 100644
index 000000000..889b9245d
--- /dev/null
+++ b/desktop/source/migration/services/basicmigration.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "misc.hxx"
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/task/XJob.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <osl/mutex.hxx>
+
+
+class INetURLObject;
+
+
+namespace migration
+{
+ typedef ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::task::XJob > BasicMigration_BASE;
+
+ class BasicMigration : public BasicMigration_BASE
+ {
+ private:
+ ::osl::Mutex m_aMutex;
+ OUString m_sSourceDir;
+
+ TStringVectorPtr getFiles( const OUString& rBaseURL ) const;
+ void checkAndCreateDirectory( INetURLObject const & rDirURL );
+ void copyFiles();
+
+ public:
+ BasicMigration();
+ virtual ~BasicMigration() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XJob
+ virtual css::uno::Any SAL_CALL execute(
+ const css::uno::Sequence< css::beans::NamedValue >& Arguments ) override;
+ };
+
+
+} // namespace migration
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/cppumaker.mk b/desktop/source/migration/services/cppumaker.mk
new file mode 100644
index 000000000..57e070f80
--- /dev/null
+++ b/desktop/source/migration/services/cppumaker.mk
@@ -0,0 +1,27 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+.IF "$(debug)" != ""
+
+# MSVC++: no inlining
+.IF "$(COM)" == "MSC"
+CFLAGS += -Ob0
+.ENDIF
+
+.ENDIF
+
diff --git a/desktop/source/migration/services/jvmfwk.cxx b/desktop/source/migration/services/jvmfwk.cxx
new file mode 100644
index 000000000..65eff6767
--- /dev/null
+++ b/desktop/source/migration/services/jvmfwk.cxx
@@ -0,0 +1,395 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/bootstrap.hxx>
+#include <sal/types.h>
+#include <sal/config.h>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/WrappedTargetException.hpp>
+#include <com/sun/star/task/XJob.hpp>
+#include <com/sun/star/configuration/backend/XLayer.hpp>
+#include <com/sun/star/configuration/backend/XLayerHandler.hpp>
+#include <com/sun/star/configuration/backend/MalformedDataException.hpp>
+#include <com/sun/star/configuration/backend/TemplateIdentifier.hpp>
+#include <jvmfwk/framework.hxx>
+#include "jvmfwk.hxx"
+#include <memory>
+#include <stack>
+#include <stdio.h>
+
+#include <osl/diagnose.h>
+
+constexpr OUStringLiteral SERVICE_NAME = u"com.sun.star.migration.Java";
+#define IMPL_NAME "com.sun.star.comp.desktop.migration.Java"
+
+#define ENABLE_JAVA 1
+#define USER_CLASS_PATH 2
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::configuration::backend;
+
+namespace migration
+{
+
+namespace {
+
+class JavaMigration : public ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::task::XJob,
+ css::configuration::backend::XLayerHandler>
+{
+public:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ //XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ //XJob
+ virtual css::uno::Any SAL_CALL execute(
+ const css::uno::Sequence<css::beans::NamedValue >& Arguments ) override;
+
+ // XLayerHandler
+ virtual void SAL_CALL startLayer() override;
+
+ virtual void SAL_CALL endLayer() override;
+
+ virtual void SAL_CALL overrideNode(
+ const OUString& aName,
+ sal_Int16 aAttributes,
+ sal_Bool bClear) override;
+
+ virtual void SAL_CALL addOrReplaceNode(
+ const OUString& aName,
+ sal_Int16 aAttributes) override;
+
+ virtual void SAL_CALL addOrReplaceNodeFromTemplate(
+ const OUString& aName,
+ const css::configuration::backend::TemplateIdentifier& aTemplate,
+ sal_Int16 aAttributes ) override;
+
+ virtual void SAL_CALL endNode() override;
+
+ virtual void SAL_CALL dropNode(
+ const OUString& aName ) override;
+
+ virtual void SAL_CALL overrideProperty(
+ const OUString& aName,
+ sal_Int16 aAttributes,
+ const css::uno::Type& aType,
+ sal_Bool bClear ) override;
+
+ virtual void SAL_CALL setPropertyValue(
+ const css::uno::Any& aValue ) override;
+
+ virtual void SAL_CALL setPropertyValueForLocale(
+ const css::uno::Any& aValue,
+ const OUString& aLocale ) override;
+
+ virtual void SAL_CALL endProperty() override;
+
+ virtual void SAL_CALL addProperty(
+ const OUString& aName,
+ sal_Int16 aAttributes,
+ const css::uno::Type& aType ) override;
+
+ virtual void SAL_CALL addPropertyWithValue(
+ const OUString& aName,
+ sal_Int16 aAttributes,
+ const css::uno::Any& aValue ) override;
+
+
+ virtual ~JavaMigration() override;
+
+private:
+ OUString m_sUserDir;
+ css::uno::Reference< css::configuration::backend::XLayer> m_xLayer;
+
+ void migrateJavarc();
+ typedef std::pair< OUString, sal_Int16> TElementType;
+ typedef std::stack< TElementType > TElementStack;
+ TElementStack m_aStack;
+
+};
+
+}
+
+JavaMigration::~JavaMigration()
+{
+ OSL_ASSERT(m_aStack.empty());
+}
+
+OUString jvmfwk_getImplementationName()
+{
+ return IMPL_NAME;
+}
+
+css::uno::Sequence< OUString > jvmfwk_getSupportedServiceNames()
+{
+ return { SERVICE_NAME };
+}
+
+// XServiceInfo
+OUString SAL_CALL JavaMigration::getImplementationName()
+{
+ return jvmfwk_getImplementationName();
+}
+
+sal_Bool JavaMigration::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL JavaMigration::getSupportedServiceNames()
+{
+ return jvmfwk_getSupportedServiceNames();
+}
+
+//XInitialization ----------------------------------------------------------------------
+void SAL_CALL JavaMigration::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ const css::uno::Any* pIter = aArguments.getConstArray();
+ const css::uno::Any* pEnd = pIter + aArguments.getLength();
+ css::uno::Sequence<css::beans::NamedValue> aOldConfigValues;
+ css::beans::NamedValue aValue;
+ for(;pIter != pEnd;++pIter)
+ {
+ *pIter >>= aValue;
+ if ( aValue.Name == "OldConfiguration" )
+ {
+ bool bSuccess = aValue.Value >>= aOldConfigValues;
+ OSL_ENSURE(bSuccess, "[Service implementation " IMPL_NAME
+ "] XInitialization::initialize: Argument OldConfiguration has wrong type.");
+ if (bSuccess)
+ {
+ const css::beans::NamedValue* pIter2 = aOldConfigValues.getConstArray();
+ const css::beans::NamedValue* pEnd2 = pIter2 + aOldConfigValues.getLength();
+ for(;pIter2 != pEnd2;++pIter2)
+ {
+ if ( pIter2->Name == "org.openoffice.Office.Java" )
+ {
+ pIter2->Value >>= m_xLayer;
+ break;
+ }
+ }
+ }
+ }
+ else if ( aValue.Name == "UserData" )
+ {
+ if ( !(aValue.Value >>= m_sUserDir) )
+ {
+ OSL_FAIL(
+ "[Service implementation " IMPL_NAME
+ "] XInitialization::initialize: Argument UserData has wrong type.");
+ }
+ }
+ }
+
+}
+
+//XJob
+css::uno::Any SAL_CALL JavaMigration::execute(
+ const css::uno::Sequence<css::beans::NamedValue >& )
+{
+ migrateJavarc();
+ if (m_xLayer.is())
+ m_xLayer->readData(this);
+
+ return css::uno::Any();
+}
+
+void JavaMigration::migrateJavarc()
+{
+ if (m_sUserDir.isEmpty())
+ return;
+
+ OUString sValue;
+ rtl::Bootstrap javaini(m_sUserDir + "/user/config/" SAL_CONFIGFILE("java"));
+ bool bSuccess = javaini.getFrom("Home", sValue);
+ OSL_ENSURE(bSuccess, "[Service implementation " IMPL_NAME
+ "] XJob::execute: Could not get Home entry from java.ini/javarc.");
+ if (!bSuccess || sValue.isEmpty())
+ return;
+
+ //get the directory
+ std::unique_ptr<JavaInfo> aInfo;
+ javaFrameworkError err = jfw_getJavaInfoByPath(sValue, &aInfo);
+
+ if (err == JFW_E_NONE)
+ {
+ if (jfw_setSelectedJRE(aInfo.get()) != JFW_E_NONE)
+ {
+ OSL_FAIL("[Service implementation " IMPL_NAME
+ "] XJob::execute: jfw_setSelectedJRE failed.");
+ fprintf(stderr, "\nCannot migrate Java. An error occurred.\n");
+ }
+ }
+ else if (err == JFW_E_FAILED_VERSION)
+ {
+ fprintf(stderr, "\nCannot migrate Java settings because the version of the Java "
+ "is not supported anymore.\n");
+ }
+}
+
+
+// XLayerHandler
+void SAL_CALL JavaMigration::startLayer()
+{
+}
+
+
+void SAL_CALL JavaMigration::endLayer()
+{
+}
+
+
+void SAL_CALL JavaMigration::overrideNode(
+ const OUString&,
+ sal_Int16,
+ sal_Bool)
+
+{
+
+}
+
+
+void SAL_CALL JavaMigration::addOrReplaceNode(
+ const OUString&,
+ sal_Int16)
+{
+
+}
+void SAL_CALL JavaMigration::endNode()
+{
+}
+
+
+void SAL_CALL JavaMigration::dropNode(
+ const OUString& )
+{
+}
+
+
+void SAL_CALL JavaMigration::overrideProperty(
+ const OUString& aName,
+ sal_Int16,
+ const Type&,
+ sal_Bool )
+{
+ if ( aName == "Enable" )
+ m_aStack.push(TElementStack::value_type(aName,ENABLE_JAVA));
+ else if ( aName == "UserClassPath" )
+ m_aStack.push(TElementStack::value_type(aName, USER_CLASS_PATH));
+}
+
+
+void SAL_CALL JavaMigration::setPropertyValue(
+ const Any& aValue )
+{
+ if ( m_aStack.empty())
+ return;
+
+ switch (m_aStack.top().second)
+ {
+ case ENABLE_JAVA:
+ {
+ bool val;
+ if (!(aValue >>= val))
+ throw MalformedDataException(
+ "[Service implementation " IMPL_NAME
+ "] XLayerHandler::setPropertyValue received wrong type for Enable property", nullptr, Any());
+ if (jfw_setEnabled(val) != JFW_E_NONE)
+ throw WrappedTargetException(
+ "[Service implementation " IMPL_NAME
+ "] XLayerHandler::setPropertyValue: jfw_setEnabled failed.", nullptr, Any());
+
+ break;
+ }
+ case USER_CLASS_PATH:
+ {
+ OUString cp;
+ if (!(aValue >>= cp))
+ throw MalformedDataException(
+ "[Service implementation " IMPL_NAME
+ "] XLayerHandler::setPropertyValue received wrong type for UserClassPath property", nullptr, Any());
+
+ if (jfw_setUserClassPath(cp) != JFW_E_NONE)
+ throw WrappedTargetException(
+ "[Service implementation " IMPL_NAME
+ "] XLayerHandler::setPropertyValue: jfw_setUserClassPath failed.", nullptr, Any());
+ break;
+ }
+ default:
+ OSL_ASSERT(false);
+ }
+}
+
+
+void SAL_CALL JavaMigration::setPropertyValueForLocale(
+ const Any&,
+ const OUString& )
+{
+}
+
+
+void SAL_CALL JavaMigration::endProperty()
+{
+ if (!m_aStack.empty())
+ m_aStack.pop();
+}
+
+
+void SAL_CALL JavaMigration::addProperty(
+ const OUString&,
+ sal_Int16,
+ const Type& )
+{
+}
+
+
+void SAL_CALL JavaMigration::addPropertyWithValue(
+ const OUString&,
+ sal_Int16,
+ const Any& )
+{
+}
+
+void SAL_CALL JavaMigration::addOrReplaceNodeFromTemplate(
+ const OUString&,
+ const TemplateIdentifier&,
+ sal_Int16 )
+{
+}
+
+
+//ToDo enable java, user class path
+
+} //end namespace jfw
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/jvmfwk.hxx b/desktop/source/migration/services/jvmfwk.hxx
new file mode 100644
index 000000000..63ec7e717
--- /dev/null
+++ b/desktop/source/migration/services/jvmfwk.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+namespace migration
+{
+OUString jvmfwk_getImplementationName();
+
+css::uno::Sequence<OUString> jvmfwk_getSupportedServiceNames();
+
+} //end blind namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/migrationoo2.component b/desktop/source/migration/services/migrationoo2.component
new file mode 100644
index 000000000..255023566
--- /dev/null
+++ b/desktop/source/migration/services/migrationoo2.component
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.desktop.migration.Basic"
+ constructor="desktop_BasicMigration_get_implementation">
+ <service name="com.sun.star.migration.Basic"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.desktop.migration.Wordbooks"
+ constructor="desktop_WordbookMigration_get_implementation">
+ <service name="com.sun.star.migration.Wordbooks"/>
+ </implementation>
+</component>
diff --git a/desktop/source/migration/services/migrationoo3.component b/desktop/source/migration/services/migrationoo3.component
new file mode 100644
index 000000000..74432e586
--- /dev/null
+++ b/desktop/source/migration/services/migrationoo3.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.desktop.migration.OOo3Extensions"
+ constructor="desktop_OO3ExtensionMigration_get_implementation">
+ <service name="com.sun.star.migration.Extensions"/>
+ </implementation>
+</component>
diff --git a/desktop/source/migration/services/misc.hxx b/desktop/source/migration/services/misc.hxx
new file mode 100644
index 000000000..c3b83b82e
--- /dev/null
+++ b/desktop/source/migration/services/misc.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+#include <vector>
+#include <memory>
+
+
+namespace migration
+{
+
+
+ typedef std::vector< OUString > TStringVector;
+ typedef std::unique_ptr< TStringVector > TStringVectorPtr;
+
+
+} // namespace migration
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/oo3extensionmigration.cxx b/desktop/source/migration/services/oo3extensionmigration.cxx
new file mode 100644
index 000000000..a3f9e02b6
--- /dev/null
+++ b/desktop/source/migration/services/oo3extensionmigration.cxx
@@ -0,0 +1,409 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "oo3extensionmigration.hxx"
+#include <sal/log.hxx>
+#include <osl/file.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/bootstrap.hxx>
+#include <unotools/textsearch.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/task/XInteractionApprove.hpp>
+#include <com/sun/star/ucb/CommandAbortedException.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/xml/xpath/XPathAPI.hpp>
+#include <com/sun/star/xml/xpath/XPathException.hpp>
+#include <com/sun/star/xml/dom/DOMException.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/deployment/ExtensionManager.hpp>
+#include <com/sun/star/deployment/XExtensionManager.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace migration
+{
+
+// ExtensionMigration
+
+
+OO3ExtensionMigration::OO3ExtensionMigration(Reference< XComponentContext > const & ctx) :
+m_ctx(ctx)
+{
+}
+
+
+OO3ExtensionMigration::~OO3ExtensionMigration()
+{
+}
+
+void OO3ExtensionMigration::scanUserExtensions( const OUString& sSourceDir, TStringVector& aMigrateExtensions )
+{
+ osl::Directory aScanRootDir( sSourceDir );
+ osl::FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL);
+ osl::FileBase::RC nRetCode = aScanRootDir.open();
+ if ( nRetCode != osl::Directory::E_None )
+ return;
+
+ sal_uInt32 nHint( 0 );
+ osl::DirectoryItem aItem;
+ while ( aScanRootDir.getNextItem( aItem, nHint ) == osl::Directory::E_None )
+ {
+ if (( aItem.getFileStatus(fs) == osl::FileBase::E_None ) &&
+ ( fs.getFileType() == osl::FileStatus::Directory ))
+ {
+ //Check next folder as the "real" extension folder is below a temp folder!
+ OUString sExtensionFolderURL = fs.getFileURL();
+
+ osl::Directory aExtensionRootDir( sExtensionFolderURL );
+
+ nRetCode = aExtensionRootDir.open();
+ if ( nRetCode == osl::Directory::E_None )
+ {
+ osl::DirectoryItem aExtDirItem;
+ while ( aExtensionRootDir.getNextItem( aExtDirItem, nHint ) == osl::Directory::E_None )
+ {
+ bool bFileStatus = aExtDirItem.getFileStatus(fs) == osl::FileBase::E_None;
+ bool bIsDir = fs.getFileType() == osl::FileStatus::Directory;
+
+ if ( bFileStatus && bIsDir )
+ {
+ sExtensionFolderURL = fs.getFileURL();
+ ScanResult eResult = scanExtensionFolder( sExtensionFolderURL );
+ if ( eResult == SCANRESULT_MIGRATE_EXTENSION )
+ aMigrateExtensions.push_back( sExtensionFolderURL );
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+OO3ExtensionMigration::ScanResult OO3ExtensionMigration::scanExtensionFolder( const OUString& sExtFolder )
+{
+ ScanResult aResult = SCANRESULT_NOTFOUND;
+ osl::Directory aDir(sExtFolder);
+
+ // get sub dirs
+ if (aDir.open() == osl::FileBase::E_None)
+ {
+ // work through directory contents...
+ osl::DirectoryItem item;
+ osl::FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL);
+ TStringVector aDirectories;
+ while ((aDir.getNextItem(item) == osl::FileBase::E_None ) &&
+ ( aResult == SCANRESULT_NOTFOUND ))
+ {
+ if (item.getFileStatus(fs) == osl::FileBase::E_None)
+ {
+ if (fs.getFileType() == osl::FileStatus::Directory)
+ aDirectories.push_back( fs.getFileURL() );
+ else
+ {
+ OUString aDirEntryURL = fs.getFileURL();
+ if ( aDirEntryURL.indexOf( "/description.xml" ) > 0 )
+ aResult = scanDescriptionXml( aDirEntryURL ) ? SCANRESULT_MIGRATE_EXTENSION : SCANRESULT_DONTMIGRATE_EXTENSION;
+ }
+ }
+ }
+
+ for (auto const& directory : aDirectories)
+ {
+ aResult = scanExtensionFolder(directory);
+ if (aResult != SCANRESULT_NOTFOUND)
+ break;
+ }
+ }
+ return aResult;
+}
+
+bool OO3ExtensionMigration::scanDescriptionXml( const OUString& sDescriptionXmlURL )
+{
+ if ( !m_xDocBuilder.is() )
+ {
+ m_xDocBuilder.set( xml::dom::DocumentBuilder::create(m_ctx) );
+ }
+
+ if ( !m_xSimpleFileAccess.is() )
+ {
+ m_xSimpleFileAccess = ucb::SimpleFileAccess::create(m_ctx);
+ }
+
+ OUString aExtIdentifier;
+ try
+ {
+ uno::Reference< io::XInputStream > xIn =
+ m_xSimpleFileAccess->openFileRead( sDescriptionXmlURL );
+
+ if ( xIn.is() )
+ {
+ uno::Reference< xml::dom::XDocument > xDoc = m_xDocBuilder->parse( xIn );
+ if ( xDoc.is() )
+ {
+ uno::Reference< xml::dom::XElement > xRoot = xDoc->getDocumentElement();
+ if ( xRoot.is() && xRoot->getTagName() == "description" )
+ {
+ uno::Reference< xml::xpath::XXPathAPI > xPath = xml::xpath::XPathAPI::create(m_ctx);
+
+ xPath->registerNS("desc", xRoot->getNamespaceURI());
+ xPath->registerNS("xlink", "http://www.w3.org/1999/xlink");
+
+ try
+ {
+ uno::Reference< xml::dom::XNode > xNode(
+ xPath->selectSingleNode(
+ xRoot, "desc:identifier/@value" ));
+ if ( xNode.is() )
+ aExtIdentifier = xNode->getNodeValue();
+ }
+ catch ( const xml::xpath::XPathException& )
+ {
+ }
+ catch ( const xml::dom::DOMException& )
+ {
+ }
+ }
+ }
+ }
+
+ if ( !aExtIdentifier.isEmpty() )
+ {
+ // scan extension identifier and try to match with our black list entries
+ for (const OUString & i : m_aDenyList)
+ {
+ utl::SearchParam param(i, utl::SearchParam::SearchType::Regexp);
+ utl::TextSearch ts(param, LANGUAGE_DONTKNOW);
+
+ sal_Int32 start = 0;
+ sal_Int32 end = aExtIdentifier.getLength();
+ if (ts.SearchForward(aExtIdentifier, &start, &end))
+ return false;
+ }
+ }
+ }
+ catch ( const ucb::CommandAbortedException& )
+ {
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ }
+
+ if ( aExtIdentifier.isEmpty() )
+ {
+ // Fallback:
+ // Try to use the folder name to match our black list
+ // as some extensions don't provide an identifier in the
+ // description.xml!
+ for (const OUString & i : m_aDenyList)
+ {
+ utl::SearchParam param(i, utl::SearchParam::SearchType::Regexp);
+ utl::TextSearch ts(param, LANGUAGE_DONTKNOW);
+
+ sal_Int32 start = 0;
+ sal_Int32 end = sDescriptionXmlURL.getLength();
+ if (ts.SearchForward(sDescriptionXmlURL, &start, &end))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void OO3ExtensionMigration::migrateExtension( const OUString& sSourceDir )
+{
+ css::uno::Reference< css::deployment::XExtensionManager > extMgr(
+ deployment::ExtensionManager::get( m_ctx ) );
+ try
+ {
+ rtl::Reference<TmpRepositoryCommandEnv> pCmdEnv = new TmpRepositoryCommandEnv();
+
+ uno::Reference< task::XAbortChannel > xAbortChannel;
+ extMgr->addExtension(
+ sSourceDir, uno::Sequence<beans::NamedValue>(), "user",
+ xAbortChannel, pCmdEnv );
+ }
+ catch ( css::uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION(
+ "desktop.migration",
+ "Ignoring UNO Exception while migrating extension from <" << sSourceDir << ">");
+ }
+}
+
+
+// XServiceInfo
+
+
+OUString OO3ExtensionMigration::getImplementationName()
+{
+ return "com.sun.star.comp.desktop.migration.OOo3Extensions";
+}
+
+
+sal_Bool OO3ExtensionMigration::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+Sequence< OUString > OO3ExtensionMigration::getSupportedServiceNames()
+{
+ return { "com.sun.star.migration.Extensions" };
+}
+
+
+// XInitialization
+
+
+void OO3ExtensionMigration::initialize( const Sequence< Any >& aArguments )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ const Any* pIter = aArguments.getConstArray();
+ const Any* pEnd = pIter + aArguments.getLength();
+ for ( ; pIter != pEnd ; ++pIter )
+ {
+ beans::NamedValue aValue;
+ *pIter >>= aValue;
+ if ( aValue.Name == "UserData" )
+ {
+ if ( !(aValue.Value >>= m_sSourceDir) )
+ {
+ OSL_FAIL( "ExtensionMigration::initialize: argument UserData has wrong type!" );
+ }
+ }
+ else if ( aValue.Name == "ExtensionDenyList" )
+ {
+ Sequence< OUString > aDenyList;
+ if ( (aValue.Value >>= aDenyList ) && aDenyList.hasElements())
+ {
+ m_aDenyList.resize( aDenyList.getLength() );
+ ::comphelper::sequenceToArray< OUString >( m_aDenyList.data(), aDenyList );
+ }
+ }
+ }
+}
+
+Any OO3ExtensionMigration::execute( const Sequence< beans::NamedValue >& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ::utl::Bootstrap::PathStatus aStatus = ::utl::Bootstrap::locateUserInstallation( m_sTargetDir );
+ if ( aStatus == ::utl::Bootstrap::PATH_EXISTS )
+ {
+ // copy all extensions
+ OUString sSourceDir = m_sSourceDir +
+ "/user/uno_packages/cache/uno_packages";
+ TStringVector aExtensionToMigrate;
+ scanUserExtensions( sSourceDir, aExtensionToMigrate );
+ for (auto const& extensionToMigrate : aExtensionToMigrate)
+ {
+ migrateExtension(extensionToMigrate);
+ }
+ }
+
+ return Any();
+}
+
+
+// TmpRepositoryCommandEnv
+
+
+TmpRepositoryCommandEnv::TmpRepositoryCommandEnv()
+{
+}
+
+TmpRepositoryCommandEnv::~TmpRepositoryCommandEnv()
+{
+}
+// XCommandEnvironment
+
+uno::Reference< task::XInteractionHandler > TmpRepositoryCommandEnv::getInteractionHandler()
+{
+ return this;
+}
+
+
+uno::Reference< ucb::XProgressHandler > TmpRepositoryCommandEnv::getProgressHandler()
+{
+ return this;
+}
+
+// XInteractionHandler
+void TmpRepositoryCommandEnv::handle(
+ uno::Reference< task::XInteractionRequest> const & xRequest )
+{
+ OSL_ASSERT( xRequest->getRequest().getValueTypeClass() == uno::TypeClass_EXCEPTION );
+
+ bool approve = true;
+
+ // select:
+ uno::Sequence< Reference< task::XInteractionContinuation > > conts(
+ xRequest->getContinuations() );
+ Reference< task::XInteractionContinuation > const * pConts =
+ conts.getConstArray();
+ sal_Int32 len = conts.getLength();
+ for ( sal_Int32 pos = 0; pos < len; ++pos )
+ {
+ if (approve) {
+ uno::Reference< task::XInteractionApprove > xInteractionApprove(
+ pConts[ pos ], uno::UNO_QUERY );
+ if (xInteractionApprove.is()) {
+ xInteractionApprove->select();
+ // don't query again for ongoing continuations:
+ approve = false;
+ }
+ }
+ }
+}
+
+// XProgressHandler
+void TmpRepositoryCommandEnv::push( uno::Any const & /*Status*/ )
+{
+}
+
+
+void TmpRepositoryCommandEnv::update( uno::Any const & /*Status */)
+{
+}
+
+void TmpRepositoryCommandEnv::pop()
+{
+}
+
+
+} // namespace migration
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+desktop_OO3ExtensionMigration_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new migration::OO3ExtensionMigration(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/oo3extensionmigration.hxx b/desktop/source/migration/services/oo3extensionmigration.hxx
new file mode 100644
index 000000000..586e7e99e
--- /dev/null
+++ b/desktop/source/migration/services/oo3extensionmigration.hxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "misc.hxx"
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/task/XJob.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/ucb/XProgressHandler.hpp>
+
+#include <osl/mutex.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+class INetURLObject;
+
+
+namespace migration
+{
+
+ typedef ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::task::XJob > ExtensionMigration_BASE;
+
+ class OO3ExtensionMigration : public ExtensionMigration_BASE
+ {
+ private:
+ css::uno::Reference< css::uno::XComponentContext > m_ctx;
+ css::uno::Reference< css::xml::dom::XDocumentBuilder > m_xDocBuilder;
+ css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSimpleFileAccess;
+ ::osl::Mutex m_aMutex;
+ OUString m_sSourceDir;
+ OUString m_sTargetDir;
+ TStringVector m_aDenyList;
+
+ enum ScanResult
+ {
+ SCANRESULT_NOTFOUND,
+ SCANRESULT_MIGRATE_EXTENSION,
+ SCANRESULT_DONTMIGRATE_EXTENSION
+ };
+
+ ScanResult scanExtensionFolder( const OUString& sExtFolder );
+ void scanUserExtensions( const OUString& sSourceDir, TStringVector& aMigrateExtensions );
+ bool scanDescriptionXml( const OUString& sDescriptionXmlFilePath );
+ void migrateExtension( const OUString& sSourceDir );
+
+ public:
+ explicit OO3ExtensionMigration(css::uno::Reference<
+ css::uno::XComponentContext > const & ctx);
+ virtual ~OO3ExtensionMigration() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XJob
+ virtual css::uno::Any SAL_CALL execute(
+ const css::uno::Sequence< css::beans::NamedValue >& Arguments ) override;
+ };
+
+ class TmpRepositoryCommandEnv
+ : public ::cppu::WeakImplHelper< css::ucb::XCommandEnvironment,
+ css::task::XInteractionHandler,
+ css::ucb::XProgressHandler >
+ {
+ public:
+ virtual ~TmpRepositoryCommandEnv() override;
+ TmpRepositoryCommandEnv();
+
+ // XCommandEnvironment
+ virtual css::uno::Reference< css::task::XInteractionHandler > SAL_CALL
+ getInteractionHandler() override;
+ virtual css::uno::Reference< css::ucb::XProgressHandler >
+ SAL_CALL getProgressHandler() override;
+
+ // XInteractionHandler
+ virtual void SAL_CALL handle(
+ css::uno::Reference< css::task::XInteractionRequest > const & xRequest ) override;
+
+ // XProgressHandler
+ virtual void SAL_CALL push( css::uno::Any const & Status ) override;
+ virtual void SAL_CALL update( css::uno::Any const & Status ) override;
+ virtual void SAL_CALL pop() override;
+ };
+
+
+} // namespace migration
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/wordbookmigration.cxx b/desktop/source/migration/services/wordbookmigration.cxx
new file mode 100644
index 000000000..a3fff8823
--- /dev/null
+++ b/desktop/source/migration/services/wordbookmigration.cxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "wordbookmigration.hxx"
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/bootstrap.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <sal/log.hxx>
+#include <osl/file.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+
+namespace migration
+{
+ WordbookMigration::WordbookMigration()
+ {
+ }
+
+
+ WordbookMigration::~WordbookMigration()
+ {
+ }
+
+
+ TStringVectorPtr WordbookMigration::getFiles( const OUString& rBaseURL ) const
+ {
+ TStringVectorPtr aResult( new TStringVector );
+ ::osl::Directory aDir( rBaseURL);
+
+ if ( aDir.open() == ::osl::FileBase::E_None )
+ {
+ // iterate over directory content
+ TStringVector aSubDirs;
+ ::osl::DirectoryItem aItem;
+ while ( aDir.getNextItem( aItem ) == ::osl::FileBase::E_None )
+ {
+ ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL );
+ if ( aItem.getFileStatus( aFileStatus ) == ::osl::FileBase::E_None )
+ {
+ if ( aFileStatus.getFileType() == ::osl::FileStatus::Directory )
+ aSubDirs.push_back( aFileStatus.getFileURL() );
+ else
+ aResult->push_back( aFileStatus.getFileURL() );
+ }
+ }
+
+ // iterate recursive over subfolders
+ for (auto const& subDir : aSubDirs)
+ {
+ TStringVectorPtr aSubResult = getFiles(subDir);
+ aResult->insert( aResult->end(), aSubResult->begin(), aSubResult->end() );
+ }
+ }
+
+ return aResult;
+ }
+
+
+ void WordbookMigration::checkAndCreateDirectory( INetURLObject const & rDirURL )
+ {
+ ::osl::FileBase::RC aResult = ::osl::Directory::create( rDirURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ) );
+ if ( aResult == ::osl::FileBase::E_NOENT )
+ {
+ INetURLObject aBaseURL( rDirURL );
+ aBaseURL.removeSegment();
+ checkAndCreateDirectory( aBaseURL );
+ ::osl::Directory::create( rDirURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ) );
+ }
+ }
+
+#define MAX_HEADER_LENGTH 16
+static bool IsUserWordbook( const OUString& rFile )
+{
+ bool bRet = false;
+ std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream( rFile, StreamMode::STD_READ );
+ if ( pStream && !pStream->GetError() )
+ {
+ static const char* const pVerOOo7 = "OOoUserDict1";
+ sal_uInt64 const nSniffPos = pStream->Tell();
+ static std::size_t nVerOOo7Len = sal::static_int_cast< std::size_t >(strlen( pVerOOo7 ));
+ char pMagicHeader[MAX_HEADER_LENGTH];
+ pMagicHeader[ nVerOOo7Len ] = '\0';
+ if (pStream->ReadBytes(static_cast<void *>(pMagicHeader), nVerOOo7Len) == nVerOOo7Len)
+ {
+ if ( !strcmp(pMagicHeader, pVerOOo7) )
+ bRet = true;
+ else
+ {
+ sal_uInt16 nLen;
+ pStream->Seek (nSniffPos);
+ pStream->ReadUInt16( nLen );
+ if ( nLen < MAX_HEADER_LENGTH )
+ {
+ pStream->ReadBytes(pMagicHeader, nLen);
+ pMagicHeader[nLen] = '\0';
+ if ( !strcmp(pMagicHeader, "WBSWG2")
+ || !strcmp(pMagicHeader, "WBSWG5")
+ || !strcmp(pMagicHeader, "WBSWG6") )
+ bRet = true;
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+
+ void WordbookMigration::copyFiles()
+ {
+ OUString sTargetDir;
+ ::utl::Bootstrap::PathStatus aStatus = ::utl::Bootstrap::locateUserInstallation( sTargetDir );
+ if ( aStatus == ::utl::Bootstrap::PATH_EXISTS )
+ {
+ sTargetDir += "/user/wordbook";
+ TStringVectorPtr aFileList = getFiles( m_sSourceDir );
+ for (auto const& elem : *aFileList)
+ {
+ if (IsUserWordbook(elem) )
+ {
+ std::u16string_view sSourceLocalName = elem.subView( m_sSourceDir.getLength() );
+ OUString sTargetName = sTargetDir + sSourceLocalName;
+ INetURLObject aURL( sTargetName );
+ aURL.removeSegment();
+ checkAndCreateDirectory( aURL );
+ ::osl::FileBase::RC aResult = ::osl::File::copy( elem, sTargetName );
+ if ( aResult != ::osl::FileBase::E_None )
+ {
+ SAL_WARN( "desktop", "WordbookMigration::copyFiles: cannot copy "
+ << elem << " to " << sTargetName);
+ }
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL( "WordbookMigration::copyFiles: no user installation!" );
+ }
+ }
+
+
+ // XServiceInfo
+
+
+ OUString WordbookMigration::getImplementationName()
+ {
+ return "com.sun.star.comp.desktop.migration.Wordbooks";
+ }
+
+
+ sal_Bool WordbookMigration::supportsService(OUString const & ServiceName)
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+
+ Sequence< OUString > WordbookMigration::getSupportedServiceNames()
+ {
+ return { "com.sun.star.migration.Wordbooks" };
+ }
+
+
+ // XInitialization
+
+
+ void WordbookMigration::initialize( const Sequence< Any >& aArguments )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ const Any* pIter = aArguments.getConstArray();
+ const Any* pEnd = pIter + aArguments.getLength();
+ for ( ; pIter != pEnd ; ++pIter )
+ {
+ beans::NamedValue aValue;
+ *pIter >>= aValue;
+ if ( aValue.Name == "UserData" )
+ {
+ if ( !(aValue.Value >>= m_sSourceDir) )
+ {
+ OSL_FAIL( "WordbookMigration::initialize: argument UserData has wrong type!" );
+ }
+ m_sSourceDir += "/user/wordbook";
+ break;
+ }
+ }
+ }
+
+
+ // XJob
+
+
+ Any WordbookMigration::execute( const Sequence< beans::NamedValue >& )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ copyFiles();
+
+ return Any();
+ }
+
+} // namespace migration
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+desktop_WordbookMigration_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new migration::WordbookMigration());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/migration/services/wordbookmigration.hxx b/desktop/source/migration/services/wordbookmigration.hxx
new file mode 100644
index 000000000..a6388fa42
--- /dev/null
+++ b/desktop/source/migration/services/wordbookmigration.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "misc.hxx"
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/task/XJob.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <osl/mutex.hxx>
+
+
+class INetURLObject;
+
+
+namespace migration
+{
+
+ typedef ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::task::XJob > WordbookMigration_BASE;
+
+ class WordbookMigration : public WordbookMigration_BASE
+ {
+ private:
+ ::osl::Mutex m_aMutex;
+ OUString m_sSourceDir;
+
+ TStringVectorPtr getFiles( const OUString& rBaseURL ) const;
+ void checkAndCreateDirectory( INetURLObject const & rDirURL );
+ void copyFiles();
+
+ public:
+ WordbookMigration();
+ virtual ~WordbookMigration() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XJob
+ virtual css::uno::Any SAL_CALL execute(
+ const css::uno::Sequence< css::beans::NamedValue >& Arguments ) override;
+ };
+
+
+} // namespace migration
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */