[Libreoffice-commits] core.git: 5 commits - include/sfx2 sfx2/source sw/qa sw/source writerfilter/source

Miklos Vajna vmiklos at collabora.co.uk
Wed Mar 9 13:19:17 UTC 2016


 include/sfx2/classificationhelper.hxx            |   10 +++
 sfx2/source/view/classificationhelper.cxx        |   29 +++++++++
 sw/qa/extras/rtfimport/data/custom-doc-props.rtf |   10 +++
 sw/qa/extras/rtfimport/rtfimport.cxx             |   10 +++
 sw/qa/extras/uiwriter/uiwriter.cxx               |   27 +++++++++
 sw/source/uibase/dochdl/swdtflvr.cxx             |   29 +++------
 writerfilter/source/rtftok/rtfcontrolwords.hxx   |    3 +
 writerfilter/source/rtftok/rtfdocumentimpl.cxx   |   68 +++++++++++++++++++++++
 writerfilter/source/rtftok/rtfdocumentimpl.hxx   |    5 +
 9 files changed, 173 insertions(+), 18 deletions(-)

New commits:
commit 8ff32dc66e3adb00209c82bddebfbeb47a275066
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Mar 9 12:21:36 2016 +0100

    RTF import: handle \staticval
    
    With this, user-defined document properties are imported from RTF.
    
    Change-Id: I8dfb8e802bd26906827620550d6f5d88f047d364

diff --git a/sw/qa/extras/rtfimport/data/custom-doc-props.rtf b/sw/qa/extras/rtfimport/data/custom-doc-props.rtf
new file mode 100644
index 0000000..b36d864
--- /dev/null
+++ b/sw/qa/extras/rtfimport/data/custom-doc-props.rtf
@@ -0,0 +1,10 @@
+{\rtf1
+{\*\userprops 
+{\propname urn:bails:IntellectualProperty:Authorization:StartValidity}
+\proptype30
+{\staticval 2016-03-08T10:55:18,531376147}
+{\propname urn:bails:IntellectualProperty:Authorization:StopValidity}
+\proptype30
+{\staticval None}
+}
+}
diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx b/sw/qa/extras/rtfimport/rtfimport.cxx
index d98b9b9..6ee8729 100644
--- a/sw/qa/extras/rtfimport/rtfimport.cxx
+++ b/sw/qa/extras/rtfimport/rtfimport.cxx
@@ -2525,6 +2525,16 @@ DECLARE_RTFIMPORT_TEST(testTdf87034, "tdf87034.rtf")
     CPPUNIT_ASSERT_EQUAL(OUString("A1B3C4D"), getParagraph(1)->getString());
 }
 
+DECLARE_RTFIMPORT_TEST(testCustomDocProps, "custom-doc-props.rtf")
+{
+    // Custom document properties were not improved, this resulted in a beans::UnknownPropertyException.
+    uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<document::XDocumentProperties> xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+    uno::Reference<beans::XPropertyContainer> xUserDefinedProperties = xDocumentProperties->getUserDefinedProperties();
+    CPPUNIT_ASSERT_EQUAL(OUString("2016-03-08T10:55:18,531376147"), getProperty<OUString>(xUserDefinedProperties, "urn:bails:IntellectualProperty:Authorization:StartValidity"));
+    CPPUNIT_ASSERT_EQUAL(OUString("None"), getProperty<OUString>(xUserDefinedProperties, "urn:bails:IntellectualProperty:Authorization:StopValidity"));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcontrolwords.hxx b/writerfilter/source/rtftok/rtfcontrolwords.hxx
index dab8196..80a2d1e 100644
--- a/writerfilter/source/rtftok/rtfcontrolwords.hxx
+++ b/writerfilter/source/rtftok/rtfcontrolwords.hxx
@@ -158,6 +158,7 @@ enum class Destination
     TOCENTRY,
     USERPROPS,
     PROPNAME,
+    STATICVAL,
 };
 
 enum RTFKeyword
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index 1fa5cbc..6dd561b 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -1291,6 +1291,7 @@ void RTFDocumentImpl::text(OUString& rString)
     case Destination::INDEXENTRY:
     case Destination::TOCENTRY:
     case Destination::PROPNAME:
