vcl/inc/pdf/COSWriter.hxx         |  196 ++++++++++++++++++++++++++++++++++++++
 vcl/source/gdi/pdfwriter_impl.cxx |  106 ++------------------
 2 files changed, 208 insertions(+), 94 deletions(-)

New commits:
commit 0c2f9c364c0ed4369213ba918ce34b6e43f0f635
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Fri Nov 22 15:21:34 2024 +0900
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Dec 11 09:49:41 2024 +0100

    pdf: move PDFStructureWriter into own file, rename to COSWriter
    
    This needs to duplicate some functions from pdfwriter_impl to make
    this possible.
    
    Change-Id: Ie738c9690306d6498c883f034a3fcd6483f24eef
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176985
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/vcl/inc/pdf/COSWriter.hxx b/vcl/inc/pdf/COSWriter.hxx
new file mode 100644
index 000000000000..767654689b73
--- /dev/null
+++ b/vcl/inc/pdf/COSWriter.hxx
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <pdf/IPDFEncryptor.hxx>
+
+namespace vcl::pdf
+{
+/** Writes the "Carousel" object structure (COS) to the string buffer.
+ *
+ * "Carousel" object structure (COS) is used by PDF.
+ *
+ * Structure elements like: objects, IDs, dictionaries, key/values, ...
+ */
+class COSWriter
+{
+    std::unique_ptr<IPDFEncryptor>& mpPDFEncryptor;
+    OStringBuffer maLine;
+
+    void appendLiteralString(const char* pStr, sal_Int32 nLength)
+    {
+        while (nLength)
+        {
+            switch (*pStr)
+            {
+                case '
':
+                    maLine.append("\n");
+                    break;
+                case ' ':
+                    maLine.append("\r");
+                    break;
+                case ' ':
+                    maLine.append("\t");
+                    break;
+                case '':
+                    maLine.append("\b");
+                    break;
+                case '':
+                    maLine.append("\f");
+                    break;
+                case '(':
+                case ')':
+                case '\':
+                    maLine.append("\");
+                    maLine.append(static_cast<char>(*pStr));
+                    break;
+                default:
+                    maLine.append(static_cast<char>(*pStr));
+                    break;
+            }
+            pStr++;
+            nLength--;
+        }
+    }
+    template <typename T> void appendHex(T nValue)
+    {
+        static constexpr const auto constHexDigits = std::to_array<char>(
+            { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 
'D', 'E', 'F' });
+        maLine.append(constHexDigits[(nValue >> 4) & 15]);
+        maLine.append(constHexDigits[nValue & 15]);
+    }
+
+    void appendHexArray(sal_uInt8* pArray, size_t nSize)
+    {
+        for (size_t i = 0; i < nSize; i++)
+            appendHex(pArray[i]);
+    }
+
+public:
+    COSWriter(std::unique_ptr<IPDFEncryptor>& pPDFEncryptor)
+        : mpPDFEncryptor(pPDFEncryptor)
+        , maLine(1024)
+    {
+    }
+
+    void startObject(sal_Int32 nObjectID)
+    {
+        maLine.append(nObjectID);
+        maLine.append(" 0 obj
");
+    }
+
+    void endObject() { maLine.append("endobj

"); }
+
+    OStringBuffer& getLine() { return maLine; }
+
+    void startDict() { maLine.append("<<"); }
+
+    void endDict() { maLine.append(">>
"); }
+
+    void write(std::string_view key, std::string_view value)
+    {
+        maLine.append(key);
+        maLine.append(value);
+    }
+
+    void write(std::string_view key, sal_Int32 value)
+    {
+        maLine.append(key);
+        maLine.append(" ");
+        maLine.append(value);
+    }
+
+    void writeString(std::string_view key, char* pString, sal_Int32 nSize)
+    {
+        maLine.append(key);
+        maLine.append(" (");
+        appendLiteralString(pString, nSize);
+        maLine.append(")");
+    }
+
+    void writeUnicodeEncrypt(std::string_view key, OUString const& rString, 
sal_Int32 nObject,
+                             bool bEncrypt, std::vector<sal_uInt8>& rKey)
+    {
+        maLine.append(key);
+        maLine.append("<");
+
+        if (bEncrypt)
+        {
+            const sal_Unicode* pString = rString.getStr();
+            size_t nLength = rString.getLength();
+            //prepare a unicode string, encrypt it
+            mpPDFEncryptor->setupEncryption(rKey, nObject);
+            sal_Int32 nChars = 2 + (nLength * 2);
+            std::vector<sal_uInt8> aEncryptionBuffer(nChars);
+            sal_uInt8* pCopy = aEncryptionBuffer.data();
+            *pCopy++ = 0xFE;
+            *pCopy++ = 0xFF;
+            // we need to prepare a byte stream from the unicode string buffer
+            for (size_t i = 0; i < nLength; i++)
+            {
+                sal_Unicode aUnicodeChar = pString[i];
+                *pCopy++ = sal_uInt8(aUnicodeChar >> 8);
+                *pCopy++ = sal_uInt8(aUnicodeChar & 255);
+            }
+            std::vector<sal_uInt8> aNewBuffer(nChars);
+            mpPDFEncryptor->encrypt(aEncryptionBuffer.data(), nChars, 
aNewBuffer, nChars);
+            //now append, hexadecimal (appendHex), the encrypted result
+            appendHexArray(aNewBuffer.data(), aNewBuffer.size());
+        }
+        else
+        {
+            //PDFWriter::AppendUnicodeTextString(rInString, maLine);
+            maLine.append("FEFF");
+            const sal_Unicode* pString = rString.getStr();
+            size_t nLength = rString.getLength();
+            for (size_t i = 0; i < nLength; i++)
+            {
+                sal_Unicode aChar = pString[i];
+                appendHex(sal_Int8(aChar >> 8));
+                appendHex(sal_Int8(aChar & 255));
+            }
+        }
+        maLine.append(">");
+    }
+
+    void writeLiteralEncrypt(std::string_view key, std::string_view value, 
sal_Int32 nObject,
+                             bool bEncrypt, std::vector<sal_uInt8>& rKey)
+    {
+        maLine.append(key);
+
+        maLine.append("(");
+        size_t nChars = value.size();
+
+        if (bEncrypt)
+        {
+            std::vector<sal_uInt8> aEncryptionBuffer(nChars);
+            mpPDFEncryptor->setupEncryption(rKey, nObject);
+            mpPDFEncryptor->encrypt(value.data(), nChars, aEncryptionBuffer, 
nChars);
+            
appendLiteralString(reinterpret_cast<char*>(aEncryptionBuffer.data()),
+                                aEncryptionBuffer.size());
+        }
+        else
+        {
+            appendLiteralString(value.data(), nChars);
+        }
+        maLine.append(")");
+    }
+
+    void writeHexArray(std::string_view key, sal_uInt8* pData, size_t nSize)
+    {
+        maLine.append(key);
+        maLine.append(" <");
+        appendHexArray(pData, nSize);
+        maLine.append(">");
+    }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index 3c462434292f..36ff34e9770c 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -84,6 +84,7 @@
 
 #include <svdata.hxx>
 #include <vcl/BitmapWriteAccess.hxx>
+#include <pdf/COSWriter.hxx>
 #include <fontsubset.hxx>
 #include <font/EmphasisMark.hxx>
 #include <font/PhysicalFontFace.hxx>
@@ -307,91 +308,6 @@ GEOMETRY lcl_convert( const MapMode& _rSource, const 
MapMode& _rDest, OutputDevi
 
 void removePlaceholderSE(std::vector<PDFStructureElement> & rStructure, 
PDFStructureElement& rEle);
 
-/** Writes the PDF structure to the string buffer.
- *
- * Structure elements like: objects, IDs, dictionaries, key/values, ...
- */
-class PDFStructureWriter
-{
-    OStringBuffer maLine;
-    PDFWriterImpl& mrWriterImpl;
-public:
-    PDFStructureWriter(PDFWriterImpl& rWriterImpl)
-        : maLine(1024)
-        , mrWriterImpl(rWriterImpl)
-    {
-    }
-
-    void startObject(sal_Int32 nID)
-    {
-        appendObjectID(nID, maLine);
-    }
-
-    void endObject()
-    {
-        maLine.append("endobj

");
-    }
-
-    OStringBuffer& getLine()
-    {
-        return maLine;
-    }
-
-    void startDict()
-    {
-        maLine.append("<<");
-    }
-
-    void endDict()
-    {
-        maLine.append(">>
");
-    }
-
-    void write(std::string_view key, std::string_view value)
-    {
-        maLine.append(key);
-        maLine.append(value);
-    }
-
-    void write(std::string_view key, sal_Int32 value)
-    {
-        maLine.append(key);
-        maLine.append(" ");
-        maLine.append(value);
-    }
-
-    /*void writeString(std::string_view key, char* pString, sal_Int32 nSize)
-    {
-        maLine.append(key);
-        maLine.append(" (");
-        appendLiteralString(pString, nSize, maLine);
-        maLine.append(")");
-    }*/
-
-    void writeUnicodeEncrypt(std::string_view key, OUString const& rString, 
sal_Int32 nObject)
-    {
-        maLine.append(key);
-        mrWriterImpl.appendUnicodeTextStringEncrypt(rString, nObject, maLine);
-    }
-
-    void writeLiteralEncrypt(std::string_view key, std::string_view value, 
sal_Int32 nObject)
-    {
-        maLine.append(key);
-        mrWriterImpl.appendLiteralStringEncrypt(value, nObject, maLine);
-    }
-
-    void writeHexArray(std::string_view key, sal_uInt8* pData, size_t nSize)
-    {
-        maLine.append(key);
-        maLine.append(" <");
-        for (size_t i = 0; i < nSize; i++)
-        {
-            appendHex(sal_Int8(pData[i]), maLine);
-        }
-        maLine.append(">");
-    }
-};
-
 } // end anonymous namespace
 
 void PDFWriter::AppendUnicodeTextString(const OUString& rString, 
OStringBuffer& rBuffer)
@@ -5833,7 +5749,9 @@ sal_Int32 PDFWriterImpl::emitInfoDict( )
     if (!updateObject(nObject))
         return 0;
 
-    PDFStructureWriter aWriter(*this);
+    COSWriter aWriter(m_pPDFEncryptor);
+    bool bEncrypt = m_aContext.Encryption.canEncrypt();
+    auto& rKey = m_aContext.Encryption.EncryptionKey;
     aWriter.startObject(nObject);
     aWriter.startDict();
 
@@ -5843,31 +5761,31 @@ sal_Int32 PDFWriterImpl::emitInfoDict( )
     {
         if (!m_aContext.DocumentInfo.Title.isEmpty())
         {
-            aWriter.writeUnicodeEncrypt("/Title", 
m_aContext.DocumentInfo.Title, nObject);
+            aWriter.writeUnicodeEncrypt("/Title", 
m_aContext.DocumentInfo.Title, nObject, bEncrypt, rKey);
         }
         if (!m_aContext.DocumentInfo.Author.isEmpty())
         {
-            aWriter.writeUnicodeEncrypt("/Author", 
m_aContext.DocumentInfo.Author, nObject);
+            aWriter.writeUnicodeEncrypt("/Author", 
m_aContext.DocumentInfo.Author, nObject, bEncrypt, rKey);
         }
         if (!m_aContext.DocumentInfo.Subject.isEmpty())
         {
-            aWriter.writeUnicodeEncrypt("/Subject", 
m_aContext.DocumentInfo.Subject, nObject);
+            aWriter.writeUnicodeEncrypt("/Subject", 
m_aContext.DocumentInfo.Subject, nObject, bEncrypt, rKey);
         }
         if (!m_aContext.DocumentInfo.Keywords.isEmpty())
         {
-            aWriter.writeUnicodeEncrypt("/Keywords", 
m_aContext.DocumentInfo.Keywords, nObject);
+            aWriter.writeUnicodeEncrypt("/Keywords", 
m_aContext.DocumentInfo.Keywords, nObject, bEncrypt, rKey);
         }
         if (!m_aContext.DocumentInfo.Creator.isEmpty())
         {
-            aWriter.writeUnicodeEncrypt("/Creator", 
m_aContext.DocumentInfo.Creator, nObject);
+            aWriter.writeUnicodeEncrypt("/Creator", 
m_aContext.DocumentInfo.Creator, nObject, bEncrypt, rKey);
         }
         if (!m_aContext.DocumentInfo.Producer.isEmpty())
         {
-            aWriter.writeUnicodeEncrypt("/Producer", 
m_aContext.DocumentInfo.Producer, nObject);
+            aWriter.writeUnicodeEncrypt("/Producer", 
m_aContext.DocumentInfo.Producer, nObject, bEncrypt, rKey);
         }
     }
     // Allowed in PDF 2.0
-    aWriter.writeLiteralEncrypt("/CreationDate", m_aCreationDateString, 
nObject);
+    aWriter.writeLiteralEncrypt("/CreationDate", m_aCreationDateString, 
nObject, bEncrypt, rKey);
     aWriter.endDict();
     aWriter.endObject();
 
@@ -6126,7 +6044,7 @@ sal_Int32 PDFWriterImpl::emitEncrypt()
     if (updateObject(nObject))
     {
         PDFEncryptionProperties& rProperties = m_aContext.Encryption;
-        PDFStructureWriter aWriter(*this);
+        COSWriter aWriter(m_pPDFEncryptor);
         aWriter.startObject(nObject);
         aWriter.startDict();
         aWriter.write("/Filter", "/Standard");

Reply via email to