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
30using namespace Debug;
31
32namespace OpenRaw {
33namespace Internals {
34
35namespace MRW {
36
37DataBlock::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
84DataBlock::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
99MRWContainer::MRWContainer(const IO::Stream::Ptr &_file, off_t _offset)
100 : IfdFileContainer(_file, _offset)
101{
102}
103
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')) {
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}
virtual bool locateDirsPreHook() override
virtual IfdFileContainer::EndianType isMagicHeader(const char *p, int len) override
Option< uint8_t > uint8_val(off_t offset)
Option< int8_t > int8_val(off_t offset)
Option< uint16_t > uint16_val(off_t offset)
DataBlock(off_t start, MRWContainer *container)
size_t fetchData(void *buf, off_t offset, size_t buf_size)
Option< uint16_t > readUInt16(const IO::Stream::Ptr &f)
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard....
Definition arwfile.cpp:30