Coverage Report

Created: 2026-03-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/exiv2/src/makernote_int.cpp
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
  File:      makernote.cpp
4
  Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
5
  History:   11-Apr-06, ahu: created
6
 */
7
// included header files
8
#include "makernote_int.hpp"
9
#include "config.h"
10
#include "safe_op.hpp"
11
#include "tags.hpp"
12
#include "tiffcomposite_int.hpp"
13
#include "tiffimage_int.hpp"
14
#include "tiffvisitor_int.hpp"
15
#include "utils.hpp"
16
#include "value.hpp"
17
18
// + standard includes
19
#include <cstring>
20
#include <iostream>
21
22
#ifdef EXV_ENABLE_FILESYSTEM
23
#include <filesystem>
24
namespace fs = std::filesystem;
25
26
#ifndef _WIN32
27
#include <pwd.h>
28
#include <unistd.h>
29
#else
30
#include <process.h>
31
#include <shlobj.h>
32
#endif
33
34
#ifdef EXV_ENABLE_INIH
35
#include <INIReader.h>
36
#endif
37
38
#endif
39
40
// *****************************************************************************
41
namespace {
42
// Todo: Can be generalized further - get any tag as a string/long/...
43
//! Get the Value for a tag within a particular group
44
const Exiv2::Value* getExifValue(Exiv2::Internal::TiffComponent* pRoot, uint16_t tag, Exiv2::IfdId group);
45
//! Get the model name from tag Exif.Image.Model
46
std::string getExifModel(Exiv2::Internal::TiffComponent* pRoot);
47
48
//! Nikon en/decryption function
49
void ncrypt(Exiv2::byte* pData, uint32_t size, uint32_t count, uint32_t serial);
50
}  // namespace
51
52
// *****************************************************************************
53
// class member definitions
54
namespace Exiv2::Internal {
55
// Function first looks for a config file in current working directory
56
// on Win the file should be named "exiv2.ini"
57
// on Lin the file should be named ".exiv2"
58
// If not found in cwd, we return the default path
59
// which is the user profile path on win and the home dir on linux
60
0
std::string getExiv2ConfigPath() {
61
0
#ifdef EXV_ENABLE_FILESYSTEM
62
#ifdef _WIN32
63
  std::string inifile("exiv2.ini");
64
#else
65
0
  std::string inifile(".exiv2");
66
0
#endif
67
0
  auto currentPath = fs::current_path();
68
0
  auto iniPath = currentPath / inifile;
69
0
  if (fs::exists(iniPath)) {
70
0
    return iniPath.string();
71
0
  }
72
73
#ifdef _WIN32
74
  PWSTR buffer = nullptr;
75
  if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &buffer))) {
76
    currentPath = buffer;
77
    CoTaskMemFree(buffer);
78
  }
79
#else
80
0
  auto pw = getpwuid(getuid());
81
0
  currentPath = std::string(pw ? pw->pw_dir : "");
82
0
#endif
83
0
  return (currentPath / inifile).string();
84
#else
85
  return "";
86
#endif
87
0
}
88
89
std::string readExiv2Config([[maybe_unused]] const std::string& section, [[maybe_unused]] const std::string& value,
90
0
                            const std::string& def) {
91
0
  std::string result = def;
92
93
#if defined(EXV_ENABLE_INIH) && defined(EXV_ENABLE_FILESYSTEM)
94
  INIReader reader(Exiv2::Internal::getExiv2ConfigPath());
95
  if (reader.ParseError() == 0) {
96
    result = reader.Get(section, value, def);
97
  }
98
#endif
99
100
0
  return result;
101
0
}
102
103
const TiffMnRegistry TiffMnCreator::registry_[] = {
104
    {"Canon", IfdId::canonId, newIfdMn, newIfdMn2},
105
    {"FOVEON", IfdId::sigmaId, newSigmaMn, newSigmaMn2},
106
    {"FUJI", IfdId::fujiId, newFujiMn, newFujiMn2},
107
    {"KONICA MINOLTA", IfdId::minoltaId, newIfdMn, newIfdMn2},
108
    {"Minolta", IfdId::minoltaId, newIfdMn, newIfdMn2},
109
    {"NIKON", IfdId::ifdIdNotSet, newNikonMn, nullptr},      // mnGroup_ is not used
110
    {"OLYMPUS", IfdId::ifdIdNotSet, newOlympusMn, nullptr},  // mnGroup_ is not used
111
    {"OM Digital", IfdId::olympus2Id, newOMSystemMn, newOMSystemMn2},
112
    {"Panasonic", IfdId::panasonicId, newPanasonicMn, newPanasonicMn2},
113
    {"PENTAX", IfdId::ifdIdNotSet, newPentaxMn, nullptr},  // mnGroup_ is not used
114
    {"RICOH", IfdId::ifdIdNotSet, newPentaxMn, nullptr},   // mnGroup_ is not used
115
    {"SAMSUNG", IfdId::samsung2Id, newSamsungMn, newSamsungMn2},
116
    {"SIGMA", IfdId::sigmaId, newSigmaMn, newSigmaMn2},
117
    {"SONY", IfdId::ifdIdNotSet, newSonyMn, nullptr},    // mnGroup_ is not used
118
    {"CASIO", IfdId::ifdIdNotSet, newCasioMn, nullptr},  // mnGroup_ is not used
119
    // Entries below are only used for lookup by group
120
    {"-", IfdId::nikon1Id, nullptr, newIfdMn2},
121
    {"-", IfdId::nikon2Id, nullptr, newNikon2Mn2},
122
    {"-", IfdId::nikon3Id, nullptr, newNikon3Mn2},
123
    {"-", IfdId::sony1Id, nullptr, newSony1Mn2},
124
    {"-", IfdId::sony2Id, nullptr, newSony2Mn2},
125
    {"-", IfdId::olympusId, nullptr, newOlympusMn2},
126
    {"-", IfdId::olympus2Id, nullptr, newOlympus2Mn2},
127
    {"-", IfdId::pentaxId, nullptr, newPentaxMn2},
128
    {"-", IfdId::pentaxDngId, nullptr, newPentaxDngMn2},
129
    {"-", IfdId::casioId, nullptr, newIfdMn2},
130
    {"-", IfdId::casio2Id, nullptr, newCasio2Mn2},
131
};
132
133
21.0k
bool TiffMnRegistry::operator==(std::string_view key) const {
134
21.0k
  if (!key.empty() && key.front() == '-')
135
0
    return false;
136
21.0k
  return key.starts_with(make_);
137
21.0k
}
138
139
0
bool TiffMnRegistry::operator==(IfdId key) const {
140
0
  return mnGroup_ == key;
141
0
}
142
143
std::unique_ptr<TiffIfdMakernote> TiffMnCreator::create(uint16_t tag, IfdId group, std::string_view make,
144
1.39k
                                                        const byte* pData, size_t size, ByteOrder byteOrder) {
145
1.39k
  if (auto tmr = Exiv2::find(registry_, make))
146
686
    return tmr->newMnFct_(tag, group, tmr->mnGroup_, pData, size, byteOrder);
147
707
  return nullptr;
148
1.39k
}  // TiffMnCreator::create
149
150
0
std::unique_ptr<TiffIfdMakernote> TiffMnCreator::create(uint16_t tag, IfdId group, IfdId mnGroup) {
151
0
  if (auto tmr = Exiv2::find(registry_, mnGroup)) {
152
0
    if (tmr->newMnFct2_) {
153
0
      return tmr->newMnFct2_(tag, group, mnGroup);
154
0
    }
155
0
    std::cout << "mnGroup = " << mnGroup << "\n";
156
0
  }
157
0
  return nullptr;
158
0
}  // TiffMnCreator::create
159
160
0
void MnHeader::setByteOrder(ByteOrder) {
161
0
}
162
163
0
size_t MnHeader::ifdOffset() const {
164
0
  return 0;
165
0
}
166
167
52
ByteOrder MnHeader::byteOrder() const {
168
52
  return invalidByteOrder;
169
52
}
170
171
24
size_t MnHeader::baseOffset(size_t /*mnOffset*/) const {
172
24
  return 0;
173
24
}
174
175
const byte OlympusMnHeader::signature_[] = {'O', 'L', 'Y', 'M', 'P', 0x00, 0x01, 0x00};
176
177
100
size_t OlympusMnHeader::sizeOfSignature() {
178
100
  return sizeof(signature_);
179
100
}
180
181
11
OlympusMnHeader::OlympusMnHeader() {
182
11
  read(signature_, sizeOfSignature(), invalidByteOrder);
183
11
}
184
185
0
size_t OlympusMnHeader::size() const {
186
0
  return header_.size();
187
0
}
188
189
0
size_t OlympusMnHeader::ifdOffset() const {
190
0
  return sizeOfSignature();
191
0
}
192
193
22
bool OlympusMnHeader::read(const byte* pData, size_t size, ByteOrder) {
194
22
  if (!pData || size < sizeOfSignature())
195
0
    return false;
196
22
  header_.alloc(sizeOfSignature());
197
22
  std::copy_n(pData, header_.size(), header_.begin());
198
22
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, 6);
199
22
}
200
201
0
size_t OlympusMnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
202
0
  ioWrapper.write(signature_, sizeOfSignature());
