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

Miklos Vajna vmiklos at collabora.co.uk
Mon Mar 27 09:48:23 UTC 2017


 include/vcl/filter/pdfdocument.hxx     |   14 +++++++++-
 vcl/source/filter/ipdf/pdfdocument.cxx |   46 ++++++++++++++++++++++++++++++---
 vcl/source/gdi/pdfwriter_impl.cxx      |   45 ++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 5 deletions(-)

New commits:
commit 044e8d795276cc495c1f796a14ad36e6a5f9cdb9
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Mar 27 09:17:30 2017 +0200

    tdf#106693 vcl PDF export, norefxobj: copy array objects
    
    So far only the dictionary and the stream of the object was copied, see
    if it has an array, and take care of that as well.
    
    Also check if the array contains a reference and act accordingly.
    
    Change-Id: I7f3bb12ec0bbc6f6e1db4f43625c7768b862c895
    Reviewed-on: https://gerrit.libreoffice.org/35744
    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 fbfb81ed10a2..9ccbb43d0225 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -32,6 +32,7 @@ class PDFDocument;
 class PDFDictionaryElement;
 class PDFArrayElement;
 class PDFStreamElement;
+class PDFNumberElement;
 
 /// A byte range in a PDF file.
 class VCL_DLLPUBLIC PDFElement
@@ -54,6 +55,10 @@ class VCL_DLLPUBLIC PDFObjectElement : public PDFElement
     /// Length of the dictionary buffer till (before) the '>>' token.
     sal_uInt64 m_nDictionaryLength;
     PDFDictionaryElement* m_pDictionaryElement;
+    /// Position after the '[' token, if m_pArrayElement is set.
+    sal_uInt64 m_nArrayOffset;
+    /// Length of the array buffer till (before) the ']' token.
+    sal_uInt64 m_nArrayLength;
     /// The contained direct array, if any.
     PDFArrayElement* m_pArrayElement;
     /// The stream of this object, used when this is an object stream.
@@ -83,6 +88,10 @@ public:
     void SetStream(PDFStreamElement* pStreamElement);
     /// Access to the stream of the object, if it has any.
     PDFStreamElement* GetStream() const;
+    void SetArrayOffset(sal_uInt64 nArrayOffset);
+    sal_uInt64 GetArrayOffset();
+    void SetArrayLength(sal_uInt64 nArrayLength);
+    sal_uInt64 GetArrayLength();
     PDFArrayElement* GetArray() const;
     /// Parse objects stored in this object stream.
     void ParseStoredObjects();
@@ -113,9 +122,11 @@ class VCL_DLLPUBLIC PDFReferenceElement : public PDFElement
     int m_fGenerationValue;
     /// Location after the 'R' token.
     sal_uInt64 m_nOffset = 0;
+    /// The element providing the object number.
+    PDFNumberElement& m_rObject;
 
 public:
-    PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue);
+    PDFReferenceElement(PDFDocument& rDoc, PDFNumberElement& rObject, PDFNumberElement& rGeneration);
     bool Read(SvStream& rStream) override;
     /// Assuming the reference points to a number object, return its value.
     double LookupNumber(SvStream& rStream) const;
@@ -124,6 +135,7 @@ public:
     int GetObjectValue() const;
     int GetGenerationValue() const;
     sal_uInt64 GetOffset() const;
+    PDFNumberElement& GetObjectElement() const;
 };
 
 /// Stream object: a byte array with a known length.
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index 8744729fdd83..926ebb0500fd 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -944,7 +944,10 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s
                 // The array is attached directly, inform the object.
                 pArray = pArr;
                 if (pObject)
+                {
                     pObject->SetArray(pArray);
+                    pObject->SetArrayOffset(rStream.Tell());
+                }
             }
             rStream.SeekRel(-1);
             if (!rElements.back()->Read(rStream))
@@ -959,6 +962,13 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s
             rElements.push_back(std::unique_ptr<PDFElement>(new PDFEndArrayElement()));
             pArray = nullptr;
             rStream.SeekRel(-1);
