Attached files - PDF 2.0 attributes

This commit is contained in:
Jakub Melka
2020-08-07 19:29:22 +02:00
parent 6814e2755e
commit 79cf21775c
4 changed files with 99 additions and 3 deletions

View File

@ -402,6 +402,16 @@ std::vector<PDFInteger> PDFDocumentDataLoaderDecorator::readIntegerArray(const P
return std::vector<PDFInteger>(); return std::vector<PDFInteger>();
} }
PDFObjectReference PDFDocumentDataLoaderDecorator::readReference(const PDFObject& object) const
{
if (object.isReference())
{
return object.getReference();
}
return PDFObjectReference();
}
PDFObjectReference PDFDocumentDataLoaderDecorator::readReferenceFromDictionary(const PDFDictionary* dictionary, const char* key) const PDFObjectReference PDFDocumentDataLoaderDecorator::readReferenceFromDictionary(const PDFDictionary* dictionary, const char* key) const
{ {
const PDFObject& object = dictionary->get(key); const PDFObject& object = dictionary->get(key);

View File

@ -307,6 +307,10 @@ public:
/// \param object Object containing array of numbers /// \param object Object containing array of numbers
std::vector<PDFInteger> readIntegerArray(const PDFObject& object) const; std::vector<PDFInteger> readIntegerArray(const PDFObject& object) const;
/// Reads reference. If error occurs, then invalid reference is returned.
/// \param object Object containing reference
PDFObjectReference readReference(const PDFObject& object) const;
/// Reads reference from dictionary. If error occurs, then invalid reference is returned. /// Reads reference from dictionary. If error occurs, then invalid reference is returned.
/// \param dictionary Dictionary containing desired data /// \param dictionary Dictionary containing desired data
/// \param key Entry key /// \param key Entry key

View File

@ -107,6 +107,12 @@ const PDFEmbeddedFile* PDFFileSpecification::getPlatformFile() const
PDFFileSpecification PDFFileSpecification::parse(const PDFObjectStorage* storage, PDFObject object) PDFFileSpecification PDFFileSpecification::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFFileSpecification result; PDFFileSpecification result;
if (object.isReference())
{
result.m_selfReference = object.getReference();
}
object = storage->getObject(object); object = storage->getObject(object);
if (object.isString()) if (object.isString())
@ -117,7 +123,6 @@ PDFFileSpecification PDFFileSpecification::parse(const PDFObjectStorage* storage
{ {
PDFDocumentDataLoaderDecorator loader(storage); PDFDocumentDataLoaderDecorator loader(storage);
const PDFDictionary* dictionary = object.getDictionary(); const PDFDictionary* dictionary = object.getDictionary();
PDFObject collectionObject = dictionary->get("Cl");
result.m_fileSystem = loader.readNameFromDictionary(dictionary, "FS"); result.m_fileSystem = loader.readNameFromDictionary(dictionary, "FS");
result.m_F = loader.readStringFromDictionary(dictionary, "F"); result.m_F = loader.readStringFromDictionary(dictionary, "F");
@ -128,15 +133,53 @@ PDFFileSpecification PDFFileSpecification::parse(const PDFObjectStorage* storage
result.m_id = PDFFileIdentifier::parse(storage, dictionary->get("ID")); result.m_id = PDFFileIdentifier::parse(storage, dictionary->get("ID"));
result.m_volatile = loader.readBooleanFromDictionary(dictionary, "V", false); result.m_volatile = loader.readBooleanFromDictionary(dictionary, "V", false);
result.m_description = loader.readTextStringFromDictionary(dictionary, "Desc", QString()); result.m_description = loader.readTextStringFromDictionary(dictionary, "Desc", QString());
result.m_collection = collectionObject.isReference() ? collectionObject.getReference() : PDFObjectReference(); result.m_collection = loader.readReferenceFromDictionary(dictionary, "CI");
result.m_thumbnailReference = loader.readReferenceFromDictionary(dictionary, "Thumb");
result.m_encryptedPayload = dictionary->get("EP");
constexpr const std::array relationships = {
std::pair<const char*, AssociatedFileRelationship>{ "Unspecified", AssociatedFileRelationship::Unspecified },
std::pair<const char*, AssociatedFileRelationship>{ "Source", AssociatedFileRelationship::Source },
std::pair<const char*, AssociatedFileRelationship>{ "Data", AssociatedFileRelationship::Data },
std::pair<const char*, AssociatedFileRelationship>{ "Alternative", AssociatedFileRelationship::Alternative },
std::pair<const char*, AssociatedFileRelationship>{ "Supplement", AssociatedFileRelationship::Supplement },
std::pair<const char*, AssociatedFileRelationship>{ "EncryptedPayload", AssociatedFileRelationship::EncryptedPayload },
std::pair<const char*, AssociatedFileRelationship>{ "FormData", AssociatedFileRelationship::FormData },
std::pair<const char*, AssociatedFileRelationship>{ "Schema", AssociatedFileRelationship::Schema },
};
result.m_associatedFileRelationship = loader.readEnumByName(dictionary->get("AFRelationship"), relationships.begin(), relationships.end(), AssociatedFileRelationship::Unspecified);
PDFObject embeddedFiles = storage->getObject(dictionary->get("EF")); PDFObject embeddedFiles = storage->getObject(dictionary->get("EF"));
PDFObject relatedFiles = storage->getObject(dictionary->get("RF"));
if (embeddedFiles.isDictionary()) if (embeddedFiles.isDictionary())
{ {
const PDFDictionary* embeddedFilesDictionary = embeddedFiles.getDictionary(); const PDFDictionary* embeddedFilesDictionary = embeddedFiles.getDictionary();
const PDFDictionary* relatedFilesDictionary = relatedFiles.isDictionary() ? relatedFiles.getDictionary() : nullptr;
for (size_t i = 0; i < embeddedFilesDictionary->getCount(); ++i) for (size_t i = 0; i < embeddedFilesDictionary->getCount(); ++i)
{ {
result.m_embeddedFiles[embeddedFilesDictionary->getKey(i).getString()] = PDFEmbeddedFile::parse(storage, embeddedFilesDictionary->getValue(i)); QByteArray key = embeddedFilesDictionary->getKey(i).getString();
result.m_embeddedFiles[key] = PDFEmbeddedFile::parse(storage, embeddedFilesDictionary->getValue(i));
if (relatedFilesDictionary)
{
PDFObject relatedFileArrayObject = storage->getObject(relatedFilesDictionary->get(key));
if (relatedFileArrayObject.isArray())
{
const PDFArray* relatedFileArray = relatedFileArrayObject.getArray();
const size_t relatedFilesCount = relatedFileArray->getCount() / 2;
RelatedFiles& relatedFiles = result.m_relatedFiles[key];
relatedFiles.reserve(relatedFilesCount);
for (size_t i = 0; i < relatedFilesCount; ++i)
{
RelatedFile relatedFile;
relatedFile.name = loader.readString(relatedFileArray->getItem(2 * i));
relatedFile.fileReference = loader.readReference(relatedFileArray->getItem(2 * i + 1));
relatedFiles.emplace_back(qMove(relatedFile));
}
}
}
} }
} }
} }

View File

@ -75,6 +75,26 @@ class PDFFORQTLIBSHARED_EXPORT PDFFileSpecification
public: public:
explicit PDFFileSpecification() = default; explicit PDFFileSpecification() = default;
struct RelatedFile
{
QByteArray name;
PDFObjectReference fileReference;
};
using RelatedFiles = std::vector<RelatedFile>;
enum class AssociatedFileRelationship
{
Unspecified,
Source,
Data,
Alternative,
Supplement,
EncryptedPayload,
FormData,
Schema
};
/// Returns platform file name as string. It looks into the UF, F, /// Returns platform file name as string. It looks into the UF, F,
/// and platform names and selects the appropriate one. If error /// and platform names and selects the appropriate one. If error
/// occurs. then empty string is returned. /// occurs. then empty string is returned.
@ -92,8 +112,13 @@ public:
const PDFFileIdentifier& getFileIdentifier() const { return m_id; } const PDFFileIdentifier& getFileIdentifier() const { return m_id; }
bool isVolatile() const { return m_volatile; } bool isVolatile() const { return m_volatile; }
const QString& getDescription() const { return m_description; } const QString& getDescription() const { return m_description; }
PDFObjectReference getSelfReference() const { return m_selfReference; }
PDFObjectReference getCollection() const { return m_collection; } PDFObjectReference getCollection() const { return m_collection; }
PDFObjectReference getThumbnail() const { return m_thumbnailReference; }
const std::map<QByteArray, PDFEmbeddedFile>& getEmbeddedFiles() const { return m_embeddedFiles; } const std::map<QByteArray, PDFEmbeddedFile>& getEmbeddedFiles() const { return m_embeddedFiles; }
const std::map<QByteArray, RelatedFiles>& getRelatedFiles() const { return m_relatedFiles; }
const PDFObject& getEncryptedPayloadDictionary() const { return m_encryptedPayload; }
AssociatedFileRelationship getAssociatedFileRelationship() const { return m_associatedFileRelationship; }
static PDFFileSpecification parse(const PDFObjectStorage* storage, PDFObject object); static PDFFileSpecification parse(const PDFObjectStorage* storage, PDFObject object);
@ -122,11 +147,25 @@ private:
/// Description of the file (for example, if file is embedded file stream) /// Description of the file (for example, if file is embedded file stream)
QString m_description; QString m_description;
/// Self reference
PDFObjectReference m_selfReference;
/// Collection item dictionary reference /// Collection item dictionary reference
PDFObjectReference m_collection; PDFObjectReference m_collection;
/// Thumbnail reference
PDFObjectReference m_thumbnailReference;
/// Embedded files /// Embedded files
std::map<QByteArray, PDFEmbeddedFile> m_embeddedFiles; std::map<QByteArray, PDFEmbeddedFile> m_embeddedFiles;
/// Related files for embedded files
std::map<QByteArray, RelatedFiles> m_relatedFiles;
/// Encrypted payload dictionary (used in document wrapper)
PDFObject m_encryptedPayload;
AssociatedFileRelationship m_associatedFileRelationship = AssociatedFileRelationship::Unspecified;
}; };
} // namespace pdf } // namespace pdf