Coverage Report

Created: 2026-08-25 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/exiv2/src/tiffvisitor_int.cpp
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
3
// included header files
4
#include "tiffvisitor_int.hpp"  // see bug #487
5
6
#include "config.h"
7
#include "enforce.hpp"
8
#include "exif.hpp"
9
#include "image_int.hpp"
10
#include "iptc.hpp"
11
#include "makernote_int.hpp"
12
#include "photoshop.hpp"
13
#include "safe_op.hpp"
14
#include "sonymn_int.hpp"
15
#include "tags.hpp"
16
#include "tags_int.hpp"
17
#include "tiffcomposite_int.hpp"
18
#include "tiffimage_int.hpp"
19
#include "value.hpp"
20
#include "xmp_exiv2.hpp"
21
22
#include <functional>
23
#include <iomanip>
24
25
#ifdef EXIV2_DEBUG_MESSAGES
26
#include <iostream>
27
#endif
28
29
// *****************************************************************************
30
namespace {
31
//! Unary predicate that matches an Exifdatum with a given group and index.
32
class FindExifdatum2 {
33
 public:
34
  //! Constructor, initializes the object with the group and index to look for.
35
0
  FindExifdatum2(Exiv2::IfdId group, int idx) : groupName_(Exiv2::Internal::groupName(group)), idx_(idx) {
36
0
  }
37
  //! Returns true if group and index match.
38
0
  bool operator()(const Exiv2::Exifdatum& md) const {
39
0
    return idx_ == md.idx() && md.groupName() == groupName_;
40
0
  }
41
42
 private:
43
  const char* groupName_;
44
  int idx_;
45
46
};  // class FindExifdatum2
47
48
0
Exiv2::ByteOrder stringToByteOrder(std::string_view val) {
49
0
  if (val == "II")
50
0
    return Exiv2::littleEndian;
51
0
  if (val == "MM")
52
0
    return Exiv2::bigEndian;
53
54
0
  return Exiv2::invalidByteOrder;
55
0
}
56
}  // namespace
57
58
// *****************************************************************************
59
// class member definitions
60
namespace Exiv2::Internal {
61
28.9k
void TiffVisitor::setGo(GoEvent event, bool go) {
62
28.9k
  go_[event] = go;
63
28.9k
}
64
65
16.1M
bool TiffVisitor::go(GoEvent event) const {
66
16.1M
  return go_[event];
67
16.1M
}
68
69
136k
void TiffVisitor::visitDirectoryNext(TiffDirectory* /*object*/) {
70
136k
}
71
72
130k
void TiffVisitor::visitDirectoryEnd(TiffDirectory* /*object*/) {
73
130k
}
74
75
1.09k
void TiffVisitor::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/) {
76
1.09k
}
77
78
78.5k
void TiffVisitor::visitBinaryArrayEnd(TiffBinaryArray* /*object*/) {
79
78.5k
}
80
81
0
void TiffFinder::init(uint16_t tag, IfdId group) {
82
0
  tag_ = tag;
83
0
  group_ = group;
84
0
  tiffComponent_ = nullptr;
85
0
  setGo(geTraverse, true);
86
0
}
87
88
4.59M
void TiffFinder::findObject(TiffComponent* object) {
89
4.59M
  if (object->tag() == tag_ && object->group() == group_) {
90
28.9k
    tiffComponent_ = object;
91
28.9k
    setGo(geTraverse, false);
92
28.9k
  }
93
4.59M
}
94
95
2.61M
void TiffFinder::visitEntry(TiffEntry* object) {
96
2.61M
  findObject(object);
97
2.61M
}
98
99
8.69k
void TiffFinder::visitDataEntry(TiffDataEntry* object) {
100
8.69k
  findObject(object);
101
8.69k
}
102
103
26.9k
void TiffFinder::visitImageEntry(TiffImageEntry* object) {
104
26.9k
  findObject(object);
105
26.9k
}
106
107
115k
void TiffFinder::visitSizeEntry(TiffSizeEntry* object) {
108
115k
  findObject(object);
109
115k
}
110
111
100k
void TiffFinder::visitDirectory(TiffDirectory* object) {
112
100k
  findObject(object);
113
100k
}
114
115
19.9k
void TiffFinder::visitSubIfd(TiffSubIfd* object) {
116
19.9k
  findObject(object);
117
19.9k
}
118
119
11.0k
void TiffFinder::visitMnEntry(TiffMnEntry* object) {
120
11.0k
  findObject(object);
121
11.0k
}
122
123
10.2k
void TiffFinder::visitIfdMakernote(TiffIfdMakernote* object) {
124
10.2k
  findObject(object);
125
10.2k
}
126
127
58.3k
void TiffFinder::visitBinaryArray(TiffBinaryArray* object) {
128
58.3k
  findObject(object);
129
58.3k
}
130
131
1.63M
void TiffFinder::visitBinaryElement(TiffBinaryElement* object) {
132
1.63M
  findObject(object);
133
1.63M
}
134
135
TiffCopier::TiffCopier(TiffComponent* pRoot, uint32_t root, const TiffHeaderBase* pHeader,
136
                       PrimaryGroups pPrimaryGroups) :
137
0
    pRoot_(pRoot), root_(root), pHeader_(pHeader), pPrimaryGroups_(std::move(pPrimaryGroups)) {
138
0
}
139
140
0
void TiffCopier::copyObject(const TiffComponent* object) {
141
0
  if (pHeader_->isImageTag(object->tag(), object->group(), pPrimaryGroups_)) {
142
0
    auto clone = object->clone();
143
    // Assumption is that the corresponding TIFF entry doesn't exist
144
0
    auto tiffPath = TiffCreator::getPath(object->tag(), object->group(), root_);
145
0
    pRoot_->addPath(object->tag(), tiffPath, pRoot_, std::move(clone));
146
#ifdef EXIV2_DEBUG_MESSAGES
147
    ExifKey key(object->tag(), groupName(object->group()));
148
    std::cerr << "Copied " << key << "\n";
149
#endif
150
0
  }
151
0
}
152
153
0
void TiffCopier::visitEntry(TiffEntry* object) {
154
0
  copyObject(object);
155
0
}
156
157
0
void TiffCopier::visitDataEntry(TiffDataEntry* object) {
158
0
  copyObject(object);
159
0
}
160
161
0
void TiffCopier::visitImageEntry(TiffImageEntry* object) {
162
0
  copyObject(object);
163
0
}
164
165
0
void TiffCopier::visitSizeEntry(TiffSizeEntry* object) {
166
0
  copyObject(object);
167
0
}
168
169
0
void TiffCopier::visitDirectory(TiffDirectory* /*object*/) {
170
  // Do not copy directories (avoids problems with SubIfds)
171
0
}
172
173
0
void TiffCopier::visitSubIfd(TiffSubIfd* object) {
174
0
  copyObject(object);
175
0
}
176
177
0
void TiffCopier::visitMnEntry(TiffMnEntry* object) {
178
0
  copyObject(object);
179
0
}
180
181
0
void TiffCopier::visitIfdMakernote(TiffIfdMakernote* object) {
182
0
  copyObject(object);
183
0
}
184
185
0
void TiffCopier::visitBinaryArray(TiffBinaryArray* object) {
186
0
  copyObject(object);
187
0
}
188
189
0
void TiffCopier::visitBinaryElement(TiffBinaryElement* object) {
190
0
  copyObject(object);
191
0
}
192
193
TiffDecoder::TiffDecoder(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, TiffComponent* pRoot,
194
                         FindDecoderFct findDecoderFct, const DecodeParams& dp) :
195
26.2k
    exifData_(exifData),
196
26.2k
    iptcData_(iptcData),
197
26.2k
    xmpData_(xmpData),
198
26.2k
    pRoot_(pRoot),
199
26.2k
    findDecoderFct_(findDecoderFct),
