Coverage Report

Created: 2026-08-11 07:29

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