Coverage Report

Created: 2026-08-17 07:50

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
41.2k
bool TiffMnRegistry::operator==(std::string_view key) const {
134
41.2k
  if (!key.empty() && key.front() == '-')
135
130
    return false;
136
41.1k
  return key.starts_with(make_);
137
41.2k
}
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
3.76k
                                                        const byte* pData, size_t size, ByteOrder byteOrder) {
145
3.76k
  if (auto tmr = Exiv2::find(registry_, make))
146
2.91k
    return tmr->newMnFct_(tag, group, tmr->mnGroup_, pData, size, byteOrder);
147
854
  return nullptr;
148
3.76k
}  // 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
31
size_t MnHeader::ifdOffset() const {
164
31
  return 0;
165
31
}
166
167
256
ByteOrder MnHeader::byteOrder() const {
168
256
  return invalidByteOrder;
169
256
}
170
171
40
size_t MnHeader::baseOffset(size_t /*mnOffset*/) const {
172
40
  return 0;
173
40
}
174
175
const byte OlympusMnHeader::signature_[] = {'O', 'L', 'Y', 'M', 'P', 0x00, 0x01, 0x00};
176
177
414
size_t OlympusMnHeader::sizeOfSignature() {
178
414
  return sizeof(signature_);
179
414
}
180
181
29
OlympusMnHeader::OlympusMnHeader() {
182
29
  read(signature_, sizeOfSignature(), invalidByteOrder);
183
29
}
184
185
0
size_t OlympusMnHeader::size() const {
186
0
  return header_.size();
187
0
}
188
189
4
size_t OlympusMnHeader::ifdOffset() const {
190
4
  return sizeOfSignature();
191
4
}
192
193
58
bool OlympusMnHeader::read(const byte* pData, size_t size, ByteOrder) {
194
58
  if (!pData || size < sizeOfSignature())
195
0
    return false;
196
58
  header_.alloc(sizeOfSignature());
197
58
  std::copy_n(pData, header_.size(), header_.begin());
198
58
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, 6);
199
58
}
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
378
size_t Olympus2MnHeader::sizeOfSignature() {
209
378
  return sizeof(signature_);
210
378
}
211
212
42
Olympus2MnHeader::Olympus2MnHeader() {
213
42
  read(signature_, sizeOfSignature(), invalidByteOrder);
214
42
}
215
216
0
size_t Olympus2MnHeader::size() const {
217
0
  return header_.size();
218
0
}
219
220
42
size_t Olympus2MnHeader::ifdOffset() const {
221
42
  return sizeOfSignature();
222
42
}
223
224
42
size_t Olympus2MnHeader::baseOffset(size_t mnOffset) const {
225
42
  return mnOffset;
226
42
}
227
228
84
bool Olympus2MnHeader::read(const byte* pData, size_t size, ByteOrder) {
229
84
  if (!pData || size < sizeOfSignature())
230
0
    return false;
231
84
  header_.alloc(sizeOfSignature());
232
84
  std::copy_n(pData, header_.size(), header_.begin());
233
84
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, 10);
234
84
}
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
312
size_t OMSystemMnHeader::sizeOfSignature() {
245
312
  return sizeof(signature_);
246
312
}
247
248
20
OMSystemMnHeader::OMSystemMnHeader() {
249
20
  read(signature_, sizeOfSignature(), invalidByteOrder);
250
20
}
251
252
0
size_t OMSystemMnHeader::size() const {
253
0
  return header_.size();
254
0
}
255
256
16
size_t OMSystemMnHeader::ifdOffset() const {
257
16
  return sizeOfSignature();
258
16
}
259
260
16
size_t OMSystemMnHeader::baseOffset(size_t mnOffset) const {
261
16
  return mnOffset;
262
16
}
263
264
40
bool OMSystemMnHeader::read(const byte* pData, size_t size, ByteOrder) {
265
40
  if (!pData || size < sizeOfSignature())
266
0
    return false;
267
40
  header_.alloc(sizeOfSignature());
268
40
  std::copy_n(pData, header_.size(), header_.begin());
269
40
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, sizeOfSignature() - 2);
270
40
}
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
404
size_t FujiMnHeader::sizeOfSignature() {
281
404
  return sizeof(signature_);
282
404
}
283
284
41
FujiMnHeader::FujiMnHeader() {
285
41
  read(signature_, sizeOfSignature(), byteOrder_);
286
41
}
287
288
0
size_t FujiMnHeader::size() const {
289
0
  return header_.size();
290
0
}
291
292
24
size_t FujiMnHeader::ifdOffset() const {
293
24
  return start_;
294
24
}
295
296
96
ByteOrder FujiMnHeader::byteOrder() const {
297
96
  return byteOrder_;
298
96
}
299
300
24
size_t FujiMnHeader::baseOffset(size_t mnOffset) const {
301
24
  return mnOffset;
302
24
}
303
304
82
bool FujiMnHeader::read(const byte* pData, size_t size, ByteOrder) {
305
82
  if (!pData || size < sizeOfSignature())
306
0
    return false;
307
82
  header_.alloc(sizeOfSignature());
308
82
  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
82
  start_ = header_.read_uint32(8, byteOrder_);
312
82
  return header_.size() >= sizeOfSignature() && 0 == header_.cmpBytes(0, signature_, 8);
313
82
}
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
80
size_t Nikon2MnHeader::sizeOfSignature() {
323
80
  return sizeof(signature_);
324
80
}
325
326
10
Nikon2MnHeader::Nikon2MnHeader() {
327
10
  read(signature_, sizeOfSignature(), invalidByteOrder);
328
10
}
329
330
0
size_t Nikon2MnHeader::size() const {
331
0
  return sizeOfSignature();
332
0
}
333
334
10
size_t Nikon2MnHeader::ifdOffset() const {
335
10
  return start_;
336
10
}
337
338
20
bool Nikon2MnHeader::read(const byte* pData, size_t size, ByteOrder) {
339
20
  if (!pData || size < sizeOfSignature())
340
0
    return false;
341
20
  if (0 != memcmp(pData, signature_, 6))
342
0
    return false;
343
20
  buf_.alloc(sizeOfSignature());
344
20
  std::copy_n(pData, buf_.size(), buf_.begin());
345
20
  start_ = sizeOfSignature();
346
20
  return true;
347
20
}  // 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
65
size_t Nikon3MnHeader::sizeOfSignature() {
358
65
  return sizeof(signature_);
359
65
}
360
361
13
Nikon3MnHeader::Nikon3MnHeader() : start_(sizeOfSignature()) {
362
13
  buf_.alloc(sizeOfSignature());
363
13
  std::copy_n(signature_, buf_.size(), buf_.begin());
364
13
}
365
366
0
size_t Nikon3MnHeader::size() const {
367
0
  return sizeOfSignature();
368
0
}
369
370
13
size_t Nikon3MnHeader::ifdOffset() const {
371
13
  return start_;
372
13
}
373
374
52
ByteOrder Nikon3MnHeader::byteOrder() const {
375
52
  return byteOrder_;
376
52
}
377
378
13
size_t Nikon3MnHeader::baseOffset(size_t mnOffset) const {
379
13
  return Safe::add<size_t>(mnOffset, 10);
380
13
}
381
382
13
bool Nikon3MnHeader::read(const byte* pData, size_t size, ByteOrder) {
383
13
  if (!pData || size < sizeOfSignature())
384
0
    return false;
385
13
  if (0 != memcmp(pData, signature_, 6))
386
0
    return false;
387
13
  buf_.alloc(sizeOfSignature());
388
13
  std::copy_n(pData, buf_.size(), buf_.begin());
389
13
  TiffHeader th;
390
13
  if (!th.read(buf_.data(10), 8))
391
0
    return false;
392
13
  byteOrder_ = th.byteOrder();
393
13
  start_ = 10 + th.offset();
394
13
  return true;
395
13
}  // 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
280
size_t PanasonicMnHeader::sizeOfSignature() {
413
280
  return sizeof(signature_);
414
280
}
415
416
31
PanasonicMnHeader::PanasonicMnHeader() {
417
31
  read(signature_, sizeOfSignature(), invalidByteOrder);
418
31
}
419
420
0
size_t PanasonicMnHeader::size() const {
421
0
  return sizeOfSignature();
422
0
}
423
424
15
size_t PanasonicMnHeader::ifdOffset() const {
425
15
  return start_;
426
15
}
427
428
62
bool PanasonicMnHeader::read(const byte* pData, size_t size, ByteOrder) {
429
62
  if (!pData || size < sizeOfSignature())
430
0
    return false;
431
62
  if (0 != memcmp(pData, signature_, 9))
432
16
    return false;
433
46
  buf_.alloc(sizeOfSignature());
434
46
  std::copy_n(pData, buf_.size(), buf_.begin());
435
46
  start_ = sizeOfSignature();
436
46
  return true;
437
62
}  // 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
31
SamsungMnHeader::SamsungMnHeader() {
511
31
  read(nullptr, 0, invalidByteOrder);
512
31
}
513
514
0
size_t SamsungMnHeader::size() const {
515
0
  return 0;
516
0
}
517
518
31
size_t SamsungMnHeader::baseOffset(size_t mnOffset) const {
519
31
  return mnOffset;
520
31
}
521
522
62
bool SamsungMnHeader::read(const byte* /*pData*/, size_t /*size*/, ByteOrder) {
523
62
  return true;
524
62
}  // 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
296
size_t SigmaMnHeader::sizeOfSignature() {
534
296
  return sizeof(signature1_);
535
296
}
536
537
30
SigmaMnHeader::SigmaMnHeader() {
538
30
  read(signature1_, sizeOfSignature(), invalidByteOrder);
539
30
}
540
541
0
size_t SigmaMnHeader::size() const {
542
0
  return sizeOfSignature();
543
0
}
544
545
10
size_t SigmaMnHeader::ifdOffset() const {
546
10
  return start_;
547
10
}
548
549
60
bool SigmaMnHeader::read(const byte* pData, size_t size, ByteOrder) {
550
60
  if (!pData || size < sizeOfSignature())
551
0
    return false;
552
60
  if (0 != memcmp(pData, signature1_, 8) && 0 != memcmp(pData, signature2_, 8))
553
20
    return false;
554
40
  buf_.alloc(sizeOfSignature());
555
40
  std::copy_n(pData, buf_.size(), buf_.begin());
556
40
  start_ = sizeOfSignature();
557
40
  return true;
558
60
}  // 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
9
size_t Casio2MnHeader::sizeOfSignature() {
603
9
  return sizeof(signature_);
604
9
}
605
606
1
Casio2MnHeader::Casio2MnHeader() {
607
1
  read(signature_, sizeOfSignature(), invalidByteOrder);
608
1
}
609
610
0
size_t Casio2MnHeader::size() const {
611
0
  return sizeOfSignature();
612
0
}
613
614
1
size_t Casio2MnHeader::ifdOffset() const {
615
1
  return start_;
616
1
}
617
618
4
ByteOrder Casio2MnHeader::byteOrder() const {
619
4
  return byteOrder_;
620
4
}
621
622
2
bool Casio2MnHeader::read(const byte* pData, size_t size, ByteOrder) {
623
2
  if (!pData || size < sizeOfSignature())
624
0
    return false;
625
2
  if (0 != memcmp(pData, signature_, sizeOfSignature()))
626
0
    return false;
627
2
  buf_.alloc(sizeOfSignature());
628
2
  std::copy_n(pData, buf_.size(), buf_.begin());
629
2
  start_ = sizeOfSignature();
630
2
  return true;
631
2
}  // 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
1.22k
                                           ByteOrder) {
643
  // Require at least an IFD with 1 entry, but not necessarily a next pointer
644
1.22k
  if (size < 14)
645
589
    return nullptr;
646
638
  return newIfdMn2(tag, group, mnGroup);
647
1.22k
}
648
649
816
std::unique_ptr<TiffIfdMakernote> newIfdMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
650
816
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, nullptr);
651
816
}
652
653
std::unique_ptr<TiffIfdMakernote> newOlympusMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
654
278
                                               ByteOrder) {
655
  // FIXME: workaround for overwritten OM System header in Olympus files (https://github.com/Exiv2/exiv2/issues/2542)
656
278
  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
29
    if (size < OMSystemMnHeader::sizeOfSignature() + 18)
659
16
      return nullptr;
660
13
    return newOMSystemMn2(tag, group, IfdId::olympus2Id);
661
29
  }
