[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - sw/qa sw/source writerfilter/source

Serge Krot Serge.Krot at cib.de
Wed Oct 18 08:43:50 UTC 2017


 sw/qa/extras/ooxmlexport/data/tdf66398_permissions.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport5.cxx               |   27 +
 sw/source/filter/ww8/docxattributeoutput.cxx            |  211 ++++++++++++---
 sw/source/filter/ww8/docxattributeoutput.hxx            |   15 +
 sw/source/filter/ww8/docxexport.cxx                     |   68 ++++
 writerfilter/source/dmapper/DomainMapper.cxx            |   24 +
 writerfilter/source/dmapper/DomainMapper_Impl.cxx       |  117 ++++++++
 writerfilter/source/dmapper/DomainMapper_Impl.hxx       |   53 +++
 writerfilter/source/dmapper/SettingsTable.cxx           |  219 +++++++++++++++-
 writerfilter/source/dmapper/SettingsTable.hxx           |    2 
 writerfilter/source/ooxml/factoryimpl.py                |    5 
 writerfilter/source/ooxml/factoryimpl_ns.py             |    6 
 writerfilter/source/ooxml/model.xml                     |   70 ++---
 13 files changed, 719 insertions(+), 98 deletions(-)

New commits:
commit 73046446ea6bae9a134092964505087f753663d7
Author: Serge Krot <Serge.Krot at cib.de>
Date:   Fri Sep 29 18:01:54 2017 +0200

    tdf#66398 Import/export docx document protection properties
    
    This includes:
     - original fix, import/export of all doc protection properties
     - unit test
     - remove double initialization of the form protection
     - do not output document protection in docx twice
     - remove useless breaks
     - fix cid#1418980: Resource leak
     - parse and output permissions for DOCX using bookmarks
     - enhance unit test: check permissions at content level
     - fix copy-paste: call start() bookmark instead of end()
    
    Conflicts:
            sw/source/filter/ww8/docxexport.cxx
            writerfilter/source/dmapper/DomainMapper.cxx
            sw/source/filter/ww8/docxexport.cxx
    
    Change-Id: I9a6fd248c58c10f4818779c1ceb81d60ffcea6c4

diff --git a/sw/qa/extras/ooxmlexport/data/tdf66398_permissions.docx b/sw/qa/extras/ooxmlexport/data/tdf66398_permissions.docx
new file mode 100644
index 000000000000..d5c855994811
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf66398_permissions.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index d4c99766b730..45f1aea29b82 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -963,6 +963,33 @@ DECLARE_OOXMLEXPORT_TEST(testSectionProtection, "sectionprot.odt")
     }
 }
 
+DECLARE_OOXMLEXPORT_TEST(tdf66398_permissions, "tdf66398_permissions.docx")
+{
+    // check document permission settings for the whole document
+    if (xmlDocPtr pXmlSettings = parseExport("word/settings.xml"))
+    {
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "edit",               "readOnly");
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "enforcement",        "1");
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "cryptProviderType",  "rsaAES");
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "cryptAlgorithmClass","hash");
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "cryptAlgorithmType", "typeAny");
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "cryptAlgorithmSid",  "14");
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "cryptSpinCount",     "100000");
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "hash",               "A0/Xy6KcXljJlZjP0TwJMPJuW2rc46UwXqn2ctxckc2nCECE5i89M85z2Noh3ZEA5NBQ9RJ5ycxiUH6nzmJaKw==");
+        assertXPath(pXmlSettings, "/w:settings/w:documentProtection", "salt",               "B8k6wb1pkjUs4Nv/8QBk/w==");
+    }
+
+    // get bookmark interface
+    uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+    uno::Reference<container::XNameAccess> xBookmarksByName(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+
+    // check: we have 2 bookmarks
+    CPPUNIT_ASSERT_EQUAL(xBookmarksByIdx->getCount(), static_cast<sal_Int32>(2));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("_GoBack"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("permission-for-group:267014232:everyone"));
+}
+
 DECLARE_OOXMLEXPORT_TEST(testSectionHeader, "sectionprot.odt")
 {
     if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index d37e9989a0e0..2b245545583c 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1224,8 +1224,13 @@ void DocxAttributeOutput::EndRun()
     // if there is some redlining in the document, output it
     StartRedline( m_pRedlineData );
 
-    DoWriteBookmarks( );
-    DoWriteAnnotationMarks( );
+    // XML_r node should be surrounded with bookmark-begin and bookmark-end nodes if it has bookmarks.
+    // The same is applied for permission ranges.
+    // But due to unit test "testFdo85542" let's output bookmark-begin with bookmark-end.
+    DoWriteBookmarksStart();
+    DoWriteBookmarksEnd();
+    DoWritePermissionsStart();
+    DoWriteAnnotationMarks();
 
     if( m_closeHyperlinkInThisRun && m_startedHyperlink && !m_hyperLinkAnchor.isEmpty() && m_hyperLinkAnchor.startsWith("_Toc"))
     {
@@ -1301,6 +1306,9 @@ void DocxAttributeOutput::EndRun()
 
     m_pSerializer->mergeTopMarks(Tag_StartRun_1);
 
+    // XML_r node should be surrounded with permission-begin and permission-end nodes if it has permission.
+    DoWritePermissionsEnd();
+
     for (std::vector<const SwOLENode*>::iterator it = m_aPostponedMaths.begin(); it != m_aPostponedMaths.end(); ++it)
         WritePostponedMath(*it);
     m_aPostponedMaths.clear();
@@ -1358,41 +1366,159 @@ void DocxAttributeOutput::EndRun()
     }
 }
 
-void DocxAttributeOutput::DoWriteBookmarks()
+void DocxAttributeOutput::DoWriteBookmarkTagStart(const OUString & bookmarkName)
+{
+    const OString rId   = OString::number(m_nNextBookmarkId);
+    const OString rName = OUStringToOString(BookmarkToWord(bookmarkName), RTL_TEXTENCODING_UTF8).getStr();
+
+    m_pSerializer->singleElementNS(XML_w, XML_bookmarkStart,
+        FSNS(XML_w, XML_id), rId.getStr(),
+        FSNS(XML_w, XML_name), rName.getStr(),
+        FSEND);
+}
+
+void DocxAttributeOutput::DoWriteBookmarkTagEnd(const OUString & bookmarkName)
 {
-    // Write the start bookmarks
-    for ( const auto & it : m_rBookmarksStart )
+    const auto nameToIdIter = m_rOpenedBookmarksIds.find(bookmarkName);
+    if (nameToIdIter != m_rOpenedBookmarksIds.end())
     {
-        OString rName = OUStringToOString( BookmarkToWord( it ), RTL_TEXTENCODING_UTF8 ).getStr();
+        const sal_Int32 nId = nameToIdIter->second;
+        const OString   rId = OString::number(nId);
+
+        m_pSerializer->singleElementNS(XML_w, XML_bookmarkEnd,
+            FSNS(XML_w, XML_id), rId.getStr(),
+            FSEND);
+    }
+}
 
