From 50bc6db73466121744848e04f21c934c3b596897 Mon Sep 17 00:00:00 2001 From: Tomaž Vajngerl Date: Mon, 9 Nov 2020 19:16:27 +0100 Subject: pdf: improve PDFObjectCopier, copy arrays/dicts recursively MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ia2f8d86ae012b530f3e9c39842bb75ef8ca27718 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105493 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl --- vcl/inc/pdf/objectcopier.hxx | 5 ++ vcl/source/gdi/pdfobjectcopier.cxx | 164 ++++++++++++++----------------------- 2 files changed, 65 insertions(+), 104 deletions(-) diff --git a/vcl/inc/pdf/objectcopier.hxx b/vcl/inc/pdf/objectcopier.hxx index 65dbbb49aef4..3880d739bb10 100644 --- a/vcl/inc/pdf/objectcopier.hxx +++ b/vcl/inc/pdf/objectcopier.hxx @@ -25,6 +25,7 @@ class PDFObjectContainer; namespace filter { class PDFObjectElement; +class PDFElement; } /// Copies objects from one PDF file into another one. @@ -32,6 +33,10 @@ class PDFObjectCopier { PDFObjectContainer& m_rContainer; + void copyRecursively(OStringBuffer& rLine, filter::PDFElement* pInputElement, + SvMemoryStream& rDocBuffer, + std::map& rCopiedResources); + public: PDFObjectCopier(PDFObjectContainer& rContainer); diff --git a/vcl/source/gdi/pdfobjectcopier.cxx b/vcl/source/gdi/pdfobjectcopier.cxx index 129a4c8bda35..d6323a17e91c 100644 --- a/vcl/source/gdi/pdfobjectcopier.cxx +++ b/vcl/source/gdi/pdfobjectcopier.cxx @@ -26,14 +26,62 @@ PDFObjectCopier::PDFObjectCopier(PDFObjectContainer& rContainer) { } +void PDFObjectCopier::copyRecursively(OStringBuffer& rLine, filter::PDFElement* pInputElement, + SvMemoryStream& rDocBuffer, + std::map& rCopiedResources) +{ + if (auto pReference = dynamic_cast(pInputElement)) + { + filter::PDFObjectElement* pReferenced = pReference->LookupObject(); + if (pReferenced) + { + // Copy the referenced object. + sal_Int32 nRef = copyExternalResource(rDocBuffer, *pReferenced, rCopiedResources); + + // Write the updated reference. + rLine.append(nRef); + rLine.append(" 0 R"); + } + } + else if (auto pInputArray = dynamic_cast(pInputElement)) + { + rLine.append("[ "); + for (auto const& pElement : pInputArray->GetElements()) + { + copyRecursively(rLine, pElement, rDocBuffer, rCopiedResources); + rLine.append(" "); + } + rLine.append("] "); + } + else if (auto pInputDictionary = dynamic_cast(pInputElement)) + { + rLine.append("<< "); + for (auto const& pPair : pInputDictionary->GetItems()) + { + rLine.append("/"); + rLine.append(pPair.first); + rLine.append(" "); + copyRecursively(rLine, pPair.second, rDocBuffer, rCopiedResources); + rLine.append(" "); + } + rLine.append(">> "); + } + else + { + pInputElement->writeString(rLine); + } +} + sal_Int32 PDFObjectCopier::copyExternalResource(SvMemoryStream& rDocBuffer, filter::PDFObjectElement& rObject, std::map& rCopiedResources) { auto it = rCopiedResources.find(rObject.GetObjectValue()); if (it != rCopiedResources.end()) + { // This resource was already copied once, nothing to do. return it->second; + } sal_Int32 nObject = m_rContainer.createObject(); // Remember what is the ID of this object in our output. @@ -50,62 +98,19 @@ sal_Int32 PDFObjectCopier::copyExternalResource(SvMemoryStream& rDocBuffer, OStringBuffer aLine; aLine.append(nObject); aLine.append(" 0 obj\n"); + if (rObject.GetDictionary()) { - aLine.append("<<"); - - // Complex case: can't copy the dictionary byte array as is, as it may contain references. - bool bDone = false; - sal_uInt64 nCopyStart = 0; - for (auto pReference : rObject.GetDictionaryReferences()) - { - if (pReference) - { - filter::PDFObjectElement* pReferenced = pReference->LookupObject(); - if (pReferenced) - { - // Copy the referenced object. - sal_Int32 nRef - = copyExternalResource(rDocBuffer, *pReferenced, rCopiedResources); - - sal_uInt64 nReferenceStart = pReference->GetObjectElement().GetLocation(); - sal_uInt64 nReferenceEnd = pReference->GetOffset(); - sal_uInt64 nOffset = 0; - if (nCopyStart == 0) - // Dict start -> reference start. - nOffset = rObject.GetDictionaryOffset(); - else - // Previous reference end -> reference start. - nOffset = nCopyStart; - aLine.append(static_cast(pObjectStream->GetData()) + nOffset, - nReferenceStart - nOffset); - // Write the updated reference. - aLine.append(" "); - aLine.append(nRef); - aLine.append(" 0 R"); - // Start copying here next time. - nCopyStart = nReferenceEnd; - - bDone = true; - } - } - } + aLine.append("<< "); - if (bDone) + for (auto const& rPair : rObject.GetDictionaryItems()) { - // Copy the last part here, in the complex case. - sal_uInt64 nDictEnd = rObject.GetDictionaryOffset() + rObject.GetDictionaryLength(); - const sal_Int32 nLen = nDictEnd - nCopyStart; - if (nLen < 0) - SAL_WARN("vcl.pdfwriter", "copyExternalResource() failed"); - else - aLine.append(static_cast(pObjectStream->GetData()) + nCopyStart, nLen); + aLine.append("/"); + aLine.append(rPair.first); + aLine.append(" "); + copyRecursively(aLine, rPair.second, rDocBuffer, rCopiedResources); + aLine.append(" "); } - else - // Can copy it as-is. - aLine.append(static_cast(pObjectStream->GetData()) - + rObject.GetDictionaryOffset(), - rObject.GetDictionaryLength()); aLine.append(">>\n"); } @@ -120,64 +125,15 @@ sal_Int32 PDFObjectCopier::copyExternalResource(SvMemoryStream& rDocBuffer, if (filter::PDFArrayElement* pArray = rObject.GetArray()) { - aLine.append("["); + aLine.append("[ "); const std::vector& rElements = pArray->GetElements(); - bool bDone = false; - // 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(pElement); - if (pReference) - { - filter::PDFObjectElement* pReferenced = pReference->LookupObject(); - if (pReferenced) - { - // Copy the referenced object. - sal_Int32 nRef - = copyExternalResource(rDocBuffer, *pReferenced, rCopiedResources); - - sal_uInt64 nReferenceStart = pReference->GetObjectElement().GetLocation(); - sal_uInt64 nReferenceEnd = pReference->GetOffset(); - 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(pObjectStream->GetData()) + nOffset, - nReferenceStart - nOffset); - - // Write the updated reference. - aLine.append(" "); - aLine.append(nRef); - aLine.append(" 0 R"); - // Start copying here next time. - nCopyStart = nReferenceEnd; - - bDone = true; - } - } - } - if (bDone) + for (auto const& pElement : rElements) { - // Copy the last part here, in the complex case. - sal_uInt64 nArrEnd = rObject.GetArrayOffset() + rObject.GetArrayLength(); - const sal_Int32 nLen = nArrEnd - nCopyStart; - if (nLen < 0) - SAL_WARN("vcl.pdfwriter", "copyExternalResource() failed"); - else - aLine.append(static_cast(pObjectStream->GetData()) + nCopyStart, nLen); + copyRecursively(aLine, pElement, rDocBuffer, rCopiedResources); + aLine.append(" "); } - else - // Can copy it as-is. - aLine.append(static_cast(pObjectStream->GetData()) - + rObject.GetArrayOffset(), - rObject.GetArrayLength()); - aLine.append("]\n"); } -- cgit