tdf#142129 vcl: add unit test
Reportedly bug was fixed by commit
5fc6a601d7a1978db291fd0f7dcec638a7c25651
Change-Id: Iee32cacff0c939bdf498e9dc8102eb2d22a5a1c9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121776
Tested-by: Michael Stahl <michael.stahl@allotropia.de>
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx
index 073225b..aae3b5a 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -546,6 +546,7 @@ public:
//@{
/// Decode a hex dump.
static std::vector<unsigned char> DecodeHexString(PDFHexStringElement const* pElement);
static OUString DecodeHexStringUTF16BE(PDFHexStringElement const& rElement);
static OString ReadKeyword(SvStream& rStream);
static size_t FindStartXRef(SvStream& rStream);
void ReadXRef(SvStream& rStream);
diff --git a/vcl/qa/cppunit/pdfexport/data/WG7100-Preface.odt b/vcl/qa/cppunit/pdfexport/data/WG7100-Preface.odt
new file mode 100644
index 0000000..05e2bb1
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/WG7100-Preface.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/master.odm b/vcl/qa/cppunit/pdfexport/data/master.odm
new file mode 100644
index 0000000..7401635
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/master.odm
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index bb20360..0da9bed 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -2791,6 +2791,93 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testPdfUaMetadata)
CPPUNIT_ASSERT_EQUAL(OString("1"), aPdfUaPart);
}
CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf142129)
{
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "master.odm";
mxComponent = loadFromDesktop(aURL);
// update linked section
dispatchCommand(mxComponent, ".uno:UpdateAllLinks", {});
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
utl::MediaDescriptor aMediaDescriptor;
aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
// Enable Outlines export
uno::Sequence<beans::PropertyValue> aFilterData(
comphelper::InitPropertySequence({ { "ExportBookmarks", uno::Any(true) } }));
aMediaDescriptor["FilterData"] <<= aFilterData;
xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
// Parse the export result.
vcl::filter::PDFDocument aDocument;
SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ);
CPPUNIT_ASSERT(aDocument.Read(aStream));
auto* pCatalog = aDocument.GetCatalog();
CPPUNIT_ASSERT(pCatalog);
auto* pCatalogDictionary = pCatalog->GetDictionary();
CPPUNIT_ASSERT(pCatalogDictionary);
auto* pOutlinesObject = pCatalogDictionary->LookupObject("Outlines");
CPPUNIT_ASSERT(pOutlinesObject);
auto* pOutlinesDictionary = pOutlinesObject->GetDictionary();
#if 0
// Type isn't actually written currently
auto* pType
= dynamic_cast<vcl::filter::PDFNameElement*>(pOutlinesDictionary->LookupElement("Type"));
CPPUNIT_ASSERT(pType);
CPPUNIT_ASSERT_EQUAL(OString("Outlines"), pType->GetValue());
#endif
auto* pFirst = dynamic_cast<vcl::filter::PDFReferenceElement*>(
pOutlinesDictionary->LookupElement("First"));
CPPUNIT_ASSERT(pFirst);
auto* pFirstD = pFirst->LookupObject()->GetDictionary();
CPPUNIT_ASSERT(pFirstD);
//CPPUNIT_ASSERT_EQUAL(OString("Outlines"), dynamic_cast<vcl::filter::PDFNameElement*>(pFirstD->LookupElement("Type"))->GetValue());
CPPUNIT_ASSERT_EQUAL(OUString(u"Preface"), ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
*dynamic_cast<vcl::filter::PDFHexStringElement*>(
pFirstD->LookupElement("Title"))));
auto* pFirst1
= dynamic_cast<vcl::filter::PDFReferenceElement*>(pFirstD->LookupElement("First"));
CPPUNIT_ASSERT(pFirst1);
auto* pFirst1D = pFirst1->LookupObject()->GetDictionary();
CPPUNIT_ASSERT(pFirst1D);
// here is a hidden section with headings "Copyright" etc.; check that
// there are no outline entries for it
//CPPUNIT_ASSERT_EQUAL(OString("Outlines"), dynamic_cast<vcl::filter::PDFNameElement*>(pFirst1D->LookupElement("Type"))->GetValue());
CPPUNIT_ASSERT_EQUAL(
OUString(u"Who is this book for?"),
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
*dynamic_cast<vcl::filter::PDFHexStringElement*>(pFirst1D->LookupElement("Title"))));
auto* pFirst2
= dynamic_cast<vcl::filter::PDFReferenceElement*>(pFirst1D->LookupElement("Next"));
auto* pFirst2D = pFirst2->LookupObject()->GetDictionary();
CPPUNIT_ASSERT(pFirst2D);
//CPPUNIT_ASSERT_EQUAL(OString("Outlines"), dynamic_cast<vcl::filter::PDFNameElement*>(pFirst2D->LookupElement("Type"))->GetValue());
CPPUNIT_ASSERT_EQUAL(
OUString(u"What\u2019s in this book?"),
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
*dynamic_cast<vcl::filter::PDFHexStringElement*>(pFirst2D->LookupElement("Title"))));
auto* pFirst3
= dynamic_cast<vcl::filter::PDFReferenceElement*>(pFirst2D->LookupElement("Next"));
auto* pFirst3D = pFirst3->LookupObject()->GetDictionary();
CPPUNIT_ASSERT(pFirst3D);
//CPPUNIT_ASSERT_EQUAL(OString("Outlines"), dynamic_cast<vcl::filter::PDFNameElement*>(pFirst3D->LookupElement("Type"))->GetValue());
CPPUNIT_ASSERT_EQUAL(
OUString(u"Minimum requirements for using LibreOffice"),
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
*dynamic_cast<vcl::filter::PDFHexStringElement*>(pFirst3D->LookupElement("Title"))));
CPPUNIT_ASSERT_EQUAL(static_cast<vcl::filter::PDFElement*>(nullptr),
pFirst3D->LookupElement("Next"));
CPPUNIT_ASSERT_EQUAL(static_cast<vcl::filter::PDFElement*>(nullptr),
pFirstD->LookupElement("Next"));
}
CPPUNIT_TEST_FIXTURE(PdfExportTest, testPdfImageRotate180)
{
// Create an empty document.
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index b8224b15..7e1a25e 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -2052,6 +2052,23 @@ std::vector<unsigned char> PDFDocument::DecodeHexString(PDFHexStringElement cons
return svl::crypto::DecodeHexString(pElement->GetValue());
}
OUString PDFDocument::DecodeHexStringUTF16BE(PDFHexStringElement const& rElement)
{
std::vector<unsigned char> const encoded(DecodeHexString(&rElement));
// Text strings can be PDF-DocEncoding or UTF-16BE with mandatory BOM;
// only the latter supported is here
if (encoded.size() < 2 || encoded[0] != 0xFE || encoded[1] != 0xFF || (encoded.size() & 1) != 0)
{
return OUString();
}
OUStringBuffer buf(static_cast<unsigned int>(encoded.size() - 2));
for (size_t i = 2; i < encoded.size(); i += 2)
{
buf.append(sal_Unicode((static_cast<sal_uInt16>(encoded[i]) << 8) | encoded[i + 1]));
}
return buf.makeStringAndClear();
}
PDFCommentElement::PDFCommentElement(PDFDocument& rDoc)
: m_rDoc(rDoc)
{