libopenraw
ifdentry.cpp
1 /*
2  * libopenraw - ifdentry.cpp
3  *
4  * Copyright (C) 2006-2017 Hubert Figuière
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 <stdlib.h>
23 #include <math.h>
24 
25 #include <cstdint>
26 #include <string>
27 
28 #include <libopenraw/debug.h>
29 
30 #include "metavalue.hpp"
31 #include "trace.hpp"
32 #include "ifdfilecontainer.hpp"
33 #include "ifdentry.hpp"
34 #include "ifd.hpp"
35 
36 using namespace Debug;
37 
38 namespace OpenRaw {
39 namespace Internals {
40 
41 
42 IfdEntry::IfdEntry(uint16_t _id, int16_t _type,
43  int32_t _count, uint32_t _data,
44  IfdFileContainer &_container)
45  : m_id(_id), m_type(_type),
46  m_count(_count), m_data(_data),
47  m_loaded(false), m_dataptr(NULL),
48  m_container(_container)
49 {
50  auto container_size = m_container.size();
51  auto unit_size = type_unit_size(static_cast<IFD::ExifTagType>(m_type));
52  if ((m_count * unit_size) > static_cast<size_t>(container_size)) {
53  LOGERR("Trying to have %u items in a container of %ld bytes\n",
54  m_count, container_size);
55  m_count = container_size / unit_size;
56  }
57 }
58 
59 
60 IfdEntry::~IfdEntry()
61 {
62  if (m_dataptr) {
63  free(m_dataptr);
64  }
65 }
66 
67 namespace {
68 
69 template <class T>
70 void convert(Internals::IfdEntry* e, std::vector<MetaValue::value_t> & values)
71 {
72  auto result = e->getArray<T>();
73  if (result.ok()) {
74  std::vector<T> v = result.unwrap();
75  values.insert(values.end(), v.cbegin(), v.cend());
76  }
77 }
78 
79 // T is the Ifd primitive type. T2 is the target MetaValue type.
80 template <class T, class T2>
81 void convert(Internals::IfdEntry* e, std::vector<MetaValue::value_t> & values)
82 {
83  auto result = e->getArray<T>();
84  if (result.ok()) {
85  std::vector<T> v = result.unwrap();
86  for(const auto & elem : v) {
87  values.push_back(T2(elem));
88  }
89  }
90 }
91 
92 }
93 
94 
95 size_t IfdEntry::type_unit_size(IFD::ExifTagType _type)
96 {
97  switch(_type) {
98  case IFD::EXIF_FORMAT_BYTE:
99  case IFD::EXIF_FORMAT_SBYTE:
100  case IFD::EXIF_FORMAT_ASCII:
101  case IFD::EXIF_FORMAT_UNDEFINED:
102  return 1;
103  case IFD::EXIF_FORMAT_SHORT:
104  case IFD::EXIF_FORMAT_SSHORT:
105  return 2;
106  case IFD::EXIF_FORMAT_LONG:
107  case IFD::EXIF_FORMAT_SLONG:
108  case IFD::EXIF_FORMAT_FLOAT:
109  return 4;
110  case IFD::EXIF_FORMAT_RATIONAL:
111  case IFD::EXIF_FORMAT_SRATIONAL:
112  case IFD::EXIF_FORMAT_DOUBLE:
113  return 8;
114  }
115 
116  return 0;
117 }
118 MetaValue* IfdEntry::make_meta_value()
119 {
120  std::vector<MetaValue::value_t> values;
121 
122  switch(type()) {
123  case Internals::IFD::EXIF_FORMAT_BYTE:
124  {
125  convert<uint8_t, uint32_t>(this, values);
126  break;
127  }
128  case Internals::IFD::EXIF_FORMAT_ASCII:
129  {
130  convert<std::string>(this, values);
131  break;
132  }
133  case Internals::IFD::EXIF_FORMAT_SHORT:
134  {
135  convert<uint16_t, uint32_t>(this, values);
136  break;
137  }
138  case Internals::IFD::EXIF_FORMAT_LONG:
139  {
140  convert<uint32_t>(this, values);
141  break;
142  }
143  case Internals::IFD::EXIF_FORMAT_SRATIONAL:
144  {
145  convert<Internals::IFD::SRational, double>(this, values);
146  break;
147  }
148  default:
149  LOGDBG1("unhandled type %d\n", type());
150  return NULL;
151  }
152  return new MetaValue(values);
153 }
154 
155 RawContainer::EndianType IfdEntry::endian() const
156 {
157  return m_container.endian();
158 }
159 
160 
161 bool IfdEntry::loadData(size_t unit_size)
162 {
163  bool success = false;
164  size_t data_size = unit_size * m_count;
165  if (data_size <= 4) {
166  m_dataptr = NULL;
167  success = true;
168  }
169  else {
170  off_t _offset;
171  if (endian() == RawContainer::ENDIAN_LITTLE) {
172  _offset = IfdTypeTrait<uint32_t>::EL((uint8_t*)&m_data, sizeof(uint32_t));
173  } else {
174  _offset = IfdTypeTrait<uint32_t>::BE((uint8_t*)&m_data, sizeof(uint32_t));
175  }
176  _offset += m_container.exifOffsetCorrection();
177  m_dataptr = (uint8_t*)realloc(m_dataptr, data_size);
178  success = (m_container.fetchData(m_dataptr,
179  _offset,
180  data_size) == data_size);
181  }
182  return success;
183 }
184 
185 uint32_t IfdEntry::getIntegerArrayItem(int idx)
186 {
187  uint32_t v = 0;
188 
189  try {
190  switch(type())
191  {
192  case IFD::EXIF_FORMAT_LONG:
193  v = IfdTypeTrait<uint32_t>::get(*this, idx);
194  break;
195  case IFD::EXIF_FORMAT_SHORT:
196  v = IfdTypeTrait<uint16_t>::get(*this, idx);
197  break;
198  case IFD::EXIF_FORMAT_RATIONAL:
199  {
201  if(r.denom == 0) {
202  v = 0;
203  }
204  else {
205  v = r.num / r.denom;
206  }
207  break;
208  }
209  default:
210  break;
211  }
212  }
213  catch(const std::exception & ex) {
214  LOGERR("Exception raised %s fetch integer value for %d\n", ex.what(), m_id);
215  }
216 
217  return v;
218 }
219 
220 
221 namespace IFD {
222 
223 Rational::operator double() const
224 {
225  if(denom == 0) {
226  return INFINITY;
227  }
228  return (double)num / (double)denom;
229 }
230 
231 SRational::operator double() const
232 {
233  if(denom == 0) {
234  return INFINITY;
235  }
236  return (double)num / (double)denom;
237 }
238 
239 }
240 
241 template <>
242 const uint16_t IfdTypeTrait<uint8_t>::type = IFD::EXIF_FORMAT_BYTE;
243 template <>
244 const size_t IfdTypeTrait<uint8_t>::size = 1;
245 
246 template <>
247 const uint16_t IfdTypeTrait<uint16_t>::type = IFD::EXIF_FORMAT_SHORT;
248 template <>
249 const size_t IfdTypeTrait<uint16_t>::size = 2;
250 
251 template <>
252 const uint16_t IfdTypeTrait<IFD::Rational>::type = IFD::EXIF_FORMAT_RATIONAL;
253 template <>
254 const size_t IfdTypeTrait<IFD::Rational>::size = 8;
255 
256 template <>
257 const uint16_t IfdTypeTrait<IFD::SRational>::type = IFD::EXIF_FORMAT_SRATIONAL;
258 template <>
259 const size_t IfdTypeTrait<IFD::SRational>::size = 8;
260 
261 
262 template <>
263 const uint16_t IfdTypeTrait<uint32_t>::type = IFD::EXIF_FORMAT_LONG;
264 template <>
265 const size_t IfdTypeTrait<uint32_t>::size = 4;
266 
267 template <>
268 const uint16_t IfdTypeTrait<std::string>::type = IFD::EXIF_FORMAT_ASCII;
269 template <>
270 const size_t IfdTypeTrait<std::string>::size = 1;
271 }
272 }
273 /*
274  Local Variables:
275  mode:c++
276  c-file-style:"stroustrup"
277  c-file-offsets:((innamespace . 0))
278  tab-width:4
279  c-basic-offset:4
280  indent-tabs-mode:t
281  fill-column:80
282  End:
283 */
size_t fetchData(void *buf, off_t offset, size_t buf_size)
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 T get(IfdEntry &e, uint32_t idx=0, bool ignore_type=false) noexcept(false)
Definition: ifdentry.hpp:262
Definition: trace.cpp:30
static size_t type_unit_size(IFD::ExifTagType _type)
Definition: ifdentry.cpp:95
bool loadData(size_t unit_size)
Definition: ifdentry.cpp:161