662
249
  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
207
    if (size < OlympusMnHeader::sizeOfSignature() + 18)
665
178
      return nullptr;
666
29
    return newOlympusMn2(tag, group, IfdId::olympusId);
667
207
  }
668
  // Require at least the header and an IFD with 1 entry
669
42
  if (size < Olympus2MnHeader::sizeOfSignature() + 18)
670
0
    return nullptr;
671
42
  return newOlympus2Mn2(tag, group, IfdId::olympus2Id);
672
42
}
673
674
29
std::unique_ptr<TiffIfdMakernote> newOlympusMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
675
29
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<OlympusMnHeader>());
676
29
}
677
678
42
std::unique_ptr<TiffIfdMakernote> newOlympus2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
679
42
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<Olympus2MnHeader>());
680
42
}
681
682
std::unique_ptr<TiffIfdMakernote> newOMSystemMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
683
87
                                                ByteOrder) {
684
  // Require at least the header and an IFD with 1 entry
685
87
  if (size < OMSystemMnHeader::sizeOfSignature() + 18)
686
80
    return nullptr;
687
7
  return newOMSystemMn2(tag, group, mnGroup);
688
87
}
689
690
20
std::unique_ptr<TiffIfdMakernote> newOMSystemMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
691
20
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<OMSystemMnHeader>());
692
20
}
693
694
std::unique_ptr<TiffIfdMakernote> newFujiMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
695
117
                                            ByteOrder) {
696
  // Require at least the header and an IFD with 1 entry
697
117
  if (size < FujiMnHeader::sizeOfSignature() + 18)
698
76
    return nullptr;
699
41
  return newFujiMn2(tag, group, mnGroup);
700
117
}
701
702
41
std::unique_ptr<TiffIfdMakernote> newFujiMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
703
41
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<FujiMnHeader>());
704
41
}
705
706
std::unique_ptr<TiffIfdMakernote> newNikonMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
707
177
                                             ByteOrder) {
708
  // If there is no "Nikon" string it must be Nikon1 format
709
177
  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
154
    if (size < 18)
712
116
      return nullptr;
713
38
    return newIfdMn2(tag, group, IfdId::nikon1Id);
714
154
  }
