Coverage Report

Created: 2025-07-11 06:50

/src/exiv2/src/cr2image.cpp
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
3
// included header files
4
#include "cr2image.hpp"
5
6
#include "config.h"
7
#include "cr2header_int.hpp"
8
#include "error.hpp"
9
#include "futils.hpp"
10
#include "image.hpp"
11
#include "tiffcomposite_int.hpp"
12
#include "tiffimage_int.hpp"
13
14
#include <array>
15
#include <iostream>
16
17
// *****************************************************************************
18
// class member definitions
19
namespace Exiv2 {
20
21
Cr2Image::Cr2Image(BasicIo::UniquePtr io, bool /*create*/) :
22
763
    Image(ImageType::cr2, mdExif | mdIptc | mdXmp, std::move(io)) {
23
763
}  // Cr2Image::Cr2Image
24
25
0
std::string Cr2Image::mimeType() const {
26
0
  return "image/x-canon-cr2";
27
0
}
28
29
12
uint32_t Cr2Image::pixelWidth() const {
30
12
  auto imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension"));
31
12
  if (imageWidth != exifData_.end() && imageWidth->count() > 0) {
32
0
    return imageWidth->toUint32();
33
0
  }
34
12
  return 0;
35
12
}
36
37
12
uint32_t Cr2Image::pixelHeight() const {
38
12
  auto imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension"));
39
12
  if (imageHeight != exifData_.end() && imageHeight->count() > 0) {
40
0
    return imageHeight->toUint32();
41
0
  }
42
12
  return 0;
43
12
}
44
45
1.47k
void Cr2Image::printStructure(std::ostream& out, Exiv2::PrintStructureOption option, size_t depth) {
46
1.47k
  if (io_->open() != 0)
47
0
    throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
48
1.47k
  io_->seek(0, BasicIo::beg);
49
1.47k
  printTiffStructure(io(), out, option, depth);
50
1.47k
}
51
52
0
void Cr2Image::setComment(const std::string&) {
53
  // not supported
54
0
  throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "CR2"));
55
0
}
56
57
763
void Cr2Image::readMetadata() {
58
#ifdef EXIV2_DEBUG_MESSAGES
59
  std::cerr << "Reading CR2 file " << io_->path() << "\n";
60
#endif
61
763
  if (io_->open() != 0) {
62
0
    throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
63
0
  }
64
763
  IoCloser closer(*io_);
65
  // Ensure that this is the correct image type
66
763
  if (!isCr2Type(*io_, false)) {
67
0
    if (io_->error() || io_->eof())
68
0
      throw Error(ErrorCode::kerFailedToReadImageData);
69
0
    throw Error(ErrorCode::kerNotAnImage, "CR2");
70
0
  }
71
763
  clearMetadata();
72
763
  ByteOrder bo = Cr2Parser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size());
73
763
  setByteOrder(bo);
74
763
}  // Cr2Image::readMetadata
75
76
0
void Cr2Image::writeMetadata() {
77
#ifdef EXIV2_DEBUG_MESSAGES
78
  std::cerr << "Writing CR2 file " << io_->path() << "\n";
79
#endif
80
0
  ByteOrder bo = byteOrder();
81
0
  byte* pData = nullptr;
82
0
  size_t size = 0;
83
0
  IoCloser closer(*io_);
84
  // Ensure that this is the correct image type
85
0
  if (io_->open() == 0 && isCr2Type(*io_, false)) {
86
0
    pData = io_->mmap(true);
87
0
    size = io_->size();
88
0
    Internal::Cr2Header cr2Header;
89
0
    if (0 == cr2Header.read(pData, 16)) {
90
0
      bo = cr2Header.byteOrder();
91
0
    }
92
0
  }
93
0
  if (bo == invalidByteOrder) {
94
0
    bo = littleEndian;
95
0
  }
96
0
  setByteOrder(bo);
97
0
  Cr2Parser::encode(*io_, pData, size, bo, exifData_, iptcData_, xmpData_);  // may throw
98
0
}  // Cr2Image::writeMetadata
99
100
763
ByteOrder Cr2Parser::decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size) {
101
763
  Internal::Cr2Header cr2Header;
102
763
  return Internal::TiffParserWorker::decode(exifData, iptcData, xmpData, pData, size, Internal::Tag::root,
103
763
                                            Internal::TiffMapping::findDecoder, &cr2Header);
104
763
}
105
106
WriteMethod Cr2Parser::encode(BasicIo& io, const byte* pData, size_t size, ByteOrder byteOrder, ExifData& exifData,
107
0
                              IptcData& iptcData, XmpData& xmpData) {
108
  // Delete IFDs which do not occur in TIFF images
109
0
  static constexpr auto filteredIfds = std::array{
110
0
      IfdId::panaRawId,
111
0
  };
112
0
  for (auto&& filteredIfd : filteredIfds) {
113
#ifdef EXIV2_DEBUG_MESSAGES
114
    std::cerr << "Warning: Exif IFD " << filteredIfd << " not encoded\n";
115
#endif
116
0
    exifData.erase(std::remove_if(exifData.begin(), exifData.end(), Internal::FindExifdatum(filteredIfd)),
117
0
                   exifData.end());
118
0
  }
119
120
0
  auto header = Internal::Cr2Header(byteOrder);
121
0
  Internal::OffsetWriter offsetWriter;
122
0
  offsetWriter.setOrigin(Internal::OffsetWriter::cr2RawIfdOffset, Internal::Cr2Header::offset2addr(), byteOrder);
123
0
  return Internal::TiffParserWorker::encode(io, pData, size, exifData, iptcData, xmpData, Internal::Tag::root,
124
0
                                            Internal::TiffMapping::findEncoder, &header, &offsetWriter);
125
0
}
126
127
// *************************************************************************
128
// free functions
129
763
Image::UniquePtr newCr2Instance(BasicIo::UniquePtr io, bool create) {
130
763
  auto image = std::make_unique<Cr2Image>(std::move(io), create);
131
763
  if (!image->good()) {
132
0
    return nullptr;
133
0
  }
134
763
  return image;
135
763
}
136
137
37.3k
bool isCr2Type(BasicIo& iIo, bool advance) {
138
37.3k
  const int32_t len = 16;
139
37.3k
  byte buf[len];
140
37.3k
  iIo.read(buf, len);
141
37.3k
  if (iIo.error() || iIo.eof()) {
142
95
    return false;
143
95
  }
144
37.2k
  Internal::Cr2Header header;
145
37.2k
  bool rc = header.read(buf, len);
146
37.2k
  if (!advance || !rc) {
147
37.2k
    iIo.seek(-len, BasicIo::cur);
148
37.2k
  }
149
37.2k
  return rc;
150
37.3k
}
151
152
}  // namespace Exiv2