200
26.2k
    max_recursion_depth_(dp.max_recursion_depth()) {
201
  // #1402 Fujifilm RAF. Search for the make
202
  // Find camera make in existing metadata (read from the JPEG)
203
26.2k
  ExifKey key("Exif.Image.Make");
204
26.2k
  if (exifData_.findKey(key) != exifData_.end()) {
205
11
    make_ = exifData_.findKey(key)->toString();
206
26.2k
  } else {
207
    // Find camera make by looking for tag 0x010f in IFD0
208
26.2k
    TiffFinder finder(0x010f, IfdId::ifd0Id);
209
26.2k
    pRoot_->accept(finder);
210
26.2k
    auto te = dynamic_cast<const TiffEntryBase*>(finder.result());
211
26.2k
    if (te && te->pValue()) {
212
7.79k
      make_ = te->pValue()->toString();
213
7.79k
    }
214
26.2k
  }
215
26.2k
}
216
217
1.29M
void TiffDecoder::visitEntry(TiffEntry* object) {
218
1.29M
  decodeTiffEntry(object);
219
1.29M
}
220
221
1.14k
void TiffDecoder::visitDataEntry(TiffDataEntry* object) {
222
1.14k
  decodeTiffEntry(object);
223
1.14k
}
224
225
4.57k
void TiffDecoder::visitImageEntry(TiffImageEntry* object) {
226
4.57k
  decodeTiffEntry(object);
227
4.57k
}
228
229
9.37k
void TiffDecoder::visitSizeEntry(TiffSizeEntry* object) {
230
9.37k
  decodeTiffEntry(object);
231
9.37k
}
232
233
43.0k
void TiffDecoder::visitDirectory(TiffDirectory* /* object */) {
234
  // Nothing to do
235
43.0k
}
236
237
10.4k
void TiffDecoder::visitSubIfd(TiffSubIfd* object) {
238
10.4k
  decodeTiffEntry(object);
239
10.4k
}
240
241
1.43k
void TiffDecoder::visitMnEntry(TiffMnEntry* object) {
242
  // Always decode binary makernote tag
243
1.43k
  decodeTiffEntry(object);
244
1.43k
}
245
246
991
void TiffDecoder::visitIfdMakernote(TiffIfdMakernote* object) {
247
991
  exifData_["Exif.MakerNote.Offset"] = static_cast<uint32_t>(object->mnOffset());
248
991
  switch (object->byteOrder()) {
249
991
    case littleEndian:
250
991
      exifData_["Exif.MakerNote.ByteOrder"] = "II";
251
991
      break;
252
0
    case bigEndian:
253
0
      exifData_["Exif.MakerNote.ByteOrder"] = "MM";
254
0
      break;
255
0
    case invalidByteOrder:
256
0
      break;
257
991
  }
258
991
}
259
260
84.1k
void TiffDecoder::getObjData(const byte*& pData, size_t& size, uint16_t tag, IfdId group, const TiffEntryBase* object) {
261
84.1k
  if (object && object->tag() == tag && object->group() == group) {
262
84.0k
    pData = object->pData();
263
84.0k
    size = object->size();
264
84.0k
    return;
265
84.0k
  }
266
40
  TiffFinder finder(tag, group);
267
40
  pRoot_->accept(finder);
268
40
  if (auto te = dynamic_cast<const TiffEntryBase*>(finder.result())) {
269
0
    pData = te->pData();
270
0
    size = te->size();
271
0
    return;
272
0
  }
273
40
}
274
275
84.0k
void TiffDecoder::decodeXmp(const TiffEntryBase* object) {
276
  // add Exif tag anyway
277
84.0k
  decodeStdTiffEntry(object);
278
279
84.0k
  const byte* pData = nullptr;
280
84.0k
  size_t size = 0;
281
84.0k
  getObjData(pData, size, 0x02bc, IfdId::ifd0Id, object);
282
84.0k
  if (pData) {
283
84.0k
    std::string xmpPacket;
284
84.0k
    xmpPacket.assign(reinterpret_cast<const char*>(pData), size);
285
84.0k
    std::string::size_type idx = xmpPacket.find_first_of('<');
286
84.0k
    if (idx != std::string::npos && idx > 0) {
287
57.7k
#ifndef SUPPRESS_WARNINGS
288
57.7k
      EXV_WARNING << "Removing " << idx << " characters from the beginning of the XMP packet\n";
289
57.7k
#endif
290
57.7k
      xmpPacket = xmpPacket.substr(idx);
291
57.7k
    }
292
84.0k
    const DecodeParams dp(max_recursion_depth_);
293
84.0k
    if (XmpParser::decode(xmpData_, xmpPacket, dp)) {
294
79.0k
#ifndef SUPPRESS_WARNINGS
295
79.0k
      EXV_WARNING << "Failed to decode XMP metadata.\n";
296
79.0k
#endif
297
79.0k
    }
298
84.0k
  }
299
84.0k
}  // TiffDecoder::decodeXmp
300
301
85
void TiffDecoder::decodeIptc(const TiffEntryBase* object) {
302
  // add Exif tag anyway
303
85
  decodeStdTiffEntry(object);
304
305
  // All tags are read at this point, so the first time we come here,
306
  // find the relevant IPTC tag and decode IPTC if found
307
85
  if (decodedIptc_) {
308
30
    return;
309
30
  }
310
55
  decodedIptc_ = true;
311
  // 1st choice: IPTCNAA
312
55
  const byte* pData = nullptr;
313
55
  size_t size = 0;
314
55
  getObjData(pData, size, 0x83bb, IfdId::ifd0Id, object);
315
55
  if (pData) {
316
33
    if (0 == IptcParser::decode(iptcData_, pData, size)) {
317
15
      return;
318
15
    }
319
18
#ifndef SUPPRESS_WARNINGS
320
18
    EXV_WARNING << "Failed to decode IPTC block found in " << "Directory Image, entry 0x83bb\n";
321
322
18
#endif
323
18
  }
324
325
  // 2nd choice if no IPTCNAA record found or failed to decode it:
326
  // ImageResources
327
40
  pData = nullptr;
328
40
  size = 0;
329
40
  getObjData(pData, size, 0x8649, IfdId::ifd0Id, object);
330
40
  if (pData) {
331
22
    const byte* record = nullptr;
332
22
    uint32_t sizeHdr = 0;
333
22
    uint32_t sizeData = 0;
334
22
    if (0 != Photoshop::locateIptcIrb(pData, size, &record, sizeHdr, sizeData)) {
335
22
      return;
336
22
    }
337
0
    if (0 == IptcParser::decode(iptcData_, record + sizeHdr, sizeData)) {
338
0
      return;
339
0
    }
340
0
#ifndef SUPPRESS_WARNINGS
341
0
    EXV_WARNING << "Failed to decode IPTC block found in " << "Directory Image, entry 0x8649\n";
342
343
0
#endif
344
0
  }
345
40
}  // TiffMetadataDecoder::decodeIptc
346
347
975
static const TagInfo* findTag(const TagInfo* pList, uint16_t tag) {
348
68.2k
  while (pList->tag_ != 0xffff && pList->tag_ != tag)
349
67.2k
    pList++;
350
975
  return pList->tag_ != 0xffff ? pList : nullptr;
351
975
}
352
353
510
void TiffDecoder::decodeCanonAFInfo(const TiffEntryBase* object) {
354
  // report Exif.Canon.AFInfo as usual
355
510
  TiffDecoder::decodeStdTiffEntry(object);
356
510
  if (object->pValue()->count() < 3 || object->pValue()->typeId() != unsignedShort)
357
43
    return;  // insufficient data
358
359
  // create vector of signedShorts from unsignedShorts in Exif.Canon.AFInfo
360
467
  std::vector<int16_t> ints;
361
467
  std::vector<uint16_t> uint;
362
68.1k
  for (size_t i = 0; i < object->pValue()->count(); i++) {
363
67.6k
    ints.push_back(object->pValue()->toInt64(i));
364
67.6k
    uint.push_back(object->pValue()->toUint32(i));
365
67.6k
  }
366
  // Check this is AFInfo2 (ints[0] = bytes in object)
367
467
  if (ints.front() != static_cast<int16_t>(object->pValue()->count()) * 2)
368
391
    return;
369
370
76
  std::string familyGroup(std::string("Exif.") + groupName(object->group()) + ".");
371
372
76
  const uint16_t nPoints = uint.at(2);
373
76
  const uint16_t nMasks = (nPoints + 15) / (sizeof(uint16_t) * 8);
374
76
  int nStart = 0;
375
376
76
  const std::tuple<uint16_t, uint16_t, bool> records[] = {
377
76
      {0x2600, 1, true},        // AFInfoSize
378
76
      {0x2601, 1, true},        // AFAreaMode
379
76
      {0x2602, 1, true},        // AFNumPoints
380
76
      {0x2603, 1, true},        // AFValidPoints
381
76
      {0x2604, 1, true},        // AFCanonImageWidth
382
76
      {0x2605, 1, true},        // AFCanonImageHeight
383
76
      {0x2606, 1, true},        // AFImageWidth"
384
76
      {0x2607, 1, true},        // AFImageHeight
385
76
      {0x2608, nPoints, true},  // AFAreaWidths
386
76
      {0x2609, nPoints, true},  // AFAreaHeights
387
76
      {0x260a, nPoints, true},  // AFXPositions
388
76
      {0x260b, nPoints, true},  // AFYPositions
389
76
      {0x260c, nMasks, false},  // AFPointsInFocus
390
76
      {0x260d, nMasks, false},  // AFPointsSelected
391
76
      {0x260e, nMasks, false},  // AFPointsUnusable
392
76
  };
393
  // check we have enough data!
394
76
  uint16_t count = 0;
395
1.09k
  for (const auto& [tag, size, bSigned] : records) {
396
1.09k
    count += size;
397
1.09k
    if (count > ints.size())
398
11
      return;
399
1.09k
  }
400
401
975
  for (const auto& [tag, size, bSigned] : records) {
402
975
    auto pTags = ExifTags::tagList("Canon");
403
975
    if (auto pTag = findTag(pTags, tag)) {
404
975
      auto v = Exiv2::Value::create(bSigned ? Exiv2::signedShort : Exiv2::unsignedShort);
405
975
      std::string s;
406
975
      if (bSigned) {
407
7.74k
        for (uint16_t k = 0; k < size; k++)
408
6.96k
          s += stringFormat(" {}", ints.at(nStart++));
409
780
      } else {
410
507
        for (uint16_t k = 0; k < size; k++)
411
312
          s += stringFormat(" {}", uint.at(nStart++));
412
195
      }
413
414
975
      v->read(s);
415
975
      exifData_[familyGroup + pTag->name_] = *v;
416
975
    }
417
975
  }
418
65
}
419
420
1.58M
void TiffDecoder::decodeTiffEntry(const TiffEntryBase* object) {
421
  // Don't decode the entry if value is not set
422
1.58M
  if (!object->pValue())
423
568k
    return;
424
425
  // skip decoding if decoderFct == 0
426
1.01M
  if (auto decoderFct = findDecoderFct_(make_, object->tag(), object->group()))
427
1.01M
    std::invoke(decoderFct, *this, object);
428
1.01M
}  // TiffDecoder::decodeTiffEntry
429
430
1.01M
void TiffDecoder::decodeStdTiffEntry(const TiffEntryBase* object) {
431
1.01M
  ExifKey key(object->tag(), groupName(object->group()));
432
1.01M
  key.setIdx(object->idx());
433
1.01M
  exifData_.add(key, object->pValue());
434
435
1.01M
}  // TiffDecoder::decodeTiffEntry
436
437
10.1k
void TiffDecoder::visitBinaryArray(TiffBinaryArray* object) {
438
10.1k
  if (!object->cfg() || !object->decoded()) {
439
5.89k
    decodeTiffEntry(object);
440
5.89k
  }
441
10.1k
}
442
443
254k
void TiffDecoder::visitBinaryElement(TiffBinaryElement* object) {
444
254k
  decodeTiffEntry(object);
445
254k
}
446
447
TiffEncoder::TiffEncoder(ExifData exifData, const IptcData& iptcData, const XmpData& xmpData, TiffComponent* pRoot,
448
                         bool isNewImage, PrimaryGroups pPrimaryGroups, const TiffHeaderBase* pHeader,
449
                         FindEncoderFct findEncoderFct) :