+/// Write the start bookmarks
+void DocxAttributeOutput::DoWriteBookmarksStart()
+{
+    for (const OUString & bookmarkName : m_rBookmarksStart)
+    {
         // Output the bookmark
-        const sal_Int32 nId = m_nNextBookmarkId++;
-        m_rOpenedBookmarksIds[it] = nId;
-        m_pSerializer->singleElementNS( XML_w, XML_bookmarkStart,
-            FSNS( XML_w, XML_id ), OString::number( nId ).getStr(  ),
-            FSNS( XML_w, XML_name ), rName.getStr(),
-            FSEND );
-        m_sLastOpenedBookmark = rName;
+        DoWriteBookmarkTagStart(bookmarkName);
+
+        m_rOpenedBookmarksIds[bookmarkName] = m_nNextBookmarkId;
+        m_sLastOpenedBookmark = OUStringToOString(BookmarkToWord(bookmarkName), RTL_TEXTENCODING_UTF8).getStr();
+        m_nNextBookmarkId++;
     }
     m_rBookmarksStart.clear();
+}
 
-    // export the end bookmarks
-    for ( const auto & it : m_rBookmarksEnd )
+/// export the end bookmarks
+void DocxAttributeOutput::DoWriteBookmarksEnd()
+{
+    for (const OUString & bookmarkName : m_rBookmarksEnd)
     {
         // Get the id of the bookmark
-        auto pPos = m_rOpenedBookmarksIds.find(it);
-        if ( pPos != m_rOpenedBookmarksIds.end() )
+        auto pPos = m_rOpenedBookmarksIds.find(bookmarkName);
+        if (pPos != m_rOpenedBookmarksIds.end())
         {
-            const sal_Int32 nId = ( *pPos ).second;
-            m_pSerializer->singleElementNS( XML_w, XML_bookmarkEnd,
-                FSNS( XML_w, XML_id ), OString::number( nId ).getStr(),
-                FSEND );
-            m_rOpenedBookmarksIds.erase( it );
+            // Output the bookmark
+            DoWriteBookmarkTagEnd(bookmarkName);
+
+            m_rOpenedBookmarksIds.erase(bookmarkName);
         }
     }
     m_rBookmarksEnd.clear();
 }
 
+// For construction of the special bookmark name template for permissions:
+// see, PermInsertPosition::createBookmarkName()
+//
+// Syntax:
+// - "permission-for-user:<permission-id>:<permission-user-name>"
+// - "permission-for-group:<permission-id>:<permission-group-name>"
+//
+void DocxAttributeOutput::DoWritePermissionTagStart(const OUString & permission)
+{
+    OUString permissionIdAndName;
+
+    if (permission.startsWith("permission-for-group:", &permissionIdAndName))
+    {
+        const sal_Int32 sparatorIndex = permissionIdAndName.indexOf(':');
+        const OUString permissionId   = permissionIdAndName.copy(0, sparatorIndex);
+        const OUString permissionName = permissionIdAndName.copy(sparatorIndex + 1);
+
+        const OString rId   = OUStringToOString(BookmarkToWord(permissionId), RTL_TEXTENCODING_UTF8).getStr();
+        const OString rName = OUStringToOString(BookmarkToWord(permissionName), RTL_TEXTENCODING_UTF8).getStr();
+
+        m_pSerializer->singleElementNS(XML_w, XML_permStart,
+            FSNS(XML_w, XML_id), rId.getStr(),
+            FSNS(XML_w, XML_edGrp), rName.getStr(),
+            FSEND);
+    }
+    else // if (permission.startsWith("permission-for-user:", &permissionIdAndName))
+    {
+        const sal_Int32 sparatorIndex = permissionIdAndName.indexOf(':');
+        const OUString permissionId   = permissionIdAndName.copy(0, sparatorIndex);
+        const OUString permissionName = permissionIdAndName.copy(sparatorIndex + 1);
+
+        const OString rId   = OUStringToOString(BookmarkToWord(permissionId), RTL_TEXTENCODING_UTF8).getStr();
+        const OString rName = OUStringToOString(BookmarkToWord(permissionName), RTL_TEXTENCODING_UTF8).getStr();
+
+        m_pSerializer->singleElementNS(XML_w, XML_permStart,
+            FSNS(XML_w, XML_id), rId.getStr(),
+            FSNS(XML_w, XML_ed), rName.getStr(),
+            FSEND);
+    }
+}
+
+
+// For construction of the special bookmark name template for permissions:
+// see, PermInsertPosition::createBookmarkName()
+//
+// Syntax:
+// - "permission-for-user:<permission-id>:<permission-user-name>"
+// - "permission-for-group:<permission-id>:<permission-group-name>"
+//
+void DocxAttributeOutput::DoWritePermissionTagEnd(const OUString & permission)
+{
+    OUString permissionIdAndName;
+
+    if (permission.startsWith("permission-for-group:", &permissionIdAndName))
+    {
+        const sal_Int32 sparatorIndex = permissionIdAndName.indexOf(':');
+        const OUString permissionId   = permissionIdAndName.copy(0, sparatorIndex);
+        const OString rId             = OUStringToOString(BookmarkToWord(permissionId), RTL_TEXTENCODING_UTF8).getStr();
+
+        m_pSerializer->singleElementNS(XML_w, XML_permEnd,
+            FSNS(XML_w, XML_id), rId.getStr(),
+            FSEND);
+    }
+    else // if (permission.startsWith("permission-for-user:", &permissionIdAndName))
+    {
+        const sal_Int32 sparatorIndex = permissionIdAndName.indexOf(':');
+        const OUString permissionId   = permissionIdAndName.copy(0, sparatorIndex);
+        const OString rId             = OUStringToOString(BookmarkToWord(permissionId), RTL_TEXTENCODING_UTF8).getStr();
+
+        m_pSerializer->singleElementNS(XML_w, XML_permEnd,
+            FSNS(XML_w, XML_id), rId.getStr(),
+            FSEND);
+    }
+}
+
+/// Write the start permissions
+void DocxAttributeOutput::DoWritePermissionsStart()
+{
+    for (const OUString & permission : m_rPermissionsStart)
+    {
+        DoWritePermissionTagStart(permission);
+    }
+    m_rPermissionsStart.clear();
+}
+
+/// export the end permissions
+void DocxAttributeOutput::DoWritePermissionsEnd()
+{
+    for (const OUString & permission : m_rPermissionsEnd)
+    {
+        DoWritePermissionTagEnd(permission);
+    }
+    m_rPermissionsEnd.clear();
+}
+
 void DocxAttributeOutput::DoWriteAnnotationMarks()
 {
     // Write the start annotation marks
@@ -1619,13 +1745,9 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
     }
 
     // Write the bookmark start if any
