libopenraw
ifdfilecontainer.cpp
1/*
2 * libopenraw - ifdfilecontainer.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#include <fcntl.h>
22#include <sys/types.h>
23#include <memory>
24
25#include <vector>
26
27#include <libopenraw/debug.h>
28
29#include "trace.hpp"
30#include "ifdfilecontainer.hpp"
31
32using namespace Debug;
33
34namespace OpenRaw {
35
36namespace Internals {
37
38IfdFileContainer::IfdFileContainer(const IO::Stream::Ptr &_file, off_t _offset)
39 : RawContainer(_file, _offset)
40 , m_error(0)
41 , m_exif_offset_correction(0)
42 , m_current_dir()
43 , m_dirs()
44{
45}
46
48{
49 m_dirs.clear();
50}
51
53 int len)
54{
55 if (len < 4) {
56 // we need at least 4 bytes to check
57 return ENDIAN_NULL;
58 }
59 if ((p[0] == 0x49) && (p[1] == 0x49) && (p[2] == 0x2a) && (p[3] == 0x00)) {
60 return ENDIAN_LITTLE;
61 } else if ((p[0] == 0x4d) && (p[1] == 0x4d) && (p[2] == 0x00) &&
62 (p[3] == 0x2a)) {
63 return ENDIAN_BIG;
64 }
65 return ENDIAN_NULL;
66}
67
69{
70 if (m_dirs.size() == 0) {
71 // FIXME check result
72 bool ret = _locateDirs();
73 if (!ret) {
74 return -1;
75 }
76 }
77 return m_dirs.size();
78}
79
80std::vector<IfdDir::Ref> &IfdFileContainer::directories()
81{
82 if (m_dirs.size() == 0) {
84 }
85 return m_dirs;
86}
87
89{
90 if (dir < 0) {
91 // FIXME set error
92 return IfdDir::Ref();
93 }
94 // FIXME handle negative values
95 int n = countDirectories();
96 if (n <= 0) {
97 // FIXME set error
98 return IfdDir::Ref();
99 }
100 // dir is signed here because we can pass negative
101 // value for specific Exif IFDs.
102 if (dir > (int)m_dirs.size()) {
103 // FIXME set error
104 return IfdDir::Ref();
105 }
106 m_current_dir = m_dirs[dir];
107 m_current_dir->load();
108 return m_current_dir;
109}
110
112{
113 // TODO move to IFDirectory
114 LOGDBG1("getDirectoryDataSize()\n");
115 off_t dir_offset = m_current_dir->offset();
116 // FIXME check error
117 LOGDBG1("offset = %lld m_numTags = %d\n", (long long int)dir_offset,
118 m_current_dir->numTags());
119 off_t begin = dir_offset + 2 + (m_current_dir->numTags() * 12);
120
121 LOGDBG1("begin = %lld\n", (long long int)begin);
122
123 m_file->seek(begin, SEEK_SET);
124 begin += 2;
125
126 int32_t nextIFD = readInt32(m_file).value_or(0);
127 LOGDBG1("nextIFD = %d\n", nextIFD);
128 if (nextIFD == 0) {
129 // FIXME not good
130 // XXX we should check the Option<> from readInt32().
131 }
132 return nextIFD - begin;
133}
134
136{
137 return true;
138}
139
140bool IfdFileContainer::_locateDirs(void)
141{
142 if (!locateDirsPreHook()) {
143 return false;
144 }
145 LOGDBG1("_locateDirs()\n");
146 if (m_endian == ENDIAN_NULL) {
147 char buf[4];
148 m_file->seek(m_offset, SEEK_SET);
149 m_file->read(buf, 4);
150 m_endian = isMagicHeader(buf, 4);
151 if (m_endian == ENDIAN_NULL) {
152 // FIXME set error code
153 return false;
154 }
155 }
156 m_file->seek(m_offset + 4, SEEK_SET);
157 int32_t dir_offset = readInt32(m_file).value_or(0);
158 m_dirs.clear();
159 do {
160 if (dir_offset != 0) {
161 LOGDBG1("push offset =0x%x\n", dir_offset);
162
163 // we assume the offset is relative to the begining of
164 // the IFD.
165 IfdDir::Ref dir(
166 std::make_shared<IfdDir>(m_offset + dir_offset, *this));
167 m_dirs.push_back(dir);
168
169 dir_offset = dir->nextIFD();
170 }
171 } while (dir_offset != 0);
172
173 LOGDBG1("# dir found = %ld\n", m_dirs.size());
174 return (m_dirs.size() != 0);
175}
176}
177}
std::vector< IfdDir::Ref > & directories()
virtual EndianType isMagicHeader(const char *p, int len)
IfdFileContainer(const IO::Stream::Ptr &file, off_t offset)
Option< int32_t > readInt32(const IO::Stream::Ptr &f)
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard....
Definition: arwfile.cpp:30