[Libreoffice-commits] core.git: include/vcl vcl/source

Miklos Vajna vmiklos at collabora.co.uk
Tue Mar 28 15:53:10 UTC 2017


 include/vcl/filter/pdfdocument.hxx     |    4 ++-
 vcl/source/filter/ipdf/pdfdocument.cxx |   34 ++++++++++++++++++++++++++-------
 vcl/source/gdi/pdfwriter_impl.cxx      |   31 ++++++++++++++++++++----------
 3 files changed, 51 insertions(+), 18 deletions(-)

New commits:
commit 30608c66374f8effa9d534f7f9a22d41daa9770f
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Mar 28 16:14:11 2017 +0200

    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 at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>

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");


More information about the Libreoffice-commits mailing list