summaryrefslogtreecommitdiffstats
path: root/vcl/qa/cppunit/filter/ipdf
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/qa/cppunit/filter/ipdf')
-rw-r--r--vcl/qa/cppunit/filter/ipdf/data/add-visible-signature-last-page.pdf111
-rw-r--r--vcl/qa/cppunit/filter/ipdf/data/comment-end.pdf69
-rw-r--r--vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf55
-rw-r--r--vcl/qa/cppunit/filter/ipdf/data/real-numbers.pdf55
-rw-r--r--vcl/qa/cppunit/filter/ipdf/ipdf.cxx208
5 files changed, 498 insertions, 0 deletions
diff --git a/vcl/qa/cppunit/filter/ipdf/data/add-visible-signature-last-page.pdf b/vcl/qa/cppunit/filter/ipdf/data/add-visible-signature-last-page.pdf
new file mode 100644
index 000000000..c321abd09
--- /dev/null
+++ b/vcl/qa/cppunit/filter/ipdf/data/add-visible-signature-last-page.pdf
@@ -0,0 +1,111 @@
+%PDF-1.6
+%äüöß
+2 0 obj
+<</Length 3 0 R/Filter/FlateDecode>>
+stream
+xTn1 ]K/I8Mg\\PԐnf2eڨpBIB2~#QwDɶƿ#gzKkMkRؼ7妁
++Rw 2Q#XQ˲sv`7Vܸ$}dFڜTXI+8+]HN+kC"Tta@+"]9ZY Rq a!O<ҫ
+d\)WiKO.H/\$ώga-/w- !9cDc
+ΩPqe:/ tqi08{{N10\N9UҸAoݵӏZ/_b7F߾ _a_t{!J@ACjl4#}ԍH뭷Gc;2?cQ@
+endstream
+endobj
+
+3 0 obj
+426
+endobj
+
+5 0 obj
+<</Length 6 0 R/Filter/FlateDecode>>
+stream
+x;1 D{qr$ZfO#Q#+r&x #Y Z}>a;zg6
+xn :d8 aQ^D,;7#M3qĵ1 Ɛ$}5+'pΏ5y^qYW]ٶuL#>"B
+endstream
+endobj
+
+6 0 obj
+167
+endobj
+
+8 0 obj
+<<
+>>
+endobj
+
+9 0 obj
+<</Font 8 0 R
+/ProcSet[/PDF/Text]
+>>
+endobj
+
+1 0 obj
+<</Type/Page/Parent 7 0 R/Resources 9 0 R/MediaBox[0 0 612 792]/Group<</S/Transparency/CS/DeviceRGB/I true>>/Contents 2 0 R>>
+endobj
+
+4 0 obj
+<</Type/Page/Parent 7 0 R/Resources 9 0 R/MediaBox[0 0 612 792]/Group<</S/Transparency/CS/DeviceRGB/I true>>/Contents 5 0 R>>
+endobj
+
+10 0 obj
+<</Count 2/First 11 0 R/Last 12 0 R
+>>
+endobj
+
+11 0 obj
+<</Count 0/Title<FEFF005000610067006500200031>
+/Dest[1 0 R/XYZ 0 792 0]/Parent 10 0 R/Next 12 0 R>>
+endobj
+
+12 0 obj
+<</Count 0/Title<FEFF005000610067006500200032>
+/Dest[4 0 R/XYZ 0 792 0]/Parent 10 0 R/Prev 11 0 R>>
+endobj
+
+7 0 obj
+<</Type/Pages
+/Resources 9 0 R
+/MediaBox[ 0 0 612 792 ]
+/Kids[ 1 0 R 4 0 R ]
+/Count 2>>
+endobj
+
+13 0 obj
+<</Type/Catalog/Pages 7 0 R
+/OpenAction[1 0 R /XYZ null null 0]
+/Outlines 10 0 R
+>>
+endobj
+
+14 0 obj
+<</Author<FEFF004D0069006B006C006F0073002000560061006A006E0061>
+/Creator<FEFF0044007200610077>
+/Producer<FEFF004C0069006200720065004F0066006600690063006500440065007600200037002E0031>
+/CreationDate(D:20200624113559+02'00')>>
+endobj
+
+xref
+0 15
+0000000000 65535 f
+0000000869 00000 n
+0000000019 00000 n
+0000000516 00000 n
+0000001011 00000 n
+0000000536 00000 n
+0000000774 00000 n
+0000001443 00000 n
+0000000794 00000 n
+0000000816 00000 n
+0000001153 00000 n
+0000001209 00000 n
+0000001326 00000 n
+0000001547 00000 n
+0000001648 00000 n
+trailer
+<</Size 15/Root 13 0 R
+/Info 14 0 R
+/ID [ <F52D3902B7388C216897409EFCC78884>
+<F52D3902B7388C216897409EFCC78884> ]
+/DocChecksum /67E881EB92900640250E0931504CE95E
+>>
+startxref
+1889
+%%EOF
diff --git a/vcl/qa/cppunit/filter/ipdf/data/comment-end.pdf b/vcl/qa/cppunit/filter/ipdf/data/comment-end.pdf
new file mode 100644
index 000000000..6f1ad86f5
--- /dev/null
+++ b/vcl/qa/cppunit/filter/ipdf/data/comment-end.pdf
@@ -0,0 +1,69 @@
+%PDF-1.7
+%
+1 0 obj <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+ /Type /Pages
+ /MediaBox [0 0 200 300]
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+>>
+endobj
+4 0 obj <<
+ /Length 4
+>>
+stream
+q
+Q
+endstream
+endobj
+xref
+0 5
+0000000000 65535 f
+0000000015 00000 n
+0000000068 00000 n
+0000000157 00000 n
+0000000226 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 5
+ /Prev 541
+>>
+startxref
+280
+%%EOF %%TEST
+4 0 obj <<
+ /Length 5 0 R
+>>
+stream
+q
+Q
+endstream
+endobj
+5 0 obj
+4
+endobj
+xref
+0 6
+0000000000 65535 f
+0000000015 00000 n
+0000000068 00000 n
+0000000157 00000 n
+0000000466 00000 n
+0000000524 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 6
+>>
+startxref
+280
+%%EOF
diff --git a/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf b/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf
new file mode 100644
index 000000000..73de3117b
--- /dev/null
+++ b/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf
@@ -0,0 +1,55 @@
+%PDF-1.7
+%
+1 0 obj <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+ /Type /Pages
+ /MediaBox [0 0 200 300]
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+ /Key[<</InnerKey 42>>]
+>>
+endobj
+4 0 obj <<
+ /Length 188
+>>
+stream
+q
+0 0 0 rg
+0 290 10 10 re B*
+10 150 50 30 re B*
+0 0 1 rg
+190 290 10 10 re B*
+70 232 50 30 re B*
+0 1 0 rg
+190 0 10 10 re B*
+130 150 50 30 re B*
+1 0 0 rg
+0 0 10 10 re B*
+70 67 50 30 re B*
+Q
+endstream
+endobj
+xref
+0 5
+0000000000 65535 f
+0000000015 00000 n
+0000000068 00000 n
+0000000157 00000 n
+0000000251 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 5
+>>
+startxref
+491
+%%EOF
diff --git a/vcl/qa/cppunit/filter/ipdf/data/real-numbers.pdf b/vcl/qa/cppunit/filter/ipdf/data/real-numbers.pdf
new file mode 100644
index 000000000..409360c54
--- /dev/null
+++ b/vcl/qa/cppunit/filter/ipdf/data/real-numbers.pdf
@@ -0,0 +1,55 @@
+%PDF-1.7
+%
+1 0 obj <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+ /Type /Pages
+ /MediaBox [0 0 200 300]
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+>>
+endobj
+4 0 obj <<
+ /Length 188
+ /Test [.00 1.00 .00 1.00 .00 1.00]
+>>
+stream
+q
+0 0 0 rg
+0 290 10 10 re B*
+10 150 50 30 re B*
+0 0 1 rg
+190 290 10 10 re B*
+70 232 50 30 re B*
+0 1 0 rg
+190 0 10 10 re B*
+130 150 50 30 re B*
+1 0 0 rg
+0 0 10 10 re B*
+70 67 50 30 re B*
+Q
+endstream
+endobj
+xref
+0 5
+0000000000 65535 f
+0000000015 00000 n
+0000000068 00000 n
+0000000157 00000 n
+0000000226 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 5
+>>
+startxref
+503
+%%EOF
diff --git a/vcl/qa/cppunit/filter/ipdf/ipdf.cxx b/vcl/qa/cppunit/filter/ipdf/ipdf.cxx
new file mode 100644
index 000000000..c34bb4794
--- /dev/null
+++ b/vcl/qa/cppunit/filter/ipdf/ipdf.cxx
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/security/XCertificate.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/xml/crypto/SEInitializer.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <osl/file.hxx>
+#include <unotools/tempfile.hxx>
+#include <sfx2/sfxbasemodel.hxx>
+#include <svx/svdview.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svx/signaturelinehelper.hxx>
+#include <sfx2/objsh.hxx>
+#include <vcl/filter/PDFiumLibrary.hxx>
+#include <vcl/filter/pdfdocument.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+constexpr OUStringLiteral DATA_DIRECTORY = u"/vcl/qa/cppunit/filter/ipdf/data/";
+}
+
+/// Covers vcl/source/filter/ipdf/ fixes.
+class VclFilterIpdfTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+ uno::Reference<xml::crypto::XSEInitializer> mxSEInitializer;
+ uno::Reference<xml::crypto::XXMLSecurityContext> mxSecurityContext;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+ uno::Reference<xml::crypto::XXMLSecurityContext>& getSecurityContext()
+ {
+ return mxSecurityContext;
+ }
+};
+
+void VclFilterIpdfTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+ MacrosTest::setUpNssGpg(m_directories, "vcl_filter_ipdf");
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+ mxSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext);
+ mxSecurityContext = mxSEInitializer->createSecurityContext(OUString());
+}
+
+void VclFilterIpdfTest::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ MacrosTest::tearDownNssGpg();
+ test::BootstrapFixture::tearDown();
+}
+
+CPPUNIT_TEST_FIXTURE(VclFilterIpdfTest, testPDFAddVisibleSignatureLastPage)
+{
+ // FIXME: the DPI check should be removed when either (1) the test is fixed to work with
+ // non-default DPI; or (2) unit tests on Windows are made to use svp VCL plugin.
+ if (!IsDefaultDPI())
+ return;
+ // Given: copy the test document to a temporary file, as it'll be modified.
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ OUString aSourceURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "add-visible-signature-last-page.pdf";
+ OUString aURL = aTempFile.GetURL();
+ osl::File::RC eRet = osl::File::copy(aSourceURL, aURL);
+ CPPUNIT_ASSERT_EQUAL(osl::File::RC::E_None, eRet);
+
+ // Open it.
+ uno::Sequence<beans::PropertyValue> aArgs = { comphelper::makePropertyValue("ReadOnly", true) };
+ getComponent() = loadFromDesktop(aURL, "com.sun.star.drawing.DrawingDocument", aArgs);
+ SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(getComponent().get());
+ CPPUNIT_ASSERT(pBaseModel);
+ SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+ CPPUNIT_ASSERT(pObjectShell);
+
+ // Add a signature line to the 2nd page.
+ uno::Reference<lang::XMultiServiceFactory> xFactory(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"), uno::UNO_QUERY);
+ xShape->setPosition(awt::Point(1000, 15000));
+ xShape->setSize(awt::Size(10000, 10000));
+ uno::Reference<drawing::XDrawPagesSupplier> xSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPages> xDrawPages = xSupplier->getDrawPages();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), xDrawPages->getCount());
+
+ uno::Reference<frame::XModel> xModel(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawView> xController(xModel->getCurrentController(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(1), uno::UNO_QUERY);
+ xController->setCurrentPage(xDrawPage);
+ xDrawPage->add(xShape);
+
+ // Select it and assign a certificate.
+ uno::Reference<view::XSelectionSupplier> xSelectionSupplier(pBaseModel->getCurrentController(),
+ uno::UNO_QUERY);
+ xSelectionSupplier->select(uno::Any(xShape));
+ auto xCert = GetValidCertificate(
+ getSecurityContext()->getSecurityEnvironment()->getPersonalCertificates());
+ if (!xCert)
+ {
+ return;
+ }
+ SdrView* pView = SfxViewShell::Current()->GetDrawView();
+ svx::SignatureLineHelper::setShapeCertificate(pView, xCert);
+
+ // When: do the actual signing.
+ pObjectShell->SignDocumentContentUsingCertificate(xCert);
+
+ // Then: count the # of shapes on the signature widget/annotation.
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ return;
+ SvFileStream aFile(aTempFile.GetURL(), StreamMode::READ);
+ SvMemoryStream aMemory;
+ aMemory.WriteStream(aFile);
+ // Last page.
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
+ = pPDFium->openDocument(aMemory.GetData(), aMemory.GetSize(), OString());
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/1);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the signature was there, but it was on the first page.
+ CPPUNIT_ASSERT_EQUAL(1, pPdfPage->getAnnotationCount());
+ std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnot = pPdfPage->getAnnotation(0);
+ CPPUNIT_ASSERT_EQUAL(4, pAnnot->getObjectCount());
+}
+
+CPPUNIT_TEST_FIXTURE(VclFilterIpdfTest, testDictArrayDict)
+{
+ // Load a file that has markup like this:
+ // 3 0 obj <<
+ // /Key[<</InnerKey 42>>]
+ // >>
+ OUString aSourceURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "dict-array-dict.pdf";
+ SvFileStream aFile(aSourceURL, StreamMode::READ);
+ vcl::filter::PDFDocument aDocument;
+ CPPUNIT_ASSERT(aDocument.Read(aFile));
+ std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
+ CPPUNIT_ASSERT(!aPages.empty());
+ vcl::filter::PDFObjectElement* pPage = aPages[0];
+ auto pKey = dynamic_cast<vcl::filter::PDFArrayElement*>(pPage->Lookup("Key"));
+
+ // Without the accompanying fix in place, this test would have failed, because the value of Key
+ // was a dictionary element, not an array element.
+ CPPUNIT_ASSERT(pKey);
+}
+
+CPPUNIT_TEST_FIXTURE(VclFilterIpdfTest, testRealNumbers)
+{
+ // Load a file that has markup like this:
+ // 4 0 obj <<
+ // /Test [.00 1.00 .00 1.00 .00 1.00]
+ // >>
+ OUString aSourceURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "real-numbers.pdf";
+ SvFileStream aFile(aSourceURL, StreamMode::READ);
+ vcl::filter::PDFDocument aDocument;
+
+ // Without the accompanying fix in place, this test would have failed, because the parser
+ // stopped when it saw an unexpected "." character.
+ CPPUNIT_ASSERT(aDocument.Read(aFile));
+ std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
+ CPPUNIT_ASSERT(!aPages.empty());
+}
+
+CPPUNIT_TEST_FIXTURE(VclFilterIpdfTest, testCommentEnd)
+{
+ // Load the test document:
+ // - it has two xrefs
+ // - second xref has an updated page content object with an indirect length
+ // - last startxref refers to the first xref
+ // - first xref has a /Prev to the second xref
+ // - first xref is terminated by a \r, which is not followed by a newline
+ // this means that if reading doesn't stop at the end of the first xref, then we'll try to look
+ // up the offset of the length object, which we don't yet have
+ OUString aSourceURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "comment-end.pdf";
+ SvFileStream aFile(aSourceURL, StreamMode::READ);
+ vcl::filter::PDFDocument aDocument;
+
+ // Without the accompanying fix in place, this test would have failed, because Tokenize() didn't
+ // stop at the end of the first xref.
+ CPPUNIT_ASSERT(aDocument.Read(aFile));
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */