comphelper/source/misc/configuration.cxx                    |  107 +----
 comphelper/source/misc/docpasswordhelper.cxx                |    5 
 comphelper/source/misc/storagehelper.cxx                    |    5 
 include/comphelper/configuration.hxx                        |   22 -
 oox/source/crypto/Standard2007Engine.cxx                    |    5 
 package/source/zippackage/ZipPackageStream.cxx              |   10 
 sc/source/core/tool/compiler.cxx                            |   10 
 sc/source/filter/excel/xeroot.cxx                           |    6 
 sc/source/filter/excel/xestream.cxx                         |    5 
 svl/source/passwordcontainer/passwordcontainer.cxx          |    5 
 sw/qa/extras/odfimport/data/tdf123968.odt                   |binary
 sw/qa/extras/odfimport/odfimport.cxx                        |   12 
 sw/qa/extras/rtfexport/data/tdf136445-1-min.rtf             |   17 
 sw/qa/extras/rtfexport/data/tdf158409.rtf                   |   12 
 sw/qa/extras/rtfexport/data/tdf158586_pageBreak1_header.rtf |   17 
 sw/qa/extras/rtfexport/rtfexport3.cxx                       |    9 
 sw/qa/extras/rtfexport/rtfexport8.cxx                       |   56 ++-
 sw/qa/extras/rtfimport/rtfimport.cxx                        |    2 
 sw/source/core/fields/expfld.cxx                            |   20 -
 sw/source/core/inc/unofield.hxx                             |    2 
 sw/source/core/layout/fly.cxx                               |    5 
 sw/source/core/unocore/unofield.cxx                         |   30 +
 sw/source/filter/ww8/wrtww8.cxx                             |    6 
 sw/source/filter/ww8/ww8par.cxx                             |    6 
 writerfilter/source/dmapper/DomainMapper.cxx                |    9 
 writerfilter/source/dmapper/DomainMapper_Impl.cxx           |  223 +++++-------
 writerfilter/source/dmapper/DomainMapper_Impl.hxx           |  119 +++---
 writerfilter/source/dmapper/SdtHelper.cxx                   |    4 
 writerfilter/source/rtftok/rtfdispatchsymbol.cxx            |    9 
 writerfilter/source/rtftok/rtfdocumentimpl.cxx              |   22 -
 writerfilter/source/rtftok/rtfdocumentimpl.hxx              |    2 
 xmlsecurity/inc/certificatechooser.hxx                      |   18 
 xmlsecurity/source/component/documentdigitalsignatures.cxx  |    2 
 xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx      |    2 
 xmlsecurity/source/xmlsec/nss/ciphercontext.cxx             |    5 
 35 files changed, 445 insertions(+), 344 deletions(-)

New commits:
commit 38a572d54dd360298d032504f1eb5de682cc2add
Author:     Caolán McNamara <[email protected]>
AuthorDate: Mon Jan 29 10:53:32 2024 +0000
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:27 2024 +0100

    ofz: Use-of-uninitialized-value
    
    keep a high water mark of the highest initialized level
    
    Change-Id: Ib799331c523209c4f165dc4c40317e25b6b0cc7c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162624
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 63b1f0969225..c9934c26fff6 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -4738,6 +4738,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( 
const OUString& rFormul
     pFunctionStack[0].eOp = ocNone;
     pFunctionStack[0].nSep = 0;
     size_t nFunction = 0;
+    size_t nHighWatermark = 0;
     short nBrackets = 0;
     bool bInArray = false;
     eLastOp = ocOpen;
@@ -4757,6 +4758,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( 
const OUString& rFormul
                     ++nFunction;
                     pFunctionStack[ nFunction ].eOp = eLastOp;
                     pFunctionStack[ nFunction ].nSep = 0;
+                    nHighWatermark = nFunction;
                 }
             }
             break;
@@ -4795,6 +4797,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( 
const OUString& rFormul
                     ++nFunction;
                     pFunctionStack[ nFunction ].eOp = eOp;
                     pFunctionStack[ nFunction ].nSep = 0;
+                    nHighWatermark = nFunction;
                 }
             }
             break;
@@ -4825,6 +4828,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( 
const OUString& rFormul
                     ++nFunction;
                     pFunctionStack[ nFunction ].eOp = eOp;
                     pFunctionStack[ nFunction ].nSep = 0;
+                    nHighWatermark = nFunction;
                 }
             }
             break;
