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 
32 using namespace Debug;
33 
34 namespace OpenRaw {
35 
36 namespace Internals {
37 
38 IfdFileContainer::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 
80 std::vector<IfdDir::Ref> &IfdFileContainer::directories()
81 {
82  if (m_dirs.size() == 0) {
84  }
85  return m_dirs;
86 }
87 
88 IfdDir::Ref IfdFileContainer::setDirectory(int dir)
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 = %ld m_numTags = %d\n", dir_offset, m_current_dir->numTags());
118  off_t begin = dir_offset + 2 + (m_current_dir->numTags() * 12);
119 
120  LOGDBG1("begin = %ld\n", begin);
121 
122  m_file->seek(begin, SEEK_SET);
123  begin += 2;
124 
125  int32_t nextIFD = readInt32(m_file).unwrap_or(0);
126  LOGDBG1("nextIFD = %d\n", nextIFD);
127  if (nextIFD == 0) {
128  // FIXME not good
129  // XXX we should check the Option<> from readInt32().
130  }
131  return nextIFD - begin;
132 }
133 
135 {
136  return true;
137 }
138 
139 bool IfdFileContainer::_locateDirs(void)
140 {
141  if (!locateDirsPreHook()) {
142  return false;
143  }
144  LOGDBG1("_locateDirs()\n");
145  if (m_endian == ENDIAN_NULL) {
146  char buf[4];
147  m_file->seek(m_offset, SEEK_SET);
148  m_file->read(buf, 4);
149  m_endian = isMagicHeader(buf, 4);
150  if (m_endian == ENDIAN_NULL) {
151  // FIXME set error code
152  return false;
153  }
154  }
155  m_file->seek(m_offset + 4, SEEK_SET);
156  int32_t dir_offset = readInt32(m_file).unwrap_or(0);
157  m_dirs.clear();
158  do {
159  if (dir_offset != 0) {
160  LOGDBG1("push offset =0x%x\n", dir_offset);
161 
162  // we assume the offset is relative to the begining of
163  // the IFD.
164  IfdDir::Ref dir(
165  std::make_shared<IfdDir>(m_offset + dir_offset, *this));
166  m_dirs.push_back(dir);
167 
168  dir_offset = dir->nextIFD();
169  }
170  } while (dir_offset != 0);
171 
172  LOGDBG1("# dir found = %ld\n", m_dirs.size());
173  return (m_dirs.size() != 0);
174 }
175 }
176 }
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
virtual EndianType isMagicHeader(const char *p, int len)
std::vector< IfdDir::Ref > & directories()
Definition: trace.cpp:30
Option< int32_t > readInt32(const IO::Stream::Ptr &f)