comphelper/source/misc/backupfilehelper.cxx |  766 ++++++-
 configmgr/source/components.cxx             |   29 
 desktop/source/app/app.cxx                  |  144 -
 desktop/source/app/app.cxx.orig             | 2735 ++++++++++++++++++++++++++++
 include/comphelper/backupfilehelper.hxx     |   10 
 5 files changed, 3490 insertions(+), 194 deletions(-)

New commits:
commit 5f1a338d54966f77e8aef2c77e5d01260f2f5bbe
Author: Armin Le Grand <armin.le.gr...@cib.de>
Date:   Wed Oct 12 13:25:54 2016 +0200

    profilesafe: Multiple adaptions
    
    Added own directory in User config to where the
    saved content is written and taken from, adapted
    to also handle ExtensionConfiguration, changed
    point for creating backups of configuration to
    doShutdown, create no configuration when a restart
    is triggered (untested configuration)
    
    Change-Id: Id7a96195b765842c31cacf81cc08d2965a205281
    Reviewed-on: https://gerrit.libreoffice.org/29729
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Armin Le Grand <armin.le.gr...@cib.de>

diff --git a/comphelper/source/misc/backupfilehelper.cxx 
b/comphelper/source/misc/backupfilehelper.cxx
index 8b842de..f452213 100644
--- a/comphelper/source/misc/backupfilehelper.cxx
+++ b/comphelper/source/misc/backupfilehelper.cxx
@@ -8,15 +8,25 @@
  */
 
 #include <sal/config.h>
-
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/deployment/XPackage.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/deployment/XExtensionManager.hpp>
+#include <com/sun/star/task/XAbortChannel.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/deployment/ExtensionManager.hpp>
 #include <rtl/ustring.hxx>
 #include <rtl/bootstrap.hxx>
 #include <comphelper/backupfilehelper.hxx>
 #include <rtl/crc.h>
 #include <algorithm>
 #include <deque>
+#include <vector>
 #include <zlib.h>
 
+using namespace css;
 typedef std::shared_ptr< osl::File > FileSharedPtr;
 static const sal_uInt32 BACKUP_FILE_HELPER_BLOCK_SIZE = 16384;
 
@@ -84,6 +94,403 @@ namespace
 
         return nCrc32;
     }