-    OUString aBkmName( m_sFieldBkm );
-    if ( !aBkmName.isEmpty() )
+    if ( !m_sFieldBkm.isEmpty() )
     {
-        m_pSerializer->singleElementNS( XML_w, XML_bookmarkStart,
-               FSNS( XML_w, XML_id ), OString::number( m_nNextBookmarkId ).getStr( ),
-               FSNS( XML_w, XML_name ), OUStringToOString( aBkmName, RTL_TEXTENCODING_UTF8 ).getStr( ),
-               FSEND );
+        DoWriteBookmarkTagStart(m_sFieldBkm);
     }
 
     if (rInfos.pField ) // For hyperlinks and TOX
@@ -1649,11 +1771,9 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
     }
 
     // Write the bookmark end if any
-    if ( !aBkmName.isEmpty() )
+    if ( !m_sFieldBkm.isEmpty() )
     {
-        m_pSerializer->singleElementNS( XML_w, XML_bookmarkEnd,
-               FSNS( XML_w, XML_id ), OString::number( m_nNextBookmarkId ).getStr( ),
-               FSEND );
+        DoWriteBookmarkTagEnd(m_sFieldBkm);
 
         m_nNextBookmarkId++;
     }
@@ -6772,18 +6892,33 @@ void DocxAttributeOutput::WriteFormData_Impl( const ::sw::mark::IFieldmark& rFie
         m_Fields.begin()->pFieldmark = &rFieldmark;
 }
 
-void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts,
-        std::vector< OUString >& rEnds )
+void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts, std::vector< OUString >& rEnds )
 {
-    for ( const auto & it : rStarts )
+    for ( const OUString & name : rStarts )
     {
-        m_rBookmarksStart.push_back( it );
+        if (name.startsWith("permission-for-group:") ||
+            name.startsWith("permission-for-user:"))
+        {
+            m_rPermissionsStart.push_back(name);
+        }
+        else
+        {
+            m_rBookmarksStart.push_back(name);
+        }
     }
     rStarts.clear();
 
-    for ( const auto & it : rEnds )
+    for ( const OUString & name : rEnds )
     {
-        m_rBookmarksEnd.push_back( it );
+        if (name.startsWith("permission-for-group:") ||
+            name.startsWith("permission-for-user:"))
+        {
+            m_rPermissionsEnd.push_back(name);
+        }
+        else
+        {
+            m_rBookmarksEnd.push_back(name);
+        }
     }
     rEnds.clear();
 }
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index fd4143081c0f..8413b487d0b4 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -692,7 +692,16 @@ protected:
 
 private:
 
-    void DoWriteBookmarks( );
+    void DoWriteBookmarkTagStart(const OUString & bookmarkName);
+    void DoWriteBookmarkTagEnd(const OUString & bookmarkName);
+    void DoWriteBookmarksStart();
+    void DoWriteBookmarksEnd();
+
+    void DoWritePermissionTagStart(const OUString & permission);
+    void DoWritePermissionTagEnd(const OUString & permission);
+    void DoWritePermissionsStart();
+    void DoWritePermissionsEnd();
+
     void DoWriteAnnotationMarks( );
     void WritePostponedGraphic();
     void WritePostponedMath(const SwOLENode* pObject);
@@ -773,6 +782,10 @@ private:
     std::vector<OUString> m_rBookmarksStart;
     std::vector<OUString> m_rBookmarksEnd;
 
+    /// Permissions to output
+    std::vector<OUString> m_rPermissionsStart;
+    std::vector<OUString> m_rPermissionsEnd;
+
     /// Annotation marks to output
     std::vector<OString> m_rAnnotationMarksStart;
     std::vector<OString> m_rAnnotationMarksEnd;
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 42900986c57c..e8e738377f25 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -21,6 +21,7 @@
 #include "docxexportfilter.hxx"
 #include "docxattributeoutput.hxx"
 #include "docxsdrexport.hxx"
+#include "docxhelper.hxx"
 
 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
 #include <com/sun/star/document/XDocumentProperties.hpp>
@@ -855,12 +856,6 @@ void DocxExport::WriteSettings()
         pFS->singleElementNS( XML_w, XML_defaultTabStop, FSNS( XML_w, XML_val ),
             OString::number( m_aSettings.defaultTabStop).getStr(), FSEND );
 
-    // Protect form
-    if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::PROTECT_FORM ))
-    {
-        pFS->singleElementNS( XML_w, XML_documentProtection, FSNS(XML_w, XML_edit), "forms", FSNS(XML_w, XML_enforcement), "1",  FSEND );
-    }
-
     // Automatic hyphenation: it's a global setting in Word, it's a paragraph setting in Writer.
     // Use the setting from the default style.
     SwTextFormatColl* pColl = m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, /*bRegardLanguage=*/false);
@@ -887,12 +882,14 @@ void DocxExport::WriteSettings()
     // Has themeFontLang information
     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
 
+    bool hasProtectionProperties = false;
     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
