libopenraw  0.3.7
mrwcontainer.cpp
1 /*
2  * libopenraw - mrwcontainer.cpp
3  *
4  * Copyright (C) 2006-2023 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(), m_container->endian());
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 
60 DataBlock::uint8_val(off_t off) const
61 {
62  MRWContainer *mc = m_container;
63  mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
64  return mc->readUInt8(mc->file());
65 }
66 
68 DataBlock::uint16_val(off_t off) const
69 {
70  MRWContainer *mc = m_container;
71  mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
72  return mc->readUInt16(mc->file(), mc->endian());
73 }
74 
76 DataBlock::string_val(off_t off) const
77 {
78  char buf[9];
79  size_t s;
80  MRWContainer *mc = m_container;
81  s = mc->fetchData(buf, m_start + DataBlockHeaderLength + off, 8);
82  if (s != 8) {
83  return Option<std::string>();
84  }
85  buf[8] = 0;
86  return Option<std::string>(buf);
87 }
88 
89 }
90 
91 MRWContainer::MRWContainer(const IO::Stream::Ptr &_file, off_t _offset)
92  : IfdFileContainer(_file, _offset)
93 {
94 }
95 
97 {
98  if (len < 4) {
99  // we need at least 4 bytes to check
100  return ENDIAN_NULL;
101  }
102 
103  if ((p[0] == 0x00) && (p[1] == 'M') && (p[2] == 'R') && (p[3] == 'M')) {
104 
105  LOGDBG1("Identified MRW file\n");
106 
107  return ENDIAN_BIG;
108  }
109 
110  LOGDBG1("Unidentified MRW file\n");
111 
112  return ENDIAN_NULL;
113 }
114 
116 {
117  char version[9];
118  off_t position;
119 
120  LOGDBG1("> MRWContainer::locateDirsPreHook()\n");
121  m_endian = ENDIAN_BIG;
122 
123  /* MRW file always starts with an MRM datablock. */
124  mrm = std::make_shared<MRW::DataBlock>(m_offset, this);
125  if (mrm->name() != "MRM") {
126  LOGWARN("MRW file begins not with MRM block, "
127  "but with unrecognized DataBlock :: name == %s\n",
128  mrm->name().c_str());
129  return false;
130  }
131 
132  /* Subblocks are contained within the MRM block. Scan them and create
133  * appropriate block descriptors.
134  */
135  position = mrm->offset() + MRW::DataBlockHeaderLength;
136  while (position < pixelDataOffset()) {
137  auto ref = std::make_shared<MRW::DataBlock>(position, this);
138  LOGDBG1("Loaded DataBlock :: name == %s\n", ref->name().c_str());
139  if (!ref || !ref->loaded()) {
140  break;
141  }
142  if (ref->name() == "PRD") {
143  if (prd) {
144  LOGWARN("File contains duplicate DataBlock :: name == %s\n",
145  ref->name().c_str());
146  }
147  prd = ref;
148  } else if (ref->name() == "TTW") {
149  if (ttw) {
150  LOGWARN("File contains duplicate DataBlock :: name == %s\n",
151  ref->name().c_str());
152  }
153  ttw = ref;
154  } else if (ref->name() == "WBG") {
155  if (wbg) {
156  LOGWARN("File contains duplicate DataBlock :: name == %s\n",
157  ref->name().c_str());
158  }
159  wbg = ref;
160  } else if (ref->name() == "RIF") {
161  if (rif) {
162  LOGWARN("File contains duplicate DataBlock :: name == %s\n",
163  ref->name().c_str());
164  }
165  rif = ref;
166  } else if (ref->name() != "PAD") {
167  LOGWARN("File contains unrecognized DataBlock :: name == %s\n",
168  ref->name().c_str());
169  }
170  position = ref->offset() + MRW::DataBlockHeaderLength + ref->length();
171  }
172 
173  /* Check that we found all the expected data blocks. */
174  if (!prd) {
175  LOGWARN("File does NOT contain expected DataBlock :: name == PRD\n");
176  return false;
177  }
178  if (!ttw) {
179  LOGWARN("File does NOT contain expected DataBlock :: name == TTW\n");
180  return false;
181  }
182  if (!wbg) {
183  LOGWARN("File does NOT contain expected DataBlock :: name == WBG\n");
184  return false;
185  }
186  if (!rif) {
187  LOGWARN("File does NOT contain expected DataBlock :: name == RIF\n");
188  return false;
189  }
190 
191  /* Extract the file version string. */
192  if (fetchData(version,
193  prd->offset() + MRW::DataBlockHeaderLength + MRW::PRD_VERSION,
194  8) != 8) {
195  // FIXME: Handle error
196  LOGDBG1(" Error reading version string\n");
197  }
198  version[8] = '\0';
199  m_version = std::string(version);
200  LOGDBG1(" MRW file version == %s\n", m_version.c_str());
201 
202  /* For the benefit of our parent class, set the container offset to the
203  * beginning of
204  * the TIFF data (the contents of the TTW data block), and seek there.
205  */
206  m_offset = ttw->offset() + MRW::DataBlockHeaderLength;
207 
208  // TODO: Not sure exactly here the origin of this.
209  // But it doesn't work.
210  // if((version[2] != '7') || (version[3] != '3')) {
211  setExifOffsetCorrection(m_offset);
212  LOGDBG1("setting correction to %lld\n", (long long int)m_offset);
213  // }
214 
215  m_file->seek(m_offset, SEEK_SET);
216  LOGDBG1("< MRWContainer\n");
217 
218  return true;
219 }
220 
221 }
222 }
std::shared_ptr< Stream > Ptr
Definition: stream.hpp:47
virtual bool locateDirsPreHook() override
hook to be called at the start of _locateDirs()
virtual IfdFileContainer::EndianType isMagicHeader(const char *p, int len) override
Option< uint16_t > uint16_val(off_t offset) const
Option< std::string > string_val(off_t offset) const
Option< uint8_t > uint8_val(off_t offset) const
Option< uint16_t > readUInt16(const IO::Stream::Ptr &f, EndianType endian) const
Read an uint16 following the m_endian set.
EndianType
Define the endian of the container.
size_t fetchData(void *buf, off_t offset, size_t buf_size) const
Fetch the data chunk from the file.
Option< int32_t > readInt32(const IO::Stream::Ptr &f, EndianType endian) const
Read an int32 following the m_endian set.
An option type inspired by Rust.
Definition: option.hpp:47
Global namespace for libopenraw.
Definition: arwfile.cpp:29