RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
TiffIFD.cpp
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
5 Copyright (C) 2015 Pedro CĂ´rte-Real
6 Copyright (C) 2017 Axel Waggershauser
7 Copyright (C) 2018 Roman Lebedev
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22*/
23
24#include "rawspeedconfig.h"
25#include "tiff/TiffIFD.h"
26#include "adt/NORangesSet.h"
27#include "common/Common.h"
29#include "io/ByteStream.h"
30#include "io/Endianness.h"
31#include "io/IOException.h"
33#include "tiff/TiffEntry.h"
34#include "tiff/TiffTag.h"
35#include <cassert>
36#include <cstdint>
37#include <map>
38#include <memory>
39#include <string>
40#include <string_view>
41#include <utility>
42#include <vector>
43
44using std::vector;
45
46namespace rawspeed {
47
48void TiffIFD::anchor() const {
49 // Empty out-of-line definition for the purpose of anchoring
50 // the class's vtable to this Translational Unit.
51}
52
54 assert(ifds);
55
57
58 auto origPos = bs.getPosition();
59
60 try {
61 t = std::make_unique<TiffEntry>(this, bs);
62 } catch (const IOException&) { // Ignore unparsable entry
63 // fix probably broken position due to interruption by exception
64 // i.e. setting it to the next entry.
65 bs.setPosition(origPos + 12);
66 return;
67 }
68
69 try {
70 switch (t->tag) {
71 using enum TiffTag;
72 case DNGPRIVATEDATA:
73 // These are arbitrarily 'rebased', to preserve the offsets, but as it is
74 // implemented right now, that could trigger UB (pointer arithmetics,
75 // creating pointer to unowned memory, etc). And since this is not even
76 // used anywhere right now, let's not
77 // add(parseDngPrivateData(ifds, t.get()));
78 // but just add them as entries. (e.g. ArwDecoder uses WB from them)
79 add(std::move(t));
80 break;
81
82 case MAKERNOTE:
83 case MAKERNOTE_ALT:
84 add(parseMakerNote(ifds, t.get()));
85 break;
86
87 case FUJI_RAW_IFD:
88 case SUBIFDS:
89 case EXIFIFDPOINTER:
90 for (uint32_t j = 0; j < t->count; j++)
91 add(std::make_unique<TiffIFD>(this, ifds, bs, t->getU32(j)));
92 break;
93
94 default:
95 add(std::move(t));
96 }
97 } catch (const RawspeedException&) { // Unparsable private data are added as
98 // entries
99 add(std::move(t));
100 }
101}
102
103TiffIFD::TiffIFD(TiffIFD* parent_) : parent(parent_) {
105 // If we are good (can add this IFD without violating the limits),
106 // we are still here. However, due to the way we add parsed sub-IFD's (lazy),
107 // we need to count this IFD right *NOW*, not when adding it at the end.
109}
110
112 uint32_t offset)
113 : TiffIFD(parent_) {
114 // see TiffParser::parse: UINT32_MAX is used to mark the "virtual" top level
115 // TiffRootIFD in a tiff file
116 if (offset == UINT32_MAX)
117 return;
118
119 assert(ifds);
120
121 ByteStream bs(data);
122 bs.setPosition(offset);
123
124 // Directory entries in this IFD
125 auto numEntries = bs.getU16();
126
127 // 2 bytes for entry count
128 // each entry is 12 bytes
129 // 4-byte offset to the next IFD at the end
130 const auto IFDFullSize = 2 + 4 + (12 * numEntries);
131 if (const Buffer IFDBuf(data.getSubView(offset, IFDFullSize));
132 !ifds->insert(IFDBuf))
133 ThrowTPE("Two IFD's overlap. Raw corrupt!");
134
135 for (uint32_t i = 0; i < numEntries; i++)
136 parseIFDEntry(ifds, bs);
137
138 nextIFD = bs.getU32();
139}
140
141/* This will attempt to parse makernotes and return it as an IFD */
143 const TiffEntry* t) {
144 assert(ifds);
145
146 // go up the IFD tree and try to find the MAKE entry on each level.
147 // we can not go all the way to the top first because this partial tree
148 // is not yet added to the TiffRootIFD.
149 const TiffIFD* p = this;
150 const TiffEntry* makeEntry = nullptr;
151 while (p && !makeEntry) {
152 makeEntry = p->getEntryRecursive(TiffTag::MAKE);
153 p = p->parent;
154 }
155 std::string make =
156 makeEntry != nullptr ? trimSpaces(makeEntry->getString()) : "";
157
158 ByteStream bs = t->getData();
159
160 // helper function for easy setup of ByteStream buffer for the different maker
161 // note types 'rebase' means position 0 of new stream equals current position
162 // 'newPosition' is the position where the IFD starts
163 // 'byteOrderOffset' is the position where the 2 magic bytes (II/MM) may be
164 // found 'context' is a string providing error information in case the byte
165 // order parsing should fail
166 auto setup = [&bs](bool rebase, uint32_t newPosition,
167 uint32_t byteOrderOffset = 0,
168 const char* context = nullptr) {
169 if (rebase)
170 bs = bs.getSubStream(bs.getPosition(), bs.getRemainSize());
171 if (context)
172 bs.setByteOrder(getTiffByteOrder(bs, byteOrderOffset, context));
173 bs.skipBytes(newPosition);
174 };
175
176 if (bs.hasPrefix(std::string_view("AOC\0", 4))) {
177 setup(false, 6, 4, "Pentax makernote");
178 } else if (bs.hasPrefix("PENTAX")) {
179 setup(true, 10, 8, "Pentax makernote");
180 } else if (bs.hasPrefix(std::string_view("FUJIFILM\x0c\x00\x00\x00", 12))) {
182 setup(true, 12);
183 } else if (bs.hasPrefix(std::string_view("Nikon\x00\x02", 7))) {
184 // this is Nikon type 3 maker note format
185 // TODO: implement Nikon type 1 maker note format
186 // see http://www.ozhiker.com/electronics/pjmt/jpeg_info/nikon_mn.html
187 bs.skipBytes(10);
188 setup(true, 8, 0, "Nikon makernote");
189 } else if (bs.hasPrefix("OLYMPUS")) { // new Olympus
190 setup(true, 12);
191 } else if (bs.hasPrefix("OLYMP")) { // old Olympus
192 setup(true, 8);
193 } else if (bs.hasPrefix("OM SYSTEM")) { // ex Olympus
194 setup(true, 16);
195 } else if (bs.hasPrefix("EPSON")) {
196 setup(false, 8);
197 } else if (bs.hasPrefix("Apple iOS")) {
198 setup(true, 14, 12, "Apple makernote");
199 } else if (bs.hasPatternAt("Exif", 6)) {
200 // TODO: for none of the rawsamples.ch files from Panasonic is this true,
201 // instead their MakerNote start with "Panasonic" Panasonic has the word
202 // Exif at byte 6, a complete Tiff header starts at byte 12 This TIFF is 0
203 // offset based
204 setup(false, 20, 12, "Panosonic makernote");
205 } else if (make == "SAMSUNG") {
206 // Samsung has no identification in its MakerNote but starts with the IFD
207 // right away
208 setup(true, 0);
209 } else {
210 // cerr << "default MakerNote from " << make << endl; // Canon, Nikon (type
211 // 2), Sony, Minolta, Ricoh, Leica, Hasselblad, etc.
212
213 // At least one MAKE has not been handled explicitly and starts its
214 // MakerNote with an endian prefix: Kodak
215 if (bs.skipPrefix("II")) {
217 } else if (bs.skipPrefix("MM")) {
219 }
220 }
221
222 // Attempt to parse the rest as an IFD
223 return std::make_unique<TiffRootIFD>(this, ifds, bs, bs.getPosition());
224}
225
226std::vector<const TiffIFD*> TiffIFD::getIFDsWithTag(TiffTag tag) const {
227 vector<const TiffIFD*> matchingIFDs;
228 if (entries.contains(tag)) {
229 matchingIFDs.push_back(this);
230 }
231 for (const auto& i : subIFDs) {
232 vector<const TiffIFD*> t = i->getIFDsWithTag(tag);
233 matchingIFDs.insert(matchingIFDs.end(), t.begin(), t.end());
234 }
235 return matchingIFDs;
236}
237
239 auto ifds = getIFDsWithTag(tag);
240 if (index >= ifds.size())
241 ThrowTPE("failed to find %u ifd with tag 0x%04x", index + 1,
242 static_cast<unsigned>(tag));
243 return ifds[index];
244}
245
246TiffEntry* RAWSPEED_READONLY TiffIFD::getEntryRecursive(TiffTag tag) const {
247 if (auto i = entries.find(tag); i != entries.end()) {
248 return i->second.get();
249 }
250 for (const auto& j : subIFDs) {
251 TiffEntry* entry = j->getEntryRecursive(tag);
252 if (entry)
253 return entry;
254 }
255 return nullptr;
256}
257
259 TiffIFD* p = this->parent;
260 if (!p)
261 return;
262
263 p->subIFDCount++;
264
265 for (; p != nullptr; p = p->parent)
266 p->subIFDCountRecursive++;
267}
268
269void TiffIFD::checkSubIFDs(int headroom) const {
270 int count = headroom + subIFDCount;
271 if (!headroom)
273 else if (count > TiffIFD::Limits::SubIFDCount)
274 ThrowTPE("TIFF IFD has %d SubIFDs", count);
275
276 count = headroom + subIFDCountRecursive;
277 if (!headroom)
280 ThrowTPE("TIFF IFD file has %d SubIFDs (recursively)", count);
281}
282
283void TiffIFD::recursivelyCheckSubIFDs(int headroom) const {
284 int depth = 0;
285 for (const TiffIFD* p = this; p != nullptr;) {
286 if (!headroom)
288 else if (depth > TiffIFD::Limits::Depth)
289 ThrowTPE("TiffIFD cascading overflow, found %d level IFD", depth);
290
291 p->checkSubIFDs(headroom);
292
293 // And step up
294 p = p->parent;
295 depth++;
296 }
297}
298
300 assert(subIFD->parent == this);
301
302 // We are good, and actually can add this sub-IFD, right?
303 subIFD->recursivelyCheckSubIFDs(0);
304
305 subIFDs.push_back(std::move(subIFD));
306}
307
309 entry->parent = this;
310 entries[entry->tag] = std::move(entry);
311}
312
314 auto i = entries.find(tag);
315 if (i == entries.end())
316 ThrowTPE("Entry 0x%x not found.", static_cast<unsigned>(tag));
317 return i->second.get();
318}
319
321 // Empty out-of-line definition for the purpose of anchoring
322 // the class's vtable to this Translational Unit.
323}
324
326 TiffID id;
327 const auto* makeE = getEntryRecursive(TiffTag::MAKE);
328 const auto* modelE = getEntryRecursive(TiffTag::MODEL);
329
330 if (!makeE)
331 ThrowTPE("Failed to find MAKE entry.");
332 if (!modelE)
333 ThrowTPE("Failed to find MODEL entry.");
334
335 id.make = trimSpaces(makeE->getString());
336 id.model = trimSpaces(modelE->getString());
337
338 return id;
339}
340
341} // namespace rawspeed
#define ThrowTPE(...)
assert(dim.area() >=area)
Buffer getSubView(size_type offset, size_type size_) const
Definition Buffer.h:78
size_type RAWSPEED_READONLY getRemainSize() const
Definition ByteStream.h:87
void setPosition(size_type newPos)
Definition ByteStream.h:83
ByteStream getSubStream(size_type offset, size_type size_) const
Definition ByteStream.h:54
bool hasPrefix(std::string_view prefix) const
Definition ByteStream.h:145
void skipBytes(size_type nbytes)
Definition ByteStream.h:130
bool skipPrefix(std::string_view prefix)
Definition ByteStream.h:149
size_type getPosition() const
Definition ByteStream.h:78
bool hasPatternAt(std::string_view pattern, size_type relPos) const
Definition ByteStream.h:135
Endianness setByteOrder(Endianness endianness_)
Definition Buffer.h:156
bool insert(const T &newElt)
Definition NORangesSet.h:61
ByteStream getData() const
Definition TiffEntry.h:129
std::string getString() const
TiffIFD(TiffIFD *parent)
Definition TiffIFD.cpp:103
std::vector< TiffIFDOwner > subIFDs
Definition TiffIFD.h:54
TiffEntry *RAWSPEED_READONLY getEntryRecursive(TiffTag tag) const
Definition TiffIFD.cpp:246
virtual void anchor() const
Definition TiffIFD.cpp:48
const TiffIFD * getIFDWithTag(TiffTag tag, uint32_t index=0) const
Definition TiffIFD.cpp:238
std::vector< const TiffIFD * > getIFDsWithTag(TiffTag tag) const
Definition TiffIFD.cpp:226
std::map< TiffTag, TiffEntryOwner > entries
Definition TiffIFD.h:59
void recursivelyCheckSubIFDs(int headroom) const
Definition TiffIFD.cpp:283
uint32_t nextIFD
Definition TiffIFD.h:50
TiffEntry * getEntry(TiffTag tag) const
Definition TiffIFD.cpp:313
int subIFDCountRecursive
Definition TiffIFD.h:57
void checkSubIFDs(int headroom) const
Definition TiffIFD.cpp:269
TiffRootIFDOwner parseMakerNote(NORangesSet< Buffer > *ifds, const TiffEntry *t)
Definition TiffIFD.cpp:142
friend class TiffEntry
Definition TiffIFD.h:63
void add(TiffIFDOwner subIFD)
Definition TiffIFD.cpp:299
TiffIFD *const parent
Definition TiffIFD.h:52
void parseIFDEntry(NORangesSet< Buffer > *ifds, ByteStream &bs)
Definition TiffIFD.cpp:53
void recursivelyIncrementSubIFDCount()
Definition TiffIFD.cpp:258
void anchor() const override
Definition TiffIFD.cpp:320
TiffID getID() const
Definition TiffIFD.cpp:325
std::unique_ptr< TiffIFD > TiffIFDOwner
Definition TiffIFD.h:45
std::string trimSpaces(std::string_view str)
Definition Common.h:163
std::unique_ptr< TiffRootIFD > TiffRootIFDOwner
Definition TiffIFD.h:46
Endianness getTiffByteOrder(ByteStream bs, uint32_t pos, const char *context="")
Definition TiffIFD.h:153
std::unique_ptr< TiffEntry > TiffEntryOwner
Definition TiffIFD.h:47
static constexpr int RecursiveSubIFDCount
Definition TiffIFD.h:96
static constexpr int SubIFDCount
Definition TiffIFD.h:91
static constexpr int Depth
Definition TiffIFD.h:85