libopenraw
mrwcontainer.cpp
1 /*
2  * libopenraw - mrwcontainer.cpp
3  *
4  * Copyright (C) 2006 Hubert Figuiere
5  * Copyright (C) 2008 Bradley Broom
6  *
7  * This library is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation, either version 3 of
10  * the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library. If not, see
19  * <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "trace.h"
23 #include "mrwcontainer.h"
24 #include "io/file.h"
25 
26 
27 using namespace Debug;
28 
29 namespace OpenRaw {
30 
31  namespace Internals {
32 
33  namespace MRW {
34 
35  DataBlock::DataBlock(off_t start, MRWContainer * _container)
36  : m_start(start),
37  m_container(_container),
38  m_loaded(false)
39  {
40  Trace(DEBUG2) << "> DataBlock start == " << start << "\n";
41  if (m_container->fetchData (m_name, m_start, 4) != 4) {
42  // FIXME: Handle error
43  Trace(WARNING) << " Error reading block name " << start << "\n";
44  return;
45  }
46  if (!m_container->readInt32 (m_container->file(), m_length)) {
47  // FIXME: Handle error
48  Trace(WARNING) << " Error reading block length " << start << "\n";
49  return;
50  }
51  Trace(DEBUG1) << " DataBlock " << name()
52  << ", length " << m_length
53  << " at " << m_start << "\n";
54  Trace(DEBUG2) << "< DataBlock\n";
55  m_loaded = true;
56  }
57 
58  int8_t DataBlock::int8_val (off_t off)
59  {
60  int8_t ret;
61  MRWContainer *mc = m_container;
62  mc->file()->seek (m_start + DataBlockHeaderLength + off, SEEK_SET);
63  mc->readInt8 (mc->file(), ret);
64  return ret;
65  }
66 
67  uint8_t DataBlock::uint8_val (off_t off)
68  {
69  uint8_t ret;
70  MRWContainer *mc = m_container;
71  mc->file()->seek (m_start + DataBlockHeaderLength + off, SEEK_SET);
72  mc->readUInt8 (mc->file(), ret);
73  return ret;
74  }
75 
76  uint16_t DataBlock::uint16_val (off_t off)
77  {
78  uint16_t ret;
79  MRWContainer *mc = m_container;
80  mc->file()->seek (m_start + DataBlockHeaderLength + off, SEEK_SET);
81  mc->readUInt16 (mc->file(), ret);
82  return ret;
83  }
84 
85  std::string DataBlock::string_val(off_t off)
86  {
87  char buf[9];
88  size_t s;
89  MRWContainer *mc = m_container;
90  s = mc->fetchData(buf, m_start + DataBlockHeaderLength + off, 8);
91  if(s == 8) {
92  buf[8] = 0;
93  }
94  else {
95  *buf = 0;
96  }
97  return buf;
98  }
99  }
100 
101  MRWContainer::MRWContainer(IO::Stream *_file, off_t offset)
102  : IFDFileContainer(_file, offset)
103  {
104 
105  }
106 
107 
109  {
110  }
111 
112 
114  MRWContainer::isMagicHeader(const char *p, int len)
115  {
116  if (len < 4) {
117  // we need at least 4 bytes to check
118  return ENDIAN_NULL;
119  }
120 
121  if ((p[0] == 0x00) && (p[1] == 'M') &&
122  (p[2] == 'R') && (p[3] == 'M')) {
123 
124  Trace(DEBUG1) << "Identified MRW file\n";
125 
126  return ENDIAN_BIG;
127  }
128 
129  Trace(DEBUG1) << "Unidentified MRW file\n";
130 
131  return ENDIAN_NULL;
132  }
133 
135  {
136  char version[9];
137  off_t position;
138 
139  Trace(DEBUG1) << "> MRWContainer::locateDirsPreHook()\n";
140  m_endian = ENDIAN_BIG;
141 
142  /* MRW file always starts with an MRM datablock. */
143  mrm = MRW::DataBlock::Ref (new MRW::DataBlock (m_offset, this));
144  if (mrm->name() != "MRM") {
145  Trace(WARNING) << "MRW file begins not with MRM block, "
146  "but with unrecognized DataBlock :: name == "
147  << mrm->name() << "\n";
148  return false;
149  }
150 
151  /* Subblocks are contained within the MRM block. Scan them and create
152  * appropriate block descriptors.
153  */
154  position = mrm->offset() + MRW::DataBlockHeaderLength;
155  while (position < pixelDataOffset()) {
156  MRW::DataBlock::Ref ref (new MRW::DataBlock (position, this));
157  Trace(DEBUG1) << "Loaded DataBlock :: name == " << ref->name() << "\n";
158  if(!ref || !ref->loaded()) {
159  break;
160  }
161  if (ref->name() == "PRD") {
162  if (prd != NULL) {
163  Trace(WARNING) << "File contains duplicate DataBlock :: name == "
164  << ref->name() << "\n";
165  }
166  prd = ref;
167  }
168  else if (ref->name() == "TTW") {
169  if (ttw != NULL) {
170  Trace(WARNING) << "File contains duplicate DataBlock :: name == "
171  << ref->name() << "\n";
172  }
173  ttw = ref;
174  }
175  else if (ref->name() == "WBG") {
176  if (wbg != NULL) {
177  Trace(WARNING) << "File contains duplicate DataBlock :: name == "
178  << ref->name() << "\n";
179  }
180  wbg = ref;
181  }
182  else if (ref->name() == "RIF") {
183  if (rif != NULL) {
184  Trace(WARNING) << "File contains duplicate DataBlock :: name == "
185  << ref->name() << "\n";
186  }
187  rif = ref;
188  }
189  else if (ref->name() != "PAD") {
190  Trace(WARNING) << "File contains unrecognized DataBlock :: name == "
191  << ref->name() << "\n";
192  }
193  position = ref->offset() + MRW::DataBlockHeaderLength + ref->length();
194  }
195 
196  /* Check that we found all the expected data blocks. */
197  if (prd == NULL) {
198  Trace(WARNING) << "File does NOT contain expected DataBlock :: name == PRD\n";
199  return false;
200  }
201  if (ttw == NULL) {
202  Trace(WARNING) << "File does NOT contain expected DataBlock :: name == TTW\n";
203  return false;
204  }
205  if (wbg == NULL) {
206  Trace(WARNING) << "File does NOT contain expected DataBlock :: name == WBG\n";
207  return false;
208  }
209  if (rif == NULL) {
210  Trace(WARNING) << "File does NOT contain expected DataBlock :: name == RIF\n";
211  return false;
212  }
213 
214  /* Extract the file version string. */
215  if (fetchData (version, prd->offset()+MRW::DataBlockHeaderLength+MRW::PRD_VERSION, 8) != 8) {
216  // FIXME: Handle error
217  Debug::Trace(DEBUG1) << " Error reading version string\n";
218  }
219  version[8] = '\0';
220  m_version = std::string (version);
221  Trace(DEBUG1) << " MRW file version == " << m_version << "\n";
222 
223  /* For the benefit of our parent class, set the container offset to the beginning of
224  * the TIFF data (the contents of the TTW data block), and seek there.
225  */
226  m_offset = ttw->offset() + MRW::DataBlockHeaderLength;
227  if((version[2] != '7') || (version[3] != '3')) {
228  setExifOffsetCorrection(m_offset);
229  Trace(DEBUG1) << "setting correction to " << m_offset << "\n";
230  }
231  m_file->seek (m_offset, SEEK_SET);
232  Trace(DEBUG1) << "< MRWContainer\n";
233 
234  return true;
235  }
236 
237  }
238 }
size_t fetchData(void *buf, const off_t offset, const size_t buf_size)
virtual IFDFileContainer::EndianType isMagicHeader(const char *p, int len)
bool readUInt16(IO::Stream *f, uint16_t &v)
virtual int seek(off_t offset, int whence)=0
uint16_t uint16_val(off_t offset)
bool readInt32(IO::Stream *f, int32_t &v)
uint8_t uint8_val(off_t offset)