summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/vcl/filter/pdfdocument.hxx14
-rw-r--r--vcl/source/filter/ipdf/pdfdocument.cxx46
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx45
3 files changed, 100 insertions, 5 deletions
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.