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;