diff options
author | Serge Krot <Serge.Krot@cib.de> | 2017-09-29 18:01:54 +0200 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2017-10-06 08:06:59 +0200 |
commit | 2694162969cf86ef366d3ce812fccd0630acc800 (patch) | |
tree | d138fe58a69d5c048f31e5a571b52b86a36db558 | |
parent | b567cfb980435df131d776915bce9152135bdf0f (diff) |
tdf#66398 Import/export docx document protection properties
Added:
+ import/export of all doc protection properties
+ unit test
Change-Id: I7b65cf4f5c7add2a96fef407c243081fcc2b6d8d
Reviewed-on: https://gerrit.libreoffice.org/43156
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf66398_permissions.docx | bin | 0 -> 10420 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport5.cxx | 16 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxexport.cxx | 42 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 11 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SettingsTable.cxx | 219 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SettingsTable.hxx | 2 |
6 files changed, 280 insertions, 10 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/tdf66398_permissions.docx b/sw/qa/extras/ooxmlexport/data/tdf66398_permissions.docx Binary files differnew file mode 100644 index 000000000000..d5c855994811 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf66398_permissions.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx index 96868a3b6f66..418b0dc64019 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx @@ -945,6 +945,22 @@ DECLARE_OOXMLEXPORT_TEST(testSectionProtection, "sectionprot.odt") } } +DECLARE_OOXMLEXPORT_TEST(tdf66398_permissions, "tdf66398_permissions.docx") +{ + 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=="); + } +} + DECLARE_OOXMLEXPORT_TEST(testSectionHeader, "sectionprot.odt") { if (xmlDocPtr pXmlDoc = parseExport("word/document.xml")) diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 2b8d97fb43e6..b76c121bb0d2 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> @@ -935,6 +936,7 @@ void DocxExport::WriteSettings() { pFS->singleElementNS( XML_w, XML_documentProtection, FSNS(XML_w, XML_edit), "forms", FSNS(XML_w, XML_enforcement), "1", FSEND ); } + // Do not justify lines with manual break if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK )) { @@ -942,6 +944,7 @@ void DocxExport::WriteSettings() pFS->singleElementNS( XML_w, XML_doNotExpandShiftReturn, FSEND ); pFS->endElementNS( XML_w, XML_compat ); } + // 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); @@ -969,11 +972,12 @@ void DocxExport::WriteSettings() uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW ); 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" ) @@ -1002,6 +1006,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; @@ -1025,8 +1030,43 @@ void DocxExport::WriteSettings() FSNS( XML_w, XML_val ), OUStringToOString(aValue, RTL_TEXTENCODING_UTF8).getStr(), FSEND); } + pFS->endElementNS( XML_w, XML_compat ); } + else if (propList[i].Name == "DocumentProtection") + { + sax_fastparser::FastAttributeList* pAttributeList = sax_fastparser::FastSerializerHelper::createAttrList(); + + uno::Sequence< beans::PropertyValue > rAttributeList; + propList[i].Value >>= rAttributeList; + + 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()); + } + + if (rAttributeList.getLength()) + { + sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList); + pFS->singleElementNS(XML_w, XML_documentProtection, xAttributeList); + } + } } } diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index a158615c583e..f492c2c2d033 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -206,10 +206,16 @@ DomainMapper::~DomainMapper() // Grab-bag handling comphelper::SequenceAsHashMap aProperties; + // Add the saved w:themeFontLang setting aProperties["ThemeFontLangProps"] <<= m_pImpl->GetSettingsTable()->GetThemeFontLangProperties(); + // Add the saved compat settings aProperties["CompatSettings"] <<= m_pImpl->GetSettingsTable()->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()) { @@ -2810,6 +2816,11 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext ) pProperties->resolve(*this); } break; + case NS_ooxml::LN_EG_RunLevelElts_permStart: // 93164 + case NS_ooxml::LN_EG_RunLevelElts_permEnd: // 93165 + { + break; + } default: { #ifdef DEBUG_WRITERFILTER diff --git a/writerfilter/source/dmapper/SettingsTable.cxx b/writerfilter/source/dmapper/SettingsTable.cxx index 9c5fed0ec78a..b747eb37abdb 100644 --- a/writerfilter/source/dmapper/SettingsTable.cxx +++ b/writerfilter/source/dmapper/SettingsTable.cxx @@ -39,6 +39,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_bRecordChanges(false) @@ -147,12 +319,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; @@ -226,9 +424,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; @@ -376,6 +572,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 28db5c26fb73..2a80bd186fc1 100644 --- a/writerfilter/source/dmapper/SettingsTable.hxx +++ b/writerfilter/source/dmapper/SettingsTable.hxx @@ -79,6 +79,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: |