sfx2/source/doc/DocumentMetadataAccess.cxx | 67 ++++++++++--- sw/inc/editsh.hxx | 12 +- sw/inc/rdfhelper.hxx | 23 ++++ sw/source/core/doc/DocumentTimerManager.cxx | 4 sw/source/core/doc/rdfhelper.cxx | 87 +++++++++++++---- sw/source/core/edit/edfcol.cxx | 139 ++++++++++++++++------------ sw/source/core/edit/edws.cxx | 11 -- sw/source/core/txtnode/ndtxt.cxx | 11 +- 8 files changed, 239 insertions(+), 115 deletions(-)
New commits: commit ad9902f34dd0b5837ab518445ea9f3a24352738b Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Wed Oct 3 05:53:28 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:41:02 2019 +0200 sw: paragraph-sign: process signatures in one pass on loading This combines the metadata field restoration logic with validation/update of said field in one pass upon loading docs. This cuts down overheads and makes the code more readable. In addition, now that paragraph signature validation is quite cheap (separate commits), esp. when no signatures exist, we validate and update signatures (where applicable) when fields are updated. Change-Id: I4adcea579c591f9be457ed742d2cf54fa308163d Reviewed-on: https://gerrit.libreoffice.org/63008 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/inc/editsh.hxx b/sw/inc/editsh.hxx index 4891dfb9f92b..01eee9f968ad 100644 --- a/sw/inc/editsh.hxx +++ b/sw/inc/editsh.hxx @@ -386,8 +386,11 @@ public: /// Validate all paragraph signatures. void ValidateAllParagraphSignatures(bool updateDontRemove); - /// Restore the metadata fields, if missing, from the RDF metadata. - void RestoreMetadataFields(); + /// Restore the metadata fields, if missing, from the RDF metadata + /// and validate the signatures and update the signature metadata fields. + /// Needed since deleting the metadata field doesn't remove the RDF + /// and editing docs using software that don't support paragraph signing. + void RestoreMetadataFieldsAndValidateParagraphSignatures(); /// Ensure that the classification of the doc is never lower than /// the paragraph with the highest classification. diff --git a/sw/source/core/doc/DocumentTimerManager.cxx b/sw/source/core/doc/DocumentTimerManager.cxx index c021276ed680..c57cfe65038c 100644 --- a/sw/source/core/doc/DocumentTimerManager.cxx +++ b/sw/source/core/doc/DocumentTimerManager.cxx @@ -34,6 +34,7 @@ #include <docfld.hxx> #include <fldbas.hxx> #include <comphelper/lok.hxx> +#include <editsh.hxx> namespace sw { @@ -191,6 +192,9 @@ IMPL_LINK( DocumentTimerManager, DoIdleJobs, Timer*, pIdle, void ) m_rDoc.getIDocumentFieldsAccess().UpdateTableFields(nullptr); // Tables m_rDoc.getIDocumentFieldsAccess().UpdateRefFields(); // References + // Validate and update the paragraph signatures. + m_rDoc.GetEditShell()->ValidateAllParagraphSignatures(true); + pTmpRoot->EndAllAction(); pShell->LockView( bOldLockView ); diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx index 191c9c70ffcf..ce08b170c986 100644 --- a/sw/source/core/edit/edfcol.cxx +++ b/sw/source/core/edit/edfcol.cxx @@ -1896,7 +1896,7 @@ uno::Reference<text::XTextField> lcl_GetParagraphMetadataFieldAtIndex(const SwDo return xTextField; } -void SwEditShell::RestoreMetadataFields() +void SwEditShell::RestoreMetadataFieldsAndValidateParagraphSignatures() { SwDocShell* pDocShell = GetDoc()->GetDocShell(); if (!pDocShell || !IsParagraphSignatureValidationEnabled()) @@ -2022,6 +2022,7 @@ void SwEditShell::RestoreMetadataFields() } } + lcl_ValidateParagraphSignatures(GetDoc(), xParagraph, true); // Validate and Update signatures. } catch (const std::exception&) { @@ -2115,7 +2116,7 @@ OUString lcl_GetHighestClassificationParagraphClass(SwPaM* pCursor) while (xParagraphs->hasMoreElements()) { uno::Reference<text::XTextContent> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY); - OUString sCurrentClass = lcl_GetParagraphClassification(aHelper, aKeyCreator, xModel, xParagraph); + const OUString sCurrentClass = lcl_GetParagraphClassification(aHelper, aKeyCreator, xModel, xParagraph); sHighestClass = aHelper.GetHigherClass(sHighestClass, sCurrentClass); } @@ -2128,7 +2129,7 @@ void SwEditShell::ClassifyDocPerHighestParagraphClass() if (!pDocShell) return; - // bail out as early as possible if we don't have paragraph classification + // Bail out as early as possible if we don't have paragraph classification. if (!SwRDFHelper::hasMetadataGraph(pDocShell->GetBaseModel(), MetaNS)) return; diff --git a/sw/source/core/edit/edws.cxx b/sw/source/core/edit/edws.cxx index d9ce2329e225..eae129280c10 100644 --- a/sw/source/core/edit/edws.cxx +++ b/sw/source/core/edit/edws.cxx @@ -17,11 +17,12 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <editsh.hxx> + #include <officecfg/Office/Common.hxx> #include <unotools/configmgr.hxx> #include <vcl/window.hxx> -#include <editsh.hxx> #include <doc.hxx> #include <IDocumentUndoRedo.hxx> #include <IDocumentState.hxx> @@ -51,12 +52,8 @@ SwEditShell::SwEditShell( SwDoc& rDoc, vcl::Window *pWindow, const SwViewOption GetDoc()->GetIDocumentUndoRedo().DoUndo(true); } - // Restore the tscp metadata fields - RestoreMetadataFields(); - - // Update the paragraph signatures. - // Since this ctor is called only on creating/loading the doc, we validate once only. - ValidateAllParagraphSignatures(true); + // Restore the paragraph metadata fields and validate signatures. + RestoreMetadataFieldsAndValidateParagraphSignatures(); } SwEditShell::~SwEditShell() // USED commit 10a0693a60d11cfd2401f9f96041bc3d5d7c4c5b Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Wed Oct 3 05:49:51 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:41:01 2019 +0200 sw: paragraph-sign: avoid re-validating paragraphs when classifying When setting the classification watermark, every edit to the document is triggering a re-validation of signatures, which is excessive and excessively expensive. Change-Id: I7808877263f553a871f2c31856da1a2f9e50c4bb Reviewed-on: https://gerrit.libreoffice.org/63007 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx index aaf7a80315a4..191c9c70ffcf 100644 --- a/sw/source/core/edit/edfcol.cxx +++ b/sw/source/core/edit/edfcol.cxx @@ -2155,6 +2155,12 @@ void SwEditShell::ClassifyDocPerHighestParagraphClass() const SfxClassificationPolicyType eHighestClassType = SfxClassificationHelper::stringToPolicyType(sHighestClass); + // Prevent paragraph signature validation since the below changes (f.e. watermarking) are benign. + const bool bOldValidationFlag = SetParagraphSignatureValidation(false); + comphelper::ScopeGuard const g([this, bOldValidationFlag]() { + SetParagraphSignatureValidation(bOldValidationFlag); + }); + // Check the origin, if "manual" (created via advanced classification dialog), // then we just need to set the category name. if (sfx::getCreationOriginProperty(xPropertyContainer, aKeyCreator) == sfx::ClassificationCreationOrigin::MANUAL) commit ffc9efb5c770a674c781bfedb3b91e912b6d0136 Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Wed Oct 3 05:47:49 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:41:00 2019 +0200 sw: paragraph-sign: skip invalid graph names Change-Id: Iaff61723497466521eddb2333656981f976d3fa6 Reviewed-on: https://gerrit.libreoffice.org/63006 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/source/core/doc/rdfhelper.cxx b/sw/source/core/doc/rdfhelper.cxx index d1fb7d4dbf4f..ff77293639cc 100644 --- a/sw/source/core/doc/rdfhelper.cxx +++ b/sw/source/core/doc/rdfhelper.cxx @@ -73,6 +73,9 @@ SwRDFHelper::getStatements(const css::uno::Reference<css::frame::XModel>& xModel for (const uno::Reference<rdf::XURI>& xGraphName : rGraphNames) { uno::Reference<rdf::XNamedGraph> xGraph = xRepo->getGraph(xGraphName); + if (!xGraph.is()) + continue; + uno::Reference<container::XEnumeration> xStatements = xGraph->getStatements( xSubject, uno::Reference<rdf::XURI>(), uno::Reference<rdf::XURI>()); while (xStatements->hasMoreElements()) commit 89c351a2610cc24720f391cf933f8af170de03ed Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Tue Oct 2 06:02:39 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:41:00 2019 +0200 sw: paragraph-sign: formatting Change-Id: I9bf1b58aa6e18202a5f7eba010cc5b914e1d33d4 Reviewed-on: https://gerrit.libreoffice.org/63005 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx index 48eb39da6a80..aaf7a80315a4 100644 --- a/sw/source/core/edit/edfcol.cxx +++ b/sw/source/core/edit/edfcol.cxx @@ -354,14 +354,16 @@ SignatureDescr lcl_getSignatureDescr(const uno::Reference<frame::XModel>& xModel SignatureDescr aDescr; aDescr.msId = sFieldId; + const OUString prefix = ParagraphSignatureRDFNamespace + sFieldId; const std::map<OUString, OUString> aStatements = lcl_getRDFStatements(xModel, xParagraph); - const auto itSig = aStatements.find(ParagraphSignatureRDFNamespace + sFieldId + ParagraphSignatureDigestRDFName); + + const auto itSig = aStatements.find(prefix + ParagraphSignatureDigestRDFName); aDescr.msSignature = (itSig != aStatements.end() ? itSig->second : OUString()); - const auto itDate = aStatements.find(ParagraphSignatureRDFNamespace + sFieldId + ParagraphSignatureDateRDFName); + const auto itDate = aStatements.find(prefix + ParagraphSignatureDateRDFName); aDescr.msDate = (itDate != aStatements.end() ? itDate->second : OUString()); - const auto itUsage = aStatements.find(ParagraphSignatureRDFNamespace + sFieldId + ParagraphSignatureUsageRDFName); + const auto itUsage = aStatements.find(prefix + ParagraphSignatureUsageRDFName); aDescr.msUsage = (itUsage != aStatements.end() ? itUsage->second : OUString()); return aDescr; @@ -371,14 +373,16 @@ SignatureDescr lcl_getSignatureDescr(const uno::Reference<frame::XModel>& xModel const uno::Reference<css::text::XTextContent>& xParagraph, const uno::Reference<css::text::XTextField>& xField) { - const std::pair<OUString, OUString> pair = lcl_getRDF(xModel, xField, ParagraphSignatureIdRDFName); - return (!pair.second.isEmpty() ? lcl_getSignatureDescr(xModel, xParagraph, pair.second) : SignatureDescr()); + const OUString sFieldId = lcl_getRDF(xModel, xField, ParagraphSignatureIdRDFName).second; + if (!sFieldId.isEmpty()) + return lcl_getSignatureDescr(xModel, xParagraph, sFieldId); + + return SignatureDescr(); } /// Validate and create the signature field display text from the fields. -std::pair<bool, OUString> -lcl_MakeParagraphSignatureFieldText(const SignatureDescr& aDescr, - const OString& utf8Text) +std::pair<bool, OUString> lcl_MakeParagraphSignatureFieldText(const SignatureDescr& aDescr, + const OString& utf8Text) { OUString msg = SwResId(STR_INVALID_SIGNATURE); bool valid = false; @@ -394,7 +398,8 @@ lcl_MakeParagraphSignatureFieldText(const SignatureDescr& aDescr, const std::vector<unsigned char> sig(svl::crypto::DecodeHexString(encSignature)); SignatureInformation aInfo(0); valid = svl::crypto::Signing::Verify(data, false, sig, aInfo); - valid = valid && aInfo.nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED; + valid = valid + && aInfo.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED; msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.ouSubject + ", "; msg += aDescr.msDate; @@ -406,7 +411,6 @@ lcl_MakeParagraphSignatureFieldText(const SignatureDescr& aDescr, return std::make_pair(valid, msg); } - /// Validate and return validation result and signature field display text. std::pair<bool, OUString> lcl_MakeParagraphSignatureFieldText(const uno::Reference<frame::XModel>& xModel, @@ -422,11 +426,10 @@ lcl_MakeParagraphSignatureFieldText(const uno::Reference<frame::XModel>& xModel, OUString lcl_getNextSignatureId(const uno::Reference<frame::XModel>& xModel, const uno::Reference<text::XTextContent>& xParagraph) { - const std::pair<OUString, OUString> pair = lcl_getRDF(xModel, xParagraph, ParagraphSignatureLastIdRDFName); - return OUString::number(!pair.second.isEmpty() ? pair.second.toInt32() + 1 : 1); + const OUString sFieldId = lcl_getRDF(xModel, xParagraph, ParagraphSignatureLastIdRDFName).second; + return OUString::number(!sFieldId.isEmpty() ? sFieldId.toInt32() + 1 : 1); } - /// Creates and inserts Paragraph Signature Metadata field and creates the RDF entry uno::Reference<text::XTextField> lcl_InsertParagraphSignature(const uno::Reference<frame::XModel>& xModel, const uno::Reference<text::XTextContent>& xParagraph, @@ -460,10 +463,11 @@ uno::Reference<text::XTextField> lcl_InsertParagraphSignature(const uno::Referen // Now set the RDF on the paragraph, since that's what is preserved in .doc(x). const css::uno::Reference<css::rdf::XResource> xParaSubject(xParagraph, uno::UNO_QUERY); + const OUString prefix = ParagraphSignatureRDFNamespace + sId; SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, ParagraphSignatureLastIdRDFName, sId); - SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, ParagraphSignatureRDFNamespace + sId + ParagraphSignatureDigestRDFName, signature); - SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, ParagraphSignatureRDFNamespace + sId + ParagraphSignatureUsageRDFName, usage); - SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, ParagraphSignatureRDFNamespace + sId + ParagraphSignatureDateRDFName, rBuffer.makeStringAndClear()); + SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureDigestRDFName, signature); + SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureUsageRDFName, usage); + SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureDateRDFName, rBuffer.makeStringAndClear()); return xField; } @@ -506,8 +510,9 @@ bool lcl_UpdateParagraphSignatureField(SwDoc* pDoc, const uno::Reference<css::text::XTextField>& xField, const OString& utf8Text) { - const std::pair<bool, OUString> res = lcl_MakeParagraphSignatureFieldText(xModel, xParagraph, xField, utf8Text); - return lcl_DoUpdateParagraphSignatureField(pDoc, xField, res.second); + const OUString sDisplayText + = lcl_MakeParagraphSignatureFieldText(xModel, xParagraph, xField, utf8Text).second; + return lcl_DoUpdateParagraphSignatureField(pDoc, xField, sDisplayText); } void lcl_RemoveParagraphMetadataField(const uno::Reference<css::text::XTextField>& xField) commit 25446d1c7d021ba99201f36b04d59c29c85b7733 Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Tue Oct 2 05:20:38 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:40:59 2019 +0200 sw: paragraph-sign: validate current SwTextNode directly When invoking undo, it turns out that the cursor position is updated after the text modification, which triggers the paragraph signature validation. Relying on the cursor position, then, results in the wrong (previous) paragraph to be validated (if the undo is in a different paragraph). Since we have the correct SwTextNode when it's modified (due to undo or otherwise), there is no reason why we shouldn't use it and try to deduce it from the cursor. Change-Id: I4c3283d59738988dcc1c592a9f3ef2c818ce675d Reviewed-on: https://gerrit.libreoffice.org/63004 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/inc/editsh.hxx b/sw/inc/editsh.hxx index 70250a85ac6c..4891dfb9f92b 100644 --- a/sw/inc/editsh.hxx +++ b/sw/inc/editsh.hxx @@ -377,7 +377,10 @@ public: /// Sign the paragraph at the cursor. void SignParagraph(); - /// Validate current paragraph signatures, if any, at the cursor start. + /// Validate the paragraph signatures, if any, of the current text node. + void ValidateParagraphSignatures(SwTextNode* pNode, bool updateDontRemove); + + /// Validate the current paragraph signatures, if any, at the cursor start. void ValidateCurrentParagraphSignatures(bool updateDontRemove); /// Validate all paragraph signatures. diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx index d95aea806c8f..48eb39da6a80 100644 --- a/sw/source/core/edit/edfcol.cxx +++ b/sw/source/core/edit/edfcol.cxx @@ -1805,16 +1805,13 @@ void SwEditShell::SignParagraph() GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::PARA_SIGN_ADD, nullptr); } -void SwEditShell::ValidateCurrentParagraphSignatures(bool updateDontRemove) +void SwEditShell::ValidateParagraphSignatures(SwTextNode* pNode, bool updateDontRemove) { - SwDocShell* pDocShell = GetDoc()->GetDocShell(); - if (!pDocShell || !GetCursor() || !GetCursor()->Start() || !IsParagraphSignatureValidationEnabled()) + if (!pNode || !IsParagraphSignatureValidationEnabled()) return; - SwPaM* pPaM = GetCursor(); - const SwPosition* pPosStart = pPaM->Start(); - SwTextNode* pNode = pPosStart->nNode.GetNode().GetTextNode(); - if (!pNode) + // Table text signing is not supported. + if (pNode->FindTableNode() != nullptr) return; // Prevent recursive validation since this is triggered on node updates, which we do below. @@ -1823,12 +1820,20 @@ void SwEditShell::ValidateCurrentParagraphSignatures(bool updateDontRemove) SetParagraphSignatureValidation(bOldValidationFlag); }); - // Table text signing is not supported. - if (pNode->FindTableNode() != nullptr) + uno::Reference<text::XTextContent> xParentText = SwXParagraph::CreateXParagraph(*GetDoc(), pNode); + lcl_ValidateParagraphSignatures(GetDoc(), xParentText, updateDontRemove); +} + +void SwEditShell::ValidateCurrentParagraphSignatures(bool updateDontRemove) +{ + SwDocShell* pDocShell = GetDoc()->GetDocShell(); + if (!pDocShell || !GetCursor() || !GetCursor()->Start() || !IsParagraphSignatureValidationEnabled()) return; - uno::Reference<text::XTextContent> xParentText = SwXParagraph::CreateXParagraph(*pNode->GetDoc(), pNode); - lcl_ValidateParagraphSignatures(GetDoc(), xParentText, updateDontRemove); + SwPaM* pPaM = GetCursor(); + const SwPosition* pPosStart = pPaM->Start(); + SwTextNode* pNode = pPosStart->nNode.GetNode().GetTextNode(); + ValidateParagraphSignatures(pNode, updateDontRemove); } void SwEditShell::ValidateAllParagraphSignatures(bool updateDontRemove) diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index c603ebdd40d4..9797c60b4441 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -1214,7 +1214,7 @@ void SwTextNode::Update( // Update the paragraph signatures. if (SwEditShell* pEditShell = GetDoc()->GetEditShell()) { - pEditShell->ValidateCurrentParagraphSignatures(true); + pEditShell->ValidateParagraphSignatures(this, true); } // Inform LOK clients about change in position of redlines (if any) commit 9ae364330ddbc7cec836d42221ebc9f7b4c40240 Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Mon Oct 1 07:56:14 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:40:59 2019 +0200 sw: paragraph-sign: get graph-names only once And reduce other overheads to make the paragraph signature validation significantly faster. Change-Id: I631bd0f15200bb8f0b85b40c0d4819a7bc4d562e Reviewed-on: https://gerrit.libreoffice.org/63003 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx index f79fc443199e..d95aea806c8f 100644 --- a/sw/source/core/edit/edfcol.cxx +++ b/sw/source/core/edit/edfcol.cxx @@ -538,6 +538,7 @@ uno::Reference<text::XTextField> lcl_FindParagraphClassificationField(const uno: if (!xTextPortionEnumerationAccess.is()) return xTextField; + // Enumerate text portions to find metadata fields. This is expensive, best to enumerate fields only. uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration(); while (xTextPortions->hasMoreElements()) { @@ -555,7 +556,6 @@ uno::Reference<text::XTextField> lcl_FindParagraphClassificationField(const uno: uno::Reference<text::XTextField> xField(xServiceInfo, uno::UNO_QUERY); if (lcl_IsParagraphClassificationField(xModel, xField, sKey)) { - uno::Reference<css::text::XTextRange> xText(xField, uno::UNO_QUERY); xTextField = xField; break; } @@ -1151,10 +1151,6 @@ void lcl_ApplyParagraphClassification(SwDoc* pDoc, if (!xNodeSubject.is()) return; - uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY); - - sfx::ClassificationKeyCreator aKeyCreator(SfxClassificationHelper::getPolicyType()); - // Remove all paragraph classification fields. for (;;) { @@ -1177,13 +1173,14 @@ void lcl_ApplyParagraphClassification(SwDoc* pDoc, { return rResult.meType == svx::ClassificationType::PARAGRAPH; }), aResults.end()); + sfx::ClassificationKeyCreator aKeyCreator(SfxClassificationHelper::getPolicyType()); std::vector<OUString> aFieldNames; for (size_t nIndex = 0; nIndex < aResults.size(); ++nIndex) { const svx::ClassificationResult& rResult = aResults[nIndex]; const bool isLast = nIndex == 0; - const bool isFirst = nIndex == aResults.size() - 1; + const bool isFirst = (nIndex == aResults.size() - 1); OUString sKey; OUString sValue = rResult.msName; switch (rResult.meType) @@ -1910,19 +1907,23 @@ void SwEditShell::RestoreMetadataFields() uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration(); if (!xParagraphs.is()) return; + + static const OUString sBlank(""); + const sfx::ClassificationKeyCreator aKeyCreator(SfxClassificationHelper::getPolicyType()); + const css::uno::Sequence<css::uno::Reference<rdf::XURI>> aGraphNames = SwRDFHelper::getGraphNames(xModel, MetaNS); + while (xParagraphs->hasMoreElements()) { uno::Reference<text::XTextContent> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY); - std::map<OUString, SignatureDescr> aSignatures; - std::vector<svx::ClassificationResult> aResults; - try { - const sfx::ClassificationKeyCreator aKeyCreator(SfxClassificationHelper::getPolicyType()); - const OUString sBlank(""); + const css::uno::Reference<css::rdf::XResource> xSubject(xParagraph, uno::UNO_QUERY); + const std::map<OUString, OUString> aStatements = SwRDFHelper::getStatements(xModel, aGraphNames, xSubject); - const OUString sFieldNames = lcl_getRDF(xModel, xParagraph, ParagraphClassificationFieldNamesRDFName).second; + const auto it = aStatements.find(ParagraphClassificationFieldNamesRDFName); + const OUString sFieldNames = (it != aStatements.end() ? it->second : sBlank); + std::vector<svx::ClassificationResult> aResults; if (!sFieldNames.isEmpty()) { // Order the fields @@ -1932,9 +1933,10 @@ void SwEditShell::RestoreMetadataFields() const OUString sCurFieldName = sFieldNames.getToken(0, '/', nIndex); if (sCurFieldName.isEmpty()) break; - std::pair<OUString, OUString> fieldNameValue = lcl_getRDF(xModel, xParagraph, sCurFieldName); - const OUString sName = fieldNameValue.first; - const OUString sValue = fieldNameValue.second; + + const auto it2 = aStatements.find(sCurFieldName); + const OUString sName = (it2 != aStatements.end() ? it->first : sBlank); + const OUString sValue = (it2 != aStatements.end() ? it->second : sBlank); if (aKeyCreator.isMarkingTextKey(sName)) { @@ -1942,14 +1944,14 @@ void SwEditShell::RestoreMetadataFields() } else if (aKeyCreator.isCategoryNameKey(sName)) { - const std::pair<OUString, OUString> pairAbbr = lcl_getRDF(xModel, xParent, ParagraphClassificationAbbrRDFName); - const OUString sAbbreviatedName = (!pairAbbr.second.isEmpty() ? pairAbbr.second : sValue); + const auto it3 = aStatements.find(ParagraphClassificationAbbrRDFName); + const OUString sAbbreviatedName = (it3 != aStatements.end() && !it3->second.isEmpty() ? it3->second : sValue); aResults.push_back({ svx::ClassificationType::CATEGORY, sValue, sAbbreviatedName, sBlank }); } else if (aKeyCreator.isCategoryIdentifierKey(sName)) { - const std::pair<OUString, OUString> pairAbbr = lcl_getRDF(xModel, xParent, ParagraphClassificationAbbrRDFName); - const OUString sAbbreviatedName = (!pairAbbr.second.isEmpty() ? pairAbbr.second : sValue); + const auto it3 = aStatements.find(ParagraphClassificationAbbrRDFName); + const OUString sAbbreviatedName = (it3 != aStatements.end() && !it3->second.isEmpty() ? it3->second : sValue); aResults.push_back({ svx::ClassificationType::CATEGORY, sBlank, sAbbreviatedName, sValue }); } else if (aKeyCreator.isMarkingKey(sName)) @@ -1964,21 +1966,23 @@ void SwEditShell::RestoreMetadataFields() while (nIndex >= 0); } + // Update classification based on results. lcl_ApplyParagraphClassification(GetDoc(), xModel, xParagraph, aResults); // Get Signatures + std::map<OUString, SignatureDescr> aSignatures; for (const auto& pair : lcl_getRDFStatements(xModel, xParagraph)) { - const OUString sName = pair.first; - const OUString sValue = pair.second; + const OUString& sName = pair.first; if (sName.startsWith(ParagraphSignatureRDFNamespace)) { - OUString sSuffix = sName.copy(ParagraphSignatureRDFNamespace.getLength()); - sal_Int32 index = sSuffix.indexOf(":"); + const OUString sSuffix = sName.copy(ParagraphSignatureRDFNamespace.getLength()); + const sal_Int32 index = sSuffix.indexOf(":"); if (index >= 0) { - OUString id = sSuffix.copy(0, index); - OUString type = sSuffix.copy(index); + const OUString id = sSuffix.copy(0, index); + const OUString type = sSuffix.copy(index); + const OUString& sValue = pair.second; if (type == ParagraphSignatureDateRDFName) aSignatures[id].msDate = sValue; else if (type == ParagraphSignatureUsageRDFName) @@ -2007,6 +2011,7 @@ void SwEditShell::RestoreMetadataFields() lcl_UpdateParagraphSignatureField(GetDoc(), xModel, xParagraph, xField, utf8Text); } } + } catch (const std::exception&) { @@ -2070,8 +2075,7 @@ OUString lcl_GetParagraphClassification(SfxClassificationHelper & rHelper, sfx:: xTextField = lcl_FindParagraphClassificationField(xModel, xParagraph, rKeyCreator.makeCategoryNameKey()); if (xTextField.is()) { - const std::pair<OUString, OUString> rdfValuePair = lcl_getRDF(xModel, xTextField, ParagraphClassificationNameRDFName); - return rdfValuePair.second; + return lcl_getRDF(xModel, xTextField, ParagraphClassificationNameRDFName).second; } return OUString(); commit f29f873d8e638d566f53f9ac5712e49910ee4094 Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Sun Oct 28 14:44:34 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:40:58 2019 +0200 paragraph-sign: exception-safe metadata graph enumeration Metadata graph enumeration can throw from a number functions and break things in horrible ways. Here we sanitize against the most egregious offenders, but not all possible sources. Change-Id: I40e006ea433dd7274d4fa08f3e8f8507680ef2f4 Reviewed-on: https://gerrit.libreoffice.org/63009 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/inc/rdfhelper.hxx b/sw/inc/rdfhelper.hxx index 149a2ed47529..03733a39d32b 100644 --- a/sw/inc/rdfhelper.hxx +++ b/sw/inc/rdfhelper.hxx @@ -26,6 +26,7 @@ namespace com { namespace sun { namespace star { class XModel; } namespace rdf { + class XDocumentMetadataAccess; class XResource; class XURI; } @@ -37,6 +38,11 @@ class SW_DLLPUBLIC SwRDFHelper public: /// Gets all graph-names in RDF of a given type. static css::uno::Sequence<css::uno::Reference<css::rdf::XURI>> + getGraphNames(const css::uno::Reference<css::rdf::XDocumentMetadataAccess>& xDocumentMetadataAccess, + const css::uno::Reference<css::rdf::XURI>& xType); + + /// Gets all graph-names in RDF of a given type. + static css::uno::Sequence<css::uno::Reference<css::rdf::XURI>> getGraphNames(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rType); /// Gets all (XResource, key, value) statements in RDF graphs given the graph-names. diff --git a/sw/source/core/doc/rdfhelper.cxx b/sw/source/core/doc/rdfhelper.cxx index 29e9e8dcf230..d1fb7d4dbf4f 100644 --- a/sw/source/core/doc/rdfhelper.cxx +++ b/sw/source/core/doc/rdfhelper.cxx @@ -23,15 +23,40 @@ using namespace com::sun::star; +css::uno::Sequence<css::uno::Reference<css::rdf::XURI>> SwRDFHelper::getGraphNames( + const css::uno::Reference<rdf::XDocumentMetadataAccess>& xDocumentMetadataAccess, + const css::uno::Reference<rdf::XURI>& xType) +{ + try + { + return xDocumentMetadataAccess->getMetadataGraphsWithType(xType); + } + catch (const uno::RuntimeException&) + { + return uno::Sequence<uno::Reference<rdf::XURI>>(); + } +} + css::uno::Sequence<uno::Reference<css::rdf::XURI>> SwRDFHelper::getGraphNames(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rType) { - uno::Reference<uno::XComponentContext> xComponentContext( - comphelper::getProcessComponentContext()); - uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); - uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY); - return xDocumentMetadataAccess->getMetadataGraphsWithType(xType); + try + { + uno::Reference<uno::XComponentContext> xComponentContext( + comphelper::getProcessComponentContext()); + // rdf::URI::create may fail with type: com.sun.star.uno.DeploymentException + // message: component context fails to supply service com.sun.star.rdf.URI of type com.sun.star.rdf.XURI + // context: cppu::ComponentContext + uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); + uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, + uno::UNO_QUERY); + return getGraphNames(xDocumentMetadataAccess, xType); + } + catch (const ::css::uno::Exception&) + { + return uno::Sequence<uno::Reference<rdf::XURI>>(); + } } std::map<OUString, OUString> @@ -76,7 +101,7 @@ void SwRDFHelper::addStatement(const css::uno::Reference<css::frame::XModel>& xM uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY); - uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = xDocumentMetadataAccess->getMetadataGraphsWithType(xType); + const uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = getGraphNames(xDocumentMetadataAccess, xType); uno::Reference<rdf::XURI> xGraphName; if (aGraphNames.hasElements()) xGraphName = aGraphNames[0]; @@ -96,8 +121,7 @@ bool SwRDFHelper::hasMetadataGraph(const css::uno::Reference<css::frame::XModel> uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY); - uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = xDocumentMetadataAccess->getMetadataGraphsWithType(xType); - return aGraphNames.hasElements(); + return getGraphNames(xDocumentMetadataAccess, xType).hasElements(); } void SwRDFHelper::removeStatement(const css::uno::Reference<css::frame::XModel>& xModel, @@ -108,7 +132,7 @@ void SwRDFHelper::removeStatement(const css::uno::Reference<css::frame::XModel>& uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY); - uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = xDocumentMetadataAccess->getMetadataGraphsWithType(xType); + const uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = getGraphNames(xDocumentMetadataAccess, xType); if (!aGraphNames.hasElements()) return; @@ -125,7 +149,7 @@ void SwRDFHelper::clearStatements(const css::uno::Reference<css::frame::XModel>& uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY); - uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = xDocumentMetadataAccess->getMetadataGraphsWithType(xType); + const uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = getGraphNames(xDocumentMetadataAccess, xType); if (!aGraphNames.hasElements()) return; @@ -152,7 +176,7 @@ void SwRDFHelper::cloneStatements(const css::uno::Reference<css::frame::XModel>& uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xSrcModel, uno::UNO_QUERY); - uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = xDocumentMetadataAccess->getMetadataGraphsWithType(xType); + const uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = getGraphNames(xDocumentMetadataAccess, xType); if (!aGraphNames.hasElements()) return; @@ -188,7 +212,7 @@ void SwRDFHelper::removeTextNodeStatement(const OUString& rType, SwTextNode& rTe uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(rTextNode.GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY); - uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = xDocumentMetadataAccess->getMetadataGraphsWithType(xType); + const uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = getGraphNames(xDocumentMetadataAccess, xType); if (!aGraphNames.hasElements()) return; @@ -205,7 +229,7 @@ void SwRDFHelper::updateTextNodeStatement(const OUString& rType, const OUString& uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(rTextNode.GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY); - uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = xDocumentMetadataAccess->getMetadataGraphsWithType(xType); + const uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = getGraphNames(xDocumentMetadataAccess, xType); uno::Reference<rdf::XURI> xGraphName; if (aGraphNames.hasElements()) { commit d5c9288e00cf39292d077d58be550af566b779ac Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Mon Oct 1 07:22:00 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:40:57 2019 +0200 sw: rdf: Split graph-name lookup from getStatement The graph-name lookup is significantly costly (compared to the statement lookup, esp. when no statements exist). Luckily, the graph-names do not change often and in the course of enumerating all paragraphs (as happens for paragraph-signature validation) it doesn't change at all. This split allows for doing the graph-name lookup only once and also allows for passing custom graph-names directly, if we know them already. Change-Id: I75425df201becb41105ba1fa6ba580af202d035c Reviewed-on: https://gerrit.libreoffice.org/63002 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/inc/rdfhelper.hxx b/sw/inc/rdfhelper.hxx index 5ec56b8a1935..149a2ed47529 100644 --- a/sw/inc/rdfhelper.hxx +++ b/sw/inc/rdfhelper.hxx @@ -17,6 +17,7 @@ #include "swdllapi.h" #include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> class SwTextNode; @@ -26,6 +27,7 @@ namespace com { namespace sun { namespace star { } namespace rdf { class XResource; + class XURI; } }}} @@ -33,11 +35,20 @@ namespace com { namespace sun { namespace star { class SW_DLLPUBLIC SwRDFHelper { public: + /// Gets all graph-names in RDF of a given type. + static css::uno::Sequence<css::uno::Reference<css::rdf::XURI>> + getGraphNames(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rType); + + /// Gets all (XResource, key, value) statements in RDF graphs given the graph-names. + static std::map<OUString, OUString> + getStatements(const css::uno::Reference<css::frame::XModel>& xModel, + const css::uno::Sequence<css::uno::Reference<css::rdf::XURI>>& rGraphNames, + const css::uno::Reference<css::rdf::XResource>& xSubject); /// Gets all (XResource, key, value) statements in RDF graphs of type rType. - static std::map<OUString, OUString> getStatements(const css::uno::Reference<css::frame::XModel>& xModel, - const OUString& rType, - const css::uno::Reference<css::rdf::XResource>& xSubject); + static std::map<OUString, OUString> + getStatements(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rType, + const css::uno::Reference<css::rdf::XResource>& xSubject); /// Add an (XResource, key, value) statement in the graph of type rType -- or if it does not exist, create a graph at rPath first. static void addStatement(const css::uno::Reference<css::frame::XModel>& xModel, diff --git a/sw/source/core/doc/rdfhelper.cxx b/sw/source/core/doc/rdfhelper.cxx index 8e8c78d90313..29e9e8dcf230 100644 --- a/sw/source/core/doc/rdfhelper.cxx +++ b/sw/source/core/doc/rdfhelper.cxx @@ -23,26 +23,36 @@ using namespace com::sun::star; -std::map<OUString, OUString> SwRDFHelper::getStatements(const css::uno::Reference<css::frame::XModel>& xModel, - const OUString& rType, - const css::uno::Reference<css::rdf::XResource>& xSubject) +css::uno::Sequence<uno::Reference<css::rdf::XURI>> +SwRDFHelper::getGraphNames(const css::uno::Reference<css::frame::XModel>& xModel, + const OUString& rType) { - std::map<OUString, OUString> aRet; - - uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); + uno::Reference<uno::XComponentContext> xComponentContext( + comphelper::getProcessComponentContext()); uno::Reference<rdf::XURI> xType = rdf::URI::create(xComponentContext, rType); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY); - uno::Sequence< uno::Reference<rdf::XURI> > aGraphNames = xDocumentMetadataAccess->getMetadataGraphsWithType(xType); - if (!aGraphNames.hasElements()) + return xDocumentMetadataAccess->getMetadataGraphsWithType(xType); +} + +std::map<OUString, OUString> +SwRDFHelper::getStatements(const css::uno::Reference<css::frame::XModel>& xModel, + const uno::Sequence<uno::Reference<css::rdf::XURI>>& rGraphNames, + const css::uno::Reference<css::rdf::XResource>& xSubject) +{ + std::map<OUString, OUString> aRet; + if (!rGraphNames.hasElements()) return aRet; - for (const uno::Reference<rdf::XURI>& xGraphName : aGraphNames) + uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY); + const uno::Reference<rdf::XRepository>& xRepo = xDocumentMetadataAccess->getRDFRepository(); + for (const uno::Reference<rdf::XURI>& xGraphName : rGraphNames) { - uno::Reference<rdf::XNamedGraph> xGraph = xDocumentMetadataAccess->getRDFRepository()->getGraph(xGraphName); - uno::Reference<container::XEnumeration> xStatements = xGraph->getStatements(xSubject, uno::Reference<rdf::XURI>(), uno::Reference<rdf::XURI>()); + uno::Reference<rdf::XNamedGraph> xGraph = xRepo->getGraph(xGraphName); + uno::Reference<container::XEnumeration> xStatements = xGraph->getStatements( + xSubject, uno::Reference<rdf::XURI>(), uno::Reference<rdf::XURI>()); while (xStatements->hasMoreElements()) { - rdf::Statement aStatement = xStatements->nextElement().get<rdf::Statement>(); + const rdf::Statement aStatement = xStatements->nextElement().get<rdf::Statement>(); aRet[aStatement.Predicate->getStringValue()] = aStatement.Object->getStringValue(); } } @@ -50,6 +60,14 @@ std::map<OUString, OUString> SwRDFHelper::getStatements(const css::uno::Referenc return aRet; } +std::map<OUString, OUString> +SwRDFHelper::getStatements(const css::uno::Reference<css::frame::XModel>& xModel, + const OUString& rType, + const css::uno::Reference<css::rdf::XResource>& xSubject) +{ + return getStatements(xModel, getGraphNames(xModel, rType), xSubject); +} + void SwRDFHelper::addStatement(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rType, const OUString& rPath, const css::uno::Reference<css::rdf::XResource>& xSubject, commit b6a16d2242cbee533ef46dd171a89ddd44f3af62 Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Mon Oct 1 07:03:47 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:40:56 2019 +0200 sfx2: Combine metadata graph lookup and filtering The graph lookup is suprisingly costly and so is filtering. By specializing the lookup with filtering the logic is more readable and slightly faster (~35% in debug build). Change-Id: Id35a562c76a84a81362f47b61ed67fb74d0a6dc7 Reviewed-on: https://gerrit.libreoffice.org/63001 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sfx2/source/doc/DocumentMetadataAccess.cxx b/sfx2/source/doc/DocumentMetadataAccess.cxx index bf765366e27f..dcdc3084187c 100644 --- a/sfx2/source/doc/DocumentMetadataAccess.cxx +++ b/sfx2/source/doc/DocumentMetadataAccess.cxx @@ -411,6 +411,48 @@ isPartOfType(struct DocumentMetadataAccess_Impl const & i_rImpl, } } +static ::std::vector<uno::Reference<rdf::XURI>> +getAllParts(struct DocumentMetadataAccess_Impl const& i_rImpl, + const uno::Reference<rdf::XURI>& i_xType) +{ + ::std::vector<uno::Reference<rdf::XURI>> ret; + try + { + const uno::Reference<container::XEnumeration> xEnum( + i_rImpl.m_xManifest->getStatements(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), + nullptr), + uno::UNO_SET_THROW); + while (xEnum->hasMoreElements()) + { + rdf::Statement stmt; + if (!(xEnum->nextElement() >>= stmt)) + { + throw uno::RuntimeException(); + } + const uno::Reference<rdf::XURI> xPart(stmt.Object, uno::UNO_QUERY); + if (!xPart.is()) + continue; + + const uno::Reference<container::XEnumeration> xEnum2( + i_rImpl.m_xManifest->getStatements( + xPart.get(), getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), i_xType.get()), + uno::UNO_SET_THROW); + if (xEnum2->hasMoreElements()) + ret.emplace_back(xPart); + } + return ret; + } + catch (const uno::RuntimeException&) + { + throw; + } + catch (const uno::Exception& e) + { + throw lang::WrappedTargetRuntimeException("getAllParts: exception", nullptr, + uno::makeAny(e)); + } +} static ucb::InteractiveAugmentedIOException mkException( OUString const & i_rMessage, @@ -850,26 +892,17 @@ DocumentMetadataAccess::getElementByURI( return getElementByMetadataReference( beans::StringPair(path, idref) ); } - -uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL -DocumentMetadataAccess::getMetadataGraphsWithType( - const uno::Reference<rdf::XURI> & i_xType) +uno::Sequence<uno::Reference<rdf::XURI>> SAL_CALL +DocumentMetadataAccess::getMetadataGraphsWithType(const uno::Reference<rdf::XURI>& i_xType) { - if (!i_xType.is()) { - throw lang::IllegalArgumentException( - "DocumentMetadataAccess::getMetadataGraphsWithType: " - "type is null", *this, 0); + if (!i_xType.is()) + { + throw lang::IllegalArgumentException("DocumentMetadataAccess::getMetadataGraphsWithType: " + "type is null", + *this, 0); } - ::std::vector< uno::Reference< rdf::XURI > > ret; - const ::std::vector< uno::Reference< rdf::XURI > > parts( - getAllParts(*m_pImpl) ); - ::std::remove_copy_if(parts.begin(), parts.end(), - ::std::back_inserter(ret), - [this, &i_xType](uno::Reference< rdf::XURI > aPart) { - return !isPartOfType(*m_pImpl, aPart, i_xType); - } ); - return ::comphelper::containerToSequence(ret); + return ::comphelper::containerToSequence(getAllParts(*m_pImpl, i_xType)); } uno::Reference<rdf::XURI> SAL_CALL commit 15701ab315a9d4cfc9ab0b05eae11a61b008eddc Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Fri Sep 28 06:27:09 2018 -0400 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Apr 25 21:40:56 2019 +0200 sw: paragraph-sign: erase metafields from copied text correctly This is relevant for paragraph signatures where the metadata is not yet copied and so we exclude it. The issue was that in some cases we didn't use the proper range of text and an assertion was triggered in debug builds. Otherwise there should be no change of behavior in release builds with this patch. Change-Id: I90bc2ca56d586b96d39f34c68de53d3dac6099d7 Reviewed-on: https://gerrit.libreoffice.org/63000 Tested-by: Jenkins Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 03fbb0c39da6..c603ebdd40d4 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -1689,7 +1689,7 @@ void SwTextNode::CopyText( SwTextNode *const pDest, { CHECK_SWPHINTS_IF_FRM(this); CHECK_SWPHINTS(pDest); - sal_Int32 nTextStartIdx = rStart.GetIndex(); + const sal_Int32 nTextStartIdx = rStart.GetIndex(); sal_Int32 nDestStart = rDestStart.GetIndex(); // remember old Pos if (pDest->GetDoc()->IsClipBoard() && GetNum()) @@ -1780,7 +1780,6 @@ void SwTextNode::CopyText( SwTextNode *const pDest, // Fetch end only now, because copying into self updates the start index // and all attributes - nTextStartIdx = rStart.GetIndex(); const sal_Int32 nEnd = nTextStartIdx + nLen; // 2. copy attributes @@ -1928,8 +1927,10 @@ void SwTextNode::CopyText( SwTextNode *const pDest, std::reverse(metaFieldRanges.begin(), metaFieldRanges.end()); for (const auto& pair : metaFieldRanges) { - const SwIndex aIdx(pDest, pair.first); - pDest->EraseText(aIdx, pair.second - pair.first); + const SwIndex aIdx(pDest, std::max<sal_Int32>(pair.first - nTextStartIdx, 0)); + const sal_Int32 nCount = pair.second - pair.first; + if (nCount > 0) + pDest->EraseText(aIdx, nCount); } } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits