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
36using namespace Debug;
37
38namespace OpenRaw {
39namespace Internals {
40
41
42IfdEntry::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 %lld bytes\n",
54 m_count, (long long int)container_size);
55 m_count = container_size / unit_size;
56 }
57}
58
59
60IfdEntry::~IfdEntry()
61{
62 if (m_dataptr) {
63 free(m_dataptr);
64 }
65}
66
67namespace {
68
69template <class T>
70void convert(Internals::IfdEntry* e, std::vector<MetaValue::value_t> & values)
71{
72 auto result = e->getArray<T>();
73 if (result) {
74 std::vector<T> v = result.value();
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.
80template <class T, class T2>
81void convert(Internals::IfdEntry* e, std::vector<MetaValue::value_t> & values)
82{
83 auto result = e->getArray<T>();
84 if (result) {
85 std::vector<T> v = result.value();
86 for(const auto & elem : v) {
87 values.push_back(T2(elem));
88 }
89 }
90}
91
92}
93
94
95size_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}
118MetaValue* 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
155RawContainer::EndianType IfdEntry::endian() const
156{
157 return m_container.endian();
158}
159
160
161bool 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
185uint32_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
221namespace IFD {
222
223Rational::operator double() const
224{
225 if(denom == 0) {
226 return INFINITY;
227 }
228 return (double)num / (double)denom;
229}
230
231SRational::operator double() const
232{
233 if(denom == 0) {
234 return INFINITY;
235 }
236 return (double)num / (double)denom;
237}
238
239}
240
241template <>
242const uint16_t IfdTypeTrait<uint8_t>::type = IFD::EXIF_FORMAT_BYTE;
243template <>
244const size_t IfdTypeTrait<uint8_t>::size = 1;
245
246template <>
247const uint16_t IfdTypeTrait<uint16_t>::type = IFD::EXIF_FORMAT_SHORT;
248template <>
249const size_t IfdTypeTrait<uint16_t>::size = 2;
250
251template <>
252const uint16_t IfdTypeTrait<IFD::Rational>::type = IFD::EXIF_FORMAT_RATIONAL;
253template <>
254const size_t IfdTypeTrait<IFD::Rational>::size = 8;
255
256template <>
257const uint16_t IfdTypeTrait<IFD::SRational>::type = IFD::EXIF_FORMAT_SRATIONAL;
258template <>
259const size_t IfdTypeTrait<IFD::SRational>::size = 8;
260
261
262template <>
263const uint16_t IfdTypeTrait<uint32_t>::type = IFD::EXIF_FORMAT_LONG;
264template <>
265const size_t IfdTypeTrait<uint32_t>::size = 4;
266
267template <>
268const uint16_t IfdTypeTrait<std::string>::type = IFD::EXIF_FORMAT_ASCII;
269template <>
270const 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*/
static size_t type_unit_size(IFD::ExifTagType _type)
Definition ifdentry.cpp:95
bool loadData(size_t unit_size)
Definition ifdentry.cpp:161
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard....
Definition arwfile.cpp:30
static T get(IfdEntry &e, uint32_t idx=0, bool ignore_type=false) noexcept(false)
Definition ifdentry.hpp:262