libopenraw
ifddir.cpp
1 /*
2  * libopenraw - ifddir.cpp
3  *
4  * Copyright (C) 2006-2016 Hubert Figuiere
5  *
6  * This library is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation, either version 3 of
9  * the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <fcntl.h>
22 #include <cstdint>
23 #include <utility>
24 
25 #include "trace.hpp"
26 #include "io/stream.hpp"
27 #include "ifdfilecontainer.hpp"
28 #include "ifddir.hpp"
29 #include "makernotedir.hpp"
30 
31 using namespace Debug;
32 
33 namespace OpenRaw {
34 
35 namespace Internals {
36 
37 bool IfdDir::isPrimary() const
38 {
39  uint32_t subtype = 1;
40  return getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype) && (subtype == 0);
41 }
42 
43 bool IfdDir::isThumbnail() const
44 {
45  uint32_t subtype = 0;
46  return getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype) && (subtype == 1);
47 }
48 
49 IfdDir::IfdDir(off_t _offset, IfdFileContainer &_container)
50  : m_offset(_offset), m_container(_container), m_entries()
51 {
52 }
53 
54 IfdDir::~IfdDir()
55 {
56 }
57 
59 {
60  Trace(DEBUG1) << "IfdDir::load() m_offset =" << m_offset << "\n";
61  int16_t numEntries = 0;
62  auto file = m_container.file();
63  m_entries.clear();
64  file->seek(m_offset, SEEK_SET);
65  m_container.readInt16(file, numEntries);
66  Trace(DEBUG1) << "num entries " << numEntries << "\n";
67  for (int16_t i = 0; i < numEntries; i++) {
68  uint16_t id;
69  int16_t type;
70  int32_t count;
71  uint32_t data;
72  m_container.readUInt16(file, id);
73  m_container.readInt16(file, type);
74  m_container.readInt32(file, count);
75  file->read(&data, 4);
76  IfdEntry::Ref entry(
77  std::make_shared<IfdEntry>(id, type, count, data, m_container));
78  m_entries[id] = entry;
79  }
80 
81  return true;
82 }
83 
84 IfdEntry::Ref IfdDir::getEntry(uint16_t id) const
85 {
86  std::map<uint16_t, IfdEntry::Ref>::const_iterator iter;
87  iter = m_entries.find(id);
88  if (iter != m_entries.end()) {
89  return iter->second;
90  }
91  return IfdEntry::Ref();
92 }
93 
94 bool IfdDir::getIntegerValue(uint16_t id, uint32_t &v)
95 {
96  bool success = false;
97  IfdEntry::Ref e = getEntry(id);
98  if (e != nullptr) {
99  v = e->getIntegerArrayItem(0);
100  success = true;
101  }
102  return success;
103 }
104 
106 {
107  int16_t numEntries;
108  auto file = m_container.file();
109 
110  if (m_entries.size() == 0) {
111  file->seek(m_offset, SEEK_SET);
112  m_container.readInt16(file, numEntries);
113  Trace(DEBUG1) << "numEntries =" << numEntries << " shifting "
114  << (numEntries * 12) + 2 << "bytes\n";
115  } else {
116  numEntries = m_entries.size();
117  }
118 
119  file->seek(m_offset + (numEntries * 12) + 2, SEEK_SET);
120  int32_t next;
121  m_container.readInt32(file, next);
122  return next;
123 }
124 
128 IfdDir::Ref IfdDir::getSubIFD(uint32_t idx) const
129 {
130  std::vector<uint32_t> offsets;
131  IfdEntry::Ref e = getEntry(IFD::EXIF_TAG_SUB_IFDS);
132  if (e != nullptr) {
133  try {
134  e->getArray(offsets);
135  if (idx >= offsets.size()) {
136  Ref ref(std::make_shared<IfdDir>(offsets[idx], m_container));
137  ref->load();
138  return ref;
139  }
140  }
141  catch (const std::exception &ex) {
142  Trace(ERROR) << "Exception " << ex.what() << "\n";
143  }
144  }
145  return Ref();
146 }
147 
148 bool IfdDir::getSubIFDs(std::vector<IfdDir::Ref> &ifds)
149 {
150  bool success = false;
151  std::vector<uint32_t> offsets;
152  IfdEntry::Ref e = getEntry(IFD::EXIF_TAG_SUB_IFDS);
153  if (e != nullptr) {
154  try {
155  e->getArray(offsets);
156  for (auto iter : offsets) {
157  Ref ifd(std::make_shared<IfdDir>(iter, m_container));
158  ifd->load();
159  ifds.push_back(ifd);
160  }
161  success = true;
162  }
163  catch (const std::exception &ex) {
164  Trace(ERROR) << "Exception " << ex.what() << "\n";
165  }
166  }
167  return success;
168 }
169 
173 IfdDir::Ref IfdDir::getExifIFD()
174 {
175  bool success = false;
176  uint32_t val_offset = 0;
177  success = getValue(IFD::EXIF_TAG_EXIF_IFD_POINTER, val_offset);
178  if (success) {
179  Trace(DEBUG1) << "Exif IFD offset (uncorrected) = " << val_offset
180  << "\n";
181  val_offset += m_container.exifOffsetCorrection();
182  Trace(DEBUG1) << "Exif IFD offset = " << val_offset << "\n";
183  Ref ref(std::make_shared<IfdDir>(val_offset, m_container));
184  ref->load();
185  return ref;
186  } else {
187  Trace(DEBUG1) << "Exif IFD offset not found.\n";
188  }
189  return Ref();
190 }
191 
193 {
194  uint32_t val_offset = 0;
195  IfdEntry::Ref e = getEntry(IFD::EXIF_TAG_MAKER_NOTE);
196  if (!e) {
197  Trace(DEBUG1) << "MakerNote IFD offset not found.\n";
198  return MakerNoteDir::Ref();
199  }
200  val_offset = e->offset();
201  Trace(DEBUG1) << "MakerNote IFD offset (uncorrected) = " << val_offset
202  << "\n";
203  val_offset += m_container.exifOffsetCorrection();
204  Trace(DEBUG1) << "MakerNote IFD offset = " << val_offset << "\n";
205 
206  auto ref = MakerNoteDir::createMakerNote(val_offset, m_container);
207  if (ref) {
208  ref->load();
209  }
210 
211  return ref;
212 }
213 }
214 }
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard. I guess it failed.
Definition: arwfile.cpp:30
bool getSubIFDs(std::vector< IfdDir::Ref > &ifds)
Definition: ifddir.cpp:148
bool getIntegerValue(uint16_t id, uint32_t &v)
Definition: ifddir.cpp:94
static Ref createMakerNote(off_t offset, IfdFileContainer &container)
std::shared_ptr< IfdEntry > Ref
Definition: ifdentry.hpp:178
Definition: trace.cpp:30
Ref getSubIFD(uint32_t idx=0) const
Definition: ifddir.cpp:128