|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* libopenraw - mrwcontainer.cpp
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Copyright (C) 2006-2017 Hubert Figuière
|
|
rpm-build |
d2b433 |
* Copyright (C) 2008 Bradley Broom
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* This library is free software: you can redistribute it and/or
|
|
rpm-build |
d2b433 |
* modify it under the terms of the GNU Lesser General Public License
|
|
rpm-build |
d2b433 |
* as published by the Free Software Foundation, either version 3 of
|
|
rpm-build |
d2b433 |
* the License, or (at your option) any later version.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* This library is distributed in the hope that it will be useful,
|
|
rpm-build |
d2b433 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
rpm-build |
d2b433 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
rpm-build |
d2b433 |
* Lesser General Public License for more details.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* You should have received a copy of the GNU Lesser General Public
|
|
rpm-build |
d2b433 |
* License along with this library. If not, see
|
|
rpm-build |
d2b433 |
* <http://www.gnu.org/licenses/>.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include <fcntl.h>
|
|
rpm-build |
d2b433 |
#include <stddef.h>
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include <libopenraw/debug.h>
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include "trace.hpp"
|
|
rpm-build |
d2b433 |
#include "mrwcontainer.hpp"
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
using namespace Debug;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
namespace OpenRaw {
|
|
rpm-build |
d2b433 |
namespace Internals {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
namespace MRW {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
DataBlock::DataBlock(off_t start, MRWContainer *_container)
|
|
rpm-build |
d2b433 |
: m_start(start), m_container(_container), m_loaded(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
LOGDBG2("> DataBlock start == %ld\n", start);
|
|
rpm-build |
d2b433 |
if (m_container->fetchData(m_name, m_start, 4) != 4) {
|
|
rpm-build |
d2b433 |
// FIXME: Handle error
|
|
rpm-build |
d2b433 |
LOGWARN(" Error reading block name %ld\n", start);
|
|
rpm-build |
d2b433 |
return;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
auto result = m_container->readInt32(m_container->file());
|
|
rpm-build |
d2b433 |
if (result.empty()) {
|
|
rpm-build |
d2b433 |
// FIXME: Handle error
|
|
rpm-build |
d2b433 |
LOGWARN(" Error reading block length %ld\n", start);
|
|
rpm-build |
d2b433 |
return;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
m_length = result.unwrap();
|
|
rpm-build |
d2b433 |
LOGDBG1(" DataBlock %s, length %d at %ld\n", name().c_str(), m_length, m_start);
|
|
rpm-build |
d2b433 |
LOGDBG2("< DataBlock\n");
|
|
rpm-build |
d2b433 |
m_loaded = true;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
Option<int8_t>
|
|
rpm-build |
d2b433 |
DataBlock::int8_val(off_t off)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
MRWContainer *mc = m_container;
|
|
rpm-build |
d2b433 |
mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
|
|
rpm-build |
d2b433 |
return mc->readInt8(mc->file());
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
Option<uint8_t>
|
|
rpm-build |
d2b433 |
DataBlock::uint8_val(off_t off)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
MRWContainer *mc = m_container;
|
|
rpm-build |
d2b433 |
mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
|
|
rpm-build |
d2b433 |
return mc->readUInt8(mc->file());
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
Option<uint16_t>
|
|
rpm-build |
d2b433 |
DataBlock::uint16_val(off_t off)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
MRWContainer *mc = m_container;
|
|
rpm-build |
d2b433 |
mc->file()->seek(m_start + DataBlockHeaderLength + off, SEEK_SET);
|
|
rpm-build |
d2b433 |
return mc->readUInt16(mc->file());
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
Option<std::string>
|
|
rpm-build |
d2b433 |
DataBlock::string_val(off_t off)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
char buf[9];
|
|
rpm-build |
d2b433 |
size_t s;
|
|
rpm-build |
d2b433 |
MRWContainer *mc = m_container;
|
|
rpm-build |
d2b433 |
s = mc->fetchData(buf, m_start + DataBlockHeaderLength + off, 8);
|
|
rpm-build |
d2b433 |
if (s != 8) {
|
|
rpm-build |
d2b433 |
return Option<std::string>();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
buf[8] = 0;
|
|
rpm-build |
d2b433 |
return Option<std::string>(buf);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
MRWContainer::MRWContainer(const IO::Stream::Ptr &_file, off_t _offset)
|
|
rpm-build |
d2b433 |
: IfdFileContainer(_file, _offset)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
MRWContainer::~MRWContainer()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
IfdFileContainer::EndianType MRWContainer::isMagicHeader(const char *p, int len)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
if (len < 4) {
|
|
rpm-build |
d2b433 |
// we need at least 4 bytes to check
|
|
rpm-build |
d2b433 |
return ENDIAN_NULL;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if ((p[0] == 0x00) && (p[1] == 'M') && (p[2] == 'R') && (p[3] == 'M')) {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
LOGDBG1("Identified MRW file\n");
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
return ENDIAN_BIG;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
LOGDBG1("Unidentified MRW file\n");
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
return ENDIAN_NULL;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
bool MRWContainer::locateDirsPreHook()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
char version[9];
|
|
rpm-build |
d2b433 |
off_t position;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
LOGDBG1("> MRWContainer::locateDirsPreHook()\n");
|
|
rpm-build |
d2b433 |
m_endian = ENDIAN_BIG;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/* MRW file always starts with an MRM datablock. */
|
|
rpm-build |
d2b433 |
mrm = std::make_shared<MRW::DataBlock>(m_offset, this);
|
|
rpm-build |
d2b433 |
if (mrm->name() != "MRM") {
|
|
rpm-build |
d2b433 |
LOGWARN("MRW file begins not with MRM block, "
|
|
rpm-build |
d2b433 |
"but with unrecognized DataBlock :: name == %s\n",
|
|
rpm-build |
d2b433 |
mrm->name().c_str());
|
|
rpm-build |
d2b433 |
return false;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/* Subblocks are contained within the MRM block. Scan them and create
|
|
rpm-build |
d2b433 |
* appropriate block descriptors.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
position = mrm->offset() + MRW::DataBlockHeaderLength;
|
|
rpm-build |
d2b433 |
while (position < pixelDataOffset()) {
|
|
rpm-build |
d2b433 |
auto ref = std::make_shared<MRW::DataBlock>(position, this);
|
|
rpm-build |
d2b433 |
LOGDBG1("Loaded DataBlock :: name == %s\n", ref->name().c_str());
|
|
rpm-build |
d2b433 |
if (!ref || !ref->loaded()) {
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if (ref->name() == "PRD") {
|
|
rpm-build |
d2b433 |
if (prd) {
|
|
rpm-build |
d2b433 |
LOGWARN("File contains duplicate DataBlock :: name == %s\n",
|
|
rpm-build |
d2b433 |
ref->name().c_str());
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
prd = ref;
|
|
rpm-build |
d2b433 |
} else if (ref->name() == "TTW") {
|
|
rpm-build |
d2b433 |
if (ttw) {
|
|
rpm-build |
d2b433 |
LOGWARN("File contains duplicate DataBlock :: name == %s\n",
|
|
rpm-build |
d2b433 |
ref->name().c_str());
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
ttw = ref;
|
|
rpm-build |
d2b433 |
} else if (ref->name() == "WBG") {
|
|
rpm-build |
d2b433 |
if (wbg) {
|
|
rpm-build |
d2b433 |
LOGWARN("File contains duplicate DataBlock :: name == %s\n",
|
|
rpm-build |
d2b433 |
ref->name().c_str());
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
wbg = ref;
|
|
rpm-build |
d2b433 |
} else if (ref->name() == "RIF") {
|
|
rpm-build |
d2b433 |
if (rif) {
|
|
rpm-build |
d2b433 |
LOGWARN("File contains duplicate DataBlock :: name == %s\n",
|
|
rpm-build |
d2b433 |
ref->name().c_str());
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
rif = ref;
|
|
rpm-build |
d2b433 |
} else if (ref->name() != "PAD") {
|
|
rpm-build |
d2b433 |
LOGWARN("File contains unrecognized DataBlock :: name == %s\n",
|
|
rpm-build |
d2b433 |
ref->name().c_str());
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
position = ref->offset() + MRW::DataBlockHeaderLength + ref->length();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/* Check that we found all the expected data blocks. */
|
|
rpm-build |
d2b433 |
if (!prd) {
|
|
rpm-build |
d2b433 |
LOGWARN("File does NOT contain expected DataBlock :: name == PRD\n");
|
|
rpm-build |
d2b433 |
return false;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if (!ttw) {
|
|
rpm-build |
d2b433 |
LOGWARN("File does NOT contain expected DataBlock :: name == TTW\n");
|
|
rpm-build |
d2b433 |
return false;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if (!wbg) {
|
|
rpm-build |
d2b433 |
LOGWARN("File does NOT contain expected DataBlock :: name == WBG\n");
|
|
rpm-build |
d2b433 |
return false;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if (!rif) {
|
|
rpm-build |
d2b433 |
LOGWARN("File does NOT contain expected DataBlock :: name == RIF\n");
|
|
rpm-build |
d2b433 |
return false;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/* Extract the file version string. */
|
|
rpm-build |
d2b433 |
if (fetchData(version,
|
|
rpm-build |
d2b433 |
prd->offset() + MRW::DataBlockHeaderLength + MRW::PRD_VERSION,
|
|
rpm-build |
d2b433 |
8) != 8) {
|
|
rpm-build |
d2b433 |
// FIXME: Handle error
|
|
rpm-build |
d2b433 |
LOGDBG1(" Error reading version string\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
version[8] = '\0';
|
|
rpm-build |
d2b433 |
m_version = std::string(version);
|
|
rpm-build |
d2b433 |
LOGDBG1(" MRW file version == %s\n", m_version.c_str());
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/* For the benefit of our parent class, set the container offset to the
|
|
rpm-build |
d2b433 |
* beginning of
|
|
rpm-build |
d2b433 |
* the TIFF data (the contents of the TTW data block), and seek there.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
m_offset = ttw->offset() + MRW::DataBlockHeaderLength;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
// TODO: Not sure exactly here the origin of this.
|
|
rpm-build |
d2b433 |
// But it doesn't work.
|
|
rpm-build |
d2b433 |
// if((version[2] != '7') || (version[3] != '3')) {
|
|
rpm-build |
d2b433 |
setExifOffsetCorrection(m_offset);
|
|
rpm-build |
d2b433 |
LOGDBG1("setting correction to %ld\n", m_offset);
|
|
rpm-build |
d2b433 |
// }
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
m_file->seek(m_offset, SEEK_SET);
|
|
rpm-build |
d2b433 |
LOGDBG1("< MRWContainer\n");
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
return true;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|