+    case Destination::STATICVAL:
         m_aStates.top().pDestinationText->append(rString);
         break;
     default:
@@ -2059,6 +2060,9 @@ RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
         case RTF_PROPNAME:
             m_aStates.top().eDestination = Destination::PROPNAME;
             break;
+        case RTF_STATICVAL:
+            m_aStates.top().eDestination = Destination::STATICVAL;
+            break;
         default:
         {
             // Check if it's a math token.
@@ -5108,6 +5112,14 @@ void RTFDocumentImpl::resetAttributes()
     m_aStates.top().aParagraphAttributes.clear();
 }
 
+bool lcl_containsProperty(const uno::Sequence<beans::Property>& rProperties, const OUString& rName)
+{
+    return std::find_if(rProperties.begin(), rProperties.end(), [&](const beans::Property& rProperty)
+    {
+        return rProperty.Name == rName;
+    }) != rProperties.end();
+}
+
 RTFError RTFDocumentImpl::popState()
 {
     //SAL_INFO("writerfilter", OSL_THIS_FUNC << " before pop: m_pTokenizer->getGroup() " << m_pTokenizer->getGroup() <<
@@ -5897,6 +5909,35 @@ RTFError RTFDocumentImpl::popState()
             break; // not for nested group
         aState.aPropName = m_aStates.top().pDestinationText->makeStringAndClear();
         break;
+    case Destination::STATICVAL:
+        if (&m_aStates.top().aDestinationText != m_aStates.top().pDestinationText)
+            break; // not for nested group
+        if (m_xDocumentProperties.is())
+        {
+            // Find out what is the key, value type and value we want to set.
+            uno::Reference<beans::XPropertyContainer> xPropertyContainer = m_xDocumentProperties->getUserDefinedProperties();
+            uno::Reference<beans::XPropertySet> xPropertySet(xPropertyContainer, uno::UNO_QUERY);
+            uno::Sequence<beans::Property> aProperties = xPropertySet->getPropertySetInfo()->getProperties();
+            const OUString& rKey = m_aStates.top().aPropName;
+            OUString aStaticVal = m_aStates.top().pDestinationText->makeStringAndClear();
+            uno::Any aAny;
+            if (m_aStates.top().aPropType == cppu::UnoType<OUString>::get())
+                aAny = uno::makeAny(aStaticVal);
+
+            // Set it.
+            try
+            {
+                if (lcl_containsProperty(aProperties, rKey))
+                    xPropertySet->setPropertyValue(rKey, aAny);
+                else
+                    xPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aAny);
+            }
+            catch (const uno::Exception& rException)
+            {
+                SAL_WARN("writerfilter", "failed to set property " << rKey << ": " << rException.Message);
+            }
+        }
+        break;
     default:
         break;
     }
commit d11b43fe02a6daf2384d50de14f98fbfd55c180e
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Mar 9 12:05:17 2016 +0100

    RTF import: handle \proptype
    
    Change-Id: I398785ff0ac47a678e3171982119a85b107404b4

diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index 7d7ee39..1fa5cbc 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -4808,6 +4808,16 @@ RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
             lcl_putNestedSprm(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_right, std::make_shared<RTFValue>(aAttributes));
         }
         break;
+    case RTF_PROPTYPE:
+    {
+        switch (nParam)
+        {
+        case 30:
+            m_aStates.top().aPropType = cppu::UnoType<OUString>::get();
+            break;
+        }
+    }
+    break;
     default:
     {
         SAL_INFO("writerfilter", "TODO handle value '" << lcl_RtfToString(nKeyword) << "'");
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
index 9445ac9..fe239a4 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -300,6 +300,8 @@ public:
 
     /// User-defined property: key name.
     OUString aPropName;
+    /// User-defined property: value type.
+    css::uno::Type aPropType;
 };
 
 /// An RTF stack is similar to std::stack, except that it has an operator[].
