1 /*
2 * This file is part of RawTherapee.
3 *
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5 * Some parts of the source code (e.g. ciff support) are taken from dcraw
6 * that is copyrighted by Dave Coffin
7 *
8 * RawTherapee is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * RawTherapee is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
20 */
21 #include <cstdio>
22 #include <iostream>
23 #include <cmath>
24 #include <cstring>
25 #include <ctime>
26 #include <sstream>
27 #include <stdint.h>
28 #include <tiff.h>
29
30 #include <glib/gstdio.h>
31 #include <glib/gunicode.h>
32 #include <glibmm/keyfile.h>
33
34 #include "rtexif.h"
35
36 #include "../rtengine/procparams.h"
37
38 #include "../rtgui/cacheimagedata.h"
39 #include "../rtgui/version.h"
40 #include "../rtgui/ppversion.h"
41
42 // see end of ExifManager::parse(bool, bool)
43 #define PRINT_METADATA_TREE 0
44
45 using namespace std;
46
47 namespace rtexif
48 {
49
50 Interpreter stdInterpreter;
51
52 //--------------- class TagDirectory ------------------------------------------
53 // this class is a collection (an array) of tags
54 //-----------------------------------------------------------------------------
55
TagDirectory()56 TagDirectory::TagDirectory ()
57 : attribs (ifdAttribs), order (HOSTORDER), parent (nullptr), parseJPEG(true) {}
58
TagDirectory(TagDirectory * p,const TagAttrib * ta,ByteOrder border)59 TagDirectory::TagDirectory (TagDirectory* p, const TagAttrib* ta, ByteOrder border)
60 : attribs (ta), order (border), parent (p), parseJPEG(true) {}
61
TagDirectory(TagDirectory * p,FILE * f,int base,const TagAttrib * ta,ByteOrder border,bool skipIgnored,bool parseJpeg)62 TagDirectory::TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border, bool skipIgnored, bool parseJpeg)
63 : attribs (ta), order (border), parent (p), parseJPEG(parseJpeg)
64 {
65
66 int numOfTags = get2 (f, order);
67
68 if (numOfTags <= 0 || numOfTags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit
69 return;
70 }
71
72 bool thumbdescr = false;
73
74 for (int i = 0; i < numOfTags; i++) {
75
76 Tag* newTag = new Tag (this, f, base);
77
78 // filter out tags with unknown type
79 if ((int)newTag->getType() == 0) {
80 delete newTag;
81 continue;
82 }
83
84 if (skipIgnored) {
85 int id = newTag->getID();
86
87 // detect and possibly ignore tags of directories belonging to the embedded thumbnail image
88 if (attribs == ifdAttribs && id == TIFFTAG_SUBFILETYPE && newTag->toInt() != 0) {
89 thumbdescr = true;
90 }
91
92 const TagAttrib* attrib = getAttrib (id);
93
94 if (!attrib || attrib->ignore == 1 || (thumbdescr && attrib->ignore == 2)) {
95 delete newTag;
96 } else {
97 addTag (newTag);
98 }
99 } else {
100 addTag (newTag);
101 }
102 }
103 }
104
~TagDirectory()105 TagDirectory::~TagDirectory ()
106 {
107
108 for (size_t i = 0; i < tags.size(); i++) {
109 delete tags[i];
110 }
111 }
112
113 class CompareTags
114 {
115 public:
operator ()(Tag * const & a,Tag * const & b) const116 int operator() (Tag* const& a, Tag* const& b) const
117 {
118 return a->getID() < b->getID();
119 }
120 };
121
sort()122 void TagDirectory::sort ()
123 {
124
125 std::sort (tags.begin(), tags.end(), CompareTags());
126
127 for (size_t i = 0; i < tags.size(); i++)
128 if (tags[i]->isDirectory())
129 for (int j = 0; tags[i]->getDirectory (j); j++) {
130 tags[i]->getDirectory (j)->sort ();
131 }
132 }
getRoot()133 TagDirectory* TagDirectory::getRoot()
134 {
135 if (parent) {
136 return parent->getRoot();
137 } else {
138 return this;
139 }
140 }
141
getAttrib(int id)142 const TagAttrib* TagDirectory::getAttrib (int id)
143 {
144
145 if (attribs)
146 for (int i = 0; attribs[i].ignore != -1; i++)
147 if (attribs[i].ID == id) {
148 return &attribs[i];
149 }
150
151 return nullptr;
152 }
153
getAttrib(const char * name)154 const TagAttrib* TagDirectory::getAttrib (const char* name)
155 {
156
157 if (attribs)
158 for (int i = 0; attribs[i].ignore != -1; i++)
159 if (!strcmp (attribs[i].name, name)) {
160 return &attribs[i];
161 }
162
163 return nullptr;
164 }
165
getAttribP(const char * name)166 const TagAttrib* TagDirectory::getAttribP (const char* name)
167 {
168
169 if (attribs)
170 for (int i = 0; attribs[i].ignore != -1; i++) {
171 // Yeah, self made comparison!
172 const char *n = name;
173 const char *a = attribs[i].name;
174
175 while (*n && *a && *n == *a) {
176 n++;
177 a++;
178 };
179
180 if (!*a && (!*n || *n == '/')) {
181 // we reached the end of the subpart of name and the end of attribs->name, so they match
182 if (*n == '/') {
183 Tag* tag = getTag (attribs[i].ID);
184 TagDirectory *tagDir;
185
186 if (attribs[i].subdirAttribs && tag && (tagDir = tag->getDirectory())) {
187 return tagDir->getAttribP (n + 1);
188 } else {
189 return nullptr;
190 }
191 } else {
192 return &attribs[i];
193 }
194 }
195 }
196
197 return nullptr;
198 }
199
printAll(unsigned int level) const200 void TagDirectory::printAll (unsigned int level) const
201 {
202
203 // set the spacer prefix string
204 char prefixStr[level * 4 + 1];
205 unsigned int i;
206
207 for (i = 0; i < level * 4; i++) {
208 prefixStr[i] = ' ';
209 }
210
211 prefixStr[i] = '\0';
212
213 // recursively iterate over the tag list
214 for (size_t i = 0; i < tags.size(); i++) {
215 std::string name = tags[i]->nameToString ();
216
217 TagDirectory* currTagDir;
218 if (tags[i]->isDirectory()) {
219 for (int j = 0; (currTagDir = tags[i]->getDirectory (j)) != nullptr; j++) {
220 printf ("%s+-- DIRECTORY %s[%d]:\n", prefixStr, name.c_str(), j);
221 currTagDir->printAll (level + 1);
222 }
223 } else {
224 printf ("%s- %s\n", prefixStr, name.c_str());
225 }
226 }
227 }
228
229 /** @brief Dump the TagDirectory and its sub-directories to the file 'fname'
230 *
231 * This method has been created to dump the metadata for the Custom Profile Builders.
232 * It contains an [RT General] section to communicate some parameters, then the TagDirectory follows.
233 *
234 * The key is composed as follow: "010F_Make", i.e. "tag number or ID _ tag name"
235 * Entries like:
236 *
237 * 927C_MakerNotesSony=$subdir
238 *
239 * indicates that this tag refer to a sub-directory. RT's Keywords begins with $, where & is the first char of the value.
240 * $subdir is the only keyword so far.
241 *
242 * You'll have then to check for the [EXIF/927C_MakerNotesSony] section, given that the root section
243 * is named [EXIF].
244 *
245 * WARNING: Some string will be sanitized, i.e. the new line char will be replaced by "\n". You'll
246 * have to check for this escape string if you want a correct display of the value, but your KeyFile module
247 * will most likely handle that automatically for you.
248 *
249 * @param commFNname Absolute path of the temporary communication file's name
250 * @param commFNname Absolute path of the image's file name
251 * @param commFNname Absolute path of the output profiles's file name
252 * @param defaultPParams absolute or relative path (to the application's folder) of the default ProcParams to use
253 * @param cfs pointer to a CacheImageData object that will contain common values
254 * @param flagMode will tell whether the Custom Profile Builder is called for on flagging event or for real development
255 * @param keyfile The KeyFile object to dump to. Has to be NULL (default value) on first call!
256 * @param tagDirName Name of the current TagDirectory (full path, i.e. "EXIF/MakerNotes/LensInfo"). Can be empty on first call, "EXIF" will then be used
257 *
258 * @return True if everything went fine, false otherwise
259 */
CPBDump(const Glib::ustring & commFName,const Glib::ustring & imageFName,const Glib::ustring & profileFName,const Glib::ustring & defaultPParams,const CacheImageData * cfs,const bool flagMode,Glib::KeyFile * keyFile,Glib::ustring tagDirName) const260 bool TagDirectory::CPBDump (const Glib::ustring &commFName, const Glib::ustring &imageFName, const Glib::ustring &profileFName, const Glib::ustring &defaultPParams,
261 const CacheImageData* cfs, const bool flagMode, Glib::KeyFile *keyFile, Glib::ustring tagDirName) const
262 {
263 const auto kf = keyFile ? keyFile : new Glib::KeyFile;
264
265 if (!kf) {
266 return false;
267 }
268
269 if (!keyFile || tagDirName.empty()) {
270 tagDirName = "EXIF";
271 }
272
273 std::vector<const TagDirectory *> tagDirList;
274 std::vector<Glib::ustring> tagDirPaths;
275
276 FILE *f = nullptr;
277
278 if (!keyFile) {
279 // open the file in write mode
280 f = g_fopen (commFName.c_str (), "wt");
281
282 if (f == nullptr) {
283 printf ("TagDirectory::keyFileDump(\"%s\") >>> Error: unable to open file with write access!\n", commFName.c_str());
284 delete kf;
285 return false;
286 }
287
288 try {
289
290 kf->set_string ("RT General", "CachePath", options.cacheBaseDir);
291 kf->set_string ("RT General", "AppVersion", RTVERSION);
292 kf->set_integer ("RT General", "ProcParamsVersion", PPVERSION);
293 kf->set_string ("RT General", "ImageFileName", imageFName);
294 kf->set_string ("RT General", "OutputProfileFileName", profileFName);
295 kf->set_string ("RT General", "DefaultProcParams", defaultPParams);
296 kf->set_boolean ("RT General", "FlaggingMode", flagMode);
297
298 kf->set_integer ("Common Data", "FrameCount", cfs->frameCount);
299 kf->set_integer ("Common Data", "SampleFormat", cfs->sampleFormat);
300 kf->set_boolean ("Common Data", "IsHDR", cfs->isHDR);
301 kf->set_boolean ("Common Data", "IsPixelShift", cfs->isPixelShift);
302 kf->set_double ("Common Data", "FNumber", cfs->fnumber);
303 kf->set_double ("Common Data", "Shutter", cfs->shutter);
304 kf->set_double ("Common Data", "FocalLength", cfs->focalLen);
305 kf->set_integer ("Common Data", "ISO", cfs->iso);
306 kf->set_string ("Common Data", "Lens", cfs->lens);
307 kf->set_string ("Common Data", "Make", cfs->camMake);
308 kf->set_string ("Common Data", "Model", cfs->camModel);
309
310 } catch (Glib::KeyFileError&) {}
311 }
312
313 // recursively iterate over the tag list
314 for (size_t i = 0; i < tags.size(); i++) {
315 std::string tagName = tags[i]->nameToString ();
316
317 if (tags[i]->isDirectory())
318 for (int j = 0; tags[i]->getDirectory (j); j++) {
319 // Accumulating the TagDirectories to dump later
320 tagDirPaths.push_back ( Glib::ustring ( tagDirName + "/" + getDumpKey (tags[i]->getID(), tagName) ) );
321 tagDirList.push_back (tags[i]->getDirectory (j));
322
323 try {
324 kf->set_string (tagDirName, getDumpKey (tags[i]->getID(), tagName), "$subdir");
325 } catch (Glib::KeyFileError&) {}
326 } else {
327 try {
328 kf->set_string (tagDirName, getDumpKey (tags[i]->getID(), tagName), tags[i]->valueToString());
329 } catch (Glib::KeyFileError&) {}
330 }
331 }
332
333 // dumping the sub-directories
334 for (size_t i = 0; i < tagDirList.size(); i++) {
335 tagDirList.at (i)->CPBDump (commFName, imageFName, profileFName, defaultPParams, cfs, flagMode, kf, tagDirPaths.at (i));
336 }
337
338 if (!keyFile) {
339 try {
340 fprintf (f, "%s", kf->to_data().c_str());
341 } catch (Glib::KeyFileError&) {}
342
343 fclose (f);
344 delete kf;
345 }
346
347 return true;
348 }
349
getDumpKey(int tagID,const Glib::ustring & tagName)350 Glib::ustring TagDirectory::getDumpKey (int tagID, const Glib::ustring &tagName)
351 {
352 Glib::ustring key;
353
354 if (options.CPBKeys == CPBKT_TID || options.CPBKeys == CPBKT_TID_NAME) {
355 key = Glib::ustring (Glib::ustring::format (std::fixed, std::hex, std::setfill (L'0'), std::setw (4), tagID));
356 }
357
358 if (options.CPBKeys == CPBKT_TID_NAME) {
359 key += Glib::ustring ("_");
360 }
361
362 if (options.CPBKeys == CPBKT_TID_NAME || options.CPBKeys == CPBKT_NAME) {
363 key += Glib::ustring (tagName);
364 }
365
366 return key;
367 }
addTag(Tag * & tag)368 void TagDirectory::addTag (Tag* &tag)
369 {
370
371 // look up if it already exists:
372 if (getTag (tag->getID())) {
373 delete tag;
374 tag = nullptr;
375 } else {
376 tags.push_back (tag);
377 }
378 }
379
addTagFront(Tag * & tag)380 void TagDirectory::addTagFront (Tag* &tag)
381 {
382
383 // look up if it already exists:
384 if (getTag (tag->getID())) {
385 delete tag;
386 tag = nullptr;
387 } else {
388 tags.insert (tags.begin(), tag);
389 }
390 }
391
replaceTag(Tag * tag)392 void TagDirectory::replaceTag (Tag* tag)
393 {
394
395 // look up if it already exists:
396 for (size_t i = 0; i < tags.size(); i++)
397 if (tags[i]->getID() == tag->getID()) {
398 delete tags[i];
399 tags[i] = tag;
400 return;
401 }
402
403 tags.push_back (tag);
404 }
405
getTag(int ID) const406 Tag* TagDirectory::getTag (int ID) const
407 {
408
409 for (size_t i = 0; i < tags.size(); i++)
410 if (tags[i]->getID() == ID) {
411 return tags[i];
412 }
413
414 return nullptr;
415 }
416
getTag(const char * name) const417 Tag* TagDirectory::getTag (const char* name) const
418 {
419
420 if (attribs) {
421 for (int i = 0; attribs[i].ignore != -1; i++)
422 if (!strcmp (attribs[i].name, name)) {
423 return getTag (attribs[i].ID);
424 }
425 }
426
427 return nullptr;
428 }
429
getTagP(const char * name) const430 Tag* TagDirectory::getTagP (const char* name) const
431 {
432
433 if (attribs)
434 for (int i = 0; attribs[i].ignore != -1; i++) {
435 // Yeah, self made comparison!
436 const char *n = name;
437 const char *a = attribs[i].name;
438
439 while (*n && *a && *n == *a) {
440 n++;
441 a++;
442 };
443
444 if (!*a && (!*n || *n == '/')) {
445 // we reached the end of the subpart of name and the end of attribs->name, so they match
446 if (*n == '/') {
447 Tag* tag = getTag (attribs[i].ID);
448 TagDirectory *tagDir;
449
450 if (attribs[i].subdirAttribs && tag && (tagDir = tag->getDirectory())) {
451 return tagDir->getTagP (n + 1);
452 } else {
453 return nullptr;
454 }
455 } else {
456 return getTag (attribs[i].ID);
457 }
458 }
459 }
460
461 return nullptr;
462 }
463
findTag(const char * name,bool lookUpward) const464 Tag* TagDirectory::findTag (const char* name, bool lookUpward) const
465 {
466 Tag* t = getTag(name);
467 if (t) {
468 return t;
469 }
470
471 Tag* foundTag = nullptr;
472 int tagDistance = 10000;
473
474 for (auto tag : tags) {
475 if (tag->isDirectory()) {
476 TagDirectory *dir;
477 int i = 0;
478 // Find the shortest path to that tag
479 while ((dir = tag->getDirectory(i)) != nullptr) {
480 TagDirectory *dir = tag->getDirectory();
481 Tag* t = dir->findTag (name);
482
483 if (t) {
484 int currTagDistance = t->getDistanceFrom(this);
485 if (currTagDistance < tagDistance) {
486 tagDistance = currTagDistance;
487 foundTag = t;
488 }
489 }
490 ++i;
491 }
492 }
493 }
494
495 if (foundTag) {
496 return foundTag;
497 }
498
499 if (lookUpward && parent) {
500 Tag* t = parent->findTagUpward(name);
501
502 if (t) {
503 return t;
504 }
505 }
506
507 return nullptr;
508 }
509
findTags(int ID)510 std::vector<const Tag*> TagDirectory::findTags (int ID)
511 {
512
513 std::vector<const Tag*> tagList;
514
515 //assuming that an entry can only exist once
516 Tag* t = getTag(ID);
517 if (t) {
518 tagList.push_back(t);
519 }
520
521 for (auto tag : tags) {
522 if (tag->isDirectory()) {
523 TagDirectory *dir;
524 int i = 0;
525 while ((dir = tag->getDirectory(i)) != nullptr) {
526 std::vector<const Tag*> subTagList = dir->findTags (ID);
527
528 if (!subTagList.empty()) {
529 // concatenating the 2 vectors
530 // not really optimal in a memory efficiency pov
531 for (auto tag2 : subTagList) {
532 tagList.push_back(tag2);
533 }
534 }
535 ++i;
536 }
537 }
538 }
539
540 return tagList;
541 }
542
findTags(const char * name)543 std::vector<const Tag*> TagDirectory::findTags (const char* name)
544 {
545
546 std::vector<const Tag*> tagList;
547
548 //assuming that an entry can only exist once
549 Tag* t = getTag(name);
550 if (t) {
551 tagList.push_back(t);
552 }
553
554 for (auto tag : tags) {
555 if (tag->isDirectory()) {
556 TagDirectory *dir;
557 int i = 0;
558 while ((dir = tag->getDirectory(i)) != nullptr) {
559 std::vector<const Tag*> subTagList = dir->findTags (name);
560
561 if (!subTagList.empty()) {
562 // concatenating the 2 vectors
563 // not really optimal in a memory efficiency pov, but adding 10 items should be a maximum
564 for (auto tag2 : subTagList) {
565 tagList.push_back(tag2);
566 }
567 }
568 ++i;
569 }
570 }
571 }
572
573 return tagList;
574 }
575
576
findTagUpward(const char * name) const577 Tag* TagDirectory::findTagUpward (const char* name) const
578 {
579 Tag* t = findTag(name);
580 if (t) {
581 return t;
582 }
583
584 if (parent) {
585 Tag* t = parent->findTagUpward(name);
586
587 if (t) {
588 return t;
589 }
590 }
591
592 return nullptr;
593 }
594
595
596 // Searches a simple value, as either attribute or element
597 // only for simple values, not for entries with special chars or free text
getXMPTagValue(const char * name,char * value) const598 bool TagDirectory::getXMPTagValue (const char* name, char* value) const
599 {
600 *value = 0;
601
602 if (!getTag ("ApplicationNotes")) {
603 return false;
604 }
605
606 char *sXMP = (char*)getTag ("ApplicationNotes")->getValue();
607
608 // Check for full word
609 char *pos = sXMP;
610
611 bool found = false;
612
613 do {
614 pos = strstr (pos, name);
615
616 if (pos) {
617 char nextChar = * (pos + strlen (name));
618
619 if (nextChar == ' ' || nextChar == '>' || nextChar == '=') {
620 found = true;
621 } else {
622 pos += strlen (name);
623 }
624 }
625 } while (pos && !found);
626
627 if (!found) {
628 return false;
629 }
630
631 char *posTag = strchr (pos, '>');
632 char *posAttr = strchr (pos, '"');
633
634 if (!posTag && !posAttr) {
635 return false;
636 }
637
638 if (posTag && (!posAttr || posTag < posAttr)) {
639 // Tag
640 pos = strchr (posTag + 1, '<');
641 strncpy (value, posTag + 1, pos - posTag - 1);
642 value[pos - posTag - 1] = 0;
643 return true;
644 } else if (posAttr && (!posTag || posAttr < posTag)) {
645 // Attribute
646 pos = strchr (posAttr + 1, '"');
647 strncpy (value, posAttr + 1, pos - posAttr - 1);
648 value[pos - posAttr - 1] = 0;
649 return true;
650 } else {
651 return false;
652 }
653 }
654
keepTag(int ID)655 void TagDirectory::keepTag (int ID)
656 {
657 for (size_t i = 0; i < tags.size(); i++)
658 if (tags[i]->getID() == ID) {
659 tags[i]->setKeep (true);
660 }
661 }
662
calculateSize()663 int TagDirectory::calculateSize ()
664 {
665
666 int size = 2; // space to store the number of tags
667
668 for (size_t i = 0; i < tags.size(); i++)
669 if (tags[i]->getKeep()) {
670 size += 12 + tags[i]->calculateSize ();
671 }
672
673 size += 4; // next ifd pointer
674 return size;
675 }
676
clone(TagDirectory * parent) const677 TagDirectory* TagDirectory::clone (TagDirectory* parent) const
678 {
679
680 TagDirectory* td = new TagDirectory (parent, attribs, order);
681
682 for (size_t i = 0; i < tags.size(); i++) {
683 td->tags.push_back (tags[i]->clone (td));
684 }
685
686 return td;
687 }
688
write(int start,unsigned char * buffer)689 int TagDirectory::write (int start, unsigned char* buffer)
690 {
691
692 int size = calculateSize ();
693 int tagnum = 0;
694 int nondirspace = 0;
695
696 for (size_t i = 0; i < tags.size(); i++)
697 if (tags[i]->getKeep()) {
698 tagnum++;
699
700 if (!tags[i]->isDirectory()) {
701 nondirspace += tags[i]->calculateSize();
702 }
703 }
704
705 int nextValOffs = start + 2 + tagnum * 12 + 4;
706 int nextDirOffs = nextValOffs + nondirspace;
707 int pos = start;
708 sset2 (tagnum, buffer + start, order);
709 pos += 2;
710 int maxPos = start + size;
711
712 for (size_t i = 0; i < tags.size(); i++) {
713 if (tags[i]->getKeep()) {
714 if (!tags[i]->isDirectory()) {
715 nextValOffs = tags[i]->write (pos, nextValOffs, buffer); // pos: where to put the tag, dataoffset: the place where the value can be put. return: next data offset
716 } else {
717 nextDirOffs = tags[i]->write (pos, nextDirOffs, buffer); // pos: where to put the tag, dataoffset: the place where the value can be put. return: next data offset
718 }
719
720 pos += 12;
721 }
722 }
723
724 sset4 (0, buffer + pos, order);
725 return maxPos;
726 }
727
applyChange(const std::string & name,const Glib::ustring & value)728 void TagDirectory::applyChange (const std::string &name, const Glib::ustring &value)
729 {
730
731 std::string::size_type dp = name.find_first_of ('.');
732 std::string fseg = name.substr (0, dp);
733
734 // this is a final segment: apply change
735 if (dp == std::string::npos) {
736
737 Tag* t = nullptr;
738
739 for (size_t i = 0; i < tags.size(); i++)
740 if (tags[i]->nameToString() == fseg) {
741 t = tags[i];
742 break;
743 }
744
745 if (value == "#keep" && t) {
746 t->setKeep (true);
747 } else if (value == "#delete" && t) {
748 t->setKeep (false);
749 } else if (t && !t->isDirectory()) {
750 if (name == "UserComment") {
751 // UserComment can be Unicode
752 t->userCommentFromString (value);
753 } else {
754 t->valueFromString (value);
755 }
756 } else {
757 const TagAttrib* attrib = nullptr;
758
759 for (int i = 0; attribs[i].ignore != -1; i++) {
760 if (!strcmp (attribs[i].name, fseg.c_str())) {
761 attrib = &attribs[i];
762 break;
763 }
764 }
765
766 if (attrib) {
767 Tag* nt = new Tag (this, attrib);
768 if (name == "UserComment") {
769 // UserComment can be Unicode
770 nt->initUserComment (value);
771 } else {
772 nt->initString (value.c_str());
773 }
774 addTag (nt);
775 }
776 }
777 }
778 // this is a subdirectory
779 else {
780 // try to find it
781 std::string::size_type dp1 = fseg.find_first_of ('[');
782 std::string basename = fseg.substr (0, dp1);
783 Tag* t = nullptr;
784 int dirnum = -1;
785
786 for (size_t i = 0; i < tags.size(); i++)
787 if (tags[i]->isDirectory()) {
788 for (int j = 0; tags[i]->getDirectory (j); j++) {
789 if (tags[i]->nameToString (j) == fseg) {
790 t = tags[i];
791 dirnum = j;
792 break;
793 }
794 }
795
796 if (!t && tags[i]->nameToString() == basename) { // found it, but that directory index does not exist
797 t = tags[i];
798 dirnum = -1;
799 }
800 }
801
802 if (!t && value != "#keep" && value != "#delete") {
803 const TagAttrib* attrib = nullptr;
804
805 for (int i = 0; attribs[i].ignore != -1; i++)
806 if (!strcmp (attribs[i].name, fseg.c_str())) {
807 attrib = &attribs[i];
808 break;
809 }
810
811 if (attrib && attrib->subdirAttribs) {
812 t = new Tag (this, attrib);
813 t->initSubDir ();
814 addTag (t);
815 }
816
817 dirnum = 0;
818 }
819
820 if (t && dirnum >= 0) {
821 t->getDirectory (dirnum)->applyChange (name.substr (dp + 1, std::string::npos), value);
822 }
823 }
824 }
825
TagDirectoryTable()826 TagDirectoryTable::TagDirectoryTable ()
827 : values (nullptr), zeroOffset (0), valuesSize (0), defaultType (INVALID)
828 {
829 }
830
TagDirectoryTable(TagDirectory * p,unsigned char * v,int memsize,int offs,TagType type,const TagAttrib * ta,ByteOrder border)831 TagDirectoryTable::TagDirectoryTable (TagDirectory* p, unsigned char *v, int memsize, int offs, TagType type, const TagAttrib* ta, ByteOrder border)
832 : TagDirectory (p, ta, border), zeroOffset (offs), valuesSize (memsize), defaultType ( type )
833 {
834 values = new unsigned char[valuesSize];
835 memcpy (values, v, valuesSize);
836
837 // Security ; will avoid to read above the buffer limit if the RT's tagDirectoryTable is longer that what's in the file
838 int count = valuesSize / getTypeSize (type);
839
840 for (const TagAttrib* tattr = ta; tattr->ignore != -1 && tattr->ID < count; ++tattr) {
841 Tag* newTag = new Tag (this, tattr, (values + zeroOffset + tattr->ID * getTypeSize (type)), tattr->type == AUTO ? type : tattr->type);
842 tags.push_back (newTag); // Here we can insert more tag in the same offset because of bitfield meaning
843 }
844 }
845
TagDirectoryTable(TagDirectory * p,FILE * f,int memsize,int offs,TagType type,const TagAttrib * ta,ByteOrder border)846 TagDirectoryTable::TagDirectoryTable (TagDirectory* p, FILE* f, int memsize, int offs, TagType type, const TagAttrib* ta, ByteOrder border)
847 : TagDirectory (p, ta, border), zeroOffset (offs), valuesSize (memsize), defaultType ( type )
848 {
849 values = new unsigned char[valuesSize];
850 if (fread (values, 1, valuesSize, f) == static_cast<size_t>(valuesSize)) {
851
852 // Security ; will avoid to read above the buffer limit if the RT's tagDirectoryTable is longer that what's in the file
853 int count = valuesSize / getTypeSize (type);
854
855 for (const TagAttrib* tattr = ta; tattr->ignore != -1 && tattr->ID < count; ++tattr) {
856 Tag* newTag = new Tag (this, tattr, (values + zeroOffset + tattr->ID * getTypeSize (type)), tattr->type == AUTO ? type : tattr->type);
857 tags.push_back (newTag); // Here we can insert more tag in the same offset because of bitfield meaning
858 }
859 }
860 }
clone(TagDirectory * parent) const861 TagDirectory* TagDirectoryTable::clone (TagDirectory* parent) const
862 {
863
864 TagDirectory* td = new TagDirectoryTable (parent, values, valuesSize, zeroOffset, defaultType, attribs, order);
865 return td;
866 }
867
~TagDirectoryTable()868 TagDirectoryTable::~TagDirectoryTable()
869 {
870 if (values) {
871 delete [] values;
872 }
873 }
calculateSize()874 int TagDirectoryTable::calculateSize ()
875 {
876 return valuesSize;
877 }
878
write(int start,unsigned char * buffer)879 int TagDirectoryTable::write (int start, unsigned char* buffer)
880 {
881 if ( values && valuesSize) {
882 memcpy (buffer + start, values, valuesSize);
883 return start + valuesSize;
884 } else {
885 return start;
886 }
887 }
888
889 //--------------- class Tag ---------------------------------------------------
890 // this class represents a tag stored in the directory
891 //-----------------------------------------------------------------------------
892
Tag(TagDirectory * p,FILE * f,int base)893 Tag::Tag (TagDirectory* p, FILE* f, int base)
894 : type (INVALID), count (0), value (nullptr), allocOwnMemory (true), attrib (nullptr), parent (p), directory (nullptr)
895 {
896
897 ByteOrder order = getOrder();
898
899 tag = get2 (f, order);
900 type = (TagType)get2 (f, order);
901 count = get4 (f, order);
902
903 if (!count) {
904 count = 1;
905 }
906
907 makerNoteKind = NOMK;
908 keep = false;
909
910 // filter out invalid tags
911 // note the large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes,
912 // (only a small part of it will actually be parsed though)
913 if ((int)type < 1 || (int)type > 14 || count > 10 * 1024 * 1024) {
914 type = INVALID;
915 valuesize = 0;
916 return;
917 }
918
919 // store next Tag's position in file
920 int save = ftell (f) + 4;
921
922 // load value field (possibly seek before)
923 valuesize = count * getTypeSize (type);
924
925 if (valuesize > 4) {
926 fseek (f, get4 (f, getOrder()) + base, SEEK_SET);
927 }
928
929 attrib = parent->getAttrib (tag);
930
931 if (attrib && (attrib->action == AC_WRITE || attrib->action == AC_NEW)) {
932 keep = true;
933 }
934
935 if ( tag == 0xc634 ) { // DNGPrivateData
936 int currPos = ftell (f);
937 const int buffersize = 32;
938 char buffer[buffersize], *p = buffer;
939
940 while ( fread (p, 1, 1, f ) && *p != 0 && p - buffer < buffersize - 1 ) {
941 p++;
942 }
943
944 *p = 0;
945
946 if ( !strncmp (buffer, "Adobe", 5) ) {
947 fread (buffer, 1, 14, f );
948
949 if ( !strncmp ( buffer, "MakN", 4) ) {
950 ByteOrder bom = ((buffer[8] == 'M' && buffer[9] == 'M') ? MOTOROLA : INTEL) ;
951 Tag* tmake = parent->getRoot()->findTag ("Make");
952 std::string make ( tmake ? tmake->valueToString() : "");
953 int save = ftell (f);
954 int originalOffset = sget4 ( (unsigned char*)&buffer[10], ( make.find ("SONY") != std::string::npos ) || ( make.find ("Canon") != std::string::npos ) || ( make.find ("OLYMPUS") != std::string::npos ) ? MOTOROLA : bom );
955
956 if ( !parseMakerNote (f, save - originalOffset, bom )) {
957 type = INVALID;
958 }
959 }
960 } else if ( !strncmp (buffer, "PENTAX", 6) ) {
961 makerNoteKind = HEADERIFD;
962 fread (buffer, 1, 2, f);
963 directory = new TagDirectory*[2];
964 directory[0] = new TagDirectory (parent, f, currPos, pentaxAttribs, strncmp (buffer, "MM", 2) ? INTEL : MOTOROLA);
965 directory[1] = nullptr;
966 } else
967 /* SONY uses this tag to write hidden info and pointer to private encrypted tags
968 {
969 unsigned offset =sget4((unsigned char*)buffer, order);
970 fseek(f,offset,SEEK_SET);
971 makerNoteKind = TABLESUBDIR;
972 directory = new TagDirectory*[2];
973 directory[0] = new TagDirectory (parent, f, base, sonyDNGMakerNote, order);
974 directory[1] = NULL;
975 fseek (f, save, SEEK_SET);
976 return;
977 }*/
978 {
979 type = INVALID;
980 }
981 }
982
983 if (parent->getParseJpeg() && tag == 0x002e) { // location of the embedded preview image in raw files of Panasonic cameras
984 ExifManager eManager(f, nullptr, true);
985 const auto fpos = ftell(f);
986
987 if (fpos >= 0) {
988 eManager.parseJPEG(fpos); // try to parse the exif data from the preview image
989
990 if (eManager.roots.size()) {
991 const TagDirectory* const previewdir = eManager.roots.at(0);
992 if (previewdir->getTag ("Exif")) {
993 if (previewdir->getTag ("Make")) {
994 if (previewdir->getTag ("Make")->valueToString() == "Panasonic") { // "make" is not yet available here, so get it from the preview tags to assure we're doing the right thing
995 Tag* t = new Tag (parent->getRoot(), lookupAttrib (ifdAttribs, "Exif")); // replace raw exif with preview exif assuming there are the same
996 t->initSubDir (previewdir->getTag ("Exif")->getDirectory());
997 parent->getRoot()->addTag (t);
998 }
999 }
1000 }
1001 }
1002 }
1003 }
1004
1005 // if this tag is the makernote, it needs special treatment (brand specific parsing)
1006 if (tag == 0x927C && attrib && !strcmp (attrib->name, "MakerNote") ) {
1007 if ( !parseMakerNote (f, base, order )) {
1008 type = INVALID;
1009 fseek (f, save, SEEK_SET);
1010 return;
1011 }
1012 } else if (attrib && attrib->subdirAttribs) {
1013 // Some subdirs are specific of maker and model
1014 char make[128], model[128];
1015 make[0] = 0;
1016 model[0] = 0;
1017 Tag* tmake = parent->getRoot()->getTag ("Make");
1018
1019 if (tmake) {
1020 tmake->toString (make);
1021 }
1022
1023 Tag* tmodel = parent->getRoot()->getTag ("Model");
1024
1025 if (tmodel) {
1026 tmodel->toString (model);
1027 }
1028
1029 if (!strncmp (make, "SONY", 4)) {
1030 switch ( tag ) {
1031 case 0x0010:
1032 directory = new TagDirectory*[2];
1033 directory[1] = nullptr;
1034
1035 if (count == 15360) {
1036 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, sonyCameraInfoAttribs, order);
1037 } else {
1038 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, sonyCameraInfo2Attribs, order);
1039 }
1040
1041 break;
1042
1043 case 0x0114:
1044 directory = new TagDirectory*[2];
1045 directory[1] = nullptr;
1046
1047 if (count == 280 || count == 364) {
1048 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, SHORT, sonyCameraSettingsAttribs, MOTOROLA);
1049 } else if (count == 332) {
1050 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, SHORT, sonyCameraSettingsAttribs2, MOTOROLA);
1051 } else if (count == 1536 || count == 2048) {
1052 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, sonyCameraSettingsAttribs3, INTEL);
1053 } else {
1054 // Unknown CameraSettings
1055 delete [] directory;
1056 directory = nullptr;
1057 type = INVALID;
1058 }
1059
1060 makerNoteKind = directory ? TABLESUBDIR : NOMK;
1061 break;
1062
1063 case 0x9405:
1064 directory = new TagDirectory*[2];
1065 directory[1] = nullptr;
1066 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, SHORT, attrib->subdirAttribs, order);
1067 makerNoteKind = TABLESUBDIR;
1068 break;
1069
1070 default:
1071 goto defsubdirs;
1072 }
1073 } else if ((!strncmp (make, "PENTAX", 6)) || (!strncmp (make, "RICOH", 5) && !strncmp (model, "PENTAX", 6))) { // Either the former Pentax brand or the RICOH brand + PENTAX model"
1074 switch ( tag ) {
1075 case 0x007d:
1076 case 0x0205:
1077 case 0x0208:
1078 case 0x0216:
1079 directory = new TagDirectory*[2];
1080 directory[1] = nullptr;
1081 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, attrib->subdirAttribs, order);
1082 makerNoteKind = TABLESUBDIR;
1083 break;
1084
1085 case 0x0215:
1086 directory = new TagDirectory*[2];
1087 directory[1] = nullptr;
1088 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, LONG, attrib->subdirAttribs, order);
1089 makerNoteKind = TABLESUBDIR;
1090 break;
1091
1092 case 0x005c:
1093 directory = new TagDirectory*[2];
1094 directory[1] = nullptr;
1095
1096 if (count == 4) { // SRInfo
1097 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxSRInfoAttribs, order);
1098 } else if (count == 2) { // SRInfo2
1099 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxSRInfo2Attribs, order);
1100 } else {
1101 // Unknown SRInfo
1102 delete [] directory;
1103 directory = nullptr;
1104 type = INVALID;
1105 }
1106
1107 makerNoteKind = directory ? TABLESUBDIR : NOMK;
1108 break;
1109
1110 case 0x0206:
1111 directory = new TagDirectory*[2];
1112 directory[1] = nullptr;
1113
1114 if (count == 21) { // AEInfo2
1115 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxAEInfo2Attribs, order);
1116 } else if (count == 48) { // AEInfo3
1117 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxAEInfo3Attribs, order);
1118 } else if (count <= 25) { // AEInfo
1119 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxAEInfoAttribs, order);
1120 } else {
1121 // Unknown AEInfo
1122 delete [] directory;
1123 directory = nullptr;
1124 type = INVALID;
1125 }
1126
1127 makerNoteKind = directory ? TABLESUBDIR : NOMK;
1128 break;
1129
1130 case 0x0207: {
1131 // There are 2 format pentaxLensDataAttribs
1132 int offsetFirst = 4; // LensInfo2
1133
1134 if ( strstr (model, "*ist") || strstr (model, "GX-1") || strstr (model, "K200D") || (strstr (model, "K100D") && !strstr (model, "K100D Super")) || strstr (model, "K110D") || strstr (model, "645Z")) {
1135 offsetFirst = 3; // LensInfo
1136 } else if ( strstr (model, "645D") ) {
1137 offsetFirst = 13; // LensInfo3
1138 } else if ( strstr (model, "K-01") || strstr (model, "K-30") || strstr (model, "K-50")) {
1139 offsetFirst = 15; // LensInfo5
1140 } else if ( strstr (model, "K-5") || strstr (model, "K-r") ) {
1141 offsetFirst = 12; // LensInfo4
1142 } else if (!strncmp (make, "RICOH", 5)) { // all PENTAX camera model produced under the RICOH era uses LensInfo5, for now...
1143 offsetFirst = 15; // LensInfo5 too
1144 }
1145
1146 directory = new TagDirectory*[2];
1147 directory[1] = nullptr;
1148 directory[0] = new TagDirectoryTable (parent, f, valuesize, offsetFirst, BYTE, attrib->subdirAttribs, order);
1149 makerNoteKind = TABLESUBDIR;
1150 }
1151 break;
1152
1153 case 0x0239:
1154 directory = new TagDirectory*[2];
1155 directory[1] = nullptr;
1156 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, attrib->subdirAttribs, order);
1157 makerNoteKind = TABLESUBDIR;
1158 break;
1159
1160 default:
1161 goto defsubdirs;
1162 }
1163 } else if (!strncmp (make, "Canon", 5)) {
1164 switch ( tag ) {
1165 case 0x0001:
1166 case 0x0002:
1167 case 0x0004:
1168 case 0x0005:
1169 case 0x0093:
1170 case 0x0098:
1171 case 0x00a0:
1172 directory = new TagDirectory*[2];
1173 directory[1] = nullptr;
1174 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, SSHORT, attrib->subdirAttribs, order);
1175 makerNoteKind = TABLESUBDIR;
1176 break;
1177
1178 case 0x009a:
1179 case 0x4013:
1180 directory = new TagDirectory*[2];
1181 directory[1] = nullptr;
1182 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, LONG, attrib->subdirAttribs, order);
1183 makerNoteKind = TABLESUBDIR;
1184 break;
1185
1186 default:
1187 goto defsubdirs;
1188 }
1189 } else if (!strncmp (make, "NIKON", 5)) {
1190 switch (tag) {
1191 case 0x0025: {
1192 directory = new TagDirectory*[2];
1193 directory[1] = nullptr;
1194 directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, attrib->subdirAttribs, order);
1195 makerNoteKind = TABLESUBDIR;
1196 break;
1197 }
1198
1199 default:
1200 goto defsubdirs;
1201 }
1202 } else if (type == UNDEFINED) {
1203 count = 1;
1204 type = LONG;
1205 directory = new TagDirectory*[2];
1206 directory[0] = new TagDirectory (parent, f, base, attrib->subdirAttribs, order);
1207 directory[1] = nullptr;
1208 } else {
1209 goto defsubdirs;
1210 }
1211 } else {
1212 // read value
1213 value = new unsigned char [valuesize + 1];
1214 auto readSize = fread (value, 1, valuesize, f);
1215 value[readSize] = '\0';
1216 }
1217
1218 // seek back to the saved position
1219 fseek (f, save, SEEK_SET);
1220 return;
1221
1222 defsubdirs:
1223 // read value
1224 value = new unsigned char [valuesize];
1225 if (fread (value, 1, valuesize, f) != static_cast<size_t>(valuesize)) {
1226 type = INVALID;
1227 } else {
1228 // count the number of valid subdirs
1229 int sdcount = count;
1230
1231 if (sdcount > 0) {
1232 if (parent->getAttribTable() == olympusAttribs) {
1233 sdcount = 1;
1234 }
1235
1236 // allocate space
1237 directory = new TagDirectory*[sdcount + 1];
1238
1239 // load directories
1240 for (size_t j = 0, i = 0; j < count; j++, i++) {
1241 int newpos = base + toInt (j * 4, LONG);
1242 fseek (f, newpos, SEEK_SET);
1243 directory[i] = new TagDirectory (parent, f, base, attrib->subdirAttribs, order, true, parent->getParseJpeg());
1244 }
1245
1246 // set the terminating NULL
1247 directory[sdcount] = nullptr;
1248 } else {
1249 type = INVALID;
1250 }
1251 }
1252 // seek back to the saved position
1253 fseek (f, save, SEEK_SET);
1254 return;
1255
1256 }
1257
parseMakerNote(FILE * f,int base,ByteOrder bom)1258 bool Tag::parseMakerNote (FILE* f, int base, ByteOrder bom )
1259 {
1260 value = nullptr;
1261 Tag* tmake = parent->getRoot()->findTag ("Make");
1262 std::string make ( tmake ? tmake->valueToString() : "");
1263
1264 Tag* tmodel = parent->getRoot()->findTag ("Model");
1265 std::string model ( tmodel ? tmodel->valueToString() : "");
1266
1267 if ( make.find ( "NIKON" ) != std::string::npos ) {
1268 if ( model.find ("NIKON E700") != std::string::npos ||
1269 model.find ("NIKON E800") != std::string::npos ||
1270 model.find ("NIKON E900") != std::string::npos ||
1271 model.find ("NIKON E900S") != std::string::npos ||
1272 model.find ("NIKON E910") != std::string::npos ||
1273 model.find ("NIKON E950") != std::string::npos ) {
1274 makerNoteKind = HEADERIFD;
1275 valuesize = 8;
1276 value = new unsigned char[8];
1277 fread (value, 1, 8, f);
1278 directory = new TagDirectory*[2];
1279 directory[0] = new TagDirectory (parent, f, base, nikon2Attribs, bom);
1280 directory[1] = nullptr;
1281 } else if ( model.find ("NIKON E990") != std::string::npos ||
1282 (model.find ("NIKON D1") != std::string::npos && model.size() > 8 && model.at (8) != '0')) {
1283 makerNoteKind = IFD;
1284 directory = new TagDirectory*[2];
1285 directory[0] = new TagDirectory (parent, f, base, nikon3Attribs, bom);
1286 directory[1] = nullptr;
1287 } else {
1288 // needs refinement! (embedded tiff header parsing)
1289 makerNoteKind = NIKON3;
1290 valuesize = 18;
1291 value = new unsigned char[18];
1292 int basepos = ftell (f);
1293 fread (value, 1, 18, f);
1294 directory = new TagDirectory*[2];
1295 // byte order for makernotes can be different from exif byte order. We have to get it from makernotes header
1296 ByteOrder MakerNoteOrder;
1297
1298 if (value[10] == 'M' && value[11] == 'M') {
1299 MakerNoteOrder = rtexif::MOTOROLA;
1300 } else {
1301 MakerNoteOrder = rtexif::INTEL;
1302 }
1303
1304 directory[0] = new TagDirectory (parent, f, basepos + 10, nikon3Attribs, MakerNoteOrder);
1305 directory[1] = nullptr;
1306 }
1307 } else if ( make.find ( "Canon" ) != std::string::npos ) {
1308 makerNoteKind = IFD;
1309 directory = new TagDirectory*[2];
1310 directory[0] = new TagDirectory (parent, f, base, canonAttribs, bom);
1311 directory[1] = nullptr;
1312 } else if ( make.find ( "PENTAX" ) != std::string::npos ) {
1313 makerNoteKind = HEADERIFD;
1314 valuesize = 6;
1315 value = new unsigned char[6];
1316 fread (value, 1, 6, f);
1317 directory = new TagDirectory*[2];
1318 directory[0] = new TagDirectory (parent, f, base, pentaxAttribs, bom);
1319 directory[1] = nullptr;
1320 } else if ( (make.find ( "RICOH" ) != std::string::npos ) && (model.find ("PENTAX") != std::string::npos) ) {
1321 makerNoteKind = HEADERIFD;
1322 valuesize = 10;
1323 value = new unsigned char[10];
1324 fread (value, 1, 10, f);
1325 directory = new TagDirectory*[2];
1326 directory[0] = new TagDirectory (parent, f, ftell (f) - 10, pentaxAttribs, bom);
1327 directory[1] = nullptr;
1328 } else if ( make.find ( "FUJIFILM" ) != std::string::npos ) {
1329 makerNoteKind = FUJI;
1330 valuesize = 12;
1331 value = new unsigned char[12];
1332 fread (value, 1, 12, f);
1333 directory = new TagDirectory*[2];
1334 directory[0] = new TagDirectory (parent, f, ftell (f) - 12, fujiAttribs, INTEL);
1335 directory[1] = nullptr;
1336 } else if ( make.find ( "KONICA MINOLTA" ) != std::string::npos || make.find ( "Minolta" ) != std::string::npos ) {
1337 makerNoteKind = IFD;
1338 directory = new TagDirectory*[2];
1339 directory[0] = new TagDirectory (parent, f, base, minoltaAttribs, bom);
1340 directory[1] = nullptr;
1341 } else if ( make.find ( "SONY" ) != std::string::npos ) {
1342 valuesize = 12;
1343 value = new unsigned char[12];
1344 fread (value, 1, 12, f);
1345
1346 if (!strncmp ((char*)value, "SONY DSC", 8)) {
1347 makerNoteKind = HEADERIFD;
1348 } else {
1349 makerNoteKind = IFD;
1350 fseek (f, -12, SEEK_CUR);
1351 }
1352
1353 directory = new TagDirectory*[2];
1354 directory[0] = new TagDirectory (parent, f, base, sonyAttribs, bom );
1355 directory[1] = nullptr;
1356 } else if ( make.find ( "OLYMPUS" ) != std::string::npos ) {
1357 makerNoteKind = HEADERIFD;
1358 valuesize = 8;
1359 value = new unsigned char[12];
1360 fread (value, 1, 8, f);
1361 directory = new TagDirectory*[2];
1362 directory[1] = nullptr;
1363
1364 if (!strncmp ((char*)value, "OLYMPUS", 7)) {
1365 makerNoteKind = OLYMPUS2;
1366 fread (value + 8, 1, 4, f);
1367 valuesize = 12;
1368 directory[0] = new TagDirectory (parent, f, ftell (f) - 12, olympusAttribs, value[8] == 'I' ? INTEL : MOTOROLA);
1369 } else {
1370 directory[0] = new TagDirectory (parent, f, base, olympusAttribs, bom);
1371 }
1372 } else if ( make.find ( "Panasonic" ) != std::string::npos) {
1373 makerNoteKind = HEADERIFD;
1374 valuesize = 12;
1375 value = new unsigned char[12];
1376 fread (value, 1, 12, f);
1377 directory = new TagDirectory*[2];
1378 directory[0] = new TagDirectory (parent, f, base, panasonicAttribs, bom, true, parent->getParseJpeg());
1379 directory[1] = nullptr;
1380 } else {
1381 return false;
1382 }
1383
1384 return true;
1385 }
1386
clone(TagDirectory * parent) const1387 Tag* Tag::clone (TagDirectory* parent) const
1388 {
1389
1390 Tag* t = new Tag (parent, attrib);
1391
1392 t->tag = tag;
1393 t->type = type;
1394 t->count = count;
1395 t->keep = keep;
1396 t->valuesize = valuesize;
1397
1398 if (value) {
1399 t->value = new unsigned char [valuesize];
1400 memcpy (t->value, value, valuesize);
1401 } else {
1402 t->value = nullptr;
1403 }
1404
1405 t->makerNoteKind = makerNoteKind;
1406
1407 if (directory) {
1408 int ds = 0;
1409
1410 for (; directory[ds]; ds++);
1411
1412 t->directory = new TagDirectory*[ds + 1];
1413
1414 for (int i = 0; i < ds; i++) {
1415 t->directory[i] = directory[i]->clone (parent);
1416 }
1417
1418 t->directory[ds] = nullptr;
1419 } else {
1420 t->directory = nullptr;
1421 }
1422
1423 return t;
1424 }
1425
~Tag()1426 Tag::~Tag ()
1427 {
1428
1429 // delete value
1430 if (value && allocOwnMemory) {
1431 delete [] value;
1432 }
1433
1434 // if there are directories behind the tag, delete them
1435 if (directory) {
1436 int i = 0;
1437
1438 while (directory[i]) {
1439 delete directory[i++];
1440 }
1441
1442 delete [] directory;
1443 }
1444 }
1445
getDistanceFrom(const TagDirectory * root)1446 int Tag::getDistanceFrom(const TagDirectory *root)
1447 {
1448 int i = 0;
1449 TagDirectory *currTagDir = parent;
1450 while (currTagDir != nullptr && currTagDir != root) {
1451 ++i;
1452 if (parent->getParent() == currTagDir) {
1453 break;
1454 }
1455 currTagDir = parent->getParent();
1456 }
1457 return i;
1458 }
1459
setInt(int v,int ofs,TagType astype)1460 void Tag::setInt (int v, int ofs, TagType astype)
1461 {
1462
1463 if (astype == SHORT) {
1464 sset2 (v, value + ofs, getOrder());
1465 } else if (astype == RATIONAL) {
1466 sset4 (v, value + ofs, getOrder());
1467 sset4 (1, value + ofs + 4, getOrder());
1468 } else {
1469 sset4 (v, value + ofs, getOrder());
1470 }
1471 }
1472
fromInt(int v)1473 void Tag::fromInt (int v)
1474 {
1475
1476 if (type == SHORT) {
1477 sset2 (v, value, getOrder());
1478 } else {
1479 sset4 (v, value, getOrder());
1480 }
1481 }
1482
fromString(const char * v,int size)1483 void Tag::fromString (const char* v, int size)
1484 {
1485
1486 if ( value && allocOwnMemory) {
1487 delete [] value;
1488 }
1489
1490 if (size < 0) {
1491 valuesize = strlen (v) + 1;
1492 } else {
1493 valuesize = size;
1494 }
1495
1496 count = valuesize;
1497
1498 if ( allocOwnMemory ) {
1499 value = new unsigned char [valuesize];
1500 }
1501
1502 if(value) {
1503 memcpy ((char*)value, v, valuesize);
1504 }
1505 }
1506
toInt(int ofs,TagType astype) const1507 int Tag::toInt (int ofs, TagType astype) const
1508 {
1509 if (attrib) {
1510 return attrib->interpreter->toInt (this, ofs, astype);
1511 }
1512
1513 int a;
1514
1515 if (astype == INVALID) {
1516 astype = type;
1517 }
1518
1519 switch (astype) {
1520 //case SBYTE: return (signed char)(value[ofs]);
1521 case SBYTE:
1522 return int ((reinterpret_cast<signed char*> (value))[ofs]);
1523
1524 case BYTE:
1525 return value[ofs];
1526
1527 case ASCII:
1528 return 0;
1529
1530 case SSHORT:
1531 return (int)int2_to_signed (sget2 (value + ofs, getOrder()));
1532
1533 case SHORT:
1534 return (int)sget2 (value + ofs, getOrder());
1535
1536 case SLONG:
1537 case LONG:
1538 return (int)sget4 (value + ofs, getOrder());
1539
1540 case SRATIONAL:
1541 case RATIONAL:
1542 a = (int)sget4 (value + ofs + 4, getOrder());
1543 return a == 0 ? 0 : (int)sget4 (value + ofs, getOrder()) / a;
1544
1545 case FLOAT:
1546 return (int)toDouble (ofs);
1547
1548 case UNDEFINED:
1549 return 0;
1550
1551 default:
1552 return 0; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR)
1553 }
1554
1555 return 0;
1556 }
1557
toDouble(int ofs) const1558 double Tag::toDouble (int ofs) const
1559 {
1560 if (attrib) {
1561 return attrib->interpreter->toDouble (this, ofs);
1562 }
1563
1564 union IntFloat {
1565 uint32_t i;
1566 float f;
1567 } conv;
1568
1569 double ud, dd;
1570
1571 switch (type) {
1572 case SBYTE:
1573 return (double) (int ((reinterpret_cast<signed char*> (value))[ofs]));
1574
1575 case BYTE:
1576 return (double) ((int)value[ofs]);
1577
1578 case ASCII:
1579 return 0.0;
1580
1581 case SSHORT:
1582 return (double)int2_to_signed (sget2 (value + ofs, getOrder()));
1583
1584 case SHORT:
1585 return (double) ((int)sget2 (value + ofs, getOrder()));
1586
1587 case SLONG:
1588 case LONG:
1589 return (double) ((int)sget4 (value + ofs, getOrder()));
1590
1591 case SRATIONAL:
1592 case RATIONAL:
1593 ud = (int)sget4 (value + ofs, getOrder());
1594 dd = (int)sget4 (value + ofs + 4, getOrder());
1595 return dd == 0. ? 0. : (double)ud / (double)dd;
1596
1597 case FLOAT:
1598 conv.i = sget4 (value + ofs, getOrder());
1599 return conv.f; // IEEE FLOATs are already C format, they just need a recast
1600
1601 case UNDEFINED:
1602 return 0.;
1603
1604 default:
1605 return 0.; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR)
1606 }
1607
1608 }
1609
1610 /**
1611 * @brief Create an array of the elements
1612 */
toDoubleArray(int ofs) const1613 double* Tag::toDoubleArray (int ofs) const
1614 {
1615 double *values = new double[count];
1616
1617 for (unsigned int i = 0; i < count; ++i) {
1618 values[i] = toDouble (ofs + i * getTypeSize (type));
1619 }
1620
1621 return values;
1622 }
1623
toRational(int & num,int & denom,int ofs) const1624 void Tag::toRational (int& num, int& denom, int ofs) const
1625 {
1626
1627 switch (type) {
1628 case BYTE:
1629 num = (int)value[ofs];
1630 denom = 1;
1631 break;
1632
1633 case ASCII:
1634 num = 0;
1635 denom = 0;
1636 break;
1637
1638 case SSHORT:
1639 case SHORT:
1640 num = (int)sget2 (value + ofs, getOrder());
1641 denom = 1;
1642 break;
1643
1644 case SLONG:
1645 case LONG:
1646 num = (int)sget4 (value + ofs, getOrder());
1647 denom = 1;
1648 break;
1649
1650 case SRATIONAL:
1651 case RATIONAL:
1652 num = (int)sget4 (value + ofs, getOrder());
1653 denom = (int)sget4 (value + ofs + 4, getOrder());
1654 break;
1655
1656 case FLOAT:
1657 num = 0;
1658 denom = 0;
1659 break;
1660
1661 case UNDEFINED:
1662 num = 0;
1663 denom = 0;
1664 break;
1665
1666 default:
1667 num = 0;
1668 denom = 0;
1669 break; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR)
1670 }
1671 }
1672
toString(char * buffer,int ofs) const1673 void Tag::toString (char* buffer, int ofs) const
1674 {
1675
1676 if (type == UNDEFINED && !directory) {
1677 bool isstring = true;
1678 unsigned int i = 0;
1679
1680 for (i = 0; i + ofs < count && i < 64 && value[i + ofs]; i++)
1681 if (value[i + ofs] < 32 || value[i + ofs] > 126) {
1682 isstring = false;
1683 }
1684
1685 if (isstring) {
1686 int j = 0;
1687
1688 for (i = 0; i + ofs < count && i < 64 && value[i + ofs]; i++) {
1689 if (value[i + ofs] == '<' || value[i + ofs] == '>') {
1690 buffer[j++] = '\\';
1691 }
1692
1693 buffer[j++] = value[i + ofs];
1694 }
1695
1696 buffer[j++] = 0;
1697 return;
1698 }
1699 } else if (type == ASCII) {
1700 sprintf (buffer, "%.64s", value + ofs);
1701 return;
1702 }
1703
1704 size_t maxcount = rtengine::min<size_t>(count, 10);
1705
1706 strcpy (buffer, "");
1707
1708 for (ssize_t i = 0; i < rtengine::min<int>(maxcount, valuesize - ofs); i++) {
1709 if (i > 0) {
1710 strcat (buffer, ", ");
1711 }
1712
1713 char* b = buffer + strlen (buffer);
1714
1715 switch (type) {
1716 case UNDEFINED:
1717 case BYTE:
1718 sprintf (b, "%d", value[i + ofs]);
1719 break;
1720
1721 case SSHORT:
1722 sprintf (b, "%d", toInt (2 * i + ofs));
1723 break;
1724
1725 case SHORT:
1726 sprintf (b, "%u", toInt (2 * i + ofs));
1727 break;
1728
1729 case SLONG:
1730 sprintf (b, "%d", toInt (4 * i + ofs));
1731 break;
1732
1733 case LONG:
1734 sprintf (b, "%u", toInt (4 * i + ofs));
1735 break;
1736
1737 case SRATIONAL:
1738 case RATIONAL:
1739 sprintf (b, "%d/%d", (int)sget4 (value + 8 * i + ofs, getOrder()), (int)sget4 (value + 8 * i + ofs + 4, getOrder()));
1740 break;
1741
1742 case FLOAT:
1743 sprintf (b, "%g", toDouble (8 * i + ofs));
1744 break;
1745
1746 default:
1747 break;
1748 }
1749 }
1750
1751 if (count > maxcount) {
1752 strcat (buffer, "...");
1753 }
1754 }
1755
nameToString(int i)1756 std::string Tag::nameToString (int i)
1757 {
1758
1759 char buffer[1025];
1760
1761 if (attrib) {
1762 strncpy (buffer, attrib->name, 1024);
1763 } else {
1764 sprintf (buffer, "0x%x", tag);
1765 }
1766
1767 if (i > 0) {
1768 sprintf (buffer + strlen (buffer) - 1, "[%d]", i);
1769 }
1770
1771 return buffer;
1772 }
1773
valueToString() const1774 std::string Tag::valueToString () const
1775 {
1776
1777 if (attrib && attrib->interpreter) {
1778 return attrib->interpreter->toString (this);
1779 } else {
1780 char buffer[1024];
1781 toString (buffer);
1782 return buffer;
1783 }
1784 }
1785
valueFromString(const std::string & value)1786 void Tag::valueFromString (const std::string& value)
1787 {
1788
1789 if (attrib && attrib->interpreter) {
1790 attrib->interpreter->fromString (this, value);
1791 }
1792 }
1793
userCommentFromString(const Glib::ustring & text)1794 void Tag::userCommentFromString (const Glib::ustring& text)
1795 {
1796
1797 if (!allocOwnMemory) {
1798 return;
1799 }
1800 if (value) {
1801 delete [] value;
1802 value = nullptr;
1803 }
1804 initUserComment(text);
1805 }
1806
calculateSize()1807 int Tag::calculateSize ()
1808 {
1809 int size = 0;
1810
1811 if (directory) {
1812 int j;
1813
1814 for (j = 0; directory[j]; j++) {
1815 size += directory[j]->calculateSize ();
1816 }
1817
1818 if (j > 1) {
1819 size += 4 * j;
1820 }
1821 if (makerNoteKind != NOMK) {
1822 count = directory[0]->calculateSize () / getTypeSize (type);
1823 }
1824 } else if (valuesize > 4) {
1825 size += valuesize + (valuesize % 2); // we align tags to even byte positions
1826 }
1827
1828
1829 if (makerNoteKind == NIKON3 || makerNoteKind == OLYMPUS2 || makerNoteKind == FUJI || makerNoteKind == HEADERIFD) {
1830 size += valuesize;
1831 }
1832
1833 return size;
1834 }
1835
write(int offs,int dataOffs,unsigned char * buffer)1836 int Tag::write (int offs, int dataOffs, unsigned char* buffer)
1837 {
1838
1839 if ((int)type == 0 || offs > 65500) {
1840 return dataOffs;
1841 }
1842
1843 sset2 (tag, buffer + offs, parent->getOrder());
1844 offs += 2;
1845 unsigned short typ = type;
1846 sset2 (typ, buffer + offs, parent->getOrder());
1847 offs += 2;
1848 sset4 (count, buffer + offs, parent->getOrder());
1849 offs += 4;
1850
1851 if (!directory) {
1852 if (valuesize > 4) {
1853 sset4 (dataOffs, buffer + offs, parent->getOrder());
1854 memcpy (buffer + dataOffs, value, valuesize);
1855
1856 if (valuesize % 2) {
1857 buffer[dataOffs + valuesize] = 0; // zero padding required by the exif standard
1858 }
1859
1860 return dataOffs + valuesize + (valuesize % 2);
1861 } else {
1862 memcpy (buffer + offs, value, valuesize);
1863 return dataOffs;
1864 }
1865 } else {
1866 if (makerNoteKind == NIKON3) {
1867 sset4 (dataOffs, buffer + offs, parent->getOrder());
1868 memcpy (buffer + dataOffs, value, 18);
1869 dataOffs += 10;
1870 dataOffs += directory[0]->write (8, buffer + dataOffs);
1871 return dataOffs;
1872 } else if (makerNoteKind == OLYMPUS2 || makerNoteKind == FUJI) {
1873 sset4 (dataOffs, buffer + offs, parent->getOrder());
1874 memcpy (buffer + dataOffs, value, valuesize);
1875 dataOffs += valuesize + directory[0]->write (valuesize, buffer + dataOffs);
1876 return dataOffs;
1877 } else if (makerNoteKind == HEADERIFD) {
1878 sset4 (dataOffs, buffer + offs, parent->getOrder());
1879 memcpy (buffer + dataOffs, value, valuesize);
1880 dataOffs += valuesize;
1881 dataOffs += directory[0]->write (dataOffs, buffer);
1882 return dataOffs;
1883 } else if ( makerNoteKind == TABLESUBDIR) {
1884 sset4 (dataOffs, buffer + offs, parent->getOrder());
1885 dataOffs = directory[0]->write (dataOffs, buffer);
1886 return dataOffs;
1887 } else if (!directory[1]) {
1888 sset4 (dataOffs, buffer + offs, parent->getOrder());
1889 return directory[0]->write (dataOffs, buffer);
1890 } else {
1891 sset4 (dataOffs, buffer + offs, parent->getOrder());
1892 int linkOffs = dataOffs;
1893
1894 for (int i = 0; directory[i]; i++) {
1895 dataOffs += 4;
1896 }
1897
1898 for (int i = 0; directory[i]; i++) {
1899 sset4 (dataOffs, buffer + linkOffs, parent->getOrder());
1900 linkOffs += 4;
1901 dataOffs = directory[i]->write (dataOffs, buffer);
1902 }
1903
1904 return dataOffs;
1905 }
1906 }
1907 }
1908
Tag(TagDirectory * p,const TagAttrib * attr)1909 Tag::Tag (TagDirectory* p, const TagAttrib* attr)
1910 : tag (attr ? attr->ID : -1), type (INVALID), count (0), value (nullptr), valuesize (0), keep (true), allocOwnMemory (true), attrib (attr), parent (p), directory (nullptr), makerNoteKind (NOMK)
1911 {
1912 }
1913
Tag(TagDirectory * p,const TagAttrib * attr,int data,TagType t)1914 Tag::Tag (TagDirectory* p, const TagAttrib* attr, int data, TagType t)
1915 : tag (attr ? attr->ID : -1), type (t), count (1), value (nullptr), valuesize (0), keep (true), allocOwnMemory (true), attrib (attr), parent (p), directory (nullptr), makerNoteKind (NOMK)
1916 {
1917
1918 initInt (data, t);
1919 }
1920
Tag(TagDirectory * p,const TagAttrib * attr,unsigned char * data,TagType t)1921 Tag::Tag (TagDirectory* p, const TagAttrib* attr, unsigned char *data, TagType t)
1922 : tag (attr ? attr->ID : -1), type (t), count (1), value (nullptr), valuesize (0), keep (true), allocOwnMemory (false), attrib (attr), parent (p), directory (nullptr), makerNoteKind (NOMK)
1923 {
1924
1925 initType (data, t);
1926 }
1927
Tag(TagDirectory * p,const TagAttrib * attr,const char * text)1928 Tag::Tag (TagDirectory* p, const TagAttrib* attr, const char* text)
1929 : tag (attr ? attr->ID : -1), type (ASCII), count (1), value (nullptr), valuesize (0), keep (true), allocOwnMemory (true), attrib (attr), parent (p), directory (nullptr), makerNoteKind (NOMK)
1930 {
1931
1932 initString (text);
1933 }
1934
initType(unsigned char * data,TagType type)1935 void Tag::initType (unsigned char *data, TagType type)
1936 {
1937 valuesize = getTypeSize (type);
1938
1939 if ( allocOwnMemory ) {
1940 value = new unsigned char[valuesize];
1941 memcpy ((char*)value, data, valuesize);
1942 } else {
1943 value = data;
1944 }
1945 }
1946
initInt(int data,TagType t,int cnt)1947 void Tag::initInt (int data, TagType t, int cnt)
1948 {
1949
1950 type = t;
1951
1952 if (t == LONG) {
1953 valuesize = 4;
1954 } else if (t == SHORT) {
1955 valuesize = 2;
1956 } else if (t == BYTE) {
1957 valuesize = 1;
1958 } else if (t == RATIONAL) {
1959 valuesize = 8;
1960 }
1961
1962 count = cnt;
1963 valuesize *= count;
1964 value = new unsigned char[valuesize];
1965 setInt (data, 0, t);
1966 }
1967
swapByteOrder2(unsigned char * buffer,int count)1968 void Tag::swapByteOrder2(unsigned char *buffer, int count)
1969 {
1970 unsigned char* ptr = buffer;
1971 for (int i = 0; i < count; i+=2) {
1972 unsigned char c = ptr[0];
1973 ptr[0] = ptr[1];
1974 ptr[1] = c;
1975 ptr += 2;
1976 }
1977 }
initUserComment(const Glib::ustring & text)1978 void Tag::initUserComment (const Glib::ustring &text)
1979 {
1980 const bool useBOM = false; // set it to true if you want to output BOM in UCS-2/UTF-8 UserComments ; this could be turned to an options entry
1981 type = UNDEFINED;
1982 if (text.is_ascii()) {
1983 valuesize = count = 8 + strlen (text.c_str());
1984 value = new unsigned char[valuesize];
1985 memcpy(value, "ASCII\0\0\0", 8);
1986 memcpy(value + 8, text.c_str(), valuesize - 8);
1987 } else {
1988 glong wcStrSize = 0;
1989 gunichar2 *commentStr = g_utf8_to_utf16 (text.c_str(), -1, nullptr, &wcStrSize, nullptr);
1990 valuesize = count = wcStrSize * 2 + 8 + (useBOM ? 2 : 0);
1991 value = new unsigned char[valuesize];
1992 memcpy(value, "UNICODE\0", 8);
1993
1994 if (useBOM) {
1995 if (getOrder() == INTEL) { //Little Endian
1996 value[8] = 0xFF;
1997 value[9] = 0xFE;
1998 } else {
1999 value[8] = 0xFE;
2000 value[9] = 0xFF;
2001 }
2002 }
2003
2004 // Swapping byte order to match the Exif's byte order
2005 if (getOrder() != HOSTORDER) {
2006 swapByteOrder2((unsigned char*)commentStr, wcStrSize * 2);
2007 }
2008
2009 memcpy(value + 8 + (useBOM ? 2 : 0), (char*)commentStr, wcStrSize * 2);
2010 g_free(commentStr);
2011 }
2012 }
2013
initString(const char * text)2014 void Tag::initString (const char* text)
2015 {
2016
2017 type = ASCII;
2018 count = strlen (text) + 1;
2019 valuesize = count;
2020 value = new unsigned char[valuesize];
2021 strcpy ((char*)value, text);
2022 }
2023
initSubDir()2024 void Tag::initSubDir ()
2025 {
2026 type = LONG;
2027 valuesize = 4;
2028 count = 1;
2029 value = new unsigned char[4];
2030 setInt (0);
2031 directory = new TagDirectory*[2];
2032 directory[0] = new TagDirectory (parent, attrib ? attrib->subdirAttribs : nullptr, parent->getOrder());
2033 directory[1] = nullptr;
2034 }
2035
initSubDir(TagDirectory * dir)2036 void Tag::initSubDir (TagDirectory* dir)
2037 {
2038 type = LONG;
2039 valuesize = 4;
2040 count = 1;
2041 value = new unsigned char[4];
2042 setInt (0);
2043 directory = new TagDirectory*[2];
2044 directory[0] = dir;
2045 directory[1] = nullptr;
2046 }
2047
initMakerNote(MNKind mnk,const TagAttrib * ta)2048 void Tag::initMakerNote (MNKind mnk, const TagAttrib* ta)
2049 {
2050 type = UNDEFINED;
2051 valuesize = 4;
2052 count = 1;
2053 value = new unsigned char[4];
2054 setInt (0);
2055 directory = new TagDirectory*[2];
2056 directory[0] = new TagDirectory (parent, ta, parent->getOrder());
2057 directory[1] = nullptr;
2058 makerNoteKind = mnk;
2059 }
2060
initUndefArray(const char * data,int len)2061 void Tag::initUndefArray (const char* data, int len)
2062 {
2063 type = UNDEFINED;
2064 count = valuesize = len;
2065 value = new unsigned char[valuesize];
2066 memcpy (value, data, len);
2067 }
2068
initLongArray(const char * data,int len)2069 void Tag::initLongArray (const char* data, int len)
2070 {
2071 type = LONG;
2072 count = (len + 3) / 4;
2073 valuesize = count * 4;
2074 value = new unsigned char[valuesize];
2075 memcpy (value, data, len);
2076 }
2077
initRational(int num,int den)2078 void Tag::initRational (int num, int den)
2079 {
2080 count = 1;
2081 valuesize = 8;
2082 value = new unsigned char[8];
2083 type = RATIONAL;
2084 setInt (num, 0);
2085 setInt (den, 4);
2086 }
2087
2088 //--------------- class IFDParser ---------------------------------------------
2089 // static functions to read tag directories from different kinds of files
2090 //-----------------------------------------------------------------------------
2091
2092
lookupAttrib(const TagAttrib * dir,const char * field)2093 const TagAttrib* lookupAttrib (const TagAttrib* dir, const char* field)
2094 {
2095
2096 for (int i = 0; dir[i].ignore != -1; i++)
2097 if (!strcmp (dir[i].name, field)) {
2098 return &dir[i];
2099 }
2100
2101 return nullptr;
2102 }
2103
setIFDOffset(unsigned int offset)2104 void ExifManager::setIFDOffset(unsigned int offset)
2105 {
2106 IFDOffset = offset;
2107 }
2108
parseCIFF()2109 void ExifManager::parseCIFF ()
2110 {
2111
2112 TagDirectory* root = new TagDirectory (nullptr, ifdAttribs, INTEL);
2113 Tag* exif = new Tag (root, lookupAttrib (ifdAttribs, "Exif"));
2114 exif->initSubDir ();
2115 root->addTag (exif);
2116 if (exif) {
2117 Tag* mn = new Tag (exif->getDirectory(), lookupAttrib (exifAttribs, "MakerNote"));
2118 mn->initMakerNote (IFD, canonAttribs);
2119 exif->getDirectory()->addTag (mn);
2120 }
2121 parseCIFF (rml->ciffLength, root);
2122 root->sort ();
2123 parse(true);
2124 }
2125
saveCIFFMNTag(TagDirectory * root,int len,const char * name)2126 Tag* ExifManager::saveCIFFMNTag (TagDirectory* root, int len, const char* name)
2127 {
2128 int s = ftell (f);
2129 if(s >= 0) {
2130 char* data = new char [len];
2131 fread (data, len, 1, f);
2132 TagDirectory* mn = root->getTag ("Exif")->getDirectory()->getTag ("MakerNote")->getDirectory();
2133 Tag* cs = new Tag (mn, lookupAttrib (canonAttribs, name));
2134 cs->initUndefArray (data, len);
2135 mn->addTag (cs);
2136 fseek (f, s, SEEK_SET);
2137 delete [] data;
2138 return cs;
2139 } else {
2140 return nullptr;
2141 }
2142 }
2143
parseCIFF(int length,TagDirectory * root)2144 void ExifManager::parseCIFF (int length, TagDirectory* root)
2145 {
2146
2147 if (!f) {
2148 #ifndef NDEBUG
2149 std::cerr << "ERROR : no file opened !" << std::endl;
2150 #endif
2151 return;
2152 }
2153
2154 char buffer[1024];
2155 Tag* t;
2156
2157 if (fseek(f, rml->ciffBase + length - 4, SEEK_SET)) {
2158 return;
2159 }
2160
2161 int dirStart = get4 (f, INTEL) + rml->ciffBase;
2162 if (fseek(f, dirStart, SEEK_SET)) {
2163 return;
2164 }
2165
2166 int numOfTags = get2 (f, INTEL);
2167
2168 if (numOfTags > 100) {
2169 return;
2170 }
2171
2172 float exptime, shutter, aperture, fnumber, ev;
2173 exptime = fnumber = shutter = aperture = ev = -1000.f;
2174 int focal_len, iso;
2175 focal_len = iso = -1;
2176
2177 TagDirectory* exif = root->getTag ("Exif")->getDirectory();
2178
2179 time_t timestamp = time (nullptr);
2180
2181 for (int i = 0; i < numOfTags; i++) {
2182
2183 int type = get2 (f, INTEL);
2184 int len = get4 (f, INTEL);
2185 int nextPos = ftell (f) + 4;
2186
2187 // seek to the location of the value
2188 fseek (f, rml->ciffBase + get4 (f, INTEL), SEEK_SET);
2189
2190 if ((((type >> 8) + 8) | 8) == 0x38) {
2191 ExifManager(
2192 f,
2193 std::unique_ptr<rtengine::RawMetaDataLocation>(
2194 new rtengine::RawMetaDataLocation(
2195 ftell(f),
2196 len
2197 )
2198 ),
2199 true
2200 ).parseCIFF(len, root); // Parse a sub-table
2201 }
2202
2203 if (type == 0x0810) {
2204 fread (buffer, 64, 1, f);
2205 t = new Tag (root, lookupAttrib (ifdAttribs, "Artist"));
2206 t->initString (buffer);
2207 root->addTag (t);
2208 }
2209
2210 if (type == 0x080a) {
2211 fread (buffer, 64, 1, f);
2212 t = new Tag (root, lookupAttrib (ifdAttribs, "Make"));
2213 t->initString (buffer);
2214 root->addTag (t);
2215 if (!fseek (f, strlen (buffer) - 63, SEEK_CUR)) {
2216 if (fread (buffer, 64, 1, f) == 1) {
2217 t = new Tag (root, lookupAttrib (ifdAttribs, "Model"));
2218 t->initString (buffer);
2219 root->addTag (t);
2220 }
2221 }
2222 }
2223
2224 if (type == 0x1818) {
2225 ev = int_to_float (get4 (f, INTEL));
2226 shutter = int_to_float (get4 (f, INTEL));
2227 exptime = pow (2, -shutter);
2228 aperture = int_to_float (get4 (f, INTEL));
2229 fnumber = pow (2, aperture / 2);
2230
2231 }
2232
2233 ExifManager exifManager(f, nullptr, true);
2234 if (type == 0x102d) {
2235 Tag* t = exifManager.saveCIFFMNTag (root, len, "CanonCameraSettings");
2236 int mm = t->toInt (34, SHORT);
2237 Tag* nt = new Tag (exif, lookupAttrib (exifAttribs, "MeteringMode"));
2238
2239 switch (mm) {
2240 case 0:
2241 nt->initInt (5, SHORT);
2242 break;
2243
2244 case 1:
2245 nt->initInt (3, SHORT);
2246 break;
2247
2248 case 2:
2249 nt->initInt (1, SHORT);
2250 break;
2251
2252 case 3:
2253 nt->initInt (5, SHORT);
2254 break;
2255
2256 case 4:
2257 nt->initInt (6, SHORT);
2258 break;
2259
2260 case 5:
2261 nt->initInt (2, SHORT);
2262 break;
2263 }
2264
2265 exif->addTag (nt);
2266 nt = new Tag (exif, lookupAttrib (exifAttribs, "MaxApertureValue"));
2267 nt->initRational (t->toInt (52, SHORT), 32);
2268 exif->addTag (nt);
2269 int em = t->toInt (40, SHORT);
2270 nt = new Tag (exif, lookupAttrib (exifAttribs, "ExposureProgram"));
2271
2272 switch (em) {
2273 case 0:
2274 nt->initInt (2, SHORT);
2275 break;
2276
2277 case 1:
2278 nt->initInt (2, SHORT);
2279 break;
2280
2281 case 2:
2282 nt->initInt (4, SHORT);
2283 break;
2284
2285 case 3:
2286 nt->initInt (3, SHORT);
2287 break;
2288
2289 case 4:
2290 nt->initInt (1, SHORT);
2291 break;
2292
2293 default:
2294 nt->initInt (0, SHORT);
2295 break;
2296 }
2297
2298 exif->addTag (nt);
2299 nt = new Tag (exif, lookupAttrib (exifAttribs, "Flash"));
2300
2301 if (t->toInt (8, SHORT) == 0) {
2302 nt->initInt (0, SHORT);
2303 } else {
2304 nt->initInt (1, SHORT);
2305 }
2306
2307 exif->addTag (nt);
2308 nt = new Tag (exif, lookupAttrib (exifAttribs, "MaxApertureValue"));
2309 nt->initRational (t->toInt (52, SHORT), 32);
2310 exif->addTag (nt);
2311 }
2312
2313 if (type == 0x1029) {
2314 exifManager.saveCIFFMNTag (root, len, "CanonFocalLength");
2315 }
2316
2317 if (type == 0x1031) {
2318 exifManager.saveCIFFMNTag (root, len, "SensorInfo");
2319 }
2320
2321 if (type == 0x1033) {
2322 exifManager.saveCIFFMNTag (root, len, "CustomFunctions");
2323 }
2324
2325 if (type == 0x1038) {
2326 exifManager.saveCIFFMNTag (root, len, "CanonAFInfo");
2327 }
2328
2329 if (type == 0x1093) {
2330 exifManager.saveCIFFMNTag (root, len, "CanonFileInfo");
2331 }
2332
2333 if (type == 0x10a9) {
2334 exifManager.saveCIFFMNTag (root, len, "ColorBalance");
2335 }
2336
2337 if (type == 0x102a) {
2338 exifManager.saveCIFFMNTag (root, len, "CanonShotInfo");
2339
2340 iso = pow (2, (get4 (f, INTEL), get2 (f, INTEL)) / 32.0 - 4) * 50;
2341 aperture = (get2 (f, INTEL), (short)get2 (f, INTEL)) / 32.0f;
2342 fnumber = pow (2, aperture / 2);
2343 shutter = ((short)get2 (f, INTEL)) / 32.0f;
2344 ev = ((short)get2 (f, INTEL)) / 32.0f;
2345 fseek (f, 34, SEEK_CUR);
2346
2347 if (shutter > 1e6) {
2348 shutter = get2 (f, INTEL) / 10.0f;
2349 }
2350
2351 exptime = pow (2, -shutter);
2352 }
2353
2354 if (type == 0x5029) {
2355 focal_len = len >> 16;
2356
2357 if ((len & 0xffff) == 2) {
2358 focal_len /= 32;
2359 }
2360 }
2361
2362 // if (type == 0x5813) flash_used = int_to_float(len);
2363 if (type == 0x580e) {
2364 timestamp = len;
2365 }
2366
2367 if (type == 0x180e) {
2368 timestamp = get4 (f, INTEL);
2369 }
2370
2371 if ((type | 0x4000) == 0x580e) {
2372 timestamp = mktime (gmtime (×tamp));
2373 }
2374
2375 fseek (f, nextPos, SEEK_SET);
2376 }
2377
2378 if (shutter > -999) {
2379 t = new Tag (exif, lookupAttrib (exifAttribs, "ShutterSpeedValue"));
2380 t->initRational ((int) (shutter * 10000), 10000);
2381 exif->addTag (t);
2382 }
2383
2384 if (exptime > -999) {
2385 t = new Tag (exif, lookupAttrib (exifAttribs, "ExposureTime"));
2386 t->initRational ((int) (exptime * 10000), 10000);
2387 exif->addTag (t);
2388 }
2389
2390 if (aperture > -999) {
2391 t = new Tag (exif, lookupAttrib (exifAttribs, "ApertureValue"));
2392 t->initRational ((int) (aperture * 10), 10);
2393 exif->addTag (t);
2394 }
2395
2396 if (fnumber > -999) {
2397 t = new Tag (exif, lookupAttrib (exifAttribs, "FNumber"));
2398 t->initRational ((int) (fnumber * 10), 10);
2399 exif->addTag (t);
2400 }
2401
2402 if (ev > -999) {
2403 t = new Tag (exif, lookupAttrib (exifAttribs, "ExposureBiasValue"));
2404 t->initRational ((int) (ev * 1000), 1000);
2405 exif->addTag (t);
2406 }
2407
2408 if (iso > 0) {
2409 t = new Tag (exif, lookupAttrib (exifAttribs, "ISOSpeedRatings"));
2410 t->initInt (iso, LONG);
2411 exif->addTag (t);
2412 }
2413
2414 if (focal_len > 0) {
2415 t = new Tag (exif, lookupAttrib (exifAttribs, "FocalLength"));
2416 t->initRational (focal_len * 32, 32);
2417 exif->addTag (t);
2418 }
2419
2420 if (timestamp != time (nullptr)) {
2421 struct tm* tim = localtime (×tamp);
2422 strftime (buffer, 20, "%Y:%m:%d %H:%M:%S", tim);
2423 t = new Tag (exif, lookupAttrib (exifAttribs, "DateTimeOriginal"));
2424 t->initString (buffer);
2425 exif->addTag (t);
2426 t = new Tag (exif, lookupAttrib (exifAttribs, "DateTimeDigitized"));
2427 t->initString (buffer);
2428 exif->addTag (t);
2429 t = new Tag (root, lookupAttrib (ifdAttribs, "DateTime"));
2430 t->initString (buffer);
2431 root->addTag (t);
2432 }
2433
2434 roots.push_back(root);
2435
2436 }
2437
2438 static void
parse_leafdata(TagDirectory * root,ByteOrder order)2439 parse_leafdata (TagDirectory* root, ByteOrder order)
2440 {
2441
2442 Tag *leafdata = root->getTag ("LeafData");
2443
2444 if (!leafdata) {
2445 return;
2446 }
2447
2448 unsigned char *value = leafdata->getValue();
2449 int valuesize = leafdata->getValueSize();
2450
2451 // parse LeafData tag, a tag specific to Leaf digital backs, and has a custom
2452 // format with 52 byte tag headers starting with "PKTS"
2453 const char *PKTS_tag = (order == MOTOROLA) ? "PKTS" : "STKP";
2454 char *hdr;
2455 int pos = 0;
2456
2457 // There are lots of sub-tags in here, but for now we only care about those directly
2458 // useful to RT, which is ISO and rotation. Shutter speed and aperture is not
2459 // available here.
2460 int iso_speed = 0;
2461 int rotation_angle = 0;
2462 int found_count = 0;
2463
2464 while (pos + (int)sizeof (hdr) <= valuesize && found_count < 2) {
2465 hdr = (char *)&value[pos];
2466
2467 if (strncmp (hdr, PKTS_tag, 4) != 0) {
2468 // in a few cases the header can be offset a few bytes, don't know why
2469 // it does not seem to be some sort of alignment, it appears random,
2470 // this check takes care of it, restart if we find an offset match.
2471 int offset = 1;
2472
2473 for (; offset <= 3; offset++) {
2474 if (strncmp (&hdr[offset], PKTS_tag, 4) == 0) {
2475 pos += offset;
2476 break;
2477 }
2478 }
2479
2480 if (offset <= 3) {
2481 continue;
2482 }
2483
2484 break;
2485 }
2486
2487 int size = sget4 ((unsigned char *)&hdr[48], order);
2488
2489 if (pos + size > valuesize) {
2490 break;
2491 }
2492
2493 pos += 52;
2494 char *val = (char *)&value[pos];
2495
2496 if (strncmp (&hdr[8], "CameraObj_ISO_speed", 19) == 0) {
2497 iso_speed = 25 * (1 << std::max((atoi (val) - 1), 0));
2498 found_count++;
2499 } else if (strncmp (&hdr[8], "ImgProf_rotation_angle", 22) == 0) {
2500 rotation_angle = atoi (val);
2501 found_count++;
2502 } else {
2503 // check if this is a sub-directory, include test for that strange offset of next header
2504 if (size >= 8 &&
2505 (strncmp (val, PKTS_tag, 4) == 0 ||
2506 strncmp (&val[1], PKTS_tag, 4) == 0 ||
2507 strncmp (&val[2], PKTS_tag, 4) == 0 ||
2508 strncmp (&val[3], PKTS_tag, 4) == 0)) {
2509 // start of next hdr, this is a sub-directory, we skip those for now.
2510 size = 0;
2511 }
2512 }
2513
2514 pos += size;
2515 }
2516
2517 // create standard tags from the custom Leaf tags
2518 Tag* exif = root->getTag ("Exif");
2519
2520 if (!exif) {
2521 exif = new Tag (root, root->getAttrib ("Exif"));
2522 exif->initSubDir();
2523 root->addTagFront (exif);
2524 }
2525
2526 if (exif && !exif->getDirectory()->getTag ("ISOSpeedRatings")) {
2527 Tag *t = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings"));
2528 t->initInt (iso_speed, LONG);
2529 exif->getDirectory()->addTagFront (t);
2530 }
2531
2532 if (!root->getTag ("Orientation")) {
2533 int orientation;
2534
2535 switch (rotation_angle) {
2536 case 0:
2537 orientation = 1;
2538 break;
2539
2540 case 90:
2541 orientation = 6;
2542 break;
2543
2544 case 180:
2545 orientation = 3;
2546 break;
2547
2548 case 270:
2549 orientation = 8;
2550 break;
2551
2552 default:
2553 orientation = 1;
2554 break;
2555 }
2556
2557 Tag *t = new Tag (root, root->getAttrib ("Orientation"));
2558 t->initInt (orientation, SHORT);
2559 root->addTagFront (t);
2560 }
2561
2562 // now look in ApplicationNotes tag for additional information
2563 Tag *appnotes = root->getTag ("ApplicationNotes");
2564
2565 if (!appnotes) {
2566 return;
2567 }
2568
2569 char *xmp = (char *)appnotes->getValue();
2570 char *end, *p;
2571
2572 // Quick-and-dirty value extractor, no real xml parsing.
2573 // We could make it more generic, but we just get most important
2574 // values we know use to be in there.
2575 if ((p = strstr (xmp, "xmlns:tiff")) != nullptr &&
2576 (end = strstr (p, "</rdf:Description>")) != nullptr) {
2577 *end = '\0';
2578
2579 while ((p = strstr (p, "<tiff:")) != nullptr) {
2580 char *tag = &p[6], *tagend;
2581
2582 if ((tagend = strchr (tag, '>')) == nullptr) {
2583 break;
2584 }
2585
2586 *tagend = '\0';
2587 char *val = &tagend[1];
2588
2589 if ((p = strstr (val, "</tiff:")) == nullptr) {
2590 *tagend = '>';
2591 break;
2592 }
2593
2594 *p = '\0';
2595
2596 if (root->getAttrib (tag) && !root->getTag (tag)) {
2597 Tag *t = new Tag (root, root->getAttrib (tag));
2598
2599 if (strcmp (tag, "Make") == 0 ||
2600 strcmp (tag, "Model") == 0) {
2601 if (strcmp (tag, "Model") == 0) {
2602 // Leaf adds back serial number and camera model to the 'Model'
2603 // tag, we strip that away here so the back can be recognized
2604 // and matched against DCP profile
2605 char *p1 = strchr (val, '(');
2606
2607 if (p1 != nullptr) {
2608 *p1 = '\0';
2609 }
2610
2611 // Model name also contains a leading "Leaf " which we already
2612 // have in the Make name, remove that.
2613 if (strstr (val, "Leaf ") == val) {
2614 t->initString (&val[5]);
2615 } else {
2616 t->initString (val);
2617 }
2618
2619 if (p1 != nullptr) {
2620 *p1 = '(';
2621 }
2622 } else {
2623 t->initString (val);
2624 }
2625
2626 root->addTagFront (t);
2627 } else {
2628 delete t;
2629 }
2630 }
2631
2632 *p = '<';
2633 *tagend = '>';
2634 }
2635
2636 *end = '<';
2637 }
2638
2639 if ((p = strstr (xmp, "xmlns:exif")) != nullptr &&
2640 (end = strstr (p, "</rdf:Description>")) != nullptr) {
2641 *end = '\0';
2642
2643 while ((p = strstr (p, "<exif:")) != nullptr) {
2644 char *tag = &p[6], *tagend;
2645
2646 if ((tagend = strchr (tag, '>')) == nullptr) {
2647 break;
2648 }
2649
2650 *tagend = '\0';
2651 char *val = &tagend[1];
2652
2653 if ((p = strstr (val, "</exif:")) == nullptr) {
2654 *tagend = '>';
2655 break;
2656 }
2657
2658 *p = '\0';
2659
2660 if (exif->getDirectory()->getAttrib (tag) && !exif->getDirectory()->getTag (tag)) {
2661 Tag *t = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib (tag));
2662 int num, denom;
2663 struct tm tm;
2664
2665 if (strcmp (tag, "ApertureValue") == 0 && sscanf (val, "%d/%d", &num, &denom) == 2) {
2666 t->initRational (num, denom);
2667 exif->getDirectory()->addTagFront (t);
2668 // we also make an "FNumber" tag since many tools don't interpret ApertureValue
2669 // according to Exif standard
2670 t = new Tag (exif->getDirectory(), lookupAttrib (exifAttribs, "FNumber"));
2671 double f = pow (sqrt (2.0), ((double)num / denom));
2672
2673 if (f > 10.0) {
2674 t->initRational ((int)floor (f), 1);
2675 } else {
2676 t->initRational ((int)floor (f * 10.0), 10);
2677 }
2678
2679 exif->getDirectory()->addTagFront (t);
2680 } else if (strcmp (tag, "ShutterSpeedValue") == 0 && sscanf (val, "%d/%d", &num, &denom) == 2) {
2681 t->initRational (num, denom);
2682 exif->getDirectory()->addTagFront (t);
2683 // we also make an "ExposureTime" tag since many tools don't interpret ShutterSpeedValue
2684 // according to Exif standard
2685 t = new Tag (exif->getDirectory(), lookupAttrib (exifAttribs, "ExposureTime"));
2686 double f = 1.0 / pow (2.0, ((double)num / denom));
2687
2688 if (f > 10.0) {
2689 t->initRational ((int)floor (f), 1);
2690 } else if (f > 1.0) {
2691 t->initRational ((int)floor (f * 10.0), 10);
2692 } else if (f == 1.0) {
2693 t->initRational (1, 1);
2694 } else {
2695 f = 1.0 / f;
2696 static const double etimes[] = {
2697 10000, 8000, 6400, 6000, 5000,
2698 4000, 3200, 3000, 2500,
2699 2000, 1600, 1500, 1250,
2700 1000, 800, 750, 640,
2701 500, 400, 350, 320,
2702 250, 200, 180, 160,
2703 125, 100, 90, 80,
2704 60, 50, 45, 40,
2705 30, 25, 22, 20,
2706 15, 13, 11, 10,
2707 8, 6, 5,
2708 4, 3, 2.5,
2709 2, 1.6, 1.5, 1.3,
2710 1, -1
2711 };
2712 double diff = etimes[0];
2713 int idx = -1;
2714
2715 for (int i = 1; etimes[i] > 0; i++) {
2716 if (abs (etimes[i] - f) < diff) {
2717 idx = i;
2718 diff = abs (etimes[i] - f);
2719 }
2720 }
2721
2722 if (idx != -1 && f < etimes[0]) {
2723 f = etimes[idx];
2724 }
2725
2726 if (f < 2) {
2727 t->initRational (10, (int) (10 * f));
2728 } else {
2729 t->initRational (1, (int)f);
2730 }
2731 }
2732
2733 exif->getDirectory()->addTagFront (t);
2734 } else if (strcmp (tag, "FocalLength") == 0 && sscanf (val, "%d/%d", &num, &denom) == 2) {
2735 t->initRational (num, denom);
2736 exif->getDirectory()->addTagFront (t);
2737 } else if (strcmp (tag, "ISOSpeedRatings") == 0) {
2738 char *p1 = val;
2739
2740 while (*p1 != '\0' && !isdigit (*p1)) {
2741 p1++;
2742 }
2743
2744 if (*p1 != '\0') {
2745 t->initInt (atoi (p1), LONG);
2746 exif->getDirectory()->addTagFront (t);
2747 } else {
2748 delete t;
2749 }
2750 } else if (strcmp (tag, "DateTimeOriginal") == 0 &&
2751 sscanf (val, "%d-%d-%dT%d:%d:%dZ",
2752 &tm.tm_year, &tm.tm_mon,
2753 &tm.tm_mday, &tm.tm_hour,
2754 &tm.tm_min, &tm.tm_sec) == 6) {
2755 char tstr[64];
2756 sprintf (tstr, "%04d:%02d:%02d %02d:%02d:%02d", tm.tm_year, tm.tm_mon,
2757 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
2758 t->initString (tstr);
2759 exif->getDirectory()->addTagFront (t);
2760 } else {
2761 delete t;
2762 }
2763 }
2764
2765 *p = '<';
2766 *tagend = '>';
2767 }
2768
2769 *end = '<';
2770 }
2771 }
2772
parseRaw(bool skipIgnored)2773 void ExifManager::parseRaw (bool skipIgnored) {
2774 parse(true, skipIgnored);
2775 }
2776
parseStd(bool skipIgnored)2777 void ExifManager::parseStd (bool skipIgnored) {
2778 parse(false, skipIgnored);
2779 }
2780
parse(bool isRaw,bool skipIgnored,bool parseJpeg)2781 void ExifManager::parse (bool isRaw, bool skipIgnored, bool parseJpeg)
2782 {
2783 int ifdOffset = IFDOffset;
2784
2785 if (!f) {
2786 #ifndef NDEBUG
2787 std::cerr << "ERROR : no file opened !" << std::endl;
2788 #endif
2789 return;
2790 }
2791 setlocale (LC_NUMERIC, "C"); // to set decimal point in sscanf
2792
2793 if (order == ByteOrder::UNKNOWN) {
2794 // read tiff header
2795 fseek (f, rml->exifBase, SEEK_SET);
2796 unsigned short bo;
2797 fread (&bo, 1, 2, f);
2798 order = (ByteOrder) ((int)bo);
2799 get2 (f, order);
2800 if (!ifdOffset) {
2801 ifdOffset = get4 (f, order);
2802 }
2803 }
2804
2805 do {
2806 // seek to IFD
2807 fseek (f, rml->exifBase + ifdOffset, SEEK_SET);
2808
2809 // first read the IFD directory
2810 TagDirectory* root = new TagDirectory (nullptr, f, rml->exifBase, ifdAttribs, order, skipIgnored, parseJpeg);
2811
2812 // fix ISO issue with nikon and panasonic cameras
2813 Tag* make = root->getTag ("Make");
2814 Tag* exif = root->getTag ("Exif");
2815
2816 if (exif && !exif->getDirectory()->getTag ("ISOSpeedRatings")) {
2817 if (make && !strncmp ((char*)make->getValue(), "NIKON", 5)) {
2818 Tag* mn = exif->getDirectory()->getTag ("MakerNote");
2819
2820 if (mn) {
2821 Tag* iso = mn->getDirectory()->getTag ("ISOSpeed");
2822
2823 if (iso) {
2824 std::string isov = iso->valueToString ();
2825 Tag* niso = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings"));
2826 niso->initInt (atoi (isov.c_str()), SHORT);
2827 exif->getDirectory()->addTagFront (niso);
2828 }
2829 }
2830 } else if (make && (!strncmp ((char*)make->getValue(), "Panasonic", 9) || !strncmp ((char*)make->getValue(), "LEICA", 5))) {
2831 Tag* iso = root->getTag ("PanaISO");
2832
2833 if (iso) {
2834 std::string isov = iso->valueToString ();
2835 Tag* niso = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings"));
2836 niso->initInt (atoi (isov.c_str()), SHORT);
2837 exif->getDirectory()->addTagFront (niso);
2838 }
2839 }
2840 }
2841
2842 if (make && !strncmp ((char*)make->getValue(), "Kodak", 5)) {
2843 if (!exif) {
2844 // old Kodak cameras may have exif tags in IFD0, reparse and create an exif subdir
2845 fseek (f, rml->exifBase + ifdOffset, SEEK_SET);
2846 TagDirectory* exifdir = new TagDirectory (nullptr, f, rml->exifBase, exifAttribs, order, true);
2847
2848 exif = new Tag (root, root->getAttrib ("Exif"));
2849 exif->initSubDir (exifdir);
2850 root->addTagFront (exif);
2851
2852 if (exif && !exif->getDirectory()->getTag ("ISOSpeedRatings") && exif->getDirectory()->getTag ("ExposureIndex")) {
2853 Tag* niso = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings"));
2854 niso->initInt (exif->getDirectory()->getTag ("ExposureIndex")->toInt(), SHORT);
2855 exif->getDirectory()->addTagFront (niso);
2856 }
2857 }
2858
2859 Tag *kodakIFD = root->getTag ("KodakIFD");
2860
2861 if (kodakIFD && kodakIFD->getDirectory()->getTag ("TextualInfo")) {
2862 parseKodakIfdTextualInfo (kodakIFD->getDirectory()->getTag ("TextualInfo"), exif);
2863 }
2864 }
2865
2866 parse_leafdata (root, order);
2867
2868 if (make && !strncmp ((char*)make->getValue(), "Hasselblad", 10)) {
2869 /*
2870 Figuring out the Hasselblad model is a mess. Hasselblad raw data comes in four slightly
2871 different containers, 3FR (directly from CF card), FFF (same as 3FR but filtered through
2872 Phocus, calibration data applied and a bit different tags), Adobe-generated DNGs and
2873 Phocus-generated DNGs.
2874
2875 FFF usually has a sane model name in Model (and is used as reference for what we shall
2876 call the different Hasselblad models), but 3FR only says like "Hasselblad H3D" for
2877 all H3D models, or "Flash Sync" if the back has been used on a mechanical camera body.
2878 V-mount backs may have the model name of the V body instead of the back model. Etc...
2879 as said it's a mess.
2880
2881 This code is supposed to handle all raw containers and end up with the same model
2882 regardless of container.
2883
2884 We don't differ between single shot and multi-shot models, and probably there's no use
2885 of doing so. You need Hasselblad's own software to shoot multi-shot and can only do that
2886 tethered. In single-shot mode they should be exactly the same as the single-shot models.
2887 */
2888 Tag *subd = root->getTag (0x14a);
2889 Tag *iw = (subd) ? subd->getDirectory()->getTag ("ImageWidth") : nullptr;
2890 int sensorWidth = (iw) ? iw->toInt() : 0;
2891 Tag* tmodel = root->getTag ("Model");
2892 const char *model = (tmodel) ? (const char *)tmodel->getValue() : "";
2893
2894 if (strstr (model, "Hasselblad ") == model) {
2895 model += 11;
2896 } else {
2897 // if HxD is used in flash sync mode for example, we need to fetch model from this tag
2898 Tag* tmodel3 = root->getTag ("UniqueCameraModel");
2899 const char *model3 = (tmodel3) ? (const char *)tmodel3->getValue() : "";
2900
2901 if (strstr (model3, "Hasselblad ") == model3) {
2902 model = model3 + 11;
2903 }
2904 }
2905
2906 // FIXME: due to lack of test files this Hasselblad model identification is not 100% complete
2907 // This needs checking out: CFV-39/CFV-50 3FR, H3DII vs H3D, old CF/CFH models
2908
2909 if (!strcmp (model, "H3D")) {
2910 // We can't differ between H3D and H3DII for the 22, 31 and 39 models. There's was no H3D-50 so we know that is a
2911 // H3DII-50. At the time of writing I have no test files for the H3D vs H3DII models, so there still may be a chance
2912 // to differ between them. AFAIK Adobe's DNG converter don't differ between them, and actually call the H3DII-50
2913 // H3D-50 although Hasselblad never released such a model.
2914 switch (sensorWidth) {
2915 case 4096:
2916 tmodel->initString ("H3D-22");
2917 break;
2918
2919 case 6542:
2920 tmodel->initString ("H3D-31");
2921 break;
2922
2923 case 7262:
2924 tmodel->initString ("H3D-39");
2925 break;
2926
2927 case 8282:
2928 tmodel->initString ("H3DII-50");
2929 break;
2930 }
2931 } else if (!strcmp (model, "H4D")) {
2932 switch (sensorWidth) {
2933 case 6542:
2934 tmodel->initString ("H4D-31");
2935 break;
2936
2937 case 7410:
2938 tmodel->initString ("H4D-40");
2939 break;
2940
2941 case 8282:
2942 tmodel->initString ("H4D-50");
2943 break;
2944
2945 case 9044:
2946 tmodel->initString ("H4D-60");
2947 break;
2948 }
2949 } else if (!strcmp (model, "H5D")) {
2950 switch (sensorWidth) {
2951 case 7410:
2952 tmodel->initString ("H5D-40");
2953 break;
2954
2955 case 8282:
2956 tmodel->initString ("H5D-50");
2957 break;
2958
2959 case 8374:
2960 tmodel->initString ("H5D-50c");
2961 break;
2962
2963 case 9044:
2964 tmodel->initString ("H5D-60");
2965 break;
2966 }
2967 } else if (!strcmp (model, "CFV")) {
2968 switch (sensorWidth) {
2969 case 7262:
2970 tmodel->initString ("CFV-39");
2971 break;
2972
2973 case 8282:
2974 tmodel->initString ("CFV-50");
2975 break;
2976
2977 case 8374:
2978 tmodel->initString ("CFV-50c");
2979 break;
2980 }
2981 }
2982
2983 // and a few special cases
2984 Tag* tmodel3 = root->getTag ("UniqueCameraModel");
2985 const char *model3 = (tmodel3) ? (const char *)tmodel3->getValue() : "";
2986
2987 if (strstr (model3, "Hasselblad ") == model3) {
2988 model3 = model3 + 11;
2989 }
2990
2991 if (!strcmp (model3, "ixpressCF132")) {
2992 tmodel->initString ("CF-22");
2993 } else if (!strcmp (model3, "Hasselblad96")) {
2994 tmodel->initString ("CFV"); // popularly called CFV-16, but the official name is CFV
2995 } else if (!strcmp (model3, "Hasselblad234")) {
2996 tmodel->initString ("CFV-39");
2997 } else if (sensorWidth == 4090) {
2998 tmodel->initString ("V96C");
2999 }
3000
3001 // and yet some, this is for Adobe-generated DNG files
3002 Tag* tmodel4 = root->getTag ("LocalizedCameraModel");
3003
3004 if (tmodel4) {
3005 const char *model4 = (const char *)tmodel4->getValue();
3006
3007 if (strstr (model4, "Hasselblad ") == model4) {
3008 model4 = model4 + 11;
3009 }
3010
3011 if (!strcmp (model4, "ixpressCF132-22")) {
3012 tmodel->initString ("CF-22");
3013 } else if (!strcmp (model4, "Hasselblad96-16")) {
3014 tmodel->initString ("CFV");
3015 } else if (!strcmp (model4, "Hasselblad234-39")) {
3016 tmodel->initString ("CFV-39");
3017 } else if (!strcmp (model4, "H3D-50")) {
3018 // Adobe names H3DII-50 incorrectly as H3D-50
3019 tmodel->initString ("H3DII-50");
3020 } else if (strstr (model4, "H3D-") == model4 || strstr (model4, "H4D-") == model4 || strstr (model4, "H5D-") == model4) {
3021 tmodel->initString (model4);
3022 }
3023 }
3024 }
3025
3026 if (!root->getTag ("Orientation")) {
3027 if (make && !strncmp ((char*)make->getValue(), "Phase One", 9)) {
3028 int orientation = 0;
3029 Tag *iw = root->getTag ("ImageWidth");
3030
3031 if (iw) {
3032 // from dcraw, derive orientation from image width
3033 orientation = "0653"[iw->toInt() & 3] - '0';
3034 }
3035
3036 Tag *t = new Tag (root, root->getAttrib ("Orientation"));
3037 t->initInt (orientation, SHORT);
3038 root->addTagFront (t);
3039 }
3040 }
3041
3042 if (!root->getTag ("Rating")) {
3043 Tag *t = new Tag (root, root->getAttrib("Rating"));
3044 t->initInt (0, LONG);
3045 root->addTag (t);
3046 }
3047
3048 // --- detecting image root IFD based on SubFileType, or if not provided, on PhotometricInterpretation
3049
3050 bool frameRootDetected = false;
3051
3052 if(!frameRootDetected) {
3053 std::vector<const Tag*> risTagList = root->findTags("RawImageSegmentation");
3054 if (!risTagList.empty()) {
3055 for (auto ris : risTagList) {
3056 frames.push_back(ris->getParent());
3057 frameRootDetected = true;
3058
3059 #if PRINT_METADATA_TREE
3060 printf("\n--------------- FRAME (RAWIMAGESEGMENTATION) ---------------\n\n");
3061 ris->getParent()->printAll ();
3062 #endif
3063 }
3064 }
3065 }
3066
3067 if(!frameRootDetected) {
3068 std::vector<const Tag*> sftTagList = root->findTags(TIFFTAG_SUBFILETYPE);
3069 if (!sftTagList.empty()) {
3070 for (auto sft : sftTagList) {
3071 int sftVal = sft->toInt();
3072 if (sftVal == 0 || (!isRaw && sftVal == 2)) {
3073 frames.push_back(sft->getParent());
3074 frameRootDetected = true;
3075
3076 #if PRINT_METADATA_TREE
3077 printf("\n--------------- FRAME (SUBFILETYPE) ---------------\n\n");
3078 sft->getParent()->printAll ();
3079 #endif
3080 }
3081 }
3082 }
3083 }
3084
3085 if(!frameRootDetected) {
3086 std::vector<const Tag*> sftTagList = root->findTags(TIFFTAG_OSUBFILETYPE);
3087 if (!sftTagList.empty()) {
3088 for (auto sft : sftTagList) {
3089 int sftVal = sft->toInt();
3090 if (sftVal == OFILETYPE_IMAGE) {
3091 frames.push_back(sft->getParent());
3092 frameRootDetected = true;
3093
3094 #if PRINT_METADATA_TREE
3095 printf("\n--------------- FRAME (OSUBFILETYPE) ---------------\n\n");
3096 sft->getParent()->printAll ();
3097 #endif
3098 }
3099 }
3100 }
3101 }
3102
3103 if(!frameRootDetected) {
3104 std::vector<const Tag*> piTagList = root->findTags("PhotometricInterpretation");
3105 if (!piTagList.empty()) {
3106 for (auto pi : piTagList) {
3107 int piVal = pi->toInt();
3108 if (piVal == (isRaw ? 32803 : 2)) {
3109 frames.push_back(pi->getParent());
3110 //frameRootDetected = true; not used afterward
3111
3112 #if PRINT_METADATA_TREE
3113 printf("\n--------------- FRAME (PHOTOMETRIC) ---------------\n\n");
3114 pi->getParent()->printAll ();
3115 #endif
3116 }
3117 }
3118 }
3119 }
3120
3121 // --- getting next sibling root
3122
3123 ifdOffset = get4 (f, order);
3124
3125 roots.push_back(root);
3126
3127 #if PRINT_METADATA_TREE
3128 printf("\n~~~~~~~~~ ROOT ~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
3129 root->printAll ();
3130 #endif
3131
3132 } while (ifdOffset > 0 && !onlyFirst);
3133
3134 // Security check : if there's at least one root, there must be at least one image.
3135 // If the following occurs, then image detection above has failed or it's an unsupported file type.
3136 // Yet the result of this should be valid.
3137 if (!roots.empty() && frames.empty()) {
3138 frames.push_back(roots.at(0));
3139 }
3140 }
3141
parseJPEG(int offset)3142 void ExifManager::parseJPEG (int offset)
3143 {
3144 if (!f) {
3145 #ifndef NDEBUG
3146 std::cerr << "ERROR : no file opened !" << std::endl;
3147 #endif
3148 return;
3149 }
3150
3151 if(!fseek (f, offset, SEEK_SET)) {
3152 unsigned char c;
3153 if(fread (&c, 1, 1, f) == 1) {
3154 constexpr unsigned char markerl = 0xff;
3155 const char exifid[] = "Exif\0\0";
3156 char idbuff[8];
3157 int tiffbase = -1;
3158
3159 while (fread (&c, 1, 1, f)) {
3160 if (c != markerl) {
3161 continue;
3162 }
3163
3164 if (fread (&c, 1, 1, f) && c == 0xe1) { // APP1 marker found
3165 if (fread (idbuff, 1, 8, f) < 8) {
3166 return;
3167 }
3168
3169 if (!memcmp (idbuff + 2, exifid, 6)) { // Exif info found
3170 tiffbase = ftell (f);
3171
3172 // We need a RawMetaDataLocation to put the 'tiffbase' value
3173 const bool rmlCreated = !rml;
3174 if (rmlCreated) {
3175 rml.reset(new rtengine::RawMetaDataLocation(0));
3176 }
3177 rml->exifBase = tiffbase;
3178 parse (false, true, false);
3179 if (rmlCreated) {
3180 rml.reset();
3181 }
3182 return;
3183 }
3184 }
3185 }
3186 }
3187 }
3188 }
3189
parseTIFF(bool skipIgnored)3190 void ExifManager::parseTIFF (bool skipIgnored)
3191 {
3192 if (!rml) {
3193 rml.reset(new rtengine::RawMetaDataLocation(0));
3194 parse(false, skipIgnored);
3195 rml.reset();
3196 } else {
3197 parse (false,skipIgnored);
3198 }
3199 }
3200
getDefaultTIFFTags(TagDirectory * forthis)3201 std::vector<Tag*> ExifManager::getDefaultTIFFTags (TagDirectory* forthis)
3202 {
3203
3204 std::vector<Tag*> defTags;
3205
3206 defTags.reserve (12);
3207 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "ImageWidth"), 0, LONG));
3208 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "ImageHeight"), 0, LONG));
3209 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "XResolution"), 300, RATIONAL));
3210 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "YResolution"), 300, RATIONAL));
3211 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "ResolutionUnit"), 2, SHORT));
3212 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "Software"), "RawTherapee " RTVERSION));
3213 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "Orientation"), 1, SHORT));
3214 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "SamplesPerPixel"), 3, SHORT));
3215 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "BitsPerSample"), 8, SHORT));
3216 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "PlanarConfiguration"), 1, SHORT));
3217 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "PhotometricInterpretation"), 2, SHORT));
3218 defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "Compression"), 1, SHORT));
3219
3220 return defTags;
3221 }
3222
3223
3224
createJPEGMarker(const TagDirectory * root,const rtengine::procparams::ExifPairs & changeList,int W,int H,unsigned char * buffer)3225 int ExifManager::createJPEGMarker (const TagDirectory* root, const rtengine::procparams::ExifPairs& changeList, int W, int H, unsigned char* buffer)
3226 {
3227
3228 // write tiff header
3229 int offs = 6;
3230 memcpy (buffer, "Exif\0\0", 6);
3231 ByteOrder order = INTEL;
3232
3233 if (root) {
3234 order = root->getOrder ();
3235 }
3236
3237 sset2 ((unsigned short)order, buffer + offs, order);
3238 offs += 2;
3239 sset2 (42, buffer + offs, order);
3240 offs += 2;
3241 sset4 (8, buffer + offs, order);
3242
3243 TagDirectory* cl;
3244
3245 if (root) {
3246 cl = (const_cast<TagDirectory*> (root))->clone (nullptr);
3247 } else {
3248 cl = new TagDirectory (nullptr, ifdAttribs, INTEL);
3249 }
3250
3251 for (rtengine::procparams::ExifPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) {
3252 cl->applyChange (i->first, i->second);
3253 }
3254
3255 const std::vector<Tag*> defTags = getDefaultTIFFTags (cl);
3256
3257 defTags[0]->setInt (W, 0, LONG);
3258 defTags[1]->setInt (H, 0, LONG);
3259 defTags[8]->setInt (8, 0, SHORT);
3260
3261 for (int i = defTags.size() - 1; i >= 0; i--) {
3262 Tag* defTag = defTags[i];
3263 cl->replaceTag (defTag->clone (cl));
3264 delete defTag;
3265 }
3266
3267 cl->sort ();
3268 int size = cl->write (8, buffer + 6);
3269
3270 delete cl;
3271
3272 return size + 6;
3273 }
3274
createPNGMarker(const TagDirectory * root,const rtengine::procparams::ExifPairs & changeList,int W,int H,int bps,const char * iptcdata,int iptclen,unsigned char * & buffer,unsigned & bufferSize)3275 int ExifManager::createPNGMarker(const TagDirectory* root, const rtengine::procparams::ExifPairs &changeList, int W, int H, int bps, const char* iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize)
3276 {
3277 // write tiff header
3278 int offs = 0;
3279 ByteOrder order = HOSTORDER;
3280
3281 if (root) {
3282 order = root->getOrder ();
3283 }
3284
3285 TagDirectory* cl;
3286
3287 if (root) {
3288 cl = (const_cast<TagDirectory*> (root))->clone (nullptr);
3289 // remove some unknown top level tags which produce warnings when opening a tiff
3290 Tag *removeTag = cl->getTag (0x9003);
3291
3292 if (removeTag) {
3293 removeTag->setKeep (false);
3294 }
3295
3296 removeTag = cl->getTag (0x9211);
3297
3298 if (removeTag) {
3299 removeTag->setKeep (false);
3300 }
3301 } else {
3302 cl = new TagDirectory (nullptr, ifdAttribs, HOSTORDER);
3303 }
3304
3305 if (iptcdata) {
3306 Tag* iptc = new Tag (cl, lookupAttrib (ifdAttribs, "IPTCData"));
3307 iptc->initLongArray (iptcdata, iptclen);
3308 cl->replaceTag (iptc);
3309 }
3310
3311 // apply list of changes
3312 for (rtengine::procparams::ExifPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) {
3313 cl->applyChange (i->first, i->second);
3314 }
3315
3316 // append default properties
3317 const std::vector<Tag*> defTags = getDefaultTIFFTags (cl);
3318
3319 defTags[0]->setInt (W, 0, LONG);
3320 defTags[1]->setInt (H, 0, LONG);
3321 defTags[8]->initInt (0, SHORT, 3);
3322
3323 for (int i = 0; i < 3; i++) {
3324 defTags[8]->setInt (bps, i * 2, SHORT);
3325 }
3326
3327 for (int i = defTags.size() - 1; i >= 0; i--) {
3328 Tag* defTag = defTags[i];
3329 cl->replaceTag (defTag->clone (cl));
3330 delete defTag;
3331 }
3332
3333 cl->sort ();
3334 bufferSize = cl->calculateSize() + 8;
3335 buffer = new unsigned char[bufferSize]; // this has to be deleted in caller
3336 sset2 ((unsigned short)order, buffer + offs, order);
3337 offs += 2;
3338 sset2 (42, buffer + offs, order);
3339 offs += 2;
3340 sset4 (8, buffer + offs, order);
3341
3342 int endOffs = cl->write (8, buffer);
3343
3344 // cl->printAll();
3345 delete cl;
3346
3347 return endOffs;
3348 }
3349
3350
3351 //-----------------------------------------------------------------------------
3352 // global functions to read byteorder dependent data
3353 //-----------------------------------------------------------------------------
sget2(unsigned char * s,rtexif::ByteOrder order)3354 unsigned short sget2 (unsigned char *s, rtexif::ByteOrder order)
3355 {
3356
3357 if (order == rtexif::INTEL) {
3358 return s[0] | s[1] << 8;
3359 } else {
3360 return s[0] << 8 | s[1];
3361 }
3362 }
3363
sget4(unsigned char * s,rtexif::ByteOrder order)3364 int sget4 (unsigned char *s, rtexif::ByteOrder order)
3365 {
3366
3367 if (order == rtexif::INTEL) {
3368 return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
3369 } else {
3370 return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
3371 }
3372 }
3373
get2(FILE * f,rtexif::ByteOrder order)3374 inline unsigned short get2 (FILE* f, rtexif::ByteOrder order)
3375 {
3376
3377 unsigned char str[2] = { 0xff, 0xff };
3378 fread (str, 1, 2, f);
3379 return rtexif::sget2 (str, order);
3380 }
3381
get4(FILE * f,rtexif::ByteOrder order)3382 int get4 (FILE* f, rtexif::ByteOrder order)
3383 {
3384
3385 unsigned char str[4] = { 0xff, 0xff, 0xff, 0xff };
3386 fread (str, 1, 4, f);
3387 return rtexif::sget4 (str, order);
3388 }
3389
sset2(unsigned short v,unsigned char * s,rtexif::ByteOrder order)3390 void sset2 (unsigned short v, unsigned char *s, rtexif::ByteOrder order)
3391 {
3392
3393 if (order == rtexif::INTEL) {
3394 s[0] = v & 0xff;
3395 v >>= 8;
3396 s[1] = v;
3397 } else {
3398 s[1] = v & 0xff;
3399 v >>= 8;
3400 s[0] = v;
3401 }
3402 }
3403
sset4(int v,unsigned char * s,rtexif::ByteOrder order)3404 void sset4 (int v, unsigned char *s, rtexif::ByteOrder order)
3405 {
3406
3407 if (order == rtexif::INTEL) {
3408 s[0] = v & 0xff;
3409 v >>= 8;
3410 s[1] = v & 0xff;
3411 v >>= 8;
3412 s[2] = v & 0xff;
3413 v >>= 8;
3414 s[3] = v;
3415 } else {
3416 s[3] = v & 0xff;
3417 v >>= 8;
3418 s[2] = v & 0xff;
3419 v >>= 8;
3420 s[1] = v & 0xff;
3421 v >>= 8;
3422 s[0] = v;
3423 }
3424 }
3425
int_to_float(int i)3426 float int_to_float (int i)
3427 {
3428 union {
3429 int i;
3430 float f;
3431 } u;
3432 u.i = i;
3433 return u.f;
3434 }
3435
int2_to_signed(short unsigned int i)3436 short int int2_to_signed (short unsigned int i)
3437 {
3438 union {
3439 short unsigned int i;
3440 short int s;
3441 } u;
3442 u.i = i;
3443 return u.s;
3444 }
3445
3446 /* Function to parse and extract focal length and aperture information from description
3447 * @fullname must conform to the following formats
3448 * <focal>mm f/<aperture>
3449 * <focal>-<focal>mm f/<aperture>
3450 * <focal>-<focal>mm f/<aperture>-<aperture>
3451 * NB: no space between separator '-'; no space between focal length and 'mm'
3452 */
extractLensInfo(const std::string & fullname,double & minFocal,double & maxFocal,double & maxApertureAtMinFocal,double & maxApertureAtMaxFocal)3453 bool extractLensInfo (const std::string &fullname, double &minFocal, double &maxFocal, double &maxApertureAtMinFocal, double &maxApertureAtMaxFocal)
3454 {
3455 minFocal = 0.0;
3456 maxFocal = 0.0;
3457 maxApertureAtMinFocal = 0.0;
3458 maxApertureAtMaxFocal = 0.0;
3459 char buffer[1025];
3460 strncpy (buffer, fullname.c_str(), 1024);
3461 char *pF = strstr (buffer, "f/" );
3462
3463 if ( pF ) {
3464 sscanf (pF + 2, "%lf-%lf", &maxApertureAtMinFocal, &maxApertureAtMaxFocal);
3465
3466 if (maxApertureAtMinFocal > 0. && maxApertureAtMaxFocal == 0.) {
3467 maxApertureAtMaxFocal = maxApertureAtMinFocal;
3468 }
3469
3470 char *pMM = pF - 3;
3471
3472 while ( pMM[0] != 'm' && pMM[1] != 'm' && pMM > buffer) {
3473 pMM--;
3474 }
3475
3476 if ( pMM[0] == 'm' && pMM[1] == 'm' ) {
3477 char *sp = pMM;
3478
3479 while ( *sp != ' ' && sp > buffer ) {
3480 sp--;
3481 }
3482
3483 sscanf (sp + 1, "%lf-%lf", &minFocal, &maxFocal);
3484
3485 if (maxFocal == 0.) {
3486 maxFocal = minFocal;
3487 }
3488
3489 return true;
3490 }
3491 }
3492
3493 return false;
3494 }
3495
3496 }
3497