libopenraw
ifdfilecontainer.cpp
1 /*
2  * libopenraw - ifdfilecontainer.cpp
3  *
4  * Copyright (C) 2006 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 <sys/types.h>
22 
23 #include <cstdlib>
24 #include <cstdio>
25 #include <vector>
26 #include <iostream>
27 
28 #include "trace.h"
29 
30 #include "ifdfilecontainer.h"
31 #include "io/file.h"
32 
33 
34 using namespace Debug;
35 
36 namespace OpenRaw {
37 
38  namespace Internals {
39 
40  IFDFileContainer::IFDFileContainer(IO::Stream *_file, off_t offset)
41  : RawContainer(_file, offset),
42  m_error(0),
43  m_exif_offset_correction(0),
44  m_current_dir(),
45  m_dirs()
46  {
47  }
48 
50  {
51  m_dirs.clear();
52  }
53 
54 
56  IFDFileContainer::isMagicHeader(const char *p, int len)
57  {
58  if (len < 4){
59  // we need at least 4 bytes to check
60  return ENDIAN_NULL;
61  }
62  if ((p[0] == 0x49) && (p[1] == 0x49)
63  && (p[2] == 0x2a) && (p[3] == 0x00)) {
64  return ENDIAN_LITTLE;
65  }
66  else if ((p[0] == 0x4d) && (p[1] == 0x4d)
67  && (p[2] == 0x00) && (p[3] == 0x2a)) {
68  return ENDIAN_BIG;
69  }
70  return ENDIAN_NULL;
71  }
72 
73 
75  {
76  if (m_dirs.size() == 0) {
77  // FIXME check result
78  bool ret = _locateDirs();
79  if (!ret) {
80  return -1;
81  }
82  }
83  return m_dirs.size();
84  }
85 
86  std::vector<IFDDir::Ref> &
88  {
89  if (m_dirs.size() == 0) {
91  }
92  return m_dirs;
93  }
94 
95  IFDDir::Ref
97  {
98  if (dir < 0) {
99  // FIXME set error
100  return IFDDir::Ref((IFDDir*)NULL);
101  }
102  // FIXME handle negative values
103  int n = countDirectories();
104  if (n <= 0) {
105  // FIXME set error
106  return IFDDir::Ref((IFDDir*)NULL);
107  }
108  // dir is signed here because we can pass negative
109  // value for specific Exif IFDs.
110  if (dir > (int)m_dirs.size()) {
111  // FIXME set error
112  return IFDDir::Ref((IFDDir*)NULL);
113  }
114  m_current_dir = m_dirs[dir];
115  m_current_dir->load();
116  return m_current_dir;
117  }
118 
119 
120  size_t
122  {
123  // TODO move to IFDirectory
124  Trace(DEBUG1) << "getDirectoryDataSize()" << "\n";
125  off_t offset = m_current_dir->offset();
126  // FIXME check error
127  Trace(DEBUG1) << "offset = " << offset
128  << " m_numTags = " << m_current_dir->numTags() << "\n";
129  off_t begin = offset + 2 + (m_current_dir->numTags()*12);
130 
131  Trace(DEBUG1) << "begin = " << begin << "\n";
132 
133  m_file->seek(begin, SEEK_SET);
134  begin += 2;
135  int32_t nextIFD;
136  readInt32(m_file, nextIFD);
137  Trace(DEBUG1) << "nextIFD = " << nextIFD << "\n";
138  if (nextIFD == 0) {
139  // FIXME not good
140  }
141  return nextIFD - begin;
142  }
143 
145  {
146  return true;
147  }
148 
149 
150  bool
151  IFDFileContainer::_locateDirs(void)
152  {
153  if(!locateDirsPreHook()) {
154  return false;
155  }
156  Trace(DEBUG1) << "_locateDirs()\n";
157  if (m_endian == ENDIAN_NULL) {
158  char buf[4];
159  m_file->seek(m_offset, SEEK_SET);
160  m_file->read(buf, 4);
161  m_endian = isMagicHeader(buf, 4);
162  if (m_endian == ENDIAN_NULL) {
163  // FIXME set error code
164  return false;
165  }
166  }
167  m_file->seek(m_offset + 4, SEEK_SET);
168  int32_t offset = 0;
169  readInt32(m_file, offset);
170  m_dirs.clear();
171  do {
172  if (offset != 0) {
173 // std::cerr.setf(std::ios_base::hex, std::ios_base::basefield);
174  Trace(DEBUG1) << "push offset =0x" << offset << "\n";
175 
176  // we assume the offset is relative to the begining of
177  // the IFD.
178  IFDDir::Ref dir(new IFDDir(m_offset + offset,*this));
179  m_dirs.push_back(dir);
180 
181 // std::cerr.setf((std::ios_base::fmtflags)0, std::ios_base::basefield);
182 
183  offset = dir->nextIFD();
184  }
185  } while(offset != 0);
186 
187  Trace(DEBUG1) << "# dir found = " << m_dirs.size() << "\n";
188  return (m_dirs.size() != 0);
189  }
190 
191 
192  }
193 }
194 
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:33
virtual int seek(off_t offset, int whence)=0
Definition: trace.cpp:28
virtual int read(void *buf, size_t count)=0
std::vector< IFDDir::Ref > & directories()
bool readInt32(IO::Stream *f, int32_t &v)
base virtual class for IO
Definition: stream.h:40
virtual EndianType isMagicHeader(const char *p, int len)