Coverage Report

Created: 2026-04-29 07:00

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