Coverage Report

Created: 2026-03-12 07:14

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
75
    Image(ImageType::cr2, mdExif | mdIptc | mdXmp, std::move(io)) {
25
75
}  // Cr2Image::Cr2Image
26
27
65
std::string Cr2Image::mimeType() const {
28
65
  return "image/x-canon-cr2";
29
65
}
30
31
65
uint32_t Cr2Image::pixelWidth() const {
32
65
  auto imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension"));
33
65
  if (imageWidth != exifData_.end() && imageWidth->count() > 0) {
34
9
    return imageWidth->toUint32();
35
9
  }
36
56
  return 0;
37
65
}
38
39
65
uint32_t Cr2Image::pixelHeight() const {
40
65
  auto imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension"));
41
65
  if (imageHeight != exifData_.end() && imageHeight->count() > 0) {
42
10
    return imageHeight->toUint32();
43
10
  }
44
55
  return 0;
45
65
}
46
47
0
void Cr2Image::printStructure(std::ostream& out, Exiv2::PrintStructureOption option, size_t depth) {
48
0
  if (io_->open() != 0)
49
0
    throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
50
0
  io_->seek(0, BasicIo::beg);
51
0
  printTiffStructure(io(), out, option, depth);
52
0
}
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
75
void Cr2Image::readMetadata() {
60
#ifdef EXIV2_DEBUG_MESSAGES
61
  std::cerr << "Reading CR2 file " << io_->path() << "\n";
62
#endif
63
75
  if (io_->open() != 0) {
64
0
    throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
65
0
  }
66
75
  IoCloser closer(*io_);
67
  // Ensure that this is the correct image type
68
75
  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
75
  clearMetadata();
74
75
  ByteOrder bo = Cr2Parser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size());
75
75
  setByteOrder(bo);
76
75
}  // 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
75
ByteOrder Cr2Parser::decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size) {
103
75
  Internal::Cr2Header cr2Header;
104
75
  return Internal::TiffParserWorker::decode(exifData, iptcData, xmpData, pData, size, Internal::Tag::root,
105
75
                                            Internal::TiffMapping::findDecoder, &cr2Header);
106
75
}
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
75
Image::UniquePtr newCr2Instance(BasicIo::UniquePtr io, bool create) {
132
75
  auto image = std::make_unique<Cr2Image>(std::move(io), create);
133
75
  if (!image->good()) {
134
0
    return nullptr;
135
0
  }
136
75
  return image;
137
75
}
138
139
20.1k
bool isCr2Type(BasicIo& iIo, bool advance) {
140
20.1k
  const int32_t len = 16;
141
20.1k
  byte buf[len];
142
20.1k
  iIo.read(buf, len);
143
20.1k
  if (iIo.error() || iIo.eof()) {
144
192
    return false;
145
192
  }
146
19.9k
  Internal::Cr2Header header;
147
19.9k
  bool rc = header.read(buf, len);
148
19.9k
  if (!advance || !rc) {
149
19.9k
    iIo.seek(-len, BasicIo::cur);
150
19.9k
  }
151
19.9k
  return rc;
152
20.1k
}
153
154
}  // namespace Exiv2