Coverage Report

Created: 2026-04-29 07:00

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