/* -*- 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/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "pdfioutdev_gpl.hxx"
#ifdef _WIN32
# include <io.h>
# include <fcntl.h> /*_O_BINARY*/
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
#ifndef SYSTEM_POPPLER
#include <string> // std::string
#include <cstddef> // std::size_t
#include <config_folders.h> //LIBO_SHARE_FOLDER
#endif
FILE* g_binary_out=stderr;
#ifdef _WIN32
// Use Unicode API
static const wchar_t *ownerPassword = nullptr;
static const wchar_t *userPassword = nullptr;
static const wchar_t *outputFile = nullptr;
static const wchar_t *options = L"";
#define TO_STRING_VIEW(s) std::wstring_view(L##s)
using my_string = std::wstring;
// Poppler expects UTF-8 strings on Windows - see its openFile in poppler/goo/gfile.cc.
static std::string myStringToStdString(std::wstring_view s)
{
int len = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), nullptr, 0, nullptr, nullptr);
char* buff = static_cast<char*>(_alloca(len * sizeof(char)));
len = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), buff, len, nullptr, nullptr);
return std::string(buff, len);
}
#else // ! _WIN32
static const char *ownerPassword = nullptr;
static const char *userPassword = nullptr;
static const char *outputFile = nullptr;
static const char *options = "";
#define TO_STRING_VIEW(s) std::string_view(s)
using my_string = std::string;
static std::string myStringToStdString(std::string&& s) { return std::move(s); }
#endif
#ifdef _WIN32
int wmain(int argc, wchar_t **argv)
#else
int main(int argc, char **argv)
#endif
{
int k = 1;
while (k < argc)
{
if (argv[k] == TO_STRING_VIEW("-f"))
{
outputFile = argv[k+1];
argc -= 2;
for (int j = k; j < argc; ++j)
argv[j] = argv[j+2];
}
else if (argv[k] == TO_STRING_VIEW("-o"))
{
options = argv[k+1];
argc -= 2;
for (int j = k; j < argc; ++j)
argv[j] = argv[j+2];
}
else if (argv[k] == TO_STRING_VIEW("-opw"))
{
ownerPassword = argv[k+1];
argc -= 2;
for (int j = k; j < argc; ++j)
argv[j] = argv[j+2];
}
else if (argv[k] == TO_STRING_VIEW("-upw"))
{
userPassword = argv[k+1];
argc -= 2;
for (int j = k; j < argc; ++j)
argv[j] = argv[j+2];
}
++k;
}
/* Get data directory location */
#ifdef SYSTEM_POPPLER
#if POPPLER_CHECK_VERSION(25, 2, 0)
const std::string datadir = "";
#else
const char* datadir = nullptr;
#endif
#else
/* Creates an absolute path to the poppler_data directory, by taking the path
* to the xpdfimport executable (provided in argv[0], and concatenating a
* relative path to the poppler_data directory from the program directory. */
const my_string execPath = argv[0];
const std::size_t filenameStartPos = execPath.find_last_of(TO_STRING_VIEW("/\\")) + 1;
const my_string programPath = execPath.substr(0, filenameStartPos);
const std::string popplerDataPath = myStringToStdString(programPath + my_string(TO_STRING_VIEW("../" LIBO_SHARE_FOLDER "/xpdfimport/poppler_data")));
const char* datadir = popplerDataPath.c_str();
#endif
// read config file
#if POPPLER_CHECK_VERSION(0, 83, 0)
globalParams = std::make_unique<GlobalParams>(datadir);
#else
globalParams = new GlobalParams(datadir);
#endif
globalParams->setErrQuiet(true);
#if defined(_MSC_VER)
globalParams->setupBaseFonts(nullptr);
#endif
if (outputFile)
#if defined _WIN32
g_binary_out = _wfopen(outputFile, L"wb");
#else
g_binary_out = fopen(outputFile,"wb");
#endif
#ifdef _WIN32
// Win actually modifies output for O_TEXT file mode, so need to
// revert to binary here
_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\n");
fflush(stdout);
return EXIT_FAILURE;
}
else
{
for (size_t i = 0; i < sizeof(aInputBuf); i++)
{
if (aInputBuf[i] == '\n')
{
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\n");
fflush(stdout);
return EXIT_FAILURE;
case 'G': // Go! - actually render
if (pDocUnique == nullptr || !pDocUnique->isOk())
{
printf("#ERROR:-1:PDF is not open\n");
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]));
#if POPPLER_CHECK_VERSION(22, 6, 0)
std::optional<GooString> ownerPasswordStr = {};
if (aPwBuf[0] != 0) {
ownerPasswordStr = std::make_optional<GooString>(aPwBuf);
} else if (ownerPassword) {
ownerPasswordStr = std::make_optional<GooString>(myStringToStdString(ownerPassword));
}
std::optional<GooString> userPasswordStr = {};
if (aPwBuf[0] != 0) {
userPasswordStr = std::make_optional<GooString>(aPwBuf);
} else if (userPassword) {
userPasswordStr = std::make_optional<GooString>(myStringToStdString(userPassword));
}
pDocUnique = std::make_unique<PDFDoc>(
std::unique_ptr<GooString>(pFileName), ownerPasswordStr, userPasswordStr);
#else
// 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));
pDocUnique = std::unique_ptr<PDFDoc>(
new PDFDoc(pFileName, pOwnerPasswordStr, pUserPasswordStr));
#endif
if (pDocUnique->isOk())
{
printf("#OPEN\n");
}
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\n", err, err==errEncrypted ? "ENCRYPTED" : "");
}
fflush(stdout);
}
break;
case 'P': // Password
free(aPwBuf);
aPwBuf = strdup(aInputBuf + 1);
break;
default:
printf("#ERROR:-1:Unknown command %d\n", aInputBuf[0]);
fflush(stdout);
return EXIT_FAILURE;
}
} while (!bFinishedInput);
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 = pDoc->getNumPages();
pdfi::PDFOutDev::setPageNum(nPages);
// virtual resolution of the PDF OutputDev in dpi
static const int PDFI_OUTDEV_RESOLUTION = 7200;
// do the conversion
for (int i = 1; i <= nPages; ++i)
{
pDoc->displayPage(&aOutDev,
i,
PDFI_OUTDEV_RESOLUTION,
PDFI_OUTDEV_RESOLUTION,
0, true, true, true);
pDoc->processLinks(&aOutDev, i);
}
return 0;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V522 There might be dereferencing of a potential null pointer 'aPwBuf'. Check lines: 208, 155.