comphelper/source/misc/sequenceashashmap.cxx              |  137 ++++++++++++++
 desktop/source/lib/init.cxx                               |  123 ------------
 filter/source/pdf/pdffilter.cxx                           |   13 +
 include/comphelper/propertysequence.hxx                   |    6 
 vcl/qa/cppunit/pdfexport/data/link-wrong-page-partial.odg |binary
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                    |   21 ++
 6 files changed, 178 insertions(+), 122 deletions(-)

New commits:
commit c5c0ba7a87b5ad8f2d9314d9685c755546de0117
Author:     Miklos Vajna <[email protected]>
AuthorDate: Mon Jan 24 08:28:21 2022 +0100
Commit:     Mike Kaganski <[email protected]>
CommitDate: Tue Feb 1 09:07:55 2022 +0100

    PDF export: allow setting filter data keys from the cmdline
    
    Follow-up improvement to commit 3eb9eb9906c9 (lok: add pdf version
    option for export, 2021-11-15), possibilities are endless.
    
    For example, to skip the first page of a Draw document:
    
    soffice --convert-to 
'pdf:draw_pdf_Export:{"PageRange":{"type":"string","value":"2-"}}' test.odg
    
    Add watermark:
    
    soffice --convert-to 
'pdf:draw_pdf_Export:{"TiledWatermark":{"type":"string","value":"draft"}}' 
test.odg
    
    Encrypt:
    
    soffice --convert-to 
'pdf:draw_pdf_Export:{"EncryptFile":{"type":"boolean","value":"true"},"DocumentOpenPassword":{"type":"string","value":"secret"}}'
 test.odg
    
    Version 1.5 (instead of the default 1.6):
    
    soffice --convert-to 
'pdf:draw_pdf_Export:{"SelectPdfVersion":{"type":"long","value":"15"}}' test.odg
    
    The cost of the verbose syntax is probably smaller than the benefit of
    having this 1:1 mapping from string to PropertyValues.
    
    (cherry picked from commit 0c3b8792b712e939d2ad524d554f96616b4844be)
    
    Change-Id: I2093a3a787a9578dd02a154593b7a020f4a0ba31
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129225
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/filter/source/pdf/pdffilter.cxx b/filter/source/pdf/pdffilter.cxx
index 3bdc5a8cb756..c38c12df0a08 100644
--- a/filter/source/pdf/pdffilter.cxx
+++ b/filter/source/pdf/pdffilter.cxx
@@ -30,6 +30,9 @@
 
 #include <com/sun/star/io/XOutputStream.hpp>
 
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+
 using namespace ::com::sun::star::io;
 
 PDFFilter::PDFFilter( const Reference< XComponentContext > &rxContext ) :
@@ -47,6 +50,7 @@ bool PDFFilter::implExport( const Sequence< PropertyValue >& 
rDescriptor )
 {
     Reference< XOutputStream >  xOStm;
     Sequence< PropertyValue >   aFilterData;
+    OUString aFilterOptions;
     sal_Int32                   nLength = rDescriptor.getLength();
     const PropertyValue*        pValue = rDescriptor.getConstArray();
     bool                        bIsRedactMode = false;
@@ -60,6 +64,8 @@ bool PDFFilter::implExport( const Sequence< PropertyValue >& 
rDescriptor )
             pValue[ i ].Value >>= xOStm;
         else if ( pValue[ i ].Name == "FilterData" )
             pValue[ i ].Value >>= aFilterData;
+        else if ( pValue[ i ].Name == "FilterOptions" )
+            pValue[ i ].Value >>= aFilterOptions;
         else if ( pValue[ i ].Name == "StatusIndicator" )
             pValue[ i ].Value >>= xStatusIndicator;
         else if ( pValue[i].Name == "InteractionHandler" )
@@ -72,6 +78,13 @@ bool PDFFilter::implExport( const Sequence< PropertyValue >& 
rDescriptor )
             pValue[i].Value >>= bIsRedactMode;
     }
 
+    if (!aFilterData.hasElements() && !aFilterOptions.isEmpty())
+    {
+        // Allow setting filter data keys from the cmdline.
+        std::vector<PropertyValue> aData = 
comphelper::JsonToPropertyValues(aFilterOptions.toUtf8());
+        aFilterData = comphelper::containerToSequence(aData);
+    }
+
     /* we don't get FilterData if we are exporting directly
        to pdf, but we have to use the last user settings (especially for the 
CompressMode) */
     if ( !aFilterData.hasElements() )
