vcl/inc/pdf/pdfwriter_impl.hxx    |    5 +
 vcl/source/gdi/pdfwriter_impl.cxx |  147 +++++++++++++++++++++++++++-----------
 2 files changed, 111 insertions(+), 41 deletions(-)

New commits:
commit 152780e4340e12397a64320bc66185000871be35
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Oct 31 23:59:00 2024 +0100
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Mon Nov 4 21:51:12 2024 +0100

    pdf: add m_nPDFA_Version to simplify PDF/A versions
    
    We have a bool for each PDFA version, which is inflexible when
    checking if the feature is supported in a range of versions so
    this adds a version number which simplifies checks a bit.
    
    Change-Id: If162e305766baa61278872297c9ab1eb41cb57d9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176025
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    Tested-by: Jenkins

diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx
index 24a2858ec994..41e137481e9e 100644
--- a/vcl/inc/pdf/pdfwriter_impl.hxx
+++ b/vcl/inc/pdf/pdfwriter_impl.hxx
@@ -1097,10 +1097,11 @@ i12626
     /* true if PDF/A-4 is output */
     bool m_bIsPDF_A4 = false;
 
+    sal_Int32 m_nPDFA_Version = 0;
+
     /* PDF/UA support enabled */
     bool m_bIsPDF_UA = false;
 
-
     PDFWriter&      m_rOuterFace;
 
     /*
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index b5d7ad31cf08..fd9d3ee1ef30 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -1394,18 +1394,22 @@ PDFWriterImpl::PDFWriterImpl( const 
PDFWriter::PDFWriterContext& rContext,
     switch (m_aContext.Version)
     {
         case PDFWriter::PDFVersion::PDF_A_1:
+            m_nPDFA_Version = 1;
             m_bIsPDF_A1 = true;
             m_aContext.Version = PDFWriter::PDFVersion::PDF_1_4; //meaning we 
need PDF 1.4, PDF/A flavour
             break;
         case PDFWriter::PDFVersion::PDF_A_2:
+            m_nPDFA_Version = 2;
             m_bIsPDF_A2 = true;
             m_aContext.Version = PDFWriter::PDFVersion::PDF_1_7;
             break;
         case PDFWriter::PDFVersion::PDF_A_3:
+            m_nPDFA_Version = 3;
             m_bIsPDF_A3 = true;
             m_aContext.Version = PDFWriter::PDFVersion::PDF_1_7;
             break;
         case PDFWriter::PDFVersion::PDF_A_4:
+            m_nPDFA_Version = 4;
             m_bIsPDF_A4 = true;
             m_aContext.Version = PDFWriter::PDFVersion::PDF_2_0;
             break;
@@ -3802,7 +3806,7 @@ bool PDFWriterImpl::emitLinkAnnotations()
 // i59651: key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate 
to 1, since it's a 'should'
 // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
         aLine.append( "<</Type/Annot" );
-        if (m_bIsPDF_A1 || m_bIsPDF_A2 || m_bIsPDF_A3 || m_bIsPDF_A4)
+        if (m_nPDFA_Version > 0)
             aLine.append( "/F 4" );
         aLine.append( "/Subtype/Link/Border[0 0 0]/Rect[" );
 
@@ -4148,7 +4152,7 @@ void PDFWriterImpl::emitTextAnnotationLine(OStringBuffer 
& aLine, PDFNoteEntry c
 
     // i59651: key /F set bits Print to 1 rest to 0. We don't set NoZoom 
NoRotate to 1, since it's a 'should'
     // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
-    if (m_bIsPDF_A1 || m_bIsPDF_A2 || m_bIsPDF_A3 || m_bIsPDF_A4)
+    if (m_nPDFA_Version > 0)
         aLine.append("/F 4 ");
 
     aLine.append("/Popup ");
@@ -4757,7 +4761,7 @@ bool PDFWriterImpl::emitAppearances( PDFWidget& rWidget, 
OStringBuffer& rAnnotDi
 
             // PDF/A requires sub-dicts for /FT/Btn objects (clause
             // 6.3.3)
-            if( m_bIsPDF_A1 || m_bIsPDF_A2 || m_bIsPDF_A3 || m_bIsPDF_A4)
+            if (m_nPDFA_Version > 0)
             {
                 if( rWidget.m_eType == PDFWriter::RadioButton ||
                     rWidget.m_eType == PDFWriter::CheckBox ||
@@ -5664,7 +5668,7 @@ bool PDFWriterImpl::emitCatalog()
         aLine.append( getResourceDictObj() );
         aLine.append( " 0 R" );
         // NeedAppearances must not be used if PDF is signed
-        if(m_bIsPDF_A1 || m_bIsPDF_A2 || m_bIsPDF_A3 || m_bIsPDF_A4
+        if (m_nPDFA_Version > 0
 #if HAVE_FEATURE_NSS
             || ( m_nSignatureObject != -1 )
 #endif
@@ -5981,7 +5985,7 @@ sal_Int32 PDFWriterImpl::emitNamedDestinations()
 // emits the output intent dictionary
 sal_Int32 PDFWriterImpl::emitOutputIntent()
 {
-    if (!m_bIsPDF_A1 && !m_bIsPDF_A2 && !m_bIsPDF_A3 && !m_bIsPDF_A4)
+    if (m_nPDFA_Version == 0) // not PDFA
         return 0;
 
     //emit the sRGB standard profile, in ICC format, in a stream, per 
IEC61966-2.1
@@ -6082,6 +6086,7 @@ static void lcl_assignMeta(const 
css::uno::Sequence<OUString>& rValues, std::vec
 }
 
 // emits the document metadata
+// Since in PDF 1.4
 sal_Int32 PDFWriterImpl::emitDocumentMetadata()
 {
     if( !m_bIsPDF_A1 && !m_bIsPDF_A2 && !m_bIsPDF_A3 && !m_bIsPDF_A4 && 
!m_bIsPDF_UA)
@@ -6094,14 +6099,8 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata()
     {
         pdf::XmpMetadata aMetadata;
 
-        if (m_bIsPDF_A1)
-            aMetadata.mnPDF_A = 1;
-        else if (m_bIsPDF_A2)
-            aMetadata.mnPDF_A = 2;
-        else if (m_bIsPDF_A3)
-            aMetadata.mnPDF_A = 3;
-        else if (m_bIsPDF_A4)
-            aMetadata.mnPDF_A = 4;
+        if (m_nPDFA_Version > 0)
+            aMetadata.mnPDF_A = m_nPDFA_Version;
 
         aMetadata.mbPDF_UA = m_bIsPDF_UA;
 
commit b0a6a402f00e966c24f5b1e74b9c8aefeb62af8b
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Oct 31 23:40:35 2024 +0100
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Mon Nov 4 21:51:00 2024 +0100

    pdf: move encrypt code into emitEncrypt, add PDFStructureWriter
    
    Move the encryption code into emitEncrypt and rewrite that with
    the newly introduced PDFStructureWriter, which is now responsible
    to write the PDF basic structure elements into a string buffer.
    
    The PDFStructureWriter will be extended with new features when
    there is demand.
    
    Change-Id: I4f4099886860b72b4f1866b19a8afb7cc8fb4ea4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176024
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    Tested-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx
index df86ea640e96..24a2858ec994 100644
--- a/vcl/inc/pdf/pdfwriter_impl.hxx
+++ b/vcl/inc/pdf/pdfwriter_impl.hxx
@@ -1025,6 +1025,8 @@ i12626
     // creates a PKCS7 object using the ByteRange and overwrite /Contents
     // of the signature dictionary
     bool finalizeSignature();
+    //writes encrypt
+    sal_Int32 emitEncrypt();
     // writes xref and trailer
     bool emitTrailer();
     // emits info dict (if applicable)
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index ce3d102d5c55..b5d7ad31cf08 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -276,6 +276,67 @@ void appendDestinationName( const OUString& rString, 
OStringBuffer& rBuffer )
     }
 }
 
+/** Writes the PDF structure to the string buffer.
+ *
+ * Structure elements like: objects, IDs, dictionaries, key/values, ...
+ *
+ */
+class PDFStructureWriter
+{
+    OStringBuffer maLine;
+public:
+    PDFStructureWriter()
+        : maLine(1024)
+    {
+    }
+
+    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(")");
+    }
+};
+
 } // end anonymous namespace
 
 namespace vcl
