/src/exiv2/src/mrwimage.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | |
3 | | // included header files |
4 | | #include "mrwimage.hpp" |
5 | | |
6 | | #include "basicio.hpp" |
7 | | #include "config.h" |
8 | | #include "enforce.hpp" |
9 | | #include "error.hpp" |
10 | | #include "futils.hpp" |
11 | | #include "image.hpp" |
12 | | #include "tags.hpp" |
13 | | #include "tiffimage.hpp" |
14 | | |
15 | | #include <array> |
16 | | #include <cstring> |
17 | | |
18 | | #ifdef EXIV2_DEBUG_MESSAGES |
19 | | #include <iostream> |
20 | | #endif |
21 | | |
22 | | namespace Exiv2 { |
23 | | MrwImage::MrwImage(BasicIo::UniquePtr io, bool /*create*/) : |
24 | 477 | Image(ImageType::mrw, mdExif | mdIptc | mdXmp, std::move(io)) { |
25 | 477 | } |
26 | | |
27 | 0 | std::string MrwImage::mimeType() const { |
28 | 0 | return "image/x-minolta-mrw"; |
29 | 0 | } |
30 | | |
31 | 32 | uint32_t MrwImage::pixelWidth() const { |
32 | 32 | auto imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth")); |
33 | 32 | if (imageWidth != exifData_.end() && imageWidth->count() > 0) { |
34 | 6 | return imageWidth->toUint32(); |
35 | 6 | } |
36 | 26 | return 0; |
37 | 32 | } |
38 | | |
39 | 32 | uint32_t MrwImage::pixelHeight() const { |
40 | 32 | auto imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageLength")); |
41 | 32 | if (imageHeight != exifData_.end() && imageHeight->count() > 0) { |
42 | 6 | return imageHeight->toUint32(); |
43 | 6 | } |
44 | 26 | return 0; |
45 | 32 | } |
46 | | |
47 | 0 | void MrwImage::setExifData(const ExifData& /*exifData*/) { |
48 | | // Todo: implement me! |
49 | 0 | throw(Error(ErrorCode::kerInvalidSettingForImage, "Exif metadata", "MRW")); |
50 | 0 | } |
51 | | |
52 | 0 | void MrwImage::setIptcData(const IptcData& /*iptcData*/) { |
53 | | // Todo: implement me! |
54 | 0 | throw(Error(ErrorCode::kerInvalidSettingForImage, "IPTC metadata", "MRW")); |
55 | 0 | } |
56 | | |
57 | 0 | void MrwImage::setComment(const std::string&) { |
58 | | // not supported |
59 | 0 | throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "MRW")); |
60 | 0 | } |
61 | | |
62 | 477 | void MrwImage::readMetadata() { |
63 | | #ifdef EXIV2_DEBUG_MESSAGES |
64 | | std::cerr << "Reading MRW file " << io_->path() << "\n"; |
65 | | #endif |
66 | 477 | if (io_->open() != 0) { |
67 | 0 | throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError()); |
68 | 0 | } |
69 | 477 | IoCloser closer(*io_); |
70 | | // Ensure that this is the correct image type |
71 | 477 | if (!isMrwType(*io_, false)) { |
72 | 0 | if (io_->error() || io_->eof()) |
73 | 0 | throw Error(ErrorCode::kerFailedToReadImageData); |
74 | 0 | throw Error(ErrorCode::kerNotAnImage, "MRW"); |
75 | 0 | } |
76 | 477 | clearMetadata(); |
77 | | |
78 | | // Find the TTW block and read it into a buffer |
79 | 477 | uint32_t const len = 8; |
80 | 477 | byte tmp[len]; |
81 | 477 | io_->read(tmp, len); |
82 | 477 | uint32_t pos = len; |
83 | 477 | uint32_t const end = getULong(tmp + 4, bigEndian); |
84 | | |
85 | 477 | pos += len; |
86 | 477 | Internal::enforce(pos <= end, ErrorCode::kerFailedToReadImageData); |
87 | 477 | io_->read(tmp, len); |
88 | 477 | if (io_->error() || io_->eof()) |
89 | 0 | throw Error(ErrorCode::kerFailedToReadImageData); |
90 | | |
91 | 1.40k | while (memcmp(tmp + 1, "TTW", 3) != 0) { |
92 | 924 | uint32_t const siz = getULong(tmp + 4, bigEndian); |
93 | 924 | Internal::enforce(siz <= end - pos, ErrorCode::kerFailedToReadImageData); |
94 | 924 | pos += siz; |
95 | 924 | io_->seek(siz, BasicIo::cur); |
96 | 924 | Internal::enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData); |
97 | | |
98 | 924 | Internal::enforce(len <= end - pos, ErrorCode::kerFailedToReadImageData); |
99 | 924 | pos += len; |
100 | 924 | io_->read(tmp, len); |
101 | 924 | Internal::enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData); |
102 | 924 | } |
103 | | |
104 | 477 | const uint32_t siz = getULong(tmp + 4, bigEndian); |
105 | | // First do an approximate bounds check of siz, so that we don't |
106 | | // get DOS-ed by a 4GB allocation on the next line. If siz is |
107 | | // greater than io_->size() then it is definitely invalid. But the |
108 | | // exact bounds checking is done by the call to io_->read, which |
109 | | // will fail if there are fewer than siz bytes left to read. |
110 | 477 | Internal::enforce(siz <= io_->size(), ErrorCode::kerFailedToReadImageData); |
111 | 477 | DataBuf buf(siz); |
112 | 477 | io_->read(buf.data(), buf.size()); |
113 | 477 | Internal::enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData); |
114 | | |
115 | 477 | ByteOrder bo = TiffParser::decode(exifData_, iptcData_, xmpData_, buf.c_data(), buf.size()); |
116 | 477 | setByteOrder(bo); |
117 | 477 | } // MrwImage::readMetadata |
118 | | |
119 | 16 | void MrwImage::writeMetadata() { |
120 | | // Todo: implement me! |
121 | 16 | throw(Error(ErrorCode::kerWritingImageFormatUnsupported, "MRW")); |
122 | 16 | } // MrwImage::writeMetadata |
123 | | |
124 | | // ************************************************************************* |
125 | | // free functions |
126 | 477 | Image::UniquePtr newMrwInstance(BasicIo::UniquePtr io, bool create) { |
127 | 477 | auto image = std::make_unique<MrwImage>(std::move(io), create); |
128 | 477 | if (!image->good()) { |
129 | 0 | return nullptr; |
130 | 0 | } |
131 | 477 | return image; |
132 | 477 | } |
133 | | |
134 | 73.6k | bool isMrwType(BasicIo& iIo, bool advance) { |
135 | 73.6k | const int32_t len = 4; |
136 | 73.6k | const std::array<byte, len> MrwId{0x0, 0x4d, 0x52, 0x4d}; |
137 | 73.6k | std::array<byte, len> buf; |
138 | 73.6k | iIo.read(buf.data(), len); |
139 | 73.6k | if (iIo.error() || iIo.eof()) { |
140 | 245 | return false; |
141 | 245 | } |
142 | 73.3k | bool rc = buf == MrwId; |
143 | 73.3k | if (!advance || !rc) { |
144 | 73.3k | iIo.seek(-len, BasicIo::cur); |
145 | 73.3k | } |
146 | 73.3k | return rc; |
147 | 73.6k | } |
148 | | |
149 | | } // namespace Exiv2 |