203
0
  return sizeOfSignature();
204
0
}  // OlympusMnHeader::write
205
206
const byte Olympus2MnHeader::signature_[] = {'O', 'L', 'Y', 'M', 'P', 'U', 'S', 0x00, 'I', 'I', 0x03, 0x00};
207
208
0
size_t Olympus2MnHeader::sizeOfSignature() {
209
0
  return sizeof(signature_);
210
0
}
211
212
0
Olympus2MnHeader::Olympus2MnHeader() {
213
0
  read(signature_, sizeOfSignature(), invalidByteOrder);
214
0
}
215
216
0
size_t Olympus2MnHeader::size() const {
217
0
  return header_.size();
218
0
}
219
220
0
size_t Olympus2MnHeader::ifdOffset() const {
221
0
  return sizeOfSignature();
222
0
}
223
224
0
size_t Olympus2MnHeader::baseOffset(size_t mnOffset) const {
225
0
  return mnOffset;
226
0
}
227
228
0
bool Olympus2MnHeader::read(const byte* pData, size_t size, ByteOrder) {
229
0
  if (!pData || size < sizeOfSignature())
230
0
    return false;
231
0
  header_.alloc(sizeOfSignature());
232
0
  std::copy_n(pData, header_.size(), header_.begin());
233
0
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, 10);
234
0
}
235
236
0
size_t Olympus2MnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
237
0
  ioWrapper.write(signature_, sizeOfSignature());
238
0
  return sizeOfSignature();
239
0
}  // Olympus2MnHeader::write
240
241
const byte OMSystemMnHeader::signature_[] = {'O', 'M',  ' ',  'S',  'Y', 'S', 'T',  'E',
242
                                             'M', 0x00, 0x00, 0x00, 'I', 'I', 0x04, 0x00};
243
244
22
size_t OMSystemMnHeader::sizeOfSignature() {
245
22
  return sizeof(signature_);
246
22
}
247
248
2
OMSystemMnHeader::OMSystemMnHeader() {
249
2
  read(signature_, sizeOfSignature(), invalidByteOrder);
250
2
}
251
252
0
size_t OMSystemMnHeader::size() const {
253
0
  return header_.size();
254
0
}
255
256
2
size_t OMSystemMnHeader::ifdOffset() const {
257
2
  return sizeOfSignature();
258
2
}
259
260
2
size_t OMSystemMnHeader::baseOffset(size_t mnOffset) const {
261
2
  return mnOffset;
262
2
}
263
264
4
bool OMSystemMnHeader::read(const byte* pData, size_t size, ByteOrder) {
265
4
  if (!pData || size < sizeOfSignature())
266
0
    return false;
267
4
  header_.alloc(sizeOfSignature());
268
4
  std::copy_n(pData, header_.size(), header_.begin());
269
4
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, sizeOfSignature() - 2);
270
4
}
271
272
0
size_t OMSystemMnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
273
0
  ioWrapper.write(signature_, sizeOfSignature());
274
0
  return sizeOfSignature();
275
0
}  // OMSystemMnHeader::write
276
277
const byte FujiMnHeader::signature_[] = {'F', 'U', 'J', 'I', 'F', 'I', 'L', 'M', 0x0c, 0x00, 0x00, 0x00};
278
const ByteOrder FujiMnHeader::byteOrder_ = littleEndian;
279
280
441
size_t FujiMnHeader::sizeOfSignature() {
281
441
  return sizeof(signature_);
282
441
}
283
284
53
FujiMnHeader::FujiMnHeader() {
285
53
  read(signature_, sizeOfSignature(), byteOrder_);
286
53
}
287
288
0
size_t FujiMnHeader::size() const {
289
0
  return header_.size();
290
0
}
291
292
28
size_t FujiMnHeader::ifdOffset() const {
293
28
  return start_;
294
28
}
295
296
112
ByteOrder FujiMnHeader::byteOrder() const {
297
112
  return byteOrder_;
298
112
}
299
300
28
size_t FujiMnHeader::baseOffset(size_t mnOffset) const {
301
28
  return mnOffset;
302
28
}
303
304
106
bool FujiMnHeader::read(const byte* pData, size_t size, ByteOrder) {
305
106
  if (!pData || size < sizeOfSignature())
306
0
    return false;
307
106
  header_.alloc(sizeOfSignature());
308
106
  std::copy_n(pData, header_.size(), header_.begin());
309
  // Read offset to the IFD relative to the start of the makernote
310
  // from the header. Note that we ignore the byteOrder argument
311
106
  start_ = header_.read_uint32(8, byteOrder_);
312
106
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, 8);
313
106
}
314
315
0
size_t FujiMnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
316
0
  ioWrapper.write(signature_, sizeOfSignature());
317
0
  return sizeOfSignature();
