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 (&timestamp));
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 (&timestamp);
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