450
0
    exifData_(std::move(exifData)),
451
0
    iptcData_(iptcData),
452
0
    xmpData_(xmpData),
453
0
    pHeader_(pHeader),
454
0
    pRoot_(pRoot),
455
0
    isNewImage_(isNewImage),
456
0
    pPrimaryGroups_(std::move(pPrimaryGroups)),
457
0
    byteOrder_(pHeader->byteOrder()),
458
0
    origByteOrder_(byteOrder_),
459
0
    findEncoderFct_(findEncoderFct) {
460
0
  encodeIptc();
461
0
  encodeXmp();
462
463
  // Find camera make
464
0
  ExifKey key("Exif.Image.Make");
465
0
  if (auto pos = exifData_.findKey(key); pos != exifData_.end()) {
466
0
    make_ = pos->toString();
467
0
  }
468
0
  if (make_.empty() && pRoot_) {
469
0
    TiffFinder finder(0x010f, IfdId::ifd0Id);
470
0
    pRoot_->accept(finder);
471
0
    auto te = dynamic_cast<const TiffEntryBase*>(finder.result());
472
0
    if (te && te->pValue()) {
473
0
      make_ = te->pValue()->toString();
474
0
    }
475
0
  }
476
0
}
477
478
0
void TiffEncoder::encodeIptc() {
479
  // Update IPTCNAA Exif tag, if it exists. Delete the tag if there
480
  // is no IPTC data anymore.
481
  // If there is new IPTC data and Exif.Image.ImageResources does
482
  // not exist, create a new IPTCNAA Exif tag.
483
0
  bool del = false;
484
0
  ExifKey iptcNaaKey("Exif.Image.IPTCNAA");
485
0
  auto pos = exifData_.findKey(iptcNaaKey);
486
0
  if (pos != exifData_.end()) {
487
0
    iptcNaaKey.setIdx(pos->idx());
488
0
    exifData_.erase(pos);
489
0
    del = true;
490
0
  }
491
0
  DataBuf rawIptc = IptcParser::encode(iptcData_);
492
0
  ExifKey irbKey("Exif.Image.ImageResources");
493
0
  pos = exifData_.findKey(irbKey);
494
0
  if (pos != exifData_.end()) {
495
0
    irbKey.setIdx(pos->idx());
496
0
  }
497
0
  if (!rawIptc.empty() && (del || pos == exifData_.end())) {
498
0
    auto value = Value::create(unsignedLong);
499
0
    DataBuf buf;
500
0
    if (rawIptc.size() % 4 != 0) {
501
      // Pad the last unsignedLong value with 0s
502
0
      buf.alloc(((rawIptc.size() / 4) * 4) + 4);
503
0
      std::move(rawIptc.begin(), rawIptc.end(), buf.begin());
504
0
    } else {
505
0
      buf = std::move(rawIptc);  // Note: This resets rawIptc
506
0
    }
507
0
    value->read(buf.data(), buf.size(), byteOrder_);
508
0
    Exifdatum iptcDatum(iptcNaaKey, value.get());
509
0
    exifData_.add(iptcDatum);
510
0
    pos = exifData_.findKey(irbKey);  // needed after add()
511
0
  }
512
  // Also update IPTC IRB in Exif.Image.ImageResources if it exists,
513
  // but don't create it if not.
514
0
  if (pos != exifData_.end()) {
515
0
    DataBuf irbBuf(pos->value().size());
516
0
    pos->value().copy(irbBuf.data(), invalidByteOrder);
517
0
    irbBuf = Photoshop::setIptcIrb(irbBuf.c_data(), irbBuf.size(), iptcData_);
518
0
    exifData_.erase(pos);
519
0
    if (!irbBuf.empty()) {
520
0
      auto value = Value::create(unsignedByte);
521
0
      value->read(irbBuf.data(), irbBuf.size(), invalidByteOrder);
522
0
      Exifdatum iptcDatum(irbKey, value.get());
523
0
      exifData_.add(iptcDatum);
524
0
    }
525
0
  }
526
0
}  // TiffEncoder::encodeIptc
527
528
0
void TiffEncoder::encodeXmp() {
529
0
#ifdef EXV_HAVE_XMP_TOOLKIT
530
0
  ExifKey xmpKey("Exif.Image.XMLPacket");
531
  // Remove any existing XMP Exif tag
532
0
  if (auto pos = exifData_.findKey(xmpKey); pos != exifData_.end()) {
533
0
    xmpKey.setIdx(pos->idx());
534
0
    exifData_.erase(pos);
535
0
  }
536
0
  std::string xmpPacket;
537
0
  if (xmpData_.usePacket()) {
538
0
    xmpPacket = xmpData_.xmpPacket();
539
0
  } else {
540
0
    if (XmpParser::encode(xmpPacket, xmpData_) > 1) {
541
0
#ifndef SUPPRESS_WARNINGS
542
0
      EXV_ERROR << "Failed to encode XMP metadata.\n";
543
0
#endif
544
0
    }
545
0
  }
546
0
  if (!xmpPacket.empty()) {
547
    // Set the XMP Exif tag to the new value
548
0
    auto value = Value::create(unsignedByte);
549
0
    value->read(reinterpret_cast<const byte*>(xmpPacket.data()), xmpPacket.size(), invalidByteOrder);
550
0
    Exifdatum xmpDatum(xmpKey, value.get());
551
0
    exifData_.add(xmpDatum);
552
0
  }
553
0
#endif
554
0
}  // TiffEncoder::encodeXmp
555
556
0
void TiffEncoder::setDirty(bool flag) {
557
0
  dirty_ = flag;
558
0
  setGo(geTraverse, !flag);
559
0
}
560
561
0
bool TiffEncoder::dirty() const {
562
0
  return dirty_ || !exifData_.empty();
563
0
}
564
565
0
void TiffEncoder::visitEntry(TiffEntry* object) {
566
0
  encodeTiffComponent(object);
567
0
}
568
569
0
void TiffEncoder::visitDataEntry(TiffDataEntry* object) {
570
0
  encodeTiffComponent(object);
571
0
}
572
573
0
void TiffEncoder::visitImageEntry(TiffImageEntry* object) {
574
0
  encodeTiffComponent(object);
575
0
}
576
577
0
void TiffEncoder::visitSizeEntry(TiffSizeEntry* object) {
578
0
  encodeTiffComponent(object);
579
0
}
580
581
0
void TiffEncoder::visitDirectory(TiffDirectory* /*object*/) {
582
  // Nothing to do
583
0
}
584
585
0
void TiffEncoder::visitDirectoryNext(TiffDirectory* object) {
586
  // Update type and count in IFD entries, in case they changed
587
0
  byte* p = object->start() + 2;
588
0
  for (const auto& component : object->components_) {
589
0
    p += updateDirEntry(p, byteOrder(), component);
590
0
  }
591
0
}
592
593
0
uint32_t TiffEncoder::updateDirEntry(byte* buf, ByteOrder byteOrder, const TiffComponent::SharedPtr& tiffComponent) {
594
0
  auto pTiffEntry = std::dynamic_pointer_cast<TiffEntryBase>(tiffComponent);
595
0
  if (!pTiffEntry)
596
0
    return 0;
597
0
  us2Data(buf + 2, pTiffEntry->tiffType(), byteOrder);
598
0
  ul2Data(buf + 4, static_cast<uint32_t>(pTiffEntry->count()), byteOrder);
599
  // Move data to offset field, if it fits and is not yet there.
600
0
  if (pTiffEntry->size() <= 4 && buf + 8 != pTiffEntry->pData()) {
601
#ifdef EXIV2_DEBUG_MESSAGES
602
    std::cerr << "Copying data for tag " << pTiffEntry->tag() << " to offset area.\n";
603
#endif
604
0
    memset(buf + 8, 0x0, 4);
605
0
    if (pTiffEntry->size() > 0) {
606
0
      std::copy_n(pTiffEntry->pData(), pTiffEntry->size(), buf + 8);
607
0
      memset(const_cast<byte*>(pTiffEntry->pData()), 0x0, pTiffEntry->size());
608
0
    }
609
0
  }
610
0
  return 12;
611
0
}
612
613
0
void TiffEncoder::visitSubIfd(TiffSubIfd* object) {
614
0
  encodeTiffComponent(object);
615
0
}
616
617
0
void TiffEncoder::visitMnEntry(TiffMnEntry* object) {
618
  // Test is required here as well as in the callback encoder function
619
0
  if (!object->mn_) {
620
0
    encodeTiffComponent(object);
621
0
  } else if (del_) {
622
    // The makernote is made up of decoded tags, delete binary tag
623
0
    ExifKey key(object->tag(), groupName(object->group()));
624
0
    auto pos = exifData_.findKey(key);
625
0
    if (pos != exifData_.end())
626
0
      exifData_.erase(pos);
627
0
  }
628
0
}
629
630
0
void TiffEncoder::visitIfdMakernote(TiffIfdMakernote* object) {
631
0
  auto pos = exifData_.findKey(ExifKey("Exif.MakerNote.ByteOrder"));
632
0
  if (pos != exifData_.end()) {
633
    // Set Makernote byte order
634
0
    ByteOrder bo = stringToByteOrder(pos->toString());
635
0
    if (bo != invalidByteOrder && bo != object->byteOrder()) {
636
0
      object->setByteOrder(bo);
637
0
      setDirty();
638
0
    }
639
0
    if (del_)
640
0
      exifData_.erase(pos);
641
0
  }
642
0
  if (del_) {
643
    // Remove remaining synthesized tags
644
0
    for (auto synthesizedTag : {"Exif.MakerNote.Offset"}) {
645
0
      pos = exifData_.findKey(ExifKey(synthesizedTag));
646
0
      if (pos != exifData_.end())
647
0
        exifData_.erase(pos);
648
0
    }
649
0
  }
650
  // Modify encoder for Makernote peculiarities, byte order
651
0
  byteOrder_ = object->byteOrder();
652
653
0
}  // TiffEncoder::visitIfdMakernote
654
655
0
void TiffEncoder::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/) {
656
  // Reset byte order back to that from the c'tor
657
0
  byteOrder_ = origByteOrder_;
658
659
0
}  // TiffEncoder::visitIfdMakernoteEnd
660
661
0
void TiffEncoder::visitBinaryArray(TiffBinaryArray* object) {
662
0
  if (!object->cfg() || !object->decoded()) {
663
0
    encodeTiffComponent(object);
664
0
  }
665
0
}
666
667
0
void TiffEncoder::visitBinaryArrayEnd(TiffBinaryArray* object) {
668
0
  if (!object->cfg() || !object->decoded())
669
0
    return;
670
0
  size_t size = object->TiffEntryBase::doSize();
671
0
  if (size == 0)
672
0
    return;
673
0
  if (!object->initialize(pRoot_))
674
0
    return;
675
676
  // Re-encrypt buffer if necessary
677
0
  CryptFct cryptFct = object->cfg()->cryptFct_;
678
0
  if (cryptFct == &sonyTagDecipher) {
679
0
    cryptFct = sonyTagEncipher;
680
0
  }
681
0
  if (cryptFct) {
682
0
    const byte* pData = object->pData();
683
0
    DataBuf buf = cryptFct(object->tag(), pData, size, pRoot_);
684
0
    if (!buf.empty()) {
685
0
      pData = buf.c_data();
686
0
      size = buf.size();
687
0
    }
688
0
    if (!object->updOrigDataBuf(pData, size)) {
689
0
      setDirty();
690
0
    }
691
0
  }
692
0
}
693
694
0
void TiffEncoder::visitBinaryElement(TiffBinaryElement* object) {
695
  // Temporarily overwrite byte order according to that of the binary element
696
0
  ByteOrder boOrig = byteOrder_;
697
0
  if (object->elByteOrder() != invalidByteOrder)
698
0
    byteOrder_ = object->elByteOrder();
699
0
  encodeTiffComponent(object);
700
0
  byteOrder_ = boOrig;
701
0
}
702
703
0
bool TiffEncoder::isImageTag(uint16_t tag, IfdId group) const {
704
0
  return !isNewImage_ && pHeader_->isImageTag(tag, group, pPrimaryGroups_);
705
0
}
706
707
0
void TiffEncoder::encodeTiffComponent(TiffEntryBase* object, const Exifdatum* datum) {
708
0
  auto pos = exifData_.end();
709
0
  const Exifdatum* ed = datum;
710
0
  if (!ed) {
711
    // Non-intrusive writing: find matching tag
712
0
    ExifKey key(object->tag(), groupName(object->group()));
713
0
    pos = exifData_.findKey(key);
714
0
    if (pos != exifData_.end()) {
715
0
      ed = &(*pos);
716
0
      if (object->idx() != pos->idx()) {
717
        // Try to find exact match (in case of duplicate tags)
718
0
        auto pos2 = std::find_if(exifData_.begin(), exifData_.end(), FindExifdatum2(object->group(), object->idx()));
719
0
        if (pos2 != exifData_.end() && pos2->key() == key.key()) {
720
0
          ed = &(*pos2);
721
0
          pos = pos2;  // make sure we delete the correct tag below
722
0
        }
723
0
      }
724
0
    } else {
725
0
      setDirty();
726
#ifdef EXIV2_DEBUG_MESSAGES
727
      std::cerr << "DELETING          " << key << ", idx = " << object->idx() << "\n";
728
#endif
729
0
    }
730
0
  } else {
731
    // For intrusive writing, the index is used to preserve the order of
732
    // duplicate tags
733
0
    object->idx_ = ed->idx();
734
0
  }
735
  // Skip encoding image tags of existing TIFF image - they were copied earlier -
736
  // but encode image tags of new images (creation)
737
0
  if (ed && !isImageTag(object->tag(), object->group())) {
738
0
    if (auto fct = findEncoderFct_(make_, object->tag(), object->group())) {
739
      // If an encoding function is registered for the tag, use it
740
0
      std::invoke(fct, *this, object, ed);
741
0
    } else {
742
      // Else use the encode function at the object (results in a double-dispatch
743
      // to the appropriate encoding function of the encoder.
744
0
      object->encode(*this, ed);
745
0
    }
746
0
  }
747
0
  if (del_ && pos != exifData_.end()) {
748
0
    exifData_.erase(pos);
749
0
  }
750
#ifdef EXIV2_DEBUG_MESSAGES
751
  std::cerr << "\n";
752
#endif
753
0
}  // TiffEncoder::encodeTiffComponent
754
755
0
void TiffEncoder::encodeBinaryArray(TiffBinaryArray* object, const Exifdatum* datum) {
756
0
  encodeOffsetEntry(object, datum);
757
0
}  // TiffEncoder::encodeBinaryArray
758
759
0
void TiffEncoder::encodeBinaryElement(TiffBinaryElement* object, const Exifdatum* datum) {
760
0
  encodeTiffEntryBase(object, datum);
761
0
}  // TiffEncoder::encodeArrayElement
762
763
0
void TiffEncoder::encodeDataEntry(TiffDataEntry* object, const Exifdatum* datum) {
764
0
  encodeOffsetEntry(object, datum);
765
766
0
  if (!dirty_ && writeMethod() == wmNonIntrusive) {
767
0
    if (object->sizeDataArea_ < object->pValue()->sizeDataArea()) {
768
#ifdef EXIV2_DEBUG_MESSAGES
769
      ExifKey key(object->tag(), groupName(object->group()));
770
      std::cerr << "DATAAREA GREW     " << key << "\n";
771
#endif
772
0
      setDirty();
773
0
    } else {
774
      // Write the new dataarea, fill with 0x0
775
#ifdef EXIV2_DEBUG_MESSAGES
776
      ExifKey key(object->tag(), groupName(object->group()));
777
      std::cerr << "Writing data area for " << key << "\n";
778
#endif
779
0
      DataBuf buf = object->pValue()->dataArea();
780
0
      if (!buf.empty()) {
781
0
        std::copy(buf.begin(), buf.end(), object->pDataArea_);
782
0
        if (object->sizeDataArea_ > buf.size()) {
783
0
          memset(object->pDataArea_ + buf.size(), 0x0, object->sizeDataArea_ - buf.size());
784
0
        }
785
0
      }
786
0
    }
787
0
  }
788
789
0
}  // TiffEncoder::encodeDataEntry
790
791
0
void TiffEncoder::encodeTiffEntry(TiffEntry* object, const Exifdatum* datum) {
792
0
  encodeTiffEntryBase(object, datum);
793
0
}  // TiffEncoder::encodeTiffEntry
794
795
0
void TiffEncoder::encodeImageEntry(TiffImageEntry* object, const Exifdatum* datum) {
796
0
  encodeOffsetEntry(object, datum);
797
798
0
  size_t sizeDataArea = object->pValue()->sizeDataArea();
799
800
0
  if (sizeDataArea > 0 && writeMethod() == wmNonIntrusive) {
801
#ifdef EXIV2_DEBUG_MESSAGES
802
    std::cerr << "\t DATAAREA IS SET (NON-INTRUSIVE WRITING)";
803
#endif
804
0
    setDirty();
805
0
  }
806
807
0
  if (sizeDataArea > 0 && writeMethod() == wmIntrusive) {
808
#ifdef EXIV2_DEBUG_MESSAGES
809
    std::cerr << "\t DATAAREA IS SET (INTRUSIVE WRITING)";
810
#endif
811
    // Set pseudo strips (without a data pointer) from the size tag
812
0
    ExifKey key(object->szTag(), groupName(object->szGroup()));
813
0
    auto pos = exifData_.findKey(key);
814
0
    const byte* zero = nullptr;
815
0
    if (pos == exifData_.end()) {
816
0
#ifndef SUPPRESS_WARNINGS
817
0
      EXV_ERROR << "Size tag " << key << " not found. Writing only one strip.\n";
818
0
#endif
819
0
      object->strips_.clear();
820
0
      object->strips_.emplace_back(zero, sizeDataArea);
821
0
    } else {
822
0
      size_t sizeTotal = 0;
823
0
      object->strips_.clear();
824
0
      for (size_t i = 0; i < pos->count(); ++i) {
825
0
        uint32_t len = pos->toUint32(i);
826
0
        object->strips_.emplace_back(zero, len);
827
0
        sizeTotal += len;
828
0
      }
829
0
      if (sizeTotal != sizeDataArea) {
830
0
#ifndef SUPPRESS_WARNINGS
831
0
        ExifKey key2(object->tag(), groupName(object->group()));
832
0
        EXV_ERROR << "Sum of all sizes of " << key << " != data size of " << key2 << ". "
833
0
                  << "This results in an invalid image.\n";
834
0
#endif
835
        // Todo: How to fix? Write only one strip?
836
0
      }
837
0
    }
838
0
  }
839
840
0
  if (sizeDataArea == 0 && writeMethod() == wmIntrusive) {
841
#ifdef EXIV2_DEBUG_MESSAGES
842
    std::cerr << "\t USE STRIPS FROM SOURCE TREE IMAGE ENTRY";
843
#endif
844
    // Set strips from source tree
845
0
    if (pSourceTree_) {
846
0
      TiffFinder finder(object->tag(), object->group());
847
0
      pSourceTree_->accept(finder);
848
0
      if (auto ti = dynamic_cast<const TiffImageEntry*>(finder.result())) {
849
0
        object->strips_ = ti->strips_;
850
0
      }
851
0
    }
852
0
#ifndef SUPPRESS_WARNINGS
853
0
    else {
854
0
      ExifKey key2(object->tag(), groupName(object->group()));
855
0
      EXV_WARNING << "No image data to encode " << key2 << ".\n";
856
0
    }
857
0
#endif
858
0
  }
859
860
0
}  // TiffEncoder::encodeImageEntry
861
862
0
void TiffEncoder::encodeMnEntry(TiffMnEntry* object, const Exifdatum* datum) {
863
  // Test is required here as well as in the visit function
864
0
  if (!object->mn_)
865
0
    encodeTiffEntryBase(object, datum);
866
0
}  // TiffEncoder::encodeMnEntry
867
868
0
void TiffEncoder::encodeSizeEntry(TiffSizeEntry* object, const Exifdatum* datum) {
869
0
  encodeTiffEntryBase(object, datum);
870
0
}  // TiffEncoder::encodeSizeEntry
871
872
0
void TiffEncoder::encodeSubIfd(TiffSubIfd* object, const Exifdatum* datum) {
873
0
  encodeOffsetEntry(object, datum);
874
0
}  // TiffEncoder::encodeSubIfd
875
876
0
void TiffEncoder::encodeTiffEntryBase(TiffEntryBase* object, const Exifdatum* datum) {
877
#ifdef EXIV2_DEBUG_MESSAGES
878
  bool tooLarge = false;
879
#endif
880
0
  if (datum->size() > object->size_) {  // value doesn't fit, encode for intrusive writing
881
0
    setDirty();
882
#ifdef EXIV2_DEBUG_MESSAGES
883
    tooLarge = true;
884
#endif
885
0
  }
886
0
  object->updateValue(datum->getValue(), byteOrder());  // clones the value
887
#ifdef EXIV2_DEBUG_MESSAGES
888
  ExifKey key(object->tag(), groupName(object->group()));
889
  std::cerr << "UPDATING DATA     " << key;
890
  if (tooLarge) {
891
    std::cerr << "\t\t\t ALLOCATED " << std::dec << object->size_ << " BYTES";
892
  }
893
#endif
894
0
}
895
896
0
void TiffEncoder::encodeOffsetEntry(TiffEntryBase* object, const Exifdatum* datum) {
897
0
  size_t newSize = datum->size();
898
0
  if (newSize > object->size_) {  // value doesn't fit, encode for intrusive writing
899
0
    setDirty();
900
0
    object->updateValue(datum->getValue(), byteOrder());  // clones the value
901
#ifdef EXIV2_DEBUG_MESSAGES
902
    ExifKey key(object->tag(), groupName(object->group()));
903
    std::cerr << "UPDATING DATA     " << key;
904
    std::cerr << "\t\t\t ALLOCATED " << object->size() << " BYTES";
905
#endif
906
0
  } else {
907
0
    object->setValue(datum->getValue());  // clones the value
908
#ifdef EXIV2_DEBUG_MESSAGES
909
    ExifKey key(object->tag(), groupName(object->group()));
910
    std::cerr << "NOT UPDATING      " << key;
911
    std::cerr << "\t\t\t PRESERVE VALUE DATA";
912
#endif
913
0
  }
914
0
}
915
916
0
void TiffEncoder::add(TiffComponent* pRootDir, TiffComponent::UniquePtr pSourceDir, uint32_t root) {
917
0
  writeMethod_ = wmIntrusive;
918
0
  pSourceTree_ = std::move(pSourceDir);
919
920
  // Ensure that the exifData_ entries are not deleted, to be able to
921
  // iterate over all remaining entries.
922
0
  del_ = false;
923
924
0
  auto posBo = exifData_.end();
925
0
  for (auto i = exifData_.begin(); i != exifData_.end(); ++i) {
926
0
    IfdId group = groupId(i->groupName());
927
    // Skip synthesized info tags
928
0
    if (group == IfdId::mnId) {
929
0
      if (i->tag() == 0x0002) {
930
0
        posBo = i;
931
0
      }
932
0
      continue;
933
0
    }
934
935
    // Skip image tags of existing TIFF image - they were copied earlier -
936
    // but add and encode image tags of new images (creation)
937
0
    if (isImageTag(i->tag(), group))
938
0
      continue;
939
940
    // Assumption is that the corresponding TIFF entry doesn't exist
941
0
    auto tiffPath = TiffCreator::getPath(i->tag(), group, root);
942
0
    TiffComponent* tc = pRootDir->addPath(i->tag(), tiffPath, pRootDir);
943
0
    auto object = dynamic_cast<TiffEntryBase*>(tc);
944
#ifdef EXIV2_DEBUG_MESSAGES
945
    if (!object) {
946
      std::cerr << "Warning: addPath() didn't add an entry for " << i->groupName() << " tag 0x" << std::setw(4)
947
                << std::setfill('0') << std::hex << i->tag() << "\n";
948
    }
949
#endif
950
0
    if (object) {
951
0
      encodeTiffComponent(object, &(*i));
952
0
    }
953
0
  }
954
955
  /*
956
    What follows is a hack. I can't think of a better way to set
957
    the makernote byte order (and other properties maybe) in the
958
    makernote header during intrusive writing. The thing is that
959
    visit/encodeIfdMakernote is not called in this case and there
960
    can't be an Exif tag which corresponds to this component.
961
   */
962
0
  if (posBo == exifData_.end())
963
0
    return;
964
965
0
  TiffFinder finder(0x927c, IfdId::exifId);
966
0
  pRootDir->accept(finder);
967
0
  if (auto te = dynamic_cast<const TiffMnEntry*>(finder.result())) {
968
0
    if (const auto& mn = te->mn_) {
969
      // Set Makernote byte order
970
0
      ByteOrder bo = stringToByteOrder(posBo->toString());
971
0
      if (bo != invalidByteOrder)
972
0
        mn->setByteOrder(bo);
973
0
    }
974
0
  }
975
976
0
}  // TiffEncoder::add
977
978
TiffReader::TiffReader(const byte* pData, size_t size, TiffComponent* pRoot, TiffRwState state) :
979
26.2k
    pData_(pData), size_(size), pLast_(pData + size), pRoot_(pRoot), origState_(state), mnState_(state) {
980
26.2k
  pState_ = &origState_;
981
982
26.2k
}  // TiffReader::TiffReader
983
984
27.2k
void TiffReader::setOrigState() {
985
27.2k
  pState_ = &origState_;
986
27.2k
}
987
988
27.2k
void TiffReader::setMnState(const TiffRwState* state) {
989
27.2k
  if (state) {
990
    // invalidByteOrder indicates 'no change'
991
991
    if (state->byteOrder() == invalidByteOrder) {
992
0
      mnState_ = TiffRwState{origState_.byteOrder(), state->baseOffset()};
993
991
    } else {
994
991
      mnState_ = *state;
995
991
    }
996
991
  }
997
27.2k
  pState_ = &mnState_;
998
27.2k
}
999
1000
5.87M
ByteOrder TiffReader::byteOrder() const {
1001
5.87M
  return pState_->byteOrder();
1002
5.87M
}
1003
1004
1.27M
size_t TiffReader::baseOffset() const {
1005
1.27M
  return pState_->baseOffset();
1006
1.27M
}
1007
1008
5.71k
void TiffReader::readDataEntryBase(TiffDataEntryBase* object) {
1009
5.71k
  readTiffEntry(object);
1010
5.71k
  TiffFinder finder(object->szTag(), object->szGroup());
1011
5.71k
  pRoot_->accept(finder);
1012
5.71k
  auto te = dynamic_cast<const TiffEntryBase*>(finder.result());
1013
5.71k
  if (te && te->pValue()) {
1014
1.23k
    object->setStrips(te->pValue(), pData_, size_, baseOffset());
1015
1.23k
  }
1016
5.71k
}
1017
1018
1.29M
void TiffReader::visitEntry(TiffEntry* object) {
1019
1.29M
  readTiffEntry(object);
1020
1.29M
}
1021
1022
1.14k
void TiffReader::visitDataEntry(TiffDataEntry* object) {
1023
1.14k
  readDataEntryBase(object);
1024
1.14k
}
1025
1026
4.57k
void TiffReader::visitImageEntry(TiffImageEntry* object) {
1027
4.57k
  readDataEntryBase(object);
1028
4.57k
}
1029
1030
9.37k
void TiffReader::visitSizeEntry(TiffSizeEntry* object) {
1031
9.37k
  readTiffEntry(object);
1032
9.37k
  TiffFinder finder(object->dtTag(), object->dtGroup());
1033
9.37k
  pRoot_->accept(finder);
1034
9.37k
  auto te = dynamic_cast<TiffDataEntryBase*>(finder.result());
1035
9.37k
  if (te && te->pValue()) {
1036
4.90k
    te->setStrips(object->pValue(), pData_, size_, baseOffset());
1037
4.90k
  }
1038
9.37k
}
1039
1040
43.0k
bool TiffReader::circularReference(const byte* start, IfdId group) {
1041
43.0k
  if (auto pos = dirList_.find(start); pos != dirList_.end()) {
1042
2.35k
#ifndef SUPPRESS_WARNINGS
1043
2.35k
    EXV_ERROR << groupName(group) << " pointer references previously read " << groupName(pos->second)
1044
2.35k
              << " directory; ignored.\n";
1045
2.35k
#endif
1046
2.35k
    return true;
1047
2.35k
  }
1048
40.7k
  dirList_[start] = group;
1049
40.7k
  return false;
1050
43.0k
}
1051
1052
1.02M
int TiffReader::nextIdx(IfdId group) {
1053
1.02M
  return ++idxSeq_[group];
1054
1.02M
}
1055
1056
26.2k
void TiffReader::postProcess() {
1057
26.2k
  setMnState();  // All components to be post-processed must be from the Makernote
1058
26.2k
  postProc_ = true;
1059
26.2k
  for (auto pos : postList_) {
1060
10.1k
    pos->accept(*this);
1061
10.1k
  }
1062
26.2k
  postProc_ = false;
1063
26.2k
  setOrigState();
1064
26.2k
}
1065
1066
43.0k
void TiffReader::visitDirectory(TiffDirectory* object) {
1067
43.0k
  const byte* p = object->start();
1068
1069
43.0k
  if (circularReference(object->start(), object->group()))
1070
2.35k
    return;
1071
1072
40.7k
  if (p + 2 > pLast_) {
1073
3
#ifndef SUPPRESS_WARNINGS
1074
3
    EXV_ERROR << "Directory " << groupName(object->group()) << ": IFD exceeds data buffer, cannot read entry count.\n";
1075
3
#endif
1076
3
    return;
1077
3
  }
1078
40.7k
  const uint16_t n = getUShort(p, byteOrder());
1079
40.7k
  p += 2;
1080
  // Sanity check with an "unreasonably" large number
1081
40.7k
  if (n > 256) {
1082
4.20k
#ifndef SUPPRESS_WARNINGS
1083
4.20k
    EXV_ERROR << "Directory " << groupName(object->group()) << " with " << n
1084
4.20k
              << " entries considered invalid; not read.\n";
1085
4.20k
#endif
1086
4.20k
    return;
1087
4.20k
  }
1088
1.37M
  for (uint16_t i = 0; i < n; ++i) {
1089
1.34M
    if (p + 12 > pLast_) {
1090
8.71k
#ifndef SUPPRESS_WARNINGS
1091
8.71k
      EXV_ERROR << "Directory " << groupName(object->group()) << ": IFD entry " << i
1092
8.71k
                << " lies outside of the data buffer.\n";
1093
8.71k
#endif
1094
8.71k
      return;
1095
8.71k
    }
1096
1.33M
    uint16_t tag = getUShort(p, byteOrder());
1097
1.33M
    if (auto tc = TiffCreator::create(tag, object->group())) {
1098
1.33M
      tc->setStart(p);
1099
1.33M
      object->addChild(std::move(tc));
1100
1.33M
    } else {
1101
347
#ifndef SUPPRESS_WARNINGS
1102
347
      EXV_WARNING << "Unable to handle tag " << tag << ".\n";
1103
347
#endif
1104
347
    }
1105
1.33M
    p += 12;
1106
1.33M
  }
1107
1108
27.7k
  if (object->hasNext()) {
1109
27.7k
    if (p + 4 > pLast_) {
1110
12
#ifndef SUPPRESS_WARNINGS
1111
12
      EXV_ERROR << "Directory " << groupName(object->group())
1112
12
                << ": IFD exceeds data buffer, cannot read next pointer.\n";
1113
12
#endif
1114
12
      return;
1115
12
    }
1116
27.7k
    TiffComponent::UniquePtr tc;
1117
27.7k
    uint32_t next = getULong(p, byteOrder());
1118
27.7k
    if (next) {
1119
18.8k
      tc = TiffCreator::create(Tag::next, object->group());
1120
18.8k
#ifndef SUPPRESS_WARNINGS
1121
18.8k
      if (!tc) {
1122
3.69k
        EXV_WARNING << "Directory " << groupName(object->group()) << " has an unexpected next pointer; ignored.\n";
1123
3.69k
      }
1124
18.8k
#endif
1125
18.8k
    }
1126
27.7k
    if (tc) {
1127
15.1k
      if (next > size_ || baseOffset() > size_ - next) {
1128
10.8k
#ifndef SUPPRESS_WARNINGS
1129
10.8k
        EXV_ERROR << "Directory " << groupName(object->group()) << ": Next pointer is out of bounds; ignored.\n";
1130
10.8k
#endif
1131
10.8k
        return;
1132
10.8k
      }
1133
4.33k
      tc->setStart(pData_ + baseOffset() + next);
1134
4.33k
      object->addNext(std::move(tc));
1135
4.33k
    }
1136
27.7k
  }  // object->hasNext()
1137
1138
27.7k
}  // TiffReader::visitDirectory
1139
1140
10.4k
void TiffReader::visitSubIfd(TiffSubIfd* object) {
1141
10.4k
  readTiffEntry(object);
1142
10.4k
  if ((object->tiffType() == ttUnsignedLong || object->tiffType() == ttSignedLong || object->tiffType() == ttTiffIfd) &&
1143
10.1k
      object->count() >= 1) {
1144
    // Todo: Fix hack
1145
9.78k
    uint32_t maxi = 9;
1146
9.78k
    if (object->group() == IfdId::ifd1Id)
1147
0
      maxi = 1;
1148
21.2k
    for (uint32_t i = 0; i < object->count(); ++i) {
1149
12.6k
      const uint32_t offset = getULong(object->pData() + (4 * i), byteOrder());
1150
12.6k
      if (offset > size_ || baseOffset() > size_ - offset) {
1151
1.00k
#ifndef SUPPRESS_WARNINGS
1152
1.00k
        EXV_ERROR << "Directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0')
1153
1.00k
                  << std::hex << object->tag() << " Sub-IFD pointer " << i << " is out of bounds; ignoring it.\n";
1154
1.00k
#endif
1155
1.00k
        return;
1156
1.00k
      }
1157
11.6k
      if (i >= maxi) {
1158
231
#ifndef SUPPRESS_WARNINGS
1159
231
        EXV_WARNING << "Directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0')
1160
231
                    << std::hex << object->tag() << ": Skipping sub-IFDs beyond the first " << i << ".\n";
1161
231
#endif
1162
231
        break;
1163
231
      }
1164
      // If there are multiple dirs, group is incremented for each
1165
11.4k
      auto td = std::make_unique<TiffDirectory>(object->tag(),
1166
11.4k
                                                static_cast<IfdId>(static_cast<uint32_t>(object->newGroup_) + i));
1167
11.4k
      td->setStart(pData_ + baseOffset() + offset);
1168
11.4k
      object->addChild(std::move(td));
1169
11.4k
    }
1170
9.78k
  }
1171
678
#ifndef SUPPRESS_WARNINGS
1172
678
  else {
1173
678
    EXV_WARNING << "Directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0')
1174
678
                << std::hex << object->tag() << " doesn't look like a sub-IFD.\n";
1175
678
  }
1176
10.4k
#endif
1177
1178
10.4k
}  // TiffReader::visitSubIfd
1179
1180
1.43k
void TiffReader::visitMnEntry(TiffMnEntry* object) {
1181
1.43k
  readTiffEntry(object);
1182
  // Find camera make
1183
1.43k
  TiffFinder finder(0x010f, IfdId::ifd0Id);
1184
1.43k
  pRoot_->accept(finder);
1185
1.43k
  auto te = dynamic_cast<const TiffEntryBase*>(finder.result());
1186
1.43k
  if (te && te->pValue()) {
1187
1.30k
    auto make = te->pValue()->toString();
1188
    // create concrete makernote, based on make and makernote contents
1189
1.30k
    object->mn_ =
1190
1.30k
        TiffMnCreator::create(object->tag(), object->mnGroup_, make, object->pData_, object->size_, byteOrder());
1191
1.30k
  }
1192
1.43k
  if (object->mn_)
1193
999
    object->mn_->setStart(object->pData());
1194
1195
1.43k
}  // TiffReader::visitMnEntry
1196
1197
999
void TiffReader::visitIfdMakernote(TiffIfdMakernote* object) {
1198
999
  object->setImageByteOrder(byteOrder());  // set the byte order for the image
1199
1200
999
  if (!object->readHeader(object->start(), pLast_ - object->start(), byteOrder())) {
1201
8
#ifndef SUPPRESS_WARNINGS
1202
8
    EXV_ERROR << "Failed to read " << groupName(object->ifd_.group()) << " IFD Makernote header.\n";
1203
#ifdef EXIV2_DEBUG_MESSAGES
1204
    if (pLast_ - object->start() >= 16u) {
1205
      hexdump(std::cerr, object->start(), 16u);
1206
    }
1207
#endif  // EXIV2_DEBUG_MESSAGES
1208
8
#endif  // SUPPRESS_WARNINGS
1209
8
    setGo(geKnownMakernote, false);
1210
8
    return;
1211
8
  }
1212
1213
991
  auto start = object->start();
1214
991
  auto offset = object->ifdOffset();
1215
991
  enforce(pData_ <= start, ErrorCode::kerCorruptedMetadata);
1216
991
  enforce(start <= pLast_, ErrorCode::kerCorruptedMetadata);
1217
991
  enforce(offset <= static_cast<size_t>(pLast_ - start), ErrorCode::kerCorruptedMetadata);
1218
991
  object->ifd_.setStart(start + offset);
1219
1220
  // Modify reader for Makernote peculiarities, byte order and offset
1221
991
  object->mnOffset_ = start - pData_;
1222
991
  auto state = TiffRwState{object->byteOrder(), object->baseOffset()};
1223
991
  setMnState(&state);
1224
1225
991
}  // TiffReader::visitIfdMakernote
1226
1227
991
void TiffReader::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/) {
1228
  // Reset state (byte order, create function, offset) back to that for the image
1229
991
  setOrigState();
1230
991
}  // TiffReader::visitIfdMakernoteEnd
1231
1232
1.33M
void TiffReader::readTiffEntry(TiffEntryBase* object) {
1233
1.33M
  try {
1234
1.33M
    byte* p = object->start();
1235
1236
1.33M
    if (p + 12 > pLast_) {
1237
0
#ifndef SUPPRESS_WARNINGS
1238
0
      EXV_ERROR << "Entry in directory " << groupName(object->group())
1239
0
                << "requests access to memory beyond the data buffer. " << "Skipping entry.\n";
1240
0
#endif
1241
0
      return;
1242
0
    }
1243
    // Component already has tag
1244
1.33M
    p += 2;
1245
1.33M
    auto tiffType = static_cast<TiffType>(getUShort(p, byteOrder()));
1246
1.33M
    TypeId typeId = toTypeId(tiffType, object->tag(), object->group());
1247
1.33M
    size_t typeSize = TypeInfo::typeSize(typeId);
1248
1.33M
    if (0 == typeSize) {
1249
904k
#ifndef SUPPRESS_WARNINGS
1250
904k
      EXV_WARNING << stringFormat(
1251
904k
          "Directory {}, entry 0x{:04x} has unknown Exif (TIFF) type {}; setting type size 1.\n",
1252
904k
          groupName(object->group()), object->tag(), static_cast<uint16_t>(tiffType));
1253
904k
#endif
1254
904k
      typeSize = 1;
1255
904k
    }
1256
1.33M
    p += 2;
1257
1.33M
    uint32_t count = getULong(p, byteOrder());
1258
1.33M
    if (count >= 0x10000000) {
1259
568k
#ifndef SUPPRESS_WARNINGS
1260
568k
      EXV_ERROR << stringFormat("Directory {}, entry 0x{:04x} has invalid size {}*{}; skipping entry.\n",
1261
568k
                                groupName(object->group()), object->tag(), count, typeSize);
1262
568k
#endif
1263
568k
      return;
1264
568k
    }
1265
766k
    p += 4;
1266
1267
766k
    if (count > std::numeric_limits<size_t>::max() / typeSize) {
1268
0
      throw Error(ErrorCode::kerArithmeticOverflow);
1269
0
    }
1270
766k
    size_t size = typeSize * count;
1271
766k
    size_t offset = getULong(p, byteOrder());
1272
766k
    byte* pData = p;
1273
766k
    if (size > 4 && Safe::add<size_t>(baseOffset(), offset) >= size_) {
1274
      // #1143
1275
226k
      if (object->tag() == 0x2001 && std::string(groupName(object->group())) == "Sony1") {
1276
        // This tag is Exif.Sony1.PreviewImage, which refers to a preview image which is
1277
        // not stored in the metadata. Instead it is stored at the end of the file, after
1278
        // the main image. The value of `size` refers to the size of the preview image, not
1279
        // the size of the tag's payload, so we set it to zero here so that we don't attempt
1280
        // to read those bytes from the metadata. We currently leave this tag as "undefined",
1281
        // although we may attempt to handle it better in the future. More discussion of
1282
        // this issue can be found here:
1283
        //
1284
        //   https://github.com/Exiv2/exiv2/issues/2001
1285
        //   https://github.com/Exiv2/exiv2/pull/2008
1286
        //   https://github.com/Exiv2/exiv2/pull/2013
1287
0
        typeId = undefined;
1288
0
        size = 0;
1289
226k
      } else {
1290
226k
#ifndef SUPPRESS_WARNINGS
1291
226k
        EXV_ERROR << "Offset of directory " << groupName(object->group()) << ", entry 0x" << std::setw(4)
1292
226k
                  << std::setfill('0') << std::hex << object->tag() << " is out of bounds: " << "Offset = 0x"
1293
226k
                  << std::setw(8) << std::setfill('0') << std::hex << offset << "; truncating the entry\n";
1294
226k
#endif
1295
226k
      }
1296
226k
      size = 0;
1297
226k
    }
1298
766k
    if (size > 4) {
1299
      // setting pData to pData_ + baseOffset() + offset can result in pData pointing to invalid memory,
1300
      // as offset can be arbitrarily large
1301
336k
      if (Safe::add<size_t>(baseOffset(), offset) > static_cast<size_t>(pLast_ - pData_)) {
1302
0
        throw Error(ErrorCode::kerCorruptedMetadata);
1303
0
      }
1304
336k
      pData = const_cast<byte*>(pData_) + baseOffset() + offset;
1305
1306
      // check for size being invalid
1307
336k
      if (size > static_cast<size_t>(pLast_ - pData)) {
1308
71.3k
#ifndef SUPPRESS_WARNINGS
1309
71.3k
        EXV_ERROR << "Upper boundary of data for " << "directory " << groupName(object->group()) << ", entry 0x"
1310
71.3k
                  << std::setw(4) << std::setfill('0') << std::hex << object->tag()
1311
71.3k
                  << " is out of bounds: " << "Offset = 0x" << std::setw(8) << std::setfill('0') << std::hex << offset
1312
71.3k
                  << ", size = " << std::dec << size
1313
71.3k
                  << ", exceeds buffer size by "
1314
                  // cast to make MSVC happy
1315
71.3k
                  << size - static_cast<size_t>(pLast_ - pData) << " Bytes; truncating the entry\n";
1316
71.3k
#endif
1317
71.3k
        size = 0;
1318
71.3k
      }
1319
336k
    }
1320
766k
    auto v = Value::create(typeId);
1321
766k
    enforce(v != nullptr, ErrorCode::kerCorruptedMetadata);
1322
766k
    v->read(pData, size, byteOrder());
1323
1324
766k
    object->setValue(std::move(v));
1325
766k
    auto d = std::make_shared<DataBuf>();
1326
766k
    object->setData(pData, size, std::move(d));
1327
766k
    object->setOffset(offset);
1328
766k
    object->setIdx(nextIdx(object->group()));
1329
766k
  } catch (std::overflow_error&) {
1330
0
    throw Error(ErrorCode::kerCorruptedMetadata);  // #562 don't throw std::overflow_error
1331
0
  }
1332
1.33M
}  // TiffReader::readTiffEntry
1333
1334
20.2k
void TiffReader::visitBinaryArray(TiffBinaryArray* object) {
1335
20.2k
  if (!postProc_) {
1336
    // Defer reading children until after all other components are read, but
1337
    // since state (offset) is not set during post-processing, read entry here
1338
10.1k
    readTiffEntry(object);
1339
10.1k
    object->iniOrigDataBuf();
1340
10.1k
    postList_.push_back(object);
1341
10.1k
    return;
1342
10.1k
  }
1343
  // Check duplicates
1344
10.1k
  TiffFinder finder(object->tag(), object->group());
1345
10.1k
  pRoot_->accept(finder);
1346
10.1k
  if (auto te = dynamic_cast<const TiffEntryBase*>(finder.result())) {
1347
10.1k
    if (te->idx() != object->idx()) {
1348
4.63k
#ifndef SUPPRESS_WARNINGS
1349
4.63k
      EXV_WARNING << "Not decoding duplicate binary array tag 0x" << std::setw(4) << std::setfill('0') << std::hex
1350
4.63k
                  << object->tag() << std::dec << ", group " << groupName(object->group()) << ", idx " << object->idx()
1351
4.63k
                  << "\n";
1352
4.63k
#endif
1353
4.63k
      object->setDecoded(false);
1354
4.63k
      return;
1355
4.63k
    }
1356
10.1k
  }
1357
1358
5.47k
  if (object->TiffEntryBase::doSize() == 0)
1359
1.26k
    return;
1360
4.20k
  if (!object->initialize(pRoot_))
1361
0
    return;
1362
4.20k
  const ArrayCfg* cfg = object->cfg();
1363
4.20k
  if (!cfg)
1364
0
    return;
1365
1366
4.20k
  if (auto cryptFct = cfg->cryptFct_) {
1367
0
    const byte* pData = object->pData();
1368
0
    size_t size = object->TiffEntryBase::doSize();
1369
0
    auto buf = std::make_shared<DataBuf>(cryptFct(object->tag(), pData, size, pRoot_));
1370
0
    if (!buf->empty())
1371
0
      object->setData(std::move(buf));
1372
0
  }
1373
1374
4.20k
  const ArrayDef* defs = object->def();
1375
4.20k
  const ArrayDef* defsEnd = defs + object->defSize();
1376
4.20k
  const ArrayDef* def = &cfg->elDefaultDef_;
1377
4.20k
  ArrayDef gap = *def;
1378
1379
258k
  for (size_t idx = 0; idx < object->TiffEntryBase::doSize();) {
1380
254k
    if (defs) {
1381
54.3k
      def = std::find(defs, defsEnd, idx);
1382
54.3k
      if (def == defsEnd) {
1383
52.9k
        if (cfg->concat_) {
1384
          // Determine gap-size
1385
0
          const ArrayDef* xdef = defs;
1386
0
          for (; xdef != defsEnd && xdef->idx_ <= idx; ++xdef) {
1387
0
          }
1388
0
          size_t gapSize = 0;
1389
0
          if (xdef != defsEnd && xdef->idx_ > idx) {
1390
0
            gapSize = xdef->idx_ - idx;
1391
0
          } else {
1392
0
            gapSize = object->TiffEntryBase::doSize() - idx;
1393
0
          }
1394
0
          gap.idx_ = idx;
1395
0
          gap.tiffType_ = cfg->elDefaultDef_.tiffType_;
1396
0
          gap.count_ = gapSize / cfg->tagStep();
1397
0
          if (gap.count_ * cfg->tagStep() != gapSize) {
1398
0
            gap.tiffType_ = ttUndefined;
1399
0
            gap.count_ = gapSize;
1400
0
          }
1401
0
          def = &gap;
1402
52.9k
        } else {
1403
52.9k
          def = &cfg->elDefaultDef_;
1404
52.9k
        }
1405
52.9k
      }
1406
54.3k
    }
1407
254k
    idx += object->addElement(idx, *def);  // idx may be different from def->idx_
1408
254k
  }
1409
1410
4.20k
}  // TiffReader::visitBinaryArray
1411
1412
254k
void TiffReader::visitBinaryElement(TiffBinaryElement* object) {
1413
254k
  auto pData = object->start();
1414
254k
  size_t size = object->TiffEntryBase::doSize();
1415
254k
  ByteOrder bo = object->elByteOrder();
1416
254k
  if (bo == invalidByteOrder)
1417
252k
    bo = byteOrder();
1418
254k
  TypeId typeId = toTypeId(object->elDef()->tiffType_, object->tag(), object->group());
1419
254k
  auto v = Value::create(typeId);
1420
254k
  enforce(v != nullptr, ErrorCode::kerCorruptedMetadata);
1421
254k
  v->read(pData, size, bo);
1422
1423
254k
  object->setValue(std::move(v));
1424
254k
  object->setOffset(0);
1425
254k
  object->setIdx(nextIdx(object->group()));
1426
254k
}
1427
1428
}  // namespace Exiv2::Internal