Coverage Report

Created: 2025-07-11 06:50

/src/exiv2/src/tiffimage_int.hpp
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
3
#ifndef TIFFIMAGE_INT_HPP_
4
#define TIFFIMAGE_INT_HPP_
5
6
// *****************************************************************************
7
// included header files
8
#include "exif.hpp"
9
#include "tifffwd_int.hpp"
10
11
#include <unordered_map>
12
13
// *****************************************************************************
14
// namespace extensions
15
namespace Exiv2 {
16
class BasicIo;
17
class IptcData;
18
class XmpData;
19
20
namespace Internal {
21
/*!
22
  @brief Contains internal objects which are not published and are not part
23
         of the <b>libexiv2</b> API.
24
 */
25
26
// *****************************************************************************
27
// class definitions
28
29
/*!
30
  @brief Abstract base class defining the interface of an image header.
31
         Used internally by classes for TIFF-based images.  Default
32
         implementation is for the regular TIFF header.
33
 */
34
class TiffHeaderBase {
35
 public:
36
  //! @name Creators
37
  //@{
38
  //! Constructor taking \em tag, \em size and default \em byteOrder and \em offset.
39
  TiffHeaderBase(uint16_t tag, uint32_t size, ByteOrder byteOrder, uint32_t offset);
40
  //! Virtual destructor.
41
45.9k
  virtual ~TiffHeaderBase() = default;
42
  //@}
43
44
  //! @name Manipulators
45
  //@{
46
  /*!
47
    @brief Read the image header from a data buffer. Return false if the
48
           data buffer does not contain an image header of the expected
49
           format, else true.
50
51
    @param pData Pointer to the data buffer.
52
    @param size  Number of bytes in the data buffer.
53
    @return True if the TIFF header was read successfully. False if the
54
           data buffer does not contain a valid TIFF header.
55
   */
56
  virtual bool read(const byte* pData, size_t size);
57
  //! Set the byte order.
58
  virtual void setByteOrder(ByteOrder byteOrder);
59
  //! Set the offset to the start of the root directory.
60
  virtual void setOffset(uint32_t offset);
61
  //@}
62
63
  //! @name Accessors
64
  //@{
65
  /*!
66
    @brief Return the image header in binary format.
67
           The caller owns this data and %DataBuf ensures that it will be deleted.
68
69
    @return Binary header data.
70
   */
71
  [[nodiscard]] virtual DataBuf write() const;
72
  /*!
73
    @brief Print debug info for the image header to \em os.
74
75
    @param os Output stream to write to.
76
    @param prefix Prefix to be written before each line of output.
77
   */
78
  virtual void print(std::ostream& os, std::string_view prefix = "") const;
79
  //! Return the byte order (little or big endian).
80
  [[nodiscard]] virtual ByteOrder byteOrder() const;
81
  //! Return the offset to the start of the root directory.
82
  [[nodiscard]] virtual uint32_t offset() const;
83
  //! Return the size (in bytes) of the image header.
84
  [[nodiscard]] virtual uint32_t size() const;
85
  //! Return the tag value (magic number) which identifies the buffer as TIFF data.
86
  [[nodiscard]] virtual uint16_t tag() const;
87
  /*!
88
    @brief Return \c true if the %Exif \em tag from \em group is an image tag.
89
90
    Certain tags of TIFF and TIFF-like images are required to correctly
91
    display the primary image. These image tags contain image data rather
92
    than metadata.
93
94
    @param tag Tag number.
95
    @param group Group identifier.
96
    @param pPrimaryGroups Pointer to a list of TIFF groups that contain
97
           primary images, empty if none are marked.
98
99
    @return The default implementation returns \c false.
100
   */
101
  [[nodiscard]] virtual bool isImageTag(uint16_t tag, IfdId group, const PrimaryGroups& pPrimaryGroups) const;
102
  //@}
103
104
 private:
105
  // DATA
106
  uint16_t tag_;         //!< Tag to identify the buffer as TIFF data
107
  uint32_t size_;        //!< Size of the header
108
  ByteOrder byteOrder_;  //!< Applicable byte order
109
  uint32_t offset_;      //!< Offset to the start of the root dir
110
};
111
112
//! Convenience function to check if tag, group is in the list of TIFF image tags.
113
bool isTiffImageTag(uint16_t tag, IfdId group);
114
115
/*!
116
  @brief Standard TIFF header structure.
117
 */
118
class TiffHeader : public TiffHeaderBase {
119
 public:
120
  //! @name Creators
121
  //@{
122
  //! Default constructor
123
  explicit TiffHeader(ByteOrder byteOrder = littleEndian, uint32_t offset = 0x00000008, bool hasImageTags = true);
124
  //@}
125
  //@{
126
  //! @name Accessors
127
  [[nodiscard]] bool isImageTag(uint16_t tag, IfdId group, const PrimaryGroups& pPrimaryGroups) const override;
128
  //@}
129
130
 private:
131
  // DATA
132
  bool hasImageTags_;  //!< Indicates if image tags are supported
133
};
134
135
/*!
136
  @brief Data structure used to list image tags for TIFF and TIFF-like images.
137
 */
138
using TiffGroupKey = std::pair<uint32_t, IfdId>;
139
140
struct TiffGroupKey_hash {
141
78.8M
  std::size_t operator()(const TiffGroupKey& pair) const noexcept {
142
78.8M
    return std::hash<uint64_t>{}(static_cast<uint64_t>(pair.first) << 32 | static_cast<uint64_t>(pair.second));
143
78.8M
  }
144
};
145
146
/*!
147
  @brief Data structure used as a row (element) of a table (array)
148
         defining the TIFF component used for each tag in a group.
149
 */
150
using TiffGroupTable = std::unordered_map<TiffGroupKey, NewTiffCompFct, TiffGroupKey_hash>;
151
152
/*!
153
  @brief Data structure used as a row of the table which describes TIFF trees.
154
         Multiple trees are needed as TIFF-based RAW image formats do not always
155
         use standard TIFF layout.
156
*/
157
using TiffTreeParent = std::pair<IfdId, uint32_t>;  // Parent group, parent tag
158
using TiffTreeTable = std::unordered_map<TiffGroupKey, TiffTreeParent, TiffGroupKey_hash>;
159
160
/*!
161
  @brief TIFF component factory.
162
 */
163
class TiffCreator {
164
 public:
165
  /*!
166
    @brief Create the TiffComponent for TIFF entry \em extendedTag and
167
           \em group. The embedded lookup table is used to find the correct
168
           component creation function. If the pointer that is returned
169
           is 0, then the TIFF entry should be ignored.
170
  */
171
  static std::unique_ptr<TiffComponent> create(uint32_t extendedTag, IfdId group);
172
  /*!
173
    @brief Get the path, i.e., a list of extended tag and group pairs, from
174
           the \em root TIFF element to the TIFF entry \em extendedTag and
175
           \em group.
176
  */
177
  static TiffPath getPath(uint32_t extendedTag, IfdId group, uint32_t root);
178
179
 private:
180
  static const TiffTreeTable tiffTreeTable_;    //!< TIFF tree structure
181
  static const TiffGroupTable tiffGroupTable_;  //!< TIFF group structure
182
};
183
184
/*!
185
  @brief Stateless parser class for data in TIFF format. Images use this
186
         class to decode and encode TIFF-based data.
187
 */
188
class TiffParserWorker {
189
 public:
190
  /*!
191
    @brief Decode TIFF metadata from a data buffer \em pData of length
192
           \em size into the provided metadata containers.
193
194
    This is the entry point to access image data in TIFF format. The
195
    parser uses classes TiffHeader and the TiffComponent and TiffVisitor
196
    hierarchies.
197
198
    @param exifData  Exif metadata container.
199
    @param iptcData  IPTC metadata container.
200
    @param xmpData   XMP metadata container.
201
    @param pData     Pointer to the data buffer. Must point to data
202
                     in TIFF format; no checks are performed.
203
    @param size      Length of the data buffer.
204
    @param root      Root tag of the TIFF tree for new TIFF components.
205
    @param findDecoderFct Function to access special decoding info.
206
    @param pHeader   Optional pointer to a TIFF header. If not provided,
207
                     a standard TIFF header is used.
208
209
    @return Byte order in which the data is encoded, invalidByteOrder if
210
            decoding failed.
211
  */
212
  static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size,
213
                          uint32_t root, FindDecoderFct findDecoderFct, TiffHeaderBase* pHeader = nullptr);
214
  /*!
215
    @brief Encode TIFF metadata from the metadata containers into a
216
           memory block \em blob.
217
218
    1) Parse the binary image, if one is provided, and
219
    2) attempt updating the parsed tree in-place ("non-intrusive writing")
220
    3) else, create a new tree and write a new TIFF structure ("intrusive
221
       writing"). If there is a parsed tree, it is only used to access the
222
       image data in this case.
223
   */
224
  static WriteMethod encode(BasicIo& io, const byte* pData, size_t size, ExifData& exifData, IptcData& iptcData,
225
                            XmpData& xmpData, uint32_t root, FindEncoderFct findEncoderFct, TiffHeaderBase* pHeader,
226
                            OffsetWriter* pOffsetWriter);
227
228
 private:
229
  /*!
230
    @brief Parse TIFF metadata from a data buffer \em pData of length
231
           \em size into a TIFF composite structure.
232
233
    @param pData     Pointer to the data buffer. Must point to data
234
                     in TIFF format; no checks are performed.
235
    @param size      Length of the data buffer.
236
    @param root      Root tag of the TIFF tree.
237
    @param pHeader   Pointer to a TIFF header.
238
    @return          An auto pointer with the root element of the TIFF
239
                     composite structure. If \em pData is 0 or \em size
240
                     is 0, the return value is a 0 pointer.
241
   */
242
  static std::unique_ptr<TiffComponent> parse(const byte* pData, size_t size, uint32_t root, TiffHeaderBase* pHeader);
243
  /*!
244
    @brief Find primary groups in the source tree provided and populate
245
           the list of primary groups.
246
247
    @param pSourceDir Pointer to the source composite tree to search (may be 0)
248
    @return List of primary groups which is populated
249
   */
250
  static PrimaryGroups findPrimaryGroups(const std::unique_ptr<TiffComponent>& pSourceDir);
251
};
252
253
/*!
254
  @brief Table of TIFF decoding and encoding functions and find functions.
255
         This class is separated from the metadata decoder and encoder
256
         visitors so that the parser can be parametrized with a different
257
         table if needed. This is used, eg., for CR2 format, which uses a
258
         different decoder table.
259
 */
260
class TiffMapping {
261
 public:
262
  /*!
263
    @brief Find the decoder function for a key.
264
265
    If the returned pointer is 0, the tag should not be decoded,
266
    else the decoder function should be used.
267
268
    @param make Camera make
269
    @param extendedTag Extended tag
270
    @param group %Group
271
272
    @return Pointer to the decoder function
273
   */
274
  static DecoderFct findDecoder(std::string_view make, uint32_t extendedTag, IfdId group);
275
  /*!
276
    @brief Find special encoder function for a key.
277
278
    If the returned pointer is 0, the tag should be encoded with the
279
    encoder function of the TIFF component, else the encoder function
280
    should be used.
281
282
    @param make Camera make
283
    @param extendedTag Extended tag
284
    @param group %Group
285
286
    @return Pointer to the encoder function
287
   */
288
  static EncoderFct findEncoder(std::string_view make, uint32_t extendedTag, IfdId group);
289
290
 private:
291
  static const TiffMappingInfo tiffMappingInfo_[];  //!< TIFF mapping table
292
};
293
294
/*!
295
  @brief Class to insert pointers or offsets to computed addresses at
296
         specific locations in an image. Used for offsets which are
297
         best computed during the regular write process. They are
298
         written in a second pass, using the writeOffsets() method.
299
 */
300
class OffsetWriter {
301
 public:
302
  //! Identifiers for supported offsets
303
  enum OffsetId {
304
    cr2RawIfdOffset  //!< CR2 RAW IFD offset, a pointer in the CR2 header to the 4th IFD in a CR2 image
305
  };
306
  //! @name Manipulators
307
  //@{
308
  /*!
309
    @brief Set the \em origin of the offset for \em id, i.e., the location in the image where the offset is,
310
           and the byte order to encode the offset.
311
312
    If the list doesn't contain an entry for \em id yet, this function will create one.
313
  */
314
  void setOrigin(OffsetId id, uint32_t origin, ByteOrder byteOrder);
315
  /*!
316
    @brief Set the \em target for offset \em id, i.e., the address to which the offset points.
317
318
    If the list doesn't contain an entry with \em id yet, this function won't do anything.
319
  */
320
  void setTarget(OffsetId id, uint32_t target);
321
  //@}
322
323
  //! @name Accessors
324
  //@{
325
  //! Write the offsets to the IO instance \em io.
326
  void writeOffsets(BasicIo& io) const;
327
  //@}
328
 private:
329
  //! Data structure for the offset list.
330
  struct OffsetData {
331
    uint32_t origin_{};                  //!< Origin address
332
    uint32_t target_{};                  //!< Target address
333
    ByteOrder byteOrder_{littleEndian};  //!< Byte order to use to encode target address
334
  };
335
  //! Type of the list containing an identifier and an address pair.
336
  using OffsetList = std::map<OffsetId, OffsetData>;
337
338
  // DATA
339
  OffsetList offsetList_;  //!< List of the offsets to replace
340
341
};  // class OffsetWriter
342
343
// Todo: Move this class to metadatum_int.hpp or tags_int.hpp
344
//! Unary predicate that matches an Exifdatum with a given IfdId.
345
class FindExifdatum {
346
 public:
347
  //! Constructor, initializes the object with the IfdId to look for.
348
24.4k
  explicit FindExifdatum(Exiv2::IfdId ifdId) : ifdId_(ifdId) {
349
24.4k
  }
350
  //! Returns true if IFD id matches.
351
5.05M
  bool operator()(const Exiv2::Exifdatum& md) const {
352
5.05M
    return ifdId_ == md.ifdId();
353
5.05M
  }
354
355
 private:
356
  Exiv2::IfdId ifdId_;
357
358
};  // class FindExifdatum
359
360
}  // namespace Internal
361
}  // namespace Exiv2
362
363
#endif  // #ifndef TIFFIMAGE_INT_HPP_