diff --git a/PdfForQtLib/sources/pdfdocument.cpp b/PdfForQtLib/sources/pdfdocument.cpp index 3dcaee0..4d36e12 100644 --- a/PdfForQtLib/sources/pdfdocument.cpp +++ b/PdfForQtLib/sources/pdfdocument.cpp @@ -402,6 +402,16 @@ std::vector PDFDocumentDataLoaderDecorator::readIntegerArray(const P return std::vector(); } +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 { const PDFObject& object = dictionary->get(key); diff --git a/PdfForQtLib/sources/pdfdocument.h b/PdfForQtLib/sources/pdfdocument.h index e087352..94d42d4 100644 --- a/PdfForQtLib/sources/pdfdocument.h +++ b/PdfForQtLib/sources/pdfdocument.h @@ -307,6 +307,10 @@ public: /// \param object Object containing array of numbers std::vector 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. /// \param dictionary Dictionary containing desired data /// \param key Entry key diff --git a/PdfForQtLib/sources/pdffile.cpp b/PdfForQtLib/sources/pdffile.cpp index dd496df..ab991b2 100644 --- a/PdfForQtLib/sources/pdffile.cpp +++ b/PdfForQtLib/sources/pdffile.cpp @@ -107,6 +107,12 @@ const PDFEmbeddedFile* PDFFileSpecification::getPlatformFile() const PDFFileSpecification PDFFileSpecification::parse(const PDFObjectStorage* storage, PDFObject object) { PDFFileSpecification result; + + if (object.isReference()) + { + result.m_selfReference = object.getReference(); + } + object = storage->getObject(object); if (object.isString()) @@ -117,7 +123,6 @@ PDFFileSpecification PDFFileSpecification::parse(const PDFObjectStorage* storage { PDFDocumentDataLoaderDecorator loader(storage); const PDFDictionary* dictionary = object.getDictionary(); - PDFObject collectionObject = dictionary->get("Cl"); result.m_fileSystem = loader.readNameFromDictionary(dictionary, "FS"); 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_volatile = loader.readBooleanFromDictionary(dictionary, "V", false); 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{ "Unspecified", AssociatedFileRelationship::Unspecified }, + std::pair{ "Source", AssociatedFileRelationship::Source }, + std::pair{ "Data", AssociatedFileRelationship::Data }, + std::pair{ "Alternative", AssociatedFileRelationship::Alternative }, + std::pair{ "Supplement", AssociatedFileRelationship::Supplement }, + std::pair{ "EncryptedPayload", AssociatedFileRelationship::EncryptedPayload }, + std::pair{ "FormData", AssociatedFileRelationship::FormData }, + std::pair{ "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 relatedFiles = storage->getObject(dictionary->get("RF")); if (embeddedFiles.isDictionary()) { const PDFDictionary* embeddedFilesDictionary = embeddedFiles.getDictionary(); + const PDFDictionary* relatedFilesDictionary = relatedFiles.isDictionary() ? relatedFiles.getDictionary() : nullptr; 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)); + } + } + } } } } diff --git a/PdfForQtLib/sources/pdffile.h b/PdfForQtLib/sources/pdffile.h index 47c19c5..32dc918 100644 --- a/PdfForQtLib/sources/pdffile.h +++ b/PdfForQtLib/sources/pdffile.h @@ -75,6 +75,26 @@ class PDFFORQTLIBSHARED_EXPORT PDFFileSpecification public: explicit PDFFileSpecification() = default; + struct RelatedFile + { + QByteArray name; + PDFObjectReference fileReference; + }; + + using RelatedFiles = std::vector; + + enum class AssociatedFileRelationship + { + Unspecified, + Source, + Data, + Alternative, + Supplement, + EncryptedPayload, + FormData, + Schema + }; + /// Returns platform file name as string. It looks into the UF, F, /// and platform names and selects the appropriate one. If error /// occurs. then empty string is returned. @@ -92,8 +112,13 @@ public: const PDFFileIdentifier& getFileIdentifier() const { return m_id; } bool isVolatile() const { return m_volatile; } const QString& getDescription() const { return m_description; } + PDFObjectReference getSelfReference() const { return m_selfReference; } PDFObjectReference getCollection() const { return m_collection; } + PDFObjectReference getThumbnail() const { return m_thumbnailReference; } const std::map& getEmbeddedFiles() const { return m_embeddedFiles; } + const std::map& 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); @@ -122,11 +147,25 @@ private: /// Description of the file (for example, if file is embedded file stream) QString m_description; + /// Self reference + PDFObjectReference m_selfReference; + /// Collection item dictionary reference PDFObjectReference m_collection; + /// Thumbnail reference + PDFObjectReference m_thumbnailReference; + /// Embedded files std::map m_embeddedFiles; + + /// Related files for embedded files + std::map m_relatedFiles; + + /// Encrypted payload dictionary (used in document wrapper) + PDFObject m_encryptedPayload; + + AssociatedFileRelationship m_associatedFileRelationship = AssociatedFileRelationship::Unspecified; }; } // namespace pdf