@@ -4867,9 +4871,9 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( 
const OUString& rFormul
             // Append a parameter for WEEKNUM, all 1.0
             // Function is already closed, parameter count is nSep+1
             size_t nFunc = nFunction + 1;
-            if (eOp == ocClose &&
-                    (pFunctionStack[ nFunc ].eOp == ocWeek &&   // 2nd week 
start
-                     pFunctionStack[ nFunc ].nSep == 0))
+            if (eOp == ocClose && nFunc <= nHighWatermark &&
+                     pFunctionStack[ nFunc ].nSep == 0 &&
+                     pFunctionStack[ nFunc ].eOp == ocWeek)   // 2nd week start
             {
                 if (    !static_cast<ScTokenArray*>(pArr)->Add( new 
FormulaToken( svSep, ocSep)) ||
                         !static_cast<ScTokenArray*>(pArr)->Add( new 
FormulaDoubleToken( 1.0)))
commit 39cd12ccfc280315ad46d6311351e9f444f4838c
Author:     Patrick Luby <[email protected]>
AuthorDate: Tue Feb 6 19:43:39 2024 -0500
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:27 2024 +0100

    Don't reuse CertificateChooser instances
    
    Reusing the same instance will, in the following case, lead to a
    crash. It appears that the CertificateChooser is getting disposed
    somewhere as mpDialogImpl in its base class ends up being null:
    
    1. Create an empty Writer document and add a digital signature
       in the Digital Signatures dialog
    2. File > Save As the document, check the "Encrypt with GPG key"
       checkbox, press Encrypt, and crash in Dialog::ImplStartExecute()
    
    Change-Id: I9aaa1bd449622e018b502d68c53d397255a1b61a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163065
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <[email protected]>
    Reviewed-by: Patrick Luby <[email protected]>
    (cherry picked from commit f0a5cb1f77496d212a90b5303a9f4be8b8c0e283)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163025

diff --git a/xmlsecurity/inc/certificatechooser.hxx 
b/xmlsecurity/inc/certificatechooser.hxx
index 12303fbf1cd5..b0cf7c7cdcc4 100644
--- a/xmlsecurity/inc/certificatechooser.hxx
+++ b/xmlsecurity/inc/certificatechooser.hxx
@@ -51,8 +51,6 @@ enum class UserAction
 class CertificateChooser final : public weld::GenericDialogController
 {
 private:
-    static inline CertificateChooser* mxInstance = nullptr;
-
     std::vector< css::uno::Reference< css::xml::crypto::XXMLSecurityContext > 
> mxSecurityContexts;
     std::vector<std::shared_ptr<UserData>> mvUserData;
 
@@ -91,14 +89,18 @@ public:
                        UserAction eAction);
     virtual ~CertificateChooser() override;
 
-    static CertificateChooser* getInstance(weld::Window* _pParent,
+    static std::unique_ptr<CertificateChooser> getInstance(weld::Window* 
_pParent,
                         std::vector< css::uno::Reference< 
css::xml::crypto::XXMLSecurityContext > > && rxSecurityContexts,
                         UserAction eAction) {
-        if (!mxInstance)
-        {
-            mxInstance = new CertificateChooser(_pParent, 
std::move(rxSecurityContexts), eAction);
-        }
-        return mxInstance;
+        // Don't reuse CertificateChooser instances
+        // Reusing the same instance will, in the following case, lead to a
+        // crash. It appears that the CertificateChooser is getting disposed
+        // somewhere as mpDialogImpl in its base class ends up being null:
+        // 1. Create an empty Writer document and add a digital signature
+        //    in the Digital Signatures dialog
+        // 2. File > Save As the document, check the "Encrypt with GPG key"
+        //    checkbox, press Encrypt, and crash in Dialog::ImplStartExecute()
+        return std::make_unique<CertificateChooser>(_pParent, 
std::move(rxSecurityContexts), eAction);
     }
 
     short run() override;
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx 
b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index 4ad63b36ed0b..c1768c0e953a 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -709,7 +709,7 @@ 
DocumentDigitalSignatures::chooseCertificatesImpl(std::map<OUString, OUString>&
             xSecContexts.push_back(aSignatureManager.getGpgSecurityContext());
     }
 
-    CertificateChooser* aChooser = 
CertificateChooser::getInstance(Application::GetFrameWeld(mxParentWindow), 
std::move(xSecContexts), eAction);
+    std::unique_ptr<CertificateChooser> aChooser = 
CertificateChooser::getInstance(Application::GetFrameWeld(mxParentWindow), 
std::move(xSecContexts), eAction);
 
     if (aChooser->run() != RET_OK)
         return { Reference< css::security::XCertificate >(nullptr) };
diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx 
b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
index b1a2cd57c95e..8349a58a31ce 100644
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -509,7 +509,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, 
weld::Button&, void)
         if 
(DocumentSignatureHelper::CanSignWithGPG(maSignatureManager.getStore(), 
m_sODFVersion))
             xSecContexts.push_back(maSignatureManager.getGpgSecurityContext());
 
-        CertificateChooser* aChooser = 
CertificateChooser::getInstance(m_xDialog.get(), std::move(xSecContexts), 
UserAction::Sign);
+        std::unique_ptr<CertificateChooser> aChooser = 
CertificateChooser::getInstance(m_xDialog.get(), std::move(xSecContexts), 
UserAction::Sign);
         if (aChooser->run() == RET_OK)
         {
             sal_Int32 nSecurityId;
commit 8e9d69f353118f7152e2dbad932f301fb9a1cf00
Author:     Xisco Fauli <[email protected]>
AuthorDate: Tue Feb 6 17:03:45 2024 +0100
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:27 2024 +0100

    tdf#157042: Revert "re-apply "optimize ConfigurationProperty::get()""
    
    This reverts commit 3a4a00a51acca8f9b5e775547abff0c4dc9144d7.
    
    it's causing 
https://crashreport.libreoffice.org/stats/signature/%3Cname%20omitted%3E
    in libreoffice-24-2 branch ( See
    https://bugs.documentfoundation.org/show_bug.cgi?id=157042#c36 )
    In previous branches, it was reported as
    
https://crashreport.libreoffice.org/stats/signature/void%20rtl::str::release%3C_rtl_uString%3E(_rtl_uString*)
    See comment in 7b46c77366fb3effd2de9bf5ba11ebd3c064974a
    "tdf#157042: Revert "re-apply "optimize ConfigurationProperty::get()""
    
    Change-Id: I3481c05b12b422404a38f0be1fea1ea69ffd0e46
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163061
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/comphelper/source/misc/configuration.cxx 
b/comphelper/source/misc/configuration.cxx
index 6e500f619232..a724b8654590 100644
--- a/comphelper/source/misc/configuration.cxx
+++ b/comphelper/source/misc/configuration.cxx
@@ -10,8 +10,11 @@
 #include <sal/config.h>
 
 #include <cassert>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <string_view>
 
-#include <com/sun/star/beans/NamedValue.hpp>
 #include <com/sun/star/beans/PropertyAttribute.hpp>
 #include <com/sun/star/configuration/ReadOnlyAccess.hpp>
 #include <com/sun/star/configuration/ReadWriteAccess.hpp>
@@ -21,16 +24,12 @@
 #include <com/sun/star/container/XHierarchicalNameReplace.hpp>
 #include <com/sun/star/container/XNameAccess.hpp>
 #include <com/sun/star/container/XNameContainer.hpp>
-#include <com/sun/star/util/XChangesListener.hpp>
-#include <com/sun/star/util/XChangesNotifier.hpp>
-#include <com/sun/star/lang/DisposedException.hpp>
 #include <com/sun/star/lang/XLocalizable.hpp>
 #include <com/sun/star/uno/Any.hxx>
 #include <com/sun/star/uno/Reference.hxx>
 #include <comphelper/solarmutex.hxx>
 #include <comphelper/configuration.hxx>
 #include <comphelper/configurationlistener.hxx>
-#include <cppuhelper/implbase.hxx>
 #include <rtl/ustring.hxx>
 #include <sal/log.hxx>
 #include <i18nlangtag/languagetag.hxx>
@@ -107,67 +106,12 @@ comphelper::detail::ConfigurationWrapper::get()
     return WRAPPER;
 }
 
-class comphelper::detail::ConfigurationChangesListener
-    : public ::cppu::WeakImplHelper<css::util::XChangesListener>
-{
-     comphelper::detail::ConfigurationWrapper& mrConfigurationWrapper;
-public:
-    ConfigurationChangesListener(comphelper::detail::ConfigurationWrapper& 
rWrapper)
-        : mrConfigurationWrapper(rWrapper)
-    {}
-    // util::XChangesListener
-    virtual void SAL_CALL changesOccurred( const css::util::ChangesEvent& ) 
override
-    {
-        std::scoped_lock aGuard(mrConfigurationWrapper.maMutex);
-        mrConfigurationWrapper.maPropertyCache.clear();
-    }
-    virtual void SAL_CALL disposing(const css::lang::EventObject&) override
-    {
-        std::scoped_lock aGuard(mrConfigurationWrapper.maMutex);
-        mrConfigurationWrapper.mbDisposed = true;
-        mrConfigurationWrapper.maPropertyCache.clear();
-        mrConfigurationWrapper.maNotifier.clear();
-        mrConfigurationWrapper.maListener.clear();
-    }
-};
-
 comphelper::detail::ConfigurationWrapper::ConfigurationWrapper():
     context_(comphelper::getProcessComponentContext()),
-    access_(css::configuration::ReadWriteAccess::create(context_, "*")),
-    mbDisposed(false)
-{
-    // Set up a configuration notifier to invalidate the cache as needed.
-    try
-    {
-        css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(
-            css::configuration::theDefaultProvider::get( context_ ) );
-
-        // set root path
-        css::uno::Sequence< css::uno::Any > params {
-            css::uno::Any( css::beans::NamedValue{ "nodepath", css::uno::Any( 
OUString("/"))} ),
-            css::uno::Any( css::beans::NamedValue{ "locale", css::uno::Any( 
OUString("*"))} ) };
-
-        css::uno::Reference< css::uno::XInterface > xCfg
-            = 
xConfigProvider->createInstanceWithArguments(u"com.sun.star.configuration.ConfigurationAccess"_ustr,
-                params);
-
-        maNotifier = css::uno::Reference< css::util::XChangesNotifier >(xCfg, 
css::uno::UNO_QUERY);
-        assert(maNotifier.is());
-        maListener.set(new ConfigurationChangesListener(*this));
-        maNotifier->addChangesListener(maListener);
-    }
-    catch(const css::uno::Exception&)
-    {
-        assert(false);
-    }
-}
+    access_(css::configuration::ReadWriteAccess::create(context_, "*"))
+{}
 
-comphelper::detail::ConfigurationWrapper::~ConfigurationWrapper()
-{
-    maPropertyCache.clear();
-    maNotifier.clear();
-    maListener.clear();
-}
+comphelper::detail::ConfigurationWrapper::~ConfigurationWrapper() {}
 
 bool comphelper::detail::ConfigurationWrapper::isReadOnly(OUString const & 
path)
     const
@@ -178,26 +122,31 @@ bool 
comphelper::detail::ConfigurationWrapper::isReadOnly(OUString const & path)
         != 0;
 }
 
-css::uno::Any 
comphelper::detail::ConfigurationWrapper::getPropertyValue(OUString const& 
path) const
+css::uno::Any 
comphelper::detail::ConfigurationWrapper::getPropertyValue(std::u16string_view 
path) const
 {
-    std::scoped_lock aGuard(maMutex);
-    if (mbDisposed)
-        throw css::lang::DisposedException();
     // Cache the configuration access, since some of the keys are used in hot 
code.
-    auto it = maPropertyCache.find(path);
-    if( it != maPropertyCache.end())
-        return it->second;
+    // Note that this cache is only used by the officecfg:: auto-generated 
code, using it for anything
+    // else would be unwise because the cache could end up containing stale 
entries.
+    static std::mutex gMutex;
+    static std::map<OUString, css::uno::Reference< css::container::XNameAccess 
>> gAccessMap;
 
-    sal_Int32 idx = path.lastIndexOf("/");
+    sal_Int32 idx = path.rfind('/');
     assert(idx!=-1);
-    OUString parentPath = path.copy(0, idx);
-    OUString childName = path.copy(idx+1);
-
-    css::uno::Reference<css::container::XNameAccess> access(
-        access_->getByHierarchicalName(parentPath), css::uno::UNO_QUERY_THROW);
-    css::uno::Any property = access->getByName(childName);
-    maPropertyCache.emplace(path, property);
-    return property;
+    OUString parentPath(path.substr(0, idx));
+    OUString childName(path.substr(idx+1));
+
+    std::scoped_lock aGuard(gMutex);
+
+    // check cache
+    auto it = gAccessMap.find(parentPath);
+    if (it == gAccessMap.end())
+    {
+        // not in the cache, look it up
+        css::uno::Reference<css::container::XNameAccess> access(
+            access_->getByHierarchicalName(parentPath), 
css::uno::UNO_QUERY_THROW);
+        it = gAccessMap.emplace(parentPath, access).first;
+    }
+    return it->second->getByName(childName);
 }
 
 void comphelper::detail::ConfigurationWrapper::setPropertyValue(
diff --git a/include/comphelper/configuration.hxx 
b/include/comphelper/configuration.hxx
index 652e9afaa640..51106a0a12c3 100644
--- a/include/comphelper/configuration.hxx
+++ b/include/comphelper/configuration.hxx
@@ -12,16 +12,15 @@
 
 #include <sal/config.h>
 
+#include <optional>
+#include <string_view>
+
 #include <com/sun/star/uno/Any.hxx>
 #include <com/sun/star/uno/Reference.h>
 #include <comphelper/comphelperdllapi.h>
 #include <comphelper/processfactory.hxx>
 #include <sal/types.h>
 #include <memory>
-#include <mutex>
-#include <optional>
-#include <string_view>
-#include <unordered_map>
 
 namespace com::sun::star {
     namespace configuration { class XReadWriteAccess; }
@@ -32,10 +31,6 @@ namespace com::sun::star {
         class XNameContainer;
     }
     namespace uno { class XComponentContext; }
-    namespace util {
-        class XChangesListener;
-        class XChangesNotifier;
-    }
 }
 
 namespace comphelper {
@@ -85,17 +80,14 @@ private:
 
 namespace detail {
 
-class ConfigurationChangesListener;
-
 /// @internal
 class COMPHELPER_DLLPUBLIC ConfigurationWrapper {
-friend class ConfigurationChangesListener;
 public:
     static ConfigurationWrapper const & get();
 
     bool isReadOnly(OUString const & path) const;
 
-    css::uno::Any getPropertyValue(OUString const & path) const;
+    css::uno::Any getPropertyValue(std::u16string_view path) const;
 
     static void setPropertyValue(
         std::shared_ptr< ConfigurationChanges > const & batch,
@@ -143,12 +135,6 @@ private:
         // css.beans.XHierarchicalPropertySetInfo), but then
         // configmgr::Access::asProperty() would report all properties as
         // READONLY, so isReadOnly() would not work
-
-    mutable std::mutex maMutex;
-    bool mbDisposed;
-    mutable std::unordered_map<OUString, css::uno::Any> maPropertyCache;
-    css::uno::Reference< css::util::XChangesNotifier > maNotifier;
-    css::uno::Reference< css::util::XChangesListener > maListener;
 };
 
 /// @internal
commit 34b0150df174e23d02190dc00e51b67be1f670dc
Author:     Michael Stahl <[email protected]>
AuthorDate: Thu Feb 1 15:11:03 2024 +0100
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:27 2024 +0100

    tdf#159015 sw: layout: fix infinite loop in ::CalcContent()
    
    SwObjectFormatter::FormatObj() will just return if IsAgain() is set, so
    the while loop here won't make any progress.
    
    (regression from commit 191babee4f0ec643b80e96b0cd98c2d04ff96e4e)
    
    Change-Id: I1c194b148760ae05cf4dee1d5729be28e87d6ba0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162880
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 13865c4da30a3a2a5ab8efbd568c47952d3ffcee)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162894
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index ba57cd6b4cdf..db50a42de053 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -43,6 +43,7 @@
 #include <svx/svdoashp.hxx>
 #include <svx/svdpage.hxx>
 #include <layouter.hxx>
+#include <layact.hxx>
 #include <pagefrm.hxx>
 #include <rootfrm.hxx>
 #include <viewimp.hxx>
@@ -1741,6 +1742,10 @@ void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
                         if (!SwObjectFormatter::FormatObj(*pAnchoredObj, 
pAnchorFrame, pAnchorPageFrame,
                                 rShell.Imp()->IsAction() ? 
&rShell.Imp()->GetLayAction() : nullptr))
                         {
+                            if (rShell.Imp()->IsAction() && 
rShell.Imp()->GetLayAction().IsAgain())
+                            {   // tdf#159015 will always fail, don't loop
+                                return;
+                            }
                             bRestartLayoutProcess = true;
                             break;
                         }
commit a0baf67973615ac25e4504f0895831e8adeb8f89
Author:     Michael Stahl <[email protected]>
AuthorDate: Fri Feb 2 20:10:24 2024 +0100
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:27 2024 +0100

    tdf#123968 sw: fix assert on importing ooo62823-1.sxw
    
    svl/source/items/itemset.cxx:662: const SfxPoolItem* 
implCreateItemEntry(SfxItemPool&, const SfxPoolItem*, bool): Assertion 
`pSource->Which() == nWhich && "ITEM: Clone of Item did NOT copy/set WhichID 
(!)"' failed.
    
    XMLVariableInputFieldImportContext::PrepareField() first sets "Input"
    and then "SubType" property.
    
    Apparently i missed that *both* of these are mutable in the API, and
    both together determine whether the field is a RES_TXTATR_INPUTFIELD or
    RES_TXTATR_FIELD.
    
    So call SwXTextField::TransmuteLeadToInputField() also when the
    "SubType" is set, and adapt it to toggling 2 different things.
    
    Hmm... actually this will change these fields to be inline editable
    after ODF import, which was the intention all along.
    
    It turns out that there is even a unit test testTdf123968 for this; it
    works in the usual case, but in this case the input field is in a
    header, so in styles.xml, and the styles.xml is imported before
    content.xml and does not contain the variable-decls element, so the
    variable field type has the GSE_EXPR subtype (default?), and setting the
    "Input" property doesn't transmute it.
    
    (regression from commit 742baabbe4d077e1ba913a7989300908f4637ac7)
    
    Change-Id: Ib5757cda32287e51651f05f5b19e82d7be0431e3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162941
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 99055ae98ef1fe67b8db4a8c3167a8acaeaac02f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163012
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sw/qa/extras/odfimport/data/tdf123968.odt 
b/sw/qa/extras/odfimport/data/tdf123968.odt
index 1c081619ea30..cd1ec8a3859a 100644
Binary files a/sw/qa/extras/odfimport/data/tdf123968.odt and 
b/sw/qa/extras/odfimport/data/tdf123968.odt differ
diff --git a/sw/qa/extras/odfimport/odfimport.cxx 
b/sw/qa/extras/odfimport/odfimport.cxx
index 168de4fb6db7..70c6452e3d9f 100644
--- a/sw/qa/extras/odfimport/odfimport.cxx
+++ b/sw/qa/extras/odfimport/odfimport.cxx
@@ -1167,9 +1167,21 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf123968)
     SwTextNode& rStart = 
dynamic_cast<SwTextNode&>(pShellCursor->Start()->GetNode());
 
     // The field is now editable like any text, thus the field content "New 
value" shows up for the cursor.
+    // This field's variable is declared as string and used as string - 
typical.
     CPPUNIT_ASSERT_EQUAL(OUString("inputfield: " + 
OUStringChar(CH_TXT_ATR_INPUTFIELDSTART)
                                   + "New value" + 
OUStringChar(CH_TXT_ATR_INPUTFIELDEND)),
                          rStart.GetText());
+
+    // This field's variable is declared as float and used as string - not
+    // typical; this can easily happen if the input field is in a 
header/footer,
+    // because only content.xml contains the variable-decls, styles.xml is
+    // imported before content.xml, and apparently the default variable type is
+    // numeric.
+    SwTextNode& rEnd = 
dynamic_cast<SwTextNode&>(pShellCursor->End()->GetNode());
+    CPPUNIT_ASSERT_EQUAL(OUString("inputfield: " + 
OUStringChar(CH_TXT_ATR_INPUTFIELDSTART)
+                                  + "String input for num variable" + 
OUStringChar(CH_TXT_ATR_INPUTFIELDEND)),
+                         rEnd.GetText());
+
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testTdf133459)
diff --git a/sw/source/core/fields/expfld.cxx b/sw/source/core/fields/expfld.cxx
index 434f67672903..6ed4cdb7c125 100644
--- a/sw/source/core/fields/expfld.cxx
+++ b/sw/source/core/fields/expfld.cxx
@@ -881,10 +881,9 @@ std::unique_ptr<SwField> SwSetExpField::Copy() const
 
 void SwSetExpField::SetSubType(sal_uInt16 nSub)
 {
+    assert((nSub & 0xff) != 
(nsSwGetSetExpType::GSE_STRING|nsSwGetSetExpType::GSE_EXPR) && "SubType is 
illegal!");
     static_cast<SwSetExpFieldType*>(GetTyp())->SetType(nSub & 0xff);
     mnSubType = nSub & 0xff00;
-
-    OSL_ENSURE( (nSub & 0xff) != 3, "SubType is illegal!" );
 }
 
 sal_uInt16 SwSetExpField::GetSubType() const
@@ -1100,8 +1099,19 @@ bool SwSetExpField::PutValue( const uno::Any& rAny, 
sal_uInt16 nWhichId )
         break;
     case FIELD_PROP_SUBTYPE:
         nTmp32 = lcl_APIToSubType(rAny);
-        if(nTmp32 >= 0)
-            SetSubType(o3tl::narrowing<sal_uInt16>((GetSubType() & 0xff00) | 
nTmp32));
+        if (0 <= nTmp32 && nTmp32 != (GetSubType() & 0xff))
+        {
+            auto const subType(o3tl::narrowing<sal_uInt16>((GetSubType() & 
0xff00) | nTmp32));
+            if (((nTmp32 & nsSwGetSetExpType::GSE_STRING) != (GetSubType() & 
nsSwGetSetExpType::GSE_STRING))
+                && GetInputFlag())
+            {
+                SwXTextField::TransmuteLeadToInputField(*this, &subType);
+            }
+            else
+            {
+                SetSubType(subType);
+            }
+        }
         break;
     case FIELD_PROP_PAR3:
         rAny >>= maPText;
@@ -1120,7 +1130,7 @@ bool SwSetExpField::PutValue( const uno::Any& rAny, 
sal_uInt16 nWhichId )
                 if (static_cast<SwSetExpFieldType*>(GetTyp())->GetType()
                         & nsSwGetSetExpType::GSE_STRING)
                 {
-                    SwXTextField::TransmuteLeadToInputField(*this);
+                    SwXTextField::TransmuteLeadToInputField(*this, nullptr);
                 }
                 else
                 {
diff --git a/sw/source/core/inc/unofield.hxx b/sw/source/core/inc/unofield.hxx
index 55214020c038..313185a0001b 100644
--- a/sw/source/core/inc/unofield.hxx
+++ b/sw/source/core/inc/unofield.hxx
@@ -133,7 +133,7 @@ private:
 public:
     SwServiceType GetServiceId() const;
 
-    static void TransmuteLeadToInputField(SwSetExpField & rField);
+    static void TransmuteLeadToInputField(SwSetExpField & rField, sal_uInt16 
const*const pSubType);
 
     /// @return an SwXTextField, either an already existing one or a new one
     static rtl::Reference<SwXTextField>
diff --git a/sw/source/core/unocore/unofield.cxx 
b/sw/source/core/unocore/unofield.cxx
index d73c0b59b34e..b3452890e0d2 100644
--- a/sw/source/core/unocore/unofield.cxx
+++ b/sw/source/core/unocore/unofield.cxx
@@ -1238,20 +1238,34 @@ SwServiceType SwXTextField::GetServiceId() const
     it has to be disconnected first and at the end connected to the
     new instance!
  */
-void SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField)
-{
-    assert(rField.GetFormatField()->Which() == (rField.GetInputFlag() ? 
RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD));
+void SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField,
+        sal_uInt16 const*const pSubType)
+{
+#ifndef NDEBUG
+    auto const oldWhich(
+        (pSubType ? (rField.GetSubType() & nsSwGetSetExpType::GSE_STRING) != 0 
: rField.GetInputFlag())
+            ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD);
+    auto const newWhich(oldWhich == RES_TXTATR_FIELD ? RES_TXTATR_INPUTFIELD : 
RES_TXTATR_FIELD);
+#endif
+    assert(rField.GetFormatField()->Which() == oldWhich);
     rtl::Reference<SwXTextField> const pXField(
         rField.GetFormatField()->GetXTextField());
     if (pXField)
         pXField->m_pImpl->SetFormatField(nullptr, nullptr);
     SwTextField *const pOldAttr(rField.GetFormatField()->GetTextField());
     SwSetExpField tempField(rField);
-    tempField.SetInputFlag(!rField.GetInputFlag());
+    if (pSubType)
+    {
+        tempField.SetSubType(*pSubType);
+    }
+    else
+    {
+        tempField.SetInputFlag(!rField.GetInputFlag());
+    }
     SwFormatField tempFormat(tempField);
     assert(tempFormat.GetField() != &rField);
     assert(tempFormat.GetField() != &tempField); // this copies it again?
-    assert(tempFormat.Which() == (static_cast<SwSetExpField 
const*>(tempFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : 
RES_TXTATR_FIELD));
+    assert(tempFormat.Which() == newWhich);
     SwTextNode & rNode(pOldAttr->GetTextNode());
     std::shared_ptr<SwPaM> pPamForTextField;
     IDocumentContentOperations & 
rIDCO(rNode.GetDoc().getIDocumentContentOperations());
@@ -1266,8 +1280,10 @@ void 
SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField)
     SwTextField const* pNewAttr(rNode.GetFieldTextAttrAt(nStart, 
::sw::GetTextAttrMode::Default));
     assert(pNewAttr);
     SwFormatField const& rNewFormat(pNewAttr->GetFormatField());
-    assert(rNewFormat.Which() == (static_cast<SwSetExpField 
const*>(rNewFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : 
RES_TXTATR_FIELD));
-    assert(static_cast<SwSetExpField 
const*>(rNewFormat.GetField())->GetInputFlag() == 
(dynamic_cast<SwTextInputField const*>(pNewAttr) != nullptr));
+    assert(rNewFormat.Which() == newWhich);
+    assert((dynamic_cast<SwTextInputField const*>(pNewAttr) != nullptr)
+        == ((static_cast<SwSetExpField 
const*>(rNewFormat.GetField())->GetSubType() & nsSwGetSetExpType::GSE_STRING)
+            && static_cast<SwSetExpField 
const*>(rNewFormat.GetField())->GetInputFlag()));
     if (pXField)
     {
         
pXField->m_pImpl->SetFormatField(const_cast<SwFormatField*>(&rNewFormat), 
&rNode.GetDoc());
commit 4beb8f34b18d80a2f4b42ebed9ed08b4eaf11403
Author:     Michael Stahl <[email protected]>
AuthorDate: Thu Feb 1 11:20:18 2024 +0100
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:27 2024 +0100

    check that rtl_random_getBytes() was successful
    
    ... everywhere it is used to generate material for encryption.
    
    Change-Id: Id3390376bb2f3a5fa1bbfd735850fce886ef7db2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162873
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit b85c2459ced6a41915dbaf567613fb5e244a0ada)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162890
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/comphelper/source/misc/docpasswordhelper.cxx 
b/comphelper/source/misc/docpasswordhelper.cxx
index 0adb6eff9a4a..1f73bd8d7026 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -427,7 +427,10 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
     uno::Sequence< sal_Int8 > aResult( nLength );
 
     rtlRandomPool aRandomPool = rtl_random_createPool ();
-    rtl_random_getBytes ( aRandomPool, aResult.getArray(), nLength );
+    if (rtl_random_getBytes(aRandomPool, aResult.getArray(), nLength) != 
rtl_Random_E_None)
+    {
+        throw uno::RuntimeException("rtl_random_getBytes failed");
+    }
     rtl_random_destroyPool ( aRandomPool );
 
     return aResult;
diff --git a/comphelper/source/misc/storagehelper.cxx 
b/comphelper/source/misc/storagehelper.cxx
index 9d3dbcd22732..c190d099ea00 100644
--- a/comphelper/source/misc/storagehelper.cxx
+++ b/comphelper/source/misc/storagehelper.cxx
@@ -446,7 +446,10 @@ uno::Sequence< beans::NamedValue > 
OStorageHelper::CreateGpgPackageEncryptionDat
 
     // get 32 random chars out of it
     uno::Sequence < sal_Int8 > aVector(32);
-    rtl_random_getBytes( aRandomPool, aVector.getArray(), aVector.getLength() 
);
+    if (rtl_random_getBytes(aRandomPool, aVector.getArray(), 
aVector.getLength()) != rtl_Random_E_None)
+    {
+        throw uno::RuntimeException("rtl_random_getBytes failed");
+    }
 
     rtl_random_destroyPool(aRandomPool);
 
diff --git a/oox/source/crypto/Standard2007Engine.cxx 
b/oox/source/crypto/Standard2007Engine.cxx
index b588fc5c8fd0..9fe18ad17e0c 100644
--- a/oox/source/crypto/Standard2007Engine.cxx
+++ b/oox/source/crypto/Standard2007Engine.cxx
@@ -28,7 +28,10 @@ namespace
 void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
 {
     rtlRandomPool aRandomPool = rtl_random_createPool();
-    rtl_random_getBytes(aRandomPool, aArray, aSize);
+    if (rtl_random_getBytes(aRandomPool, aArray, aSize) != rtl_Random_E_None)
+    {
+        throw css::uno::RuntimeException("rtl_random_getBytes failed");
+    }
     rtl_random_destroyPool(aRandomPool);
 }
 
diff --git a/package/source/zippackage/ZipPackageStream.cxx 
b/package/source/zippackage/ZipPackageStream.cxx
index d3068a666519..a5d4a0f7ce3d 100644
--- a/package/source/zippackage/ZipPackageStream.cxx
+++ b/package/source/zippackage/ZipPackageStream.cxx
@@ -592,8 +592,14 @@ bool ZipPackageStream::saveChild(
                 uno::Sequence<sal_Int8> aSalt(16);
                 // note: for GCM it's particularly important that IV is unique
                 uno::Sequence<sal_Int8> aVector(GetIVSize());
-                rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 );
-                rtl_random_getBytes ( rRandomPool, aVector.getArray(), 
aVector.getLength() );
+                if (rtl_random_getBytes(rRandomPool, aSalt.getArray(), 16) != 
rtl_Random_E_None)
+                {
+                    throw uno::RuntimeException("rtl_random_getBytes failed");
+                }
+                if (rtl_random_getBytes(rRandomPool, aVector.getArray(), 
aVector.getLength()) != rtl_Random_E_None)
+                {
+                    throw uno::RuntimeException("rtl_random_getBytes failed");
+                }
                 if ( !m_bHaveOwnKey )
                 {
                     m_aEncryptionKey = rEncryptionKey;
diff --git a/sc/source/filter/excel/xeroot.cxx 
b/sc/source/filter/excel/xeroot.cxx
index ce281890f837..c1959767d97d 100644
--- a/sc/source/filter/excel/xeroot.cxx
+++ b/sc/source/filter/excel/xeroot.cxx
@@ -317,8 +317,10 @@ uno::Sequence< beans::NamedValue > 
XclExpRoot::GenerateEncryptionData( std::u16s
     {
         rtlRandomPool aRandomPool = rtl_random_createPool ();
         sal_uInt8 pnDocId[16];
-        rtl_random_getBytes( aRandomPool, pnDocId, 16 );
-
+        if (rtl_random_getBytes(aRandomPool, pnDocId, 16) != rtl_Random_E_None)
+        {
+            throw uno::RuntimeException("rtl_random_getBytes failed");
+        }
         rtl_random_destroyPool( aRandomPool );
 
         sal_uInt16 pnPasswd[16] = {};
diff --git a/sc/source/filter/excel/xestream.cxx 
b/sc/source/filter/excel/xestream.cxx
index 4158fa2c153d..a70e4e08bd71 100644
--- a/sc/source/filter/excel/xestream.cxx
+++ b/sc/source/filter/excel/xestream.cxx
@@ -564,7 +564,10 @@ void XclExpBiff8Encrypter::Init( const Sequence< 
NamedValue >& rEncryptionData )
 
     // generate the salt here
     rtlRandomPool aRandomPool = rtl_random_createPool ();
-    rtl_random_getBytes( aRandomPool, mpnSalt, 16 );
+    if (rtl_random_getBytes(aRandomPool, mpnSalt, 16) != rtl_Random_E_None)
+    {
+        throw uno::RuntimeException("rtl_random_getBytes failed");
+    }
     rtl_random_destroyPool( aRandomPool );
 
     memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) );
diff --git a/svl/source/passwordcontainer/passwordcontainer.cxx 
b/svl/source/passwordcontainer/passwordcontainer.cxx
index 333e2921b493..90b27c29f7b0 100644
--- a/svl/source/passwordcontainer/passwordcontainer.cxx
+++ b/svl/source/passwordcontainer/passwordcontainer.cxx
@@ -654,7 +654,10 @@ OUString PasswordContainer::createIV()
 {
     rtlRandomPool randomPool = mRandomPool.get();
     unsigned char iv[RTL_DIGEST_LENGTH_MD5];
-    rtl_random_getBytes(randomPool, iv, RTL_DIGEST_LENGTH_MD5);
+    if (rtl_random_getBytes(randomPool, iv, RTL_DIGEST_LENGTH_MD5) != 
rtl_Random_E_None)
+    {
+        throw uno::RuntimeException("rtl_random_getBytes failed");
+    }
     OUStringBuffer aBuffer;
     for (sal_uInt8 i : iv)
     {
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index 38fbfb21666a..74e9d27c09ea 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -3517,8 +3517,10 @@ bool SwWW8Writer::InitStd97CodecUpdateMedium( 
::msfilter::MSCodec_Std97& rCodec
                 // Generate random number with a seed of time as salt.
                 rtlRandomPool aRandomPool = rtl_random_createPool ();
                 sal_uInt8 pDocId[ 16 ];
-                rtl_random_getBytes( aRandomPool, pDocId, 16 );
-
+                if (rtl_random_getBytes(aRandomPool, pDocId, 16) != 
rtl_Random_E_None)
+                {
+                    throw uno::RuntimeException("rtl_random_getBytes failed");
+                }
                 rtl_random_destroyPool( aRandomPool );
 
                 sal_uInt16 aPassword[16] = {};
diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx
index c36097898495..10ccaa487816 100644
--- a/sw/source/filter/ww8/ww8par.cxx
+++ b/sw/source/filter/ww8/ww8par.cxx
@@ -5664,8 +5664,10 @@ namespace
 
                 rtlRandomPool aRandomPool = rtl_random_createPool();
                 sal_uInt8 pDocId[ 16 ];
-                rtl_random_getBytes( aRandomPool, pDocId, 16 );
-
+                if (rtl_random_getBytes(aRandomPool, pDocId, 16) != 
rtl_Random_E_None)
+                {
+                    throw uno::RuntimeException("rtl_random_getBytes failed");
+                }
                 rtl_random_destroyPool( aRandomPool );
 
                 sal_uInt16 pStd97Pass[16] = {};
diff --git a/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx 
b/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx
index c3bbfdb0f2ef..e5f2a89d113d 100644
--- a/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx
+++ b/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx
@@ -326,7 +326,10 @@ uno::Sequence< ::sal_Int8 > SAL_CALL 
OCipherContext::finalizeCipherContextAndDis
         if ( nPaddingSize > 1 )
         {
             rtlRandomPool aRandomPool = rtl_random_createPool();
-            rtl_random_getBytes( aRandomPool, pLastBlock + nOldLastBlockLen, 
nPaddingSize - 1 );
+            if (rtl_random_getBytes(aRandomPool, pLastBlock + 
nOldLastBlockLen, nPaddingSize - 1) != rtl_Random_E_None)
+            {
+                throw uno::RuntimeException("rtl_random_getBytes failed");
+            }
             rtl_random_destroyPool ( aRandomPool );
         }
         pLastBlock[m_aLastBlock.getLength() - 1] = static_cast< sal_Int8 >( 
nPaddingSize );
commit a77fa2be1e0d8c22198a3a45153bb25ecf3135dd
Author:     Michael Stahl <[email protected]>
AuthorDate: Thu Feb 1 12:53:07 2024 +0100
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:26 2024 +0100

    writerfilter: fix missing paragraph break on tdf136445-1.rtf
    
    This causes an assert:
    crossrefbookmark.cxx:44: sw::mark::CrossRefBookmark::CrossRefBookmark(): 
Assertion `IDocumentMarkAccess::IsLegalPaMForCrossRefHeadingBookmark(rPaM) && 
"<CrossRefBookmark::CrossRefBookmark(..)>" "- creation of cross-reference 
bookmark with an illegal PaM that does not expand over exactly one whole 
paragraph."' failed.
    
    The problem is that there is an annotation at the end of a paragraph,
    and reading the annotation changes various members of DomainMapper_Impl,
    in particular m_bParaSectpr and m_bParaChanged, causing "bRemove" in
    DomainMapper::lcl_utext() to be erroneously true, removing the just
    inserted paragraph break again.
    
    Move all flags that are evaluated for bRemove to SubstreamContext.
    
    This causes one test failure, but it turns out that the new result is
    the same as in Word 2013.
    
      Test name: (anonymous namespace)::testTdf108947::TestBody
      equality assertion failed
      - Expected: Header Page 2 ?
      - Actual  :
      Header Page 2 ?
    
    (regression from commit 15b886f460919ea3dce425a621dc017c2992a96b)
    
    Change-Id: I44a7a8928ab04c600d4d3c43bc4e4deeafe57d89
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162932
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 86ad08f9d25110e91e92a0badf6de75e785b3644)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162936
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sw/qa/extras/rtfexport/data/tdf136445-1-min.rtf 
b/sw/qa/extras/rtfexport/data/tdf136445-1-min.rtf
new file mode 100644
index 000000000000..c0abd0d293be
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf136445-1-min.rtf
@@ -0,0 +1,17 @@
+{ tf1
+{\*\listtable
+{\list\listtemplateid8
+{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext 
\'02E\'00;}{\levelnumbers\'02;}i-720\li720}\listid8}
+}
+{\listoverridetable{\listoverride\listid8\listoverridecount0\ls8}}
+
+\ltrpar \sectd
+\pard\plain \ltrpar{ tlch\hich \ltrch\loch
+I ax xoixx xuxixx xxe xixxx. (Xaxxexx 1989 x.x. xaxax a)}{ tlch\hich 
\ltrch\loch
+{\*tnid CL}{\*tnauthor Christian}+sic!}}}
+\par \pard\plain {\listtext\pard\plain  E119   ab}\ilvl0\ls8 \li720 i0\lin720 
in0i-720\ql\ltrpar{{\*kmkstart __RefNumPara__395941_134077278}{\*kmkend 
__RefNumPara__395941_134077278} tlch\hich \ltrch\loch
+Xix    ab xaxa ab x-a  ab      ab      ab xix  ab }{ tlch\hich 
\ltrch\langfe0\dbch\loch\lang255\loch
+x xi = xa.}
+\par
+}
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index 167539197051..08ca8452f928 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -109,6 +109,20 @@ DECLARE_RTFEXPORT_TEST(testTdf158586_lostFrame, 
"tdf158586_lostFrame.rtf")
     CPPUNIT_ASSERT_EQUAL(2, getPages());
 }
 
+DECLARE_RTFEXPORT_TEST(testAnnotationPar, "tdf136445-1-min.rtf")
+{
+    // the problem was that the paragraph break following annotation was 
missing
+    CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
+    CPPUNIT_ASSERT_EQUAL(
+        OUString("Annotation"),
+        getProperty<OUString>(
+            getRun(getParagraph(1, "I ax xoixx xuxixx xxe xixxx. (Xaxxexx 1989 
x.x. xaxax a)"), 2),
+            "TextPortionType"));
+    CPPUNIT_ASSERT(
+        !getProperty<OUString>(getParagraph(2, "Xix    xaxa    x-a             
        xix     x xi = xa."), "ListId")
+             .isEmpty());
+}
+
 DECLARE_RTFEXPORT_TEST(testTdf158826_extraCR, "tdf158826_extraCR.rtf")
 {
     // Note: this is a hand-minimized sample, and very likely doesn't follow 
RTF { } rules...
diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx 
b/sw/qa/extras/rtfimport/rtfimport.cxx
index 3d516a004218..1a6d1c9772ea 100644
--- a/sw/qa/extras/rtfimport/rtfimport.cxx
+++ b/sw/qa/extras/rtfimport/rtfimport.cxx
@@ -1568,7 +1568,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf108947)
     uno::Reference<text::XText> xHeaderTextLeft = 
getProperty<uno::Reference<text::XText>>(
         getStyles("PageStyles")->getByName("Default Page Style"), 
"HeaderTextLeft");
     aActual = xHeaderTextLeft->getString();
-    CPPUNIT_ASSERT_EQUAL(OUString("Header Page 2 ?"), aActual);
+    CPPUNIT_ASSERT_EQUAL(OUString(SAL_NEWLINE_STRING "Header Page 2 ?"), 
aActual);
 #endif
 }
 
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 31448f77b596..4780df543d2c 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -370,15 +370,9 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bIsParaMarkerChange( false ),
         m_bIsParaMarkerMove( false ),
         m_bRedlineImageInPreviousRun( false ),
-        m_bParaChanged( false ),
-        m_bIsFirstParaInSection( true ),
-        m_bIsFirstParaInSectionAfterRedline( true ),
         m_bDummyParaAddedForTableInSection( false ),
         m_bTextFrameInserted(false),
-        m_bIsPreviousParagraphFramed( false ),
-        m_bIsLastParaInSection( false ),
         m_bIsLastSectionGroup( false ),
-        m_bParaSectpr( false ),
         m_bUsingEnhancedFields( false ),
         m_bSdt(false),
         m_bIsFirstRun(false),
@@ -399,7 +393,6 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bIsSplitPara(false),
         m_bIsActualParagraphFramed( false ),
         m_bParaAutoBefore(false),
-        m_bParaWithInlineObject(false),
         m_bSaxError(false)
 {
     m_StreamStateStack.emplace(); // add state for document body
@@ -936,25 +929,27 @@ void DomainMapper_Impl::SetIsLastSectionGroup( bool 
bIsLast )
 
 void DomainMapper_Impl::SetIsLastParagraphInSection( bool bIsLast )
 {
-    m_bIsLastParaInSection = bIsLast;
+    m_StreamStateStack.top().bIsLastParaInSection = bIsLast;
 }
 
 
 void DomainMapper_Impl::SetIsFirstParagraphInSection( bool bIsFirst )
 {
-    m_bIsFirstParaInSection = bIsFirst;
+    m_StreamStateStack.top().bIsFirstParaInSection = bIsFirst;
 }
 
 void DomainMapper_Impl::SetIsFirstParagraphInSectionAfterRedline( bool 
bIsFirstAfterRedline )
 {
-    m_bIsFirstParaInSectionAfterRedline = bIsFirstAfterRedline;
+    m_StreamStateStack.top().bIsFirstParaInSectionAfterRedline = 
bIsFirstAfterRedline;
 }
 
 bool DomainMapper_Impl::GetIsFirstParagraphInSection( bool bAfterRedline ) 
const
 {
     // Anchored objects may include multiple paragraphs,
     // and none of them should be considered the first para in section.
-    return ( bAfterRedline ? m_bIsFirstParaInSectionAfterRedline : 
m_bIsFirstParaInSection )
+    return (bAfterRedline
+                    ? 
m_StreamStateStack.top().bIsFirstParaInSectionAfterRedline
+                    : m_StreamStateStack.top().bIsFirstParaInSection)
                 && !IsInShape()
                 && !IsInComments()
                 && !IsInFootOrEndnote();
@@ -976,13 +971,11 @@ void DomainMapper_Impl::SetIsTextFrameInserted( bool 
bIsInserted )
     m_bTextFrameInserted  = bIsInserted;
 }
 
-
 void DomainMapper_Impl::SetParaSectpr(bool bParaSectpr)
 {
-    m_bParaSectpr = bParaSectpr;
+    m_StreamStateStack.top().bParaSectpr = bParaSectpr;
 }
 
-
 void DomainMapper_Impl::SetSdt(bool bSdt)
 {
     m_bSdt = bSdt;
@@ -2830,7 +2823,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
 
                     xCur->goLeft( 1 , true );
                     // Extend the redline ranges for empty paragraphs
-                    if ( !m_bParaChanged && m_previousRedline )
+                    if (!m_StreamStateStack.top().bParaChanged && 
m_previousRedline)
                         CreateRedline( xCur, m_previousRedline );
                     CheckParaMarkerRedline( xCur );
                 }
@@ -2974,21 +2967,21 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
     else
         SetIsPreviousParagraphFramed(false);
 
-    m_bRemoveThisParagraph = false;
+    m_StreamStateStack.top().bRemoveThisParagraph = false;
     if( !IsInHeaderFooter() && !IsInShape()
         && (!pParaContext || !pParaContext->props().IsFrameMode()) )
     { // If the paragraph is in a frame, shape or header/footer, it's not a 
paragraph of the section itself.
         SetIsFirstParagraphInSection(false);
         // don't count an empty deleted paragraph as first paragraph in 
section to avoid of
         // the deletion of the next empty paragraph later, resulting loss of 
the associated page break
-        if (!m_previousRedline || m_bParaChanged)
+        if (!m_previousRedline || m_StreamStateStack.top().bParaChanged)
         {
             SetIsFirstParagraphInSectionAfterRedline(false);
             SetIsLastParagraphInSection(false);
         }
     }
     m_previousRedline.clear();
-    m_bParaChanged = false;
+    m_StreamStateStack.top().bParaChanged = false;
 
     if (IsInComments() && pParaContext)
     {
@@ -3025,7 +3018,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
     }
 
     m_bParaAutoBefore = false;
-    m_bParaWithInlineObject = false;
+    m_StreamStateStack.top().bParaWithInlineObject = false;
 
 #ifdef DBG_UTIL
     TagLogger::getInstance().endElement();
@@ -3305,7 +3298,7 @@ void DomainMapper_Impl::applyToggleAttributes(const 
PropertyMapPtr& pPropertyMap
             m_pParaMarkerRedlineMove.clear();
         }
         CheckRedline( xTextRange );
-        m_bParaChanged = true;
+        m_StreamStateStack.top().bParaChanged = true;
 
         //getTableManager( ).handle(xTextRange);
     }
@@ -4164,7 +4157,8 @@ void DomainMapper_Impl::CheckRedline( uno::Reference< 
text::XTextRange > const&
 
     // only export ParagraphFormat, when there is no other redline in the same 
text portion to avoid missing redline compression,
     // but always export the first ParagraphFormat redline in a paragraph to 
keep the paragraph style change data for rejection
-    if( (!bUsedRange || !m_bParaChanged) && 
GetTopContextOfType(CONTEXT_PARAGRAPH) )
+    if ((!bUsedRange || !m_StreamStateStack.top().bParaChanged)
+        && GetTopContextOfType(CONTEXT_PARAGRAPH))
     {
         std::vector<RedlineParamsPtr>& avRedLines = 
GetTopContextOfType(CONTEXT_PARAGRAPH)->Redlines();
         for( const auto& rRedline : avRedLines )
@@ -4809,7 +4803,7 @@ void DomainMapper_Impl::PushShapeContext( const 
uno::Reference< drawing::XShape
                         getPropertyName( PROP_OPAQUE ),
                         uno::Any( true ) );
         }
-        m_bParaChanged = true;
+        m_StreamStateStack.top().bParaChanged = true;
         getTableManager().setIsInShape(true);
     }
     catch ( const uno::Exception& )
@@ -6792,15 +6786,15 @@ OUString DomainMapper_Impl::extractTocTitle()
 css::uno::Reference<css::beans::XPropertySet>
 DomainMapper_Impl::StartIndexSectionChecked(const OUString& sServiceName)
 {
-    if (m_bParaChanged)
+    if (m_StreamStateStack.top().bParaChanged)
     {
-        finishParagraph(GetTopContextOfType(CONTEXT_PARAGRAPH), false); // 
resets m_bParaChanged
+        finishParagraph(GetTopContextOfType(CONTEXT_PARAGRAPH), false); // 
resets bParaChanged
         PopProperties(CONTEXT_PARAGRAPH);
         PushProperties(CONTEXT_PARAGRAPH);
         SetIsFirstRun(true);
         // The first paragraph of the index that is continuation of just 
finished one needs to be
-        // removed when finished (unless more content will arrive, which will 
set m_bParaChanged)
-        m_bRemoveThisParagraph = true;
+        // removed when finished (unless more content will arrive, which will 
set bParaChanged)
+        m_StreamStateStack.top().bRemoveThisParagraph = true;
     }
     const auto& xTextAppend = GetTopTextAppend();
     const auto xTextRange = xTextAppend->getEnd();
@@ -8625,7 +8619,7 @@ void DomainMapper_Impl::PopFieldContext()
                     if (m_bStartedTOC || m_bStartIndex || m_bStartBibliography)
                     {
                         // inside SDT, last empty paragraph is also part of 
index
-                        if (!m_bParaChanged && !m_xSdtEntryStart)
+                        if (!m_StreamStateStack.top().bParaChanged && 
!m_xSdtEntryStart)
                         {
                             // End of index is the first item on a new 
paragraph - this paragraph
                             // should not be part of index
@@ -8651,7 +8645,7 @@ void DomainMapper_Impl::PopFieldContext()
                         m_bStartedTOC = false;
                         m_aTextAppendStack.pop();
                         m_StreamStateStack.top().bTextInserted = false;
-                        m_bParaChanged = true; // the paragraph must stay 
anyway
+                        m_StreamStateStack.top().bParaChanged = true; // the 
paragraph must stay anyway
                     }
                     m_bStartTOC = false;
                     m_bStartIndex = false;
@@ -9248,7 +9242,7 @@ void  DomainMapper_Impl::ImportGraphic(const 
writerfilter::Reference<Properties>
         }
         else if (m_eGraphicImportType == IMPORT_AS_DETECTED_INLINE)
         {
-            m_bParaWithInlineObject = true;
+            m_StreamStateStack.top().bParaWithInlineObject = true;
 
             // store inline images with track changes, because the anchor point
             // to set redlining is not available yet
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 3417147a92f3..708855e41fb6 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -177,14 +177,26 @@ struct SubstreamContext
      * inTbl SPRM or not).
      */
     sal_Int32 nTableDepth = 0;
-    // deferred breaks need to be saved for RTF, probably not for DOCX
-    bool      bIsColumnBreakDeferred = false;
-    bool      bIsPageBreakDeferred = false;
+    // deferred breaks need to be saved for RTF, also for DOCX annotations
+    bool bIsColumnBreakDeferred = false;
+    bool bIsPageBreakDeferred = false;
     sal_Int32 nLineBreaksDeferred = 0;
     /// Current paragraph had at least one field in it.
-    bool      bParaHadField = false;
+    bool bParaHadField = false;
     /// Current paragraph in a table is first paragraph of a cell
-    bool      bFirstParagraphInCell = true;
+    bool bFirstParagraphInCell = true;
+    /// If the current paragraph has any runs.
+    bool bParaChanged = false;
+    bool bIsFirstParaInSectionAfterRedline = true;
+    bool bIsFirstParaInSection = true;
+    bool bIsLastParaInSection = false;
+    /// If the current paragraph contains section property definitions.
+    bool bParaSectpr = false;
+    bool bIsPreviousParagraphFramed = false;
+    /// Current paragraph had at least one inline object in it.
+    bool bParaWithInlineObject = false;
+    /// This is a continuation of already finished paragraph - e.g., first in 
an index section
+    bool bRemoveThisParagraph = false;
 };
 
 /// Information about a paragraph to be finished after a field end.
@@ -596,25 +608,15 @@ private:
     // text ZWSPs to keep the change tracking of the image in Writer.)
     bool                            m_bRedlineImageInPreviousRun;
 
-    /// If the current paragraph has any runs.
-    bool                            m_bParaChanged;
-    bool                            m_bIsFirstParaInSection;
-    bool                            m_bIsFirstParaInSectionAfterRedline;
     bool                            m_bIsFirstParaInShape = false;
     bool                            m_bDummyParaAddedForTableInSection;
     bool                            m_bTextFrameInserted;
-    bool                            m_bIsPreviousParagraphFramed;
-    bool                            m_bIsLastParaInSection;
     bool                            m_bIsLastSectionGroup;
-    /// If the current paragraph contains section property definitions.
-    bool                            m_bParaSectpr;
     bool                            m_bUsingEnhancedFields;
     /// If the current paragraph is inside a structured document element.
     bool                            m_bSdt;
     bool                            m_bIsFirstRun;
     bool                            m_bIsOutsideAParagraph;
-    /// This is a continuation of already finished paragraph - e.g., first in 
an index section
-    bool                            m_bRemoveThisParagraph = false;
 
     css::uno::Reference< css::text::XTextCursor > m_xTOCMarkerCursor;
 
@@ -713,7 +715,7 @@ public:
 
     void SetIsDecimalComma() { m_bIsDecimalComma = true; };
     void SetIsLastParagraphInSection( bool bIsLast );
-    bool GetIsLastParagraphInSection() const { return m_bIsLastParaInSection;}
+    bool GetIsLastParagraphInSection() const { return 
m_StreamStateStack.top().bIsLastParaInSection; }
     void SetRubySprmId( sal_uInt32 nSprmId) { m_aRubyInfo.nSprmId = nSprmId ; }
     void SetRubyText( OUString const &sText, OUString const &sStyle) {
         m_aRubyInfo.sRubyText = sText;
@@ -737,10 +739,11 @@ public:
     bool GetIsTextFrameInserted() const { return m_bTextFrameInserted;}
     void SetIsTextDeleted(bool bIsTextDeleted) { m_bTextDeleted = 
bIsTextDeleted; }
 
-    void SetIsPreviousParagraphFramed( bool bIsFramed ) { 
m_bIsPreviousParagraphFramed = bIsFramed; }
-    bool GetIsPreviousParagraphFramed() const { return 
m_bIsPreviousParagraphFramed; }
+    void SetIsPreviousParagraphFramed(bool const bIsFramed)
+    { m_StreamStateStack.top().bIsPreviousParagraphFramed = bIsFramed; }
+    bool GetIsPreviousParagraphFramed() const { return 
m_StreamStateStack.top().bIsPreviousParagraphFramed; }
     void SetParaSectpr(bool bParaSectpr);
-    bool GetParaSectpr() const { return m_bParaSectpr;}
+    bool GetParaSectpr() const { return m_StreamStateStack.top().bParaSectpr; }
 
     void SetSymbolChar( sal_Int32 nSymbol) { m_aSymbolData.cSymbol = 
sal_Unicode(nSymbol); }
     void SetSymbolFont( OUString const &rName ) { m_aSymbolData.sFont = rName; 
}
@@ -756,9 +759,9 @@ public:
 
     /// Getter method for m_bSdt.
     bool GetSdt() const { return m_bSdt;}
-    bool GetParaChanged() const { return m_bParaChanged;}
+    bool GetParaChanged() const { return 
m_StreamStateStack.top().bParaChanged; }
     bool GetParaHadField() const { return 
m_StreamStateStack.top().bParaHadField; }
-    bool GetRemoveThisPara() const { return m_bRemoveThisParagraph; }
+    bool GetRemoveThisPara() const { return 
m_StreamStateStack.top().bRemoveThisParagraph; }
 
     void deferBreak( BreakType deferredBreakType );
     bool isBreakDeferred( BreakType deferredBreakType );
@@ -1186,7 +1189,7 @@ public:
     bool m_bIsActualParagraphFramed;
     std::deque<css::uno::Any> m_aStoredRedlines[StoredRedlines::NONE];
 
-    bool IsParaWithInlineObject() const { return m_bParaWithInlineObject; }
+    bool IsParaWithInlineObject() const { return 
m_StreamStateStack.top().bParaWithInlineObject; }
 
     css::uno::Reference< css::embed::XStorage > m_xDocumentStorage;
 
@@ -1216,8 +1219,6 @@ private:
     css::uno::Reference<css::beans::XPropertySet> m_xPreviousParagraph;
     /// Current paragraph has automatic before spacing.
     bool m_bParaAutoBefore;
-    /// Current paragraph had at least one inline object in it.
-    bool m_bParaWithInlineObject;
     /// SAXException was seen so document will be abandoned
     bool m_bSaxError;
 
diff --git a/writerfilter/source/rtftok/rtfdispatchsymbol.cxx 
b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx
index 6c1c94b944d9..0f01d79f5cd4 100644
--- a/writerfilter/source/rtftok/rtfdispatchsymbol.cxx
+++ b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx
@@ -406,6 +406,8 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword 
nKeyword)
                 }
                 sal_uInt8 const sBreak[] = { 0xc };
                 Mapper().text(sBreak, 1);
+                // testFdo81892 don't do another \par break directly; because 
of
+                // GetSplitPgBreakAndParaMark() it does finishParagraph *twice*
                 m_bNeedCr = true;
             }
         }
commit 0ee5143f1bfbe71133d90dc984a0709af0551fb9
Author:     Michael Stahl <[email protected]>
AuthorDate: Wed Jan 31 14:47:22 2024 +0100
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:26 2024 +0100

    writerfilter: move members to SubstreamContext
    
    writerfilter: move m_bParaHadField to SubstreamContext
    
    Change-Id: Ie15e35d304a423bfa3d7b7ead71015d5ec1228d4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162839
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 4913812baeabd44b46302e54b73a227e760c688a)
    
    writerfilter: use SubstreamContext for all substreams
    
    <vmiklos> possibly just nobody needed that so far. could be some more
    general SubstreamContext, i don't see an obvious problem reusing that at
    more places.
    
    Change-Id: If0749155452f65f8dfc4ac2b10f91bb8e48a6b2b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162840
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 95b01848b18283fd2f903c982108ccdb8efee022)
    
    writerfilter: move m_bFirstParagraphInCell to SubstreamContext
    
    This is a change to set it for all substreams.
    
    Change-Id: I44ed9a5485000f40f8ccfe3ec885ef8f05f5aab2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162841
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 30323c813977eb0127251848fecd2532dce75749)
    
    writerfilter: replace members w/ SubstreamContext::eSubstreamType
    
    This should not change any behaviour.
    
    Change-Id: Ic970f0e1b6401119d875c9e811589b9c210e0c34
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162842
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 992f7114ab8645fb5b7a22b5f974a95fe7be7712)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162933
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 6909e3925846..31448f77b596 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -357,10 +357,7 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bInStyleSheetImport( false ),
         m_bInNumberingImport(false),
         m_bInAnyTableImport( false ),
