|
rpm-build |
d2b433 |
/* -*- mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil; -*- */
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* libopenraw - ifddir.cpp
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Copyright (C) 2006-2017 Hubert Figuière
|
|
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 <cstdint>
|
|
rpm-build |
d2b433 |
#include <utility>
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include "trace.hpp"
|
|
rpm-build |
d2b433 |
#include "io/stream.hpp"
|
|
rpm-build |
d2b433 |
#include "ifdfilecontainer.hpp"
|
|
rpm-build |
d2b433 |
#include "ifddir.hpp"
|
|
rpm-build |
d2b433 |
#include "makernotedir.hpp"
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
using namespace Debug;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
namespace OpenRaw {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
namespace Internals {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
bool IfdDir::isPrimary() const
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
auto result = getValue<uint32_t>(IFD::EXIF_TAG_NEW_SUBFILE_TYPE);
|
|
rpm-build |
d2b433 |
return result.ok() && (result.unwrap() == 0);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
bool IfdDir::isThumbnail() const
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
auto result = getValue<uint32_t>(IFD::EXIF_TAG_NEW_SUBFILE_TYPE);
|
|
rpm-build |
d2b433 |
return result.ok() && (result.unwrap() == 1);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
IfdDir::IfdDir(off_t _offset, IfdFileContainer &_container)
|
|
rpm-build |
d2b433 |
: m_offset(_offset), m_container(_container), m_entries()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
IfdDir::~IfdDir()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
bool IfdDir::load()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
LOGDBG1("IfdDir::load() m_offset =%ld\n", m_offset);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
auto file = m_container.file();
|
|
rpm-build |
d2b433 |
m_entries.clear();
|
|
rpm-build |
d2b433 |
file->seek(m_offset, SEEK_SET);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
int16_t numEntries = m_container.readInt16(file).unwrap_or(0);
|
|
rpm-build |
d2b433 |
LOGDBG1("num entries %d\n", numEntries);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (int16_t i = 0; i < numEntries; i++) {
|
|
rpm-build |
d2b433 |
uint32_t data;
|
|
rpm-build |
d2b433 |
auto id = m_container.readUInt16(file);
|
|
rpm-build |
d2b433 |
auto type = m_container.readInt16(file);
|
|
rpm-build |
d2b433 |
auto count = m_container.readInt32(file);
|
|
rpm-build |
d2b433 |
size_t sz = file->read(&data, 4);
|
|
rpm-build |
d2b433 |
if (id.empty() || type.empty() || count.empty() || sz != 4) {
|
|
rpm-build |
d2b433 |
LOGERR("Failed to read entry %d\n", i);
|
|
rpm-build |
d2b433 |
return false;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
uint16_t n_id = id.unwrap();
|
|
rpm-build |
d2b433 |
IfdEntry::Ref entry =
|
|
rpm-build |
d2b433 |
std::make_shared<IfdEntry>(n_id, type.unwrap(),
|
|
rpm-build |
d2b433 |
count.unwrap(), data, m_container);
|
|
rpm-build |
d2b433 |
m_entries[n_id] = entry;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
return true;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
IfdEntry::Ref IfdDir::getEntry(uint16_t id) const
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
std::map<uint16_t, IfdEntry::Ref>::const_iterator iter;
|
|
rpm-build |
d2b433 |
iter = m_entries.find(id);
|
|
rpm-build |
d2b433 |
if (iter != m_entries.end()) {
|
|
rpm-build |
d2b433 |
return iter->second;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return IfdEntry::Ref();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
Option<uint32_t>
|
|
rpm-build |
d2b433 |
IfdDir::getIntegerValue(uint16_t id)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
IfdEntry::Ref e = getEntry(id);
|
|
rpm-build |
d2b433 |
if (e != nullptr) {
|
|
rpm-build |
d2b433 |
return Option<uint32_t>(e->getIntegerArrayItem(0));
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return Option<uint32_t>();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
off_t IfdDir::nextIFD()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int16_t numEntries = 0;
|
|
rpm-build |
d2b433 |
auto file = m_container.file();
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (m_entries.size() == 0) {
|
|
rpm-build |
d2b433 |
file->seek(m_offset, SEEK_SET);
|
|
rpm-build |
d2b433 |
numEntries = m_container.readInt16(file).unwrap_or(0);
|
|
rpm-build |
d2b433 |
LOGDBG1("numEntries =%d shifting %d bytes\n", numEntries, (numEntries * 12) + 2);
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
numEntries = m_entries.size();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
file->seek(m_offset + (numEntries * 12) + 2, SEEK_SET);
|
|
rpm-build |
d2b433 |
// XXX how about we check the error. Even though 0 is not valid.
|
|
rpm-build |
d2b433 |
return m_container.readInt32(file).unwrap_or(0);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/** The SubIFD is locate at offset found in the field
|
|
rpm-build |
d2b433 |
* EXIF_TAG_SUB_IFDS
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
IfdDir::Ref IfdDir::getSubIFD(uint32_t idx) const
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
IfdEntry::Ref e = getEntry(IFD::EXIF_TAG_SUB_IFDS);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (e != nullptr) {
|
|
rpm-build |
d2b433 |
auto result = e->getArray<uint32_t>();
|
|
rpm-build |
d2b433 |
if (result.ok()) {
|
|
rpm-build |
d2b433 |
std::vector<uint32_t> offsets = result.unwrap();
|
|
rpm-build |
d2b433 |
if (idx >= offsets.size()) {
|
|
rpm-build |
d2b433 |
Ref ref = std::make_shared<IfdDir>(offsets[idx], m_container);
|
|
rpm-build |
d2b433 |
ref->load();
|
|
rpm-build |
d2b433 |
return ref;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
LOGERR("Can't get SubIFD offsets\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return Ref();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
Option<std::vector<IfdDir::Ref>> IfdDir::getSubIFDs()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
std::vector<IfdDir::Ref> ifds;
|
|
rpm-build |
d2b433 |
IfdEntry::Ref e = getEntry(IFD::EXIF_TAG_SUB_IFDS);
|
|
rpm-build |
d2b433 |
if (e != nullptr) {
|
|
rpm-build |
d2b433 |
auto result = e->getArray<uint32_t>();
|
|
rpm-build |
d2b433 |
if (result.ok()) {
|
|
rpm-build |
d2b433 |
std::vector<uint32_t> offsets = result.unwrap();
|
|
rpm-build |
d2b433 |
for (auto offset : offsets) {
|
|
rpm-build |
d2b433 |
Ref ifd = std::make_shared<IfdDir>(offset, m_container);
|
|
rpm-build |
d2b433 |
ifd->load();
|
|
rpm-build |
d2b433 |
ifds.push_back(ifd);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return Option<std::vector<IfdDir::Ref>>(std::move(ifds));
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return Option<std::vector<IfdDir::Ref>>();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/** The SubIFD is located at offset found in the field
|
|
rpm-build |
d2b433 |
* EXIF_TAG_SUB_IFDS
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
IfdDir::Ref IfdDir::getExifIFD()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
auto result = getValue<uint32_t>(IFD::EXIF_TAG_EXIF_IFD_POINTER);
|
|
rpm-build |
d2b433 |
if (result.empty()) {
|
|
rpm-build |
d2b433 |
LOGDBG1("Exif IFD offset not found.\n");
|
|
rpm-build |
d2b433 |
return Ref();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
uint32_t val_offset = result.unwrap();
|
|
rpm-build |
d2b433 |
LOGDBG1("Exif IFD offset (uncorrected) = %u\n", val_offset);
|
|
rpm-build |
d2b433 |
val_offset += m_container.exifOffsetCorrection();
|
|
rpm-build |
d2b433 |
LOGDBG1("Exif IFD offset = %u\n", val_offset);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
Ref ref = std::make_shared<IfdDir>(val_offset, m_container);
|
|
rpm-build |
d2b433 |
ref->load();
|
|
rpm-build |
d2b433 |
return ref;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
IfdDir::Ref IfdDir::getMakerNoteIfd()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
uint32_t val_offset = 0;
|
|
rpm-build |
d2b433 |
IfdEntry::Ref e = getEntry(IFD::EXIF_TAG_MAKER_NOTE);
|
|
rpm-build |
d2b433 |
if (!e) {
|
|
rpm-build |
d2b433 |
LOGDBG1("MakerNote IFD offset not found.\n");
|
|
rpm-build |
d2b433 |
return MakerNoteDir::Ref();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
val_offset = e->offset();
|
|
rpm-build |
d2b433 |
LOGDBG1("MakerNote IFD offset (uncorrected) = %u\n", val_offset);
|
|
rpm-build |
d2b433 |
val_offset += m_container.exifOffsetCorrection();
|
|
rpm-build |
d2b433 |
LOGDBG1("MakerNote IFD offset = %u\n", val_offset);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
auto ref = MakerNoteDir::createMakerNote(val_offset, m_container);
|
|
rpm-build |
d2b433 |
if (ref) {
|
|
rpm-build |
d2b433 |
ref->load();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
return ref;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|