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