-    OUString aGrabBagName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
+    const OUString aGrabBagName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
     if ( xPropSetInfo->hasPropertyByName( aGrabBagName ) )
     {
         uno::Sequence< beans::PropertyValue > propList;
         xPropSet->getPropertyValue( aGrabBagName ) >>= propList;
+
         for( sal_Int32 i=0; i < propList.getLength(); ++i )
         {
             if ( propList[i].Name == "ThemeFontLangProps" )
@@ -921,6 +918,7 @@ void DocxExport::WriteSettings()
 
                 uno::Sequence< beans::PropertyValue > aCompatSettingsSequence;
                 propList[i].Value >>= aCompatSettingsSequence;
+
                 for(sal_Int32 j=0; j < aCompatSettingsSequence.getLength(); ++j)
                 {
                     uno::Sequence< beans::PropertyValue > aCompatSetting;
@@ -947,18 +945,64 @@ void DocxExport::WriteSettings()
 
                 pFS->endElementNS( XML_w, XML_compat );
             }
+            else if (propList[i].Name == "DocumentProtection")
+            {
+
+                uno::Sequence< beans::PropertyValue > rAttributeList;
+                propList[i].Value >>= rAttributeList;
+
+                if (rAttributeList.getLength())
+                {
+                    sax_fastparser::FastAttributeList* pAttributeList = sax_fastparser::FastSerializerHelper::createAttrList();
+                    for (sal_Int32 j = 0; j < rAttributeList.getLength(); ++j)
+                    {
+                        static DocxStringTokenMap const aTokens[] =
+                        {
+                            { "edit",                XML_edit },
+                            { "enforcement",         XML_enforcement },
+                            { "formatting",          XML_formatting },
+                            { "cryptProviderType",   XML_cryptProviderType },
+                            { "cryptAlgorithmClass", XML_cryptAlgorithmClass },
+                            { "cryptAlgorithmType",  XML_cryptAlgorithmType },
+                            { "cryptAlgorithmSid",   XML_cryptAlgorithmSid },
+                            { "cryptSpinCount",      XML_cryptSpinCount },
+                            { "hash",                XML_hash },
+                            { "salt",                XML_salt },
+                            { nullptr, 0 }
+                        };
+
+                        if (sal_Int32 nToken = DocxStringGetToken(aTokens, rAttributeList[j].Name))
+                            pAttributeList->add(FSNS(XML_w, nToken), rAttributeList[j].Value.get<OUString>().toUtf8());
+                    }
+
+                    // we have document protection from from input DOCX file
+
+                    sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList);
+                    pFS->singleElementNS(XML_w, XML_documentProtection, xAttributeList);
+
+                    hasProtectionProperties = true;
+                }
+            }
         }
     }
 
+    // Protect form
     // Section-specific write protection
-    if ( m_pSections->DocumentIsProtected() )
+    if (! hasProtectionProperties)
     {
-        pFS->singleElementNS( XML_w, XML_documentProtection,
-                              FSNS( XML_w, XML_enforcement ), "true",
-                              FSNS( XML_w, XML_edit ), "forms",
-                              FSEND );
+        if (m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM) ||
+            m_pSections->DocumentIsProtected())
+        {
+            // we have form protection from Writer or from input ODT file
+
+            pFS->singleElementNS(XML_w, XML_documentProtection,
+                FSNS(XML_w, XML_edit), "forms",
+                FSNS(XML_w, XML_enforcement), "true",
+                FSEND);
+        }
     }
 
+    // finish settings.xml
     pFS->endElementNS( XML_w, XML_settings );
 }
 
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index 789aebea2cf8..138fca3f7863 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -190,10 +190,14 @@ DomainMapper::~DomainMapper()
 
         // Grab-bag handling
         comphelper::SequenceAsHashMap aProperties;
+
         // Add the saved w:themeFontLang setting
         aProperties["ThemeFontLangProps"] = uno::makeAny(GetThemeFontLangProperties());
         // Add the saved compat settings
         aProperties["CompatSettings"] = uno::makeAny(GetCompatSettings());
+        // Add the saved DocumentProtection settings
+        aProperties["DocumentProtection"] <<= m_pImpl->GetSettingsTable()->GetDocumentProtectionSettings();
+
         uno::Reference<beans::XPropertySet> xDocProps(m_pImpl->GetTextDocument(), uno::UNO_QUERY);
         if (xDocProps.is())
         {
@@ -1077,6 +1081,26 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
         case NS_ooxml::LN_CT_Cnf_val:
             m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "val", sStringValue);
             break;
+        case NS_ooxml::LN_CT_PermStart_ed:
+        {
+            m_pImpl->setPermissionRangeEd(sStringValue);
+            break;
+        }
+        case NS_ooxml::LN_CT_PermStart_edGrp:
+        {
+            m_pImpl->setPermissionRangeEdGrp(sStringValue);
+            break;
+        }
+        case NS_ooxml::LN_CT_PermStart_id:
+        {
+            m_pImpl->startOrEndPermissionRange(nIntValue);
+            break;
+        }
+        case NS_ooxml::LN_CT_PermEnd_id:
+        {
+            m_pImpl->startOrEndPermissionRange(nIntValue);
+            break;
+        }
         default:
             SAL_WARN("writerfilter", "DomainMapper::lcl_attribute: unhandled token: " << nName);
         }
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index bd532b87cc19..19d6f1a82985 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -199,6 +199,7 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bTOCPageRef(false),
         m_bStartGenericField(false),
         m_bTextInserted(false),
+        m_sCurrentPermId(0),
         m_pLastSectionContext( ),
         m_pLastCharacterContext(),
         m_nCurrentTabStopIndex( 0 ),
@@ -4586,6 +4587,7 @@ void DomainMapper_Impl::SetBookmarkName( const OUString& rBookmarkName )
         m_sCurrentBkmkName = rBookmarkName;
 }
 
