Coverage Report

Created: 2026-01-17 06:15

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