715
  // If the "Nikon" string is not followed by a TIFF header, we assume
716
  // Nikon2 format
717
23
  TiffHeader tiffHeader;
718
23
  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
10
    if (size < Nikon2MnHeader::sizeOfSignature() + 18)
721
0
      return nullptr;
722
10
    return newNikon2Mn2(tag, group, IfdId::nikon2Id);
723
10
  }
724
  // Else we have a Nikon3 makernote
725
  // Require at least the header and an IFD with 1 entry
726
13
  if (size < Nikon3MnHeader::sizeOfSignature() + 18)
727
0
    return nullptr;
728
13
  return newNikon3Mn2(tag, group, IfdId::nikon3Id);
729
13
}
730
731
10
std::unique_ptr<TiffIfdMakernote> newNikon2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
732
10
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<Nikon2MnHeader>());
733
10
}
734
735
13
std::unique_ptr<TiffIfdMakernote> newNikon3Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
736
13
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<Nikon3MnHeader>());
737
13
}
738
739
std::unique_ptr<TiffIfdMakernote> newPanasonicMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
740
95
                                                 ByteOrder) {
741
  // Require at least the header and an IFD with 1 entry, but without a next pointer
742
95
  if (size < PanasonicMnHeader::sizeOfSignature() + 14)
743
64
    return nullptr;
744
31
  return newPanasonicMn2(tag, group, mnGroup);
745
95
}
746
747
31
std::unique_ptr<TiffIfdMakernote> newPanasonicMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
748
31
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<PanasonicMnHeader>(), false);
749
31
}
750
751
std::unique_ptr<TiffIfdMakernote> newPentaxMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
752
208
                                              ByteOrder) {
753
208
  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
208
  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
208
  return nullptr;
766
208
}
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
179
                                               ByteOrder) {
778
179
  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
179
  if (size < 18)
788
148
    return nullptr;
789
31
  return newSamsungMn2(tag, group, mnGroup);
790
179
}
791
792
31
std::unique_ptr<TiffIfdMakernote> newSamsungMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
793
31
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<SamsungMnHeader>());
794
31
}
795
796
std::unique_ptr<TiffIfdMakernote> newSigmaMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte*, size_t size,
797
126
                                             ByteOrder) {
798
  // Require at least the header and an IFD with 1 entry
799
126
  if (size < SigmaMnHeader::sizeOfSignature() + 18)
800
96
    return nullptr;
801
30
  return newSigmaMn2(tag, group, mnGroup);
802
126
}
803
804
30
std::unique_ptr<TiffIfdMakernote> newSigmaMn2(uint16_t tag, IfdId group, IfdId mnGroup) {
805
30
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<SigmaMnHeader>());
806
30
}
807
808
std::unique_ptr<TiffIfdMakernote> newSonyMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
809
49
                                            ByteOrder) {
810
  // If there is no "SONY DSC " string we assume it's a simple IFD Makernote
811
49
  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
49
    if (size < 18)
814
32
      return nullptr;
815
17
    return newSony2Mn2(tag, group, IfdId::sony2Id);
816
49
  }
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
17
std::unique_ptr<TiffIfdMakernote> newSony2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
828
17
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, nullptr, true);
829
17
}
830
831
std::unique_ptr<TiffIfdMakernote> newCasioMn(uint16_t tag, IfdId group, IfdId, const byte* pData, size_t size,
832
372
                                             ByteOrder) {
833
372
  if (size > 6 && std::string(reinterpret_cast<const char*>(pData), 6) == std::string("QVC\0\0\0", 6))
834
1
    return newCasio2Mn2(tag, group, IfdId::casio2Id);
835
  // Require at least an IFD with 1 entry, but not necessarily a next pointer
836
371
  if (size < 14)
837
231
    return nullptr;
838
140
  return newIfdMn2(tag, group, IfdId::casioId);
839
371
}
840
841
1
std::unique_ptr<TiffIfdMakernote> newCasio2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) {
842
1
  return std::make_unique<TiffIfdMakernote>(tag, group, mnGroup, std::make_unique<Casio2MnHeader>());
843
1
}
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
1.21k
  bool operator==(const Key& key) const {
855
1.21k
    return key.tag_ == tag_ && 0 == strncmp(key.ver_, ver_, strlen(ver_)) && (size_ == 0 || key.size_ == size_);
856
1.21k
  }
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
6
#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
35
int nikonSelector(uint16_t tag, const byte* pData, size_t size, TiffComponent* /*pRoot*/) {
911
35
  if (size < 4)
912
0
    return -1;
913
914
35
  auto ix = NikonArrayIdx::Key{tag, reinterpret_cast<const char*>(pData), size};
915
35
  if (auto it = Exiv2::find(nikonArrayIdx, ix))
916
3
    return it->idx_;
917
32
  return -1;
918
35
}
919
920
3
DataBuf nikonCrypt(uint16_t tag, const byte* pData, size_t size, TiffComponent* pRoot) {
921
3
  DataBuf buf;
922
923
3
  if (size < 4)
924
0
    return buf;
925
3
  auto nci = Exiv2::find(nikonArrayIdx, NikonArrayIdx::Key{tag, reinterpret_cast<const char*>(pData), size});
926
3
  if (!nci || nci->start_ == NA || size <= nci->start_)
927
0
    return buf;
928
929
  // Find Exif.Nikon3.ShutterCount
930
3
  TiffFinder finder(0x00a7, IfdId::nikon3Id);
931
3
  pRoot->accept(finder);
932
3
  auto te = dynamic_cast<const TiffEntryBase*>(finder.result());
933
3
  if (!te || !te->pValue() || te->pValue()->count() == 0)
934
0
    return buf;
935
3
  auto count = te->pValue()->toUint32();
936
937
  // Find Exif.Nikon3.SerialNumber
938
3
  finder.init(0x001d, IfdId::nikon3Id);
939
3
  pRoot->accept(finder);
940
3
  te = dynamic_cast<const TiffEntryBase*>(finder.result());
941
3
  if (!te || !te->pValue() || te->pValue()->count() == 0)
942
0
    return buf;
943
3
  bool ok(false);
944
3
  auto serial = stringTo<uint32_t>(te->pValue()->toString(), ok);
945
3
  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
3
  buf.alloc(size);
956
3
  std::copy_n(pData, buf.size(), buf.begin());
957
3
  ncrypt(buf.data(nci->start_), static_cast<uint32_t>(buf.size()) - nci->start_, count, serial);
958
3
  return buf;
959
3
}
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/2200871d9cef988051d2a99d67df3bda6cbb30a8/lib/Image/ExifTool/Sony.pm#L1826
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:  // 0x23 for DSC-RX10/HX60V/HX350/HX400V/WX220/WX350, ILCE-7/7R/5000/6000, ILCA-68/77M2
1033
0
    case 36:  // 0x24 for ILCA-99M2,ILCE-5100/6300/6500/7M2/7RM2/7S/7SM2/QX1,