+// This method was used as-is for DomainMapper_Impl::startOrEndPermissionRange() implementation.
 void DomainMapper_Impl::StartOrEndBookmark( const OUString& rId )
 {
     /*
@@ -4665,6 +4667,121 @@ void DomainMapper_Impl::StartOrEndBookmark( const OUString& rId )
     }
 }
 
+void DomainMapper_Impl::setPermissionRangeEd(const OUString& user)
+{
+    PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId);
+    if (aPremIter != m_aPermMap.end())
+        aPremIter->second.m_Ed = user;
+    else
+        m_sCurrentPermEd = user;
+}
+
+void DomainMapper_Impl::setPermissionRangeEdGrp(const OUString& group)
+{
+    PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId);
+    if (aPremIter != m_aPermMap.end())
+        aPremIter->second.m_EdGrp = group;
+    else
+        m_sCurrentPermEdGrp = group;
+}
+
+// This method is based on implementation from DomainMapper_Impl::StartOrEndBookmark()
+void DomainMapper_Impl::startOrEndPermissionRange(sal_Int32 permissinId)
+{
+    /*
+    * Add the dummy paragraph to handle section properties
+    * 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()
+        && !GetIsDummyParaAddedForTableInSection() && !GetIsTextFrameInserted())
+    {
+        AddDummyParaForTableInSection();
+    }
+
+    if (m_aTextAppendStack.empty())
+        return;
+
+    const bool bIsAfterDummyPara = GetIsDummyParaAddedForTableInSection() && GetIsFirstParagraphInSection();
+
+    uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+    PermMap_t::iterator aPermIter = m_aPermMap.find(permissinId);
+
+    //is the bookmark name already registered?
+    try
+    {
+        if (aPermIter == m_aPermMap.end())
+        {
+            //otherwise insert a text range as marker
+            bool bIsStart = true;
+            uno::Reference< text::XTextRange > xCurrent;
+            if (xTextAppend.is())
+            {
+                uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursorByRange(xTextAppend->getEnd());
+
+                if (!bIsAfterDummyPara)
+                    bIsStart = !xCursor->goLeft(1, false);
+                xCurrent = xCursor->getStart();
+            }
+
+            // register the start of the new permission
+            m_sCurrentPermId = permissinId;
+            m_aPermMap.emplace(permissinId, PermInsertPosition(bIsStart, permissinId, m_sCurrentPermEd, m_sCurrentPermEdGrp, xCurrent));
+
+            // clean up
+            m_sCurrentPermEd.clear();
+            m_sCurrentPermEdGrp.clear();
+        }
+        else
+        {
+            if (m_xTextFactory.is())
+            {
+                uno::Reference< text::XTextCursor > xCursor;
+                uno::Reference< text::XText > xText = aPermIter->second.m_xTextRange->getText();
+                if (aPermIter->second.m_bIsStartOfText && !bIsAfterDummyPara)
+                {
+                    xCursor = xText->createTextCursorByRange(xText->getStart());
+                }
+                else
+                {
+                    xCursor = xText->createTextCursorByRange(aPermIter->second.m_xTextRange);
+                    xCursor->goRight(1, false);
+                }
+
+                xCursor->gotoRange(xTextAppend->getEnd(), true);
+                // A Paragraph was recently finished, and a new Paragraph has not been started as yet
+                // then  move the bookmark-End to the earlier paragraph
+                if (IsOutsideAParagraph())
+                {
+                    xCursor->goLeft(1, false);
+                }
+
+                // create a new bookmark using specific bookmark name pattern for permissions
+                uno::Reference< text::XTextContent > xPerm(m_xTextFactory->createInstance("com.sun.star.text.Bookmark"), uno::UNO_QUERY_THROW);
+                uno::Reference< container::XNamed > xPermNamed(xPerm, uno::UNO_QUERY_THROW);
+                xPermNamed->setName(aPermIter->second.createBookmarkName());
+
+                // add new bookmark
+                const bool bAbsorb = !xCursor->isCollapsed();
+                uno::Reference< text::XTextRange > xCurrent = uno::Reference< text::XTextRange >(xCursor, uno::UNO_QUERY_THROW);
+                xTextAppend->insertTextContent(xCurrent, xPerm, bAbsorb);
+            }
+
+            // remove proccessed permission
+            m_aPermMap.erase(aPermIter);
+
+            // clean up
+            m_sCurrentPermId = 0;
+            m_sCurrentPermEd.clear();
+            m_sCurrentPermEdGrp.clear();
+        }
+    }
+    catch (const uno::Exception&)
+    {
+        //TODO: What happens to bookmarks where start and end are at different XText objects?
+    }
+}
+
 void DomainMapper_Impl::AddAnnotationPosition(
     const bool bStart,
     const sal_Int32 nAnnotationId)
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 37bea0a84605..ad96d4c77ef9 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -261,6 +261,49 @@ struct BookmarkInsertPosition
      {}
 };
 
+struct PermInsertPosition
+{
+    bool        m_bIsStartOfText;
+    sal_Int32   m_Id;
+    OUString    m_Ed;
+    OUString    m_EdGrp;
+
+    css::uno::Reference<css::text::XTextRange> m_xTextRange;
+
+    PermInsertPosition(bool bIsStartOfText, sal_Int32 id, const OUString& ed, const OUString& edGrp, css::uno::Reference<css::text::XTextRange> const& xTextRange)
+        : m_bIsStartOfText(bIsStartOfText)
+        , m_Id(id)
+        , m_Ed(ed)
+        , m_EdGrp(edGrp)
+        , m_xTextRange(xTextRange)
+    {}
+
+    OUString createBookmarkName() const
+    {
+        OUString bookmarkName;
+
+        assert((!m_Ed.isEmpty()) || (!m_EdGrp.isEmpty()));
+
+        if (m_Ed.isEmpty())
+        {
+            bookmarkName += "permission-for-group:";
+            bookmarkName += OUString::number(m_Id);
+            bookmarkName += ":";
+            bookmarkName += m_EdGrp;
+        }
+        else
+        {
+            bookmarkName += "permission-for-user:";
+            bookmarkName += OUString::number(m_Id);
+            bookmarkName += ":";
+            bookmarkName += m_Ed;
+        }
+
+        //todo: make sure the name is not used already!
+        return bookmarkName;
+    }
+};
+
 /// Stores the start/end positions of an annotation before its insertion.
 struct AnnotationPosition
 {
@@ -339,6 +382,7 @@ class DomainMapper_Impl
 {
 public:
     typedef std::map < OUString, BookmarkInsertPosition > BookmarkMap_t;
+    typedef std::map < sal_Int32, PermInsertPosition >    PermMap_t;
 
 private:
     SourceDocumentType                                                              m_eDocumentType;
@@ -380,6 +424,11 @@ private:
     OUString                                                                        m_sCurrentBkmkId;
     OUString                                                                        m_sCurrentBkmkName;
 
+    PermMap_t                                                                       m_aPermMap;
+    sal_Int32                                                                       m_sCurrentPermId;
+    OUString                                                                        m_sCurrentPermEd;
+    OUString                                                                        m_sCurrentPermEdGrp;
+
     PageMar                                                                        m_aPageMargins;
     SymbolData                                                                      m_aSymbolData;
 
@@ -696,6 +745,10 @@ public:
     void SetBookmarkName( const OUString& rBookmarkName );
     void StartOrEndBookmark( const OUString& rId );
 
+    void setPermissionRangeEd(const OUString& user);
+    void setPermissionRangeEdGrp(const OUString& group);
+    void startOrEndPermissionRange(sal_Int32 permissinId);
+
     void AddAnnotationPosition(
         const bool bStart,
         const sal_Int32 nAnnotationId );
diff --git a/writerfilter/source/dmapper/SettingsTable.cxx b/writerfilter/source/dmapper/SettingsTable.cxx
index 10791f065f5e..56c1c247e7df 100644
--- a/writerfilter/source/dmapper/SettingsTable.cxx
+++ b/writerfilter/source/dmapper/SettingsTable.cxx
@@ -38,6 +38,176 @@ namespace writerfilter {
 
 namespace dmapper
 {
+    /** Document protection restrictions
+     *
+     * This element specifies the set of document protection restrictions which have been applied to the contents of a
+     * WordprocessingML document.These restrictions should be enforced by applications editing this document
+     * when the enforcement attribute is turned on, and ignored(but persisted) otherwise.Document protection is a
+     * set of restrictions used to prevent unintentional changes to all or part of a WordprocessingML document.
+     */
+    struct DocumentProtection_Impl
+    {
+        /** Document Editing Restrictions
+         *
+         * Possible values:
+         *  - NS_ooxml::LN_Value_doc_ST_DocProtect_none
+         *  - NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly
+         *  - NS_ooxml::LN_Value_doc_ST_DocProtect_comments
+         *  - NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges
+         *  - NS_ooxml::LN_Value_doc_ST_DocProtect_forms
+         */
+        sal_Int32       m_nEdit;
+        bool            m_bEnforcement;
+        bool            m_bFormatting;
+
+        /** Provider type
+         *
+         * Possible values:
+         *  "rsaAES"  - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES
+         *  "rsaFull" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaFull
+         */
+        sal_Int32       m_nCryptProviderType;
+        OUString        m_sCryptAlgorithmClass;
+        OUString        m_sCryptAlgorithmType;
+        OUString        m_sCryptAlgorithmSid;
+        sal_Int32       m_CryptSpinCount;
+        OUString        m_sHash;
+        OUString        m_sSalt;
+
+        DocumentProtection_Impl()
+            : m_nEdit(NS_ooxml::LN_Value_doc_ST_DocProtect_none) // Specifies that no editing restrictions have been applied to the document
+            , m_bEnforcement(false)
+            , m_bFormatting(false)
+            , m_nCryptProviderType(NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES)
+            , m_sCryptAlgorithmClass("hash")
+            , m_sCryptAlgorithmType("typeAny")
+            , m_CryptSpinCount(0)
+        {
+        }
+
+        css::uno::Sequence<css::beans::PropertyValue> toSequence() const;
+
+        bool enabled() const
+        {
+            return ! isNone();
+        }
+
+        bool isNone()           const { return m_nEdit == NS_ooxml::LN_Value_doc_ST_DocProtect_none; };
+        // bool isReadOnly()       const { return m_nEdit == NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly; };
+        // bool isComments()       const { return m_nEdit == NS_ooxml::LN_Value_doc_ST_DocProtect_comments; };
+        // bool isTrackChanges()   const { return m_nEdit == NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges; };
+        bool isForms()          const { return m_nEdit == NS_ooxml::LN_Value_doc_ST_DocProtect_forms; };
+    };
+
+    css::uno::Sequence<css::beans::PropertyValue> DocumentProtection_Impl::toSequence() const
+    {
+        std::vector<beans::PropertyValue> documentProtection;
+
+        if (enabled())
+        {
+            // w:edit
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "edit";
+
+                switch (m_nEdit)
+                {
+                case NS_ooxml::LN_Value_doc_ST_DocProtect_none:             aValue.Value <<= OUString("none"); break;
+                case NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly:         aValue.Value <<= OUString("readOnly"); break;
+                case NS_ooxml::LN_Value_doc_ST_DocProtect_comments:         aValue.Value <<= OUString("comments"); break;
+                case NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges:   aValue.Value <<= OUString("trackedChanges"); break;
+                case NS_ooxml::LN_Value_doc_ST_DocProtect_forms:            aValue.Value <<= OUString("forms"); break;
+                default:
+                {
+#ifdef DEBUG_WRITERFILTER
+                    TagLogger::getInstance().element("unhandled");
+#endif
+                }
+                }
+
+                documentProtection.push_back(aValue);
+            }
+
+            // w:enforcement
+            if (m_bEnforcement)
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "enforcement";
+                aValue.Value <<= OUString("1");
+                documentProtection.push_back(aValue);
+            }
+
+            // w:formatting
+            if (m_bFormatting)
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "formatting";
+                aValue.Value <<= OUString("1");
+                documentProtection.push_back(aValue);
+            }
+
+            // w:cryptProviderType
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "cryptProviderType";
+                if (m_nCryptProviderType == NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES)
+                    aValue.Value <<= OUString("rsaAES");
+                else if (m_nCryptProviderType == NS_ooxml::LN_Value_doc_ST_CryptProv_rsaFull)
+                    aValue.Value <<= OUString("rsaFull");
+                documentProtection.push_back(aValue);
+            }
+
+            // w:cryptAlgorithmClass
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "cryptAlgorithmClass";
+                aValue.Value <<= m_sCryptAlgorithmClass;
+                documentProtection.push_back(aValue);
+            }
+
+            // w:cryptAlgorithmType
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "cryptAlgorithmType";
+                aValue.Value <<= m_sCryptAlgorithmType;
+                documentProtection.push_back(aValue);
+            }
+
+            // w:cryptAlgorithmSid
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "cryptAlgorithmSid";
+                aValue.Value <<= m_sCryptAlgorithmSid;
+                documentProtection.push_back(aValue);
+            }
+
+            // w:cryptSpinCount
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "cryptSpinCount";
+                aValue.Value <<= OUString::number(m_CryptSpinCount);
+                documentProtection.push_back(aValue);
+            }
+
+            // w:hash
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "hash";
+                aValue.Value <<= m_sHash;
+                documentProtection.push_back(aValue);
+            }
+
+            // w:salt
+            {
+                beans::PropertyValue aValue;
+                aValue.Name = "salt";
+                aValue.Value <<= m_sSalt;
+                documentProtection.push_back(aValue);
+            }
+        }
+
+        return comphelper::containerToSequence(documentProtection);
+    }
 
 struct SettingsTable_Impl
 {
@@ -71,6 +241,8 @@ struct SettingsTable_Impl
     std::vector<beans::PropertyValue> m_aCompatSettings;
     uno::Sequence<beans::PropertyValue> m_pCurrentCompatSetting;
 
+    DocumentProtection_Impl m_DocumentProtection;
+
     SettingsTable_Impl() :
       m_nDefaultTabStop( 720 ) //default is 1/2 in
     , m_nHyphenationZone(0)
@@ -146,12 +318,40 @@ void SettingsTable::lcl_attribute(Id nName, Value & val)
         m_pImpl->m_pCurrentCompatSetting[2].Name = "val";
         m_pImpl->m_pCurrentCompatSetting[2].Value <<= sStringValue;
         break;
-    case NS_ooxml::LN_CT_DocProtect_edit:
-        m_pImpl->m_bProtectForm = (nIntValue == NS_ooxml::LN_Value_doc_ST_DocProtect_forms);
+    case NS_ooxml::LN_CT_DocProtect_edit: // 92037
+        m_pImpl->m_DocumentProtection.m_nEdit = nIntValue;
+        m_pImpl->m_bProtectForm = m_pImpl->m_DocumentProtection.isForms();
         break;
-    case NS_ooxml::LN_CT_DocProtect_enforcement:
+    case NS_ooxml::LN_CT_DocProtect_enforcement: // 92039
+        m_pImpl->m_DocumentProtection.m_bEnforcement = (nIntValue != 0);
         m_pImpl->m_bProtectForm &= (bool)nIntValue;
         break;
+    case NS_ooxml::LN_CT_DocProtect_formatting: // 92038
+        m_pImpl->m_DocumentProtection.m_bFormatting = (nIntValue != 0);
+        break;
+    case NS_ooxml::LN_AG_Password_cryptProviderType: // 92025
+        m_pImpl->m_DocumentProtection.m_nCryptProviderType = nIntValue;
+        break;
+    case NS_ooxml::LN_AG_Password_cryptAlgorithmClass: // 92026
+        if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgClass_hash) // 92023
+            m_pImpl->m_DocumentProtection.m_sCryptAlgorithmClass = "hash";
+        break;
+    case NS_ooxml::LN_AG_Password_cryptAlgorithmType: // 92027
+        if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgType_typeAny) // 92024
+            m_pImpl->m_DocumentProtection.m_sCryptAlgorithmType = "typeAny";
+        break;
+    case NS_ooxml::LN_AG_Password_cryptAlgorithmSid: // 92028
+        m_pImpl->m_DocumentProtection.m_sCryptAlgorithmSid = sStringValue;
+        break;
+    case NS_ooxml::LN_AG_Password_cryptSpinCount: // 92029
+        m_pImpl->m_DocumentProtection.m_CryptSpinCount = nIntValue;
+        break;
+    case NS_ooxml::LN_AG_Password_hash: // 92035
+        m_pImpl->m_DocumentProtection.m_sHash = sStringValue;
+        break;
+    case NS_ooxml::LN_AG_Password_salt: // 92036
+        m_pImpl->m_DocumentProtection.m_sSalt = sStringValue;
+        break;
     default:
     {
 #ifdef DEBUG_WRITERFILTER
@@ -184,9 +384,7 @@ void SettingsTable::lcl_sprm(Sprm& rSprm)
     case NS_ooxml::LN_CT_Settings_view:
     //PropertySetValues - need to be resolved
     {
-        writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
-        if( pProperties.get())
-            pProperties->resolve(*this);
+        resolveSprmProps(*this, rSprm);
     }
     break;
     case NS_ooxml::LN_CT_Settings_stylePaneFormatFilter: // 92493;
@@ -229,9 +427,7 @@ void SettingsTable::lcl_sprm(Sprm& rSprm)
     }
     break;
     case NS_ooxml::LN_CT_Settings_documentProtection:
