PDF4QT/PdfTool/pdftoolinfo.cpp
2022-09-17 13:56:41 +02:00

306 lines
12 KiB
C++

// Copyright (C) 2020-2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdftoolinfo.h"
#include "pdfform.h"
#include "pdfjavascriptscanner.h"
#include <QPageSize>
#include <QCryptographicHash>
namespace pdftool
{
static PDFToolInfoApplication s_infoApplication;
QString PDFToolInfoApplication::getStandardString(StandardString standardString) const
{
switch (standardString)
{
case Command:
return "info";
case Name:
return PDFToolTranslationContext::tr("Info");
case Description:
return PDFToolTranslationContext::tr("Retrieve basic informations about a document.");
default:
Q_ASSERT(false);
break;
}
return QString();
}
int PDFToolInfoApplication::execute(const PDFToolOptions& options)
{
pdf::PDFDocument document;
QByteArray sourceData;
if (!readDocument(options, document, &sourceData, false))
{
return ErrorDocumentReading;
}
QLocale locale;
const pdf::PDFDocumentInfo* info = document.getInfo();
const pdf::PDFCatalog* catalog = document.getCatalog();
PDFOutputFormatter formatter(options.outputStyle);
formatter.beginDocument("info", PDFToolTranslationContext::tr("Information about document %1").arg(options.document));
formatter.endl();
formatter.beginTable("properties", PDFToolTranslationContext::tr("Properties:"));
formatter.beginTableHeaderRow("header");
formatter.writeTableHeaderColumn("property", PDFToolTranslationContext::tr("Property"), Qt::AlignLeft);
formatter.writeTableHeaderColumn("value", PDFToolTranslationContext::tr("Value"), Qt::AlignLeft);
formatter.endTableHeaderRow();
auto writeProperty = [&formatter](const QString& propertyName, const QString& property, const QString& value)
{
formatter.beginTableRow(propertyName);
formatter.writeTableColumn("property", property);
formatter.writeTableColumn("value", value);
formatter.endTableRow();
};
writeProperty("title", PDFToolTranslationContext::tr("Title"), info->title);
writeProperty("subject", PDFToolTranslationContext::tr("Subject"), info->subject);
writeProperty("keywords", PDFToolTranslationContext::tr("Keywords"), info->keywords);
writeProperty("author", PDFToolTranslationContext::tr("Author"), info->author);
writeProperty("creator", PDFToolTranslationContext::tr("Creator"), info->creator);
writeProperty("producer", PDFToolTranslationContext::tr("Producer"), info->producer);
writeProperty("creation-date", PDFToolTranslationContext::tr("Creation date"), convertDateTimeToString(info->creationDate.toLocalTime(), options.outputDateFormat));
writeProperty("modified-date", PDFToolTranslationContext::tr("Modified date"), convertDateTimeToString(info->modifiedDate.toLocalTime(), options.outputDateFormat));
writeProperty("version", PDFToolTranslationContext::tr("Version"), QString::fromLatin1(document.getVersion()));
QString trapped;
switch (info->trapped)
{
case pdf::PDFDocumentInfo::Trapped::True:
trapped = PDFToolTranslationContext::tr("Yes");
break;
case pdf::PDFDocumentInfo::Trapped::False:
trapped = PDFToolTranslationContext::tr("No");
break;
case pdf::PDFDocumentInfo::Trapped::Unknown:
trapped = PDFToolTranslationContext::tr("Unknown");
break;
default:
Q_ASSERT(false);
break;
}
writeProperty("tagged", PDFToolTranslationContext::tr("Tagged"), trapped);
QString formType;
pdf::PDFForm form = pdf::PDFForm::parse(&document, catalog->getFormObject());
switch (form.getFormType())
{
case pdf::PDFForm::FormType::None:
formType = PDFToolTranslationContext::tr("None");
break;
case pdf::PDFForm::FormType::AcroForm:
formType = PDFToolTranslationContext::tr("AcroForm");
break;
case pdf::PDFForm::FormType::XFAForm:
formType = PDFToolTranslationContext::tr("XFA");
break;
default:
Q_ASSERT(false);
break;
}
writeProperty("form-type", PDFToolTranslationContext::tr("Form type"), formType);
const pdf::PDFInteger pageCount = catalog->getPageCount();
writeProperty("page-count", PDFToolTranslationContext::tr("Page count"), locale.toString(pageCount));
if (pageCount > 0)
{
const pdf::PDFPage* firstPage = catalog->getPage(0);
QSizeF pageSizeMM = firstPage->getRectMM(firstPage->getRotatedMediaBox()).size();
QPageSize pageSize(pageSizeMM, QPageSize::Millimeter, QString(), QPageSize::FuzzyOrientationMatch);
QString paperSizeString = QString("%1 x %2 mm").arg(locale.toString(pageSizeMM.width()), locale.toString(pageSizeMM.height()));
writeProperty("paper-format", PDFToolTranslationContext::tr("Paper format"), pageSize.name());
writeProperty("paper-size", PDFToolTranslationContext::tr("Paper size"), paperSizeString);
}
if (!info->extra.empty())
{
for (const auto& item : info->extra)
{
QString key = QString::fromLatin1(item.first);
QVariant valueVariant = item.second;
QString value = (valueVariant.typeId() == QMetaType::QDateTime) ? convertDateTimeToString(valueVariant.toDateTime().toLocalTime(), options.outputDateFormat) : valueVariant.toString();
writeProperty("custom-property", key, value);
}
}
writeProperty("file-name", PDFToolTranslationContext::tr("File name"), options.document);
writeProperty("file-size", PDFToolTranslationContext::tr("File size"), locale.toString(sourceData.size()));
pdf::PDFJavaScriptScanner scanner(&document);
writeProperty("javascript", PDFToolTranslationContext::tr("JavaScript"), scanner.hasJavaScript() ? PDFToolTranslationContext::tr("Yes") : PDFToolTranslationContext::tr("No"));
const pdf::PDFSecurityHandler* securityHandler = document.getStorage().getSecurityHandler();
const pdf::EncryptionMode mode = securityHandler->getMode();
QString modeString;
switch (mode)
{
case pdf::EncryptionMode::None:
modeString = PDFToolTranslationContext::tr("None");
break;
case pdf::EncryptionMode::Standard:
modeString = PDFToolTranslationContext::tr("Standard");
break;
case pdf::EncryptionMode::PublicKey:
modeString = PDFToolTranslationContext::tr("Public Key");
break;
case pdf::EncryptionMode::Custom:
modeString = PDFToolTranslationContext::tr("Custom");
break;
default:
Q_ASSERT(false);
break;
}
QString authorizationMode;
switch (securityHandler->getAuthorizationResult())
{
case pdf::PDFSecurityHandler::AuthorizationResult::NoAuthorizationRequired:
authorizationMode = PDFToolTranslationContext::tr("No authorization required");
break;
case pdf::PDFSecurityHandler::AuthorizationResult::OwnerAuthorized:
authorizationMode = PDFToolTranslationContext::tr("Authorized as owner");
break;
case pdf::PDFSecurityHandler::AuthorizationResult::UserAuthorized:
authorizationMode = PDFToolTranslationContext::tr("Authorized as user");
break;
default:
Q_ASSERT(false);
break;
}
writeProperty("encryption", PDFToolTranslationContext::tr("Encryption"), modeString);
writeProperty("authorized-as", PDFToolTranslationContext::tr("Authorization"), authorizationMode);
QStringList permissions;
if (securityHandler->getAuthorizationResult() != pdf::PDFSecurityHandler::AuthorizationResult::NoAuthorizationRequired)
{
writeProperty("metadata-encrypted", PDFToolTranslationContext::tr("Metadata encrypted"), securityHandler->isMetadataEncrypted() ? PDFToolTranslationContext::tr("Yes") : PDFToolTranslationContext::tr("No"));
writeProperty("version", PDFToolTranslationContext::tr("Version"), locale.toString(securityHandler->getVersion()));
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::PrintLowResolution))
{
permissions << PDFToolTranslationContext::tr("Print (low resolution)");
}
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::PrintHighResolution))
{
permissions << PDFToolTranslationContext::tr("Print");
}
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::CopyContent))
{
permissions << PDFToolTranslationContext::tr("Copy content");
}
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::Accessibility))
{
permissions << PDFToolTranslationContext::tr("Accessibility");
}
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::Assemble))
{
permissions << PDFToolTranslationContext::tr("Page assembling");
}
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::Modify))
{
permissions << PDFToolTranslationContext::tr("Modify content");
}
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::ModifyInteractiveItems))
{
permissions << PDFToolTranslationContext::tr("Modify interactive items");
}
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::ModifyFormFields))
{
permissions << PDFToolTranslationContext::tr("Form filling");
}
}
else
{
permissions << PDFToolTranslationContext::tr("All");
}
writeProperty("permissions", PDFToolTranslationContext::tr("Permissions"), permissions.join(", "));
formatter.endTable();
if (options.computeHashes)
{
formatter.endl();
formatter.beginTable("hashes", PDFToolTranslationContext::tr("File hashes:"));
formatter.beginTableHeaderRow("header");
formatter.writeTableHeaderColumn("algorithm", PDFToolTranslationContext::tr("Algorithm"), Qt::AlignLeft);
formatter.writeTableHeaderColumn("hash", PDFToolTranslationContext::tr("Hash"), Qt::AlignLeft);
formatter.endTableHeaderRow();
auto writeHash = [&formatter, &sourceData](QCryptographicHash::Algorithm algorithm, const QString& algorithmName, const QString& algorithmDescription)
{
formatter.beginTableRow(algorithmName);
formatter.writeTableColumn("algorithm", algorithmDescription);
formatter.writeTableColumn("hash", QString::fromLatin1(QCryptographicHash::hash(sourceData, algorithm).toHex()).toUpper());
formatter.endTableRow();
};
writeHash(QCryptographicHash::Md5, "MD5", PDFToolTranslationContext::tr("MD5"));
writeHash(QCryptographicHash::Sha1, "SHA1", PDFToolTranslationContext::tr("SHA1"));
writeHash(QCryptographicHash::Sha256, "SHA256", PDFToolTranslationContext::tr("SHA256"));
writeHash(QCryptographicHash::Sha384, "SHA384", PDFToolTranslationContext::tr("SHA384"));
writeHash(QCryptographicHash::Sha512, "SHA512", PDFToolTranslationContext::tr("SHA512"));
formatter.endTable();
}
formatter.endDocument();
PDFConsole::writeText(formatter.getString(), options.outputCodec);
return ExitSuccess;
}
PDFToolAbstractApplication::Options PDFToolInfoApplication::getOptionsFlags() const
{
return ConsoleFormat | OpenDocument | DateFormat | ComputeHashes;
}
} // namespace pdftool