RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
CiffIFD.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) 2014 Pedro CĂ´rte-Real
6 Copyright (C) 2017-2018 Roman Lebedev
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21*/
22
23#include "rawspeedconfig.h"
24#include "tiff/CiffIFD.h"
25#include "adt/NORangesSet.h"
26#include "common/Common.h"
27#include "io/Buffer.h"
28#include "io/ByteStream.h"
30#include "tiff/CiffEntry.h"
31#include "tiff/CiffTag.h"
32#include <algorithm>
33#include <cassert>
34#include <cstdint>
35#include <map>
36#include <memory>
37#include <string>
38#include <utility>
39#include <vector>
40
41using std::vector;
42
43namespace rawspeed {
44
46 ByteStream valueData, ByteStream& dirEntries) {
47 assert(valueDatas);
48
49 ByteStream dirEntry = dirEntries.getStream(10); // Entry is 10 bytes.
50
51 CiffEntry t = CiffEntry::Create(valueDatas, valueData, dirEntry);
52
53 switch (t.type) {
55 case CiffDataType::SUB2: {
56 add(std::make_unique<CiffIFD>(this, t.data));
57 break;
58 }
59
60 default:
61 // Will we ever look for this entry?
63 return;
64 add(std::make_unique<CiffEntry>(t));
65 }
66}
67
68CiffIFD::CiffIFD(CiffIFD* const parent_) : parent(parent_) {
70 // If we are good (can add this IFD without violating the limits),
71 // we are still here. However, due to the way we add parsed sub-IFD's (lazy),
72 // we need to count this IFD right *NOW*, not when adding it at the end.
74}
75
76CiffIFD::CiffIFD(CiffIFD* const parent_, ByteStream directory)
77 : CiffIFD(parent_) {
78 if (directory.getSize() < 4)
79 ThrowCPE("CIFF directory is too short.");
80
81 directory.setPosition(directory.getSize() - 4);
82 const uint32_t valueDataSize = directory.getU32();
83
84 // The Recursion. Directory entries store data here. May contain IFDs.
85 directory.setPosition(0);
86 const ByteStream valueData(directory.getStream(valueDataSize));
87
88 // count of the Directory entries in this IFD
89 const uint16_t entryCount = directory.getU16();
90
91 // each entry is 10 bytes
92 ByteStream dirEntries(directory.getStream(entryCount, 10));
93
94 // IFDData might still contain OtherData until the valueDataSize at the end.
95 // But we do not care about that.
96
97 // Each IFD has it's own valueData area.
98 // In that area, no two entries may overlap.
99 NORangesSet<Buffer> valueDatas;
100
101 for (uint32_t i = 0; i < entryCount; i++)
102 parseIFDEntry(&valueDatas, valueData, dirEntries);
103
104 assert(valueDatas.size() <= entryCount);
105 assert(mEntry.size() <= CiffTagsWeCareAbout.size());
106 assert(mSubIFD.size() == decltype(mSubIFD)::size_type(subIFDCount));
108 assert(mEntry.size() + mSubIFD.size() <= entryCount);
109}
110
112 CiffIFD* p = this->parent;
113 if (!p)
114 return;
115
116 p->subIFDCount++;
117
118 for (; p != nullptr; p = p->parent)
119 p->subIFDCountRecursive++;
120}
121
122void CiffIFD::checkSubIFDs(int headroom) const {
123 int count = headroom + subIFDCount;
124 if (!headroom)
126 else if (count > CiffIFD::Limits::SubIFDCount)
127 ThrowCPE("TIFF IFD has %d SubIFDs", count);
128
129 count = headroom + subIFDCountRecursive;
130 if (!headroom)
133 ThrowCPE("TIFF IFD file has %d SubIFDs (recursively)", count);
134}
135
136void CiffIFD::recursivelyCheckSubIFDs(int headroom) const {
137 int depth = 0;
138 for (const CiffIFD* p = this; p != nullptr;) {
139 if (!headroom)
141 else if (depth > CiffIFD::Limits::Depth)
142 ThrowCPE("CiffIFD cascading overflow, found %d level IFD", depth);
143
144 p->checkSubIFDs(headroom);
145
146 // And step up
147 p = p->parent;
148 depth++;
149 }
150}
151
152void CiffIFD::add(std::unique_ptr<CiffIFD> subIFD) {
153 assert(subIFD->parent == this);
154
155 // We are good, and actually can add this sub-IFD, right?
156 subIFD->recursivelyCheckSubIFDs(0);
157
158 mSubIFD.push_back(std::move(subIFD));
159}
160
161void CiffIFD::add(std::unique_ptr<CiffEntry> entry) {
162 assert(isIn(entry->tag, CiffTagsWeCareAbout));
163 mEntry[entry->tag] = std::move(entry);
164 assert(mEntry.size() <= CiffTagsWeCareAbout.size());
165}
166
167template <typename Lambda>
168std::vector<const CiffIFD*> CiffIFD::getIFDsWithTagIf(CiffTag tag,
169 const Lambda& f) const {
171
172 std::vector<const CiffIFD*> matchingIFDs;
173
174 if (const auto found = mEntry.find(tag); found != mEntry.end()) {
175 const auto* const entry = found->second.get();
176 if (f(entry))
177 matchingIFDs.push_back(this);
178 }
179
180 for (const auto& i : mSubIFD) {
181 const auto t = i->getIFDsWithTagIf(tag, f);
182 matchingIFDs.insert(matchingIFDs.end(), t.begin(), t.end());
183 }
184
185 return matchingIFDs;
186}
187
188template <typename Lambda>
190 const Lambda& f) const {
192
193 if (const auto found = mEntry.find(tag); found != mEntry.end()) {
194 const auto* const entry = found->second.get();
195 if (f(entry))
196 return entry;
197 }
198
199 for (const auto& i : mSubIFD) {
200 const CiffEntry* entry = i->getEntryRecursiveIf(tag, f);
201 if (entry)
202 return entry;
203 }
204
205 return nullptr;
206}
207
208vector<const CiffIFD*> CiffIFD::getIFDsWithTag(CiffTag tag) const {
210 return getIFDsWithTagIf(tag,
211 [](const CiffEntry* /*unused*/) { return true; });
212}
213
214vector<const CiffIFD*> CiffIFD::getIFDsWithTagWhere(CiffTag tag,
215 uint32_t isValue) const {
217 return getIFDsWithTagIf(tag, [&isValue](const CiffEntry* entry) {
218 return entry->isInt() && entry->getU32() == isValue;
219 });
220}
221
222vector<const CiffIFD*>
223CiffIFD::getIFDsWithTagWhere(CiffTag tag, const std::string& isValue) const {
225 return getIFDsWithTagIf(tag, [&isValue](const CiffEntry* entry) {
226 return entry->isString() && isValue == entry->getString();
227 });
228}
229
230bool RAWSPEED_READONLY CiffIFD::hasEntry(CiffTag tag) const {
232
233 return mEntry.contains(tag);
234}
235
236bool RAWSPEED_READONLY CiffIFD::hasEntryRecursive(CiffTag tag) const {
238
239 if (mEntry.contains(tag))
240 return true;
241
242 return std::any_of(mSubIFD.begin(), mSubIFD.end(),
243 [tag](const std::unique_ptr<const CiffIFD>& i) {
244 return i->hasEntryRecursive(tag);
245 });
246}
247
250
251 if (const auto found = mEntry.find(tag); found != mEntry.end())
252 return found->second.get();
253
254 ThrowCPE("Entry 0x%x not found.", static_cast<unsigned>(tag));
255}
256
259 return getEntryRecursiveIf(tag,
260 [](const CiffEntry* /*unused*/) { return true; });
261}
262
264 uint32_t isValue) const {
266 return getEntryRecursiveIf(tag, [&isValue](const CiffEntry* entry) {
267 return entry->isInt() && entry->getU32() == isValue;
268 });
269}
270
271const CiffEntry*
272CiffIFD::getEntryRecursiveWhere(CiffTag tag, const std::string& isValue) const {
274 return getEntryRecursiveIf(tag, [&isValue](const CiffEntry* entry) {
275 return entry->isString() && isValue == entry->getString();
276 });
277}
278
279} // namespace rawspeed
#define ThrowCPE(...)
assert(dim.area() >=area)
size_type RAWSPEED_READONLY getSize() const
Definition Buffer.h:115
void setPosition(size_type newPos)
Definition ByteStream.h:83
ByteStream getStream(size_type size_)
Definition ByteStream.h:119
Definition CiffEntry.h:54
ByteStream data
Definition CiffEntry.h:57
static CiffEntry Create(NORangesSet< Buffer > *valueDatas, ByteStream valueData, ByteStream dirEntry)
Definition CiffEntry.cpp:45
CiffDataType type
Definition CiffEntry.h:81
uint32_t getU32(uint32_t num=0) const
std::string_view getString() const
CiffTag tag
Definition CiffEntry.h:80
bool RAWSPEED_READONLY isInt() const
bool RAWSPEED_READONLY isString() const
bool RAWSPEED_READONLY hasEntry(CiffTag tag) const
Definition CiffIFD.cpp:230
int subIFDCountRecursive
Definition CiffIFD.h:49
CiffIFD *const parent
Definition CiffIFD.h:43
const CiffEntry *RAWSPEED_READONLY getEntryRecursiveIf(CiffTag tag, const Lambda &f) const
void recursivelyCheckSubIFDs(int headroom) const
Definition CiffIFD.cpp:136
std::vector< const CiffIFD * > RAWSPEED_READONLY getIFDsWithTag(CiffTag tag) const
Definition CiffIFD.cpp:208
void recursivelyIncrementSubIFDCount()
Definition CiffIFD.cpp:111
CiffIFD(CiffIFD *parent)
Definition CiffIFD.cpp:68
void add(std::unique_ptr< CiffIFD > subIFD)
Definition CiffIFD.cpp:152
std::vector< const CiffIFD * > RAWSPEED_READONLY getIFDsWithTagIf(CiffTag tag, const Lambda &f) const
const CiffEntry *RAWSPEED_READONLY getEntryRecursiveWhere(CiffTag tag, uint32_t isValue) const
Definition CiffIFD.cpp:263
std::vector< const CiffIFD * > RAWSPEED_READONLY getIFDsWithTagWhere(CiffTag tag, uint32_t isValue) const
Definition CiffIFD.cpp:214
const CiffEntry *RAWSPEED_READONLY getEntryRecursive(CiffTag tag) const
Definition CiffIFD.cpp:257
const CiffEntry *RAWSPEED_READONLY getEntry(CiffTag tag) const
Definition CiffIFD.cpp:248
bool RAWSPEED_READONLY hasEntryRecursive(CiffTag tag) const
Definition CiffIFD.cpp:236
void parseIFDEntry(NORangesSet< Buffer > *valueDatas, ByteStream valueData, ByteStream &dirEntries)
Definition CiffIFD.cpp:45
std::map< CiffTag, std::unique_ptr< const CiffEntry > > mEntry
Definition CiffIFD.h:46
std::vector< std::unique_ptr< const CiffIFD > > mSubIFD
Definition CiffIFD.h:45
void checkSubIFDs(int headroom) const
Definition CiffIFD.cpp:122
bool RAWSPEED_READONLY isIn(const T value, const std::initializer_list< T2 > &list)
Definition Common.h:156
static constexpr std::initializer_list< CiffTag > CiffTagsWeCareAbout
Definition CiffTag.h:42
static constexpr int SubIFDCount
Definition CiffIFD.h:69
static constexpr int RecursiveSubIFDCount
Definition CiffIFD.h:74
static constexpr int Depth
Definition CiffIFD.h:63