// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2008 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tiffvisitor_int.hpp @brief Internal operations on a TIFF composite tree, implemented as visitor classes. @version $Rev$ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Apr-06, ahu: created */ #ifndef TIFFVISITOR_INT_HPP_ #define TIFFVISITOR_INT_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" #include "tifffwd_int.hpp" #include "types.hpp" // + standard includes #include #include #include #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions /*! @brief Abstract base class defining the interface for TIFF composite vistors (Visitor pattern) A concrete visitor class is used as shown in the example below. Accept() will invoke the member function corresponding to the concrete type of each component in the composite. @code void visitorExample(Exiv2::TiffComponent* tiffComponent, Exiv2::TiffVisitor& visitor) { tiffComponent->accept(visitor); } @endcode */ class TiffVisitor { public: //! Events for the stop/go flag. See setGo(). enum GoEvent { //! Signal to control traversing of the composite tree. geTraverse = 0, //! Signal used by TiffReader to signal an unknown makernote. geKnownMakernote = 1 // Note: If you add more events here, adjust the events_ constant too! }; private: static const int events_ = 2; //!< The number of stop/go flags. bool go_[events_]; //!< Array of stop/go flags. See setGo(). public: //! @name Creators //@{ //! Default constructor. Initialises all stop/go flags to true. TiffVisitor(); //! Virtual destructor virtual ~TiffVisitor() {} //@} //! @name Manipulators //@{ /*! @brief Set the stop/go flag: true for go, false for stop. This mechanism is used by visitors and components to signal special events. Specifically, TiffFinder sets the geTraverse flag as soon as it finds the correct component to signal to components that the search should be aborted. TiffReader uses geKnownMakernote to signal problems reading a makernote to the TiffMnEntry component. There is an array of flags, one for each defined \em event, so different signals can be used independent of each other. */ void setGo(GoEvent event, bool go); //! Operation to perform for a TIFF entry virtual void visitEntry(TiffEntry* object) =0; //! Operation to perform for a TIFF data entry virtual void visitDataEntry(TiffDataEntry* object) =0; //! Operation to perform for a TIFF image entry virtual void visitImageEntry(TiffImageEntry* object) =0; //! Operation to perform for a TIFF size entry virtual void visitSizeEntry(TiffSizeEntry* object) =0; //! Operation to perform for a TIFF directory virtual void visitDirectory(TiffDirectory* object) =0; /*! @brief Operation to perform for a TIFF directory, after all components and before the next entry is processed. */ virtual void visitDirectoryNext(TiffDirectory* /*object*/) {} /*! @brief Operation to perform for a TIFF directory, at the end of the processing. */ virtual void visitDirectoryEnd(TiffDirectory* /*object*/) {} //! Operation to perform for a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object) =0; //! Operation to perform for the makernote component virtual void visitMnEntry(TiffMnEntry* object) =0; //! Operation to perform for an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object) =0; //! Operation to perform after processing an IFD makernote virtual void visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/) {} //! Operation to perform for an array entry (as found in Canon makernotes) virtual void visitArrayEntry(TiffArrayEntry* object) =0; //! Operation to perform for an array element virtual void visitArrayElement(TiffArrayElement* object) =0; //@} //! @name Accessors //@{ //! Check if stop flag for \em event is clear, return true if it's clear. bool go(GoEvent event) const; //@} }; // class TiffVisitor /*! @brief Search the composite for a component with \em tag and \em group. Return a pointer to the component or 0, if not found. The class is ready for a first search after construction and can be re-initialized with init(). */ class TiffFinder : public TiffVisitor { public: //! @name Creators //@{ //! Constructor, taking \em tag and \em group of the component to find. TiffFinder(uint16_t tag, uint16_t group) : tag_(tag), group_(group), tiffComponent_(0) {} //! Virtual destructor virtual ~TiffFinder() {} //@} //! @name Manipulators //@{ //! Find tag and group in a TIFF entry virtual void visitEntry(TiffEntry* object); //! Find tag and group in a TIFF data entry virtual void visitDataEntry(TiffDataEntry* object); //! Find tag and group in a TIFF image entry virtual void visitImageEntry(TiffImageEntry* object); //! Find tag and group in a TIFF size entry virtual void visitSizeEntry(TiffSizeEntry* object); //! Find tag and group in a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Find tag and group in a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object); //! Find tag and group in a TIFF makernote virtual void visitMnEntry(TiffMnEntry* object); //! Find tag and group in an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Find tag and group in an array entry component virtual void visitArrayEntry(TiffArrayEntry* object); //! Find tag and group in an array element virtual void visitArrayElement(TiffArrayElement* object); //! Check if \em object matches \em tag and \em group void findObject(TiffComponent* object); //! Initialize the Finder for a new search. void init(uint16_t tag, uint16_t group); //@} //! @name Accessors //@{ /*! @brief Return the search result. 0 if no TIFF component was found for the tag and group combination. */ TiffComponent* result() const { return tiffComponent_; } //@} private: uint16_t tag_; uint16_t group_; TiffComponent* tiffComponent_; }; // class TiffFinder /*! @brief TIFF composite visitor to decode metadata from the TIFF tree and add it to an Image, which is supplied in the constructor (Visitor pattern). Used by TiffParser to decode the metadata from a TIFF composite. */ class TiffDecoder : public TiffVisitor { public: //! @name Creators //@{ /*! @brief Constructor, taking metadata containers to add the metadata to, the root element of the composite to decode and a FindDecoderFct function to get the decoder function for each tag. */ TiffDecoder( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, TiffComponent* const pRoot, FindDecoderFct findDecoderFct ); //! Virtual destructor virtual ~TiffDecoder() {} //@} //! @name Manipulators //@{ //! Decode a TIFF entry virtual void visitEntry(TiffEntry* object); //! Decode a TIFF data entry virtual void visitDataEntry(TiffDataEntry* object); //! Decode a TIFF image entry virtual void visitImageEntry(TiffImageEntry* object); //! Decode a TIFF size entry virtual void visitSizeEntry(TiffSizeEntry* object); //! Decode a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Decode a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object); //! Decode a TIFF makernote virtual void visitMnEntry(TiffMnEntry* object); //! Decode an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Decode an array entry component virtual void visitArrayEntry(TiffArrayEntry* object); //! Decode an array element virtual void visitArrayElement(TiffArrayElement* object); //! Entry function, determines how to decode each tag void decodeTiffEntry(const TiffEntryBase* object); //! Decode a standard TIFF entry void decodeStdTiffEntry(const TiffEntryBase* object); //! Decode Olympus Thumbnail from the TIFF makernote into IFD1 void decodeOlympThumb(const TiffEntryBase* object); //! Decode SubIFD contents to Image group if it contains primary image data void decodeSubIfd(const TiffEntryBase* object); //! Decode IPTC data from an IPTCNAA tag or Photoshop ImageResources void decodeIptc(const TiffEntryBase* object); //! Decode XMP packet from an XMLPacket tag void decodeXmp(const TiffEntryBase* object); //@} private: //! Tag priorities enum Prio { pvNormal, pvHigh }; //! @name Manipulators //@{ //! Set an Exif tag in the image. void setExifTag(const ExifKey& key, const Value* pValue, Prio prio); /*! @brief Get the data for a \em tag and \em group, either from the \em object provided, if it matches or from the matching element in the hierarchy. Populates \em pData and \em size with the result. If no matching element is found the function leaves both of these parameters unchanged. */ void getObjData(byte const*& pData, long& size, uint16_t tag, uint16_t group, const TiffEntryBase* object); //@} private: // DATA ExifData& exifData_; //!< Exif metadata container IptcData& iptcData_; //!< IPTC metadata container XmpData& xmpData_; //!< XMP metadata container TiffComponent* const pRoot_; //!< Root element of the composite const FindDecoderFct findDecoderFct_; //!< Ptr to the function to find special decoding functions std::string make_; //!< Camera make, determined from the tags to decode //! Type used to remember tag 0x00fe (NewSubfileType) for each group typedef std::map GroupType; GroupType groupType_; //!< NewSubfileType for each group bool decodedIptc_; //!< Indicates if IPTC has been decoded yet //! Type used as the container for "priority keys" typedef std::set PriorityKeys; PriorityKeys priorityKeys_; //!< Priority keys }; // class TiffDecoder /*! @brief TIFF composite visitor to encode metadata from an image to the TIFF tree. The metadata containers and root element of the tree are supplied in the constructor. Used by TiffParserWorker to encode the metadata into a TIFF composite. For non-intrusive writing, the encoder is used as a visitor (by passing it to the accept() member of a TiffComponent). The composite tree is then traversed and metadata from the image is used to encode each existing component. For intrusive writing, add() is called, which loops through the metadata and creates and populates corresponding TiffComponents as needed. */ class TiffEncoder : public TiffVisitor { public: //! @name Creators //@{ /*! @brief Constructor, taking the root element of the composite to encode to, the image with the metadata to encode and a function to find special encoders. */ TiffEncoder( const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData, TiffComponent* pRoot, ByteOrder byteOrder, FindEncoderFct findEncoderFct ); //! Virtual destructor virtual ~TiffEncoder() {} //@} //! @name Manipulators //@{ //! Encode a TIFF entry virtual void visitEntry(TiffEntry* object); //! Encode a TIFF data entry virtual void visitDataEntry(TiffDataEntry* object); //! Encode a TIFF image entry virtual void visitImageEntry(TiffImageEntry* object); //! Encode a TIFF size entry virtual void visitSizeEntry(TiffSizeEntry* object); //! Encode a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Update directory entries virtual void visitDirectoryNext(TiffDirectory* object); //! Encode a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object); //! Encode a TIFF makernote virtual void visitMnEntry(TiffMnEntry* object); //! Encode an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Reset encoder to its original state, undo makernote specific settings virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object); //! Encode an array entry component virtual void visitArrayEntry(TiffArrayEntry* object); //! Encode an array element virtual void visitArrayElement(TiffArrayElement* object); /*! @brief Top level encoder function. Determines how to encode each TIFF component. This function is called by the visit methods of the encoder as well as the add() method. If no \em datum is provided, search the metadata based on tag and group of the \em object. This is the case if the function is called from a visit method. Then check if a special encoder function is registered for the tag, and if so use it to encode the \em object. Else use the callback encoder function at the object (which results in a double-dispatch to the appropriate encoding function of the encoder. @param object Object in the TIFF component tree to encode. @param datum The corresponding metadatum with the updated value. @note Encoder functions may use metadata other than \em datum. */ void encodeTiffComponent( TiffEntryBase* object, const Exifdatum* datum =0 ); //! Callback encoder function for an array element. void encodeArrayElement(TiffArrayElement* object, const Exifdatum* datum); //! Callback encoder function for an array entry. void encodeArrayEntry(TiffArrayEntry* object, const Exifdatum* datum); //! Callback encoder function for a data entry. void encodeDataEntry(TiffDataEntry* object, const Exifdatum* datum); //! Callback encoder function for a standard TIFF entry void encodeTiffEntry(TiffEntry* object, const Exifdatum* datum); //! Callback encoder function for an image entry. void encodeImageEntry(TiffImageEntry* object, const Exifdatum* datum); //! Callback encoder function for a %Makernote entry. void encodeMnEntry(TiffMnEntry* object, const Exifdatum* datum); //! Callback encoder function for a size entry. void encodeSizeEntry(TiffSizeEntry* object, const Exifdatum* datum); //! Callback encoder function for a sub-IFD entry. void encodeSubIfd(TiffSubIfd* object, const Exifdatum* datum); //! Special encoder function for the base part of a TIFF entry. void encodeTiffEntryBase(TiffEntryBase* object, const Exifdatum* datum); //! Special encoder function for an offset entry. void encodeOffsetEntry(TiffEntryBase* object, const Exifdatum* datum); //! Special encoder function to encode an Olympus Thumbnail from the TIFF makernote into IFD1. void encodeOlympThumb(TiffEntryBase* object, const Exifdatum* datum); //! Special encoder function to encode SubIFD contents to Image group if it contains primary image data // Todo void encodeNikonSubIfd(TiffEntryBase* object, const Exifdatum* datum); //! Special encoder function to encode IPTC data to an IPTCNAA or Photoshop ImageResources tag. void encodeIptc(TiffEntryBase* object, const Exifdatum* datum); //! Special encoder function for a standard TIFF entry using big endian byte order. void encodeBigEndianEntry(TiffEntryBase* object, const Exifdatum* datum); /*! @brief Add metadata from image to the TIFF composite. For each Exif metadatum, the corresponding TiffComponent is created if necessary and populated using encodeTiffComponent(). The add() function is used during intrusive writing, to create a new TIFF structure. @note For non-intrusive writing, the encoder is used as a visitor (by passing it to the accept() member of a TiffComponent). The composite tree is then traversed and metadata from the image is used to encode each existing component. */ void add( TiffComponent* pRootDir, TiffComponent* pSourceDir, TiffCompFactoryFct createFct ); //! Set the dirty flag and end of traversing signal. void setDirty(bool flag =true); //@} //! @name Accessors //@{ /*! @brief Return the applicable byte order. May be different for the Makernote and the rest of the TIFF entries. */ ByteOrder byteOrder() const { return byteOrder_; } /*! @brief True if any tag was deleted or allocated in the process of visiting a TIFF composite tree. */ bool dirty() const; //! Return the write method used. WriteMethod writeMethod() const { return writeMethod_; } //@} private: //! @name Manipulators //@{ /*! Encode IPTC data. Updates or adds tag Exif.Image.IPTCNAA, updates but never adds tag Exif.Image.ImageResources. This method is called from the constructor. */ void encodeIptc(); /*! Encode XMP data. Adds tag Exif.Image.XMLPacket with the XMP packet. This method is called from the constructor. */ void encodeXmp(); //@} //! @name Accessors //@{ /*! @brief Update a directory entry. This is called after all directory entries are encoded. It takes care of type and count changes and size shrinkage for non-intrusive writing. */ uint32_t updateDirEntry(byte* buf, ByteOrder byteOrder, TiffComponent* pTiffComponent) const; //@} private: // DATA ExifData exifData_; //!< Copy of the Exif data to encode IptcData iptcData_; //!< Copy of the IPTC data to encode XmpData xmpData_; //!< Copy of the XMP data to encode bool del_; //!< Indicates if Exif data entries should be deleted after encoding TiffComponent* pRoot_; //!< Root element of the composite TiffComponent* pSourceTree_; //!< Parsed source tree for reference ByteOrder byteOrder_; //!< Byteorder for encoding ByteOrder origByteOrder_; //!< Byteorder as set in the c'tor const FindEncoderFct findEncoderFct_; //!< Ptr to the function to find special encoding functions std::string make_; //!< Camera make, determined from the tags to encode bool dirty_; //!< Signals if any tag is deleted or allocated WriteMethod writeMethod_; //!< Write method used. }; // class TiffEncoder /*! @brief Simple state class containing relevant state information for the TIFF reader. This is in a separate class so that the reader can change state if needed (e.g., to read certain complex makernotes). */ class TiffRwState { friend class TiffReader; public: //! TiffRWState auto_ptr type typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Constructor. TiffRwState(ByteOrder byteOrder, uint32_t baseOffset, TiffCompFactoryFct createFct =0) : byteOrder_(byteOrder), baseOffset_(baseOffset), createFct_(createFct) {} //@} //! @name Accessors //@{ /*! @brief Return the applicable byte order. May be different for the Makernote and the rest of the TIFF entries. */ ByteOrder byteOrder() const { return byteOrder_; } /*! @brief Return the base offset. TIFF standard format uses byte offsets which are always relative to the start of the TIFF file, i.e., relative to the start of the TIFF image header. In this case, the base offset is 0. However, some camera vendors encode their makernotes in TIFF IFDs using offsets relative to (somewhere near) the start of the makernote data. In this case, base offset added to the start of the TIFF image header points to the basis for such makernote offsets. */ uint32_t baseOffset() const { return baseOffset_; } /*! @brief Return the factory function to create new TIFF components. Different create functions may use different lookup tables, so that makernotes can independently use their own factory function and lookup table, which can be defined together with the makernote implementation. */ TiffCompFactoryFct createFct() const { return createFct_; } //@} private: ByteOrder byteOrder_; const uint32_t baseOffset_; TiffCompFactoryFct createFct_; }; // TiffRwState /*! @brief TIFF composite visitor to read the TIFF structure from a block of memory and build the composite from it (Visitor pattern). Used by TiffParser to read the TIFF data from a block of memory. */ class TiffReader : public TiffVisitor { public: //! @name Creators //@{ /*! @brief Constructor. The data buffer and table describing the TIFF structure of the data are set in the constructor. @param pData Pointer to the data buffer, starting with a TIFF header. @param size Number of bytes in the data buffer. @param pRoot Root element of the TIFF composite. @param state State object for creation function, byte order and base offset. */ TiffReader(const byte* pData, uint32_t size, TiffComponent* pRoot, TiffRwState::AutoPtr state); //! Virtual destructor virtual ~TiffReader(); //@} //! @name Manipulators //@{ //! Read a TIFF entry from the data buffer virtual void visitEntry(TiffEntry* object); //! Read a TIFF data entry from the data buffer virtual void visitDataEntry(TiffDataEntry* object); //! Read a TIFF image entry from the data buffer virtual void visitImageEntry(TiffImageEntry* object); //! Read a TIFF size entry from the data buffer virtual void visitSizeEntry(TiffSizeEntry* object); //! Read a TIFF directory from the data buffer virtual void visitDirectory(TiffDirectory* object); //! Read a TIFF sub-IFD from the data buffer virtual void visitSubIfd(TiffSubIfd* object); //! Read a TIFF makernote entry from the data buffer virtual void visitMnEntry(TiffMnEntry* object); //! Read an IFD makernote from the data buffer virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Reset reader to its original state, undo makernote specific settings virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object); //! Read an array entry component from the data buffer virtual void visitArrayEntry(TiffArrayEntry* object); //! Read an array element from the data buffer virtual void visitArrayElement(TiffArrayElement* object); //! Read a standard TIFF entry from the data buffer void readTiffEntry(TiffEntryBase* object); //! Read a TiffDataEntryBase from the data buffer void readDataEntryBase(TiffDataEntryBase* object); //! Set the \em state class. Assumes ownership of the object passed in. void changeState(TiffRwState::AutoPtr state); //! Reset the state to the original state as set in the constructor. void resetState(); //@} //! @name Accessors //@{ //! Return the byte order. ByteOrder byteOrder() const; //! Return the base offset. See class TiffRwState for details uint32_t baseOffset() const; //! Create a TIFF component for \em extendedTag and group std::auto_ptr create(uint32_t extendedTag, uint16_t group) const; //@} private: // DATA const byte* pData_; //!< Pointer to the memory buffer const uint32_t size_; //!< Size of the buffer const byte* pLast_; //!< Pointer to the last byte TiffComponent* const pRoot_; //!< Root element of the composite TiffRwState* pState_; //!< State class TiffRwState* pOrigState_; //!< State class as set in the c'tor }; // class TiffReader /*! @brief TIFF composite visitor to print the TIFF structure to an output stream. */ class TiffPrinter : public TiffVisitor { public: //! @name Creators //@{ //! Constructor, takes an output stream to write to. TiffPrinter(std::ostream& os, const std::string& prefix ="") : os_(os), prefix_(prefix) {} //! Virtual destructor virtual ~TiffPrinter() {} //@} //! @name Manipulators //@{ //! Print a TIFF entry. virtual void visitEntry(TiffEntry* object); //! Print a TIFF data entry. virtual void visitDataEntry(TiffDataEntry* object); //! Print a TIFF image entry. virtual void visitImageEntry(TiffImageEntry* object); //! Print a TIFF size entry. virtual void visitSizeEntry(TiffSizeEntry* object); //! Print a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Print header before next directory virtual void visitDirectoryNext(TiffDirectory* object); //! Cleanup before leaving this directory virtual void visitDirectoryEnd(TiffDirectory* object); //! Print a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object); //! Print a TIFF makernote virtual void visitMnEntry(TiffMnEntry* object); //! Print an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Print an array entry component virtual void visitArrayEntry(TiffArrayEntry* object); //! Print an array element virtual void visitArrayElement(TiffArrayElement* object); //! Increment the indent by one level void incIndent(); //! Decrement the indent by one level void decIndent(); //@} //! @name Accessors //@{ //! Print a standard TIFF entry. void printTiffEntry(TiffEntryBase* object, const std::string& prefix ="") const; //! Return the current prefix std::string prefix() const { return prefix_; } //@} private: // DATA std::ostream& os_; //!< Output stream to write to std::string prefix_; //!< Current prefix static const std::string indent_; //!< Indent for one level }; // class TiffPrinter }} // namespace Internal, Exiv2 #endif // #ifndef TIFFVISITOR_INT_HPP_