diff --git a/vcl/qa/cppunit/pdfexport/data/link-wrong-page-partial.odg 
b/vcl/qa/cppunit/pdfexport/data/link-wrong-page-partial.odg
new file mode 100644
index 000000000000..1fad913e0493
Binary files /dev/null and 
b/vcl/qa/cppunit/pdfexport/data/link-wrong-page-partial.odg differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index ba1468af5253..b6908df15184 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -1942,6 +1942,27 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testLinkWrongPage)
     CPPUNIT_ASSERT(!HasLinksOnPage(pPdfPage2));
 }
 
+CPPUNIT_TEST_FIXTURE(PdfExportTest, testPageRange)
+{
+    // Given a document with 3 pages:
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"link-wrong-page-partial.odg";
+
+    // When exporting that document to PDF, skipping the first page:
+    utl::MediaDescriptor aMediaDescriptor;
+    aMediaDescriptor["FilterName"] <<= OUString("draw_pdf_Export");
+    aMediaDescriptor["FilterOptions"]
+        <<= OUString("{\"PageRange\":{\"type\":\"string\",\"value\":\"2-\"}}");
+    std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = 
exportAndParse(aURL, aMediaDescriptor);
+
+    // Then make sure the resulting PDF has 2 pages:
+    CPPUNIT_ASSERT(pPdfDocument);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2
+    // - Actual  : 3
+    // i.e. FilterOptions was ignored.
+    CPPUNIT_ASSERT_EQUAL(2, pPdfDocument->getPageCount());
+}
+
 CPPUNIT_TEST_FIXTURE(PdfExportTest, testLargePage)
 {
     // Import the bugdoc and export as PDF.
commit 0ade7309e774e48a2074d09765856b78d5f72067
Author:     Miklos Vajna <[email protected]>
AuthorDate: Thu Jan 20 21:02:35 2022 +0100
Commit:     Mike Kaganski <[email protected]>
CommitDate: Tue Feb 1 09:07:43 2022 +0100

    comphelper: move JsonToPropertyValues() from desktop/
    
    Because filter/ code will need this in a bit, and that can't depend on
    desktop/.
    
    (cherry picked from commit 4871cae48c1c9f522a0c0cc85a852b0568ca31e6)
    
    Conflicts:
            desktop/source/lib/init.cxx
    
    Change-Id: I07f0f8ef30942a2d11388c6721c7f277e117bfba
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129224
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/comphelper/source/misc/sequenceashashmap.cxx 
b/comphelper/source/misc/sequenceashashmap.cxx
index eb78e60c55d2..c6ac57326935 100644
--- a/comphelper/source/misc/sequenceashashmap.cxx
+++ b/comphelper/source/misc/sequenceashashmap.cxx
@@ -19,11 +19,82 @@
 
 #include <sal/config.h>
 
+#include <boost/property_tree/json_parser.hpp>
+
 #include <com/sun/star/beans/NamedValue.hpp>
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/reflection/XIdlField.hpp>
+#include <com/sun/star/reflection/theCoreReflection.hpp>
 #include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <sal/log.hxx>
+
+using namespace com::sun::star;
 
+namespace
+{
+uno::Any jsonToUnoAny(const boost::property_tree::ptree& aTree)
+{
+    uno::Any aAny;
+    uno::Any aValue;
+    sal_Int32 nFields;
+    uno::Reference<reflection::XIdlField> aField;
+    boost::property_tree::ptree aNodeNull, aNodeValue, aNodeField;
+    const std::string& rType = aTree.get<std::string>("type", "");
+    const std::string& rValue = aTree.get<std::string>("value", "");
+    uno::Sequence<uno::Reference<reflection::XIdlField>> aFields;
+    uno::Reference<reflection::XIdlClass> xIdlClass
+        = 
css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())
+              ->forName(OUString::fromUtf8(rType.c_str()));
+    if (xIdlClass.is())
+    {
+        uno::TypeClass aTypeClass = xIdlClass->getTypeClass();
+        xIdlClass->createObject(aAny);
+        aFields = xIdlClass->getFields();
+        nFields = aFields.getLength();
+        aNodeValue = aTree.get_child("value", aNodeNull);
+        if (nFields > 0 && aNodeValue != aNodeNull)
+        {
+            for (sal_Int32 itField = 0; itField < nFields; ++itField)
+            {
+                aField = aFields[itField];
+                aNodeField = 
aNodeValue.get_child(aField->getName().toUtf8().getStr(), aNodeNull);
+                if (aNodeField != aNodeNull)
+                {
+                    aValue = jsonToUnoAny(aNodeField);
+                    aField->set(aAny, aValue);
+                }
+            }
+        }
+        else if (!rValue.empty())
+        {
+            if (aTypeClass == uno::TypeClass_VOID)
+                aAny.clear();
+            else if (aTypeClass == uno::TypeClass_BYTE)
+                aAny <<= 
static_cast<sal_Int8>(OString(rValue.c_str()).toInt32());
+            else if (aTypeClass == uno::TypeClass_BOOLEAN)
+                aAny <<= OString(rValue.c_str()).toBoolean();
+            else if (aTypeClass == uno::TypeClass_SHORT)
+                aAny <<= 
static_cast<sal_Int16>(OString(rValue.c_str()).toInt32());
+            else if (aTypeClass == uno::TypeClass_UNSIGNED_SHORT)
+                aAny <<= 
static_cast<sal_uInt16>(OString(rValue.c_str()).toUInt32());
+            else if (aTypeClass == uno::TypeClass_LONG)
+                aAny <<= OString(rValue.c_str()).toInt32();
+            else if (aTypeClass == uno::TypeClass_UNSIGNED_LONG)
+                aAny <<= 
static_cast<sal_uInt32>(OString(rValue.c_str()).toInt32());
+            else if (aTypeClass == uno::TypeClass_FLOAT)
+                aAny <<= OString(rValue.c_str()).toFloat();
+            else if (aTypeClass == uno::TypeClass_DOUBLE)
+                aAny <<= OString(rValue.c_str()).toDouble();
+            else if (aTypeClass == uno::TypeClass_STRING)
+                aAny <<= OUString::fromUtf8(rValue.c_str());
+        }
+    }
+    return aAny;
+}
+}
 
 namespace comphelper{
 
@@ -234,6 +305,72 @@ void SequenceAsHashMap::update(const SequenceAsHashMap& 
rUpdate)
     }
 }
 
