libopenraw
mrwcontainer.cpp
1 /*
2  * libopenraw - mrwcontainer.cpp
3  *
4  * Copyright (C) 2006-2016 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 <fcntl.h>
23 #include <stddef.h>
24 
25 #include <libopenraw/debug.h>
26 
27 #include "trace.hpp"
28 #include "mrwcontainer.hpp"
29 
30 using namespace Debug;
31 
32 namespace OpenRaw {
33 namespace Internals {
34 
35 namespace MRW {
36 
37 DataBlock::DataBlock(off_t start, MRWContainer *_container)
38  : m_start(start), m_container(_container), 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() << ", length " << m_length
52  << " at " << m_start << "\n";
53  Trace(DEBUG2) << "< DataBlock\n";
54  m_loaded = true;
55 }
56 
57 int8_t DataBlock::int8_val(off_t off)
58 {
59  int8_t ret;
60  MRWContainer *mc = m_container;
61  mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
62  mc->readInt8(mc->file(), ret);
63  return ret;
64 }
65 
66 uint8_t DataBlock::uint8_val(off_t off)
67 {
68  uint8_t ret;
69  MRWContainer *mc = m_container;
70  mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
71  mc->readUInt8(mc->file(), ret);
72  return ret;
73 }
74 
75 uint16_t DataBlock::uint16_val(off_t off)
76 {
77  uint16_t ret;
78  MRWContainer *mc = m_container;
79  mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
80  mc->readUInt16(mc->file(), ret);
81  return ret;
82 }
83 
84 std::string DataBlock::string_val(off_t off)
85 {
86  char buf[9];
87  size_t s;
88  MRWContainer *mc = m_container;
89  s = mc->fetchData(buf, m_start + DataBlockHeaderLength + off, 8);
90  if (s == 8) {
91  buf[8] = 0;
92  } else {
93  *buf = 0;
94  }
95  return buf;
96 }
97 }
98 
99 MRWContainer::MRWContainer(const IO::Stream::Ptr &_file, off_t _offset)
100  : IfdFileContainer(_file, _offset)
101 {
102 }
103 
105 {
106 }
107 
109 {
110  if (len < 4) {
111  // we need at least 4 bytes to check
112  return ENDIAN_NULL;
113  }
114 
115  if ((p[0] == 0x00) && (p[1] == 'M') && (p[2] == 'R') && (p[3] == 'M')) {
116 
117  Trace(DEBUG1) << "Identified MRW file\n";
118 
119  return ENDIAN_BIG;
120  }
121 
122  Trace(DEBUG1) << "Unidentified MRW file\n";
123 
124  return ENDIAN_NULL;
125 }
126 
128 {
129  char version[9];
130  off_t position;
131 
132  Trace(DEBUG1) << "> MRWContainer::locateDirsPreHook()\n";
133  m_endian = ENDIAN_BIG;
134 
135  /* MRW file always starts with an MRM datablock. */
136  mrm = std::make_shared<MRW::DataBlock>(m_offset, this);
137  if (mrm->name() != "MRM") {
138  Trace(WARNING) << "MRW file begins not with MRM block, "
139  "but with unrecognized DataBlock :: name == "
140  << mrm->name() << "\n";
141  return false;
142  }
143 
144  /* Subblocks are contained within the MRM block. Scan them and create
145  * appropriate block descriptors.
146  */
147  position = mrm->offset() + MRW::DataBlockHeaderLength;
148  while (position < pixelDataOffset()) {
149  MRW::DataBlock::Ref ref(
150  std::make_shared<MRW::DataBlock>(position, this));
151  Trace(DEBUG1) << "Loaded DataBlock :: name == " << ref->name() << "\n";
152  if (!ref || !ref->loaded()) {
153  break;
154  }
155  if (ref->name() == "PRD") {
156  if (prd) {
157  Trace(WARNING)
158  << "File contains duplicate DataBlock :: name == "
159  << ref->name() << "\n";
160  }
161  prd = ref;
162  } else if (ref->name() == "TTW") {
163  if (ttw) {
164  Trace(WARNING)
165  << "File contains duplicate DataBlock :: name == "
166  << ref->name() << "\n";
167  }
168  ttw = ref;
169  } else if (ref->name() == "WBG") {
170  if (wbg) {
171  Trace(WARNING)
172  << "File contains duplicate DataBlock :: name == "
173  << ref->name() << "\n";
174  }
175  wbg = ref;
176  } else if (ref->name() == "RIF") {
177  if (rif) {
178  Trace(WARNING)
179  << "File contains duplicate DataBlock :: name == "
180  << ref->name() << "\n";
181  }
182  rif = ref;
183  } else if (ref->name() != "PAD") {
184  Trace(WARNING) << "File contains unrecognized DataBlock :: name == "
185  << ref->name() << "\n";
186  }
187  position = ref->offset() + MRW::DataBlockHeaderLength + ref->length();
188  }
189 
190  /* Check that we found all the expected data blocks. */
191  if (!prd) {
192  Trace(WARNING)
193  << "File does NOT contain expected DataBlock :: name == PRD\n";
194  return false;
195  }
196  if (!ttw) {
197  Trace(WARNING)
198  << "File does NOT contain expected DataBlock :: name == TTW\n";
199  return false;
200  }
201  if (!wbg) {
202  Trace(WARNING)
203  << "File does NOT contain expected DataBlock :: name == WBG\n";
204  return false;
205  }
206  if (!rif) {
207  Trace(WARNING)
208  << "File does NOT contain expected DataBlock :: name == RIF\n";
209  return false;
210  }
211 
212  /* Extract the file version string. */
213  if (fetchData(version,
214  prd->offset() + MRW::DataBlockHeaderLength + MRW::PRD_VERSION,
215  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
224  * beginning of
225  * the TIFF data (the contents of the TTW data block), and seek there.
226  */
227  m_offset = ttw->offset() + MRW::DataBlockHeaderLength;
228 
229  // TODO: Not sure exactly here the origin of this.
230  // But it doesn't work.
231  // if((version[2] != '7') || (version[3] != '3')) {
232  setExifOffsetCorrection(m_offset);
233  Trace(DEBUG1) << "setting correction to " << m_offset << "\n";
234  // }
235 
236  m_file->seek(m_offset, SEEK_SET);
237  Trace(DEBUG1) << "< MRWContainer\n";
238 
239  return true;
240 }
241 }
242 }
size_t fetchData(void *buf, off_t offset, size_t buf_size)
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 IfdFileContainer::EndianType isMagicHeader(const char *p, int len) override
uint16_t uint16_val(off_t offset)
Definition: trace.cpp:30
bool readUInt16(const IO::Stream::Ptr &f, uint16_t &v)
bool readInt32(const IO::Stream::Ptr &f, int32_t &v)
virtual bool locateDirsPreHook() override
uint8_t uint8_val(off_t offset)