@@ -6085,6 +6146,39 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata()
     return nObject;
 }
 
+sal_Int32 PDFWriterImpl::emitEncrypt()
+{
+    //emit the security information
+    //must be emitted as indirect dictionary object, since
+    //Acrobat Reader 5 works only with this kind of implementation
+
+    sal_Int32 nObject = createObject();
+
+    if (updateObject(nObject))
+    {
+        PDFStructureWriter aWriter;
+        aWriter.startObject(nObject);
+        aWriter.startDict();
+        aWriter.write("/Filter", "/Standard");
+        aWriter.write("/V", 2);
+        aWriter.write("/Length", 128);
+        aWriter.write("/R", 3);
+        // emit the owner password, must not be encrypted
+        aWriter.writeString("/O", 
reinterpret_cast<char*>(m_aContext.Encryption.OValue.data()), 
sal_Int32(m_aContext.Encryption.OValue.size()));
+        aWriter.writeString("/U", 
reinterpret_cast<char*>(m_aContext.Encryption.UValue.data()), 
sal_Int32(m_aContext.Encryption.UValue.size()));
+        aWriter.write("/P", m_nAccessPermissions);
+        aWriter.endDict();
+        aWriter.endObject();
+
+        if (!writeBuffer(aWriter.getLine()))
+            nObject = 0;
+    }
+    else
+        nObject = 0;
+
+    return nObject;
+}
+
 bool PDFWriterImpl::emitTrailer()
 {
     // emit doc info
@@ -6094,33 +6188,7 @@ bool PDFWriterImpl::emitTrailer()
 
     if( m_aContext.Encryption.Encrypt() )
     {
-        //emit the security information
-        //must be emitted as indirect dictionary object, since
-        //Acrobat Reader 5 works only with this kind of implementation
-        nSecObject = createObject();
-
-        if( updateObject( nSecObject ) )
-        {
-            OStringBuffer aLineS( 1024 );
-            aLineS.append( nSecObject );
-            aLineS.append( " 0 obj
"
-                           "<</Filter/Standard/V " );
-            // check the version
-            aLineS.append( "2/Length 128/R 3" );
-
-            // emit the owner password, must not be encrypted
-            aLineS.append( "/O(" );
-            appendLiteralString( 
reinterpret_cast<char*>(m_aContext.Encryption.OValue.data()), 
sal_Int32(m_aContext.Encryption.OValue.size()), aLineS );
-            aLineS.append( ")/U(" );
-            appendLiteralString( 
reinterpret_cast<char*>(m_aContext.Encryption.UValue.data()), 
sal_Int32(m_aContext.Encryption.UValue.size()), aLineS );
-            aLineS.append( ")/P " );// the permission set
-            aLineS.append( m_nAccessPermissions );
-            aLineS.append( ">>
endobj

" );
-            if( !writeBuffer( aLineS ) )
-                nSecObject = 0;
-        }
-        else
-            nSecObject = 0;
+        nSecObject = emitEncrypt();
     }
     // emit xref table
     // remember start

Reply via email to