318
0
}  // FujiMnHeader::write
319
320
const byte Nikon2MnHeader::signature_[] = {'N', 'i', 'k', 'o', 'n', '\0', 0x01, 0x00};
321
322
0
size_t Nikon2MnHeader::sizeOfSignature() {
323
0
  return sizeof(signature_);
324
0
}
325
326
0
Nikon2MnHeader::Nikon2MnHeader() {
327
0
  read(signature_, sizeOfSignature(), invalidByteOrder);
328
0
}
329
330
0
size_t Nikon2MnHeader::size() const {
331
0
  return sizeOfSignature();
332
0
}
333
334
0
size_t Nikon2MnHeader::ifdOffset() const {
335
0
  return start_;
336
0
}
337
338
0
bool Nikon2MnHeader::read(const byte* pData, size_t size, ByteOrder) {
339
0
  if (!pData || size < sizeOfSignature())
340
0
    return false;
341
0
  if (0 != memcmp(pData, signature_, 6))
342
0
    return false;
343
0
  buf_.alloc(sizeOfSignature());
344
0
  std::copy_n(pData, buf_.size(), buf_.begin());
345
0
  start_ = sizeOfSignature();
346
0
  return true;
347
0
}  // Nikon2MnHeader::read
348
349
0
size_t Nikon2MnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
350
0
  ioWrapper.write(signature_, sizeOfSignature());
351
0
  return sizeOfSignature();
352
0
}  // Nikon2MnHeader::write
353
354
const byte Nikon3MnHeader::signature_[] = {'N',  'i',  'k',  'o',  'n',  '\0', 0x02, 0x10, 0x00,
355
                                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
356
357
15
size_t Nikon3MnHeader::sizeOfSignature() {
358
15
  return sizeof(signature_);
359
15
}
360
361
3
Nikon3MnHeader::Nikon3MnHeader() : start_(sizeOfSignature()) {
362
3
  buf_.alloc(sizeOfSignature());
363
3
  std::copy_n(signature_, buf_.size(), buf_.begin());
364
3
}
365
366
0
size_t Nikon3MnHeader::size() const {
367
0
  return sizeOfSignature();
368
0
}
369
370
3
size_t Nikon3MnHeader::ifdOffset() const {
371
3
  return start_;
372
3
}
373
374
12
ByteOrder Nikon3MnHeader::byteOrder() const {
375
12
  return byteOrder_;
376
12
}
377
378
3
size_t Nikon3MnHeader::baseOffset(size_t mnOffset) const {
379
3
  return Safe::add<size_t>(mnOffset, 10);
380
3
}
381
382
3
bool Nikon3MnHeader::read(const byte* pData, size_t size, ByteOrder) {
383
3
  if (!pData || size < sizeOfSignature())
384
0
    return false;
385
3
  if (0 != memcmp(pData, signature_, 6))
386
0
    return false;
387
3
  buf_.alloc(sizeOfSignature());
388
3
  std::copy_n(pData, buf_.size(), buf_.begin());
389
3
  TiffHeader th;
390
3
  if (!th.read(buf_.data(10), 8))
391
0
    return false;
392
3
  byteOrder_ = th.byteOrder();
393
3
  start_ = 10 + th.offset();
394
3
  return true;
395
3
}  // Nikon3MnHeader::read
396
397
0
size_t Nikon3MnHeader::write(IoWrapper& ioWrapper, ByteOrder byteOrder) const {
398
0
  ioWrapper.write(buf_.c_data(), 10);
399
  /// \todo: This removes any gap between the header and makernote IFD. The gap should be copied too.
400
0
  TiffHeader th(byteOrder);
401
0
  DataBuf buf = th.write();
402
0
  ioWrapper.write(buf.c_data(), buf.size());
403
0
  return 10 + buf.size();
404
0
}
405
406
0
void Nikon3MnHeader::setByteOrder(ByteOrder byteOrder) {
407
0
  byteOrder_ = byteOrder;
408
0
}
409
410
const byte PanasonicMnHeader::signature_[] = {'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0x00, 0x00, 0x00};
411
412
286
size_t PanasonicMnHeader::sizeOfSignature() {
413
286
  return sizeof(signature_);
414
286
}
415
416
38
PanasonicMnHeader::PanasonicMnHeader() {
417
38
  read(signature_, sizeOfSignature(), invalidByteOrder);
418
38
}
419
420
0
size_t PanasonicMnHeader::size() const {
421
0
  return sizeOfSignature();
422
0
}
423
424
24
size_t PanasonicMnHeader::ifdOffset() const {
425
24
  return start_;
426
24
}
427
428
76
bool PanasonicMnHeader::read(const byte* pData, size_t size, ByteOrder) {
429
76
  if (!pData || size < sizeOfSignature())
430
0
    return false;
431
76
  if (0 != memcmp(pData, signature_, 9))
432
14
    return false;
433
62
  buf_.alloc(sizeOfSignature());
434
62
  std::copy_n(pData, buf_.size(), buf_.begin());
435
62
  start_ = sizeOfSignature();
436
62
  return true;
437
76
}  // PanasonicMnHeader::read
438
439
0
size_t PanasonicMnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
440
0
  ioWrapper.write(signature_, sizeOfSignature());
441
0
  return sizeOfSignature();
442
0
}  // PanasonicMnHeader::write
443
444
const byte PentaxDngMnHeader::signature_[] = {'P', 'E', 'N', 'T', 'A', 'X', ' ', 0x00, 'M', 'M'};
445
446
0
size_t PentaxDngMnHeader::sizeOfSignature() {
447
0
  return sizeof(signature_);
448
0
}
449
450
0
PentaxDngMnHeader::PentaxDngMnHeader() {
451
0
  read(signature_, sizeOfSignature(), invalidByteOrder);
452
0
}
453
454
0
size_t PentaxDngMnHeader::size() const {
455
0
  return header_.size();
456
0
}
457
458
0
size_t PentaxDngMnHeader::baseOffset(size_t mnOffset) const {
459
0
  return mnOffset;
460
0
}
461
462
0
size_t PentaxDngMnHeader::ifdOffset() const {
463
0
  return sizeOfSignature();
464
0
}
465
466
0
bool PentaxDngMnHeader::read(const byte* pData, size_t size, ByteOrder) {
467
0
  if (!pData || size < sizeOfSignature())
468
0
    return false;
469
0
  header_.alloc(sizeOfSignature());
470
0
  std::copy_n(pData, header_.size(), header_.begin());
471
0
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, 7);
472
0
}
473
474
0
size_t PentaxDngMnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
475
0
  ioWrapper.write(signature_, sizeOfSignature());
476
0
  return sizeOfSignature();
