sdext/source/pdfimport/wrapper/wrapper.cxx         |   43 +++--
 sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx |  156 +++++++++++++--------
 2 files changed, 124 insertions(+), 75 deletions(-)

New commits:
commit 779a77d1a9a467230dd1ae98b89ea76b02b22c42
Author:     Dr. David Alan Gilbert <d...@treblig.org>
AuthorDate: Sat Feb 15 01:10:50 2025 +0000
Commit:     David Gilbert <d...@treblig.org>
CommitDate: Tue Mar 4 00:56:28 2025 +0100

    tdf#55425 sdext,pdfimport: Add a command loop to the poppler wrapper
    
    At the moment the poppler wrapper just takes in a password and
    gives a status followed by the actual data.
    
    Make this a more controlled process where the LO side can
    send commands.
    
    The commands we have are:
    
     Pmypassword
         Set the password to be used for future opening of the PDF
     O
         Open the PDF document using the password; this returns
         the #OPEN or #ERROR response.
     G
         Render the previously opened PDF to commands/data
     E
         Quit without rendering.
    
    Change-Id: Id81a0ceb024d75abfda8d908e3228b7d0d903b32
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181741
    Reviewed-by: David Gilbert <freedesk...@treblig.org>
    Tested-by: Jenkins

diff --git a/sdext/source/pdfimport/wrapper/wrapper.cxx 
b/sdext/source/pdfimport/wrapper/wrapper.cxx
index e32af020c729..e8b900b14075 100644
--- a/sdext/source/pdfimport/wrapper/wrapper.cxx
+++ b/sdext/source/pdfimport/wrapper/wrapper.cxx
@@ -1147,6 +1147,7 @@ bool xpdf_ImportFromFile(const OUString& rURL,
     try
     {
         std::unique_ptr<Buffering> pBuffering;
+        sal_uInt64 nWritten = 0;
 
         if( eErr!=osl_Process_E_None )
         {
@@ -1157,41 +1158,43 @@ bool xpdf_ImportFromFile(const OUString& rURL,
             return false;
         }
 
-        if( pIn )
+        if (!pIn || !pOut || !pErr)
         {
-            OStringBuffer aBuf(256);
-            if( bIsEncrypted )
-                aBuf.append( OUStringToOString( aPwd, 
RTL_TEXTENCODING_ISO_8859_1 ) );
-            aBuf.append( '
' );
-
-            sal_uInt64 nWritten = 0;
-            osl_writeFile( pIn, aBuf.getStr(), sal_uInt64(aBuf.getLength()), 
&nWritten );
+            SAL_WARN("sdext.pdfimport", "Failure opening pipes");
+            bRet = false;
         }
+        OStringBuffer aBuf(256);
+        // Password lines are Pmypassword
 followed by "O
" to try to open
+        aBuf = "P" + OUStringToOString(aPwd, RTL_TEXTENCODING_ISO_8859_1) + "
O
";
 
-        if (pOut)
+        osl_writeFile(pIn, aBuf.getStr(), sal_uInt64(aBuf.getLength()), 
&nWritten);
+
+        // Check for a header saying if the child managed to open the document
+        OStringBuffer aHeaderLine;
+        pBuffering = std::unique_ptr<Buffering>(new Buffering(pOut));
+        oslFileError eFileErr = pBuffering->readLine(aHeaderLine);
+        if (osl_File_E_None == eFileErr)
         {
-            // Check for a header saying if the child managed to open the 
document
-            OStringBuffer aHeaderLine;
-            pBuffering = std::unique_ptr<Buffering>(new Buffering(pOut));
-            oslFileError eFileErr = pBuffering->readLine(aHeaderLine);
-            if (osl_File_E_None == eFileErr)
+            auto aHeaderString = aHeaderLine.toString();
+            SAL_INFO("sdext.pdfimport", "Header line:" << aHeaderString);
+            if (!aHeaderString.startsWith("#OPEN"))
             {
-                SAL_INFO("sdext.pdfimport", "Header line:" << 
aHeaderLine.toString());
-            }
-            else
-            {
-                SAL_WARN("sdext.pdfimport", "Unable to read header line; " << 
eFileErr);
+                SAL_WARN("sdext.pdfimport", "Error from parser: " << 
aHeaderString);
                 bRet = false;
             }
         }
         else
         {
-            SAL_WARN("sdext.pdfimport", "No output file");
+            SAL_WARN("sdext.pdfimport", "Unable to read header line; " << 
eFileErr);
             bRet = false;
         }
 
         if (bRet && pOut && pErr)
         {
+            // Start the rendering by sending G command
+            osl_writeFile(pIn, "G
", 2, &nWritten);
+            SAL_INFO("sdext.pdfimport", "Sent Go command: " << nWritten);
+
             // read results of PDF parser. One line - one call to
             // OutputDev. stderr is used for alternate streams, like
             // embedded fonts and bitmaps
diff --git a/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx 
b/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx
index 35cf370e07fa..96fa917a79d4 100644
--- a/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx
+++ b/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx
@@ -137,37 +137,6 @@ int main(int argc, char **argv)
     globalParams->setupBaseFonts(nullptr);
 #endif
 
-    // try to read a possible open password from stdin
-    char aPwBuf[129];
-    aPwBuf[128] = 0;
-    if( ! fgets( aPwBuf, sizeof(aPwBuf)-1, stdin ) )
-        aPwBuf[0] = 0; // mark as empty
-    else
-    {
-        for( size_t i = 0; i < sizeof(aPwBuf); i++ )
-        {
-            if( aPwBuf[i] == '
' )
-            {
-                aPwBuf[i] = 0;
-                break;
-            }
-        }
-    }
-
-    // PDFDoc takes over ownership for all strings below
-    GooString* pFileName = new GooString(myStringToStdString(argv[1]));
-
-    // check for password string(s)
-    GooString* pOwnerPasswordStr( aPwBuf[0] != 0
-                                 ? new GooString( aPwBuf )
-                                 : (ownerPassword
-                                    ? new 
GooString(myStringToStdString(ownerPassword))
-                                    : nullptr ) );
-    GooString* pUserPasswordStr( aPwBuf[0] != 0
-                                ? new GooString( aPwBuf )
-                                : (userPassword
-                                  ? new 
GooString(myStringToStdString(userPassword))
-                                  : nullptr ) );
     if (outputFile)
 #if defined _WIN32
         g_binary_out = _wfopen(outputFile, L"wb");
@@ -181,38 +150,115 @@ int main(int argc, char **argv)
     _setmode( _fileno( g_binary_out ), _O_BINARY );
 #endif
 
+    // We receive commands from stdin, these can include a password.
+    bool bFinishedInput = false;
+    char *aPwBuf = strdup("");
+    std::unique_ptr<PDFDoc> pDocUnique;
+
+    do
+    {
+        // try to read an input line
+        char aInputBuf[129];
+        aInputBuf[128] = 0;
+        if (!fgets(aInputBuf, sizeof(aInputBuf)-1, stdin))
+        {
+            printf("#ERROR:-1:Empty Input
");
+            fflush(stdout);
+            return EXIT_FAILURE;
+        }
+        else
+        {
+            for (size_t i = 0; i < sizeof(aInputBuf); i++)
+            {
+                if (aInputBuf[i] == '
')
+                {
+                    aInputBuf[i] = 0;
+                    break;
+                }
+            }
+        }
+
+        switch (aInputBuf[0])
+        {
+            case 'E': // Exit
+                // We treat this as an error, we normally
+                // expect password input and then processing
+                printf("#ERROR:-1:Exit on request
");
+                fflush(stdout);
+                return EXIT_FAILURE;
+
+            case 'G': // Go! - actually render
+                if (pDocUnique == nullptr || !pDocUnique->isOk())
+                {
+                    printf("#ERROR:-1:PDF is not open
");
+                    fflush(stdout);
+                    return EXIT_FAILURE;
+                }
+                bFinishedInput = true;
+                break;
+
+            case 'O': // Open
+                // Try opening the document with any password we have
+                {
+                    // PDFDoc takes over ownership for all strings below
+                    GooString* pFileName = new 
GooString(myStringToStdString(argv[1]));
+
+                    // check for password string(s)
+                    GooString* pOwnerPasswordStr(aPwBuf[0] != 0
+                                                 ? new GooString(aPwBuf)
+                                                 : (ownerPassword
+                                                    ? new 
GooString(myStringToStdString(ownerPassword))
+                                                    : nullptr));
+                    GooString* pUserPasswordStr(aPwBuf[0] != 0
+                                                ? new GooString(aPwBuf)
+                                                : (userPassword
+                                                  ? new 
GooString(myStringToStdString(userPassword))
+                                                  : nullptr));
 #if POPPLER_CHECK_VERSION(22, 6, 0)
-    PDFDoc aDoc( std::make_unique<GooString>(pFileName),
-                 std::optional<GooString>(pOwnerPasswordStr),
-                 std::optional<GooString>(pUserPasswordStr) );
+                    pDocUnique = std::unique_ptr<PDFDoc>(
+                        new PDFDoc(std::make_unique<GooString>(pFileName),
+                                   std::optional<GooString>(pOwnerPasswordStr),
+                                   
std::optional<GooString>(pUserPasswordStr)));
 #else
-    PDFDoc aDoc( pFileName,
-                 pOwnerPasswordStr,
-                 pUserPasswordStr );
+                    pDocUnique = std::unique_ptr<PDFDoc>(
+                        new PDFDoc(pFileName, pOwnerPasswordStr, 
pUserPasswordStr));
 #endif
 
-    if (aDoc.isOk())
-    {
-        printf("#OPEN
");
-        fflush(stdout);
-    }
-    else
-    {
-        int err = aDoc.getErrorCode();
-        // e.g. #ERROR:1:   (code for OpenFile)
-        //      #ERROR:2:ENCRYPTED   For ones we need to detect, use text
-        printf( "#ERROR:%d:%s
", err, err==errEncrypted ? "ENCRYPTED" : "");
-        fflush(stdout);
-        return err;
-    }
+                    if (pDocUnique->isOk())
+                    {
+                        printf("#OPEN
");
+                    }
+                    else
+                    {
+                        int err = pDocUnique->getErrorCode();
+                        // e.g. #ERROR:1:   (code for OpenFile)
+                        //      #ERROR:2:ENCRYPTED   For ones we need to 
detect, use text
+                        printf("#ERROR:%d:%s
", err, err==errEncrypted ? "ENCRYPTED" : "");
+                    }
+                    fflush(stdout);
+                }
+                break;
+
+            case 'P': // Password
+                free(aPwBuf);
+                aPwBuf = strdup(aInputBuf + 1);
+                break;
+
+            default:
+                printf("#ERROR:-1:Unknown command %d
", aInputBuf[0]);
+                fflush(stdout);
+                return EXIT_FAILURE;
+        }
+    } while (!bFinishedInput);
 
-    pdfi::PDFOutDev aOutDev(&aDoc);
+    PDFDoc* pDoc = pDocUnique.release();
+    pdfi::PDFOutDev aOutDev(pDoc);
     if (options == TO_STRING_VIEW("SkipImages")) {
             aOutDev.setSkipImages(true);
     }
 
     // tell the receiver early - needed for proper progress calculation
-    const int nPages = aDoc.getNumPages();
+    const int nPages = pDoc->getNumPages();
     pdfi::PDFOutDev::setPageNum(nPages);
 
     // virtual resolution of the PDF OutputDev in dpi
@@ -221,12 +267,12 @@ int main(int argc, char **argv)
     // do the conversion
     for (int i = 1; i <= nPages; ++i)
     {
-        aDoc.displayPage(&aOutDev,
+        pDoc->displayPage(&aOutDev,
                 i,
                 PDFI_OUTDEV_RESOLUTION,
                 PDFI_OUTDEV_RESOLUTION,
                 0, true, true, true);
-        aDoc.processLinks(&aOutDev, i);
+        pDoc->processLinks(&aOutDev, i);
     }
 
     return 0;

Reply via email to