libopenraw
mrwcontainer.cpp
1 /*
2  * libopenraw - mrwcontainer.cpp
3  *
4  * Copyright (C) 2006-2017 Hubert Figuière
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  LOGDBG2("> DataBlock start == %lld\n", (long long int)start);
41  if (m_container->fetchData(m_name, m_start, 4) != 4) {
42  // FIXME: Handle error
43  LOGWARN(" Error reading block name %lld\n", (long long int)start);
44  return;
45  }
46  auto result = m_container->readInt32(m_container->file());
47  if (result.empty()) {
48  // FIXME: Handle error
49  LOGWARN(" Error reading block length %lld\n", (long long int)start);
50  return;
51  }
52  m_length = result.value();
53  LOGDBG1(" DataBlock %s, length %d at %lld\n", name().c_str(), m_length,
54  (long long int)m_start);
55  LOGDBG2("< DataBlock\n");
56  m_loaded = true;
57 }
58 
61 {
62  MRWContainer *mc = m_container;
63  mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
64  return mc->readInt8(mc->file());
65 }
66 
69 {
70  MRWContainer *mc = m_container;
71  mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
72  return mc->readUInt8(mc->file());
73 }
74 
77 {
78  MRWContainer *mc = m_container;
79  mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
80  return mc->readUInt16(mc->file());
81 }
82 
84 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  return Option<std::string>();
92  }
93  buf[8] = 0;
94  return Option<std::string>(buf);
95 }
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  LOGDBG1("Identified MRW file\n");
118 
119  return ENDIAN_BIG;
120  }
121 
122  LOGDBG1("Unidentified MRW file\n");
123 
124  return ENDIAN_NULL;
125 }
126 
128 {
129  char version[9];
130  off_t position;
131 
132  LOGDBG1("> 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  LOGWARN("MRW file begins not with MRM block, "
139  "but with unrecognized DataBlock :: name == %s\n",
140  mrm->name().c_str());
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  auto ref = std::make_shared<MRW::DataBlock>(position, this);
150  LOGDBG1("Loaded DataBlock :: name == %s\n", ref->name().c_str());
151  if (!ref || !ref->loaded()) {
152  break;
153  }
154  if (ref->name() == "PRD") {
155  if (prd) {
156  LOGWARN("File contains duplicate DataBlock :: name == %s\n",
157  ref->name().c_str());
158  }
159  prd = ref;
160  } else if (ref->name() == "TTW") {
161  if (ttw) {
162  LOGWARN("File contains duplicate DataBlock :: name == %s\n",
163  ref->name().c_str());
164  }
165  ttw = ref;
166  } else if (ref->name() == "WBG") {
167  if (wbg) {
168  LOGWARN("File contains duplicate DataBlock :: name == %s\n",
169  ref->name().c_str());
170  }
171  wbg = ref;
172  } else if (ref->name() == "RIF") {
173  if (rif) {
174  LOGWARN("File contains duplicate DataBlock :: name == %s\n",
175  ref->name().c_str());
176  }
177  rif = ref;
178  } else if (ref->name() != "PAD") {
179  LOGWARN("File contains unrecognized DataBlock :: name == %s\n",
180  ref->name().c_str());
181  }
182  position = ref->offset() + MRW::DataBlockHeaderLength + ref->length();
183  }
184 
185  /* Check that we found all the expected data blocks. */
186  if (!prd) {
187  LOGWARN("File does NOT contain expected DataBlock :: name == PRD\n");
188  return false;
189  }
190  if (!ttw) {
191  LOGWARN("File does NOT contain expected DataBlock :: name == TTW\n");
192  return false;
193  }
194  if (!wbg) {
195  LOGWARN("File does NOT contain expected DataBlock :: name == WBG\n");
196  return false;
197  }
198  if (!rif) {
199  LOGWARN("File does NOT contain expected DataBlock :: name == RIF\n");
200  return false;
201  }
202 
203  /* Extract the file version string. */
204  if (fetchData(version,
205  prd->offset() + MRW::DataBlockHeaderLength + MRW::PRD_VERSION,
206  8) != 8) {
207  // FIXME: Handle error
208  LOGDBG1(" Error reading version string\n");
209  }
210  version[8] = '\0';
211  m_version = std::string(version);
212  LOGDBG1(" MRW file version == %s\n", m_version.c_str());
213 
214  /* For the benefit of our parent class, set the container offset to the
215  * beginning of
216  * the TIFF data (the contents of the TTW data block), and seek there.
217  */
218  m_offset = ttw->offset() + MRW::DataBlockHeaderLength;
219 
220  // TODO: Not sure exactly here the origin of this.
221  // But it doesn't work.
222  // if((version[2] != '7') || (version[3] != '3')) {
223  setExifOffsetCorrection(m_offset);
224  LOGDBG1("setting correction to %lld\n", (long long int)m_offset);
225  // }
226 
227  m_file->seek(m_offset, SEEK_SET);
228  LOGDBG1("< MRWContainer\n");
229 
230  return true;
231 }
232 
233 }
234 }
OpenRaw::Internals::MRWContainer::isMagicHeader
virtual IfdFileContainer::EndianType isMagicHeader(const char *p, int len) override
Definition: mrwcontainer.cpp:108
OpenRaw::Internals::RawContainer::readInt32
Option< int32_t > readInt32(const IO::Stream::Ptr &f)
Definition: rawcontainer.cpp:138
OpenRaw::Internals::MRWContainer
Definition: mrwcontainer.hpp:217
OpenRaw::Internals::MRW::DataBlock::int8_val
Option< int8_t > int8_val(off_t offset)
Definition: mrwcontainer.cpp:60
OpenRaw
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard....
Definition: arwfile.cpp:30
OpenRaw::Internals::MRWContainer::~MRWContainer
virtual ~MRWContainer()
Definition: mrwcontainer.cpp:104
OpenRaw::Internals::MRW::DataBlock::uint8_val
Option< uint8_t > uint8_val(off_t offset)
Definition: mrwcontainer.cpp:68
OpenRaw::Internals::RawContainer::fetchData
size_t fetchData(void *buf, off_t offset, size_t buf_size)
Definition: rawcontainer.cpp:203
OpenRaw::Internals::RawContainer::readUInt16
Option< uint16_t > readUInt16(const IO::Stream::Ptr &f)
Definition: rawcontainer.cpp:160
Option
Definition: option.hpp:29
OpenRaw::Internals::RawContainer::EndianType
EndianType
Definition: rawcontainer.hpp:44
OpenRaw::Internals::MRWContainer::locateDirsPreHook
virtual bool locateDirsPreHook() override
Definition: mrwcontainer.cpp:127
OpenRaw::Internals::MRW::DataBlock::name
std::string name()
Definition: mrwcontainer.hpp:70
OpenRaw::Internals::MRW::DataBlock::uint16_val
Option< uint16_t > uint16_val(off_t offset)
Definition: mrwcontainer.cpp:76