diff options
author | Vasily Melenchuk <vasily.melenchuk@cib.de> | 2021-11-16 11:50:03 +0300 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2021-12-03 10:02:09 +0100 |
commit | 1733ed0935125814c963e37383f51daec8031e59 (patch) | |
tree | 8ccbc63b6a3da42cb6fd00b850462c542ae4ea62 /sw | |
parent | 4bb07962ef6c4fbd061dcdb4c637fd31f8c77a73 (diff) |
tdf#137466: docx: support w:placeholder & w15:color in w:sdtPr
Content controls in Word can contain some other elements which
are not supported by Writer. Put them into grabbag and write
back to DOCX on save to avoid losing quite sensitive data.
Test testSimpleSdts is modified: testcase is actully containing
4 sdt elements with ids in input and output.
Change-Id: I1f9addd03ed828bf375ccac5188a004f011e8a0d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125271
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Reviewed-by: Vasily Melenchuk <vasily.melenchuk@cib.de>
(cherry picked from commit 7db38a496a5e458ec12888ddbf63c603706ae3fc)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126000
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf137466.docx | bin | 0 -> 20243 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport17.cxx | 15 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport4.cxx | 2 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport5.cxx | 4 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlw14export.cxx | 2 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 89 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 6 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxexport.cxx | 3 |
8 files changed, 107 insertions, 14 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/tdf137466.docx b/sw/qa/extras/ooxmlexport/data/tdf137466.docx Binary files differnew file mode 100644 index 000000000000..3c5977251bda --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf137466.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index c711a6b2a10b..a7762a057e32 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -64,6 +64,21 @@ CPPUNIT_TEST_FIXTURE(Test, testParaStyleNumLevel) assertXPath(pXmlDoc, "/w:styles/w:style[@w:styleId='Mystyle']/w:pPr/w:numPr/w:ilvl", "val", "1"); } +DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx") +{ + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + if (!pXmlDoc) + return; // initial import, no futher checks + + // Ensure that we have <w:placeholder><w:docPart v:val="xxxx"/></w:placeholder> + OUString sDocPart = getXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:placeholder/w:docPart", "val"); + CPPUNIT_ASSERT_EQUAL(OUString("DefaultPlaceholder_-1854013440"), sDocPart); + + // Ensure that we have <w15:color v:val="xxxx"/> + OUString sColor = getXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w15:color", "val"); + CPPUNIT_ASSERT_EQUAL(OUString("FF0000"), sColor); +} + CPPUNIT_TEST_FIXTURE(Test, testDontAddNewStyles) { // Given a document that lacks builtin styles, and addition of them is disabled: diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx index 5858eec46524..cfb779d13c84 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx @@ -1021,7 +1021,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSimpleSdts) xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:text", 1); - assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:id", 3); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:id", 4); assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:picture", 1); assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:group", 1); assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:citation", 1); diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx index 081ac3252d31..6b6c5c497b65 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx @@ -579,10 +579,10 @@ CPPUNIT_TEST_FIXTURE(Test, testFDO79062) { loadAndSave("fdo79062.docx"); xmlDocUniquePtr pXmlFootNotes = parseExport("word/footnotes.xml"); - assertXPath(pXmlFootNotes, "/w:footnotes", "Ignorable", "w14 wp14"); + assertXPath(pXmlFootNotes, "/w:footnotes", "Ignorable", "w14 wp14 w15"); xmlDocUniquePtr pXmlEndNotes = parseExport("word/endnotes.xml"); - assertXPath(pXmlEndNotes, "/w:endnotes", "Ignorable", "w14 wp14"); + assertXPath(pXmlEndNotes, "/w:endnotes", "Ignorable", "w14 wp14 w15"); //tdf#93121 don't add fake tabs in front of extra footnote paragraphs uno::Reference<text::XFootnotesSupplier> xFootnoteSupp(mxComponent, uno::UNO_QUERY); diff --git a/sw/qa/extras/ooxmlexport/ooxmlw14export.cxx b/sw/qa/extras/ooxmlexport/ooxmlw14export.cxx index 157939060024..9e3184b566fe 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlw14export.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlw14export.cxx @@ -248,7 +248,7 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(Test_McIgnorable, "TextEffects_StylisticSets { xmlDocUniquePtr pXmlDocument = parseExport("word/document.xml"); - assertXPath(pXmlDocument, "/w:document", "Ignorable", "w14 wp14"); + assertXPath(pXmlDocument, "/w:document", "Ignorable", "w14 wp14 w15"); xmlDocUniquePtr pXmlStyles = parseExport("word/styles.xml"); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index ce1b190382bc..a2057d0d4786 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -587,7 +587,7 @@ static void lcl_deleteAndResetTheLists( rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTextAttrs, - OUString& rSdtPrAlias) + OUString& rSdtPrAlias, OUString& rSdtPrPlaceholderDocPart, OUString& rColor) { if( pSdtPrTokenChildren.is() ) pSdtPrTokenChildren.clear(); @@ -597,6 +597,10 @@ static void lcl_deleteAndResetTheLists( pSdtPrTextAttrs.clear(); if (!rSdtPrAlias.isEmpty()) rSdtPrAlias.clear(); + if (!rSdtPrPlaceholderDocPart.isEmpty()) + rSdtPrPlaceholderDocPart.clear(); + if (!rColor.isEmpty()) + rColor.clear(); } void DocxAttributeOutput::PopulateFrameProperties(const SwFrameFormat* pFrameFormat, const Size& rSize) @@ -803,14 +807,20 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT m_pSerializer->endElementNS( XML_w, XML_p ); // on export sdt blocks are never nested ATM if( !m_bAnchorLinkedToNode && !m_bStartedParaSdt ) - WriteSdtBlock( m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrTokenAttributes, m_pParagraphSdtPrDataBindingAttrs, m_pParagraphSdtPrTextAttrs, m_aParagraphSdtPrAlias, /*bPara=*/true ); + WriteSdtBlock(m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, + m_pParagraphSdtPrTokenAttributes, m_pParagraphSdtPrDataBindingAttrs, + m_pParagraphSdtPrTextAttrs, m_aParagraphSdtPrAlias, + m_aParagraphSdtPrPlaceHolderDocPart, m_aParagraphSdtPrColor, /*bPara=*/true); else { //These should be written out to the actual Node and not to the anchor. //Clear them as they will be repopulated when the node is processed. m_nParagraphSdtPrToken = 0; m_bParagraphSdtHasId = false; - lcl_deleteAndResetTheLists( m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs, m_pParagraphSdtPrTextAttrs, m_aParagraphSdtPrAlias ); + lcl_deleteAndResetTheLists(m_pParagraphSdtPrTokenChildren, + m_pParagraphSdtPrDataBindingAttrs, m_pParagraphSdtPrTextAttrs, + m_aParagraphSdtPrAlias, m_aParagraphSdtPrPlaceHolderDocPart, + m_aParagraphSdtPrColor); } m_pSerializer->mark(Tag_StartParagraph_2); @@ -849,9 +859,11 @@ void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTextAttrs, OUString& rSdtPrAlias, + OUString& rSdtPrPlaceholderDocPart, + OUString& rColor, bool bPara ) { - if( nSdtPrToken <= 0 && !pSdtPrDataBindingAttrs.is() ) + if( nSdtPrToken <= 0 && !pSdtPrDataBindingAttrs.is() && !m_bParagraphSdtHasId) return; // sdt start mark @@ -908,6 +920,17 @@ void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken, m_pSerializer->singleElementNS(XML_w, XML_text, xAttrList); } + if (!rSdtPrPlaceholderDocPart.isEmpty()) + { + m_pSerializer->startElementNS(XML_w, XML_placeholder); + m_pSerializer->singleElementNS(XML_w, XML_docPart, FSNS(XML_w, XML_val), rSdtPrPlaceholderDocPart); + m_pSerializer->endElementNS(XML_w, XML_placeholder); + } + if (!rColor.isEmpty()) + { + m_pSerializer->singleElementNS(XML_w15, XML_color, FSNS(XML_w, XML_val), rColor); + } + if (!rSdtPrAlias.isEmpty()) m_pSerializer->singleElementNS(XML_w, XML_alias, FSNS(XML_w, XML_val), rSdtPrAlias); @@ -938,7 +961,7 @@ void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken, pSdtPrDataBindingAttrs.clear(); pSdtPrTextAttrs.clear(); rSdtPrAlias.clear(); - + m_bParagraphSdtHasId = false; } void DocxAttributeOutput::EndSdtBlock() @@ -1616,14 +1639,18 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / if ( !m_bAnchorLinkedToNode && !m_bStartedCharSdt ) { rtl::Reference<sax_fastparser::FastAttributeList> pRunSdtPrTokenAttributes; - WriteSdtBlock( m_nRunSdtPrToken, m_pRunSdtPrTokenChildren, pRunSdtPrTokenAttributes, m_pRunSdtPrDataBindingAttrs, m_pRunSdtPrTextAttrs, m_aRunSdtPrAlias, /*bPara=*/false ); + WriteSdtBlock(m_nRunSdtPrToken, m_pRunSdtPrTokenChildren, pRunSdtPrTokenAttributes, + m_pRunSdtPrDataBindingAttrs, m_pRunSdtPrTextAttrs, m_aRunSdtPrAlias, + m_aRunSdtPrPlaceHolderDocPart, m_aRunSdtPrColor, /*bPara=*/false); } else { //These should be written out to the actual Node and not to the anchor. //Clear them as they will be repopulated when the node is processed. m_nRunSdtPrToken = 0; - lcl_deleteAndResetTheLists( m_pRunSdtPrTokenChildren, m_pRunSdtPrDataBindingAttrs, m_pRunSdtPrTextAttrs, m_aRunSdtPrAlias ); + lcl_deleteAndResetTheLists(m_pRunSdtPrTokenChildren, m_pRunSdtPrDataBindingAttrs, + m_pRunSdtPrTextAttrs, m_aRunSdtPrAlias, + m_aRunSdtPrPlaceHolderDocPart, m_aRunSdtPrColor); } if (bCloseEarlierSDT) @@ -9836,7 +9863,7 @@ void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem) for (const auto& rProp : std::as_const(aGrabBag)) { OUString sValue = rProp.Value.get<OUString>(); - if (rProp.Name == "ooxml:LN_CT_SdtText_multiLine") + if (rProp.Name == "ooxml:CT_SdtText_multiLine") AddToAttrList(m_pParagraphSdtPrTextAttrs, FSNS(XML_w, XML_multiLine), OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr()); @@ -9869,6 +9896,28 @@ void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem) OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); } } + else if (aPropertyValue.Name == "ooxml:CT_SdtPlaceholder_docPart") + { + uno::Sequence<beans::PropertyValue> aGrabBag; + aPropertyValue.Value >>= aGrabBag; + for (const auto& rProp : std::as_const(aGrabBag)) + { + OUString sValue = rProp.Value.get<OUString>(); + if (rProp.Name == "ooxml:CT_SdtPlaceholder_docPart_val") + m_aParagraphSdtPrPlaceHolderDocPart = sValue; + } + } + else if (aPropertyValue.Name == "ooxml:CT_SdtPr_color") + { + uno::Sequence<beans::PropertyValue> aGrabBag; + aPropertyValue.Value >>= aGrabBag; + for (const auto& rProp : std::as_const(aGrabBag)) + { + OUString sValue = rProp.Value.get<OUString>(); + if (rProp.Name == "ooxml:CT_SdtColor_val") + m_aParagraphSdtPrColor = sValue; + } + } else if (aPropertyValue.Name == "ooxml:CT_SdtPr_alias" && m_aParagraphSdtPrAlias.isEmpty()) { if (!(aPropertyValue.Value >>= m_aParagraphSdtPrAlias)) @@ -10070,7 +10119,7 @@ void DocxAttributeOutput::CharGrabBag( const SfxGrabBagItem& rItem ) for (const auto& rProp : std::as_const(aGrabBag)) { OUString sValue = rProp.Value.get<OUString>(); - if (rProp.Name == "ooxml:LN_CT_SdtText_multiLine") + if (rProp.Name == "ooxml:CT_SdtText_multiLine") AddToAttrList(m_pRunSdtPrTextAttrs, FSNS(XML_w, XML_multiLine), OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr()); @@ -10097,6 +10146,28 @@ void DocxAttributeOutput::CharGrabBag( const SfxGrabBagItem& rItem ) OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); } } + else if (aPropertyValue.Name == "ooxml:CT_SdtPlaceholder_docPart") + { + uno::Sequence<beans::PropertyValue> aGrabBag; + aPropertyValue.Value >>= aGrabBag; + for (const auto& rProp : std::as_const(aGrabBag)) + { + OUString sValue = rProp.Value.get<OUString>(); + if (rProp.Name == "ooxml:CT_SdtPlaceholder_docPart_val") + m_aRunSdtPrPlaceHolderDocPart = sValue; + } + } + else if (aPropertyValue.Name == "ooxml:CT_SdtPr_color") + { + uno::Sequence<beans::PropertyValue> aGrabBag; + aPropertyValue.Value >>= aGrabBag; + for (const auto& rProp : std::as_const(aGrabBag)) + { + OUString sValue = rProp.Value.get<OUString>(); + if (rProp.Name == "ooxml:CT_SdtColor_val") + m_aRunSdtPrColor = sValue; + } + } else if (aPropertyValue.Name == "ooxml:CT_SdtPr_alias" && m_aRunSdtPrAlias.isEmpty()) { if (!(aPropertyValue.Value >>= m_aRunSdtPrAlias)) diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 8843eb01ca4e..967e42e54e77 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -726,6 +726,8 @@ private: rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTextAttrs, OUString& rSdtPrAlias, + OUString& rSdtPrPlaceholderDocPart, + OUString& rColor, bool bPara); /// Closes a currently open SDT block. void EndSdtBlock(); @@ -1006,9 +1008,13 @@ private: rtl::Reference<sax_fastparser::FastAttributeList> m_pRunSdtPrTextAttrs; /// Value of the <w:alias> paragraph SDT element. OUString m_aParagraphSdtPrAlias; + OUString m_aParagraphSdtPrPlaceHolderDocPart; + OUString m_aParagraphSdtPrColor; /// Same as m_aParagraphSdtPrAlias, but its content is available till the SDT is closed. OUString m_aStartedParagraphSdtPrAlias; OUString m_aRunSdtPrAlias; + OUString m_aRunSdtPrPlaceHolderDocPart; + OUString m_aRunSdtPrColor; /// Currently paragraph SDT has a <w:id> child element. bool m_bParagraphSdtHasId; diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index a1ead25a3b7e..3d5fc3fe679a 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -1769,7 +1769,8 @@ rtl::Reference<FastAttributeList> DocxExport::MainXmlNamespaces() pAttr->add( FSNS( XML_xmlns, XML_mc ), OUStringToOString(m_rFilter.getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8) ); pAttr->add( FSNS( XML_xmlns, XML_wp14 ), OUStringToOString(m_rFilter.getNamespaceURL(OOX_NS(wp14)), RTL_TEXTENCODING_UTF8) ); pAttr->add( FSNS( XML_xmlns, XML_w14 ), OUStringToOString(m_rFilter.getNamespaceURL(OOX_NS(w14)), RTL_TEXTENCODING_UTF8) ); - pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14" ); + pAttr->add( FSNS( XML_xmlns, XML_w15 ), OUStringToOString(m_rFilter.getNamespaceURL(OOX_NS(w15)), RTL_TEXTENCODING_UTF8)); + pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14 w15" ); return pAttr; } |