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