Coverage Report

Created: 2026-01-16 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/exiv2/src/crwimage_int.hpp
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
3
#ifndef EXIV2_CRWIMAGE_INT_HPP
4
#define EXIV2_CRWIMAGE_INT_HPP
5
6
// *****************************************************************************
7
// included header files
8
#include "types.hpp"
9
10
// + standard includes
11
#include <cstdint>
12
#include <iosfwd>
13
#include <memory>
14
#include <stack>
15
#include <vector>
16
17
// *****************************************************************************
18
// namespace extensions
19
namespace Exiv2 {
20
enum class IfdId : uint32_t;
21
class ExifData;
22
class Image;
23
24
namespace Internal {
25
// *****************************************************************************
26
// class declarations
27
class CiffHeader;
28
class CiffComponent;
29
struct CrwMapping;
30
struct CrwSubDir {
31
  uint16_t dir;
32
  uint16_t parent;
33
};
34
35
// *****************************************************************************
36
// type definitions
37
38
//! Function pointer for functions to decode Exif tags from a CRW entry
39
using CrwDecodeFct = void (*)(const CiffComponent&, const CrwMapping*, Image&, ByteOrder);
40
41
//! Function pointer for functions to encode CRW entries from Exif tags
42
using CrwEncodeFct = void (*)(const Image&, const CrwMapping&, CiffHeader&);
43
44
//! Stack to hold a path of CRW directories
45
using CrwDirs = std::stack<CrwSubDir>;
46
47
//! Type to identify where the data is stored in a directory
48
enum class DataLocId { valueData, directoryData, lastDataLocId };
49
50
// *****************************************************************************
51
// class definitions
52
53
/*!
54
  @brief Interface class for components of the CIFF directory hierarchy of a
55
         CRW (Canon Raw data) image. Both CIFF directories as well as
56
         entries implement this interface. This class is implemented as NVI
57
         (non-virtual interface).
58
 */
59
class CiffComponent {
60
 public:
61
  //! CiffComponent auto_ptr type
62
  using UniquePtr = std::unique_ptr<CiffComponent>;
63
  //! Container type to hold all metadata
64
  using Components = std::vector<UniquePtr>;
65
66
  //! @name Creators
67
  //@{
68
  //! Default constructor
69
22.3k
  CiffComponent() = default;
70
  //! Constructor taking a tag and directory
71
  CiffComponent(uint16_t tag, uint16_t dir);
72
  //! Virtual destructor.
73
22.8k
  virtual ~CiffComponent() = default;
74
  CiffComponent(const CiffComponent&) = delete;
75
  CiffComponent& operator=(const CiffComponent&) = delete;
76
  //@}
77
78
  //! @name Manipulators
79
  //@{
80
  // Default assignment operator is fine
81
82
  //! Add a component to the composition
83
  const UniquePtr& add(UniquePtr component);
84
  /*!
85
    @brief Add \em crwTagId to the parse tree, if it doesn't exist
86
           yet. \em crwDirs contains the path of subdirectories, starting
87
           with the root directory, leading to \em crwTagId. Directories
88
           that don't exist yet are added along the way. Returns a pointer
89
           to the newly added component.
90
91
    @param crwDirs   Subdirectory path from root to the subdirectory
92
                     containing the tag to be added.
93
    @param crwTagId  Tag to be added.
94
95
    @return A pointer to the newly added component.
96
   */
97
  const UniquePtr& add(CrwDirs& crwDirs, uint16_t crwTagId);
98
  /*!
99
    @brief Remove \em crwTagId from the parse tree, if it exists yet. \em
100
           crwDirs contains the path of subdirectories, starting with the
101
           root directory, leading to \em crwTagId.
102
103
    @param crwDirs   Subdirectory path from root to the subdirectory
104
                     containing the tag to be removed.
105
    @param crwTagId  Tag to be removed.
106
   */
107
  void remove(CrwDirs& crwDirs, uint16_t crwTagId);
108
  /*!
109
    @brief Read a component from a data buffer
110
111
    @param pData     Pointer to the data buffer.
112
    @param size      Number of bytes in the data buffer.
113
    @param start     Component starts at \em pData + \em start.
114
    @param byteOrder Applicable byte order (little or big endian).
115
116
    @throw Error If the component cannot be parsed.
117
   */
118
  void read(const byte* pData, size_t size, uint32_t start, ByteOrder byteOrder);
119
  /*!
120
    @brief Write the metadata from the raw metadata component to the
121
           binary image \em blob. This method may append to the blob.
122
123
    @param blob      Binary image to add metadata to
124
    @param byteOrder Byte order
125
    @param offset    Current offset
126
127
    @return New offset
128
   */
129
  size_t write(Blob& blob, ByteOrder byteOrder, size_t offset);
130
131
  /*!
132
    @brief Writes the entry's value if size is larger than eight bytes. If
133
           needed, the value is padded with one 0 byte to make the number
134
           of bytes written to the blob even. The offset of the component
135
           is set to the offset passed in.
136
    @param blob The binary image to write to.
137
    @param offset Offset from the start of the directory for this entry.
138
139
    @return New offset.
140
   */
141
  size_t writeValueData(Blob& blob, size_t offset);
142
143
  //! Set the directory tag for this component.
144
21.1k
  void setDir(uint16_t dir) {
145
21.1k
    dir_ = dir;
146
21.1k
  }
147
  //! Set the data value of the entry.
148
  void setValue(DataBuf&& buf);
149
  //@}
150
151
  //! Return the type id for a tag
152
  static TypeId typeId(uint16_t tag);
153
  //! Return the data location id for a tag
154
  static DataLocId dataLocation(uint16_t tag);
155
156
  //! @name Accessors
157
  //@{
158
  /*!
159
    @brief Decode metadata from the component and add it to
160
           \em image.
161
162
    @param image Image to add metadata to
163
    @param byteOrder Byte order
164
   */
165
  void decode(Image& image, ByteOrder byteOrder) const;
166
  /*!
167
    @brief Print debug info about a component to \em os.
168
169
    @param os Output stream to write to
170
    @param byteOrder Byte order
171
    @param prefix Prefix to be written before each line of output
172
   */
173
  void print(std::ostream& os, ByteOrder byteOrder, const std::string& prefix = "") const;
174
  /*!
175
    @brief Write a directory entry for the component to the \em blob.
176
           If the size of the data is not larger than 8 bytes, the
177
           data is written to the directory entry.
178
   */
179
  void writeDirEntry(Blob& blob, ByteOrder byteOrder) const;
180
  //! Return the tag of the directory containing this component
181
6.70k
  [[nodiscard]] uint16_t dir() const {
182
6.70k
    return dir_;
183
6.70k
  }
184
185
  //! Return the tag of this component
186
84.9k
  [[nodiscard]] uint16_t tag() const {
187
84.9k
    return tag_;
188
84.9k
  }
189
190
  //! Return true if the component is empty, else false
191
  [[nodiscard]] bool empty() const;
192
193
  /*!
194
    @brief Return the data size of this component
195
196
    @note If the data is contained in the directory entry itself,
197
          this method returns 8, which is the maximum number
198
          of data bytes this component can have. The actual size,
199
          i.e., used data bytes, may be less than 8.
200
   */
201
7.74k
  [[nodiscard]] size_t size() const {
202
7.74k
    return size_;
203
7.74k
  }
204
205
  //! Return the offset to the data from the start of the directory
206
4.95k
  [[nodiscard]] size_t offset() const {
207
4.95k
    return offset_;
208
4.95k
  }
209
210
  //! Return a pointer to the data area of this component
211
8.05k
  [[nodiscard]] const byte* pData() const {
212
8.05k
    return pData_;
213
8.05k
  }
214
215
  //! Return the tag id of this component
216
26.0k
  [[nodiscard]] uint16_t tagId() const {
217
26.0k
    return tag_ & 0x3fff;
218
26.0k
  }
219
220
  //! Return the type id of this component
221
2.06k
  [[nodiscard]] TypeId typeId() const {
222
2.06k
    return typeId(tag_);
223
2.06k
  }
224
225
  //! Return the data location for this component
226
35.5k
  [[nodiscard]] DataLocId dataLocation() const {
227
35.5k
    return dataLocation(tag_);
228
35.5k
  }
229
230
  /*!
231
    @brief Finds \em crwTagId in directory \em crwDir, returning a pointer to
232
           the component or 0 if not found.
233
   */
234
  [[nodiscard]] CiffComponent* findComponent(uint16_t crwTagId, uint16_t crwDir);
235
  //@}
236
237
 protected:
238
  //! @name Manipulators
239
  //@{
240
  //! Implements add()
241
  virtual const UniquePtr& doAdd(UniquePtr component) = 0;
242
  //! Implements add(). The default implementation does nothing.
243
  virtual const UniquePtr& doAdd(CrwDirs& crwDirs, uint16_t crwTagId);
244
  //! Implements remove(). The default implementation does nothing.
245
  virtual void doRemove(CrwDirs& crwDirs, uint16_t crwTagId);
246
  //! Implements read(). The default implementation reads a directory entry.
247
  virtual void doRead(const byte* pData, size_t size, uint32_t start, ByteOrder byteOrder);
248
  //! Implements write()
249
  virtual size_t doWrite(Blob& blob, ByteOrder byteOrder, size_t offset) = 0;
250
  //! Set the size of the data area.
251
1.65k
  void setSize(size_t size) {
252
1.65k
    size_ = size;
253
1.65k
  }
254
  //! Set the offset for this component.
255
1.65k
  void setOffset(size_t offset) {
256
1.65k
    offset_ = offset;
257
1.65k
  }
258
  //@}
259
260
  //! @name Accessors
261
  //@{
262
  //! Implements decode()
263
  virtual void doDecode(Image& image, ByteOrder byteOrder) const = 0;
264
  //! Implements print(). The default implementation prints the entry.
265
  virtual void doPrint(std::ostream& os, ByteOrder byteOrder, const std::string& prefix) const;
266
  //! Implements empty(). Default implementation returns true if size is 0.
267
  [[nodiscard]] virtual bool doEmpty() const;
268
  //! Implements findComponent(). The default implementation checks the entry.
269
  [[nodiscard]] virtual CiffComponent* doFindComponent(uint16_t crwTagId, uint16_t crwDir);
270
  //@}
271
272
 private:
273
  // DATA
274
  uint16_t dir_ = 0;   //!< Tag of the directory containing this component
275
  uint16_t tag_ = 0;   //!< Tag of the entry
276
  size_t size_ = 0;    //!< Size of the data area
277
  size_t offset_ = 0;  //!< Offset to the data area from start of dir
278
279
  // Notes on the ownership model of pData_: pData_ is a always a read-only
280
  // pointer to a buffer owned by somebody else. Usually it is a pointer
281
  // into a copy of the image that was memory-mapped in CrwImage::readMetadata().
282
  // However, if CiffComponent::setValue() is used, then it is a pointer into
283
  // the storage_ DataBuf below.
284
  const byte* pData_ = nullptr;  //!< Pointer to the data area
285
286
  // This DataBuf is only used when CiffComponent::setValue is called.
287
  // Otherwise, it remains empty.
288
  DataBuf storage_;
289
};  // class CiffComponent
290
291
/*!
292
  @brief This class models one directory entry of a CIFF directory of
293
         a CRW (Canon Raw data) image.
294
 */
295
class CiffEntry : public CiffComponent {
296
  using CiffComponent::CiffComponent;
297
  //! @name Manipulators
298
  //@{
299
  using CiffComponent::doAdd;
300
  // See base class comment
301
  const UniquePtr& doAdd(UniquePtr component) override;
302
  /*!
303
    @brief Implements write(). Writes only the value data of the entry,
304
           using writeValueData().
305
   */
306
  size_t doWrite(Blob& blob, ByteOrder byteOrder, size_t offset) override;
307
  //@}
308
309
  //! @name Accessors
310
  //@{
311
  // See base class comment
312
  void doDecode(Image& image, ByteOrder byteOrder) const override;
313
  //@}
314
315
};  // class CiffEntry
316
317
//! This class models a CIFF directory of a CRW (Canon Raw data) image.
318
class CiffDirectory : public CiffComponent {
319
  using CiffComponent::CiffComponent;
320
321
 public:
322
  //! @name Manipulators
323
  //@{
324
  // Default assignment operator is fine
325
326
  /*!
327
    @brief Parse a CIFF directory from a memory buffer
328
329
    @param pData     Pointer to the memory buffer containing the directory
330
    @param size      Size of the memory buffer
331
    @param byteOrder Applicable byte order (little or big endian)
332
   */
333
  void readDirectory(const byte* pData, size_t size, ByteOrder byteOrder);
334
  //@}
335
336
 private:
337
  //! @name Manipulators
338
  //@{
339
  // See base class comment
340
  const UniquePtr& doAdd(UniquePtr component) override;
341
  // See base class comment
342
  const UniquePtr& doAdd(CrwDirs& crwDirs, uint16_t crwTagId) override;
343
  // See base class comment
344
  void doRemove(CrwDirs& crwDirs, uint16_t crwTagId) override;
345
  /*!
346
    @brief Implements write(). Writes the complete Ciff directory to
347
           the blob.
348
   */
349
  size_t doWrite(Blob& blob, ByteOrder byteOrder, size_t offset) override;
350
  // See base class comment
351
  void doRead(const byte* pData, size_t size, uint32_t start, ByteOrder byteOrder) override;
352
  //@}
353
354
  //! @name Accessors
355
  //@{
356
  // See base class comment
357
  void doDecode(Image& image, ByteOrder byteOrder) const override;
358
359
  // See base class comment
360
  void doPrint(std::ostream& os, ByteOrder byteOrder, const std::string& prefix) const override;
361
362
  //! See base class comment. A directory is empty if it has no components.
363
  [[nodiscard]] bool doEmpty() const override;
364
365
  // See base class comment
366
  [[nodiscard]] CiffComponent* doFindComponent(uint16_t crwTagId, uint16_t crwDir) override;
367
  //@}
368
369
  // DATA
370
  Components components_;  //!< List of components in this dir
371
372
};  // class CiffDirectory
373
374
/*!
375
  @brief This class models the header of a CRW (Canon Raw data) image.  It
376
         is the head of a CIFF parse tree, consisting of CiffDirectory and
377
         CiffEntry objects. Most of its methods will walk the parse tree to
378
         perform the requested action.
379
 */
380
class CiffHeader {
381
 public:
382
  //! @name Manipulators
383
  //@{
384
  /*!
385
    @brief Read the CRW image from a data buffer, starting with the Ciff
386
           header.
387
388
    @param pData Pointer to the data buffer.
389
    @param size  Number of bytes in the data buffer.
390
391
    @throw Error If the image cannot be parsed.
392
   */
393
  void read(const byte* pData, size_t size);
394
  /*!
395
    @brief Set the value of entry \em crwTagId in directory \em crwDir to
396
           \em buf. If this tag doesn't exist, it is added along with all
397
           directories needed.
398
399
    @param crwTagId Tag to be added.
400
    @param crwDir   Parent directory of the tag.
401
    @param buf      Value to be set.
402
   */
403
  void add(uint16_t crwTagId, uint16_t crwDir, DataBuf&& buf);
404
  /*!
405
    @brief Remove entry \em crwTagId in directory \em crwDir from the parse
406
           tree. If it's the last entry in the directory, the directory is
407
           removed as well, etc.
408
409
    @param crwTagId Tag id to be removed.
410
    @param crwDir   Parent directory of the tag.
411
   */
412
  void remove(uint16_t crwTagId, uint16_t crwDir) const;
413
  //@}
414
415
  //! Return a pointer to the Canon CRW signature.
416
39.0k
  static const char* signature() {
417
39.0k
    return signature_;
418
39.0k
  }
419
420
  //! @name Accessors
421
  //@{
422
  /*!
423
    @brief Write the CRW image to the binary image \em blob, starting with
424
           the Ciff header. This method appends to the blob.
425
426
    @param blob Binary image to add to.
427
428
    @throw Error If the image cannot be written.
429
   */
430
  void write(Blob& blob) const;
431
  /*!
432
    @brief Decode the CRW image and add it to \em image.
433
434
    Walk the parse tree and convert CIFF entries to metadata
435
    entries which are added to \em image.
436
437
    @param image Image to add metadata to
438
   */
439
  void decode(Image& image) const;
440
441
  //! Return the byte order (little or big endian).
442
1.34k
  [[nodiscard]] ByteOrder byteOrder() const {
443
1.34k
    return byteOrder_;
444
1.34k
  }
445
  /*!
446
    @brief Finds \em crwTagId in directory \em crwDir in the parse tree,
447
           returning a pointer to the component or 0 if not found.
448
   */
449
  [[nodiscard]] CiffComponent* findComponent(uint16_t crwTagId, uint16_t crwDir) const;
450
  //@}
451
452
 private:
453
  // DATA
454
  static constexpr auto signature_ = "HEAPCCDR";  //!< Canon CRW signature
455
456
  std::unique_ptr<CiffDirectory> pRootDir_;  //!< Pointer to the root directory
457
  ByteOrder byteOrder_ = littleEndian;       //!< Applicable byte order
458
  uint32_t offset_ = 0;                      //!< Offset to the start of the root dir
459
  Blob pPadding_;                            //!< the (unknown) remainder
460
  uint32_t padded_ = 0;                      //!< Number of padding-bytes
461
462
};  // class CiffHeader
463
464
/*!
465
  @brief Structure for a mapping table for conversion of CIFF entries to
466
         image metadata and vice versa.
467
 */
468
struct CrwMapping {
469
  uint16_t crwTagId_;      //!< CRW tag id
470
  uint16_t crwDir_;        //!< CRW directory tag
471
  uint32_t size_;          //!< Data size (overwrites the size from the entry)
472
  uint16_t tag_;           //!< Exif tag to map to
473
  IfdId ifdId_;            //!< Exif Ifd id to map to
474
  CrwDecodeFct toExif_;    //!< Conversion function
475
  CrwEncodeFct fromExif_;  //!< Reverse conversion function
476
};
477
478
/*!
479
  @brief Static class providing mapping functionality from CRW entries
480
         to image metadata and vice versa
481
 */
482
class CrwMap {
483
 public:
484
  /*!
485
    @brief Decode image metadata from a CRW entry, convert and add it
486
           to the image metadata. This function converts only one CRW
487
           component.
488
489
    @param ciffComponent Source CIFF entry
490
    @param image         Destination image for the metadata
491
    @param byteOrder     Byte order in which the data of the entry
492
                         is encoded
493
   */
494
  static void decode(const CiffComponent& ciffComponent, Image& image, ByteOrder byteOrder);
495
  /*!
496
    @brief Encode image metadata from \em image into the CRW parse tree.
497
           This function converts all Exif metadata that %Exiv2 can
498
           convert to CRW format, in a loop through the entries of the
499
           mapping table.
500
501
    @param pHead         Destination parse tree.
502
    @param image         Source image containing the metadata.
503
   */
504
  static void encode(CiffHeader& pHead, const Image& image);
505
506
  /*!
507
    @brief Load the stack: loop through the CRW subdirs hierarchy and push
508
           all directories on the path from \em crwDir to root onto the
509
           stack \em crwDirs. Requires the subdirs array to be arranged in
510
           bottom-up order to be able to finish in only one pass.
511
   */
512
  static void loadStack(CrwDirs& crwDirs, uint16_t crwDir);
513
514
 private:
515
  //! Return conversion information for one \em crwDir and \em crwTagId
516
  static const CrwMapping* crwMapping(uint16_t crwDir, uint16_t crwTagId);
517
518
  /*!
519
    @brief Standard decode function to convert CRW entries to
520
           Exif metadata.
521
522
    Uses the mapping defined in the conversion structure \em pCrwMapping
523
    to convert the data. If the \em size field in the conversion structure
524
    is not 0, then it is used instead of the \em size provided by the
525
    entry itself.
526
   */
527
  static void decodeBasic(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image,
528
                          ByteOrder byteOrder);
529
530
  //! Decode the user comment
531
  static void decode0x0805(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image,
532
                           ByteOrder byteOrder);
533
534
  //! Decode camera Make and Model information
535
  static void decode0x080a(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image,
536
                           ByteOrder byteOrder);
537
538
  //! Decode Canon Camera Settings 1, 2 and Custom Function arrays
539
  static void decodeArray(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image,
540
                          ByteOrder byteOrder);
541
542
  //! Decode the date when the picture was taken
543
  static void decode0x180e(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image,
544
                           ByteOrder byteOrder);
545
546
  //! Decode image width and height
547
  static void decode0x1810(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image,
548
                           ByteOrder byteOrder);
549
550
  //! Decode the thumbnail image
551
  static void decode0x2008(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image,
552
                           ByteOrder byteOrder);
553
554
  /*!
555
    @brief Standard encode function to convert Exif metadata to Crw
556
           entries.
557
558
    This is the basic encode function taking one Exif key and converting
559
    it to one Ciff entry. Both are available in the \em pCrwMapping passed
560
    in.
561
562
    @param image Image with the metadata to encode
563
    @param pCrwMapping Pointer to an entry into the \em crwMapping_ table
564
                 with information on the source and target metadata entries.
565
    @param pHead Pointer to the head of the CIFF parse tree into which
566
                 the metadata from \em image is encoded.
567
   */
568
  static void encodeBasic(const Image& image, const CrwMapping& pCrwMapping, CiffHeader& pHead);
569
570
  //! Encode the user comment
571
  static void encode0x0805(const Image& image, const CrwMapping& pCrwMapping, CiffHeader& pHead);
572
573
  //! Encode camera Make and Model information
574
  static void encode0x080a(const Image& image, const CrwMapping& pCrwMapping, CiffHeader& pHead);
575
576
  //! Encode Canon Camera Settings 1, 2 and Custom Function arrays
577
  static void encodeArray(const Image& image, const CrwMapping& pCrwMapping, CiffHeader& pHead);
578
579
  //! Encode the date when the picture was taken
580
  static void encode0x180e(const Image& image, const CrwMapping& pCrwMapping, CiffHeader& pHead);
581
582
  //! Encode image width and height
583
  static void encode0x1810(const Image& image, const CrwMapping& pCrwMapping, CiffHeader& pHead);
584
585
  //! Encode the thumbnail image
586
  static void encode0x2008(const Image& image, const CrwMapping& pCrwMapping, CiffHeader& pHead);
587
588
  // DATA
589
  static const CrwMapping crwMapping_[];  //!< Metadata conversion table
590
  static const CrwSubDir crwSubDir_[];    //!< Ciff directory hierarchy
591
592
};  // class CrwMap
593
594
// *****************************************************************************
595
// template, inline and free functions
596
597
/*!
598
  @brief Pack the tag values of all \em ifdId tags in \em exifData into a
599
         data buffer. This function is used to pack Canon Camera Settings1,2
600
         and Custom Function tags.
601
 */
602
DataBuf packIfdId(const ExifData& exifData, IfdId ifdId, ByteOrder byteOrder);
603
604
}  // namespace Internal
605
}  // namespace Exiv2
606
607
#endif  // EXIV2_CRWIMAGE_INT_HPP