summaryrefslogtreecommitdiff
path: root/vcl/source/filter/ipdf/pdfdocument.cxx
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2017-04-13 18:09:32 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-04-14 00:11:06 +0200
commitf15a69bd57e578ca607f14cb62f29a16986b96e6 (patch)
tree015c67815618700d7b6b6723647752dc446157fe /vcl/source/filter/ipdf/pdfdocument.cxx
parentdf556aa47da22f96b3fcd356c12419d3035cba3c (diff)
vcl PDF import: don't assume larger offset -> newer trailer
Usually when the PDF file contains incremental updates the updates are appended at the end of the document. But this is not required, the various trailers can be in any order. Make sure that we look at the last trailer (logically last, not the one with the largest file offset) when looking for pages. Change-Id: Idcd85a7c6bbf08c9436dd73933d79cdb683f482c Reviewed-on: https://gerrit.libreoffice.org/36527 Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk> Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'vcl/source/filter/ipdf/pdfdocument.cxx')
-rw-r--r--vcl/source/filter/ipdf/pdfdocument.cxx37
1 files changed, 34 insertions, 3 deletions
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
{