diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-03-28 16:14:11 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-03-28 15:52:49 +0000 |
commit | 30608c66374f8effa9d534f7f9a22d41daa9770f (patch) | |
tree | 9298896890717507fe01cdaf4545775d5b1010ca | |
parent | b566f0d68804e97f9c73d1cc2beed568a4b74105 (diff) |
tdf#106693 vcl PDF export, norefxobj: handle multiple refs in copied arrays
Also fix confusion about dictionaries in arrays and arrays in
dictionaries.
Change-Id: I0d71d5796b1eb4f89e3fd9a5b1f807d2a7340a35
Reviewed-on: https://gerrit.libreoffice.org/35806
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
-rw-r--r-- | include/vcl/filter/pdfdocument.hxx | 4 | ||||
-rw-r--r-- | vcl/source/filter/ipdf/pdfdocument.cxx | 34 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 31 |
3 files changed, 51 insertions, 18 deletions
diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx index d6b44e88d027..4bed3c32737a 100644 --- a/include/vcl/filter/pdfdocument.hxx +++ b/include/vcl/filter/pdfdocument.hxx @@ -109,8 +109,10 @@ class VCL_DLLPUBLIC PDFArrayElement : public PDFElement /// Location after the '[' token. sal_uInt64 m_nOffset = 0; std::vector<PDFElement*> m_aElements; + /// The object that contains this array. + PDFObjectElement* m_pObject; public: - PDFArrayElement(); + PDFArrayElement(PDFObjectElement* pObject); bool Read(SvStream& rStream) override; void PushBack(PDFElement* pElement); const std::vector<PDFElement*>& GetElements(); diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx index 1c132353e0a6..86aeade27137 100644 --- a/vcl/source/filter/ipdf/pdfdocument.cxx +++ b/vcl/source/filter/ipdf/pdfdocument.cxx @@ -939,7 +939,7 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s } case '[': { - auto pArr = new PDFArrayElement(); + auto pArr = new PDFArrayElement(pObject); rElements.push_back(std::unique_ptr<PDFElement>(pArr)); if (nDictionaryDepth == 0 && nArrayDepth == 0) { @@ -963,9 +963,10 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s case ']': { rElements.push_back(std::unique_ptr<PDFElement>(new PDFEndArrayElement())); - pArray = nullptr; - rStream.SeekRel(-1); --nArrayDepth; + if (nArrayDepth == 0) + pArray = nullptr; + rStream.SeekRel(-1); if (nDictionaryDepth == 0 && nArrayDepth == 0) { if (pObject) @@ -2127,18 +2128,25 @@ size_t PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement PDFArrayElement* pArray = nullptr; sal_uInt64 nDictionaryOffset = 0; int nDictionaryDepth = 0; + // Toplevel dictionary found (not inside an array). + bool bDictionaryFound = false; + // Toplevel array found (not inside a dictionary). + bool bArrayFound = false; for (size_t i = nIndex; i < rElements.size(); ++i) { // Dictionary tokens can be nested, track enter/leave. if (auto pDictionary = dynamic_cast<PDFDictionaryElement*>(rElements[i].get())) { + bDictionaryFound = true; if (++nDictionaryDepth == 1) { // First dictionary start, track start offset. nDictionaryOffset = pDictionary->m_nLocation; if (pThisObject) { - pThisObject->SetDictionary(pDictionary); + if (!bArrayFound) + // The the toplevel dictionary of the object. + pThisObject->SetDictionary(pDictionary); pThisDictionary = pDictionary; pThisObject->SetDictionaryOffset(nDictionaryOffset); } @@ -2189,7 +2197,11 @@ size_t PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement else { if (pArray) - pArray->PushBack(pName); + { + if (bDictionaryFound) + // Array inside dictionary. + pArray->PushBack(pName); + } else { // Name-name key-value. @@ -2208,6 +2220,7 @@ size_t PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement auto pArr = dynamic_cast<PDFArrayElement*>(rElements[i].get()); if (pArr) { + bArrayFound = true; pArray = pArr; continue; } @@ -2248,7 +2261,9 @@ size_t PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement } else { - pArray->PushBack(pReference); + if (bDictionaryFound) + // Array inside dictionary. + pArray->PushBack(pReference); } aNumbers.clear(); continue; @@ -2932,7 +2947,10 @@ bool PDFEndObjectElement::Read(SvStream& /*rStream*/) return true; } -PDFArrayElement::PDFArrayElement() = default; +PDFArrayElement::PDFArrayElement(PDFObjectElement* pObject) + : m_pObject(pObject) +{ +} bool PDFArrayElement::Read(SvStream& rStream) { @@ -2952,6 +2970,8 @@ bool PDFArrayElement::Read(SvStream& rStream) void PDFArrayElement::PushBack(PDFElement* pElement) { + if (m_pObject) + SAL_INFO("vcl.filter", "PDFArrayElement::PushBack: object is " << m_pObject->GetObjectValue()); m_aElements.push_back(pElement); } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 000e2875d95b..4b8b9542b46a 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -10855,6 +10855,7 @@ void PDFWriterImpl::writeJPG( JPGEmit& rObject ) sal_Int32 PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter::PDFObjectElement& rObject) { sal_Int32 nObject = createObject(); + SAL_INFO("vcl.pdfwriter", "PDFWriterImpl::copyExternalResource: " << rObject.GetObjectValue() << " -> " << nObject); OStringBuffer aLine; aLine.append(nObject); @@ -10927,7 +10928,8 @@ sal_Int32 PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter const std::vector<filter::PDFElement*>& rElements = pArray->GetElements(); bool bDone = false; - // Complex case: can't copy the array byte array as is, as it contains a reference. + // Complex case: can't copy the array byte array as is, as it may contain references. + sal_uInt64 nCopyStart = 0; for (const auto pElement : rElements) { auto pReference = dynamic_cast<filter::PDFReferenceElement*>(pElement); @@ -10939,28 +10941,37 @@ sal_Int32 PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter // Copy the referenced object. sal_Int32 nRef = copyExternalResource(rDocBuffer, *pReferenced); - sal_uInt64 nArrStart = rObject.GetArrayOffset(); sal_uInt64 nReferenceStart = pReference->GetObjectElement().GetLocation(); sal_uInt64 nReferenceEnd = pReference->GetOffset(); - sal_uInt64 nArrEnd = nArrStart + rObject.GetArrayLength(); + sal_uInt64 nOffset = 0; + if (nCopyStart == 0) + // Array start -> reference start. + nOffset = rObject.GetArrayOffset(); + else + // Previous reference end -> reference start. + nOffset = nCopyStart; + aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nOffset, nReferenceStart - nOffset); - // Array start -> reference start. - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nArrStart, nReferenceStart - nArrStart); // Write the updated reference. aLine.append(" "); aLine.append(nRef); aLine.append(" 0 R"); - // Reference end -> array end. - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nReferenceEnd, nArrEnd - nReferenceEnd); + // Start copying here next time. + nCopyStart = nReferenceEnd; bDone = true; - break; } } } - // Can copy it as-is. - if (!bDone) + if (bDone) + { + // Copy the last part here, in the complex case. + sal_uInt64 nArrEnd = rObject.GetArrayOffset() + rObject.GetArrayLength(); + aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nCopyStart, nArrEnd - nCopyStart); + } + else + // Can copy it as-is. aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + rObject.GetArrayOffset(), rObject.GetArrayLength()); aLine.append("]\n"); |