mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Document requirements
This commit is contained in:
@ -973,4 +973,151 @@ std::optional<PDFLegalAttestation> PDFLegalAttestation::parse(const PDFObjectSto
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFDocumentRequirements::ValidationResult PDFDocumentRequirements::validate(Requirements supported) const
|
||||||
|
{
|
||||||
|
ValidationResult result;
|
||||||
|
|
||||||
|
QStringList unsatisfiedRequirements;
|
||||||
|
for (const RequirementEntry& entry : m_requirements)
|
||||||
|
{
|
||||||
|
if (entry.requirement == None)
|
||||||
|
{
|
||||||
|
// Unrecognized entry, just add the penalty
|
||||||
|
result.penalty += entry.penalty;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supported.testFlag(entry.requirement))
|
||||||
|
{
|
||||||
|
result.penalty += entry.penalty;
|
||||||
|
unsatisfiedRequirements << getRequirementName(entry.requirement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unsatisfiedRequirements.isEmpty())
|
||||||
|
{
|
||||||
|
result.message = PDFTranslationContext::tr("Required features %1 are unsupported. Document processing can be limited.").arg(unsatisfiedRequirements.join(", "));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PDFDocumentRequirements::getRequirementName(Requirement requirement)
|
||||||
|
{
|
||||||
|
switch (requirement)
|
||||||
|
{
|
||||||
|
case OCInteract:
|
||||||
|
return PDFTranslationContext::tr("Optional Content User Interaction");
|
||||||
|
case OCAutoStates:
|
||||||
|
return PDFTranslationContext::tr("Optional Content Usage");
|
||||||
|
case AcroFormInteract:
|
||||||
|
return PDFTranslationContext::tr("Acrobat Forms");
|
||||||
|
case Navigation:
|
||||||
|
return PDFTranslationContext::tr("Navigation");
|
||||||
|
case Markup:
|
||||||
|
return PDFTranslationContext::tr("Markup Annotations");
|
||||||
|
case _3DMarkup:
|
||||||
|
return PDFTranslationContext::tr("Markup of 3D Content");
|
||||||
|
case Multimedia:
|
||||||
|
return PDFTranslationContext::tr("Multimedia");
|
||||||
|
case U3D:
|
||||||
|
return PDFTranslationContext::tr("U3D Format of PDF 3D");
|
||||||
|
case PRC:
|
||||||
|
return PDFTranslationContext::tr("PRC Format of PDF 3D");
|
||||||
|
case Action:
|
||||||
|
return PDFTranslationContext::tr("Actions");
|
||||||
|
case EnableJavaScripts:
|
||||||
|
return PDFTranslationContext::tr("JavaScript");
|
||||||
|
case Attachment:
|
||||||
|
return PDFTranslationContext::tr("Attached Files");
|
||||||
|
case AttachmentEditing:
|
||||||
|
return PDFTranslationContext::tr("Attached Files Modification");
|
||||||
|
case Collection:
|
||||||
|
return PDFTranslationContext::tr("Collections of Attached Files");
|
||||||
|
case CollectionEditing:
|
||||||
|
return PDFTranslationContext::tr("Collections of Attached Files (editation)");
|
||||||
|
case DigSigValidation:
|
||||||
|
return PDFTranslationContext::tr("Digital Signature Validation");
|
||||||
|
case DigSig:
|
||||||
|
return PDFTranslationContext::tr("Apply Digital Signature");
|
||||||
|
case DigSigMDP:
|
||||||
|
return PDFTranslationContext::tr("Digital Signature Validation (with MDP)");
|
||||||
|
case RichMedia:
|
||||||
|
return PDFTranslationContext::tr("Rich Media");
|
||||||
|
case Geospatial2D:
|
||||||
|
return PDFTranslationContext::tr("Geospatial 2D Features");
|
||||||
|
case Geospatial3D:
|
||||||
|
return PDFTranslationContext::tr("Geospatial 3D Features");
|
||||||
|
case DPartInteract:
|
||||||
|
return PDFTranslationContext::tr("Navigation for Document Parts");
|
||||||
|
case SeparationSimulation:
|
||||||
|
return PDFTranslationContext::tr("Separation Simulation");
|
||||||
|
case Transitions:
|
||||||
|
return PDFTranslationContext::tr("Transitions/Presentations");
|
||||||
|
case Encryption:
|
||||||
|
return PDFTranslationContext::tr("Encryption");
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFDocumentRequirements PDFDocumentRequirements::parse(const PDFObjectStorage* storage, const PDFObject& object)
|
||||||
|
{
|
||||||
|
PDFDocumentRequirements requirements;
|
||||||
|
|
||||||
|
PDFDocumentDataLoaderDecorator loader(storage);
|
||||||
|
requirements.m_requirements = loader.readObjectList<RequirementEntry>(object);
|
||||||
|
|
||||||
|
return requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFDocumentRequirements::RequirementEntry PDFDocumentRequirements::RequirementEntry::parse(const PDFObjectStorage* storage, const PDFObject& object)
|
||||||
|
{
|
||||||
|
RequirementEntry entry;
|
||||||
|
|
||||||
|
if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
|
||||||
|
{
|
||||||
|
PDFDocumentDataLoaderDecorator loader(storage);
|
||||||
|
|
||||||
|
constexpr const std::array requirementTypes = {
|
||||||
|
std::pair<const char*, Requirement>{ "OCInteract", OCInteract },
|
||||||
|
std::pair<const char*, Requirement>{ "OCAutoStates", OCAutoStates },
|
||||||
|
std::pair<const char*, Requirement>{ "AcroFormInteract", AcroFormInteract },
|
||||||
|
std::pair<const char*, Requirement>{ "Navigation", Navigation },
|
||||||
|
std::pair<const char*, Requirement>{ "Markup", Markup },
|
||||||
|
std::pair<const char*, Requirement>{ "3DMarkup", _3DMarkup },
|
||||||
|
std::pair<const char*, Requirement>{ "Multimedia", Multimedia },
|
||||||
|
std::pair<const char*, Requirement>{ "U3D", U3D },
|
||||||
|
std::pair<const char*, Requirement>{ "PRC", PRC },
|
||||||
|
std::pair<const char*, Requirement>{ "Action", Action },
|
||||||
|
std::pair<const char*, Requirement>{ "EnableJavaScripts", EnableJavaScripts },
|
||||||
|
std::pair<const char*, Requirement>{ "Attachment", Attachment },
|
||||||
|
std::pair<const char*, Requirement>{ "AttachmentEditing", AttachmentEditing },
|
||||||
|
std::pair<const char*, Requirement>{ "Collection", Collection },
|
||||||
|
std::pair<const char*, Requirement>{ "CollectionEditing", CollectionEditing },
|
||||||
|
std::pair<const char*, Requirement>{ "DigSigValidation", DigSigValidation },
|
||||||
|
std::pair<const char*, Requirement>{ "DigSig", DigSig },
|
||||||
|
std::pair<const char*, Requirement>{ "DigSigMDP", DigSigMDP },
|
||||||
|
std::pair<const char*, Requirement>{ "RichMedia", RichMedia },
|
||||||
|
std::pair<const char*, Requirement>{ "Geospatial2D", Geospatial2D },
|
||||||
|
std::pair<const char*, Requirement>{ "Geospatial3D", Geospatial3D },
|
||||||
|
std::pair<const char*, Requirement>{ "DPartInteract", DPartInteract },
|
||||||
|
std::pair<const char*, Requirement>{ "SeparationSimulation", SeparationSimulation },
|
||||||
|
std::pair<const char*, Requirement>{ "Transitions", Transitions },
|
||||||
|
std::pair<const char*, Requirement>{ "Encryption", Encryption }
|
||||||
|
};
|
||||||
|
|
||||||
|
entry.requirement = loader.readEnumByName(dictionary->get("S"), requirementTypes.begin(), requirementTypes.end(), None);
|
||||||
|
entry.handler = dictionary->get("RH");
|
||||||
|
entry.version = loader.readNameFromDictionary(dictionary, "V");
|
||||||
|
entry.penalty = loader.readIntegerFromDictionary(dictionary, "Penalty", 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -450,6 +450,82 @@ private:
|
|||||||
QString m_attestation;
|
QString m_attestation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Document can contain requirements for viewer application. This class
|
||||||
|
/// verifies, if this library and viewer application satisfies these requirements
|
||||||
|
/// and returns result.
|
||||||
|
class PDFFORQTLIBSHARED_EXPORT PDFDocumentRequirements
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Requirement
|
||||||
|
{
|
||||||
|
None = 0x00000000,
|
||||||
|
OCInteract = 0x00000001,
|
||||||
|
OCAutoStates = 0x00000002,
|
||||||
|
AcroFormInteract = 0x00000004,
|
||||||
|
Navigation = 0x00000008,
|
||||||
|
Markup = 0x00000010,
|
||||||
|
_3DMarkup = 0x00000020,
|
||||||
|
Multimedia = 0x00000040,
|
||||||
|
U3D = 0x00000080,
|
||||||
|
PRC = 0x00000100,
|
||||||
|
Action = 0x00000200,
|
||||||
|
EnableJavaScripts = 0x00000400,
|
||||||
|
Attachment = 0x00000800,
|
||||||
|
AttachmentEditing = 0x00001000,
|
||||||
|
Collection = 0x00002000,
|
||||||
|
CollectionEditing = 0x00004000,
|
||||||
|
DigSigValidation = 0x00008000,
|
||||||
|
DigSig = 0x00010000,
|
||||||
|
DigSigMDP = 0x00020000,
|
||||||
|
RichMedia = 0x00040000,
|
||||||
|
Geospatial2D = 0x00080000,
|
||||||
|
Geospatial3D = 0x00100000,
|
||||||
|
DPartInteract = 0x00200000,
|
||||||
|
SeparationSimulation = 0x00400000,
|
||||||
|
Transitions = 0x00800000,
|
||||||
|
Encryption = 0x01000000
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_FLAGS(Requirements, Requirement)
|
||||||
|
|
||||||
|
struct RequirementEntry
|
||||||
|
{
|
||||||
|
Requirement requirement = None;
|
||||||
|
PDFInteger penalty = 100;
|
||||||
|
QByteArray version;
|
||||||
|
PDFObject handler;
|
||||||
|
|
||||||
|
static RequirementEntry parse(const PDFObjectStorage* storage, const PDFObject& object);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ValidationResult
|
||||||
|
{
|
||||||
|
Requirements unsatisfied = None;
|
||||||
|
PDFInteger penalty = 0;
|
||||||
|
QString message;
|
||||||
|
|
||||||
|
bool isOk() const { return penalty < 100; }
|
||||||
|
bool isError() const { return !isOk(); }
|
||||||
|
bool isWarning() const { return isOk() && !message.isEmpty(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Validates requirements against supported requirements
|
||||||
|
ValidationResult validate(Requirements supported) const;
|
||||||
|
|
||||||
|
/// Returns string version of requirement
|
||||||
|
static QString getRequirementName(Requirement requirement);
|
||||||
|
|
||||||
|
/// Parses document requirements. If error occurs, empty
|
||||||
|
/// document requirements are returned.
|
||||||
|
/// \param storage Storage
|
||||||
|
/// \param object Object
|
||||||
|
static PDFDocumentRequirements parse(const PDFObjectStorage* storage, const PDFObject& object);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<RequirementEntry> m_requirements;
|
||||||
|
};
|
||||||
|
|
||||||
class PDFFORQTLIBSHARED_EXPORT PDFCatalog
|
class PDFFORQTLIBSHARED_EXPORT PDFCatalog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -1051,6 +1051,23 @@ void PDFViewerMainWindow::onDocumentReadingFinished()
|
|||||||
pdf::PDFModifiedDocument document(m_pdfDocument.data(), m_optionalContentActivity);
|
pdf::PDFModifiedDocument document(m_pdfDocument.data(), m_optionalContentActivity);
|
||||||
setDocument(document);
|
setDocument(document);
|
||||||
|
|
||||||
|
pdf::PDFDocumentRequirements requirements = pdf::PDFDocumentRequirements::parse(&m_pdfDocument->getStorage(), m_pdfDocument->getCatalog()->getRequirements());
|
||||||
|
constexpr pdf::PDFDocumentRequirements::Requirements requirementFlags = pdf::PDFDocumentRequirements::OCInteract |
|
||||||
|
pdf::PDFDocumentRequirements::OCAutoStates |
|
||||||
|
pdf::PDFDocumentRequirements::Navigation |
|
||||||
|
pdf::PDFDocumentRequirements::Attachment |
|
||||||
|
pdf::PDFDocumentRequirements::DigSigValidation |
|
||||||
|
pdf::PDFDocumentRequirements::Encryption;
|
||||||
|
pdf::PDFDocumentRequirements::ValidationResult requirementResult = requirements.validate(requirementFlags);
|
||||||
|
if (requirementResult.isError())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("PDF Viewer"), requirementResult.message);
|
||||||
|
}
|
||||||
|
else if (requirementResult.isWarning())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("PDF Viewer"), requirementResult.message);
|
||||||
|
}
|
||||||
|
|
||||||
statusBar()->showMessage(tr("Document '%1' was successfully loaded!").arg(m_fileInfo.fileName), 4000);
|
statusBar()->showMessage(tr("Document '%1' was successfully loaded!").arg(m_fileInfo.fileName), 4000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user