+std::vector<css::beans::PropertyValue> JsonToPropertyValues(const OString& 
rJson)
+{
+    std::vector<beans::PropertyValue> aArguments;
+    boost::property_tree::ptree aTree, aNodeNull, aNodeValue;
+    std::stringstream aStream(rJson.getStr());
+    boost::property_tree::read_json(aStream, aTree);
+
+    for (const auto& rPair : aTree)
+    {
+        const std::string& rType = rPair.second.get<std::string>("type", "");
+        const std::string& rValue = rPair.second.get<std::string>("value", "");
+
+        beans::PropertyValue aValue;
+        aValue.Name = OUString::fromUtf8(rPair.first.c_str());
+        if (rType == "string")
+            aValue.Value <<= OUString::fromUtf8(rValue.c_str());
+        else if (rType == "boolean")
+            aValue.Value <<= OString(rValue.c_str()).toBoolean();
+        else if (rType == "float")
+            aValue.Value <<= OString(rValue.c_str()).toFloat();
+        else if (rType == "long")
+            aValue.Value <<= OString(rValue.c_str()).toInt32();
+        else if (rType == "short")
+            aValue.Value <<= sal_Int16(OString(rValue.c_str()).toInt32());
+        else if (rType == "unsigned short")
+            aValue.Value <<= sal_uInt16(OString(rValue.c_str()).toUInt32());
+        else if (rType == "int64")
+            aValue.Value <<= OString(rValue.c_str()).toInt64();
+        else if (rType == "int32")
+            aValue.Value <<= OString(rValue.c_str()).toInt32();
+        else if (rType == "int16")
+            aValue.Value <<= sal_Int16(OString(rValue.c_str()).toInt32());
+        else if (rType == "uint64")
+            aValue.Value <<= OString(rValue.c_str()).toUInt64();
+        else if (rType == "uint32")
+            aValue.Value <<= OString(rValue.c_str()).toUInt32();
+        else if (rType == "uint16")
+            aValue.Value <<= sal_uInt16(OString(rValue.c_str()).toUInt32());
+        else if (rType == "[]byte")
+        {
+            aNodeValue = rPair.second.get_child("value", aNodeNull);
+            if (aNodeValue != aNodeNull && aNodeValue.size() == 0)
+            {
+                uno::Sequence<sal_Int8> aSeqByte(reinterpret_cast<const 
sal_Int8*>(rValue.c_str()),
+                                                 rValue.size());
+                aValue.Value <<= aSeqByte;
+            }
+        }
+        else if (rType == "[]any")
+        {
+            aNodeValue = rPair.second.get_child("value", aNodeNull);
+            if (aNodeValue != aNodeNull && !aNodeValue.empty())
+            {
+                uno::Sequence<uno::Any> aSeq(aNodeValue.size());
+                std::transform(aNodeValue.begin(), aNodeValue.end(), 
aSeq.getArray(),
+                               [](const auto& rSeqPair) { return 
jsonToUnoAny(rSeqPair.second); });
+                aValue.Value <<= aSeq;
+            }
+        }
+        else
+            SAL_WARN("comphelper", "JsonToPropertyValues: unhandled type '" << 
rType << "'");
+        aArguments.push_back(aValue);
+    }
+    return aArguments;
+}
+
 } // namespace comphelper
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 9ae83863d341..1c2952ab8953 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -73,9 +73,6 @@
 #include <com/sun/star/lang/Locale.hpp>
 #include <com/sun/star/lang/XComponent.hpp>
 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