-        {
-            resolveSprmProps(*this, rSprm);
-        }
+        resolveSprmProps(*this, rSprm);
         break;
     case NS_ooxml::LN_CT_Compat_usePrinterMetrics:
         m_pImpl->m_bUsePrinterMetrics = nIntValue;
@@ -363,6 +559,11 @@ uno::Sequence<beans::PropertyValue> SettingsTable::GetCompatSettings() const
     return comphelper::containerToSequence(m_pImpl->m_aCompatSettings);
 }
 
+css::uno::Sequence<css::beans::PropertyValue> SettingsTable::GetDocumentProtectionSettings() const
+{
+    return m_pImpl->m_DocumentProtection.toSequence();
+}
+
 static bool lcl_isDefault(const uno::Reference<beans::XPropertyState>& xPropertyState, const OUString& rPropertyName)
 {
     return xPropertyState->getPropertyState(rPropertyName) == beans::PropertyState_DEFAULT_VALUE;
diff --git a/writerfilter/source/dmapper/SettingsTable.hxx b/writerfilter/source/dmapper/SettingsTable.hxx
index 648bf6d41b93..347de39c2cdf 100644
--- a/writerfilter/source/dmapper/SettingsTable.hxx
+++ b/writerfilter/source/dmapper/SettingsTable.hxx
@@ -77,6 +77,8 @@ class SettingsTable : public LoggedProperties, public LoggedTable
 
     css::uno::Sequence<css::beans::PropertyValue> GetCompatSettings() const;
 
+    css::uno::Sequence<css::beans::PropertyValue> GetDocumentProtectionSettings() const;
+
     void ApplyProperties(css::uno::Reference<css::text::XTextDocument> const& xDoc);
 
  private:
diff --git a/writerfilter/source/ooxml/factoryimpl.py b/writerfilter/source/ooxml/factoryimpl.py
index 8584e196cb38..519936b7b42e 100644
--- a/writerfilter/source/ooxml/factoryimpl.py
+++ b/writerfilter/source/ooxml/factoryimpl.py
@@ -25,7 +25,7 @@ def createFastChildContextFromFactory(model):
 (OOXMLFastContextHandler* pHandler, OOXMLFactory_ns::Pointer_t pFactory, Token_t Element)
 {
     uno::Reference <xml::sax::XFastContextHandler> aResult;
-    Id nDefine = pHandler->getDefine();
+    const Id nDefine = pHandler->getDefine();
 
     if (pFactory.get() != NULL)
     {
@@ -33,7 +33,7 @@ def createFastChildContextFromFactory(model):
         Id nElementId;
         if (pFactory->getElementId(nDefine, Element, nResource, nElementId))
         {
-            Id nId = pFactory->getResourceId(nDefine, Element);
+            const Id nId = pFactory->getResourceId(nDefine, Element);
 
             switch (nResource)
             {""")
@@ -118,7 +118,6 @@ public:
 
 std::string fastTokenToId(sal_uInt32 nToken)
 {
-
     std::string sResult;
 #ifdef DEBUG_WRITERFILTER
 
diff --git a/writerfilter/source/ooxml/factoryimpl_ns.py b/writerfilter/source/ooxml/factoryimpl_ns.py
index d9baaa1c3613..a222af8e8fb0 100644
--- a/writerfilter/source/ooxml/factoryimpl_ns.py
+++ b/writerfilter/source/ooxml/factoryimpl_ns.py
@@ -235,7 +235,6 @@ def printValueData(values):
                 output_else = "else "
             print("            else { return false; }")
             print("            return true;")
-            print("            break;")
     print("        }")
 
 
@@ -258,7 +257,6 @@ def factoryGetListValue(nsNode):
             appendValueData(values, valueData, idToLabel(valueNode.getAttribute("tokenid")))
         printValueData(values)
         print("        return false;")
-        print("        break;")
 
     print("""    default:
         break;
@@ -376,7 +374,6 @@ def factoryCreateElementMap(files, nsNode):
             print("        default: return false;")
             print("        }")
             print("        return true;")
-            print("        break;")
     print("    default:")
     print("        switch (nId)")
     print("        {")
@@ -384,10 +381,7 @@ def factoryCreateElementMap(files, nsNode):
     print("""        default: return false;
         }
         return true;
-        break;
     }
-
-    return false;
 }
 """)
 
diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml
index 1f5aa8285ecc..a96acdc05627 100644
--- a/writerfilter/source/ooxml/model.xml
+++ b/writerfilter/source/ooxml/model.xml
@@ -12117,6 +12117,9 @@
         </attribute>
         <ref name="CT_MarkupRange"/>
       </define>
+      <define name="CT_MarkupRangePerm">
+        <ref name="CT_MarkupRange"/>
+      </define>
       <define name="CT_MarkupRangeCommentStart">
         <ref name="CT_Markup"/>
       </define>
@@ -12157,6 +12160,24 @@
           <ref name="ST_String"/>
         </attribute>
       </define>
+      <define name="CT_PermStart">
+        <ref name="CT_MarkupRangePerm"/>
+        <attribute name="ed">
+          <data type="string"/>
+        </attribute>
+        <attribute name="edGrp">
+          <data type="string"/>
+        </attribute>
+        <attribute name="colFirst">
+          <data type="ST_DecimalNumber"/>
+        </attribute>
+        <attribute name="colLast">
+          <data type="ST_DecimalNumber"/>
+        </attribute>
+      </define>
+      <define name="CT_PermEnd">
+        <ref name="CT_MarkupRangePerm"/>
+      </define>
       <define name="CT_TrackChangeNumbering">
         <ref name="CT_TrackChange"/>
         <attribute name="original">
@@ -12245,6 +12266,12 @@
           <element name="bookmarkEnd">
             <ref name="CT_MarkupRangeBookmark"/>
           </element>
+          <element name="permStart">
+            <ref name="CT_PermStart"/>
+          </element>
+          <element name="permEnd">
+            <ref name="CT_PermEnd"/>
+          </element>
           <element name="moveFromRangeStart">
             <ref name="CT_MoveBookmark"/>
           </element>
@@ -13271,29 +13298,6 @@
           <data type="string"/>
         </attribute>
       </define>
-      <define name="CT_Perm">
-        <attribute name="id">
-          <data type="string"/>
-        </attribute>
-        <attribute name="displacedByCustomXml">
-          <data type="string"/>
-        </attribute>
-      </define>
-      <define name="CT_PermStart">
-        <ref name="CT_Perm"/>
-        <attribute name="edGrp">
-          <data type="string"/>
-        </attribute>
-        <attribute name="ed">
-          <data type="string"/>
-        </attribute>
-        <attribute name="colFirst">
-          <data type="string"/>
-        </attribute>
-        <attribute name="colLast">
-          <data type="string"/>
-        </attribute>
-      </define>
       <define name="CT_Text">
         <ref name="ST_String"/>
         <attribute name="xml:space">
@@ -16255,12 +16259,6 @@
           <element name="proofErr">
             <ref name="CT_ProofErr"/>
           </element>
-          <element name="permStart">
-            <ref name="CT_PermStart"/>
-          </element>
-          <element name="permEnd">
-            <ref name="CT_Perm"/>
-          </element>
           <ref name="EG_RangeMarkupElements"/>
           <element name="ins">
             <ref name="CT_RunTrackChange"/>
@@ -17326,6 +17324,18 @@
     <resource name="CT_MarkupRangeBookmark" resource="Properties">
       <attribute name="id" tokenid="ooxml:CT_MarkupRangeBookmark_id"/>
     </resource>
+    <resource name="CT_PermStart" resource="Properties">
+      <attribute name="id" tokenid="ooxml:CT_PermStart_id"/>
+      <attribute name="colFirst" tokenid="ooxml:CT_PermStart_colFirst"/>
+      <attribute name="colLast" tokenid="ooxml:CT_PermStart_colLast"/>
+      <attribute name="ed" tokenid="ooxml:CT_PermStart_ed"/>
+      <attribute name="edGrp" tokenid="ooxml:CT_PermStart_edGrp"/>
+      <attribute name="displacedByCustomXml" tokenid="ooxml:CT_PermStart_displacedByCustomXml"/>
+    </resource>
+    <resource name="CT_PermEnd" resource="Properties">
+      <attribute name="id" tokenid="ooxml:CT_PermEnd_id"/>
+      <attribute name="displacedByCustomXml" tokenid="ooxml:CT_PermEnd_displacedByCustomXml"/>
+    </resource>
     <resource name="CT_MarkupRangeCommentStart" resource="Properties">
       <attribute name="id" tokenid="ooxml:EG_RangeMarkupElements_commentRangeStart"/>
     </resource>
@@ -17388,6 +17398,8 @@
     <resource name="EG_RangeMarkupElements" resource="Properties">
       <element name="bookmarkStart" tokenid="ooxml:EG_RangeMarkupElements_bookmarkStart"/>
       <element name="bookmarkEnd" tokenid="ooxml:EG_RangeMarkupElements_bookmarkEnd"/>
+      <element name="permStart" tokenid="ooxml:EG_RangeMarkupElements_PermStart"/>
+      <element name="permEnd" tokenid="ooxml:EG_RangeMarkupElements_PermEnd"/>
       <element name="moveFromRangeStart" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart"/>
       <element name="moveFromRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd"/>
       <element name="moveToRangeStart" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart"/>


More information about the Libreoffice-commits mailing list