commit cf773edad7033b23c53b5e9a60ecc0b56d7f83f9
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Mar 9 11:59:14 2016 +0100

    RTF import: handle \userprops and \propname
    
    Change-Id: I3fa0be5186603006e671779933625efff5d31867

diff --git a/writerfilter/source/rtftok/rtfcontrolwords.hxx b/writerfilter/source/rtftok/rtfcontrolwords.hxx
index dfbbabf..dab8196 100644
--- a/writerfilter/source/rtftok/rtfcontrolwords.hxx
+++ b/writerfilter/source/rtftok/rtfcontrolwords.hxx
@@ -156,6 +156,8 @@ enum class Destination
     FOOTNOTESEPARATOR,
     INDEXENTRY,
     TOCENTRY,
+    USERPROPS,
+    PROPNAME,
 };
 
 enum RTFKeyword
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index 187eb5a..7d7ee39 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -1290,6 +1290,7 @@ void RTFDocumentImpl::text(OUString& rString)
     case Destination::MGROW:
     case Destination::INDEXENTRY:
     case Destination::TOCENTRY:
+    case Destination::PROPNAME:
         m_aStates.top().pDestinationText->append(rString);
         break;
     default:
@@ -2051,6 +2052,13 @@ RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
             m_aStates.top().eDestination = Destination::FOOTNOTESEPARATOR;
             m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_FtnEdn_type, std::make_shared<RTFValue>(NS_ooxml::LN_Value_doc_ST_FtnEdn_separator));
             break;
+        case RTF_USERPROPS:
+            // Container of all user-defined properties.
+            m_aStates.top().eDestination = Destination::USERPROPS;
+            break;
+        case RTF_PROPNAME:
+            m_aStates.top().eDestination = Destination::PROPNAME;
+            break;
         default:
         {
             // Check if it's a math token.
@@ -5874,6 +5882,11 @@ RTFError RTFDocumentImpl::popState()
         if (aState.bCreatedShapeGroup)
             m_pSdrImport->popParent();
         break;
+    case Destination::PROPNAME:
+        if (&m_aStates.top().aDestinationText != m_aStates.top().pDestinationText)
+            break; // not for nested group
+        aState.aPropName = m_aStates.top().pDestinationText->makeStringAndClear();
+        break;
     default:
         break;
     }
@@ -6143,6 +6156,10 @@ RTFError RTFDocumentImpl::popState()
                 m_aStates.top().aDrawingObject.nBottom = aState.aDrawingObject.nBottom;
         }
         break;
+    case Destination::PROPNAME:
+        if (m_aStates.top().eDestination == Destination::USERPROPS)
+            m_aStates.top().aPropName = aState.aPropName;
+        break;
     default:
     {
         if (!m_aStates.empty() && m_aStates.top().eDestination == Destination::PICT)
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
index 37727d8..9445ac9 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -297,6 +297,9 @@ public:
     bool bInShape; ///< If we're inside a \shp group.
     bool bCreatedShapeGroup; ///< A GroupShape was created and pushed to the parent stack.
     bool bStartedTrackchange; ///< Track change is started, need to end it before popping.
+
+    /// User-defined property: key name.
+    OUString aPropName;
 };
 
 /// An RTF stack is similar to std::stack, except that it has an operator[].
commit 38dd218425b3e4a56d71af7082eea1dda24b48da
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Mar 9 11:32:12 2016 +0100

    CppunitTest_sw_uiwriter: add classification copy/paste testcase
    
    Change-Id: Ic3ac02fe28bee0ea3189fb2c9d3548f5ca13fe5c

diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx
index 96e8cd5..fced549 100644
--- a/sw/qa/extras/uiwriter/uiwriter.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter.cxx
@@ -89,6 +89,7 @@
 #include <txtfrm.hxx>
 #include <editeng/svxenum.hxx>
 #include <comphelper/propertysequence.hxx>
+#include <sfx2/classificationhelper.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
 static const char* DATA_DIRECTORY = "/sw/qa/extras/uiwriter/data/";