+            if (nDictionaryDepth == 0)
+            {
+                if (pObject)
+                {
+                    pObject->SetArrayLength(rStream.Tell() - pObject->GetArrayOffset());
+                }
+            }
             if (!rElements.back()->Read(rStream))
             {
                 SAL_WARN("vcl.filter", "PDFDocument::Tokenize: PDFEndArrayElement::Read() failed");
@@ -1049,7 +1059,7 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s
                     }
                     else
                     {
-                        rElements.push_back(std::unique_ptr<PDFElement>(new PDFReferenceElement(*this, pObjectNumber->GetValue(), pGenerationNumber->GetValue())));
+                        rElements.push_back(std::unique_ptr<PDFElement>(new PDFReferenceElement(*this, *pObjectNumber, *pGenerationNumber)));
                         if (pArray)
                             // Reference is part of a direct (non-dictionary) array, inform the array.
                             pArray->PushBack(rElements.back().get());
@@ -2068,6 +2078,8 @@ PDFObjectElement::PDFObjectElement(PDFDocument& rDoc, double fObjectValue, doubl
       m_nDictionaryOffset(0),
       m_nDictionaryLength(0),
       m_pDictionaryElement(nullptr),
+      m_nArrayOffset(0),
+      m_nArrayLength(0),
       m_pArrayElement(nullptr),
       m_pStreamElement(nullptr)
 {
@@ -2368,6 +2380,16 @@ sal_uInt64 PDFObjectElement::GetDictionaryOffset()
     return m_nDictionaryOffset;
 }
 
+void PDFObjectElement::SetArrayOffset(sal_uInt64 nArrayOffset)
+{
+    m_nArrayOffset = nArrayOffset;
+}
+
+sal_uInt64 PDFObjectElement::GetArrayOffset()
+{
+    return m_nArrayOffset;
+}
+
 void PDFDictionaryElement::SetKeyOffset(const OString& rKey, sal_uInt64 nOffset)
 {
     m_aDictionaryKeyOffset[rKey] = nOffset;
@@ -2414,6 +2436,16 @@ sal_uInt64 PDFObjectElement::GetDictionaryLength()
     return m_nDictionaryLength;
 }
 
+void PDFObjectElement::SetArrayLength(sal_uInt64 nArrayLength)
+{
+    m_nArrayLength = nArrayLength;
+}
+
+sal_uInt64 PDFObjectElement::GetArrayLength()
+{
+    return m_nArrayLength;
+}
+
 PDFDictionaryElement* PDFObjectElement::GetDictionary() const
 {
     return m_pDictionaryElement;
@@ -2599,11 +2631,17 @@ PDFDocument& PDFObjectElement::GetDocument()
     return m_rDoc;
 }
 
-PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue)
+PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, PDFNumberElement& rObject, PDFNumberElement& rGeneration)
     : m_rDoc(rDoc),
-      m_fObjectValue(fObjectValue),
-      m_fGenerationValue(fGenerationValue)
+      m_fObjectValue(rObject.GetValue()),
+      m_fGenerationValue(rGeneration.GetValue()),
+      m_rObject(rObject)
+{
+}
+
+PDFNumberElement& PDFReferenceElement::GetObjectElement() const
 {
+    return m_rObject;
 }
 
 bool PDFReferenceElement::Read(SvStream& rStream)
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 061bc825d7a4..6d6e7eec9993 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -10912,6 +10912,51 @@ sal_Int32 PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter
         aLine.append("\nendstream\n");
     }
 
+    if (filter::PDFArrayElement* pArray = rObject.GetArray())
+    {
+        aLine.append("[");
+
+        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.
+        for (const auto pElement : rElements)
+        {
+            auto pReference = dynamic_cast<filter::PDFReferenceElement*>(pElement);
+            if (pReference)
+            {
+                filter::PDFObjectElement* pReferenced = pReference->LookupObject();
+                if (pReferenced)
+                {
+                    // 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();
+
+                    // 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);
+
+                    bDone = true;
+                    break;
+                }
+            }
+        }
+
+        // Can copy it as-is.
+        if (!bDone)
+            aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + rObject.GetArrayOffset(), rObject.GetArrayLength());
+
+        aLine.append("]\n");
+    }
+
     aLine.append("endobj\n\n");
 
     // We have the whole object, now write it to the output.


More information about the Libreoffice-commits mailing list