-        m_eInHeaderFooterImport( HeaderFooterImportState::none ),
         m_bDiscardHeaderFooter( false ),
-        m_bInFootOrEndnote(false),
-        m_bInFootnote(false),
         m_bHasFootnoteStyle(false),
         m_bCheckFootnoteStyle(false),
         m_eSkipFootnoteState(SkipFootnoteSeparator::OFF),
@@ -381,7 +378,6 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bIsPreviousParagraphFramed( false ),
         m_bIsLastParaInSection( false ),
         m_bIsLastSectionGroup( false ),
-        m_bIsInComments( false ),
         m_bParaSectpr( false ),
         m_bUsingEnhancedFields( false ),
         m_bSdt(false),
@@ -402,11 +398,7 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bIgnoreNextTab(false),
         m_bIsSplitPara(false),
         m_bIsActualParagraphFramed( false ),
-        m_bParaHadField(false),
-        m_bSaveParaHadField(false),
         m_bParaAutoBefore(false),
-        m_bFirstParagraphInCell(true),
-        m_bSaveFirstParagraphInCell(false),
         m_bParaWithInlineObject(false),
         m_bSaxError(false)
 {
@@ -964,7 +956,7 @@ bool DomainMapper_Impl::GetIsFirstParagraphInSection( bool 
bAfterRedline ) const
     // and none of them should be considered the first para in section.
     return ( bAfterRedline ? m_bIsFirstParaInSectionAfterRedline : 
m_bIsFirstParaInSection )
                 && !IsInShape()
-                && !m_bIsInComments
+                && !IsInComments()
                 && !IsInFootOrEndnote();
 }
 
