libopenraw
ifdfilecontainer.cpp
1 /*
2  * libopenraw - ifdfilecontainer.cpp
3  *
4  * Copyright (C) 2006-2016 Hubert Figuiere
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  Trace(DEBUG1) << "getDirectoryDataSize()"
115  << "\n";
116  off_t dir_offset = m_current_dir->offset();
117  // FIXME check error
118  Trace(DEBUG1) << "offset = " << dir_offset
119  << " m_numTags = " << m_current_dir->numTags() << "\n";
120  off_t begin = dir_offset + 2 + (m_current_dir->numTags() * 12);
121 
122  Trace(DEBUG1) << "begin = " << begin << "\n";
123 
124  m_file->seek(begin, SEEK_SET);
125  begin += 2;
126  int32_t nextIFD;
127  readInt32(m_file, nextIFD);
128  Trace(DEBUG1) << "nextIFD = " << nextIFD << "\n";
129  if (nextIFD == 0) {
130  // FIXME not good
131  }
132  return nextIFD - begin;
133 }
134 
136 {
137  return true;
138 }
139 
140 bool IfdFileContainer::_locateDirs(void)
141 {
142  if (!locateDirsPreHook()) {
143  return false;
144  }
145  Trace(DEBUG1) << "_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 = 0;
158  readInt32(m_file, dir_offset);
159  m_dirs.clear();
160  do {
161  if (dir_offset != 0) {
162  // std::cerr.setf(std::ios_base::hex,
163  // std::ios_base::basefield);
164  Trace(DEBUG1) << "push offset =0x" << dir_offset << "\n";
165 
166  // we assume the offset is relative to the begining of
167  // the IFD.
168  IfdDir::Ref dir(
169  std::make_shared<IfdDir>(m_offset + dir_offset, *this));
170  m_dirs.push_back(dir);
171 
172  // std::cerr.setf((std::ios_base::fmtflags)0,
173  // std::ios_base::basefield);
174 
175  dir_offset = dir->nextIFD();
176  }
177  } while (dir_offset != 0);
178 
179  Trace(DEBUG1) << "# dir found = " << m_dirs.size() << "\n";
180  return (m_dirs.size() != 0);
181 }
182 }
183 }
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
bool readInt32(const IO::Stream::Ptr &f, int32_t &v)