1034
              // DSC-HX80/HX90V/QX30/RX0/RX100M3/RX100M4/RX100M5/RX10M2/RX10M3/RX1RM2/WX500
1035
0
    case 38:  // 0x26 for ILCE-6100/6400/6600/7M3/7RM3/9, DSC-RX0M2/RX10M4/RX100M5A/RX100M6/HX95/HX99
1036
0
    case 40:  // 0x28 for ILCE-7RM4/9M2, DSC-RX100M7, ZV-1/1F/1M2/E10
1037
0
    case 49:  // 0x31 for ILCE-1/7M4/7SM3, ILME-FX3
1038
0
    case 50:  // 0x32 for ILCE-7RM5, ILME-FX30
1039
0
    case 51:  // 0x33 for ILCE-6700/7CM2/7CR/9M3, ZV-E1
1040
0
    case 52:  // 0x34 for DSC-RX10M5
1041
0
    case 65:  // 0x41 for ILCE-7M5
1042
0
    case 67:  // 0x43 for ILCE-7RM6
1043
0
      return 0;
1044
0
    default:
1045
0
      break;
1046
0
  }
1047
0
  return -1;
1048
0
}
1049
}  // namespace Exiv2::Internal
1050
1051
// *****************************************************************************
1052
// local definitions
1053
namespace {
1054
0
const Exiv2::Value* getExifValue(Exiv2::Internal::TiffComponent* pRoot, uint16_t tag, Exiv2::IfdId group) {
1055
0
  Exiv2::Internal::TiffFinder finder(tag, group);
1056
0
  if (!pRoot)
1057
0
    return nullptr;
1058
0
  pRoot->accept(finder);
1059
0
  auto te = dynamic_cast<const Exiv2::Internal::TiffEntryBase*>(finder.result());
1060
0
  return (!te || !te->pValue()) ? nullptr : te->pValue();
1061
0
}
1062
1063
0
std::string getExifModel(Exiv2::Internal::TiffComponent* pRoot) {
1064
  // Lookup the Exif.Image.Model tag
1065
0
  const auto value = getExifValue(pRoot, 0x0110, Exiv2::IfdId::ifd0Id);
1066
0
  return (!value || value->count() == 0) ? std::string() : value->toString();
1067
0
}
1068
1069
3
void ncrypt(Exiv2::byte* pData, uint32_t size, uint32_t count, uint32_t serial) {
1070
3
  static const Exiv2::byte xlat[2][256] = {
1071
3
      {0xc1, 0xbf, 0x6d, 0x0d, 0x59, 0xc5, 0x13, 0x9d, 0x83, 0x61, 0x6b, 0x4f, 0xc7, 0x7f, 0x3d, 0x3d, 0x53, 0x59, 0xe3,
1072
3
       0xc7, 0xe9, 0x2f, 0x95, 0xa7, 0x95, 0x1f, 0xdf, 0x7f, 0x2b, 0x29, 0xc7, 0x0d, 0xdf, 0x07, 0xef, 0x71, 0x89, 0x3d,
1073
3
       0x13, 0x3d, 0x3b, 0x13, 0xfb, 0x0d, 0x89, 0xc1, 0x65, 0x1f, 0xb3, 0x0d, 0x6b, 0x29, 0xe3, 0xfb, 0xef, 0xa3, 0x6b,
1074
3
       0x47, 0x7f, 0x95, 0x35, 0xa7, 0x47, 0x4f, 0xc7, 0xf1, 0x59, 0x95, 0x35, 0x11, 0x29, 0x61, 0xf1, 0x3d, 0xb3, 0x2b,
1075
3
       0x0d, 0x43, 0x89, 0xc1, 0x9d, 0x9d, 0x89, 0x65, 0xf1, 0xe9, 0xdf, 0xbf, 0x3d, 0x7f, 0x53, 0x97, 0xe5, 0xe9, 0x95,
1076
3
       0x17, 0x1d, 0x3d, 0x8b, 0xfb, 0xc7, 0xe3, 0x67, 0xa7, 0x07, 0xf1, 0x71, 0xa7, 0x53, 0xb5, 0x29, 0x89, 0xe5, 0x2b,
1077
3
       0xa7, 0x17, 0x29, 0xe9, 0x4f, 0xc5, 0x65, 0x6d, 0x6b, 0xef, 0x0d, 0x89, 0x49, 0x2f, 0xb3, 0x43, 0x53, 0x65, 0x1d,
1078
3
       0x49, 0xa3, 0x13, 0x89, 0x59, 0xef, 0x6b, 0xef, 0x65, 0x1d, 0x0b, 0x59, 0x13, 0xe3, 0x4f, 0x9d, 0xb3, 0x29, 0x43,
1079
3
       0x2b, 0x07, 0x1d, 0x95, 0x59, 0x59, 0x47, 0xfb, 0xe5, 0xe9, 0x61, 0x47, 0x2f, 0x35, 0x7f, 0x17, 0x7f, 0xef, 0x7f,
1080
3
       0x95, 0x95, 0x71, 0xd3, 0xa3, 0x0b, 0x71, 0xa3, 0xad, 0x0b, 0x3b, 0xb5, 0xfb, 0xa3, 0xbf, 0x4f, 0x83, 0x1d, 0xad,
1081
3
       0xe9, 0x2f, 0x71, 0x65, 0xa3, 0xe5, 0x07, 0x35, 0x3d, 0x0d, 0xb5, 0xe9, 0xe5, 0x47, 0x3b, 0x9d, 0xef, 0x35, 0xa3,
1082
3
       0xbf, 0xb3, 0xdf, 0x53, 0xd3, 0x97, 0x53, 0x49, 0x71, 0x07, 0x35, 0x61, 0x71, 0x2f, 0x43, 0x2f, 0x11, 0xdf, 0x17,
1083
3
       0x97, 0xfb, 0x95, 0x3b, 0x7f, 0x6b, 0xd3, 0x25, 0xbf, 0xad, 0xc7, 0xc5, 0xc5, 0xb5, 0x8b, 0xef, 0x2f, 0xd3, 0x07,
1084
3
       0x6b, 0x25, 0x49, 0x95, 0x25, 0x49, 0x6d, 0x71, 0xc7},
1085
3
      {0xa7, 0xbc, 0xc9, 0xad, 0x91, 0xdf, 0x85, 0xe5, 0xd4, 0x78, 0xd5, 0x17, 0x46, 0x7c, 0x29, 0x4c, 0x4d, 0x03, 0xe9,
1086
3
       0x25, 0x68, 0x11, 0x86, 0xb3, 0xbd, 0xf7, 0x6f, 0x61, 0x22, 0xa2, 0x26, 0x34, 0x2a, 0xbe, 0x1e, 0x46, 0x14, 0x68,
1087
3
       0x9d, 0x44, 0x18, 0xc2, 0x40, 0xf4, 0x7e, 0x5f, 0x1b, 0xad, 0x0b, 0x94, 0xb6, 0x67, 0xb4, 0x0b, 0xe1, 0xea, 0x95,
1088
3
       0x9c, 0x66, 0xdc, 0xe7, 0x5d, 0x6c, 0x05, 0xda, 0xd5, 0xdf, 0x7a, 0xef, 0xf6, 0xdb, 0x1f, 0x82, 0x4c, 0xc0, 0x68,
1089
3
       0x47, 0xa1, 0xbd, 0xee, 0x39, 0x50, 0x56, 0x4a, 0xdd, 0xdf, 0xa5, 0xf8, 0xc6, 0xda, 0xca, 0x90, 0xca, 0x01, 0x42,
1090
3
       0x9d, 0x8b, 0x0c, 0x73, 0x43, 0x75, 0x05, 0x94, 0xde, 0x24, 0xb3, 0x80, 0x34, 0xe5, 0x2c, 0xdc, 0x9b, 0x3f, 0xca,
1091
3
       0x33, 0x45, 0xd0, 0xdb, 0x5f, 0xf5, 0x52, 0xc3, 0x21, 0xda, 0xe2, 0x22, 0x72, 0x6b, 0x3e, 0xd0, 0x5b, 0xa8, 0x87,
1092
3
       0x8c, 0x06, 0x5d, 0x0f, 0xdd, 0x09, 0x19, 0x93, 0xd0, 0xb9, 0xfc, 0x8b, 0x0f, 0x84, 0x60, 0x33, 0x1c, 0x9b, 0x45,
1093
3
       0xf1, 0xf0, 0xa3, 0x94, 0x3a, 0x12, 0x77, 0x33, 0x4d, 0x44, 0x78, 0x28, 0x3c, 0x9e, 0xfd, 0x65, 0x57, 0x16, 0x94,
1094
3
       0x6b, 0xfb, 0x59, 0xd0, 0xc8, 0x22, 0x36, 0xdb, 0xd2, 0x63, 0x98, 0x43, 0xa1, 0x04, 0x87, 0x86, 0xf7, 0xa6, 0x26,
1095
3
       0xbb, 0xd6, 0x59, 0x4d, 0xbf, 0x6a, 0x2e, 0xaa, 0x2b, 0xef, 0xe6, 0x78, 0xb6, 0x4e, 0xe0, 0x2f, 0xdc, 0x7c, 0xbe,
1096
3
       0x57, 0x19, 0x32, 0x7e, 0x2a, 0xd0, 0xb8, 0xba, 0x29, 0x00, 0x3c, 0x52, 0x7d, 0xa8, 0x49, 0x3b, 0x2d, 0xeb, 0x25,
1097
3
       0x49, 0xfa, 0xa3, 0xaa, 0x39, 0xa7, 0xc5, 0xa7, 0x50, 0x11, 0x36, 0xfb, 0xc6, 0x67, 0x4a, 0xf5, 0xa5, 0x12, 0x65,
1098
3
       0x7e, 0xb0, 0xdf, 0xaf, 0x4e, 0xb3, 0x61, 0x7f, 0x2f},
1099
3
  };
1100
3
  Exiv2::byte key = 0;
1101
15
  for (int i = 0; i < 4; ++i) {
1102
12
    key ^= static_cast<Exiv2::byte>(count >> (i * 8));
1103
12
  }
1104
3
  Exiv2::byte ci = xlat[0][serial & 0xff];
1105
3
  Exiv2::byte cj = xlat[1][key];
1106
3
  Exiv2::byte ck = 0x60;
1107
84
  for (uint32_t i = 0; i < size; ++i) {
1108
81
    cj += ci * ck++;
1109
81
    pData[i] ^= cj;
1110
81
  }
1111
3
}
1112
}  // namespace