@@ -187,6 +188,7 @@ public:
     void testTdf96536();
     void testTdf96479();
     void testTdf96961();
+    void testClassificationPaste();
 
     CPPUNIT_TEST_SUITE(SwUiWriterTest);
     CPPUNIT_TEST(testReplaceForward);
@@ -277,6 +279,7 @@ public:
     CPPUNIT_TEST(testTdf96536);
     CPPUNIT_TEST(testTdf96479);
     CPPUNIT_TEST(testTdf96961);
+    CPPUNIT_TEST(testClassificationPaste);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -3246,6 +3249,30 @@ void SwUiWriterTest::testTdf96961()
     CPPUNIT_ASSERT(nLast > nOther);
 }
 
+void SwUiWriterTest::testClassificationPaste()
+{
+    SwDocShell* pSourceShell = createDoc()->GetDocShell();
+    uno::Reference<lang::XComponent> xSourceComponent = mxComponent;
+    mxComponent.clear();
+
+    SwDocShell* pDestinationShell = createDoc()->GetDocShell();
+
+    // Not classified source, not classified destination.
+    CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::None), int(SfxClassificationHelper::CheckPaste(*pSourceShell, *pDestinationShell)));
+
+    // Classified source, not classified destination.
+    uno::Sequence<beans::PropertyValue> aInternalOnly = comphelper::InitPropertySequence({{"Name", uno::makeAny(OUString("Internal Only"))}});
+    lcl_dispatchCommand(xSourceComponent, ".uno:ClassificationApply", aInternalOnly);
+    CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::TargetDocNotClassified), int(SfxClassificationHelper::CheckPaste(*pSourceShell, *pDestinationShell)));
+
+    // Classified source and classified destination -- internal only has a higher level than confidential.
+    uno::Sequence<beans::PropertyValue> aConfidential = comphelper::InitPropertySequence({{"Name", uno::makeAny(OUString("Confidential"))}});
+    lcl_dispatchCommand(mxComponent, ".uno:ClassificationApply", aConfidential);
+    CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::DocClassificationTooLow), int(SfxClassificationHelper::CheckPaste(*pSourceShell, *pDestinationShell)));
+
+    xSourceComponent->dispose();
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwUiWriterTest);
 CPPUNIT_PLUGIN_IMPLEMENT();
 
commit 76e2cede5a415df8d3e7a874f56be7a0b5953e12
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Mar 9 10:58:25 2016 +0100

    Move copy/paste classification check from sw to sfx2
    
    So that it's easy to unit test it and other apps can use it as well in
    the future.
    
    Change-Id: I38d601924b7fbb17615ff6e9c031a71b40777c4c

diff --git a/include/sfx2/classificationhelper.hxx b/include/sfx2/classificationhelper.hxx
index 5c49db7..5a58fcc 100644
--- a/include/sfx2/classificationhelper.hxx
+++ b/include/sfx2/classificationhelper.hxx
@@ -23,6 +23,14 @@ namespace basegfx
 class BColor;
 }
 
+/// Return code of SfxClassificationHelper::CheckPaste().
+enum class SfxClassificationCheckPasteResult
+{
+    None = 1,
+    TargetDocNotClassified = 2,
+    DocClassificationTooLow = 3
+};
+
 /// Shared code to handle Business Authorization Identification and Labeling Scheme (BAILS) properties.
 class SFX2_DLLPUBLIC SfxClassificationHelper
 {
@@ -32,6 +40,8 @@ class SFX2_DLLPUBLIC SfxClassificationHelper
 public:
     /// Does the document have any BAILS properties?
     static bool IsClassified(SfxObjectShell& rObjectShell);
+    /// Checks if pasting from rSource to rDestination would leak information.
+    static SfxClassificationCheckPasteResult CheckPaste(SfxObjectShell& rSource, SfxObjectShell& rDestination);
 
     SfxClassificationHelper(SfxObjectShell& rObjectShell);
     ~SfxClassificationHelper();
diff --git a/sfx2/source/view/classificationhelper.cxx b/sfx2/source/view/classificationhelper.cxx
index ab913b5..6950048 100644
--- a/sfx2/source/view/classificationhelper.cxx
+++ b/sfx2/source/view/classificationhelper.cxx
@@ -426,6 +426,35 @@ bool SfxClassificationHelper::IsClassified(SfxObjectShell& rObjectShell)
     return false;
 }
 