477
0
}  // PentaxDngMnHeader::write
478
479
const byte PentaxMnHeader::signature_[] = {'A', 'O', 'C', 0x00, 'M', 'M'};
480
481
0
size_t PentaxMnHeader::sizeOfSignature() {
482
0
  return sizeof(signature_);
483
0
}
484
485
0
PentaxMnHeader::PentaxMnHeader() {
486
0
  read(signature_, sizeOfSignature(), invalidByteOrder);
487
0
}
488
489
0
size_t PentaxMnHeader::size() const {
490
0
  return header_.size();
491
0
}
492
493
0
size_t PentaxMnHeader::ifdOffset() const {
494
0
  return sizeOfSignature();
495
0
}
496
497
0
bool PentaxMnHeader::read(const byte* pData, size_t size, ByteOrder) {
498
0
  if (!pData || size < sizeOfSignature())
499
0
    return false;
500
0
  header_.alloc(sizeOfSignature());
501
0
  std::copy_n(pData, header_.size(), header_.begin());
502
0
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, 3);
503
0
}
504
505
0
size_t PentaxMnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
506
0
  ioWrapper.write(signature_, sizeOfSignature());
507
0
  return sizeOfSignature();
508
0
}
509
510
0
SamsungMnHeader::SamsungMnHeader() {
511
0
  read(nullptr, 0, invalidByteOrder);
512
0
}
513
514
0
size_t SamsungMnHeader::size() const {
515
0
  return 0;
516
0
}
517
518
0
size_t SamsungMnHeader::baseOffset(size_t mnOffset) const {
519
0
  return mnOffset;
520
0
}
521
522
0
bool SamsungMnHeader::read(const byte* /*pData*/, size_t /*size*/, ByteOrder) {
523
0
  return true;
524
0
}  // SamsungMnHeader::read
525
526
0
size_t SamsungMnHeader::write(IoWrapper& /*ioWrapper*/, ByteOrder) const {
527
0
  return 0;
528
0
}  // SamsungMnHeader::write
529
530
const byte SigmaMnHeader::signature1_[] = {'S', 'I', 'G', 'M', 'A', '\0', '\0', '\0', 0x01, 0x00};
531
const byte SigmaMnHeader::signature2_[] = {'F', 'O', 'V', 'E', 'O', 'N', '\0', '\0', 0x01, 0x00};
532
533
67
size_t SigmaMnHeader::sizeOfSignature() {
534
67
  return sizeof(signature1_);
535
67
}
536
537
10
SigmaMnHeader::SigmaMnHeader() {
538
10
  read(signature1_, sizeOfSignature(), invalidByteOrder);
539
10
}
540
541
0
size_t SigmaMnHeader::size() const {
542
0
  return sizeOfSignature();
543
0
}
544
545
0
size_t SigmaMnHeader::ifdOffset() const {
546
0
  return start_;
547
0
}
548
549
20
bool SigmaMnHeader::read(const byte* pData, size_t size, ByteOrder) {
550
20
  if (!pData || size < sizeOfSignature())
551
0
    return false;
552
20
  if (0 != memcmp(pData, signature1_, 8) && 0 != memcmp(pData, signature2_, 8))
553
10
    return false;
554
10
  buf_.alloc(sizeOfSignature());
555
10
  std::copy_n(pData, buf_.size(), buf_.begin());
556
10
  start_ = sizeOfSignature();
557
10
  return true;
558
20
}  // SigmaMnHeader::read
559
560
0
size_t SigmaMnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
561
0
  ioWrapper.write(signature1_, sizeOfSignature());
562
0
  return sizeOfSignature();
563
0
}  // SigmaMnHeader::write
564
565
const byte SonyMnHeader::signature_[] = {'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', '\0', '\0', '\0'};
566
567
0
size_t SonyMnHeader::sizeOfSignature() {
568
0
  return sizeof(signature_);
569
0
}
570
571
0
SonyMnHeader::SonyMnHeader() {
572
0
  read(signature_, sizeOfSignature(), invalidByteOrder);
573
0
}
574
575
0
size_t SonyMnHeader::size() const {
576
0
  return sizeOfSignature();
577
0
}
578
579
0
size_t SonyMnHeader::ifdOffset() const {
580
0
  return start_;
581
0
}
582
583
0
bool SonyMnHeader::read(const byte* pData, size_t size, ByteOrder) {
584
0
  if (!pData || size < sizeOfSignature())
585
0
    return false;
586
0
  if (0 != memcmp(pData, signature_, sizeOfSignature()))
587
0
    return false;
588
0
  buf_.alloc(sizeOfSignature());
589
0
  std::copy_n(pData, buf_.size(), buf_.begin());
590
0
  start_ = sizeOfSignature();
591
0
  return true;
592
0
}  // SonyMnHeader::read
593
594
0
size_t SonyMnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
595
0
  ioWrapper.write(signature_, sizeOfSignature());
596
0
  return sizeOfSignature();
