mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-02-28 09:27:42 +01:00
Tool for gathering info about document
This commit is contained in:
parent
b226e35208
commit
2acbcd68b2
@ -54,6 +54,7 @@ SOURCES += \
|
|||||||
sources/pdffile.cpp \
|
sources/pdffile.cpp \
|
||||||
sources/pdfform.cpp \
|
sources/pdfform.cpp \
|
||||||
sources/pdfitemmodels.cpp \
|
sources/pdfitemmodels.cpp \
|
||||||
|
sources/pdfjavascriptscanner.cpp \
|
||||||
sources/pdfjbig2decoder.cpp \
|
sources/pdfjbig2decoder.cpp \
|
||||||
sources/pdfmultimedia.cpp \
|
sources/pdfmultimedia.cpp \
|
||||||
sources/pdfobject.cpp \
|
sources/pdfobject.cpp \
|
||||||
@ -108,6 +109,7 @@ HEADERS += \
|
|||||||
sources/pdffile.h \
|
sources/pdffile.h \
|
||||||
sources/pdfform.h \
|
sources/pdfform.h \
|
||||||
sources/pdfitemmodels.h \
|
sources/pdfitemmodels.h \
|
||||||
|
sources/pdfjavascriptscanner.h \
|
||||||
sources/pdfjbig2decoder.h \
|
sources/pdfjbig2decoder.h \
|
||||||
sources/pdfmeshqualitysettings.h \
|
sources/pdfmeshqualitysettings.h \
|
||||||
sources/pdfmultimedia.h \
|
sources/pdfmultimedia.h \
|
||||||
|
@ -487,7 +487,7 @@ public:
|
|||||||
const PDFRendition* getRendition() const { return m_rendition.has_value() ? &m_rendition.value() : nullptr; }
|
const PDFRendition* getRendition() const { return m_rendition.has_value() ? &m_rendition.value() : nullptr; }
|
||||||
PDFObjectReference getAnnotation() const { return m_annotation; }
|
PDFObjectReference getAnnotation() const { return m_annotation; }
|
||||||
Operation getOperation() const { return m_operation; }
|
Operation getOperation() const { return m_operation; }
|
||||||
const QString& getJavascript() const { return m_javascript; }
|
const QString& getJavaScript() const { return m_javascript; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<PDFRendition> m_rendition;
|
std::optional<PDFRendition> m_rendition;
|
||||||
|
@ -1026,6 +1026,10 @@ PDFAnnotationAdditionalActions PDFAnnotationAdditionalActions::parse(const PDFOb
|
|||||||
result.m_actions[PageClosed] = PDFAction::parse(storage, dictionary->get("PC"));
|
result.m_actions[PageClosed] = PDFAction::parse(storage, dictionary->get("PC"));
|
||||||
result.m_actions[PageShow] = PDFAction::parse(storage, dictionary->get("PV"));
|
result.m_actions[PageShow] = PDFAction::parse(storage, dictionary->get("PV"));
|
||||||
result.m_actions[PageHide] = PDFAction::parse(storage, dictionary->get("PI"));
|
result.m_actions[PageHide] = PDFAction::parse(storage, dictionary->get("PI"));
|
||||||
|
result.m_actions[FormFieldModified] = PDFAction::parse(storage, dictionary->get("K"));
|
||||||
|
result.m_actions[FormFieldFormatted] = PDFAction::parse(storage, dictionary->get("F"));
|
||||||
|
result.m_actions[FormFieldValidated] = PDFAction::parse(storage, dictionary->get("V"));
|
||||||
|
result.m_actions[FormFieldCalculated] = PDFAction::parse(storage, dictionary->get("C"));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.m_actions[Default] = PDFAction::parse(storage, defaultAction);
|
result.m_actions[Default] = PDFAction::parse(storage, defaultAction);
|
||||||
|
@ -394,6 +394,10 @@ public:
|
|||||||
PageClosed,
|
PageClosed,
|
||||||
PageShow,
|
PageShow,
|
||||||
PageHide,
|
PageHide,
|
||||||
|
FormFieldModified,
|
||||||
|
FormFieldFormatted,
|
||||||
|
FormFieldValidated,
|
||||||
|
FormFieldCalculated,
|
||||||
Default,
|
Default,
|
||||||
End
|
End
|
||||||
};
|
};
|
||||||
@ -405,6 +409,9 @@ public:
|
|||||||
/// \param action Action type
|
/// \param action Action type
|
||||||
const PDFAction* getAction(Action action) const { return m_actions.at(action).get(); }
|
const PDFAction* getAction(Action action) const { return m_actions.at(action).get(); }
|
||||||
|
|
||||||
|
/// Returns array with all actions
|
||||||
|
const std::array<PDFActionPtr, End>& getActions() const { return m_actions; }
|
||||||
|
|
||||||
/// Parses annotation additional actions from the object. If object is invalid, then
|
/// Parses annotation additional actions from the object. If object is invalid, then
|
||||||
/// empty additional actions is constructed.
|
/// empty additional actions is constructed.
|
||||||
/// \param storage Object storage
|
/// \param storage Object storage
|
||||||
|
@ -1120,4 +1120,17 @@ PDFDocumentRequirements::RequirementEntry PDFDocumentRequirements::RequirementEn
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFPageAdditionalActions PDFPageAdditionalActions::parse(const PDFObjectStorage* storage, PDFObject object)
|
||||||
|
{
|
||||||
|
PDFPageAdditionalActions result;
|
||||||
|
|
||||||
|
if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
|
||||||
|
{
|
||||||
|
result.m_actions[Open] = PDFAction::parse(storage, dictionary->get("O"));
|
||||||
|
result.m_actions[Close] = PDFAction::parse(storage, dictionary->get("C"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -526,6 +526,38 @@ private:
|
|||||||
std::vector<RequirementEntry> m_requirements;
|
std::vector<RequirementEntry> m_requirements;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Storage for page additional actions
|
||||||
|
class PDFPageAdditionalActions
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Action
|
||||||
|
{
|
||||||
|
Open,
|
||||||
|
Close,
|
||||||
|
End
|
||||||
|
};
|
||||||
|
|
||||||
|
inline explicit PDFPageAdditionalActions() = default;
|
||||||
|
|
||||||
|
/// Returns action for given type. If action is invalid,
|
||||||
|
/// or not present, nullptr is returned.
|
||||||
|
/// \param action Action type
|
||||||
|
const PDFAction* getAction(Action action) const { return m_actions.at(action).get(); }
|
||||||
|
|
||||||
|
/// Returns array with all actions
|
||||||
|
const std::array<PDFActionPtr, End>& getActions() const { return m_actions; }
|
||||||
|
|
||||||
|
/// Parses page additional actions from the object. If object is invalid, then
|
||||||
|
/// empty additional actions is constructed.
|
||||||
|
/// \param storage Object storage
|
||||||
|
/// \param object Additional actions object
|
||||||
|
static PDFPageAdditionalActions parse(const PDFObjectStorage* storage, PDFObject object);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<PDFActionPtr, End> m_actions;
|
||||||
|
};
|
||||||
|
|
||||||
class PDFFORQTLIBSHARED_EXPORT PDFCatalog
|
class PDFFORQTLIBSHARED_EXPORT PDFCatalog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -582,6 +614,7 @@ public:
|
|||||||
const PDFDocumentSecurityStore& getDocumentSecurityStore() const { return m_documentSecurityStore; }
|
const PDFDocumentSecurityStore& getDocumentSecurityStore() const { return m_documentSecurityStore; }
|
||||||
const std::vector<PDFArticleThread>& getArticleThreads() const { return m_threads; }
|
const std::vector<PDFArticleThread>& getArticleThreads() const { return m_threads; }
|
||||||
const PDFAction* getDocumentAction(DocumentAction action) const { return m_documentActions.at(action).get(); }
|
const PDFAction* getDocumentAction(DocumentAction action) const { return m_documentActions.at(action).get(); }
|
||||||
|
const auto& getDocumentActions() const { return m_documentActions; }
|
||||||
const PDFObject& getMetadata() const { return m_metadata; }
|
const PDFObject& getMetadata() const { return m_metadata; }
|
||||||
const PDFObject& getStructureTreeRoot() const { return m_structureTreeRoot; }
|
const PDFObject& getStructureTreeRoot() const { return m_structureTreeRoot; }
|
||||||
const QString& getLanguage() const { return m_language; }
|
const QString& getLanguage() const { return m_language; }
|
||||||
@ -661,6 +694,9 @@ public:
|
|||||||
/// \returns Rendition, or nullptr
|
/// \returns Rendition, or nullptr
|
||||||
PDFObject getNamedRendition(const QByteArray& key) const;
|
PDFObject getNamedRendition(const QByteArray& key) const;
|
||||||
|
|
||||||
|
/// Returns all named JavaScript actions
|
||||||
|
const std::map<QByteArray, PDFActionPtr>& getNamedJavaScriptActions() const { return m_namedJavaScriptActions; }
|
||||||
|
|
||||||
/// Parses catalog from catalog dictionary. If object cannot be parsed, or error occurs,
|
/// Parses catalog from catalog dictionary. If object cannot be parsed, or error occurs,
|
||||||
/// then exception is thrown.
|
/// then exception is thrown.
|
||||||
static PDFCatalog parse(const PDFObject& catalog, const PDFDocument* document);
|
static PDFCatalog parse(const PDFObject& catalog, const PDFDocument* document);
|
||||||
|
@ -217,6 +217,9 @@ public:
|
|||||||
/// \param action Action type
|
/// \param action Action type
|
||||||
const PDFAction* getAction(PDFAnnotationAdditionalActions::Action action) const { return m_additionalActions.getAction(action); }
|
const PDFAction* getAction(PDFAnnotationAdditionalActions::Action action) const { return m_additionalActions.getAction(action); }
|
||||||
|
|
||||||
|
/// Returns container of actions
|
||||||
|
const PDFAnnotationAdditionalActions& getActions() const { return m_additionalActions; }
|
||||||
|
|
||||||
/// Parses form field from the object reference. If some error occurs
|
/// Parses form field from the object reference. If some error occurs
|
||||||
/// then null pointer is returned, no exception is thrown.
|
/// then null pointer is returned, no exception is thrown.
|
||||||
/// \param storage Storage
|
/// \param storage Storage
|
||||||
|
199
PdfForQtLib/sources/pdfjavascriptscanner.cpp
Normal file
199
PdfForQtLib/sources/pdfjavascriptscanner.cpp
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
// Copyright (C) 2020 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt 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
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt 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 PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdfjavascriptscanner.h"
|
||||||
|
#include "pdfaction.h"
|
||||||
|
#include "pdfform.h"
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
PDFJavaScriptScanner::PDFJavaScriptScanner(const PDFDocument* document) :
|
||||||
|
m_document(document)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFJavaScriptScanner::Entries PDFJavaScriptScanner::scan(const std::vector<PDFInteger>& pages, Options options) const
|
||||||
|
{
|
||||||
|
Entries result;
|
||||||
|
|
||||||
|
auto scanAction = [this, options, &result](PDFJavaScriptEntry::Type type, PDFInteger pageIndex, const PDFAction* action)
|
||||||
|
{
|
||||||
|
if (!result.empty() && options.testFlag(FindFirstOnly))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action)
|
||||||
|
{
|
||||||
|
std::vector<const PDFAction*> actions = action->getActionList();
|
||||||
|
for (const PDFAction* a : actions)
|
||||||
|
{
|
||||||
|
switch (a->getType())
|
||||||
|
{
|
||||||
|
case ActionType::JavaScript:
|
||||||
|
{
|
||||||
|
const PDFActionJavaScript* javascriptAction = dynamic_cast<const PDFActionJavaScript*>(a);
|
||||||
|
Q_ASSERT(javascriptAction);
|
||||||
|
|
||||||
|
result.emplace_back(type, pageIndex, javascriptAction->getJavaScript());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType::Rendition:
|
||||||
|
{
|
||||||
|
const PDFActionRendition* renditionAction = dynamic_cast<const PDFActionRendition*>(a);
|
||||||
|
Q_ASSERT(renditionAction);
|
||||||
|
|
||||||
|
if (!renditionAction->getJavaScript().isEmpty())
|
||||||
|
{
|
||||||
|
result.emplace_back(type, pageIndex, renditionAction->getJavaScript());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.empty() && options.testFlag(FindFirstOnly))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto scanContainer = [this, options, &scanAction](PDFJavaScriptEntry::Type type, PDFInteger pageIndex, const auto& container)
|
||||||
|
{
|
||||||
|
for (const PDFActionPtr& action : container)
|
||||||
|
{
|
||||||
|
scanAction(type, pageIndex, action.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const PDFCatalog* catalog = m_document->getCatalog();
|
||||||
|
|
||||||
|
if (options.testFlag(ScanDocument) && (result.empty() || !options.testFlag(FindFirstOnly)))
|
||||||
|
{
|
||||||
|
scanContainer(PDFJavaScriptEntry::Type::Document, -1, catalog->getDocumentActions());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.testFlag(ScanNamed) && (result.empty() || !options.testFlag(FindFirstOnly)))
|
||||||
|
{
|
||||||
|
for (const auto& actionItem : catalog->getNamedJavaScriptActions())
|
||||||
|
{
|
||||||
|
scanAction(PDFJavaScriptEntry::Type::Named, -1, actionItem.second.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.testFlag(ScanForm) && (result.empty() || !options.testFlag(FindFirstOnly)))
|
||||||
|
{
|
||||||
|
PDFForm form = PDFForm::parse(m_document, catalog->getFormObject());
|
||||||
|
if (form.isAcroForm() || form.isXFAForm())
|
||||||
|
{
|
||||||
|
auto fillActions = [this, &scanContainer](const PDFFormField* formField)
|
||||||
|
{
|
||||||
|
scanContainer(PDFJavaScriptEntry::Type::Form, -1, formField->getActions().getActions());
|
||||||
|
};
|
||||||
|
form.apply(fillActions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.testFlag(ScanPage) && (result.empty() || !options.testFlag(FindFirstOnly)))
|
||||||
|
{
|
||||||
|
std::vector<PDFInteger> scannedPages;
|
||||||
|
if (options.testFlag(AllPages))
|
||||||
|
{
|
||||||
|
scannedPages.resize(m_document->getCatalog()->getPageCount(), 0);
|
||||||
|
std::iota(scannedPages.begin(), scannedPages.end(), 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scannedPages = pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const PDFInteger pageIndex : scannedPages)
|
||||||
|
{
|
||||||
|
if (pageIndex < 0 || pageIndex >= PDFInteger(catalog->getPageCount()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.empty() && options.testFlag(FindFirstOnly))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageAdditionalActions pageActions = PDFPageAdditionalActions::parse(&m_document->getStorage(), catalog->getPage(pageIndex)->getAdditionalActions(&m_document->getStorage()));
|
||||||
|
scanContainer(PDFJavaScriptEntry::Type::Page, pageIndex, pageActions.getActions());
|
||||||
|
|
||||||
|
const std::vector<PDFObjectReference>& pageAnnotations = catalog->getPage(pageIndex)->getAnnotations();
|
||||||
|
for (PDFObjectReference annotationReference : pageAnnotations)
|
||||||
|
{
|
||||||
|
PDFAnnotationPtr annotationPtr = PDFAnnotation::parse(&m_document->getStorage(), annotationReference);
|
||||||
|
if (annotationPtr)
|
||||||
|
{
|
||||||
|
switch (annotationPtr->getType())
|
||||||
|
{
|
||||||
|
case AnnotationType::Link:
|
||||||
|
{
|
||||||
|
const PDFLinkAnnotation* linkAnnotation = dynamic_cast<const PDFLinkAnnotation*>(annotationPtr.get());
|
||||||
|
Q_ASSERT(linkAnnotation);
|
||||||
|
|
||||||
|
scanAction(PDFJavaScriptEntry::Type::Annotation, pageIndex, linkAnnotation->getAction());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AnnotationType::Screen:
|
||||||
|
{
|
||||||
|
const PDFScreenAnnotation* screenAnnotation = dynamic_cast<const PDFScreenAnnotation*>(annotationPtr.get());
|
||||||
|
Q_ASSERT(screenAnnotation);
|
||||||
|
|
||||||
|
scanAction(PDFJavaScriptEntry::Type::Annotation, pageIndex, screenAnnotation->getAction());
|
||||||
|
scanContainer(PDFJavaScriptEntry::Type::Annotation, pageIndex, screenAnnotation->getAdditionalActions().getActions());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AnnotationType::Widget:
|
||||||
|
{
|
||||||
|
const PDFWidgetAnnotation* widgetAnnotation = dynamic_cast<const PDFWidgetAnnotation*>(annotationPtr.get());
|
||||||
|
Q_ASSERT(widgetAnnotation);
|
||||||
|
|
||||||
|
scanAction(PDFJavaScriptEntry::Type::Annotation, pageIndex, widgetAnnotation->getAction());
|
||||||
|
scanContainer(PDFJavaScriptEntry::Type::Annotation, pageIndex, widgetAnnotation->getAdditionalActions().getActions());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PDFJavaScriptScanner::hasJavaScript() const
|
||||||
|
{
|
||||||
|
return !scan({ }, Options(AllPages | FindFirstOnly | ScanDocument | ScanNamed | ScanForm | ScanPage)).empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
86
PdfForQtLib/sources/pdfjavascriptscanner.h
Normal file
86
PdfForQtLib/sources/pdfjavascriptscanner.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright (C) 2020 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt 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
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt 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 PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFJAVASCRIPTSCANNER_H
|
||||||
|
#define PDFJAVASCRIPTSCANNER_H
|
||||||
|
|
||||||
|
#include "pdfdocument.h"
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PDFJavaScriptEntry
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
Document,
|
||||||
|
Named,
|
||||||
|
Form,
|
||||||
|
Page,
|
||||||
|
Annotation
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit PDFJavaScriptEntry() = default;
|
||||||
|
explicit PDFJavaScriptEntry(Type type, PDFInteger pageIndex, QString javaScript) :
|
||||||
|
type(type), pageIndex(pageIndex), javaScript(javaScript)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type = Type::Invalid;
|
||||||
|
PDFInteger pageIndex = -1;
|
||||||
|
QString javaScript;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Scans document for all javascript presence (in actions). Several option
|
||||||
|
/// can be set, for example, scan only document actions, or stop scanning,
|
||||||
|
/// when first javascript is found.
|
||||||
|
class PDFFORQTLIBSHARED_EXPORT PDFJavaScriptScanner
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFJavaScriptScanner(const PDFDocument* document);
|
||||||
|
|
||||||
|
enum Option
|
||||||
|
{
|
||||||
|
AllPages = 0x0001, ///< Scan all pages
|
||||||
|
FindFirstOnly = 0x0002, ///< Return only first javascript found
|
||||||
|
ScanDocument = 0x0004, ///< Scan document related actions for javascript
|
||||||
|
ScanNamed = 0x0008, ///< Scan named javascript in catalog
|
||||||
|
ScanForm = 0x0010, ///< Scan javascript in form actions
|
||||||
|
ScanPage = 0x0020, ///< Scan javascript in page annotations
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(Options, Option)
|
||||||
|
|
||||||
|
using Entries = std::vector<PDFJavaScriptEntry>;
|
||||||
|
|
||||||
|
/// Scans document for javascript actions using flags
|
||||||
|
Entries scan(const std::vector<PDFInteger>& pages, Options options) const;
|
||||||
|
|
||||||
|
/// Returns true, if document has any java script action. Calling
|
||||||
|
/// this function can be slow.
|
||||||
|
bool hasJavaScript() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const PDFDocument* m_document;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(pdf::PDFJavaScriptScanner::Options)
|
||||||
|
|
||||||
|
#endif // PDFJAVASCRIPTSCANNER_H
|
@ -86,11 +86,11 @@ void PDFDocumentPropertiesDialog::initializeProperties(const pdf::PDFDocument* d
|
|||||||
switch (info->trapped)
|
switch (info->trapped)
|
||||||
{
|
{
|
||||||
case pdf::PDFDocumentInfo::Trapped::True:
|
case pdf::PDFDocumentInfo::Trapped::True:
|
||||||
trapped = tr("True");
|
trapped = tr("Yes");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pdf::PDFDocumentInfo::Trapped::False:
|
case pdf::PDFDocumentInfo::Trapped::False:
|
||||||
trapped = tr("False");
|
trapped = tr("No");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pdf::PDFDocumentInfo::Trapped::Unknown:
|
case pdf::PDFDocumentInfo::Trapped::Unknown:
|
||||||
|
@ -43,6 +43,7 @@ SOURCES += \
|
|||||||
pdfoutputformatter.cpp \
|
pdfoutputformatter.cpp \
|
||||||
pdftoolabstractapplication.cpp \
|
pdftoolabstractapplication.cpp \
|
||||||
pdftoolattachments.cpp \
|
pdftoolattachments.cpp \
|
||||||
|
pdftoolinfo.cpp \
|
||||||
pdftoolverifysignatures.cpp \
|
pdftoolverifysignatures.cpp \
|
||||||
pdftoolxml.cpp
|
pdftoolxml.cpp
|
||||||
|
|
||||||
@ -59,5 +60,6 @@ HEADERS += \
|
|||||||
pdfoutputformatter.h \
|
pdfoutputformatter.h \
|
||||||
pdftoolabstractapplication.h \
|
pdftoolabstractapplication.h \
|
||||||
pdftoolattachments.h \
|
pdftoolattachments.h \
|
||||||
|
pdftoolinfo.h \
|
||||||
pdftoolverifysignatures.h \
|
pdftoolverifysignatures.h \
|
||||||
pdftoolxml.h
|
pdftoolxml.h
|
||||||
|
@ -151,6 +151,11 @@ void PDFToolAbstractApplication::initializeCommandLineParser(QCommandLineParser*
|
|||||||
parser->addOption(QCommandLineOption("text-codec", QString("Text codec used when writing text output to redirected standard output. UTF-8 is default."), "text codec", "UTF-8"));
|
parser->addOption(QCommandLineOption("text-codec", QString("Text codec used when writing text output to redirected standard output. UTF-8 is default."), "text codec", "UTF-8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optionFlags.testFlag(DateFormat))
|
||||||
|
{
|
||||||
|
parser->addOption(QCommandLineOption("date-format", "Console output date/time format (valid values: short|long|iso|rfc2822).", "date format", "short"));
|
||||||
|
}
|
||||||
|
|
||||||
if (optionFlags.testFlag(OpenDocument))
|
if (optionFlags.testFlag(OpenDocument))
|
||||||
{
|
{
|
||||||
parser->addOption(QCommandLineOption("pswd", "Password for encrypted document.", "password"));
|
parser->addOption(QCommandLineOption("pswd", "Password for encrypted document.", "password"));
|
||||||
@ -165,7 +170,6 @@ void PDFToolAbstractApplication::initializeCommandLineParser(QCommandLineParser*
|
|||||||
parser->addOption(QCommandLineOption("ver-no-cert-check", "Disable certificate validation."));
|
parser->addOption(QCommandLineOption("ver-no-cert-check", "Disable certificate validation."));
|
||||||
parser->addOption(QCommandLineOption("ver-details", "Print details (including certificate chain, if found)."));
|
parser->addOption(QCommandLineOption("ver-details", "Print details (including certificate chain, if found)."));
|
||||||
parser->addOption(QCommandLineOption("ver-ignore-exp-date", "Ignore certificate expiration date."));
|
parser->addOption(QCommandLineOption("ver-ignore-exp-date", "Ignore certificate expiration date."));
|
||||||
parser->addOption(QCommandLineOption("ver-date-format", "Console output date/time format (valid values: short|long|iso|rfc2822).", "ver-date-format", "short"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optionFlags.testFlag(XmlExport))
|
if (optionFlags.testFlag(XmlExport))
|
||||||
@ -184,6 +188,11 @@ void PDFToolAbstractApplication::initializeCommandLineParser(QCommandLineParser*
|
|||||||
parser->addOption(QCommandLineOption("att-target-dir", "Target directory to which is attachment saved.", "directory", QString()));
|
parser->addOption(QCommandLineOption("att-target-dir", "Target directory to which is attachment saved.", "directory", QString()));
|
||||||
parser->addOption(QCommandLineOption("att-target-file", "File, to which is attachment saved.", "target", QString()));
|
parser->addOption(QCommandLineOption("att-target-file", "File, to which is attachment saved.", "target", QString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optionFlags.testFlag(ComputeHashes))
|
||||||
|
{
|
||||||
|
parser->addOption(QCommandLineOption("compute-hashes", "Compute hashes (MD5, SHA1, SHA256...) of document."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser) const
|
PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser) const
|
||||||
@ -221,6 +230,31 @@ PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser
|
|||||||
options.outputCodec = parser->value("text-codec");
|
options.outputCodec = parser->value("text-codec");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optionFlags.testFlag(DateFormat))
|
||||||
|
{
|
||||||
|
QString dateFormat = parser->value("date-format");
|
||||||
|
if (dateFormat == "short")
|
||||||
|
{
|
||||||
|
options.outputDateFormat = Qt::DefaultLocaleShortDate;
|
||||||
|
}
|
||||||
|
else if (dateFormat == "long")
|
||||||
|
{
|
||||||
|
options.outputDateFormat = Qt::DefaultLocaleLongDate;
|
||||||
|
}
|
||||||
|
else if (dateFormat == "iso")
|
||||||
|
{
|
||||||
|
options.outputDateFormat = Qt::ISODate;
|
||||||
|
}
|
||||||
|
else if (dateFormat == "rfc2822")
|
||||||
|
{
|
||||||
|
options.outputDateFormat = Qt::RFC2822Date;
|
||||||
|
}
|
||||||
|
else if (!dateFormat.isEmpty())
|
||||||
|
{
|
||||||
|
PDFConsole::writeError(PDFToolTranslationContext::tr("Unknown console date/time format '%1'. Defaulting to short date/time format.").arg(dateFormat), options.outputCodec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (optionFlags.testFlag(OpenDocument))
|
if (optionFlags.testFlag(OpenDocument))
|
||||||
{
|
{
|
||||||
options.document = positionalArguments.isEmpty() ? QString() : positionalArguments.front();
|
options.document = positionalArguments.isEmpty() ? QString() : positionalArguments.front();
|
||||||
@ -235,28 +269,6 @@ PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser
|
|||||||
options.verificationOmitCertificateCheck = parser->isSet("ver-no-cert-check");
|
options.verificationOmitCertificateCheck = parser->isSet("ver-no-cert-check");
|
||||||
options.verificationPrintCertificateDetails = parser->isSet("ver-details");
|
options.verificationPrintCertificateDetails = parser->isSet("ver-details");
|
||||||
options.verificationIgnoreExpirationDate = parser->isSet("ver-ignore-exp-date");
|
options.verificationIgnoreExpirationDate = parser->isSet("ver-ignore-exp-date");
|
||||||
|
|
||||||
QString dateFormat = parser->value("ver-date-format");
|
|
||||||
if (dateFormat == "short")
|
|
||||||
{
|
|
||||||
options.verificationDateFormat = Qt::DefaultLocaleShortDate;
|
|
||||||
}
|
|
||||||
else if (dateFormat == "long")
|
|
||||||
{
|
|
||||||
options.verificationDateFormat = Qt::DefaultLocaleLongDate;
|
|
||||||
}
|
|
||||||
else if (dateFormat == "iso")
|
|
||||||
{
|
|
||||||
options.verificationDateFormat = Qt::ISODate;
|
|
||||||
}
|
|
||||||
else if (dateFormat == "rfc2822")
|
|
||||||
{
|
|
||||||
options.verificationDateFormat = Qt::RFC2822Date;
|
|
||||||
}
|
|
||||||
else if (!dateFormat.isEmpty())
|
|
||||||
{
|
|
||||||
PDFConsole::writeError(PDFToolTranslationContext::tr("Unknown console date/time format '%1'. Defaulting to short date/time format.").arg(dateFormat), options.outputCodec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optionFlags.testFlag(XmlExport))
|
if (optionFlags.testFlag(XmlExport))
|
||||||
@ -276,10 +288,15 @@ PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser
|
|||||||
options.attachmentsTargetFile = parser->isSet("att-target-file") ? parser->value("att-target-file") : QString();
|
options.attachmentsTargetFile = parser->isSet("att-target-file") ? parser->value("att-target-file") : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optionFlags.testFlag(ComputeHashes))
|
||||||
|
{
|
||||||
|
options.computeHashes = parser->isSet("compute-hashes");
|
||||||
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PDFToolAbstractApplication::readDocument(const PDFToolOptions& options, pdf::PDFDocument& document)
|
bool PDFToolAbstractApplication::readDocument(const PDFToolOptions& options, pdf::PDFDocument& document, QByteArray* sourceData)
|
||||||
{
|
{
|
||||||
bool isFirstPasswordAttempt = true;
|
bool isFirstPasswordAttempt = true;
|
||||||
auto passwordCallback = [&options, &isFirstPasswordAttempt](bool* ok) -> QString
|
auto passwordCallback = [&options, &isFirstPasswordAttempt](bool* ok) -> QString
|
||||||
@ -294,7 +311,13 @@ bool PDFToolAbstractApplication::readDocument(const PDFToolOptions& options, pdf
|
|||||||
switch (reader.getReadingResult())
|
switch (reader.getReadingResult())
|
||||||
{
|
{
|
||||||
case pdf::PDFDocumentReader::Result::OK:
|
case pdf::PDFDocumentReader::Result::OK:
|
||||||
|
{
|
||||||
|
if (sourceData)
|
||||||
|
{
|
||||||
|
*sourceData = reader.getSource();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case pdf::PDFDocumentReader::Result::Cancelled:
|
case pdf::PDFDocumentReader::Result::Cancelled:
|
||||||
{
|
{
|
||||||
|
@ -44,6 +44,9 @@ struct PDFToolOptions
|
|||||||
PDFOutputFormatter::Style outputStyle = PDFOutputFormatter::Style::Text;
|
PDFOutputFormatter::Style outputStyle = PDFOutputFormatter::Style::Text;
|
||||||
QString outputCodec;
|
QString outputCodec;
|
||||||
|
|
||||||
|
// For option 'DateFormat'
|
||||||
|
Qt::DateFormat outputDateFormat = Qt::DefaultLocaleShortDate;
|
||||||
|
|
||||||
// For option 'OpenDocument'
|
// For option 'OpenDocument'
|
||||||
QString document;
|
QString document;
|
||||||
QString password;
|
QString password;
|
||||||
@ -55,7 +58,6 @@ struct PDFToolOptions
|
|||||||
bool verificationOmitCertificateCheck = false;
|
bool verificationOmitCertificateCheck = false;
|
||||||
bool verificationPrintCertificateDetails = false;
|
bool verificationPrintCertificateDetails = false;
|
||||||
bool verificationIgnoreExpirationDate = false;
|
bool verificationIgnoreExpirationDate = false;
|
||||||
Qt::DateFormat verificationDateFormat = Qt::DefaultLocaleShortDate;
|
|
||||||
|
|
||||||
// For option 'XMLExport'
|
// For option 'XMLExport'
|
||||||
bool xmlExportStreams = false;
|
bool xmlExportStreams = false;
|
||||||
@ -69,6 +71,9 @@ struct PDFToolOptions
|
|||||||
QString attachmentsOutputDirectory;
|
QString attachmentsOutputDirectory;
|
||||||
QString attachmentsTargetFile;
|
QString attachmentsTargetFile;
|
||||||
bool attachmentsSaveAll = false;
|
bool attachmentsSaveAll = false;
|
||||||
|
|
||||||
|
// For option 'ComputeHashes'
|
||||||
|
bool computeHashes = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Base class for all applications
|
/// Base class for all applications
|
||||||
@ -101,6 +106,8 @@ public:
|
|||||||
SignatureVerification = 0x0004, ///< Flags for signature verification,
|
SignatureVerification = 0x0004, ///< Flags for signature verification,
|
||||||
XmlExport = 0x0008, ///< Flags for xml export
|
XmlExport = 0x0008, ///< Flags for xml export
|
||||||
Attachments = 0x0010, ///< Flags for attachments manipulating
|
Attachments = 0x0010, ///< Flags for attachments manipulating
|
||||||
|
DateFormat = 0x0020, ///< Date format
|
||||||
|
ComputeHashes = 0x0040, ///< Compute hashes
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(Options, Option)
|
Q_DECLARE_FLAGS(Options, Option)
|
||||||
|
|
||||||
@ -111,7 +118,14 @@ public:
|
|||||||
void initializeCommandLineParser(QCommandLineParser* parser) const;
|
void initializeCommandLineParser(QCommandLineParser* parser) const;
|
||||||
PDFToolOptions getOptions(QCommandLineParser* parser) const;
|
PDFToolOptions getOptions(QCommandLineParser* parser) const;
|
||||||
|
|
||||||
bool readDocument(const PDFToolOptions& options, pdf::PDFDocument& document);
|
protected:
|
||||||
|
/// Tries to read the document. If document is successfully read, true is returned,
|
||||||
|
/// if error occurs, then false is returned. Optionally, original document content
|
||||||
|
/// can also be retrieved.
|
||||||
|
/// \param options Options
|
||||||
|
/// \param document Document
|
||||||
|
/// \param[out] sourceData Pointer, to which source data are stored
|
||||||
|
bool readDocument(const PDFToolOptions& options, pdf::PDFDocument& document, QByteArray* sourceData = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This class stores information about all applications available. Application
|
/// This class stores information about all applications available. Application
|
||||||
|
@ -202,7 +202,7 @@ int PDFToolAttachmentsApplication::execute(const PDFToolOptions& options)
|
|||||||
|
|
||||||
PDFToolAbstractApplication::Options PDFToolAttachmentsApplication::getOptionsFlags() const
|
PDFToolAbstractApplication::Options PDFToolAttachmentsApplication::getOptionsFlags() const
|
||||||
{
|
{
|
||||||
return OpenDocument | Attachments;
|
return ConsoleFormat | OpenDocument | Attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pdftool
|
} // namespace pdftool
|
||||||
|
296
PdfTool/pdftoolinfo.cpp
Normal file
296
PdfTool/pdftoolinfo.cpp
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
// Copyright (C) 2020 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt 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
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt 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 PDFForQt. 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))
|
||||||
|
{
|
||||||
|
return ErrorDocumentReading;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLocale locale;
|
||||||
|
|
||||||
|
const pdf::PDFDocumentInfo* info = document.getInfo();
|
||||||
|
const pdf::PDFCatalog* catalog = document.getCatalog();
|
||||||
|
|
||||||
|
PDFOutputFormatter formatter(options.outputStyle, options.outputCodec);
|
||||||
|
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"), info->creationDate.toLocalTime().toString(options.outputDateFormat));
|
||||||
|
writeProperty("modified-date", PDFToolTranslationContext::tr("Modified date"), info->modifiedDate.toLocalTime().toString(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.type() == QVariant::DateTime) ? valueVariant.toDateTime().toLocalTime().toString(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::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);
|
||||||
|
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList permissions;
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
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
|
36
PdfTool/pdftoolinfo.h
Normal file
36
PdfTool/pdftoolinfo.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (C) 2020 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt 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
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt 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 PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFTOOLINFO_H
|
||||||
|
#define PDFTOOLINFO_H
|
||||||
|
|
||||||
|
#include "pdftoolabstractapplication.h"
|
||||||
|
|
||||||
|
namespace pdftool
|
||||||
|
{
|
||||||
|
|
||||||
|
class PDFToolInfoApplication : public PDFToolAbstractApplication
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual QString getStandardString(StandardString standardString) const override;
|
||||||
|
virtual int execute(const PDFToolOptions& options) override;
|
||||||
|
virtual Options getOptionsFlags() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdftool
|
||||||
|
|
||||||
|
#endif // PDFTOOLINFO_H
|
@ -165,8 +165,8 @@ int PDFToolVerifySignaturesApplication::execute(const PDFToolOptions& options)
|
|||||||
formatter.writeTableColumn("common-name", commonName);
|
formatter.writeTableColumn("common-name", commonName);
|
||||||
formatter.writeTableColumn("cert-status", options.verificationOmitCertificateCheck ? PDFToolTranslationContext::tr("Skipped") : signature.getCertificateStatusText());
|
formatter.writeTableColumn("cert-status", options.verificationOmitCertificateCheck ? PDFToolTranslationContext::tr("Skipped") : signature.getCertificateStatusText());
|
||||||
formatter.writeTableColumn("signature-status", signature.getSignatureStatusText());
|
formatter.writeTableColumn("signature-status", signature.getSignatureStatusText());
|
||||||
formatter.writeTableColumn("signing-date", signature.getSignatureDate().isValid() ? signature.getSignatureDate().toLocalTime().toString(options.verificationDateFormat) : QString());
|
formatter.writeTableColumn("signing-date", signature.getSignatureDate().isValid() ? signature.getSignatureDate().toLocalTime().toString(options.outputDateFormat) : QString());
|
||||||
formatter.writeTableColumn("timestamp-date", signature.getTimestampDate().isValid() ? signature.getTimestampDate().toLocalTime().toString(options.verificationDateFormat) : QString());
|
formatter.writeTableColumn("timestamp-date", signature.getTimestampDate().isValid() ? signature.getTimestampDate().toLocalTime().toString(options.outputDateFormat) : QString());
|
||||||
formatter.writeTableColumn("hash-algorithm", signature.getHashAlgorithms().join(", ").toUpper());
|
formatter.writeTableColumn("hash-algorithm", signature.getHashAlgorithms().join(", ").toUpper());
|
||||||
formatter.writeTableColumn("handler", QString::fromLatin1(signature.getSignatureHandler()));
|
formatter.writeTableColumn("handler", QString::fromLatin1(signature.getSignatureHandler()));
|
||||||
formatter.writeTableColumn("whole-signed", signature.hasFlag(pdf::PDFSignatureVerificationResult::Warning_Signature_NotCoveredBytes) ? PDFToolTranslationContext::tr("No") : PDFToolTranslationContext::tr("Yes"));
|
formatter.writeTableColumn("whole-signed", signature.hasFlag(pdf::PDFSignatureVerificationResult::Warning_Signature_NotCoveredBytes) ? PDFToolTranslationContext::tr("No") : PDFToolTranslationContext::tr("Yes"));
|
||||||
@ -194,8 +194,8 @@ int PDFToolVerifySignaturesApplication::execute(const PDFToolOptions& options)
|
|||||||
formatter.writeText("common-name", PDFToolTranslationContext::tr("Signed by: %1").arg(commonName));
|
formatter.writeText("common-name", PDFToolTranslationContext::tr("Signed by: %1").arg(commonName));
|
||||||
formatter.writeText("certificate-status", PDFToolTranslationContext::tr("Certificate status: %1").arg(options.verificationOmitCertificateCheck ? PDFToolTranslationContext::tr("Skipped") : signature.getCertificateStatusText()));
|
formatter.writeText("certificate-status", PDFToolTranslationContext::tr("Certificate status: %1").arg(options.verificationOmitCertificateCheck ? PDFToolTranslationContext::tr("Skipped") : signature.getCertificateStatusText()));
|
||||||
formatter.writeText("signature-status", PDFToolTranslationContext::tr("Signature status: %1").arg(signature.getSignatureStatusText()));
|
formatter.writeText("signature-status", PDFToolTranslationContext::tr("Signature status: %1").arg(signature.getSignatureStatusText()));
|
||||||
formatter.writeText("signing-date", PDFToolTranslationContext::tr("Signing date: %1").arg(signature.getSignatureDate().isValid() ? signature.getSignatureDate().toLocalTime().toString(options.verificationDateFormat) : QString()));
|
formatter.writeText("signing-date", PDFToolTranslationContext::tr("Signing date: %1").arg(signature.getSignatureDate().isValid() ? signature.getSignatureDate().toLocalTime().toString(options.outputDateFormat) : QString()));
|
||||||
formatter.writeText("timestamp-date", PDFToolTranslationContext::tr("Timestamp date: %1").arg(signature.getTimestampDate().isValid() ? signature.getTimestampDate().toLocalTime().toString(options.verificationDateFormat) : QString()));
|
formatter.writeText("timestamp-date", PDFToolTranslationContext::tr("Timestamp date: %1").arg(signature.getTimestampDate().isValid() ? signature.getTimestampDate().toLocalTime().toString(options.outputDateFormat) : QString()));
|
||||||
formatter.writeText("hash-algorithm", PDFToolTranslationContext::tr("Hash algorithm: %1").arg(signature.getHashAlgorithms().join(", ").toUpper()));
|
formatter.writeText("hash-algorithm", PDFToolTranslationContext::tr("Hash algorithm: %1").arg(signature.getHashAlgorithms().join(", ").toUpper()));
|
||||||
formatter.writeText("handler", PDFToolTranslationContext::tr("Handler: %1").arg(QString::fromLatin1(signature.getSignatureHandler())));
|
formatter.writeText("handler", PDFToolTranslationContext::tr("Handler: %1").arg(QString::fromLatin1(signature.getSignatureHandler())));
|
||||||
formatter.writeText("whole-signed", PDFToolTranslationContext::tr("Is whole document signed: %1").arg(signature.hasFlag(pdf::PDFSignatureVerificationResult::Warning_Signature_NotCoveredBytes) ? PDFToolTranslationContext::tr("No") : PDFToolTranslationContext::tr("Yes")));
|
formatter.writeText("whole-signed", PDFToolTranslationContext::tr("Is whole document signed: %1").arg(signature.hasFlag(pdf::PDFSignatureVerificationResult::Warning_Signature_NotCoveredBytes) ? PDFToolTranslationContext::tr("No") : PDFToolTranslationContext::tr("Yes")));
|
||||||
@ -307,7 +307,7 @@ int PDFToolVerifySignaturesApplication::execute(const PDFToolOptions& options)
|
|||||||
{
|
{
|
||||||
formatter.beginTableRow("valid-from");
|
formatter.beginTableRow("valid-from");
|
||||||
formatter.writeTableColumn("description", PDFToolTranslationContext::tr("Valid from"));
|
formatter.writeTableColumn("description", PDFToolTranslationContext::tr("Valid from"));
|
||||||
formatter.writeTableColumn("value", notValidBefore.toString(options.verificationDateFormat));
|
formatter.writeTableColumn("value", notValidBefore.toString(options.outputDateFormat));
|
||||||
formatter.endTableRow();
|
formatter.endTableRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +315,7 @@ int PDFToolVerifySignaturesApplication::execute(const PDFToolOptions& options)
|
|||||||
{
|
{
|
||||||
formatter.beginTableRow("valid-to");
|
formatter.beginTableRow("valid-to");
|
||||||
formatter.writeTableColumn("description", PDFToolTranslationContext::tr("Valid to"));
|
formatter.writeTableColumn("description", PDFToolTranslationContext::tr("Valid to"));
|
||||||
formatter.writeTableColumn("value", notValidAfter.toString(options.verificationDateFormat));
|
formatter.writeTableColumn("value", notValidAfter.toString(options.outputDateFormat));
|
||||||
formatter.endTableRow();
|
formatter.endTableRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +392,7 @@ int PDFToolVerifySignaturesApplication::execute(const PDFToolOptions& options)
|
|||||||
|
|
||||||
PDFToolAbstractApplication::Options PDFToolVerifySignaturesApplication::getOptionsFlags() const
|
PDFToolAbstractApplication::Options PDFToolVerifySignaturesApplication::getOptionsFlags() const
|
||||||
{
|
{
|
||||||
return PDFToolAbstractApplication::ConsoleFormat | PDFToolAbstractApplication::OpenDocument | PDFToolAbstractApplication::SignatureVerification;
|
return PDFToolAbstractApplication::ConsoleFormat | PDFToolAbstractApplication::OpenDocument | PDFToolAbstractApplication::SignatureVerification | PDFToolAbstractApplication::DateFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pdftool
|
} // namespace pdftool
|
||||||
|
Loading…
x
Reference in New Issue
Block a user