Coverage Report

Created: 2026-08-25 06:40

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