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