-#include <com/sun/star/reflection/theCoreReflection.hpp>
-#include <com/sun/star/reflection/XIdlClass.hpp>
-#include <com/sun/star/reflection/XIdlReflection.hpp>
 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
 #include <com/sun/star/util/URLTransformer.hpp>
 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
@@ -372,130 +369,12 @@ static OUString getAbsoluteURL(const char* pURL)
     return OUString();
 }
 
-static uno::Any jsonToUnoAny(const boost::property_tree::ptree& aTree)
-{
-    uno::Any aAny;
-    uno::Any aValue;
-    sal_Int32 nFields;
-    uno::Reference< reflection::XIdlField > aField;
-    boost::property_tree::ptree aNodeNull, aNodeValue, aNodeField;
-    const std::string& rType = aTree.get<std::string>("type", "");
-    const std::string& rValue = aTree.get<std::string>("value", "");
-    uno::Sequence< uno::Reference< reflection::XIdlField > > aFields;
-    uno::Reference< reflection:: XIdlClass > xIdlClass =
-        
css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())->forName(OUString::fromUtf8(rType.c_str()));
-    if (xIdlClass.is())
-    {
-        uno::TypeClass aTypeClass = xIdlClass->getTypeClass();
-        xIdlClass->createObject(aAny);
-        aFields = xIdlClass->getFields();
-        nFields = aFields.getLength();
-        aNodeValue = aTree.get_child("value", aNodeNull);
-        if (nFields > 0 && aNodeValue != aNodeNull)
-        {
-            for (sal_Int32 itField = 0; itField < nFields; ++itField)
-            {
-                aField = aFields[itField];
-                aNodeField = 
aNodeValue.get_child(aField->getName().toUtf8().getStr(), aNodeNull);
-                if (aNodeField != aNodeNull)
-                {
-                    aValue = jsonToUnoAny(aNodeField);
-                    aField->set(aAny, aValue);
-                }
-            }
-        }
-        else if (!rValue.empty())
-        {
-            if (aTypeClass == uno::TypeClass_VOID)
-                aAny.clear();
-            else if (aTypeClass == uno::TypeClass_BYTE)
-                aAny <<= 
static_cast<sal_Int8>(OString(rValue.c_str()).toInt32());
-            else if (aTypeClass == uno::TypeClass_BOOLEAN)
-                aAny <<= OString(rValue.c_str()).toBoolean();
-            else if (aTypeClass == uno::TypeClass_SHORT)
-                aAny <<= 
static_cast<sal_Int16>(OString(rValue.c_str()).toInt32());
-            else if (aTypeClass == uno::TypeClass_UNSIGNED_SHORT)
-                aAny <<= 
static_cast<sal_uInt16>(OString(rValue.c_str()).toUInt32());
-            else if (aTypeClass == uno::TypeClass_LONG)
-                aAny <<= OString(rValue.c_str()).toInt32();
-            else if (aTypeClass == uno::TypeClass_UNSIGNED_LONG)
-                aAny <<= 
static_cast<sal_uInt32>(OString(rValue.c_str()).toInt32());
-            else if (aTypeClass == uno::TypeClass_FLOAT)
-                aAny <<= OString(rValue.c_str()).toFloat();
-            else if (aTypeClass == uno::TypeClass_DOUBLE)
-                aAny <<= OString(rValue.c_str()).toDouble();
-            else if (aTypeClass == uno::TypeClass_STRING)
-                aAny <<= OUString::fromUtf8(rValue.c_str());
-        }
-    }
-    return aAny;
-}
-
 std::vector<beans::PropertyValue> desktop::jsonToPropertyValuesVector(const 
char* pJSON)
 {
     std::vector<beans::PropertyValue> aArguments;
     if (pJSON && pJSON[0] != '\0')
     {
-        boost::property_tree::ptree aTree, aNodeNull, aNodeValue;
-        std::stringstream aStream(pJSON);
-        boost::property_tree::read_json(aStream, aTree);
-
-        for (const auto& rPair : aTree)
-        {
-            const std::string& rType = rPair.second.get<std::string>("type", 
"");
-            const std::string& rValue = rPair.second.get<std::string>("value", 
"");
-
-            beans::PropertyValue aValue;
-            aValue.Name = OUString::fromUtf8(rPair.first.c_str());
-            if (rType == "string")
-                aValue.Value <<= OUString::fromUtf8(rValue.c_str());
-            else if (rType == "boolean")
-                aValue.Value <<= OString(rValue.c_str()).toBoolean();
-            else if (rType == "float")
-                aValue.Value <<= OString(rValue.c_str()).toFloat();
-            else if (rType == "long")
-                aValue.Value <<= OString(rValue.c_str()).toInt32();
-            else if (rType == "short")
-                aValue.Value <<= sal_Int16(OString(rValue.c_str()).toInt32());
-            else if (rType == "unsigned short")
-                aValue.Value <<= 
sal_uInt16(OString(rValue.c_str()).toUInt32());
-            else if (rType == "int64")
-                aValue.Value <<= OString(rValue.c_str()).toInt64();
-            else if (rType == "int32")
-                aValue.Value <<= OString(rValue.c_str()).toInt32();
-            else if (rType == "int16")
-                aValue.Value <<= sal_Int16(OString(rValue.c_str()).toInt32());
-            else if (rType == "uint64")
-                aValue.Value <<= OString(rValue.c_str()).toUInt64();
-            else if (rType == "uint32")
-                aValue.Value <<= OString(rValue.c_str()).toUInt32();
-            else if (rType == "uint16")
-                aValue.Value <<= 
sal_uInt16(OString(rValue.c_str()).toUInt32());
-            else if (rType == "[]byte")
-            {
-                aNodeValue = rPair.second.get_child("value", aNodeNull);
-                if (aNodeValue != aNodeNull && aNodeValue.size() == 0)
-                {
-                    uno::Sequence< sal_Int8 > aSeqByte(reinterpret_cast<const 
sal_Int8*>(rValue.c_str()), rValue.size());
-                    aValue.Value <<= aSeqByte;
-                }
-            }
-            else if (rType == "[]any")
-            {
-                aNodeValue = rPair.second.get_child("value", aNodeNull);
-                if (aNodeValue != aNodeNull && !aNodeValue.empty())
-                {
-                    sal_Int32 itSeq = 0;
-                    uno::Sequence< uno::Any > aSeq(aNodeValue.size());
-                    for (const auto& rSeqPair : aNodeValue)
-                        aSeq[itSeq++] = jsonToUnoAny(rSeqPair.second);
-                    aValue.Value <<= aSeq;
-                }
-            }
-            else
-                SAL_WARN("desktop.lib", "jsonToPropertyValuesVector: unhandled 
type '"<<rType<<"'");
-            aArguments.push_back(aValue);
-        }
+        aArguments = comphelper::JsonToPropertyValues(pJSON);
     }
     return aArguments;
 }
diff --git a/include/comphelper/propertysequence.hxx 
b/include/comphelper/propertysequence.hxx
index 3f9838f9ab8f..a73109b0ffa9 100644
--- a/include/comphelper/propertysequence.hxx
+++ b/include/comphelper/propertysequence.hxx
@@ -13,10 +13,14 @@
 #include <utility>
 #include <algorithm>
 #include <initializer_list>
+#include <vector>
+
 #include <com/sun/star/uno/Any.hxx>
 #include <com/sun/star/uno/Sequence.hxx>
 #include <com/sun/star/beans/PropertyValue.hpp>
 
+#include <comphelper/comphelperdllapi.h>
+
 namespace comphelper
 {
     /// Init list for property sequences.
@@ -48,6 +52,8 @@ namespace comphelper
                        });
         return vResult;
     }
+
+    COMPHELPER_DLLPUBLIC std::vector<css::beans::PropertyValue> 
JsonToPropertyValues(const OString& rJson);
 }   // namespace comphelper
 
 

Reply via email to