+
+    bool read_sal_uInt32(FileSharedPtr& rFile, sal_uInt32& rTarget)
+    {
+        sal_uInt8 aArray[4];
+        sal_uInt64 nBaseRead(0);
+
+        // read rTarget
+        if (osl::File::E_None == rFile->read(static_cast<void*>(aArray), 4, 
nBaseRead) && 4 == nBaseRead)
+        {
+            rTarget = (sal_uInt32(aArray[0]) << 24) + (sal_uInt32(aArray[1]) 
<< 16) + (sal_uInt32(aArray[2]) << 8) + sal_uInt32(aArray[3]);
+            return true;
+        }
+
+        return false;
+    }
+
+    bool write_sal_uInt32(oslFileHandle& rHandle, sal_uInt32 nSource)
+    {
+        sal_uInt8 aArray[4];
+        sal_uInt64 nBaseWritten(0);
+
+        // write nSource
+        aArray[0] = sal_uInt8((nSource & 0xff000000) >> 24);
+        aArray[1] = sal_uInt8((nSource & 0x00ff0000) >> 16);
+        aArray[2] = sal_uInt8((nSource & 0x0000ff00) >> 8);
+        aArray[3] = sal_uInt8(nSource & 0x000000ff);
+
+        if (osl_File_E_None == osl_writeFile(rHandle, static_cast<const 
void*>(aArray), 4, &nBaseWritten) && 4 == nBaseWritten)
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    bool read_OString(FileSharedPtr& rFile, OString& rTarget)
+    {
+        sal_uInt32 nLength(0);
+
+        if (!read_sal_uInt32(rFile, nLength))
+        {
+            return false;
+        }
+
+        std::vector< sal_Char > aTarget(nLength);
+        sal_uInt64 nBaseRead(0);
+
+        // read rTarget
+        if (osl::File::E_None == rFile->read(static_cast<void*>(&aTarget[0]), 
nLength, nBaseRead) && nLength == nBaseRead)
+        {
+            rTarget = OString(&aTarget[0], static_cast< sal_Int32 >(nLength));
+            return true;
+        }
+
+        return false;
+    }
+
+    bool write_OString(oslFileHandle& rHandle, const OString& rSource)
+    {
+        const sal_uInt32 nLength(rSource.getLength());
+
+        if (!write_sal_uInt32(rHandle, nLength))
+        {
+            return false;
+        }
+
+        sal_uInt64 nBaseWritten(0);
+
+        if (osl_File_E_None == osl_writeFile(rHandle, static_cast<const 
void*>(rSource.getStr()), nLength, &nBaseWritten) && nLength == nBaseWritten)
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    bool fileExists(const OUString& rBaseURL)
+    {
+        if (!rBaseURL.isEmpty())
+        {
+            FileSharedPtr aBaseFile(new osl::File(rBaseURL));
+
+            return (osl::File::E_None == 
aBaseFile->open(osl_File_OpenFlag_Read));
+        }
+
+        return false;
+    }
+}
+
+namespace
+{
+    enum PackageState { REGISTERED, NOT_REGISTERED, AMBIGUOUS, NOT_AVAILABLE };
+
+    class ExtensionInfoEntry
+    {
+    private:
+        PackageState    meState;            // REGISTERED, NOT_REGISTERED, 
AMBIGUOUS, NOT_AVAILABLE
+        OString         maRepositoryName;   // user|shared|bundled
+        OString         maName;
+        OString         maIdentifier;
+        OString         maVersion;
+
+    public:
+        ExtensionInfoEntry()
+        :   meState(NOT_AVAILABLE),
+            maRepositoryName(),
+            maName(),
+            maIdentifier(),
+            maVersion()
+        {
+        }
+
+        ExtensionInfoEntry(const uno::Reference< deployment::XPackage >& 
rxPackage)
+        :   meState(NOT_AVAILABLE),
+            maRepositoryName(OUStringToOString(rxPackage->getRepositoryName(), 
RTL_TEXTENCODING_ASCII_US)),
+            maName(OUStringToOString(rxPackage->getName(), 
RTL_TEXTENCODING_ASCII_US)),
+            maIdentifier(OUStringToOString(rxPackage->getIdentifier().Value, 
RTL_TEXTENCODING_ASCII_US)),
+            maVersion(OUStringToOString(rxPackage->getVersion(), 
RTL_TEXTENCODING_ASCII_US))
+        {
+            const beans::Optional< beans::Ambiguous< sal_Bool > > option(
+                rxPackage->isRegistered(uno::Reference< task::XAbortChannel 
>(),
+                uno::Reference< ucb::XCommandEnvironment >()));
+
+            if (option.IsPresent)
+            {
+                ::beans::Ambiguous< sal_Bool > const& reg = option.Value;
+
+                if (reg.IsAmbiguous)
+                {
+                    meState = AMBIGUOUS;
+                }
+                else
+                {
+                    meState = reg.Value ? REGISTERED : NOT_REGISTERED;
+                }
+            }
+            else
+            {
+                meState = NOT_AVAILABLE;
+            }
+        }
+
+        bool operator<(const ExtensionInfoEntry& rComp) const
+        {
+            if (0 == maRepositoryName.compareTo(rComp.maRepositoryName))
+            {
+                if (0 == maName.compareTo(rComp.maName))
+                {
+                    if (0 == maVersion.compareTo(rComp.maVersion))
+                    {
+                        if (0 == maIdentifier.compareTo(rComp.maIdentifier))
+                        {
+                            return meState < rComp.meState;
+                        }
+                        else
+                        {
+                            return 0 > 
maIdentifier.compareTo(rComp.maIdentifier);
+                        }
+                    }
+                    else
+                    {
+                        return 0 > maVersion.compareTo(rComp.maVersion);
+                    }
+                }
+                else
+                {
+                    return 0 > maName.compareTo(rComp.maName);
+                }
+            }
+            else
+            {
+                return 0 > maRepositoryName.compareTo(rComp.maRepositoryName);
+            }
+        }
+
+        bool read_entry(FileSharedPtr& rFile)
+        {
+            // read meState
+            sal_uInt32 nState(0);
+
+            if (read_sal_uInt32(rFile, nState))
+            {
+                meState = static_cast< PackageState >(nState);
+            }
+            else
+            {
+                return false;
+            }
+
+            // read maRepositoryName;
+            if (!read_OString(rFile, maRepositoryName))
+            {
+                return false;
+            }
+
+            // read maName;
+            if (!read_OString(rFile, maName))
+            {
+                return false;
+            }
+
+            // read maIdentifier;
+            if (!read_OString(rFile, maIdentifier))
+            {
+                return false;
+            }
+
+            // read maVersion;
+            if (!read_OString(rFile, maVersion))
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        bool write_entry(oslFileHandle& rHandle) const
+        {
+            // write meState
+            const sal_uInt32 nState(meState);
+
+            if (!write_sal_uInt32(rHandle, nState))
+            {
+                return false;
+            }
+
+            // write maRepositoryName
+            if (!write_OString(rHandle, maRepositoryName))
+            {
+                return false;
+            }
+
+            // write maName;
+            if (!write_OString(rHandle, maName))
+            {
+                return false;
+            }
+
+            // write maIdentifier;
+            if (!write_OString(rHandle, maIdentifier))
+            {
+                return false;
+            }
+
+            // write maVersion;
+            if (!write_OString(rHandle, maVersion))
+            {
+                return false;
+            }
+
+            return true;
+        }
+    };
+
+    typedef ::std::vector< ExtensionInfoEntry > ExtensionInfoEntryVector;
+
+    class ExtensionInfo
+    {
+    private:
+        ExtensionInfoEntryVector    maEntries;
+
+    public:
+        ExtensionInfo()
+        :   maEntries()
+        {
+        }
+
+        void reset()
+        {
+            // clear all data
+            maEntries.clear();
+        }
+
+        void createCurrent()
+        {
+            // clear all data
+            reset();
+
+            // create content from current extension configuration
+            uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage 
> > > xAllPackages;
+            uno::Reference< uno::XComponentContext > xContext = 
::comphelper::getProcessComponentContext();
+            uno::Reference< deployment::XExtensionManager > 
m_xExtensionManager = deployment::ExtensionManager::get(xContext);
+
+            try
+            {
+                xAllPackages = 
m_xExtensionManager->getAllExtensions(uno::Reference< task::XAbortChannel >(),
+                    uno::Reference< ucb::XCommandEnvironment >());
+            }
+            catch (const deployment::DeploymentException &)
+            {
+                return;
+            }
+            catch (const ucb::CommandFailedException &)
+            {
+                return;
+            }
+            catch (const ucb::CommandAbortedException &)
+            {
+                return;
+            }
+            catch (const lang::IllegalArgumentException & e)
+            {
+                throw uno::RuntimeException(e.Message, e.Context);
+            }
+
+            for (sal_Int32 i = 0; i < xAllPackages.getLength(); ++i)
+            {
+                uno::Sequence< uno::Reference< deployment::XPackage > > 
xPackageList = xAllPackages[i];
+
+                for (sal_Int32 j = 0; j < xPackageList.getLength(); ++j)
+                {
+                    uno::Reference< deployment::XPackage > xPackage = 
xPackageList[j];
+
+                    if (xPackage.is())
+                    {
+                        maEntries.push_back(ExtensionInfoEntry(xPackage));
+                    }
+                }
+            }
+
+            if (!maEntries.empty())
+            {
+                // sort the list
+                std::sort(maEntries.begin(), maEntries.end());
+            }
+        }
+
+        bool read_entries(FileSharedPtr& rFile)
+        {
+            // read NumExtensionEntries
+            sal_uInt32 nExtEntries(0);
+
+            if (!read_sal_uInt32(rFile, nExtEntries))
+            {
+                return false;
+            }
+
+            for (sal_uInt32 a(0); a < nExtEntries; a++)
+            {
+                ExtensionInfoEntry aNewEntry;
+
+                if (aNewEntry.read_entry(rFile))
+                {
+                    maEntries.push_back(aNewEntry);
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        bool write_entries(oslFileHandle& rHandle) const
+        {
+            const sal_uInt32 nExtEntries(maEntries.size());
+
+            if (!write_sal_uInt32(rHandle, nExtEntries))
+            {
+                return false;
+            }
+
+            for (const auto& a : maEntries)
+            {
+                if (!a.write_entry(rHandle))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        bool createTempFile(OUString& rTempFileName)
+        {
+            oslFileHandle aHandle;
+            bool bRetval(false);
+
+            // create current configuration
+            if (maEntries.empty())
+            {
+                createCurrent();
+            }
+
+            // open target temp file and write current configuration to it - 
it exists until deleted
+            if (osl::File::E_None == osl::FileBase::createTempFile(nullptr, 
&aHandle, &rTempFileName))
+            {
+                bRetval = write_entries(aHandle);
+
+                // close temp file - it exists until deleted
+                osl_closeFile(aHandle);
+            }
+
+            return bRetval;
+        }
+    };
 }
 
 namespace
@@ -91,12 +498,12 @@ namespace
     class PackedFileEntry
     {
     private:
-        sal_uInt32          mnFullFileSize; // size in bytes of unpacked 
original file
-        sal_uInt32          mnPackFileSize; // size in bytes in file backup 
package (smaller if compressed, same if not)
-        sal_uInt32          mnOffset;       // offset in File (zero identifies 
new file)
-        sal_uInt32          mnCrc32;        // checksum
-        FileSharedPtr       maFile;         // file where to find the data (at 
offset)
-        bool                mbDoCompress;   // flag if this file is scheduled 
to be compredded when written
+        sal_uInt32          mnFullFileSize;     // size in bytes of unpacked 
original file
+        sal_uInt32          mnPackFileSize;     // size in bytes in file 
backup package (smaller if compressed, same if not)
+        sal_uInt32          mnOffset;           // offset in File (zero 
identifies new file)
+        sal_uInt32          mnCrc32;            // checksum
+        FileSharedPtr       maFile;             // file where to find the data 
(at offset)
+        bool                mbDoCompress;       // flag if this file is 
scheduled to be compredded when written
 
         bool copy_content_straight(oslFileHandle& rTargetHandle)
         {
@@ -336,93 +743,67 @@ namespace
             return mnOffset;
         }
 
+        void setOffset(sal_uInt32 nOffset)
+        {
+            mnOffset = nOffset;
+        }
+
+        static sal_uInt32 getEntrySize()
+        {
+            return 12;
+        }
+
         sal_uInt32 getCrc32() const
         {
             return mnCrc32;
         }
 
-        bool read_header(
-            FileSharedPtr& rFile,
-            sal_uInt32 nOffset)
+        bool read_header(FileSharedPtr& rFile)
         {
-            mnOffset = nOffset;
-            maFile = rFile;
-
-            if (maFile)
+            if (!rFile)
             {
-                sal_uInt8 aArray[4];
-                sal_uInt64 nBaseRead(0);
+                return false;
+            }
 
-                // read and compute full file size
-                if (osl::File::E_None == 
maFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
-                {
-                    mnFullFileSize = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
-                }
-                else
-                {
-                    return false;
-                }
+            maFile = rFile;
 
-                // read and compute entry crc32
-                if (osl::File::E_None == 
maFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
-                {
-                    mnCrc32 = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
-                }
-                else
-                {
-                    return false;
-                }
+            // read and compute full file size
+            if (!read_sal_uInt32(rFile, mnFullFileSize))
+            {
+                return false;
+            }
 
-                // read and compute packed size
-                if (osl::File::E_None == 
maFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
-                {
-                    mnPackFileSize = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
-                }
-                else
-                {
-                    return false;
-                }
+            // read and compute entry crc32
+            if (!read_sal_uInt32(rFile, mnCrc32))
+            {
+                return false;
+            }
 
-                return true;
+            // read and compute packed size
+            if (!read_sal_uInt32(rFile, mnPackFileSize))
+            {
+                return false;
             }
 
-            return false;
+            return true;
         }
 
-        bool write_header(oslFileHandle& rHandle)
+        bool write_header(oslFileHandle& rHandle) const
         {
-            sal_uInt8 aArray[4];
-            sal_uInt64 nBaseWritten(0);
-
             // write full file size
-            aArray[0] = sal_uInt8((mnFullFileSize & 0xff000000) >> 24);
-            aArray[1] = sal_uInt8((mnFullFileSize & 0x00ff0000) >> 16);
-            aArray[2] = sal_uInt8((mnFullFileSize & 0x0000ff00) >> 8);
-            aArray[3] = sal_uInt8(mnFullFileSize & 0x000000ff);
-
-            if (osl_File_E_None != osl_writeFile(rHandle, static_cast<const 
void*>(aArray), 4, &nBaseWritten) || 4 != nBaseWritten)
+            if (!write_sal_uInt32(rHandle, mnFullFileSize))
             {
                 return false;
             }
 
             // write crc32
-            aArray[0] = sal_uInt8((mnCrc32 & 0xff000000) >> 24);
-            aArray[1] = sal_uInt8((mnCrc32 & 0x00ff0000) >> 16);
-            aArray[2] = sal_uInt8((mnCrc32 & 0x0000ff00) >> 8);
-            aArray[3] = sal_uInt8(mnCrc32 & 0x000000ff);
-
-            if (osl_File_E_None != osl_writeFile(rHandle, static_cast<const 
void*>(aArray), 4, &nBaseWritten) || 4 != nBaseWritten)
+            if (!write_sal_uInt32(rHandle, mnCrc32))
             {
                 return false;
             }
 
             // write packed file size
-            aArray[0] = sal_uInt8((mnPackFileSize & 0xff000000) >> 24);
-            aArray[1] = sal_uInt8((mnPackFileSize & 0x00ff0000) >> 16);
-            aArray[2] = sal_uInt8((mnPackFileSize & 0x0000ff00) >> 8);
-            aArray[3] = sal_uInt8(mnPackFileSize & 0x000000ff);
-
-            if (osl_File_E_None != osl_writeFile(rHandle, static_cast<const 
void*>(aArray), 4, &nBaseWritten) || 4 != nBaseWritten)
+            if (!write_sal_uInt32(rHandle, mnPackFileSize))
             {
                 return false;
             }
@@ -509,23 +890,16 @@ namespace
                                 // if there are entries (and less than max), 
read them
                                 if (nEntries >= 1 && nEntries <= 10)
                                 {
-                                    // offset in souce file starts with 8 Byte 
for header + numEntries and
-                                    // 12 byte for each entry (size, crc32 and 
PackedSize)
-                                    sal_uInt32 nOffset(8 + (12 * nEntries));
-
                                     for (sal_uInt32 a(0); a < nEntries; a++)
                                     {
                                         // create new entry, read header 
(size, crc and PackedSize),
                                         // set offset and source file
                                         PackedFileEntry aEntry;
 
-                                        if (aEntry.read_header(aSourceFile, 
nOffset))
+                                        if (aEntry.read_header(aSourceFile))
                                         {
                                             // add to local data
                                             
maPackedFileEntryVector.push_back(aEntry);
-
-                                            // increase offset for next entry
-                                            nOffset += 
aEntry.getPackFileSize();
                                         }
                                         else
                                         {
@@ -539,6 +913,21 @@ namespace
                                         // on read error clear local data
                                         maPackedFileEntryVector.clear();
                                     }
+                                    else
+                                    {
+                                        // calculate and set offsets to file 
binary content
+                                        sal_uInt32 nHeaderSize(8);
+
+                                        nHeaderSize += 
maPackedFileEntryVector.size() * PackedFileEntry::getEntrySize();
+
+                                        sal_uInt32 nOffset(nHeaderSize);
+
+                                        for (auto& b : maPackedFileEntryVector)
+                                        {
+                                            b.setOffset(nOffset);
+                                            nOffset += b.getPackFileSize();
+                                        }
+                                    }
                                 }
                             }
                         }
@@ -571,7 +960,7 @@ namespace
                 oslFileHandle aHandle;
                 OUString aTempURL;
 
-                // open target temp file
+                // open target temp file - it exists until deleted
                 if (osl::File::E_None == 
osl::FileBase::createTempFile(nullptr, &aHandle, &aTempURL))
                 {
                     sal_uInt8 aArray[4];
@@ -586,27 +975,25 @@ namespace
                     if (osl_File_E_None == osl_writeFile(aHandle, 
static_cast<const void*>(aArray), 4, &nBaseWritten) && 4 == nBaseWritten)
                     {
                         const sal_uInt32 nSize(maPackedFileEntryVector.size());
-                        aArray[0] = sal_uInt8((nSize & 0xff000000) >> 24);
-                        aArray[1] = sal_uInt8((nSize & 0x00ff0000) >> 16);
-                        aArray[2] = sal_uInt8((nSize & 0x0000ff00) >> 8);
-                        aArray[3] = sal_uInt8(nSize & 0x000000ff);
 
                         // write number of entries
-                        if (osl_File_E_None == osl_writeFile(aHandle, 
static_cast<const void*>(aArray), 4, &nBaseWritten) && 4 == nBaseWritten)
+                        if (write_sal_uInt32(aHandle, nSize))
                         {
                             if (bRetval)
                             {
                                 // write placeholder for headers. Due to the 
fact that
                                 // PackFileSize for newly added files gets set 
during
                                 // writing the content entry, write headers 
after content
-                                // is written. To do so, write placeholders 
here. We know
-                                // the number of entries to write
-                                const sal_uInt32 nWriteSize(3 * 
maPackedFileEntryVector.size());
+                                // is written. To do so, write placeholders 
here
+                                sal_uInt32 nWriteSize(0);
+
+                                nWriteSize += maPackedFileEntryVector.size() * 
PackedFileEntry::getEntrySize();
+
                                 aArray[0] = aArray[1] = aArray[2] = aArray[3] 
= 0;
 
                                 for (sal_uInt32 a(0); bRetval && a < 
nWriteSize; a++)
                                 {
-                                    if (osl_File_E_None != 
osl_writeFile(aHandle, static_cast<const void*>(aArray), 4, &nBaseWritten) || 4 
!= nBaseWritten)
+                                    if (osl_File_E_None != 
osl_writeFile(aHandle, static_cast<const void*>(aArray), 1, &nBaseWritten) || 1 
!= nBaseWritten)
                                     {
                                         bRetval = false;
                                     }
@@ -653,7 +1040,7 @@ namespace
                     }
                 }
 
-                // close temp file (in all cases)
+                // close temp file (in all cases) - it exists until deleted
                 osl_closeFile(aHandle);
 
                 if (bRetval)
@@ -690,11 +1077,17 @@ namespace
             bool bNeedToAdd(false);
             sal_uInt32 nCrc32(0);
 
-            if (!maPackedFileEntryVector.empty())
+            if (maPackedFileEntryVector.empty())
+            {
+                // no backup yet, add as 1st backup
+                bNeedToAdd = true;
+            }
+            else
             {
                 // already backups there, check if different from last entry
                 const PackedFileEntry& aLastEntry = 
maPackedFileEntryVector.back();
 
+                // check if file is different
                 if (aLastEntry.getFullFileSize() != 
static_cast<sal_uInt32>(nFileSize))
                 {
                     // different size, different file
@@ -712,11 +1105,6 @@ namespace
                     }
                 }
             }
-            else
-            {
-                // no backup yet, add
-                bNeedToAdd = true;
-            }
 
             if (bNeedToAdd)
             {
@@ -829,16 +1217,89 @@ namespace comphelper
         return bRetval;
     }
 
-    rtl::OUString BackupFileHelper::getName()
+    bool BackupFileHelper::tryPush(bool bCompress)
     {
-        return OUString(maBase + "/." + maName + ".pack");
+        bool bDidPush(false);
+
+        if (splitBaseURL())
+        {
+            // ensure directory existence
+            osl::Directory::createPath(getPackDirName());
+
+            // try push for base file (usually registrymodifications)
+            bDidPush = tryPush_basefile(bCompress);
+
+            // Try Push of ExtensionInfo
+            bDidPush |= tryPush_extensionInfo(bCompress);
+        }
+
+        return bDidPush;
     }
 
-    bool BackupFileHelper::tryPush(bool bCompress)
+    bool BackupFileHelper::isPopPossible()
+    {
+        bool bPopPossible(false);
+
+        if (splitBaseURL())
+        {
+            // try for base file (usually registrymodifications)
+            bPopPossible = isPopPossible_basefile();
+
+            // try for ExtensionInfo
+            bPopPossible |= isPopPossible_extensionInfo();
+        }
+
+        return bPopPossible;
+    }
+
+    bool BackupFileHelper::tryPop()
+    {
+        bool bDidPop(false);
+
+        if (splitBaseURL())
+        {
+            // try for base file (usually registrymodifications)
+            bDidPop = tryPop_basefile();
+
+            // try for ExtensionInfo
+            bDidPop |= tryPop_extensionInfo();
+
+            if (bDidPop)
+            {
+                // try removal of evtl. empty directory
+                osl::Directory::remove(getPackDirName());
+            }
+        }
+
+        return bDidPop;
+    }
+
+    bool BackupFileHelper::splitBaseURL()
+    {
+        if (maBase.isEmpty() && !mrBaseURL.isEmpty())
+        {
+            // split URL at extension and at last path separator
+            maBase = splitAtLastToken(splitAtLastToken(mrBaseURL, '.', maExt), 
'/', maName);
+        }
+
+        return !maBase.isEmpty() && !maName.isEmpty();
+    }
+
+    const rtl::OUString BackupFileHelper::getPackDirName() const
+    {
+        return rtl::OUString(maBase + "/pack");
+    }
+
+    const rtl::OUString BackupFileHelper::getPackFileName(const rtl::OUString& 
rFileName) const
+    {
+        return rtl::OUString(getPackDirName() + "/" + rFileName + ".pack");
+    }
+
+    bool BackupFileHelper::tryPush_basefile(bool bCompress)
     {
-        if (splitBaseURL() && baseFileExists())
+        if (fileExists(mrBaseURL))
         {
-            PackedFile aPackedFile(getName());
+            PackedFile aPackedFile(getPackFileName(maName));
             FileSharedPtr aBaseFile(new osl::File(mrBaseURL));
 
             if (aPackedFile.tryPush(aBaseFile, bCompress))
@@ -854,11 +1315,37 @@ namespace comphelper
         return false;
     }
 
-    bool BackupFileHelper::isPopPossible()
+    bool BackupFileHelper::tryPush_extensionInfo(bool bCompress)
+    {
+        ExtensionInfo aExtensionInfo;
+        OUString aTempURL;
+        bool bRetval(false);
+
+        // create current configuration and write to temp file - it exists 
until deleted
+        if (aExtensionInfo.createTempFile(aTempURL))
+        {
+            PackedFile aPackedFile(getPackFileName("ExtensionInfo"));
+            FileSharedPtr aBaseFile(new osl::File(aTempURL));
+
+            if (aPackedFile.tryPush(aBaseFile, bCompress))
+            {
+                // reduce to allowed number and flush
+                aPackedFile.tryReduceToNumBackups(mnNumBackups);
+                aPackedFile.flush();
+                bRetval = true;
+            }
+        }
+
+        // delete temp file (in all cases)
+        osl::File::remove(aTempURL);
+        return bRetval;
+    }
+
+    bool BackupFileHelper::isPopPossible_basefile()
     {
-        if (splitBaseURL() && baseFileExists())
+        if (fileExists(mrBaseURL))
         {
-            PackedFile aPackedFile(getName());
+            PackedFile aPackedFile(getPackFileName(maName));
 
             return !aPackedFile.empty();
         }
@@ -866,23 +1353,32 @@ namespace comphelper
         return false;
     }
 
-    bool BackupFileHelper::tryPop()
+    bool BackupFileHelper::isPopPossible_extensionInfo()
+    {
+        // extensionInfo always exists internally, no test needed
+        PackedFile aPackedFile(getPackFileName("ExtensionInfo"));
+
+        return !aPackedFile.empty();
+    }
+
+    bool BackupFileHelper::tryPop_basefile()
     {
-        if (splitBaseURL() && baseFileExists())
+        if (fileExists(mrBaseURL))
         {
-            PackedFile aPackedFile(getName());
+            // try Pop for base file (usually registrymodifications)
+            PackedFile aPackedFile(getPackFileName(maName));
 
             if (!aPackedFile.empty())
             {
                 oslFileHandle aHandle;
                 OUString aTempURL;
 
-                // open target temp file
+                // open target temp file - it exists until deleted
                 if (osl::File::E_None == 
osl::FileBase::createTempFile(nullptr, &aHandle, &aTempURL))
                 {
                     bool bRetval(aPackedFile.tryPop(aHandle));
 
-                    // close temp file (in all cases)
+                    // close temp file (in all cases) - it exists until deleted
                     osl_closeFile(aHandle);
 
                     if (bRetval)
@@ -908,24 +1404,58 @@ namespace comphelper
         return false;
     }
 
-    bool BackupFileHelper::splitBaseURL()
+    bool BackupFileHelper::tryPop_extensionInfo()
     {
-        if (maBase.isEmpty() && !mrBaseURL.isEmpty())
+        // extensionInfo always exists internally, no test needed
+        PackedFile aPackedFile(getPackFileName("ExtensionInfo"));
+
+        if (!aPackedFile.empty())
         {
-            // split URL at extension and at last path separator
-            maBase = splitAtLastToken(splitAtLastToken(mrBaseURL, '.', maExt), 
'/', maName);
-        }
+            oslFileHandle aHandle;
+            OUString aTempURL;
 
-        return !maBase.isEmpty() && !maName.isEmpty();
-    }
+            // open target temp file - it exists until deleted
+            if (osl::File::E_None == osl::FileBase::createTempFile(nullptr, 
&aHandle, &aTempURL))
+            {
+                bool bRetval(aPackedFile.tryPop(aHandle));
 
-    bool BackupFileHelper::baseFileExists()
-    {
-        if (!mrBaseURL.isEmpty())
-        {
-            FileSharedPtr aBaseFile(new osl::File(mrBaseURL));
+                // close temp file (in all cases) - it exists until deleted
+                osl_closeFile(aHandle);
 
-            return (osl::File::E_None == 
aBaseFile->open(osl_File_OpenFlag_Read));
+                if (bRetval)
+                {
+                    // last config is in temp file, load it to ExtensionInfo
+                    ExtensionInfo aLoadedExtensionInfo;
+                    FileSharedPtr aBaseFile(new osl::File(aTempURL));
+
+                    if (osl::File::E_None == 
aBaseFile->open(osl_File_OpenFlag_Read))
+                    {
+                        if (aLoadedExtensionInfo.read_entries(aBaseFile))
+                        {
+                            ExtensionInfo aCurrentExtensionInfo;
+
+                            aCurrentExtensionInfo.createCurrent();
+
+                            // now we have loaded and current ExtensionInfo 
and may react on differences
+
+
+
+
+
+                            bRetval = true;
+                        }
+                    }
+
+                    // reduce to allowed number and flush
+                    aPackedFile.tryReduceToNumBackups(mnNumBackups);
+                    aPackedFile.flush();
+                }
+
+                // delete temp file (in all cases - it may be moved already)
+                osl::File::remove(aTempURL);
+
+                return bRetval;
+            }
         }
 
         return false;
diff --git a/configmgr/source/components.cxx b/configmgr/source/components.cxx
index 17f09a3..9072da4 100644
--- a/configmgr/source/components.cxx
+++ b/configmgr/source/components.cxx
@@ -613,18 +613,22 @@ Components::Components(
 
 Components::~Components()
 {
-    // get flag if _exit was already called which is a sign to not to secure 
user config
+    // get flag if _exit was already called which is a sign to not secure user 
config.
+    // this is used for win only currently where calling _exit() unfortunately 
still
+    // calls destructors (what is not wanted). May be needed for other 
systems, too
+    // (unknown yet) but can do no harm
     const bool 
bExitWasCalled(comphelper::BackupFileHelper::getExitWasCalled());
 
 #ifndef WNT
     // we can add a SAL_WARN here for other systems where the destructor gets 
called after
-    // an _exit() call - which should not happen. Still safe - the 
getExitWasCalled() is
-    // used, but a hint that _exit behaves different on a system
+    // an _exit() call. Still safe - the getExitWasCalled() is used, but a 
hint that _exit
+    // behaves different on a system
     SAL_WARN_IF(bExitWasCalled, "configmgr", "Components::~Components() called 
after _exit() call");
 #endif
 
     if (bExitWasCalled)
     {
+        // do not write, re-join thereads
         osl::MutexGuard g(*lock_);
 
         if (writeThread_.is())
@@ -634,30 +638,13 @@ Components::~Components()
     }
     else
     {
+        // write changes
         flushModifications();
     }
 
     for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
         (*i)->setAlive(false);
     }
-
-    if (!bExitWasCalled &&
-        ModificationTarget::File == modificationTarget_ &&
-        !modificationFileUrl_.isEmpty())
-    {
-        // test backup of registrymodifications
-        sal_uInt16 nSecureUserConfigNumCopies(0);
-
-        // read configuration from soffice.ini
-        const bool 
bSecureUserConfig(comphelper::BackupFileHelper::getSecureUserConfig(nSecureUserConfigNumCopies));
-
-        if (bSecureUserConfig)
-        {
-            comphelper::BackupFileHelper 
aBackupFileHelper(modificationFileUrl_, nSecureUserConfigNumCopies);
-
-            aBackupFileHelper.tryPush();
-        }
-    }
 }
 
 void Components::parseFileLeniently(
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index 69da758..b9e5401 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -818,6 +818,42 @@ OUString    Desktop::CreateErrorMsgString(
     return MakeStartupErrorMessage( aMsg );
 }
 
+// helper method to test if SecureUserConfig is active, detect the num copies
+// and extract the User's config directory URL
+bool testSecureUserConfigActive(sal_uInt16& rnSecureUserConfigNumCopies, 
OUString& raUserConfigDir)
+{
+    // read configuration from soffice.ini
+    
if(comphelper::BackupFileHelper::getSecureUserConfig(rnSecureUserConfigNumCopies))
+    {
+        // try to asccess user layer configuration file
+        OUString conf("${CONFIGURATION_LAYERS}");
+        rtl::Bootstrap::expandMacros(conf);
+        const OUString aTokenUser("user:");
+        sal_Int32 nStart(conf.indexOf(aTokenUser));
+
+        if (-1 != nStart)
+        {
+            nStart += aTokenUser.getLength();
+            sal_Int32 nEnd(conf.indexOf(' ', nStart));
+
+            if (-1 == nEnd)
+            {
+                nEnd = conf.getLength();
+            }
+
+            raUserConfigDir = conf.copy(nStart, nEnd - nStart);
+            raUserConfigDir.startsWith("!", &raUserConfigDir);
+        }
+
+        if (!raUserConfigDir.isEmpty())
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void Desktop::HandleBootstrapErrors(
     BootstrapError aBootstrapError, OUString const & aErrorMessage )
 {
@@ -951,75 +987,50 @@ void Desktop::HandleBootstrapErrors(
     }
     else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
     {
-        // test restore of registrymodifications
+        // test if SecureUserConfig is active
         sal_uInt16 nSecureUserConfigNumCopies(0);
+        OUString aUserConfigDir;
         bool bFireOriginalError(true);
 
-        // read configuration from soffice.ini
-        const bool 
bSecureUserConfig(comphelper::BackupFileHelper::getSecureUserConfig(nSecureUserConfigNumCopies));
-
-        if (bSecureUserConfig)
+        if (testSecureUserConfigActive(nSecureUserConfigNumCopies, 
aUserConfigDir))
         {
-            // try to asccess user layer configuration file
-            OUString conf("${CONFIGURATION_LAYERS}");
-            rtl::Bootstrap::expandMacros(conf);
-            const OUString aTokenUser("user:");
-            sal_Int32 nStart(conf.indexOf(aTokenUser));
-            OUString aUser;
+            comphelper::BackupFileHelper aBackupFileHelper(aUserConfigDir, 
nSecureUserConfigNumCopies);
 
-            if (-1 != nStart)
+            if (aBackupFileHelper.isPopPossible())
             {
-                nStart += aTokenUser.getLength();
-                sal_Int32 nEnd(conf.indexOf(' ', nStart));
-
-                if (-1 == nEnd)
+                // for linux (and probably others?) we need to instantiate 
XDesktop2
+                // to be able to open a *.ui-file based dialog, so do this 
here locally.
+                // does no harm on win, so better always do this (in error 
case only anyways)
+                Reference< XComponentContext > xLocalContext = 
::comphelper::getProcessComponentContext();
+                Reference< XDesktop2 > xDesktop = 
css::frame::Desktop::create(xLocalContext);
+
+                ScopedVclPtrInstance< MessageDialog > aQueryShouldRestore(
+                    Application::GetDefDialogParent(),
+                    "QueryTryToRestoreConfigurationDialog",
+                    "desktop/ui/querytrytorestoreconfigurationdialog.ui");
+
+                if (aQueryShouldRestore.get())
                 {
-                    nEnd = conf.getLength();
-                }
-
-                aUser = conf.copy(nStart, nEnd - nStart);
-                aUser.startsWith("!", &aUser);
-            }
+                    if (!aErrorMessage.isEmpty())
+                    {
+                        OUString 
aPrimaryText(aQueryShouldRestore->get_primary_text());
 
-            if (!aUser.isEmpty())
-            {
-                comphelper::BackupFileHelper aBackupFileHelper(aUser, 
nSecureUserConfigNumCopies);
+                        aPrimaryText += "\n(\"" + aErrorMessage + "\")";
+                        aQueryShouldRestore->set_primary_text(aPrimaryText);
+                    }
 
-                if (aBackupFileHelper.isPopPossible())
-                {
-                    // for linux (and probably others?) we need to instantiate 
XDesktop2
-                    // to be able to open a *.ui-file based dialog, so do this 
here locally.
-                    // does no harm on win, so better always do this (in error 
case only anyways)
-                    Reference< XComponentContext > xLocalContext = 
::comphelper::getProcessComponentContext();
-                    Reference< XDesktop2 > xDesktop = 
css::frame::Desktop::create(xLocalContext);
-
-                    ScopedVclPtrInstance< MessageDialog > aQueryShouldRestore(
-                        Application::GetDefDialogParent(),
-                        "QueryTryToRestoreConfigurationDialog",
-                        "desktop/ui/querytrytorestoreconfigurationdialog.ui");
-
-                    if (aQueryShouldRestore.get())
+                    if (RET_YES == aQueryShouldRestore->Execute())
                     {
-                        if (!aErrorMessage.isEmpty())
-                        {
-                            OUString 
aPrimaryText(aQueryShouldRestore->get_primary_text());
-
-                            aPrimaryText += "\n(\"" + aErrorMessage + "\")";
-                            
aQueryShouldRestore->set_primary_text(aPrimaryText);
-                        }
-
-                        if (RET_YES == aQueryShouldRestore->Execute())
-                        {
-                            aBackupFileHelper.tryPop();
-                            bFireOriginalError = false;
-                        }
+                        aBackupFileHelper.tryPop();
+                        bFireOriginalError = false;
                     }
                 }
             }
         }
 
         // set flag at BackupFileHelper to be able to know if _exit was called 
and
-        // actions are executed after this
+        // actions are executed after this. This method we are in will not 
return,
+        // but end up in a _exit() call
         comphelper::BackupFileHelper::setExitWasCalled();
 
         if (bFireOriginalError)
@@ -1836,7 +1847,34 @@ int Desktop::doShutdown()
 
     // remove temp directory
     RemoveTemporaryDirectory();
+
+    // flush evtl. configuration changes so that all config files in user
+    // dir are written
     FlushConfiguration();
+
+    if (pExecGlobals->bRestartRequested)
+    {
+        // a restart is already requested, usually due to a configuration 
change
+        // that needs a restart to get active. If this is the case, do not try
+        // to use SecureUserConfig to safe this still untested new 
configuration
+    }
+    else
+    {
+        // Test if SecureUserConfig is active. If yes and we are at this 
point, regular shutdown
+        // is in progress and the currently used configuration was working. 
Try to secure this
+        // working configuration for later eventually necessary restores
+        sal_uInt16 nSecureUserConfigNumCopies(0);
+        OUString aUserConfigDir;
+
+        if (testSecureUserConfigActive(nSecureUserConfigNumCopies, 
aUserConfigDir))
+        {
+            // try to push registrymodifications.xcu
+            comphelper::BackupFileHelper aBackupFileHelper(aUserConfigDir, 
nSecureUserConfigNumCopies);
+
+            aBackupFileHelper.tryPush();
+        }
+    }
+
     // The acceptors in the AcceptorMap must be released (in 
DeregisterServices)
     // with the solar mutex unlocked, to avoid deadlock:
     {
diff --git a/desktop/source/app/app.cxx.orig b/desktop/source/app/app.cxx.orig
new file mode 100644
index 0000000..a9d10c3
--- /dev/null
+++ b/desktop/source/app/app.cxx.orig
@@ -0,0 +1,2735 @@
+/* -*- 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 <config_features.h>
+#include <config_folders.h>
+
+#include <sal/config.h>
+
+#include <iostream>
+#if defined UNX
+#include <signal.h>
+#endif
+
+#include "app.hxx"
+#include "desktop.hrc"
+#include "cmdlineargs.hxx"
+#include "cmdlinehelp.hxx"
+#include "dispatchwatcher.hxx"
+#include "lockfile.hxx"
+#include "userinstall.hxx"
+#include "desktopcontext.hxx"
+#include "migration.hxx"
+
+#include <svl/languageoptions.hxx>
+#include <svtools/javacontext.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/theAutoRecovery.hpp>
+#include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
+#include <com/sun/star/frame/SessionListener.hpp>
+#include <com/sun/star/frame/XSessionManagerListener.hpp>
+#include <com/sun/star/frame/XSynchronousDispatch.hpp>
+#include <com/sun/star/document/CorruptedFilterConfigurationException.hpp>
+#include <com/sun/star/configuration/CorruptedConfigurationException.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/StartModule.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/view/XPrintable.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
+#include <com/sun/star/configuration/MissingBootstrapFileException.hpp>
+#include <com/sun/star/configuration/InvalidBootstrapFileException.hpp>
+#include <com/sun/star/configuration/InstallationIncompleteException.hpp>
+#include <com/sun/star/configuration/backend/BackendSetupException.hpp>
+#include <com/sun/star/configuration/backend/BackendAccessException.hpp>
+#include <com/sun/star/task/theJobExecutor.hpp>
+#include <com/sun/star/task/OfficeRestartManager.hpp>
+#include <com/sun/star/task/XRestartManager.hpp>
+#include <com/sun/star/document/XDocumentEventListener.hpp>
+#include <com/sun/star/frame/theUICommandDescription.hpp>
+#include <com/sun/star/ui/theUIElementFactoryManager.hpp>
+#include <com/sun/star/ui/theWindowStateConfiguration.hpp>
+#include <com/sun/star/frame/thePopupMenuControllerFactory.hpp>
+#include <com/sun/star/office/Quickstart.hpp>
+
+#include <desktop/exithelper.h>
+#include <sal/log.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/configuration.hxx>
+#include <comphelper/fileurl.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/backupfilehelper.hxx>
+#include <unotools/bootstrap.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <unotools/localfilehelper.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <officecfg/Office/Recovery.hxx>
+#include <officecfg/Setup.hxx>
+#include <osl/file.hxx>
+#include <osl/process.h>
+#include <rtl/uri.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svtools/miscopt.hxx>
+#include <svtools/menuoptions.hxx>
+#include <rtl/bootstrap.hxx>
+#include <vcl/help.hxx>
+#include <vcl/layout.hxx>
+#include <vcl/settings.hxx>
+#include <sfx2/sfx.hrc>
+#include <sfx2/app.hxx>
+#include <svl/itemset.hxx>
+#include <svl/eitem.hxx>
+#include <basic/sbstar.hxx>
+#include <desktop/crashreport.hxx>
+
+#include <svtools/fontsubstconfig.hxx>
+#include <svtools/accessibilityoptions.hxx>
+#include <svtools/apearcfg.hxx>
+#include <vcl/graphicfilter.hxx>
+
+#include "langselect.hxx"
+
+#include <config_telepathy.h>
+
+#if ENABLE_TELEPATHY
+#include <tubes/manager.hxx>
+#endif
+
+#if HAVE_FEATURE_BREAKPAD
+#include <fstream>
+#endif
+
+#if defined MACOSX
+#include <errno.h>
+#include <sys/wait.h>
+#endif
+
+#ifdef _WIN32
+#ifdef _MSC_VER
+#pragma warning(push, 1) /* disable warnings within system headers */
+#pragma warning (disable: 4005)
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+#endif //WNT
+
+#if defined(_WIN32)
+#include <process.h>
+#define GETPID _getpid
+#else
+#include <unistd.h>
+#define GETPID getpid
+#endif
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::system;
+using namespace ::com::sun::star::ui;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::container;
+
+ResMgr* desktop::Desktop::pResMgr = nullptr;
+
+namespace desktop
+{
+
+static oslSignalHandler pSignalHandler = nullptr;
+
+namespace {
+
+#if HAVE_FEATURE_EXTENSIONS
+
+// Remove any existing UserInstallation's extensions cache data remaining from
+// old installations.  This addresses at least two problems:
+//
+// For one, apparently due to the old share/prereg/bundled mechanism (disabled
+// since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying
+// share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled
+// cache could contain corrupted information (like a UNO component registered
+// twice, which got changed from active to passive registration in one LO
+// version, but the version of the corresponding bundled extension only
+// incremented in a later LO version).
+//
+// For another, UserInstallations have been seen in the wild where no 
extensions
+// were installed per-user (any longer), but user/uno_packages/cache/registry/
+// com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files
+// contained data nevertheless.
+//
+// When a LO upgrade is detected (i.e., no user/extensions/buildid or one
+// containing an old build ID), then user/extensions and
+// user/uno_packages/cache/registry/
+// com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are
+// removed.  That should prevent any problems starting the service manager due
+// to old junk.  Later on in Desktop::SynchronizeExtensionRepositories, the
+// removed cache data is recreated.
+//
+// Multiple instances of soffice.bin can execute this code in parallel for a
+// single UserInstallation, as it is called before RequestHandler is set up.
+// Therefore, any errors here only lead to SAL_WARNs.
+//
+// At least in theory, this function could be removed again once no
+// UserInstallation can be poisoned by old junk any more.
+bool cleanExtensionCache() {
+    OUString buildId(
+        "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") 
":buildid}");
+    rtl::Bootstrap::expandMacros(buildId); //TODO: detect failure
+    OUString extDir(
+        "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap")
+        ":UserInstallation}/user/extensions");
+    rtl::Bootstrap::expandMacros(extDir); //TODO: detect failure
+    OUString buildIdFile(extDir + "/buildid");
+    osl::File fr(buildIdFile);
+    osl::FileBase::RC rc = fr.open(osl_File_OpenFlag_Read);
+    switch (rc) {
+    case osl::FileBase::E_None:
+        {
+            rtl::ByteSequence s1;
+            rc = fr.readLine(s1);
+            osl::FileBase::RC rc2 = fr.close();
+            SAL_WARN_IF(
+                rc2 != osl::FileBase::E_None, "desktop.app",
+                "cannot close " << fr.getURL() << " after reading: " << +rc2);
+            // readLine returns E_AGAIN for a zero-size file:
+            if (rc != osl::FileBase::E_None && rc != osl::FileBase::E_AGAIN) {
+                SAL_WARN( "desktop.app", "cannot read from " << fr.getURL() << 
": " << +rc);
+                break;
+            }
+            OUString s2(
+                reinterpret_cast< char const * >(s1.getConstArray()),
+                s1.getLength(), RTL_TEXTENCODING_ISO_8859_1);
+                // using ISO 8859-1 avoids any and all conversion errors; the
+                // content should only be a subset of ASCII, anyway
+            if (s2 == buildId) {
+                return false;
+            }
+            break;
+        }
+    case osl::FileBase::E_NOENT:
+        break;
+    default:
+        SAL_WARN( "desktop.app", "cannot open " << fr.getURL() << " for 
reading: " << +rc);
+        break;
+    }
+    utl::removeTree(extDir);
+    OUString userRcFile(
+        "$UNO_USER_PACKAGES_CACHE/registry/"
+        "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc");
+    rtl::Bootstrap::expandMacros(userRcFile); //TODO: detect failure
+    rc = osl::File::remove(userRcFile);
+    SAL_WARN_IF(
+        rc != osl::FileBase::E_None && rc != osl::FileBase::E_NOENT, 
"desktop.app",
+        "cannot remove file " << userRcFile << ": " << +rc);
+    rc = osl::Directory::createPath(extDir);
+    SAL_WARN_IF(
+        rc != osl::FileBase::E_None && rc != osl::FileBase::E_EXIST, 
"desktop.app",
+        "cannot create path " << extDir << ": " << +rc);
+    osl::File fw(buildIdFile);
+    rc = fw.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
+    if (rc != osl::FileBase::E_None) {
+        SAL_WARN( "desktop.app", "cannot open " << fw.getURL() << " for 
writing: " << +rc);
+        return true;
+    }
+    OString buf(OUStringToOString(buildId, RTL_TEXTENCODING_UTF8));
+        // using UTF-8 avoids almost all conversion errors (and buildid
+        // containing single surrogate halves should never happen, anyway); the
+        // content should only be a subset of ASCII, anyway
+    sal_uInt64 n = 0;
+    rc = fw.write(buf.getStr(), buf.getLength(), n);
+    SAL_WARN_IF(
+        (rc != osl::FileBase::E_None
+         || n != static_cast< sal_uInt32 >(buf.getLength())),
+        "desktop.app",
+        "cannot write to " << fw.getURL() << ": " << +rc << ", " << n);
+    rc = fw.close();
+    SAL_WARN_IF(
+        rc != osl::FileBase::E_None, "desktop.app",
+        "cannot close " << fw.getURL() << " after writing: " << +rc);
+    return true;
+}
+
+#endif
+
+bool shouldLaunchQuickstart()
+{
+    bool bQuickstart = Desktop::GetCommandLineArgs().IsQuickstart();
+    if (!bQuickstart)
+    {
+        const SfxPoolItem* pItem=nullptr;
+        SfxItemSet aQLSet(SfxGetpApp()->GetPool(), SID_ATTR_QUICKLAUNCHER, 
SID_ATTR_QUICKLAUNCHER);
+        SfxGetpApp()->GetOptions(aQLSet);
+        SfxItemState eState = aQLSet.GetItemState(SID_ATTR_QUICKLAUNCHER, 
false, &pItem);
+        if (SfxItemState::SET == eState)
+            bQuickstart = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+    }
+    return bQuickstart;
+}
+
+void SetRestartState() {
+    try {
+        std::shared_ptr< comphelper::ConfigurationChanges > batch(
+            comphelper::ConfigurationChanges::create());
+        officecfg::Setup::Office::OfficeRestartInProgress::set(true, batch);
+        batch->commit();
+    } catch (css::uno::Exception & e) {
+        SAL_WARN("desktop.app", "ignoring Exception \"" << e.Message << "\"");
+    }
+}
+
+void DoRestartActionsIfNecessary(bool quickstart) {
+    if (quickstart) {
+        try {
+            if (officecfg::Setup::Office::OfficeRestartInProgress::get()) {
+                std::shared_ptr< comphelper::ConfigurationChanges > batch(
+                    comphelper::ConfigurationChanges::create());
+                officecfg::Setup::Office::OfficeRestartInProgress::set(
+                    false, batch);
+                batch->commit();
+                css::office::Quickstart::createStart(
+                    comphelper::getProcessComponentContext(),
+                    shouldLaunchQuickstart());
+            }
+        } catch (css::uno::Exception & e) {
+            SAL_WARN(
+                "desktop.app", "ignoring Exception \"" << e.Message << "\"");
+        }
+    }
+}
+
+}
+
+
+ResMgr* Desktop::GetDesktopResManager()
+{
+    if ( !Desktop::pResMgr )
+    {
+        // Create desktop resource manager and bootstrap process
+        // was successful. Use default way to get language specific message.
+        if ( Application::IsInExecute() )
+            Desktop::pResMgr = ResMgr::CreateResMgr("dkt");
+
+        if ( !Desktop::pResMgr )
+        {
+            // Use VCL to get the correct language specific message as we
+            // are in the bootstrap process and not able to get the installed
+            // language!!
+            OUString aUILocaleString = langselect::getEmergencyLocale();
+            LanguageTag aLanguageTag( aUILocaleString);
+            //! ResMgr may modify the Locale for fallback!
+            Desktop::pResMgr = ResMgr::SearchCreateResMgr( "dkt", 
aLanguageTag);
+        }
+    }
+
+    return Desktop::pResMgr;
+}
+
+namespace {
+
+
+// Get a message string securely. There is a fallback string if the resource
+// is not available.
+
+OUString GetMsgString(
+    sal_uInt16 nId, const OUString& aFallbackMsg,
+    bool bAlwaysUseFallbackMsg = false )
+{
+    if ( !bAlwaysUseFallbackMsg )
+    {
+        ResMgr* resMgr = Desktop::GetDesktopResManager();
+        if ( resMgr )
+            return ResId(nId, *resMgr).toString();
+    }
+    return aFallbackMsg;
+}
+
+OUString MakeStartupErrorMessage(
+    OUString const & aErrorMessage, bool bAlwaysUseFallbackMsg = false )
+{
+    OUStringBuffer    aDiagnosticMessage( 100 );
+
+    aDiagnosticMessage.append(
+        GetMsgString(
+            STR_BOOTSTRAP_ERR_CANNOT_START, "The program cannot be started.",
+            bAlwaysUseFallbackMsg ) );
+
+    aDiagnosticMessage.append( "\n" );
+
+    aDiagnosticMessage.append( aErrorMessage );
+
+    return aDiagnosticMessage.makeStringAndClear();
+}
+
+OUString MakeStartupConfigAccessErrorMessage( OUString const & aInternalErrMsg 
)
+{
+    OUStringBuffer aDiagnosticMessage( 200 );
+
+    ResMgr* pResMgr = Desktop::GetDesktopResManager();
+    if ( pResMgr )
+        aDiagnosticMessage.append( ResId(STR_BOOTSTRAP_ERR_CFG_DATAACCESS, 
*pResMgr).toString() );
+    else
+        aDiagnosticMessage.append( "The program cannot be started." );
+
+    if ( !aInternalErrMsg.isEmpty() )
+    {
+        aDiagnosticMessage.append( "\n\n" );
+        if ( pResMgr )
+            aDiagnosticMessage.append( ResId(STR_INTERNAL_ERRMSG, 
*pResMgr).toString() );
+        else
+            aDiagnosticMessage.append( "The following internal error has 
occurred:\n\n" );
+        aDiagnosticMessage.append( aInternalErrMsg );
+    }
+
+    return aDiagnosticMessage.makeStringAndClear();
+}
+
+
+// shows a simple error box with the given message ... but exits from these 
process !
+// Fatal errors can't be solved by the process ... nor any recovery can help.
+// Mostly the installation was damaged and must be repaired manually .. or by 
calling
+// setup again.
+// On the other side we must make sure that no further actions will be 
possible within
+// the current office process ! No pipe requests, no menu/toolbar/shortcut 
actions
+// are allowed. Otherwise we will force a "crash inside a crash".
+// Thats why we have to use a special native message box here which does not 
use yield :-)
+
+void FatalError(const OUString& sMessage)
+{
+    OUString sProductKey = ::utl::Bootstrap::getProductKey();
+    if ( sProductKey.isEmpty())
+    {
+        osl_getExecutableFile( &sProductKey.pData );
+
+        ::sal_uInt32 nLastIndex = sProductKey.lastIndexOf('/');
+        if ( nLastIndex > 0 )
+            sProductKey = sProductKey.copy( nLastIndex+1 );
+    }
+
+    OUStringBuffer sTitle (128);
+    sTitle.append      (sProductKey     );
+    sTitle.append (" - Fatal Error");
+
+    Application::ShowNativeErrorBox (sTitle.makeStringAndClear (), sMessage);
+    _exit(EXITHELPER_FATAL_ERROR);
+}
+
+struct theCommandLineArgs : public rtl::Static< CommandLineArgs, 
theCommandLineArgs > {};
+
+}
+
+CommandLineArgs& Desktop::GetCommandLineArgs()
+{
+    return theCommandLineArgs::get();
+}
+
+namespace
+{
+    struct BrandName
+        : public rtl::Static< OUString, BrandName > {};
+    struct Version
+        : public rtl::Static< OUString, Version > {};
+    struct AboutBoxVersion
+        : public rtl::Static< OUString, AboutBoxVersion > {};
+    struct AboutBoxVersionSuffix
+        : public rtl::Static< OUString, AboutBoxVersionSuffix > {};
+    struct OOOVendor
+        : public rtl::Static< OUString, OOOVendor > {};
+    struct Extension
+        : public rtl::Static< OUString, Extension > {};
+}
+
+OUString ReplaceStringHookProc( const OUString& rStr )
+{
+    OUString sRet(rStr);
+
+    if (sRet.indexOf("%PRODUCT") != -1 || sRet.indexOf("%ABOUTBOX") != -1)
+    {
+        OUString sBrandName = BrandName::get();
+        OUString sVersion = Version::get();
+        OUString sBuildId = utl::Bootstrap::getBuildIdData("development");
+        OUString sAboutBoxVersion = AboutBoxVersion::get();
+        OUString sAboutBoxVersionSuffix = AboutBoxVersionSuffix::get();
+        OUString sExtension = Extension::get();
+
+        if ( sBrandName.isEmpty() )
+        {
+            sBrandName = utl::ConfigManager::getProductName();
+            sVersion = utl::ConfigManager::getProductVersion();
+            sAboutBoxVersion = utl::ConfigManager::getAboutBoxProductVersion();
+            sAboutBoxVersionSuffix = 
utl::ConfigManager::getAboutBoxProductVersionSuffix();
+            if ( sExtension.isEmpty() )
+            {
+                sExtension = utl::ConfigManager::getProductExtension();
+            }
+        }
+
+        sRet = sRet.replaceAll( "%PRODUCTNAME", sBrandName );
+        sRet = sRet.replaceAll( "%PRODUCTVERSION", sVersion );
+        sRet = sRet.replaceAll( "%BUILDID", sBuildId );
+        sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSIONSUFFIX", 
sAboutBoxVersionSuffix );
+        sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSION", sAboutBoxVersion );
+        sRet = sRet.replaceAll( "%PRODUCTEXTENSION", sExtension );
+    }
+
+    if ( sRet.indexOf( "%OOOVENDOR" ) != -1 )
+    {
+        OUString sOOOVendor = OOOVendor::get();
+
+        if ( sOOOVendor.isEmpty() )
+        {
+            sOOOVendor = utl::ConfigManager::getVendor();
+        }
+
+        sRet = sRet.replaceAll( "%OOOVENDOR", sOOOVendor );
+    }
+
+    return sRet;
+}
+
+Desktop::Desktop()
+    : m_bCleanedExtensionCache(false)
+    , m_bServicesRegistered(false)
+    , m_aBootstrapError(BE_OK)
+    , m_aBootstrapStatus(BS_OK)
+{
+}
+
+Desktop::~Desktop()
+{
+#if ENABLE_TELEPATHY
+    TeleManager::finalize();
+#endif
+}
+
+void Desktop::Init()
+{
+    SetBootstrapStatus(BS_OK);
+
+#if HAVE_FEATURE_EXTENSIONS
+    m_bCleanedExtensionCache = cleanExtensionCache();
+#endif
+
+    // We need to have service factory before going further, but see fdo#37195.
+    // Doing this will mmap common.rdb, making it not overwritable on windows,
+    // so this can't happen before the synchronization above. Lets rework this
+    // so that the above is called *from* CreateApplicationServiceManager or
+    // something to enforce this gotcha
+    try
+    {
+        InitApplicationServiceManager();
+    }
+    catch (css::uno::Exception & e)
+    {
+        SetBootstrapError( BE_UNO_SERVICEMANAGER, e.Message );
+    }
+
+    if ( m_aBootstrapError == BE_OK )
+    {
+        try
+        {
+            if (!langselect::prepareLocale())
+            {
+                SetBootstrapError( BE_LANGUAGE_MISSING, OUString() );
+            }
+        }
+        catch (css::uno::Exception & e)
+        {
+            SetBootstrapError( BE_OFFICECONFIG_BROKEN, e.Message );
+        }
+
+        // test code for ProfileSafeMode to allow testing the fail
+        // of loading the office configuration initially. To use,
+        // either set to true and compile, or set a breakpoint
+        // in debugger and change the local bool
+        static bool bTryHardOfficeconfigBroken(false);
+
+        if (bTryHardOfficeconfigBroken)
+        {
+            SetBootstrapError(BE_OFFICECONFIG_BROKEN, OUString());
+        }
+    }
+
+    if ( true )
+    {
+        const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
+
+        // start ipc thread only for non-remote offices
+        RequestHandler::Status aStatus = RequestHandler::Enable(true);
+        if ( aStatus == RequestHandler::IPC_STATUS_PIPE_ERROR )
+        {
+#if defined ANDROID
+            // Ignore crack pipe errors on Android
+#else
+            // Keep using this oddly named BE_PATHINFO_MISSING value
+            // for pipe-related errors on other platforms. Of course
+            // this crack with two (if not more) levels of our own
+            // error codes hiding the actual system error code is
+            // broken, but that is done all over the code, let's leave
+            // reengineering that to another year.
+            SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
+#endif
+        }
+        else if ( aStatus == RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR )
+        {
+            SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
+        }
+        else if ( aStatus == RequestHandler::IPC_STATUS_2ND_OFFICE )
+        {
+            // 2nd office startup should terminate after sending cmdlineargs 
through pipe
+            SetBootstrapStatus(BS_TERMINATE);
+        }
+        else if ( !rCmdLineArgs.GetUnknown().isEmpty()
+                  || rCmdLineArgs.IsHelp() || rCmdLineArgs.IsVersion() )
+        {
+            // disable IPC thread in an instance that is just showing a help 
message
+            RequestHandler::Disable();
+        }
+        pSignalHandler = osl_addSignalHandler(SalMainPipeExchangeSignal_impl, 
nullptr);
+    }
+}
+
+void Desktop::InitFinished()
+{
+    CloseSplashScreen();
+}
+
+void Desktop::DeInit()
+{
+    try {
+        // instead of removing of the configManager just let it commit all the 
changes
+        utl::ConfigManager::storeConfigItems();
+        FlushConfiguration();
+
+        // close splashscreen if it's still open
+        CloseSplashScreen();
+        Reference< XComponent >(
+            comphelper::getProcessComponentContext(), UNO_QUERY_THROW )->
+            dispose();
+        // nobody should get a destroyed service factory...
+        ::comphelper::setProcessServiceFactory( nullptr );
+
+        // clear lockfile
+        m_xLockfile.reset();
+
+        RequestHandler::Disable();
+        if( pSignalHandler )
+            osl_removeSignalHandler( pSignalHandler );
+    } catch (const RuntimeException&) {
+        // someone threw an exception during shutdown
+        // this will leave some garbage behind..
+    }
+}
+
+bool Desktop::QueryExit()
+{
+    try
+    {
+        utl::ConfigManager::storeConfigItems();
+    }
+    catch ( const RuntimeException& )
+    {
+    }
+
+    const sal_Char SUSPEND_QUICKSTARTVETO[] = "SuspendQuickstartVeto";
+
+    Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( 
::comphelper::getProcessComponentContext() );
+    Reference< XPropertySet > xPropertySet(xDesktop, UNO_QUERY_THROW);
+    xPropertySet->setPropertyValue( SUSPEND_QUICKSTARTVETO, Any(true) );
+
+    bool bExit = xDesktop->terminate();
+
+    if ( !bExit )
+    {
+        xPropertySet->setPropertyValue( SUSPEND_QUICKSTARTVETO, Any(false) );
+    }
+    else if (!Application::IsEventTestingModeEnabled())
+    {
+        FlushConfiguration();
+        try
+        {
+            // it is no problem to call RequestHandler::Disable() more than 
once
+            // it also looks to be threadsafe
+            RequestHandler::Disable();
+        }
+        catch ( const RuntimeException& )
+        {
+        }
+
+        m_xLockfile.reset();
+
+    }
+
+    return bExit;
+}
+
+void Desktop::HandleBootstrapPathErrors( ::utl::Bootstrap::Status 
aBootstrapStatus, const OUString& aDiagnosticMessage )
+{
+    if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK )
+    {
+        OUString        aProductKey;
+        OUString        aTemp;
+
+        osl_getExecutableFile( &aProductKey.pData );
+        sal_uInt32     lastIndex = aProductKey.lastIndexOf('/');
+        if ( lastIndex > 0 )
+            aProductKey = aProductKey.copy( lastIndex+1 );
+
+        aTemp = ::utl::Bootstrap::getProductKey( aProductKey );
+        if ( !aTemp.isEmpty() )
+            aProductKey = aTemp;
+
+        OUString const aMessage(aDiagnosticMessage + "\n");
+
+        ScopedVclPtrInstance< MessageDialog > aBootstrapFailedBox(nullptr, 
aMessage);
+        aBootstrapFailedBox->SetText( aProductKey );
+        aBootstrapFailedBox->Execute();
+    }
+}
+
+// Create a error message depending on bootstrap failure code and an optional 
file url
+OUString    Desktop::CreateErrorMsgString(
+    utl::Bootstrap::FailureCode nFailureCode,
+    const OUString& aFileURL )
+{
+    OUString        aMsg;
+    OUString        aFilePath;
+    bool            bFileInfo = true;
+
+    switch ( nFailureCode )
+    {
+        /// the shared installation directory could not be located
+        case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
+        {
+            aMsg = GetMsgString( STR_BOOTSTRAP_ERR_PATH_INVALID,
+                        "The installation path is not available." );
+            bFileInfo = false;
+        }
+        break;
+
+        /// the bootstrap INI file could not be found or read
+        case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
+        {
+            aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_MISSING,
+                        "The configuration file \"$1\" is missing." );
+        }
+        break;
+
+        /// the bootstrap INI is missing a required entry
+        /// the bootstrap INI contains invalid data
+         case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY:
+         case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
+        {
+            aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_CORRUPT,
+                        "The configuration file \"$1\" is corrupt." );
+        }
+        break;
+
+        /// the version locator INI file could not be found or read
+        case ::utl::Bootstrap::MISSING_VERSION_FILE:
+        {
+            aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_MISSING,
+                        "The configuration file \"$1\" is missing." );
+        }
+        break;
+
+        /// the version locator INI has no entry for this version
+         case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
+        {
+            aMsg = GetMsgString( STR_BOOTSTRAP_ERR_NO_SUPPORT,
+                        "The main configuration file \"$1\" does not support 
the current version." );
+        }
+        break;
+
+        /// the user installation directory does not exist
+           case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
+        {
+            aMsg = GetMsgString( STR_BOOTSTRAP_ERR_DIR_MISSING,
+                        "The configuration directory \"$1\" is missing." );
+        }
+        break;
+
+        /// some bootstrap data was invalid in unexpected ways
+        case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
+        {
+            aMsg = GetMsgString( STR_BOOTSTRAP_ERR_INTERNAL,
+                        "An internal failure occurred." );
+            bFileInfo = false;
+        }
+        break;
+
+        case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
+        {
+            // This needs to be improved, see #i67575#:
+            aMsg = "Invalid version file entry";
+            bFileInfo = false;
+        }
+        break;
+
+        case ::utl::Bootstrap::NO_FAILURE:
+        {
+            OSL_ASSERT(false);
+        }
+        break;
+    }
+
+    if ( bFileInfo )
+    {
+        OUString aMsgString( aMsg );
+
+        osl::File::getSystemPathFromFileURL( aFileURL, aFilePath );
+
+        aMsgString = aMsgString.replaceFirst( "$1", aFilePath );
+        aMsg = aMsgString;
+    }
+
+    return MakeStartupErrorMessage( aMsg );
+}
+
+void Desktop::HandleBootstrapErrors(
+    BootstrapError aBootstrapError, OUString const & aErrorMessage )
+{
+    if ( aBootstrapError == BE_PATHINFO_MISSING )
+    {
+        OUString                    aErrorMsg;
+        OUString                    aBuffer;
+        utl::Bootstrap::Status        aBootstrapStatus;
+        utl::Bootstrap::FailureCode    nFailureCode;
+
+        aBootstrapStatus = ::utl::Bootstrap::checkBootstrapStatus( aBuffer, 
nFailureCode );
+        if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK )
+        {
+            switch ( nFailureCode )
+            {
+                case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
+                case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
+                {
+                    aErrorMsg = CreateErrorMsgString( nFailureCode, OUString() 
);
+                }
+                break;
+
+                /// the bootstrap INI file could not be found or read
+                /// the bootstrap INI is missing a required entry
+                /// the bootstrap INI contains invalid data
+                case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY:
+                case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
+                case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
+                {
+                    OUString aBootstrapFileURL;
+
+                    utl::Bootstrap::locateBootstrapFile( aBootstrapFileURL );
+                    aErrorMsg = CreateErrorMsgString( nFailureCode, 
aBootstrapFileURL );
+                }
+                break;
+
+                /// the version locator INI file could not be found or read
+                /// the version locator INI has no entry for this version
+                /// the version locator INI entry is not a valid directory URL
+                 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
+                 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
+                 case ::utl::Bootstrap::MISSING_VERSION_FILE:
+                {
+                    OUString aVersionFileURL;
+
+                    utl::Bootstrap::locateVersionFile( aVersionFileURL );
+                    aErrorMsg = CreateErrorMsgString( nFailureCode, 
aVersionFileURL );
+                }
+                break;
+
+                /// the user installation directory does not exist
+                 case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
+                {
+                    OUString aUserInstallationURL;
+
+                    utl::Bootstrap::locateUserInstallation( 
aUserInstallationURL );
+                    aErrorMsg = CreateErrorMsgString( nFailureCode, 
aUserInstallationURL );
+                }
+                break;
+
+                case ::utl::Bootstrap::NO_FAILURE:
+                {
+                    OSL_ASSERT(false);
+                }
+                break;
+            }
+
+            HandleBootstrapPathErrors( aBootstrapStatus, aErrorMsg );
+        }
+    }
+    else if ( aBootstrapError == BE_UNO_SERVICEMANAGER || aBootstrapError == 
BE_UNO_SERVICE_CONFIG_MISSING )
+    {
+        // Uno service manager is not available. VCL needs a uno service 
manager to display a message box!!!
+        // Currently we are not able to display a message box with a service 
manager due to this limitations inside VCL.
+
+        // When UNO is not properly initialized, all kinds of things can fail
+        // and cause the process to crash (e.g., a call to GetMsgString may
+        // crash when somewhere deep within that call Any::operator <= is used
+        // with a PropertyValue, and no binary UNO type description for
+        // PropertyValue is available).  To give the user a hint even if
+        // generating and displaying a message box below crashes, print a
+        // hard-coded message on stderr first:
+        std::cerr
+            << "The application cannot be started.\n"
+                // STR_BOOTSTRAP_ERR_CANNOT_START
+            << (aBootstrapError == BE_UNO_SERVICEMANAGER
+                ? "The component manager is not available.\n"
+                    // STR_BOOTSTRAP_ERR_NO_SERVICE
+                : "The configuration service is not available.\n");
+                    // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE
+        if ( !aErrorMessage.isEmpty() )
+        {
+            std::cerr << "(\"" << aErrorMessage << "\")\n";
+        }
+
+        // First sentence. We cannot bootstrap office further!
+        OUString            aMessage;
+        OUStringBuffer        aDiagnosticMessage( 100 );
+
+        OUString aErrorMsg;
+
+        if ( aBootstrapError == BE_UNO_SERVICEMANAGER )
+            aErrorMsg = "The service manager is not available.";
+        else
+            aErrorMsg = GetMsgString( STR_BOOTSTRAP_ERR_NO_CFG_SERVICE,
+                            "The configuration service is not available." );
+
+        aDiagnosticMessage.append( aErrorMsg );
+        aDiagnosticMessage.append( "\n" );
+        if ( !aErrorMessage.isEmpty() )
+        {
+            aDiagnosticMessage.append( "(\"" );
+            aDiagnosticMessage.append( aErrorMessage );
+            aDiagnosticMessage.append( "\")\n" );
+        }
+
+        // Due to the fact the we haven't a backup applicat.rdb file anymore 
it is not possible to
+        // repair the installation with the setup executable besides the 
office executable. Now
+        // we have to ask the user to start the setup on CD/installation 
directory manually!!
+        OUString aStartSetupManually( GetMsgString(
+            STR_ASK_START_SETUP_MANUALLY,
+            "Start setup application to repair the installation from CD, or 
the folder containing the installation packages.",
+            aBootstrapError == BE_UNO_SERVICEMANAGER ) );
+
+        aDiagnosticMessage.append( aStartSetupManually );
+        aMessage = MakeStartupErrorMessage(
+            aDiagnosticMessage.makeStringAndClear(),
+            aBootstrapError == BE_UNO_SERVICEMANAGER );
+
+        FatalError( aMessage);
+    }
+    else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
+    {
+        // test restore of registrymodifications
+        sal_uInt16 nSecureUserConfigNumCopies(0);
+        bool bFireOriginalError(true);
+
+        // read configuration from soffice.ini
+        const bool 
bSecureUserConfig(comphelper::BackupFileHelper::getSecureUserConfig(nSecureUserConfigNumCopies));
+
+        if (bSecureUserConfig)
+        {
+            // try to asccess user layer configuration file
+            OUString conf("${CONFIGURATION_LAYERS}");
+            rtl::Bootstrap::expandMacros(conf);
+            const OUString aTokenUser("user:");
+            sal_Int32 nStart(conf.indexOf(aTokenUser));
+            OUString aUser;
+
+            if (-1 != nStart)
+            {
+                nStart += aTokenUser.getLength();
+                sal_Int32 nEnd(conf.indexOf(' ', nStart));
+
+                if (-1 == nEnd)
+                {
+                    nEnd = conf.getLength();
+                }
+
+                aUser = conf.copy(nStart, nEnd - nStart);
+                aUser.startsWith("!", &aUser);
+            }
+
+            if (!aUser.isEmpty())
+            {
+                comphelper::BackupFileHelper aBackupFileHelper(aUser, 
nSecureUserConfigNumCopies);
+
+                if (aBackupFileHelper.isPopPossible())
+                {
+                    // for linux (and probably others?) we need to instantiate 
XDesktop2
+                    // to be able to open a *.ui-file based dialog, so do this 
here locally.
+                    // does no harm on win, so better always do this (in error 
case only anyways)
+                    Reference< XComponentContext > xLocalContext = 
::comphelper::getProcessComponentContext();
+                    Reference< XDesktop2 > xDesktop = 
css::frame::Desktop::create(xLocalContext);
+
+                    ScopedVclPtrInstance< MessageDialog > aQueryShouldRestore(
+                        Application::GetDefDialogParent(),
+                        "QueryTryToRestoreConfigurationDialog",
+                        "desktop/ui/querytrytorestoreconfigurationdialog.ui");
+
+                    if (aQueryShouldRestore.get())
+                    {
+                        if (!aErrorMessage.isEmpty())
+                        {
+                            OUString 
aPrimaryText(aQueryShouldRestore->get_primary_text());
+
+                            aPrimaryText += "\n(\"" + aErrorMessage + "\")";
+                            
aQueryShouldRestore->set_primary_text(aPrimaryText);
+                        }
+
+                        if (RET_YES == aQueryShouldRestore->Execute())
+                        {
+                            aBackupFileHelper.tryPop();
+                            bFireOriginalError = false;
+                        }
+                    }
+                }
+            }
+        }
+
+        // set flag at BackupFileHelper to be able to know if _exit was called 
and
+        // actions are executed after this
+        comphelper::BackupFileHelper::setExitWasCalled();
+
+        if (bFireOriginalError)
+        {
+            OUString msg(
+                GetMsgString(
+                STR_CONFIG_ERR_ACCESS_GENERAL,
+                ("A general error occurred while accessing your central"
+                " configuration.")));
+            if (!aErrorMessage.isEmpty()) {
+                msg += "\n(\"" + aErrorMessage + "\")";
+            }
+            FatalError(MakeStartupErrorMessage(msg));
+        }
+        else
+        {
+            // Already presented all information to the user.
+            // just do what FatalError does at it's end
+            _exit(EXITHELPER_FATAL_ERROR);
+        }
+    }
+    else if ( aBootstrapError == BE_USERINSTALL_FAILED )
+    {
+        OUString aMessage;
+        OUStringBuffer aDiagnosticMessage( 100 );
+        OUString aErrorMsg;
+        aErrorMsg = GetMsgString( STR_BOOTSTRAP_ERR_USERINSTALL_FAILED,
+            "User installation could not be completed" );
+        aDiagnosticMessage.append( aErrorMsg );
+        aMessage = MakeStartupErrorMessage( 
aDiagnosticMessage.makeStringAndClear() );
+        FatalError(aMessage);
+    }
+    else if ( aBootstrapError == BE_LANGUAGE_MISSING )
+    {
+        OUString aMessage;
+        OUStringBuffer aDiagnosticMessage( 100 );
+        OUString aErrorMsg;
+        aErrorMsg = GetMsgString(
+            //@@@ FIXME: should use an own resource string => #i36213#
+            STR_BOOTSTRAP_ERR_LANGUAGE_MISSING,
+            "Language could not be determined." );
+        aDiagnosticMessage.append( aErrorMsg );
+        aMessage = MakeStartupErrorMessage(
+            aDiagnosticMessage.makeStringAndClear() );
+        FatalError(aMessage);
+    }
+    else if (( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE ) ||
+             ( aBootstrapError == BE_USERINSTALL_NOWRITEACCESS      ))
+    {
+        OUString       aUserInstallationURL;
+        OUString       aUserInstallationPath;
+        OUString       aMessage;
+        OUString       aErrorMsg;
+        OUStringBuffer aDiagnosticMessage( 100 );
+
+        utl::Bootstrap::locateUserInstallation( aUserInstallationURL );
+
+        if ( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE )
+            aErrorMsg = GetMsgString(
+                STR_BOOSTRAP_ERR_NOTENOUGHDISKSPACE,
+                "User installation could not be completed due to insufficient 
free disk space." );
+        else
+            aErrorMsg = GetMsgString(
+                STR_BOOSTRAP_ERR_NOACCESSRIGHTS,
+                "User installation could not be processed due to missing 
access rights." );
+
+        osl::File::getSystemPathFromFileURL( aUserInstallationURL, 
aUserInstallationPath );
+
+        aDiagnosticMessage.append( aErrorMsg );
+        aDiagnosticMessage.append( aUserInstallationPath );
+        aMessage = MakeStartupErrorMessage(
+            aDiagnosticMessage.makeStringAndClear() );
+        FatalError(aMessage);
+    }
+
+    return;
+}
+
+
+bool Desktop::isUIOnSessionShutdownAllowed()
+{
+    return officecfg::Office::Recovery::SessionShutdown::DocumentStoreUIEnabled
+        ::get();
+}
+
+namespace {
+
+bool crashReportInfoExists()
+{
+#if HAVE_FEATURE_BREAKPAD
+    std::string path = CrashReporter::getIniFileName();
+    std::ifstream aFile(path);
+    while (aFile.good())
+    {
+        std::string line;
+        std::getline(aFile, line);
+        int sep = line.find('=');
+        if (sep >= 0)
+        {
+            std::string key = line.substr(0, sep);
+            if (key == "DumpFile")
+                return true;
+        }
+    }
+#endif
+    return false;
+}
+
+#if HAVE_FEATURE_BREAKPAD
+void handleCrashReport()
+{
+    static const char SERVICENAME_CRASHREPORT[] = 
"com.sun.star.comp.svx.CrashReportUI";
+
+    css::uno::Reference< css::uno::XComponentContext > xContext = 
::comphelper::getProcessComponentContext();
+
+    Reference< css::frame::XSynchronousDispatch > xRecoveryUI(
+        
xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_CRASHREPORT,
 xContext),
+        css::uno::UNO_QUERY_THROW);
+
+    Reference< css::util::XURLTransformer > xURLParser =
+        
css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
+
+    css::util::URL aURL;
+    css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, 
css::uno::Sequence< css::beans::PropertyValue >());
+    bool bRet = false;
+    aRet >>= bRet;
+}
+#endif
+
+void handleSafeMode()
+{
+    static const char SERVICENAME_SAFEMODE[] = 
"com.sun.star.comp.svx.SafeModeUI";
+
+    css::uno::Reference< css::uno::XComponentContext > xContext = 
::comphelper::getProcessComponentContext();
+
+    Reference< css::frame::XSynchronousDispatch > xSafeModeUI(
+        
xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_SAFEMODE, 
xContext),
+        css::uno::UNO_QUERY_THROW);
+
+    css::util::URL aURL;
+    css::uno::Any aRet = xSafeModeUI->dispatchWithReturnValue(aURL, 
css::uno::Sequence< css::beans::PropertyValue >());
+    bool bRet = false;
+    aRet >>= bRet;
+}
+
+/** @short  check if recovery must be started or not.
+
+    @param  bCrashed [boolean ... out!]
+            the office crashed last times.
+            But may be there are no recovery data.
+            Useful to trigger the error report tool without
+            showing the recovery UI.
+
+    @param  bRecoveryDataExists [boolean ... out!]
+            there exists some recovery data.
+
+    @param  bSessionDataExists [boolean ... out!]
+            there exists some session data.
+            Because the user may be logged out last time from its
+            unix session...
+*/
+void impl_checkRecoveryState(bool& bCrashed           ,
+                             bool& bRecoveryDataExists,
+                             bool& bSessionDataExists )
+{
+    bCrashed = officecfg::Office::Recovery::RecoveryInfo::Crashed::get() || 
crashReportInfoExists();
+    bool elements = officecfg::Office::Recovery::RecoveryList::get()->
+        hasElements();
+    bool session
+        = officecfg::Office::Recovery::RecoveryInfo::SessionData::get();
+    bRecoveryDataExists = elements && !session;
+    bSessionDataExists = elements && session;
+}
+
+
+/*  @short  start the recovery wizard.
+
+    @param  bEmergencySave
+            differs between EMERGENCY_SAVE and RECOVERY
+*/
+bool impl_callRecoveryUI(bool bEmergencySave     ,
+                         bool bExistsRecoveryData)
+{
+    static const char SERVICENAME_RECOVERYUI[] = 
"com.sun.star.comp.svx.RecoveryUI";
+    static const char COMMAND_EMERGENCYSAVE[] = 
"vnd.sun.star.autorecovery:/doEmergencySave";
+    static const char COMMAND_RECOVERY[] = 
"vnd.sun.star.autorecovery:/doAutoRecovery";
+
+    css::uno::Reference< css::uno::XComponentContext > xContext = 
::comphelper::getProcessComponentContext();
+
+    Reference< css::frame::XSynchronousDispatch > xRecoveryUI(
+        
xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_RECOVERYUI,
 xContext),
+        css::uno::UNO_QUERY_THROW);
+
+    Reference< css::util::XURLTransformer > xURLParser =
+        
css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
+
+    css::util::URL aURL;
+    if (bEmergencySave)
+        aURL.Complete = COMMAND_EMERGENCYSAVE;
+    else if (bExistsRecoveryData)
+        aURL.Complete = COMMAND_RECOVERY;
+    else
+        return false;
+
+    xURLParser->parseStrict(aURL);
+
+    css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, 
css::uno::Sequence< css::beans::PropertyValue >());
+    bool bRet = false;
+    aRet >>= bRet;
+    return bRet;
+}
+
+}
+
+/*
+ * Save all open documents so they will be reopened
+ * the next time the application is started
+ *
+ * returns sal_True if at least one document could be saved...
+ *
+ */
+bool Desktop::SaveTasks()
+{
+    return impl_callRecoveryUI(
+        true , // sal_True => force emergency save
+        false);
+}
+
+namespace {
+
+void restartOnMac(bool passArguments) {
+#if defined MACOSX
+    RequestHandler::Disable();
+#if HAVE_FEATURE_MACOSX_SANDBOX
+    (void) passArguments; // avoid warnings
+    ResMgr *resMgr = Desktop::GetDesktopResManager();
+    OUString aMessage = ResId(STR_LO_MUST_BE_RESTARTED, *resMgr).toString();
+
+    MessageDialog aRestartBox(NULL, aMessage);
+    aRestartBox.Execute();
+#else
+    OUString execUrl;
+    OSL_VERIFY(osl_getExecutableFile(&execUrl.pData) == osl_Process_E_None);
+    OUString execPath;
+    OString execPath8;
+    if ((osl::FileBase::getSystemPathFromFileURL(execUrl, execPath)
+         != osl::FileBase::E_None) ||
+        !execPath.convertToString(
+            &execPath8, osl_getThreadTextEncoding(),
+            (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+             RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+    {
+        std::abort();
+    }
+    std::vector< OString > args;
+    args.push_back(execPath8);
+    bool wait = false;
+    if (passArguments) {
+        sal_uInt32 n = osl_getCommandArgCount();
+        for (sal_uInt32 i = 0; i < n; ++i) {
+            OUString arg;
+            osl_getCommandArg(i, &arg.pData);
+            if (arg.match("--accept=")) {
+                wait = true;
+            }
+            OString arg8;
+            if (!arg.convertToString(
+                    &arg8, osl_getThreadTextEncoding(),
+                    (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+                     RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+            {
+                std::abort();
+            }
+            args.push_back(arg8);
+        }
+    }
+    std::vector< char const * > argPtrs;
+    for (std::vector< OString >::iterator i(args.begin()); i != args.end();
+         ++i)
+    {
+        argPtrs.push_back(i->getStr());
+    }
+    argPtrs.push_back(nullptr);
+    execv(execPath8.getStr(), const_cast< char ** >(&argPtrs[0]));
+    if (errno == ENOTSUP) { // happens when multithreaded on OS X < 10.6
+        pid_t pid = fork();
+        if (pid == 0) {
+            execv(execPath8.getStr(), const_cast< char ** >(&argPtrs[0]));
+        } else if (pid > 0) {
+            // Two simultaneously running soffice processes lead to two dock
+            // icons, so avoid waiting here unless it must be assumed that the
+            // process invoking soffice itself wants to wait for soffice to
+            // finish:
+            if (!wait) {
+                return;
+            }
+            int stat;
+            if (waitpid(pid, &stat, 0) == pid && WIFEXITED(stat)) {
+                _exit(WEXITSTATUS(stat));
+            }
+        }
+    }
+    std::abort();
+#endif
+#else
+    (void) passArguments; // avoid warnings
+#endif
+}
+
+}
+
+void Desktop::Exception(ExceptionCategory nCategory)
+{
+    // protect against recursive calls
+    static bool bInException = false;
+
+    SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
+    Application::SetSystemWindowMode( nOldMode & 
~SystemWindowFlags::NOAUTOMODE );
+    if ( bInException )
+    {
+        OUString aDoubleExceptionString;
+        Application::Abort( aDoubleExceptionString );
+    }
+
+    bInException = true;
+    const CommandLineArgs& rArgs = GetCommandLineArgs();
+
+    // save all modified documents ... if it's allowed doing so.
+    bool bRestart                           = false;
+    bool bAllowRecoveryAndSessionManagement = (
+                                                    ( !rArgs.IsNoRestore()     
               ) && // some use cases of office must work without recovery
+                                                    ( !rArgs.IsHeadless()      
               ) &&
+                                                    ( nCategory != 
ExceptionCategory::UserInterface ) && // recovery can't work without UI ... but 
UI layer seems to be the reason for this crash
+                                                    ( 
Application::IsInExecute()               )    // crashes during startup and 
shutdown should be ignored (they indicates a corrupt installation ...)
+                                                  );
+    if ( bAllowRecoveryAndSessionManagement )
+        bRestart = SaveTasks();
+
+    FlushConfiguration();
+
+    switch( nCategory )
+    {
+        case ExceptionCategory::ResourceNotLoaded:
+        {
+            OUString aResExceptionString;
+            Application::Abort( aResExceptionString );
+            break;
+        }
+
+        default:
+        {
+            m_xLockfile.reset();
+
+            if( bRestart )
+            {
+                RequestHandler::Disable();
+                if( pSignalHandler )
+                    osl_removeSignalHandler( pSignalHandler );
+
+                restartOnMac(false);
+                if ( m_rSplashScreen.is() )
+                    m_rSplashScreen->reset();
+
+                _exit( EXITHELPER_CRASH_WITH_RESTART );
+            }
+            else
+            {
+                Application::Abort( OUString() );
+            }
+
+            break;
+        }
+    }
+
+    OSL_ASSERT(false); // unreachable
+}
+
+void Desktop::AppEvent( const ApplicationEvent& rAppEvent )
+{
+    HandleAppEvent( rAppEvent );
+}
+
+struct ExecuteGlobals
+{
+    Reference < css::document::XDocumentEventListener > xGlobalBroadcaster;
+    bool bRestartRequested;
+    bool bUseSystemFileDialog;
+    std::unique_ptr<SvtLanguageOptions> pLanguageOptions;
+    std::unique_ptr<SvtPathOptions> pPathOptions;
+
+    ExecuteGlobals()
+    : bRestartRequested( false )
+    , bUseSystemFileDialog( true )
+    {}
+};
+
+static ExecuteGlobals* pExecGlobals = nullptr;
+
+
+//This just calls Execute() for all normal uses of LibreOffice, but for
+//ui-testing if built with afl-clang-fast++ then on exit it will pseudo-restart
+//(up to 100 times)
+void Desktop::DoExecute()
+{
+#if !defined(__AFL_HAVE_MANUAL_CONTROL)
+    Execute();
+#else
+    while (__AFL_LOOP(1000))
+    {
+        Execute();
+        OpenDefault();
+    }
+#endif
+}
+
+int Desktop::Main()
+{
+    pExecGlobals = new ExecuteGlobals();
+
+    // Remember current context object
+    css::uno::ContextLayer layer( css::uno::getCurrentContext() );
+
+    if ( m_aBootstrapError != BE_OK )
+    {
+        HandleBootstrapErrors( m_aBootstrapError, m_aBootstrapErrorMessage );
+        return EXIT_FAILURE;
+    }
+
+    BootstrapStatus eStatus = GetBootstrapStatus();
+    if (eStatus == BS_TERMINATE) {
+        return EXIT_SUCCESS;
+    }
+
+    // Detect desktop environment - need to do this as early as possible
+    css::uno::setCurrentContext( new DesktopContext( 
css::uno::getCurrentContext() ) );
+
+    CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
+
+#if HAVE_FEATURE_DESKTOP
+    OUString aUnknown( rCmdLineArgs.GetUnknown() );
+    if ( !aUnknown.isEmpty() )
+    {
+        displayCmdlineHelp( aUnknown );
+        return EXIT_FAILURE;
+    }
+    if ( rCmdLineArgs.IsHelp() )
+    {
+        displayCmdlineHelp( OUString() );
+        return EXIT_SUCCESS;
+    }
+    if ( rCmdLineArgs.IsVersion() )
+    {
+        displayVersion();
+        return EXIT_SUCCESS;
+    }
+#endif
+
+    ResMgr::SetReadStringHook( ReplaceStringHookProc );
+
+    // Startup screen
+    OpenSplashScreen();
+
+    SetSplashScreenProgress(10);
+
+    userinstall::Status inst_fin = userinstall::finalize();
+    if (inst_fin != userinstall::EXISTED && inst_fin != userinstall::CREATED)
+    {
+        SAL_WARN( "desktop.app", "userinstall failed");
+        if ( inst_fin == userinstall::ERROR_NO_SPACE )
+            HandleBootstrapErrors(
+                BE_USERINSTALL_NOTENOUGHDISKSPACE, OUString() );
+        else if ( inst_fin == userinstall::ERROR_CANT_WRITE )
+            HandleBootstrapErrors( BE_USERINSTALL_NOWRITEACCESS, OUString() );
+        else
+            HandleBootstrapErrors( BE_USERINSTALL_FAILED, OUString() );
+        return EXIT_FAILURE;
+    }
+    // refresh path information
+    utl::Bootstrap::reloadData();
+    SetSplashScreenProgress(20);
+
+    Reference< XComponentContext > xContext = 
::comphelper::getProcessComponentContext();
+
+    Reference< XRestartManager > xRestartManager( 
OfficeRestartManager::get(xContext) );
+
+    Reference< XDesktop2 > xDesktop;
+    try
+    {
+        RegisterServices(xContext);
+
+        SetSplashScreenProgress(25);
+
+#if HAVE_FEATURE_DESKTOP
+        // check user installation directory for lockfile so we can be sure
+        // there is no other instance using our data files from a remote host
+        m_xLockfile.reset(new Lockfile);
+
+        if ( !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsInvisible() &&
+             !rCmdLineArgs.IsNoLockcheck() && !m_xLockfile->check( 
Lockfile_execWarning ))
+        {
+            // Lockfile exists, and user clicked 'no'
+            return EXIT_FAILURE;
+        }
+
+        // check if accessibility is enabled but not working and allow to quit
+        if( 
Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() )
+        {
+            if( !InitAccessBridge() )
+                return EXIT_FAILURE;
+        }
+#endif
+
+        // terminate if requested...
+        if( rCmdLineArgs.IsTerminateAfterInit() )
+            return EXIT_SUCCESS;
+
+        //  Read the common configuration items for optimization purpose
+        if ( !InitializeConfiguration() )
+            return EXIT_FAILURE;
+
+        SetSplashScreenProgress(30);
+
+        // create title string
+        LanguageTag aLocale( LANGUAGE_SYSTEM);
+        ResMgr* pLabelResMgr = GetDesktopResManager();

... etc. - the rest is truncated
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to