summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/vcl/filter/pdfdocument.hxx4
-rw-r--r--vcl/source/filter/ipdf/pdfdocument.cxx37
-rw-r--r--xmlsecurity/qa/unit/pdfsigning/data/tdf107149.pdf97
-rw-r--r--xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx6
4 files changed, 141 insertions, 3 deletions
diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx
index d83cb8308f11..5011504f13df 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -308,6 +308,10 @@ class VCL_DLLPUBLIC PDFDocument
std::map<size_t, PDFObjectElement*> m_aIDObjects;
/// List of xref offsets we know.
std::vector<size_t> m_aStartXRefs;
+ /// Offsets of trailers, from latest to oldest.
+ std::vector<size_t> m_aTrailerOffsets;
+ /// Trailer offset <-> Trailer pointer map.
+ std::map<size_t, PDFTrailerElement*> m_aOffsetTrailers;
/// List of EOF offsets we know.
std::vector<size_t> m_aEOFs;
PDFTrailerElement* m_pTrailer;
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index b0bb8be6c93e..105800974532 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -112,11 +112,14 @@ class PDFTrailerElement : public PDFElement
{
PDFDocument& m_rDoc;
std::map<OString, PDFElement*> m_aDictionary;
+ /// Location of the end of the trailer token.
+ sal_uInt64 m_nOffset = 0;
public:
explicit PDFTrailerElement(PDFDocument& rDoc);
bool Read(SvStream& rStream) override;
PDFElement* Lookup(const OString& rDictionaryKey);
+ sal_uInt64 GetLocation() const;
};
XRefEntry::XRefEntry()
@@ -1176,6 +1179,11 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s
else if (aKeyword == "trailer")
{
auto pTrailer = new PDFTrailerElement(*this);
+
+ // Make it possible to find this trailer later by offset.
+ pTrailer->Read(rStream);
+ m_aOffsetTrailers[pTrailer->GetLocation()] = pTrailer;
+
// When reading till the first EOF token only, remember
// just the first trailer token.
if (eMode != TokenizeMode::EOF_TOKEN || !m_pTrailer)
@@ -1261,7 +1269,13 @@ bool PDFDocument::Read(SvStream& rStream)
PDFNumberElement* pPrev = nullptr;
if (m_pTrailer)
+ {
pPrev = dynamic_cast<PDFNumberElement*>(m_pTrailer->Lookup("Prev"));
+
+ // Remember the offset of this trailer in the correct order. It's
+ // possible that newer trailers don't have a larger offset.
+ m_aTrailerOffsets.push_back(m_pTrailer->GetLocation());
+ }
else if (m_pXRefStream)
pPrev = dynamic_cast<PDFNumberElement*>(m_pXRefStream->Lookup("Prev"));
if (pPrev)
@@ -1788,8 +1802,20 @@ std::vector<PDFObjectElement*> PDFDocument::GetPages()
std::vector<PDFObjectElement*> aRet;
PDFReferenceElement* pRoot = nullptr;
- if (m_pTrailer)
- pRoot = dynamic_cast<PDFReferenceElement*>(m_pTrailer->Lookup("Root"));
+
+
+ PDFTrailerElement* pTrailer = nullptr;
+ if (!m_aTrailerOffsets.empty())
+ {
+ // Get access to the latest trailer, and work with the keys of that
+ // one.
+ auto it = m_aOffsetTrailers.find(m_aTrailerOffsets[0]);
+ if (it != m_aOffsetTrailers.end())
+ pTrailer = it->second;
+ }
+
+ if (pTrailer)
+ pRoot = dynamic_cast<PDFReferenceElement*>(pTrailer->Lookup("Root"));
else if (m_pXRefStream)
pRoot = dynamic_cast<PDFReferenceElement*>(m_pXRefStream->Lookup("Root"));
@@ -2085,8 +2111,9 @@ PDFTrailerElement::PDFTrailerElement(PDFDocument& rDoc)
{
}
-bool PDFTrailerElement::Read(SvStream& /*rStream*/)
+bool PDFTrailerElement::Read(SvStream& rStream)
{
+ m_nOffset = rStream.Tell();
return true;
}
@@ -2098,6 +2125,10 @@ PDFElement* PDFTrailerElement::Lookup(const OString& rDictionaryKey)
return PDFDictionaryElement::Lookup(m_aDictionary, rDictionaryKey);
}
+sal_uInt64 PDFTrailerElement::GetLocation() const
+{
+ return m_nOffset;
+}
double PDFNumberElement::GetValue() const
{
diff --git a/xmlsecurity/qa/unit/pdfsigning/data/tdf107149.pdf b/xmlsecurity/qa/unit/pdfsigning/data/tdf107149.pdf
new file mode 100644
index 000000000000..db063f366a93
--- /dev/null
+++ b/xmlsecurity/qa/unit/pdfsigning/data/tdf107149.pdf
@@ -0,0 +1,97 @@
+%PDF-1.2
+%
+3 0 obj
+<<
+/Length 61
+>>
+stream
+ BT
+ /F1 24 Tf
+ 1 0 0 1 260 254 Tm
+ (Hello Worl2)Tj
+ ET
+
+endstream
+endobj xref
+0 7
+0000000000 65535 f
+0000000312 00000 n
+0000000532 00000 n
+0000000015 00000 n
+0000000660 00000 n
+0000000578 00000 n
+0000000743 00000 n
+trailer
+
+<<
+/Root 6 0 R
+/Size 7
+>>
+1 0 obj
+<<
+/Resources 2 0 R
+/Contents 3 0 R
+/Parent 4 0 R
+/Type /Page
+/MediaBox [0 0 612 446]
+>>
+endobj
+3 0 obj
+<<
+/Length 61
+>>
+stream
+ BT
+ /F1 24 Tf
+ 1 0 0 1 260 254 Tm
+ (Hello World)Tj
+ ET
+
+endstream
+endobj
+2 0 obj
+<<
+/Font
+<<
+/F1 5 0 R
+>>
+>>
+endobj
+5 0 obj
+<<
+/Subtype /Type1
+/Name /F1
+/Type /Font
+/BaseFont /Helvetica
+>>
+endobj
+4 0 obj
+<<
+/Kids [1 0 R]
+/Type /Pages
+/MediaBox [0 0 612 446]
+/Count 1
+>>
+endobj
+6 0 obj
+<<
+/Type /Catalog
+/Pages 4 0 R
+>>
+endobj xref
+0 7
+0000000000 65535 f
+0000000015 00000 n
+0000000235 00000 n
+0000000121 00000 n
+0000000363 00000 n
+0000000281 00000 n
+0000000446 00000 n
+trailer
+
+<<
+/Size 7
+>>
+startxref
+128
+%%EOF
diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
index 05f8517ffec3..7462be32882a 100644
--- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
+++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
@@ -395,6 +395,7 @@ void PDFSigningTest::testTokenize()
"noeol.pdf",
// File that's intentionally smaller than 1024 bytes.
"small.pdf",
+ "tdf107149.pdf",
};
for (const auto& rName : aNames)
@@ -403,6 +404,11 @@ void PDFSigningTest::testTokenize()
vcl::filter::PDFDocument aDocument;
// Just make sure the tokenizer finishes without an error, don't look at the signature.
CPPUNIT_ASSERT(aDocument.Read(aStream));
+
+ OUString aNoPages("tdf107149.pdf");
+ if (aNoPages == rName)
+ // This failed, page list was empty.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aDocument.GetPages().size());
}
}