@@ -2361,7 +2353,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
         {
             if ( GetIsFirstParagraphInShape() ||
                  (GetIsFirstParagraphInSection() && GetSectionContext() && 
GetSectionContext()->IsFirstSection()) ||
-                (m_bFirstParagraphInCell
+                (m_StreamStateStack.top().bFirstParagraphInCell
                  && 0 < m_StreamStateStack.top().nTableDepth
                  && m_StreamStateStack.top().nTableDepth == m_nTableCellDepth))
             {
@@ -2616,7 +2608,8 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
                 else
                 {
                     uno::Reference<text::XTextCursor> xCursor;
-                    if (m_bParaHadField && !m_bIsInComments && 
!m_xTOCMarkerCursor.is())
+                    if (m_StreamStateStack.top().bParaHadField
+                        && !IsInComments() && !m_xTOCMarkerCursor.is())
                     {
                         // Workaround to make sure char props of the field are 
not lost.
                         // Not relevant for editeng-based comments.
@@ -2658,9 +2651,10 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
                                 TOOLS_WARN_EXCEPTION("writerfilter", 
"DomainMapper_Impl::finishParagraph NumberingRules");
                             }
                         }
-                        else if ( 
m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("NumberingStyleName")
 &&
+                        else if 
(m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("NumberingStyleName")
                                 // don't update before tables
-                                (m_StreamStateStack.top().nTableDepth == 0 || 
!m_bFirstParagraphInCell))
+                            && (m_StreamStateStack.top().nTableDepth == 0
+                                || 
!m_StreamStateStack.top().bFirstParagraphInCell))
                         {
                             aCurrentNumberingName = GetListStyleName(nListId);
                             
m_xPreviousParagraph->getPropertyValue("NumberingStyleName") >>= 
aPreviousNumberingName;
@@ -2844,7 +2838,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
                 css::uno::Reference<css::beans::XPropertySet> 
xParaProps(xTextRange, uno::UNO_QUERY);
 
                 // table style precedence and not hidden shapes anchored to 
hidden empty table paragraphs
-                if (xParaProps && !m_bIsInComments
+                if (xParaProps && !IsInComments()
                     && (0 < m_StreamStateStack.top().nTableDepth
                         || !m_aAnchoredObjectAnchors.empty()))
                 {
@@ -2996,7 +2990,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
     m_previousRedline.clear();
     m_bParaChanged = false;
 
-    if (m_bIsInComments && pParaContext)
+    if (IsInComments() && pParaContext)
     {
         if (const OUString sParaId = pParaContext->props().GetParaId(); 
!sParaId.isEmpty())
         {
@@ -3019,15 +3013,15 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
     }
 
     SetIsOutsideAParagraph(true);
-    m_bParaHadField = false;
+    m_StreamStateStack.top().bParaHadField = false;
 
     // don't overwrite m_bFirstParagraphInCell in table separator nodes
     // and in text boxes anchored to the first paragraph of table cells
     if (0 < m_StreamStateStack.top().nTableDepth
         && m_StreamStateStack.top().nTableDepth == m_nTableCellDepth
-        && !IsInShape() && !m_bIsInComments)
+        && !IsInShape() && !IsInComments())
     {
-        m_bFirstParagraphInCell = false;
+        m_StreamStateStack.top().bFirstParagraphInCell = false;
     }
 
     m_bParaAutoBefore = false;
@@ -3199,7 +3193,7 @@ void DomainMapper_Impl::applyToggleAttributes(const 
PropertyMapPtr& pPropertyMap
     {
         applyToggleAttributes(pPropertyMap);
         // If we are in comments, then disable CharGrabBag, comment text 
doesn't support that.
-        uno::Sequence< beans::PropertyValue > aValues = 
pPropertyMap->GetPropertyValues(/*bCharGrabBag=*/!m_bIsInComments);
+        uno::Sequence<beans::PropertyValue> aValues = 
pPropertyMap->GetPropertyValues(/*bCharGrabBag=*/!IsInComments());
 
         if (IsInTOC() || m_bStartIndex || m_bStartBibliography)
             for( auto& rValue : asNonConstRange(aValues) )
@@ -3791,9 +3785,6 @@ bool isContentEmpty(uno::Reference<text::XText> const& 
xText, uno::Reference<tex
 
 void DomainMapper_Impl::PushPageHeaderFooter(PagePartType ePagePartType, 
PageType eType)
 {
-    m_bSaveParaHadField = m_bParaHadField;
-    m_StreamStateStack.emplace();
-
     bool bHeader = ePagePartType == PagePartType::Header;
 
     const PropertyIds ePropIsOn = bHeader ? PROP_HEADER_IS_ON: 
PROP_FOOTER_IS_ON;
@@ -3803,7 +3794,7 @@ void DomainMapper_Impl::PushPageHeaderFooter(PagePartType 
ePagePartType, PageTyp
     const PropertyIds ePropTextRight = bHeader ? PROP_HEADER_TEXT: 
PROP_FOOTER_TEXT;
 
     m_bDiscardHeaderFooter = true;
-    m_eInHeaderFooterImport = bHeader ? HeaderFooterImportState::header : 
HeaderFooterImportState::footer;
+    m_StreamStateStack.top().eSubstreamType = bHeader ? SubstreamType::Header 
: SubstreamType::Footer;
 
     //get the section context
     SectionPropertyMap* pSectionContext = GetSectionContext();;
@@ -3961,21 +3952,13 @@ void 
DomainMapper_Impl::PopPageHeaderFooter(PagePartType ePagePartType, PageType
         }
         m_bDiscardHeaderFooter = false;
     }
-    m_eInHeaderFooterImport = HeaderFooterImportState::none;
-
-    assert(!m_StreamStateStack.empty());
-    m_StreamStateStack.pop();
-
-    m_bParaHadField = m_bSaveParaHadField;
 }
 
 void DomainMapper_Impl::PushFootOrEndnote( bool bIsFootnote )
 {
-    SAL_WARN_IF(m_bInFootOrEndnote, "writerfilter.dmapper", 
"PushFootOrEndnote() is called from another foot or endnote");
-    m_bInFootOrEndnote = true;
-    m_bInFootnote = bIsFootnote;
+    SAL_WARN_IF(m_StreamStateStack.top().eSubstreamType != 
SubstreamType::Body, "writerfilter.dmapper", "PushFootOrEndnote() is called 
from another foot or endnote");
+    m_StreamStateStack.top().eSubstreamType = bIsFootnote ? 
SubstreamType::Footnote : SubstreamType::Endnote;
     m_bCheckFirstFootnoteTab = true;
-    m_bSaveFirstParagraphInCell = m_bFirstParagraphInCell;
     try
     {
         // Redlines outside the footnote should not affect footnote content
@@ -4240,7 +4223,7 @@ void DomainMapper_Impl::PushAnnotation()
 {
     try
     {
-        m_bIsInComments = true;
+        m_StreamStateStack.top().eSubstreamType = SubstreamType::Annotation;
         if (!GetTextFactory().is())
             return;
         m_xAnnotationField.set( GetTextFactory()->createInstance( 
"com.sun.star.text.TextField.Annotation" ),
@@ -4502,16 +4485,13 @@ void DomainMapper_Impl::PopFootOrEndnote()
     }
     m_aRedlines.pop();
     m_eSkipFootnoteState = SkipFootnoteSeparator::OFF;
-    m_bInFootOrEndnote = m_bInFootnote = false;
     m_pFootnoteContext = nullptr;
-    m_bFirstParagraphInCell = m_bSaveFirstParagraphInCell;
 }
 
 void DomainMapper_Impl::PopAnnotation()
 {
     RemoveLastParagraph();
 
-    m_bIsInComments = false;
     m_aTextAppendStack.pop();
 
     try
@@ -4991,7 +4971,7 @@ void DomainMapper_Impl::ClearPreviousParagraph()
     m_xPreviousParagraph.clear();
 
     // next table paragraph will be first paragraph in a cell
-    m_bFirstParagraphInCell = true;
+    m_StreamStateStack.top().bFirstParagraphInCell = true;
 }
 
 void DomainMapper_Impl::HandleAltChunk(const OUString& rStreamName)
@@ -5941,7 +5921,7 @@ uno::Reference<beans::XPropertySet> 
DomainMapper_Impl::FindOrCreateFieldMaster(c
 
 void DomainMapper_Impl::PushFieldContext()
 {
-    m_bParaHadField = true;
+    m_StreamStateStack.top().bParaHadField = true;
     if(m_bDiscardHeaderFooter)
         return;
 #ifdef DBG_UTIL
@@ -7054,7 +7034,7 @@ void DomainMapper_Impl::handleToc
 
     m_bStartTOC = true;
     pContext->SetTOC(xTOC);
-    m_bParaHadField = false;
+    m_StreamStateStack.top().bParaHadField = false;
 
     if (!xTOC)
         return;
@@ -7287,7 +7267,7 @@ void DomainMapper_Impl::handleBibliography
         xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), 
uno::Any(OUString()));
 
     pContext->SetTOC( xTOC );
-    m_bParaHadField = false;
+    m_StreamStateStack.top().bParaHadField = false;
 
     uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
     appendTextContent(xToInsert, uno::Sequence< beans::PropertyValue >() );
@@ -7330,7 +7310,7 @@ void DomainMapper_Impl::handleIndex
         }
     }
     pContext->SetTOC( xTOC );
-    m_bParaHadField = false;
+    m_StreamStateStack.top().bParaHadField = false;
 
     uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
     appendTextContent(xToInsert, uno::Sequence< beans::PropertyValue >() );
@@ -8348,7 +8328,7 @@ void DomainMapper_Impl::CloseFieldCommand()
                 }
             }
             else
-                m_bParaHadField = false;
+                m_StreamStateStack.top().bParaHadField = false;
         }
     }
     catch( const uno::Exception& )
@@ -8918,8 +8898,11 @@ void DomainMapper_Impl::StartOrEndBookmark( const 
OUString& rId )
                     // keep bookmark range, if it doesn't exceed cell boundary
                     uno::Reference< text::XTextRange > xStart = 
xCursor->getStart();
                     xCursor->goLeft( 1, false );
-                    if (m_StreamStateStack.top().nTableDepth == 0 || 
!m_bFirstParagraphInCell)
+                    if (m_StreamStateStack.top().nTableDepth == 0
+                        || !m_StreamStateStack.top().bFirstParagraphInCell)
+                    {
                         xCursor->gotoRange(xStart, true );
+                    }
                 }
                 uno::Reference< container::XNamed > xBkmNamed( xBookmark, 
uno::UNO_QUERY_THROW );
                 SAL_WARN_IF(aBookmarkIter->second.m_sBookmarkName.isEmpty(), 
"writerfilter.dmapper", "anonymous bookmark");
@@ -9757,6 +9740,8 @@ void DomainMapper_Impl::substream(Id rName,
     appendTableHandler();
     getTableManager().startLevel();
 
+    m_StreamStateStack.emplace();
+
     //import of page header/footer
     //Ensure that only one header/footer per section is pushed
 
@@ -9787,8 +9772,12 @@ void DomainMapper_Impl::substream(Id rName,
     case NS_ooxml::LN_annotation :
         PushAnnotation();
     break;
+    default:
+        assert(false); // unexpected?
     }
 
+    assert(m_StreamStateStack.top().eSubstreamType != SubstreamType::Body);
+
     try
     {
         ref->resolve(m_rDMapper);
@@ -9828,6 +9817,9 @@ void DomainMapper_Impl::substream(Id rName,
     break;
     }
 
+    assert(!m_StreamStateStack.empty());
+    m_StreamStateStack.pop();
+
     getTableManager().endLevel();
     popTableManager();
     m_bHasFtn = bHasFtn;
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index aad946e81702..3417147a92f3 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -146,6 +146,16 @@ enum StoredRedlines
     NONE
 };
 
+enum class SubstreamType
+{
+    Body,
+    Header,
+    Footer,
+    Footnote,
+    Endnote,
+    Annotation,
+};
+
 /**
  * Storage for state that is relevant outside a header/footer, but not inside 
it.
  *
@@ -157,6 +167,7 @@ enum StoredRedlines
  */
 struct SubstreamContext
 {
+    SubstreamType eSubstreamType = SubstreamType::Body;
     bool      bTextInserted = false;
     /**
      * This contains the raw table depth. nTableDepth > 0 is the same as
@@ -170,6 +181,10 @@ struct SubstreamContext
     bool      bIsColumnBreakDeferred = false;
     bool      bIsPageBreakDeferred = false;
     sal_Int32 nLineBreaksDeferred = 0;
+    /// Current paragraph had at least one field in it.
+    bool      bParaHadField = false;
+    /// Current paragraph in a table is first paragraph of a cell
+    bool      bFirstParagraphInCell = true;
 };
 
 /// Information about a paragraph to be finished after a field end.
@@ -543,15 +558,7 @@ private:
     bool                            m_bInStyleSheetImport; //in import of 
fonts, styles, lists or lfos
     bool                            m_bInNumberingImport; //in import of 
numbering (i.e. numbering.xml)
     bool                            m_bInAnyTableImport; //in import of fonts, 
styles, lists or lfos
-    enum class HeaderFooterImportState
-    {
-        none,
-        header,
-        footer,
-    }                               m_eInHeaderFooterImport;
     bool                            m_bDiscardHeaderFooter;
-    bool                            m_bInFootOrEndnote;
-    bool                            m_bInFootnote;
     PropertyMapPtr m_pFootnoteContext;
     bool m_bHasFootnoteStyle;
     bool m_bCheckFootnoteStyle;
@@ -599,7 +606,6 @@ private:
     bool                            m_bIsPreviousParagraphFramed;
     bool                            m_bIsLastParaInSection;
     bool                            m_bIsLastSectionGroup;
-    bool                            m_bIsInComments;
     /// If the current paragraph contains section property definitions.
     bool                            m_bParaSectpr;
     bool                            m_bUsingEnhancedFields;
@@ -751,7 +757,7 @@ public:
     /// Getter method for m_bSdt.
     bool GetSdt() const { return m_bSdt;}
     bool GetParaChanged() const { return m_bParaChanged;}
-    bool GetParaHadField() const { return m_bParaHadField; }
+    bool GetParaHadField() const { return 
m_StreamStateStack.top().bParaHadField; }
     bool GetRemoveThisPara() const { return m_bRemoveThisParagraph; }
 
     void deferBreak( BreakType deferredBreakType );
@@ -871,7 +877,7 @@ public:
     css::uno::Reference<css::drawing::XShape> PopPendingShape();
 
     void PopPageHeaderFooter(PagePartType ePagePartType, PageType eType);
-    bool IsInHeaderFooter() const { return m_eInHeaderFooterImport != 
HeaderFooterImportState::none; }
+    bool IsInHeaderFooter() const { auto const 
type(m_StreamStateStack.top().eSubstreamType); return type == 
SubstreamType::Header || type == SubstreamType::Footer; }
     void ConvertHeaderFooterToTextFrame(bool, bool);
     static void 
fillEmptyFrameProperties(std::vector<css::beans::PropertyValue>& 
rFrameProperties, bool bSetAnchorToChar);
 
@@ -879,8 +885,8 @@ public:
 
     void PushFootOrEndnote( bool bIsFootnote );
     void PopFootOrEndnote();
-    bool IsInFootOrEndnote() const { return m_bInFootOrEndnote; }
-    bool IsInFootnote() const { return IsInFootOrEndnote() && m_bInFootnote; }
+    bool IsInFootOrEndnote() const { auto const 
type(m_StreamStateStack.top().eSubstreamType); return type == 
SubstreamType::Footnote || type == SubstreamType::Endnote; }
+    bool IsInFootnote() const { return m_StreamStateStack.top().eSubstreamType 
== SubstreamType::Footnote; }
 
     void StartCustomFootnote(const PropertyMapPtr pContext);
     void EndCustomFootnote();
@@ -1026,7 +1032,7 @@ public:
     void SetInFootnoteProperties(bool bSet) { m_bIsInFootnoteProperties = 
bSet;}
     bool IsInFootnoteProperties() const { return m_bIsInFootnoteProperties;}
 
-    bool IsInComments() const { return m_bIsInComments; };
+    bool IsInComments() const { return m_StreamStateStack.top().eSubstreamType 
== SubstreamType::Annotation; };
 
     std::vector<css::beans::PropertyValue> MakeFrameProperties(const 
ParagraphProperties& rProps);
     void CheckUnregisteredFrameConversion(bool bPreventOverlap = false);
@@ -1207,15 +1213,9 @@ private:
     // Start a new index section; if needed, finish current paragraph
     css::uno::Reference<css::beans::XPropertySet> 
StartIndexSectionChecked(const OUString& sServiceName);
     std::vector<css::uno::Reference< css::drawing::XShape > > 
m_vTextFramesForChaining ;
-    /// Current paragraph had at least one field in it.
-    bool m_bParaHadField;
-    bool m_bSaveParaHadField;
     css::uno::Reference<css::beans::XPropertySet> m_xPreviousParagraph;
     /// Current paragraph has automatic before spacing.
     bool m_bParaAutoBefore;
-    /// Current paragraph in a table is first paragraph of a cell
-    bool m_bFirstParagraphInCell;
-    bool m_bSaveFirstParagraphInCell;
     /// Current paragraph had at least one inline object in it.
     bool m_bParaWithInlineObject;
     /// SAXException was seen so document will be abandoned
commit 56721f63b1056b273f2d97c2c26914db884986c8
Author:     Michael Stahl <[email protected]>
AuthorDate: Wed Jan 31 14:33:46 2024 +0100
Commit:     Andras Timar <[email protected]>
CommitDate: Wed Feb 7 22:57:26 2024 +0100

    tdf#158586 writerfilter: RTF import: fix \page \sect \skbnone w/ header
    
    The problem was not fixed yet for the less-minimized bugzilla attachment
    where the sections contain headers and footers.
    
    What happened there is that first \page caused a deferred page break,
    then \sect and sectBreak() delayed-read the header substream and the
    \par in the header resets all the deferred break flags.
    
    Add the deferred break to an already existing Context class, and remove
    the direct members in DomainMapper_Impl in favor of always using the
    m_StreamStateStack.
    
    Probably this problem cannot occur for DOCX import, because it imports
    header/footer eagerly where the reference element is, and sectPr is
    before any runs that contain breaks in the same paragraph element.
    
    Change-Id: Iba971955e9cf0c398d416518e72d99307d3e1cfd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162833
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 17e2c7226a73675d69febf0915aaeae61ad8e9f1)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162823
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sw/qa/extras/rtfexport/data/tdf158586_pageBreak1_header.rtf 
b/sw/qa/extras/rtfexport/data/tdf158586_pageBreak1_header.rtf
new file mode 100644
index 000000000000..cd8eefabb276
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf158586_pageBreak1_header.rtf
@@ -0,0 +1,17 @@
+{ tf1
+
+\paperw8419\paperh5953
+
+\spltpgpar
+
+\ltrpar \sectd
+
+{\headerl \pard\plain \par}
+
+\pard\plain \wrapdefault\pvmrg\posxlbsw0bsh0\phcol \posyilbslock\dxfrtext10
+
+\page \sect \sectd \sbknone
+
+\pard\plain Second page
+\par
+}
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index ebc2c3d2bf3f..167539197051 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -85,6 +85,19 @@ DECLARE_RTFEXPORT_TEST(testTdf158586_1, 
"tdf158586_pageBreak1.rtf")
     assertXPathContent(pLayout, "/root/page[2]/body//txt"_ostr, "Second page");
 }
 
+DECLARE_RTFEXPORT_TEST(testTdf158586_1header, 
"tdf158586_pageBreak1_header.rtf")
+{
+    // None of the specified text frame settings initiates a real text frame - 
page break not lost
+    CPPUNIT_ASSERT_EQUAL(2, getPages());
+    CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
+
+    // There should be no empty carriage return at the start of the second page
+    const auto& pLayout = parseLayoutDump();
+    // on import there is a section on page 2; on reimport there is no section
+    // (probably not an important difference?)
+    assertXPathContent(pLayout, "/root/page[2]/body//txt"_ostr, "Second page");
+}
+
 DECLARE_RTFEXPORT_TEST(testTdf158586_lostFrame, "tdf158586_lostFrame.rtf")
 {
     // The anchor and align properties are sufficient to define a frame
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index 34e3c04e35a8..b9093998a4d1 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -3258,7 +3258,8 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
          * section is a table. So in case first element is a table add a dummy 
para
          * and remove it again when lcl_endSectionGroup is called
          */
-        if(m_pImpl->m_nTableDepth == 0 && 
m_pImpl->GetIsFirstParagraphInSection()
+        if (m_pImpl->m_StreamStateStack.top().nTableDepth == 0
+            && m_pImpl->GetIsFirstParagraphInSection()
                 && !m_pImpl->GetIsDummyParaAddedForTableInSection() && 
!m_pImpl->GetIsTextFrameInserted()
                 && !m_pImpl->GetIsPreviousParagraphFramed() && 
!IsInHeaderFooter())
         {
@@ -3266,7 +3267,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
         }
 
         // if first paragraph style in table has break-before-page, transfer 
that setting to the table itself.
-        if( m_pImpl->m_nTableDepth == 0 )
+        if (m_pImpl->m_StreamStateStack.top().nTableDepth == 0)
         {
             const uno::Any aBreakType(style::BreakType_PAGE_BEFORE);
             const PropertyMapPtr pParagraphProps = 
m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
@@ -3287,11 +3288,11 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
             }
         }
 
-        m_pImpl->m_nTableDepth++;
+        m_pImpl->m_StreamStateStack.top().nTableDepth++;
     }
     break;
     case NS_ooxml::LN_tblEnd:
-        m_pImpl->m_nTableDepth--;
+        m_pImpl->m_StreamStateStack.top().nTableDepth--;
     break;
     case NS_ooxml::LN_tcStart:
         m_pImpl->m_nTableCellDepth++;
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 5342e7a21b83..6909e3925846 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -341,9 +341,6 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bSetCitation( false ),
         m_bSetDateValue( false ),
         m_bIsFirstSection( true ),
-        m_bIsColumnBreakDeferred( false ),
-        m_bIsPageBreakDeferred( false ),
-        m_nLineBreaksDeferred( 0 ),
         m_bSdtEndDeferred(false),
         m_bParaSdtEndDeferred(false),
         m_bStartTOC(false),
@@ -352,7 +349,6 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bStartIndex(false),
         m_bStartBibliography(false),
         m_nStartGenericField(0),
-        m_bTextInserted(false),
         m_bTextDeleted(false),
         m_nLastRedlineMovedID(1),
         m_sCurrentPermId(0),
@@ -399,7 +395,6 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bIsNewDoc(!rMediaDesc.getUnpackedValueOrDefault("InsertMode", 
false)),
         m_bIsAltChunk(rMediaDesc.getUnpackedValueOrDefault("AltChunkMode", 
false)),
         
m_bIsReadGlossaries(rMediaDesc.getUnpackedValueOrDefault("ReadGlossaries", 
false)),
-        m_nTableDepth(0),
         m_nTableCellDepth(0),
         m_bHasFtn(false),
         m_bHasFtnSep(false),
@@ -415,6 +410,7 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bParaWithInlineObject(false),
         m_bSaxError(false)
 {
+    m_StreamStateStack.emplace(); // add state for document body
     m_aBaseUrl = rMediaDesc.getUnpackedValueOrDefault(
         utl::MediaDescriptor::PROP_DOCUMENTBASEURL, OUString());
     if (m_aBaseUrl.isEmpty()) {
@@ -454,6 +450,7 @@ DomainMapper_Impl::DomainMapper_Impl(
 
 DomainMapper_Impl::~DomainMapper_Impl()
 {
+    assert(!m_StreamStateStack.empty());
     ChainTextFrames();
     // Don't remove last paragraph when pasting, sw expects that empty 
paragraph.
     if (m_bIsNewDoc)
@@ -1599,21 +1596,22 @@ ListsManager::Pointer const & 
DomainMapper_Impl::GetListTable()
 
 void DomainMapper_Impl::deferBreak( BreakType deferredBreakType)
 {
+    assert(!m_StreamStateStack.empty());
     switch (deferredBreakType)
     {
     case LINE_BREAK:
-        m_nLineBreaksDeferred++;
+        m_StreamStateStack.top().nLineBreaksDeferred++;
         break;
     case COLUMN_BREAK:
-        m_bIsColumnBreakDeferred = true;
+        m_StreamStateStack.top().bIsColumnBreakDeferred = true;
     break;
     case PAGE_BREAK:
             // See SwWW8ImplReader::HandlePageBreakChar(), page break should be
             // ignored inside tables.
-            if (m_nTableDepth > 0)
+            if (0 < m_StreamStateStack.top().nTableDepth)
                 return;
 
-            m_bIsPageBreakDeferred = true;
+            m_StreamStateStack.top().bIsPageBreakDeferred = true;
         break;
     default:
         return;
@@ -1622,14 +1620,15 @@ void DomainMapper_Impl::deferBreak( BreakType 
deferredBreakType)
 
 bool DomainMapper_Impl::isBreakDeferred( BreakType deferredBreakType )
 {
+    assert(!m_StreamStateStack.empty());
     switch (deferredBreakType)
     {
     case LINE_BREAK:
-        return m_nLineBreaksDeferred > 0;
+        return 0 < m_StreamStateStack.top().nLineBreaksDeferred;
     case COLUMN_BREAK:
-        return m_bIsColumnBreakDeferred;
+        return m_StreamStateStack.top().bIsColumnBreakDeferred;
     case PAGE_BREAK:
-        return m_bIsPageBreakDeferred;
+        return m_StreamStateStack.top().bIsPageBreakDeferred;
     default:
         return false;
     }
@@ -1637,17 +1636,18 @@ bool DomainMapper_Impl::isBreakDeferred( BreakType 
deferredBreakType )
 
 void DomainMapper_Impl::clearDeferredBreak(BreakType deferredBreakType)
 {
+    assert(!m_StreamStateStack.empty());
     switch (deferredBreakType)
     {
     case LINE_BREAK:
-        assert(m_nLineBreaksDeferred > 0);
-        m_nLineBreaksDeferred--;
+        assert(0 < m_StreamStateStack.top().nLineBreaksDeferred);
+        m_StreamStateStack.top().nLineBreaksDeferred--;
         break;
     case COLUMN_BREAK:
-        m_bIsColumnBreakDeferred = false;
+        m_StreamStateStack.top().bIsColumnBreakDeferred = false;
         break;
     case PAGE_BREAK:
-        m_bIsPageBreakDeferred = false;
+        m_StreamStateStack.top().bIsPageBreakDeferred = false;
         break;
     default:
         break;
@@ -1656,9 +1656,10 @@ void DomainMapper_Impl::clearDeferredBreak(BreakType 
deferredBreakType)
 
 void DomainMapper_Impl::clearDeferredBreaks()
 {
-    m_nLineBreaksDeferred = 0;
-    m_bIsColumnBreakDeferred = false;
-    m_bIsPageBreakDeferred = false;
+    assert(!m_StreamStateStack.empty());
+    m_StreamStateStack.top().nLineBreaksDeferred = 0;
+    m_StreamStateStack.top().bIsColumnBreakDeferred = false;
+    m_StreamStateStack.top().bIsPageBreakDeferred = false;
 }
 
 void DomainMapper_Impl::setSdtEndDeferred(bool bSdtEndDeferred)
@@ -2360,7 +2361,9 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
         {
             if ( GetIsFirstParagraphInShape() ||
                  (GetIsFirstParagraphInSection() && GetSectionContext() && 
GetSectionContext()->IsFirstSection()) ||
-                 (m_bFirstParagraphInCell && m_nTableDepth > 0 && 
m_nTableDepth == m_nTableCellDepth) )
+                (m_bFirstParagraphInCell
+                 && 0 < m_StreamStateStack.top().nTableDepth
+                 && m_StreamStateStack.top().nTableDepth == m_nTableCellDepth))
             {
                 // export requires grabbag to match top_margin, so keep them 
in sync
                 if (nBeforeAutospacing && bIsAutoSet)
@@ -2657,7 +2660,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
                         }
                         else if ( 
m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("NumberingStyleName")
 &&
                                 // don't update before tables
-                                (m_nTableDepth == 0 || 
!m_bFirstParagraphInCell))
+                                (m_StreamStateStack.top().nTableDepth == 0 || 
!m_bFirstParagraphInCell))
                         {
                             aCurrentNumberingName = GetListStyleName(nListId);
                             
m_xPreviousParagraph->getPropertyValue("NumberingStyleName") >>= 
aPreviousNumberingName;
@@ -2812,7 +2815,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
 
                     // tdf#77417 trim right white spaces in table cells in 
2010 compatibility mode
                     sal_Int32 nMode = 
GetSettingsTable()->GetWordCompatibilityMode();
-                    if ( m_nTableDepth > 0 && nMode > 0 && nMode <= 14 )
+                    if (0 < m_StreamStateStack.top().nTableDepth && 0 < nMode 
&& nMode <= 14)
                     {
                         // skip new line
                         xCur->goLeft(1, false);
@@ -2842,7 +2845,8 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
 
                 // table style precedence and not hidden shapes anchored to 
hidden empty table paragraphs
                 if (xParaProps && !m_bIsInComments
-                    && (m_nTableDepth > 0 || 
!m_aAnchoredObjectAnchors.empty()))
+                    && (0 < m_StreamStateStack.top().nTableDepth
+                        || !m_aAnchoredObjectAnchors.empty()))
                 {
                     // table style has got bigger precedence than docDefault 
style
                     // collect these pending paragraph properties to process 
in endTable()
@@ -2852,7 +2856,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
                     uno::Reference<text::XTextCursor> xCur2 =  
xTextRange->getText()->createTextCursorByRange(xCur);
                     uno::Reference<text::XParagraphCursor> xParaCursor(xCur2, 
uno::UNO_QUERY_THROW);
                     xParaCursor->gotoStartOfParagraph(false);
-                    if (m_nTableDepth > 0)
+                    if (0 < m_StreamStateStack.top().nTableDepth)
                     {
                         TableParagraph aPending{xParaCursor, xCur, 
pParaContext, xParaProps};
                         
getTableManager().getCurrentParagraphs()->push_back(aPending);
@@ -3019,8 +3023,12 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
 
     // don't overwrite m_bFirstParagraphInCell in table separator nodes
     // and in text boxes anchored to the first paragraph of table cells
-    if (m_nTableDepth > 0 && m_nTableDepth == m_nTableCellDepth && 
!IsInShape() && !m_bIsInComments)
+    if (0 < m_StreamStateStack.top().nTableDepth
+        && m_StreamStateStack.top().nTableDepth == m_nTableCellDepth
+        && !IsInShape() && !m_bIsInComments)
+    {
         m_bFirstParagraphInCell = false;
+    }
 
     m_bParaAutoBefore = false;
     m_bParaWithInlineObject = false;
@@ -3262,7 +3270,7 @@ void DomainMapper_Impl::applyToggleAttributes(const 
PropertyMapPtr& pPropertyMap
                     SAL_WARN_IF(!xTextRange.is(), "writerfilter.dmapper", 
"insertTextPortion failed");
                     if (!xTextRange.is())
                         throw uno::Exception("insertTextPortion failed", 
nullptr);
-                    m_bTextInserted = true;
+                    m_StreamStateStack.top().bTextInserted = true;
                     xTOCTextCursor->gotoRange(xTextRange->getEnd(), true);
                     if (m_nStartGenericField == 0)
                     {
@@ -3784,9 +3792,7 @@ bool isContentEmpty(uno::Reference<text::XText> const& 
xText, uno::Reference<tex
 void DomainMapper_Impl::PushPageHeaderFooter(PagePartType ePagePartType, 
PageType eType)
 {
     m_bSaveParaHadField = m_bParaHadField;
-    m_aHeaderFooterStack.push(HeaderFooterContext(m_bTextInserted, 
m_nTableDepth));
-    m_bTextInserted = false;
-    m_nTableDepth = 0;
+    m_StreamStateStack.emplace();
 
     bool bHeader = ePagePartType == PagePartType::Header;
 
@@ -3957,12 +3963,8 @@ void DomainMapper_Impl::PopPageHeaderFooter(PagePartType 
ePagePartType, PageType
     }
     m_eInHeaderFooterImport = HeaderFooterImportState::none;
 
-    if (!m_aHeaderFooterStack.empty())
-    {
-        m_bTextInserted = m_aHeaderFooterStack.top().getTextInserted();
-        m_nTableDepth = m_aHeaderFooterStack.top().getTableDepth();
-        m_aHeaderFooterStack.pop();
-    }
+    assert(!m_StreamStateStack.empty());
+    m_StreamStateStack.pop();
 
     m_bParaHadField = m_bSaveParaHadField;
 }
@@ -4121,7 +4123,7 @@ void 
DomainMapper_Impl::CreateRedline(uno::Reference<text::XTextRange> const& xR
         }
         // store frame and (possible floating) table redline data for 
restoring them after frame conversion
         enum StoredRedlines eType;
-        if (m_bIsActualParagraphFramed || m_nTableDepth > 0)
+        if (m_bIsActualParagraphFramed || 0 < 
m_StreamStateStack.top().nTableDepth)
             eType = StoredRedlines::FRAME;
         else if (IsInFootOrEndnote())
             eType = IsInFootnote() ? StoredRedlines::FOOTNOTE : 
StoredRedlines::ENDNOTE;
@@ -4977,7 +4979,7 @@ bool DomainMapper_Impl::IsDiscardHeaderFooter() const
 void DomainMapper_Impl::ClearPreviousParagraph()
 {
     // in table cells, set bottom auto margin of last paragraph to 0, except 
in paragraphs with numbering
-    if ((m_nTableDepth == (m_nTableCellDepth + 1))
+    if ((m_StreamStateStack.top().nTableDepth == (m_nTableCellDepth + 1))
         && m_xPreviousParagraph.is()
         && hasTableManager() && 
getTableManager().isCellLastParaAfterAutospacing())
     {
@@ -5984,18 +5986,6 @@ void DomainMapper_Impl::SetFieldLocked()
         m_aFieldStack.back()->SetFieldLocked();
 }
 
-HeaderFooterContext::HeaderFooterContext(bool bTextInserted, sal_Int32 
nTableDepth)
-    : m_bTextInserted(bTextInserted)
-    , m_nTableDepth(nTableDepth)
-{
-}
-
-bool HeaderFooterContext::getTextInserted() const
-{
-    return m_bTextInserted;
-}
-
-sal_Int32 HeaderFooterContext::getTableDepth() const { return m_nTableDepth; }
 
 FieldContext::FieldContext(uno::Reference< text::XTextRange > xStart)
     : m_bFieldCommandCompleted(false)
@@ -8680,7 +8670,7 @@ void DomainMapper_Impl::PopFieldContext()
                         }
                         m_bStartedTOC = false;
                         m_aTextAppendStack.pop();
-                        m_bTextInserted = false;
+                        m_StreamStateStack.top().bTextInserted = false;
                         m_bParaChanged = true; // the paragraph must stay 
anyway
                     }
                     m_bStartTOC = false;
@@ -8802,9 +8792,9 @@ void DomainMapper_Impl::PopFieldContext()
                         {
                             --m_nStartGenericField;
                             PopFieldmark(m_aTextAppendStack, xCrsr, 
pContext->GetFieldId());
-                            if(m_bTextInserted)
+                            if (m_StreamStateStack.top().bTextInserted)
                             {
-                                m_bTextInserted = false;
+                                m_StreamStateStack.top().bTextInserted = false;
                             }
                         }
                     }
@@ -8884,8 +8874,10 @@ void DomainMapper_Impl::StartOrEndBookmark( const 
OUString& rId )
      * iff the first element in the section is a table. If the dummy para is 
not added yet, then add it;
      * So bookmark is not attached to the wrong paragraph.
      */
-    if(hasTableManager() && getTableManager().isInCell() && m_nTableDepth == 0 
&& GetIsFirstParagraphInSection()
-                    && !GetIsDummyParaAddedForTableInSection() 
&&!GetIsTextFrameInserted())
+    if (hasTableManager() && getTableManager().isInCell()
+        && m_StreamStateStack.top().nTableDepth == 0
+        && GetIsFirstParagraphInSection()
+        && !GetIsDummyParaAddedForTableInSection() && 
!GetIsTextFrameInserted())
     {
         AddDummyParaForTableInSection();
     }
@@ -8926,7 +8918,7 @@ void DomainMapper_Impl::StartOrEndBookmark( const 
OUString& rId )
                     // keep bookmark range, if it doesn't exceed cell boundary
                     uno::Reference< text::XTextRange > xStart = 
xCursor->getStart();
                     xCursor->goLeft( 1, false );
-                    if (m_nTableDepth == 0 || !m_bFirstParagraphInCell)
+                    if (m_StreamStateStack.top().nTableDepth == 0 || 
!m_bFirstParagraphInCell)
                         xCursor->gotoRange(xStart, true );
                 }
                 uno::Reference< container::XNamed > xBkmNamed( xBookmark, 
uno::UNO_QUERY_THROW );
@@ -9005,7 +8997,8 @@ void 
DomainMapper_Impl::startOrEndPermissionRange(sal_Int32 permissinId)
     * if the first element in the section is a table. If the dummy para is not 
added yet, then add it;
     * So permission is not attached to the wrong paragraph.
     */
-    if (getTableManager().isInCell() && m_nTableDepth == 0 && 
GetIsFirstParagraphInSection()
+    if (getTableManager().isInCell()
+        && m_StreamStateStack.top().nTableDepth == 0 && 
GetIsFirstParagraphInSection()
         && !GetIsDummyParaAddedForTableInSection() && 
!GetIsTextFrameInserted())
     {
         AddDummyParaForTableInSection();
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index fbca4aa1f3f0..aad946e81702 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -152,16 +152,24 @@ enum StoredRedlines
  * In case some state of DomainMapper_Impl should be reset before handling the
  * header/footer and should be restored once handling of header/footer is done,
  * then you can use this class to do so.
+ *
+ * note: presumably more state should be moved here.
  */
-class HeaderFooterContext
+struct SubstreamContext
 {
-    bool      m_bTextInserted;
-    sal_Int32 m_nTableDepth;
-
-public:
-e 
... etc. - the rest is truncated

Reply via email to