597
0
}  // SonyMnHeader::write
598
599
const byte Casio2MnHeader::signature_[] = {'Q', 'V', 'C', '\0', '\0', '\0'};
600
const ByteOrder Casio2MnHeader::byteOrder_ = bigEndian;
601
602
0
size_t Casio2MnHeader::sizeOfSignature() {
603
0
  return sizeof(signature_);
604
0
}
605
606
0
Casio2MnHeader::Casio2MnHeader() {
607
0
  read(signature_, sizeOfSignature(), invalidByteOrder);
608
0
}
609
610
0
size_t Casio2MnHeader::size() const {
611
0
  return sizeOfSignature();
612
0
}
613
614
0
size_t Casio2MnHeader::ifdOffset() const {
615
0
  return start_;
616
0
}
617
618
0
ByteOrder Casio2MnHeader::byteOrder() const {
619
0
  return byteOrder_;
620
0
}
621
622
0
bool Casio2MnHeader::read(const byte* pData, size_t size, ByteOrder) {
623
0
  if (!pData || size < sizeOfSignature())
624
0
    return false;
625
0
  if (0 != memcmp(pData, signature_, sizeOfSignature()))
626
0
    return false;
627
0
  buf_.alloc(sizeOfSignature());
628
0
  std::copy_n(pData, buf_.size(), buf_.begin());
629
0
  start_ = sizeOfSignature();
630
0
  return true;
631
0
}  // Casio2MnHeader::read
632
633
0
size_t Casio2MnHeader::write(IoWrapper& ioWrapper, ByteOrder) const {
634
0
  ioWrapper.write(signature_, sizeOfSignature());
635
0
  return sizeOfSignature();
636
0
}  // Casio2MnHeader::write
637
638
// *************************************************************************
639
// free functions
640
641
std::unique_ptr<TiffIfdMakernote> newIfdMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
642
451
                                           ByteOrder) {
643
  // Require at least an IFD with 1 entry, but not necessarily a next pointer
644
451
  if (size < 14)
645
40
    return nullptr;
646
411
  return newIfdMn2(tag, group, mnGroup);
647
451
}
648
649
411
std::unique_ptr<TiffIfdMakernote> newIfdMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
650
411
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, nullptr);
651
411
}
652
653
std::unique_ptr<TiffIfdMakernote> newOlympusMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
654
25
                                               ByteOrder) {
655
  // FIXME: workaround for overwritten OM System header in Olympus files (https://github.com/Exiv2/exiv2/issues/2542)
656
25
  if (size >= 14 && std::string(reinterpret_cast<const char*>(pData), 14) == std::string("OM SYSTEM\0\0\0II", 14)) {
657
    // Require at least the header and an IFD with 1 entry
658
2
    if (size < OMSystemMnHeader::sizeOfSignature() + 18)
659
0
      return nullptr;
660
2
    return newOMSystemMn2(tag, group, IfdId::olympus2Id);
661
2
  }
662
23
  if (size < 10 || std::string(reinterpret_cast<const char*>(pData), 10) != std::string("OLYMPUS\0II", 10)) {
663
    // Require at least the header and an IFD with 1 entry
664
23
    if (size < OlympusMnHeader::sizeOfSignature() + 18)
665
12
      return nullptr;
666
11
    return newOlympusMn2(tag, group, IfdId::olympusId);
667
23
  }
668
  // Require at least the header and an IFD with 1 entry
669
0
  if (size < Olympus2MnHeader::sizeOfSignature() + 18)
670
0
    return nullptr;
671
0
  return newOlympus2Mn2(tag, group, IfdId::olympus2Id);
672
0
}
673
674
11
std::unique_ptr<TiffIfdMakernote> newOlympusMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
675
11
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<OlympusMnHeader>());
676
11
}
677
678
0
std::unique_ptr<TiffIfdMakernote> newOlympus2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
679
0
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<Olympus2MnHeader>());
680
0
}
681
682
std::unique_ptr<TiffIfdMakernote> newOMSystemMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
683
0
                                                ByteOrder) {
684
  // Require at least the header and an IFD with 1 entry
685
0
  if (size < OMSystemMnHeader::sizeOfSignature() + 18)
686
0
    return nullptr;
687
0
  return newOMSystemMn2(tag, group, mnGroup);
688
0
}
689
690
2
std::unique_ptr<TiffIfdMakernote> newOMSystemMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
691
2
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<OMSystemMnHeader>());
692
2
}
693
694
std::unique_ptr<TiffIfdMakernote> newFujiMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
695
70
                                            ByteOrder) {
696
  // Require at least the header and an IFD with 1 entry
697
70
  if (size < FujiMnHeader::sizeOfSignature() + 18)
698
17
    return nullptr;
699
53
  return newFujiMn2(tag, group, mnGroup);
700
70
}
701
702
53
std::unique_ptr<TiffIfdMakernote> newFujiMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
703
53
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<FujiMnHeader>());
704
53
}
705
706
std::unique_ptr<TiffIfdMakernote> newNikonMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
707
9
                                             ByteOrder) {
708
  // If there is no "Nikon" string it must be Nikon1 format
709
9
  if (size < 6 || std::string(reinterpret_cast<const char*>(pData), 6) != std::string("Nikon\0", 6)) {
710
    // Require at least an IFD with 1 entry
711
6
    if (size < 18)
712
6
      return nullptr;
713
0
    return newIfdMn2(tag, group, IfdId::nikon1Id);
714
6
  }
715
  // If the "Nikon" string is not followed by a TIFF header, we assume
716
  // Nikon2 format
717
3
  TiffHeader tiffHeader;
718
3
  if (size < 18 || !tiffHeader.read(pData + 10, size - 10) || tiffHeader.tag() != 0x002a) {
719
    // Require at least the header and an IFD with 1 entry
720
0
    if (size < Nikon2MnHeader::sizeOfSignature() + 18)
721
0
      return nullptr;
722
0
    return newNikon2Mn2(tag, group, IfdId::nikon2Id);
723
0
  }
724
  // Else we have a Nikon3 makernote
725
  // Require at least the header and an IFD with 1 entry
726
3
  if (size < Nikon3MnHeader::sizeOfSignature() + 18)
727
0
    return nullptr;
728
3
  return newNikon3Mn2(tag, group, IfdId::nikon3Id);
729
3
}
730
731
0
std::unique_ptr<TiffIfdMakernote> newNikon2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
732
0
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<Nikon2MnHeader>());
733
0
}
734
735
3
std::unique_ptr<TiffIfdMakernote> newNikon3Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
736
3
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<Nikon3MnHeader>());
737
3
}
738
739
std::unique_ptr<TiffIfdMakernote> newPanasonicMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
740
48
                                                 ByteOrder) {
741
  // Require at least the header and an IFD with 1 entry, but without a next pointer
742
48
  if (size < PanasonicMnHeader::sizeOfSignature() + 14)
743
10
    return nullptr;
744
38
  return newPanasonicMn2(tag, group, mnGroup);
745
48
}
746
747
38
std::unique_ptr<TiffIfdMakernote> newPanasonicMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
748
38
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<PanasonicMnHeader>(), false);
749
38
}
750
751
std::unique_ptr<TiffIfdMakernote> newPentaxMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
752
66
                                              ByteOrder) {
753
66
  if (size > 8 && std::string(reinterpret_cast<const char*>(pData), 8) == std::string("PENTAX \0", 8)) {
754
    // Require at least the header and an IFD with 1 entry
755
0
    if (size < PentaxDngMnHeader::sizeOfSignature() + 18)
756
0
      return nullptr;
757
0
    return newPentaxDngMn2(tag, group, (tag == 0xc634 ? IfdId::pentaxDngId : IfdId::pentaxId));
758
0
  }
759
66
  if (size > 4 && std::string(reinterpret_cast<const char*>(pData), 4) == std::string("AOC\0", 4)) {
760
    // Require at least the header and an IFD with 1 entry
761
0
    if (size < PentaxMnHeader::sizeOfSignature() + 18)
762
0
      return nullptr;
763
0
    return newPentaxMn2(tag, group, IfdId::pentaxId);
764
0
  }
765
66
  return nullptr;
766
66
}
767
768
0
std::unique_ptr<TiffIfdMakernote> newPentaxMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
769
0
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<PentaxMnHeader>());
770
0
}
771
772
0
std::unique_ptr<TiffIfdMakernote> newPentaxDngMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
773
0
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<PentaxDngMnHeader>());
774
0
}
775
776
std::unique_ptr<TiffIfdMakernote> newSamsungMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte* pData, size_t size,
777
0
                                               ByteOrder) {
778
0
  if (size > 4 && std::string(reinterpret_cast<const char*>(pData), 4) == std::string("AOC\0", 4)) {
779
    // Samsung branded Pentax camera:
780
    // Require at least the header and an IFD with 1 entry
781
0
    if (size < PentaxMnHeader::sizeOfSignature() + 18)
782
0
      return nullptr;
783
0
    return newPentaxMn2(tag, group, IfdId::pentaxId);
784
0
  }
785
  // Genuine Samsung camera:
786
  // Require at least an IFD with 1 entry
787
0
  if (size < 18)
788
0
    return nullptr;
789
0
  return newSamsungMn2(tag, group, mnGroup);
790
0
}
791
792
0
std::unique_ptr<TiffIfdMakernote> newSamsungMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
793
0
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<SamsungMnHeader>());
794
0
}
795
796
std::unique_ptr<TiffIfdMakernote> newSigmaMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
797
17
                                             ByteOrder) {
798
  // Require at least the header and an IFD with 1 entry
799
17
  if (size < SigmaMnHeader::sizeOfSignature() + 18)
800
7
    return nullptr;
801
10
  return newSigmaMn2(tag, group, mnGroup);
802
17
}
803
804
10
std::unique_ptr<TiffIfdMakernote> newSigmaMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
805
10
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<SigmaMnHeader>());
806
10
}
807
808
std::unique_ptr<TiffIfdMakernote> newSonyMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
809
0
                                            ByteOrder) {
810
  // If there is no "SONY DSC " string we assume it's a simple IFD Makernote
811
0
  if (size < 12 || std::string(reinterpret_cast<const char*>(pData), 12) != std::string("SONY DSC \0\0\0", 12)) {
812
    // Require at least an IFD with 1 entry
813
0
    if (size < 18)
814
0
      return nullptr;
815
0
    return newSony2Mn2(tag, group, IfdId::sony2Id);
816
0
  }
817
  // Require at least the header and an IFD with 1 entry, but without a next pointer
818
0
  if (size < SonyMnHeader::sizeOfSignature() + 14)
819
0
    return nullptr;
820
0
  return newSony1Mn2(tag, group, IfdId::sony1Id);
821
0
}
822
823
0
std::unique_ptr<TiffIfdMakernote> newSony1Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
824
0
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<SonyMnHeader>(), false);
825
0
}
826
827
0
std::unique_ptr<TiffIfdMakernote> newSony2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
828
0
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, nullptr, true);
829
0
}
830
831
std::unique_ptr<TiffIfdMakernote> newCasioMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
832
0
                                             ByteOrder) {
833
0
  if (size > 6 && std::string(reinterpret_cast<const char*>(pData), 6) == std::string("QVC\0\0\0", 6))
834
0
    return newCasio2Mn2(tag, group, IfdId::casio2Id);
835
  // Require at least an IFD with 1 entry, but not necessarily a next pointer
836
0
  if (size < 14)
837
0
    return nullptr;
838
0
  return newIfdMn2(tag, group, IfdId::casioId);
839
0
}
840
841
0
std::unique_ptr<TiffIfdMakernote> newCasio2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
842
0
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<Casio2MnHeader>());
843
0
}
844
845
//! Structure for an index into the array set of complex binary arrays.
846
struct NikonArrayIdx {
847
  //! Key for comparisons
848
  struct Key {
849
    uint16_t tag_;     //!< Tag number
850
    const char* ver_;  //!< Version string
851
    size_t size_;      //!< Size of the data (not the version string)
852
  };
853
  //! Comparison operator for a key
854
374
  bool operator==(const Key& key) const {
855
374
    return key.tag_ == tag_ && 0 == strncmp(key.ver_, ver_, strlen(ver_)) && (size_ == 0 || key.size_ == size_);
856
374
  }
857
858
  uint16_t tag_;     //!< Tag number of the binary array
859
  const char* ver_;  //!< Version string
860
  uint32_t size_;    //!< Size of the data
861
  int idx_;          //!< Index into the array set
862
  uint32_t start_;   //!< Start of the encrypted data
863
};
864
865
0
#define NA std::numeric_limits<uint32_t>::max()
866
867
//! Nikon binary array version lookup table
868
constexpr NikonArrayIdx nikonArrayIdx[] = {
869
    // NikonSi
870
    {0x0091, "0208", 0, 0, 4},     // D80
871
    {0x0091, "0209", 0, 1, 4},     // D40
872
    {0x0091, "0210", 5291, 2, 4},  // D300
873
    {0x0091, "0210", 5303, 3, 4},  // D300, firmware version 1.10
874
    {0x0091, "02", 0, 4, 4},       // Other v2.* (encrypted)
875
    {0x0091, "01", 0, 5, NA},      // Other v1.* (not encrypted)
876
    // NikonCb
877
    {0x0097, "0100", 0, 0, NA},
878
    {0x0097, "0102", 0, 1, NA},
879
    {0x0097, "0103", 0, 4, NA},
880
    {0x0097, "0205", 0, 2, 4},
881
    {0x0097, "0209", 0, 5, 284},
882
    {0x0097, "0212", 0, 5, 284},
883
    {0x0097, "0214", 0, 5, 284},
884
    {0x0097, "02", 0, 3, 284},
885
    // NikonLd
886
    {0x0098, "0100", 0, 0, NA},
887
    {0x0098, "0101", 0, 1, NA},
888
    {0x0098, "0201", 0, 1, 4},
889
    {0x0098, "0202", 0, 1, 4},
890
    {0x0098, "0203", 0, 1, 4},
891
    {0x0098, "0204", 0, 2, 4},
892
    {0x0098, "0800", 0, 3, 4},  // for e.g. Z6/7
893
    {0x0098, "0801", 0, 3, 4},  // for e.g. Z6/7
894
    {0x0098, "0802", 0, 3, 4},  // for e.g. Z9
895
    // NikonFl
896
    {0x00a8, "0100", 0, 0, NA},
897
    {0x00a8, "0101", 0, 0, NA},
898
    {0x00a8, "0102", 0, 1, NA},
899
    {0x00a8, "0103", 0, 2, NA},
900
    {0x00a8, "0104", 0, 2, NA},
901
    {0x00a8, "0105", 0, 2, NA},
902
    {0x00a8, "0106", 0, 3, NA},
903
    {0x00a8, "0107", 0, 4, NA},
904
    {0x00a8, "0108", 0, 4, NA},
905
    // NikonAf
906
    {0x00b7, "0100", 30, 0, NA},  // These sizes have been found in tiff headers of MN
907
    {0x00b7, "0101", 84, 1, NA},  // tag 0xb7 in sample image metadata for each version
908
};
909
910
11
int nikonSelector(uint16_t tag, const byte* pData, size_t size, TiffComponent* /*pRoot*/) {
911
11
  if (size < 4)
912
0
    return -1;
913
914
11
  auto ix = NikonArrayIdx::Key{tag, reinterpret_cast<const char*>(pData), size};
915
11
  if (auto it = Exiv2::find(nikonArrayIdx, ix))
916
0
    return it->idx_;
917
11
  return -1;
918
11
}
919
920
0
DataBuf nikonCrypt(uint16_t tag, const byte* pData, size_t size, TiffComponent* pRoot) {
921
0
  DataBuf buf;
922
923
0
  if (size < 4)
924
0
    return buf;
925
0
  auto nci = Exiv2::find(nikonArrayIdx, NikonArrayIdx::Key{tag, reinterpret_cast<const char*>(pData), size});
926
0
  if (!nci || nci->start_ == NA || size <= nci->start_)
927
0
    return buf;
928
929
  // Find Exif.Nikon3.ShutterCount
930
0
  TiffFinder finder(0x00a7, IfdId::nikon3Id);
931
0
  pRoot->accept(finder);
932
0
  auto te = dynamic_cast<const TiffEntryBase*>(finder.result());
933
0
  if (!te || !te->pValue() || te->pValue()->count() == 0)
934
0
    return buf;
935
0
  auto count = te->pValue()->toUint32();
936
937
  // Find Exif.Nikon3.SerialNumber
938
0
  finder.init(0x001d, IfdId::nikon3Id);
939
0
  pRoot->accept(finder);
940
0
  te = dynamic_cast<const TiffEntryBase*>(finder.result());
941
0
  if (!te || !te->pValue() || te->pValue()->count() == 0)
942
0
    return buf;
943
0
  bool ok(false);
944
0
  auto serial = stringTo<uint32_t>(te->pValue()->toString(), ok);
945
0
  if (!ok) {
946
0
    std::string model = getExifModel(pRoot);
947
0
    if (model.empty())
948
0
      return buf;
949
0
    if (Internal::contains(model, "D50")) {
950
0
      serial = 0x22;
951
0
    } else {
952
0
      serial = 0x60;
953
0
    }
954
0
  }
955
0
  buf.alloc(size);
956
0
  std::copy_n(pData, buf.size(), buf.begin());
957
0
  ncrypt(buf.data(nci->start_), static_cast<uint32_t>(buf.size()) - nci->start_, count, serial);
958
0
  return buf;
959
0
}
960
961
0
int sonyCsSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) {
962
0
  std::string model = getExifModel(pRoot);
963
0
  if (model.empty())
964
0
    return -1;
965
0
  int idx = 0;
966
0
  if (Internal::contains(model, "DSLR-A330") || Internal::contains(model, "DSLR-A380")) {
967
0
    idx = 1;
968
0
  }
969
0
  return idx;
970
0
}
971
0
int sony2010eSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) {
972
0
  static constexpr const char* models[] = {
973
0
      "SLT-A58",   "SLT-A99",  "ILCE-3000", "ILCE-3500", "NEX-3N",    "NEX-5R",   "NEX-5T",
974
0
      "NEX-6",     "VG30E",    "VG900",     "DSC-RX100", "DSC-RX1",   "DSC-RX1R", "DSC-HX300",
975
0
      "DSC-HX50V", "DSC-TX30", "DSC-WX60",  "DSC-WX200", "DSC-WX300",
976
0
  };
977
0
  return Exiv2::find(models, getExifModel(pRoot)) ? 0 : -1;
978
0
}
979
980
0
int sony2FpSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) {
981
  // Not valid for models beginning
982
0
  std::string model = getExifModel(pRoot);
983
0
  for (auto str : {"SLT-", "HV", "ILCA-"})
984
0
    if (model.starts_with(str))
985
0
      return -1;
986
0
  return 0;
987
0
}
988
989
0
int sonyMisc2bSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) {
990
  // From Exiftool: https://github.com/exiftool/exiftool/blob/master/lib/Image/ExifTool/Sony.pm
991
  // >  First byte must be 9 or 12 or 13 or 15 or 16 and 4th byte must be 2 (deciphered)
992
993
  // Get the value from the image format that is being used
994
0
  auto value = getExifValue(pRoot, 0x9404, Exiv2::IfdId::sony1Id);
995
0
  if (!value) {
996
0
    value = getExifValue(pRoot, 0x9404, Exiv2::IfdId::sony2Id);
997
0
    if (!value)
998
0
      return -1;
999
0
  }
1000
1001
0
  if (value->count() < 4)
1002
0
    return -1;
1003
1004
0
  switch (value->toInt64(0)) {                 // Using encrypted values
1005
0
    case 231:                                  // 231 == 9
1006
0
    case 234:                                  // 234 == 12
1007
0
    case 205:                                  // 205 == 13
1008
0
    case 138:                                  // 138 == 15
1009
0
    case 112:                                  // 112 == 16
1010
0
      return value->toInt64(3) == 8 ? 0 : -1;  // 8   == 2
1011
0
    default:
1012
0
      break;
1013
0
  }
1014
0
  return -1;
1015
0
}
1016
0
int sonyMisc3cSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) {
1017
  // For condition, see Exiftool (Tag 9400c):
1018
  // https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L1681
1019
1020
  // Get the value from the image format that is being used
1021
0
  auto value = getExifValue(pRoot, 0x9400, Exiv2::IfdId::sony1Id);
1022
0
  if (!value) {
1023
0
    value = getExifValue(pRoot, 0x9400, Exiv2::IfdId::sony2Id);
1024
0
    if (!value)
1025
0
      return -1;
1026
0
  }
1027
1028
0
  if (value->count() < 1)
1029
0
    return -1;
1030
1031
0
  switch (value->toInt64()) {
1032
0
    case 35:
1033
0
    case 36:
1034
0
    case 38:
1035
0
    case 40:
1036
0
    case 49:
1037
0
    case 50:
1038
0
      return 0;
1039
0
    default:
1040
0
      break;
1041
0
  }
1042
0
  return -1;
1043
0
}
1044
}  // namespace Exiv2::Internal
1045
1046
// *****************************************************************************
1047
// local definitions
1048
namespace {
1049
0
const Exiv2::Value* getExifValue(Exiv2::Internal::TiffComponent* pRoot, uint16_t tag, Exiv2::IfdId group) {
1050
0
  Exiv2::Internal::TiffFinder finder(tag, group);
1051
0
  if (!pRoot)
1052
0
    return nullptr;
1053
0
  pRoot->accept(finder);
1054
0
  auto te = dynamic_cast<const Exiv2::Internal::TiffEntryBase*>(finder.result());
1055
0
  return (!te || !te->pValue()) ? nullptr : te->pValue();
1056
0
}
1057
1058
0
std::string getExifModel(Exiv2::Internal::TiffComponent* pRoot) {
1059
  // Lookup the Exif.Image.Model tag
1060
0
  const auto value = getExifValue(pRoot, 0x0110, Exiv2::IfdId::ifd0Id);
1061
0
  return (!value || value->count() == 0) ? std::string() : value->toString();
1062
0
}
1063
1064
0
void ncrypt(Exiv2::byte* pData, uint32_t size, uint32_t count, uint32_t serial) {
1065
0
  static const Exiv2::byte xlat[2][256] = {
1066
0
      {0xc1, 0xbf, 0x6d, 0x0d, 0x59, 0xc5, 0x13, 0x9d, 0x83, 0x61, 0x6b, 0x4f, 0xc7, 0x7f, 0x3d, 0x3d, 0x53, 0x59, 0xe3,
1067
0
       0xc7, 0xe9, 0x2f, 0x95, 0xa7, 0x95, 0x1f, 0xdf, 0x7f, 0x2b, 0x29, 0xc7, 0x0d, 0xdf, 0x07, 0xef, 0x71, 0x89, 0x3d,
1068
0
       0x13, 0x3d, 0x3b, 0x13, 0xfb, 0x0d, 0x89, 0xc1, 0x65, 0x1f, 0xb3, 0x0d, 0x6b, 0x29, 0xe3, 0xfb, 0xef, 0xa3, 0x6b,
1069
0
       0x47, 0x7f, 0x95, 0x35, 0xa7, 0x47, 0x4f, 0xc7, 0xf1, 0x59, 0x95, 0x35, 0x11, 0x29, 0x61, 0xf1, 0x3d, 0xb3, 0x2b,
1070
0
       0x0d, 0x43, 0x89, 0xc1, 0x9d, 0x9d, 0x89, 0x65, 0xf1, 0xe9, 0xdf, 0xbf, 0x3d, 0x7f, 0x53, 0x97, 0xe5, 0xe9, 0x95,
1071
0
       0x17, 0x1d, 0x3d, 0x8b, 0xfb, 0xc7, 0xe3, 0x67, 0xa7, 0x07, 0xf1, 0x71, 0xa7, 0x53, 0xb5, 0x29, 0x89, 0xe5, 0x2b,
1072
0
       0xa7, 0x17, 0x29, 0xe9, 0x4f, 0xc5, 0x65, 0x6d, 0x6b, 0xef, 0x0d, 0x89, 0x49, 0x2f, 0xb3, 0x43, 0x53, 0x65, 0x1d,
1073
0
       0x49, 0xa3, 0x13, 0x89, 0x59, 0xef, 0x6b, 0xef, 0x65, 0x1d, 0x0b, 0x59, 0x13, 0xe3, 0x4f, 0x9d, 0xb3, 0x29, 0x43,
1074
0
       0x2b, 0x07, 0x1d, 0x95, 0x59, 0x59, 0x47, 0xfb, 0xe5, 0xe9, 0x61, 0x47, 0x2f, 0x35, 0x7f, 0x17, 0x7f, 0xef, 0x7f,
1075
0
       0x95, 0x95, 0x71, 0xd3, 0xa3, 0x0b, 0x71, 0xa3, 0xad, 0x0b, 0x3b, 0xb5, 0xfb, 0xa3, 0xbf, 0x4f, 0x83, 0x1d, 0xad,
1076
0
       0xe9, 0x2f, 0x71, 0x65, 0xa3, 0xe5, 0x07, 0x35, 0x3d, 0x0d, 0xb5, 0xe9, 0xe5, 0x47, 0x3b, 0x9d, 0xef, 0x35, 0xa3,
1077
0
       0xbf, 0xb3, 0xdf, 0x53, 0xd3, 0x97, 0x53, 0x49, 0x71, 0x07, 0x35, 0x61, 0x71, 0x2f, 0x43, 0x2f, 0x11, 0xdf, 0x17,
1078
0
       0x97, 0xfb, 0x95, 0x3b, 0x7f, 0x6b, 0xd3, 0x25, 0xbf, 0xad, 0xc7, 0xc5, 0xc5, 0xb5, 0x8b, 0xef, 0x2f, 0xd3, 0x07,
1079
0
       0x6b, 0x25, 0x49, 0x95, 0x25, 0x49, 0x6d, 0x71, 0xc7},
1080
0
      {0xa7, 0xbc, 0xc9, 0xad, 0x91, 0xdf, 0x85, 0xe5, 0xd4, 0x78, 0xd5, 0x17, 0x46, 0x7c, 0x29, 0x4c, 0x4d, 0x03, 0xe9,
1081
0
       0x25, 0x68, 0x11, 0x86, 0xb3, 0xbd, 0xf7, 0x6f, 0x61, 0x22, 0xa2, 0x26, 0x34, 0x2a, 0xbe, 0x1e, 0x46, 0x14, 0x68,
1082
0
       0x9d, 0x44, 0x18, 0xc2, 0x40, 0xf4, 0x7e, 0x5f, 0x1b, 0xad, 0x0b, 0x94, 0xb6, 0x67, 0xb4, 0x0b, 0xe1, 0xea, 0x95,
1083
0
       0x9c, 0x66, 0xdc, 0xe7, 0x5d, 0x6c, 0x05, 0xda, 0xd5, 0xdf, 0x7a, 0xef, 0xf6, 0xdb, 0x1f, 0x82, 0x4c, 0xc0, 0x68,
1084
0
       0x47, 0xa1, 0xbd, 0xee, 0x39, 0x50, 0x56, 0x4a, 0xdd, 0xdf, 0xa5, 0xf8, 0xc6, 0xda, 0xca, 0x90, 0xca, 0x01, 0x42,
1085
0
       0x9d, 0x8b, 0x0c, 0x73, 0x43, 0x75, 0x05, 0x94, 0xde, 0x24, 0xb3, 0x80, 0x34, 0xe5, 0x2c, 0xdc, 0x9b, 0x3f, 0xca,
1086
0
       0x33, 0x45, 0xd0, 0xdb, 0x5f, 0xf5, 0x52, 0xc3, 0x21, 0xda, 0xe2, 0x22, 0x72, 0x6b, 0x3e, 0xd0, 0x5b, 0xa8, 0x87,
1087
0
       0x8c, 0x06, 0x5d, 0x0f, 0xdd, 0x09, 0x19, 0x93, 0xd0, 0xb9, 0xfc, 0x8b, 0x0f, 0x84, 0x60, 0x33, 0x1c, 0x9b, 0x45,
1088
0
       0xf1, 0xf0, 0xa3, 0x94, 0x3a, 0x12, 0x77, 0x33, 0x4d, 0x44, 0x78, 0x28, 0x3c, 0x9e, 0xfd, 0x65, 0x57, 0x16, 0x94,
1089
0
       0x6b, 0xfb, 0x59, 0xd0, 0xc8, 0x22, 0x36, 0xdb, 0xd2, 0x63, 0x98, 0x43, 0xa1, 0x04, 0x87, 0x86, 0xf7, 0xa6, 0x26,
1090
0
       0xbb, 0xd6, 0x59, 0x4d, 0xbf, 0x6a, 0x2e, 0xaa, 0x2b, 0xef, 0xe6, 0x78, 0xb6, 0x4e, 0xe0, 0x2f, 0xdc, 0x7c, 0xbe,
1091
0
       0x57, 0x19, 0x32, 0x7e, 0x2a, 0xd0, 0xb8, 0xba, 0x29, 0x00, 0x3c, 0x52, 0x7d, 0xa8, 0x49, 0x3b, 0x2d, 0xeb, 0x25,
1092
0
       0x49, 0xfa, 0xa3, 0xaa, 0x39, 0xa7, 0xc5, 0xa7, 0x50, 0x11, 0x36, 0xfb, 0xc6, 0x67, 0x4a, 0xf5, 0xa5, 0x12, 0x65,
1093
0
       0x7e, 0xb0, 0xdf, 0xaf, 0x4e, 0xb3, 0x61, 0x7f, 0x2f},
1094
0
  };
1095
0
  Exiv2::byte key = 0;
1096
0
  for (int i = 0; i < 4; ++i) {
1097
0
    key ^= static_cast<Exiv2::byte>(count >> (i * 8));
1098
0
  }
1099
0
  Exiv2::byte ci = xlat[0][serial & 0xff];
1100
0
  Exiv2::byte cj = xlat[1][key];
1101
0
  Exiv2::byte ck = 0x60;
1102
0
  for (uint32_t i = 0; i < size; ++i) {
1103
0
    cj += ci * ck++;
1104
0
    pData[i] ^= cj;
1105
0
  }
1106
0
}
1107
}  // namespace