libopenraw
ifddir.cpp
1 /*
2  * libopenraw - ifddir.cpp
3  *
4  * Copyright (C) 2006-2007 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 
22 #include <libopenraw/types.h>
23 
24 #include "trace.h"
25 #include "exception.h"
26 #include "ifd.h"
27 #include "io/stream.h"
28 #include "ifdfilecontainer.h"
29 #include "ifddir.h"
30 
31 using namespace Debug;
32 
33 namespace OpenRaw {
34 
35  namespace Internals {
36 
37  bool IFDDir::isPrimary::operator()(const Ref &dir)
38  {
39  uint32_t subtype = 1;
40  return dir->getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype)
41  && (subtype == 0);
42  }
43 
44  bool IFDDir::isThumbnail::operator()(const Ref &dir)
45  {
46  uint32_t subtype = 0;
47  return dir->getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype)
48  && (subtype == 1);
49  }
50 
51  IFDDir::IFDDir(off_t _offset, IFDFileContainer & _container)
52  : m_offset(_offset), m_container(_container),
53  m_entries()
54  {
55 
56  }
57 
58  IFDDir::~IFDDir()
59  {
60 
61  }
62 
63  bool IFDDir::load()
64  {
65  Trace(DEBUG1) << "IFDDir::load() m_offset =" << m_offset << "\n";
66  int16_t numEntries = 0;
67  IO::Stream *file = m_container.file();
68  m_entries.clear();
69  file->seek(m_offset, SEEK_SET);
70  m_container.readInt16(file, numEntries);
71 
72  for(int16_t i = 0; i < numEntries; i++) {
73  uint16_t id;
74  int16_t type;
75  int32_t count;
76  uint32_t data;
77  m_container.readUInt16(file, id);
78  m_container.readInt16(file, type);
79  m_container.readInt32(file, count);
80  file->read(&data, 4);
81  IFDEntry::Ref entry(new IFDEntry(id, type,
82  count, data, m_container));
83  m_entries[id] = entry;
84  }
85 
86  return true;
87  }
88 
89  IFDEntry::Ref IFDDir::getEntry(uint16_t id) const
90  {
91  std::map<uint16_t, IFDEntry::Ref>::const_iterator iter;
92  iter = m_entries.find(id);
93  if (iter != m_entries.end()) {
94  return iter->second;
95  }
96  return IFDEntry::Ref((IFDEntry*)NULL);
97  }
98 
99 
100  bool IFDDir::getIntegerValue(uint16_t id, uint32_t &v)
101  {
102  bool success = false;
103  IFDEntry::Ref e = getEntry(id);
104  if (e != NULL) {
105  try {
106  switch(e->type())
107  {
108  case IFD::EXIF_FORMAT_LONG:
110  success = true;
111  break;
112  case IFD::EXIF_FORMAT_SHORT:
114  success = true;
115  break;
116  default:
117  break;
118  }
119  }
120  catch(const std::exception & ex) {
121  Trace(ERROR) << "Exception raised " << ex.what()
122  << " fetch integer value for " << id << "\n";
123  }
124  }
125  return success;
126  }
127 
128 
130  {
131  int16_t numEntries;
132  IO::Stream *file = m_container.file();
133 
134  if(m_entries.size() == 0) {
135  file->seek(m_offset, SEEK_SET);
136  m_container.readInt16(file, numEntries);
137  Trace(DEBUG1) << "numEntries =" << numEntries
138  << " shifting " << (numEntries * 12) + 2
139  << "bytes\n";
140  }
141  else {
142  numEntries = m_entries.size();
143  }
144 
145  file->seek(m_offset + (numEntries * 12) + 2, SEEK_SET);
146  int32_t next;
147  m_container.readInt32(file, next);
148  return next;
149  }
150 
154  IFDDir::Ref IFDDir::getSubIFD(uint32_t idx) const
155  {
156  std::vector<uint32_t> offsets;
157  IFDEntry::Ref e = getEntry(IFD::EXIF_TAG_SUB_IFDS);
158  if (e != NULL) {
159  try {
160  e->getArray(offsets);
161  if (idx >= offsets.size()) {
162  Ref ref(new IFDDir(offsets[idx], m_container));
163  ref->load();
164  return ref;
165  }
166  }
167  catch(const std::exception &ex) {
168  Trace(ERROR) << "Exception " << ex.what() << "\n";
169  }
170  }
171  return Ref(static_cast<IFDDir*>(NULL));
172  }
173 
174 
175  bool IFDDir::getSubIFDs(std::vector<IFDDir::Ref> & ifds)
176  {
177  bool success = false;
178  std::vector<uint32_t> offsets;
179  IFDEntry::Ref e = getEntry(IFD::EXIF_TAG_SUB_IFDS);
180  if (e != NULL) {
181  try {
182  e->getArray(offsets);
183  for (std::vector<uint32_t>::const_iterator iter = offsets.begin();
184  iter != offsets.end(); iter++) {
185  Ref ifd(new IFDDir(*iter, m_container));
186  ifd->load();
187  ifds.push_back(ifd);
188  }
189  success = true;
190  }
191  catch(const std::exception &ex) {
192  Trace(ERROR) << "Exception " << ex.what() << "\n";
193  }
194  }
195  return success;
196  }
197 
201  IFDDir::Ref IFDDir::getExifIFD()
202  {
203  bool success = false;
204  uint32_t val_offset = 0;
205  success = getValue(IFD::EXIF_TAG_EXIF_IFD_POINTER, val_offset);
206  if (success) {
207  Trace(DEBUG1) << "Exif IFD offset (uncorrected) = " << val_offset
208  << "\n";
209  val_offset += m_container.exifOffsetCorrection();
210  Trace(DEBUG1) << "Exif IFD offset = " << val_offset << "\n";
211  Ref ref(new IFDDir(val_offset, m_container));
212  ref->load();
213  return ref;
214  }
215  else {
216  Trace(DEBUG1) << "Exif IFD offset not found.\n";
217  }
218  return Ref(static_cast<IFDDir*>(NULL));
219  }
220 
221  }
222 }
223