// Copyright (C) 2019-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 . #ifndef PDFFILE_H #define PDFFILE_H #include "pdfobject.h" #include #include namespace pdf { class PDFObjectStorage; /// File identifier according section 14.4 of PDF 2.0 specification. /// Each identifier consists of two parts - permanent identifier, which /// is unique identifier based on original document, and changing identifier, /// which is updated when document is being modified. class Pdf4QtLIBSHARED_EXPORT PDFFileIdentifier { public: explicit inline PDFFileIdentifier() = default; const QByteArray& getPermanentIdentifier() const { return m_permanentIdentifier; } const QByteArray& getChangingIdentifier() const { return m_changingIdentifier; } static PDFFileIdentifier parse(const PDFObjectStorage* storage, PDFObject object); private: QByteArray m_permanentIdentifier; QByteArray m_changingIdentifier; }; /// Provides description of collection item property field. It describes it's /// kind, data type, if content of the property should be presented to the user, /// and ordering, visibility and editability. class Pdf4QtLIBSHARED_EXPORT PDFCollectionField { public: explicit inline PDFCollectionField() = default; enum class Kind { Invalid, TextField, DateField, NumberField, FileName, Description, ModifiedDate, CreationDate, Size, CompressedSize }; enum class Value { Invalid, TextString, DateTime, Number }; Kind getKind() const { return m_kind; } Value getValue() const { return m_value; } QString getFieldName() const { return m_fieldName; } PDFInteger getOrder() const { return m_order; } bool isVisible() const { return m_visible; } bool isEditable() const { return m_editable; } static PDFCollectionField parse(const PDFObjectStorage* storage, PDFObject object); private: Kind m_kind = Kind::Invalid; Value m_value = Value::Invalid; QString m_fieldName; PDFInteger m_order = 0; bool m_visible = true; bool m_editable = false; }; /// Collection schema. Contains a list of defined fields. /// Schema can be queried for field definition. class Pdf4QtLIBSHARED_EXPORT PDFCollectionSchema { public: explicit inline PDFCollectionSchema() = default; /// Returns true, if schema is valid, i.e. some fields /// are defined. bool isValid() const { return !m_fields.empty(); } /// Returns collection field. This function always returns /// valid field definition. If field can't be found, then /// default field (invalid) is returned. /// \param key Key const PDFCollectionField* getField(const QByteArray& key) const; /// Returns true, if field definition with given key is valid. /// \param key Key bool isFieldValid(const QByteArray& key) const { return getField(key)->getKind() != PDFCollectionField::Kind::Invalid;} static PDFCollectionSchema parse(const PDFObjectStorage* storage, PDFObject object); private: std::map m_fields; }; /// Collection of file attachments. In the PDF file, attached files /// can be grouped in collection (if they are related to each other). class Pdf4QtLIBSHARED_EXPORT PDFCollection { public: explicit inline PDFCollection() = default; enum class ViewMode { /// Collection items should be displayed in details mode, /// for example, multi-column table, which contains icon, /// file name, and all properties listed in the schema. Details, /// Collection should be presented in tile mode, each file /// should have icon, and some information from the schema /// dictionary. Tiles, /// Collection should be initially hidden and should be presented /// to the user if user performs some explicit action. Hidden, /// Collection should be presented via Navigation entry Navigation }; enum class SplitMode { /// List of files nad preview should be splitted horizontally Horizontally, /// List of files and preview should be splitted vertically Vertically, /// No preview should be shown None }; enum ColorRole { Background, CardBackground, CardBorder, PrimaryText, SecondaryText, LastColorRole }; struct SortColumn { QByteArray field; bool ascending = true; }; using SortColumns = std::vector; /// Returns true, if collection schema is valid. If not, /// default file properties should be used. /// \returns true, if collection's schema is valid bool isSchemaValid() const { return m_schema.isValid(); } /// Returns collection field. This function always returns /// valid field definition. If field can't be found, then /// default field (invalid) is returned. /// \param key Key const PDFCollectionField* getField(const QByteArray& key) const { return m_schema.getField(key); } /// Returns true, if field definition with given key is valid. /// \param key Key bool isFieldValid(const QByteArray& key) const { return m_schema.isFieldValid(key); } /// Returns file field schema. Fields are properties of the files, /// such as size, description, date/time etc. const PDFCollectionSchema& getSchema() const { return m_schema; } /// Returns initial document, which shall be presented to the user /// in the ui (so interactive processor should display this file first). const QByteArray& getDocument() const { return m_document; } /// Returns view mode of the collection. It defines how collection /// should appear in user interface. ViewMode getViewMode() const { return m_viewMode; } /// Returns reference to a navigator (if it exists) PDFObjectReference getNavigator() const { return m_navigator; } /// Returns color for given role. Invalid color can be returned. /// If this occurs, default color should be used. /// \param role Color role QColor getColor(ColorRole role) const { return m_colors.at(role); } /// Returns sorting information (list of columns, defining /// sort key). If it is empty, default sorting should occur. const SortColumns& getSortColumns() const { return m_sortColumns; } /// If sort columns are empty, then is default sorting ascending? bool isSortAscending() const { return m_sortAscending; } /// Returns folder root (if collection has folders) PDFObjectReference getFolderRoot() const { return m_folderRoot; } /// Returns split mode of list of files and preview SplitMode getSplitMode() const { return m_splitMode; } /// Returns split proportion PDFReal getSplitPropertion() const { return m_splitProportion; } static PDFCollection parse(const PDFObjectStorage* storage, PDFObject object); private: PDFCollectionSchema m_schema; QByteArray m_document; ViewMode m_viewMode = ViewMode::Details; PDFObjectReference m_navigator; std::array m_colors; SortColumns m_sortColumns; bool m_sortAscending = true; PDFObjectReference m_folderRoot; SplitMode m_splitMode = SplitMode::None; PDFReal m_splitProportion = 30; }; /// Collection folder. Can contain subfolders and files. class Pdf4QtLIBSHARED_EXPORT PDFCollectionFolder { public: explicit inline PDFCollectionFolder() = default; PDFInteger getInteger() const { return m_ID; } const QString& getName() const { return m_name; } const QString& getDescription() const { return m_description; } PDFObjectReference getParent() const { return m_parent; } PDFObjectReference getChild() const { return m_child; } PDFObjectReference getNext() const { return m_next; } PDFObjectReference getCollection() const { return m_collection; } PDFObjectReference getThumbnail() const { return m_thumbnail; } const QDateTime& getCreatedDate() const { return m_created; } const QDateTime& getModifiedDate() const { return m_modified; } const std::vector& getFreeIds() const { return m_freeIds; } static PDFCollectionFolder parse(const PDFObjectStorage* storage, PDFObject object); private: PDFInteger m_ID = 0; QString m_name; QString m_description; PDFObjectReference m_parent; PDFObjectReference m_child; PDFObjectReference m_next; PDFObjectReference m_collection; PDFObjectReference m_thumbnail; QDateTime m_created; QDateTime m_modified; std::vector m_freeIds; }; /// Collection item. Contains properties of the collection item, /// for example, embedded file. class Pdf4QtLIBSHARED_EXPORT PDFCollectionItem { public: explicit inline PDFCollectionItem() = default; explicit inline PDFCollectionItem(const PDFObject& object) : m_object(object) { } /// Returns true, if collection item entry is valid bool isValid() const { return m_object.isDictionary(); } /// Returns string from property key. If property is invalid, empty /// string is returned, no exception is thrown. /// \param key Key /// \param storage Storage QString getString(const QByteArray& key, const PDFObjectStorage* storage) const; /// Returns date/time from property key. If property is invalid, invalid /// QDateTime is returned, no exception is thrown. /// \param key Key /// \param storage Storage QDateTime getDateTime(const QByteArray& key, const PDFObjectStorage* storage) const; /// Returns integer from property key. If property is invalid, zero /// integer is returned, no exception is thrown. /// \param key Key /// \param storage Storage PDFInteger getNumber(const QByteArray& key, const PDFObjectStorage* storage) const; /// Returns prefix string from property key. If property is invalid, empty /// string is returned, no exception is thrown. /// \param key Key /// \param storage Storage QString getPrefixString(const QByteArray& key, const PDFObjectStorage* storage) const; private: PDFObject m_object; }; /// Collection navigator. It contains modes of display. Interactive /// PDF processor should display first layout it is capable of. class Pdf4QtLIBSHARED_EXPORT PDFCollectionNavigator { public: explicit inline PDFCollectionNavigator() = default; enum Layout { None = 0x0000, Invalid = 0x0001, Details = 0x0002, Tile = 0x0004, Hidden = 0x0008, FilmStrip = 0x0010, FreeForm = 0x0020, Linear = 0x0040, Tree = 0x0080 }; Q_DECLARE_FLAGS(Layouts, Layout) /// Returns true, if navigator has valid layout bool hasLayout() const { return (m_layouts != None) && !m_layouts.testFlag(Invalid); } /// Returns current layouts Layouts getLayout() const { return m_layouts; } static PDFCollectionNavigator parse(const PDFObjectStorage* storage, PDFObject object); private: Layouts m_layouts = None; }; class Pdf4QtLIBSHARED_EXPORT PDFEmbeddedFile { public: explicit PDFEmbeddedFile() = default; bool isValid() const { return m_stream.isStream(); } const QByteArray& getSubtype() const { return m_subtype; } PDFInteger getSize() const { return m_size; } const QDateTime& getCreationDate() const { return m_creationDate; } const QDateTime& getModifiedDate() const { return m_modifiedDate; } const QByteArray& getChecksum() const { return m_checksum; } const PDFStream* getStream() const { return m_stream.getStream(); } static PDFEmbeddedFile parse(const PDFObjectStorage* storage, PDFObject object); private: PDFObject m_stream; QByteArray m_subtype; PDFInteger m_size = -1; QDateTime m_creationDate; QDateTime m_modifiedDate; QByteArray m_checksum; }; /// File specification class Pdf4QtLIBSHARED_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. QString getPlatformFileName() const; /// Returns platform file. const PDFEmbeddedFile* getPlatformFile() const; const QByteArray& getFileSystem() const { return m_fileSystem; } const QByteArray& getF() const { return m_F; } const QString& getUF() const { return m_UF; } const QByteArray& getDOS() const { return m_DOS; } const QByteArray& getMac() const { return m_Mac; } const QByteArray& getUnix() const { return m_Unix; } 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); private: /// Name of the file system used to interpret this file specification, /// usually, it is URL (this is only file system defined in PDF specification 1.7). QByteArray m_fileSystem; /// File specification string (for backward compatibility). If file system is URL, /// it contains unified resource locator. QByteArray m_F; /// File specification string as unicode. QString m_UF; QByteArray m_DOS; QByteArray m_Mac; QByteArray m_Unix; PDFFileIdentifier m_id; /// Is file volatile? I.e it is, for example, link to a video file from online camera? /// If this boolean is true, then file should never be cached. bool m_volatile = false; /// 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 #endif // PDFFILE_H