+SfxClassificationCheckPasteResult SfxClassificationHelper::CheckPaste(SfxObjectShell& rSource, SfxObjectShell& rDestination)
+{
+    bool bSourceClassified = SfxClassificationHelper::IsClassified(rSource);
+    if (!bSourceClassified)
+        // No classification on the source side. Return early, regardless the
+        // state of the destination side.
+        return SfxClassificationCheckPasteResult::None;
+
+    bool bDestinationClassified = SfxClassificationHelper::IsClassified(rDestination);
+    if (bSourceClassified && !bDestinationClassified)
+    {
+        // Paste from a classified document to a non-classified one -> deny.
+        return SfxClassificationCheckPasteResult::TargetDocNotClassified;
+    }
+
+    // Remaining case: paste between two classified documents.
+    SfxClassificationHelper aSource(rSource);
+    SfxClassificationHelper aDestination(rDestination);
+    if (aSource.GetImpactScale() != aDestination.GetImpactScale())
+        // It's possible to compare them if they have the same scale.
+        return SfxClassificationCheckPasteResult::None;
+
+    if (aSource.GetImpactLevel() > aDestination.GetImpactLevel())
+        // Paste from a doc that has higher classification -> deny.
+        return SfxClassificationCheckPasteResult::DocClassificationTooLow;
+
+    return SfxClassificationCheckPasteResult::None;
+}
+
 SfxClassificationHelper::SfxClassificationHelper(SfxObjectShell& rObjectShell)
     : m_pImpl(o3tl::make_unique<Impl>(rObjectShell))
 {
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index 04c3ae1..fb46de91 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -3222,33 +3222,26 @@ bool lcl_checkClassification(SwDoc* pSourceDoc, SwDoc* pDestinationDoc)
     if (!pSourceShell || !pDestinationShell)
         return true;
 
-    bool bSourceClassified = SfxClassificationHelper::IsClassified(*pSourceShell);
-    if (!bSourceClassified)
-        // No classification on the source side. Return early, regardless the
-        // state of the destination side.
+    switch (SfxClassificationHelper::CheckPaste(*pSourceShell, *pDestinationShell))
+    {
+    case SfxClassificationCheckPasteResult::None:
+    {
         return true;
-
-    bool bDestinationClassified = SfxClassificationHelper::IsClassified(*pDestinationShell);
-    if (bSourceClassified && !bDestinationClassified)
+    }
+    break;
+    case SfxClassificationCheckPasteResult::TargetDocNotClassified:
     {
-        // Paste from a classified document to a non-classified one -> deny.
         ScopedVclPtrInstance<MessageDialog>::Create(nullptr, SW_RES(STR_TARGET_DOC_NOT_CLASSIFIED), VCL_MESSAGE_INFO)->Execute();
         return false;
     }
-
-    // Remaining case: paste between two classified documents.
-    SfxClassificationHelper aSource(*pSourceShell);
-    SfxClassificationHelper aDestination(*pDestinationShell);
-    if (aSource.GetImpactScale() != aDestination.GetImpactScale())
-        // It's possible to compare them if they have the same scale.
-        return true;
-
-    if (aSource.GetImpactLevel() > aDestination.GetImpactLevel())
+    break;
+    case SfxClassificationCheckPasteResult::DocClassificationTooLow:
     {
-        // Paste from a doc that has higher classification -> deny.
         ScopedVclPtrInstance<MessageDialog>::Create(nullptr, SW_RES(STR_DOC_CLASSIFICATION_TOO_LOW), VCL_MESSAGE_INFO)->Execute();
         return false;
     }
+    break;
+    }
 
     return true;
 }


More information about the Libreoffice-commits mailing list