|
Packit |
01d647 |
#include "crwimage_int.hpp"
|
|
Packit |
01d647 |
#include "canonmn_int.hpp"
|
|
Packit |
01d647 |
#include "i18n.h" // NLS support.
|
|
Packit |
01d647 |
#include "timegm.h"
|
|
Packit |
01d647 |
#include "unused.h"
|
|
Packit |
01d647 |
#include "error.hpp"
|
|
Packit Service |
fb147c |
#include "enforce.hpp"
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#include <cassert>
|
|
Packit |
01d647 |
#include <ctime>
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// *****************************************************************************
|
|
Packit |
01d647 |
// local declarations
|
|
Packit |
01d647 |
namespace {
|
|
Packit |
01d647 |
//! Helper class to map Exif orientation values to CRW rotation degrees
|
|
Packit |
01d647 |
class RotationMap {
|
|
Packit |
01d647 |
public:
|
|
Packit |
01d647 |
//! Get the orientation number for a degree value
|
|
Packit |
01d647 |
static uint16_t orientation(int32_t degrees);
|
|
Packit |
01d647 |
//! Get the degree value for an orientation number
|
|
Packit |
01d647 |
static int32_t degrees(uint16_t orientation);
|
|
Packit |
01d647 |
private:
|
|
Packit |
01d647 |
//! Helper structure for the mapping list
|
|
Packit |
01d647 |
struct OmList {
|
|
Packit |
01d647 |
uint16_t orientation; //!< Exif orientation value
|
|
Packit |
01d647 |
int32_t degrees; //!< CRW Rotation degrees
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
// DATA
|
|
Packit |
01d647 |
static const OmList omList_[];
|
|
Packit |
01d647 |
}; // class RotationMap
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// *****************************************************************************
|
|
Packit |
01d647 |
// local definitions
|
|
Packit |
01d647 |
namespace {
|
|
Packit |
01d647 |
//! @cond IGNORE
|
|
Packit |
01d647 |
const RotationMap::OmList RotationMap::omList_[] = {
|
|
Packit |
01d647 |
{ 1, 0 },
|
|
Packit |
01d647 |
{ 3, 180 },
|
|
Packit |
01d647 |
{ 3, -180 },
|
|
Packit |
01d647 |
{ 6, 90 },
|
|
Packit |
01d647 |
{ 6, -270 },
|
|
Packit |
01d647 |
{ 8, 270 },
|
|
Packit |
01d647 |
{ 8, -90 },
|
|
Packit |
01d647 |
// last entry
|
|
Packit |
01d647 |
{ 0, 0 }
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
uint16_t RotationMap::orientation(int32_t degrees)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
uint16_t o = 1;
|
|
Packit |
01d647 |
for (int i = 0; omList_[i].orientation != 0; ++i) {
|
|
Packit |
01d647 |
if (omList_[i].degrees == degrees) {
|
|
Packit |
01d647 |
o = omList_[i].orientation;
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return o;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
int32_t RotationMap::degrees(uint16_t orientation)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
int32_t d = 0;
|
|
Packit |
01d647 |
for (int i = 0; omList_[i].orientation != 0; ++i) {
|
|
Packit |
01d647 |
if (omList_[i].orientation == orientation) {
|
|
Packit |
01d647 |
d = omList_[i].degrees;
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return d;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
//! @endcond
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
namespace Exiv2 {
|
|
Packit |
01d647 |
namespace Internal {
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*
|
|
Packit |
01d647 |
Mapping table used to decode and encode CIFF tags to/from Exif tags. Only
|
|
Packit |
01d647 |
a subset of the Exif tags can be mapped to known tags found in CRW files
|
|
Packit |
01d647 |
and not all CIFF tags in the CRW files have a corresponding Exif tag. Tags
|
|
Packit |
01d647 |
which are not mapped in the table below are ignored.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
When decoding, each CIFF tag/directory pair in the CRW image is looked up
|
|
Packit |
01d647 |
in the table and if it has an entry, the corresponding decode function is
|
|
Packit |
01d647 |
called (CrwMap::decode). This function may or may not make use of the
|
|
Packit |
01d647 |
other parameters in the structure (such as the Exif tag and Ifd id).
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Encoding is done in a loop over the mapping table (CrwMap::encode). For
|
|
Packit |
01d647 |
each entry, the encode function is called, which looks up the (Exif)
|
|
Packit |
01d647 |
metadata to encode in the image. This function may or may not make use of
|
|
Packit |
01d647 |
the other parameters in the mapping structure.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
const CrwMapping CrwMap::crwMapping_[] = {
|
|
Packit |
01d647 |
// CrwTag CrwDir Size ExifTag IfdId decodeFct encodeFct
|
|
Packit |
01d647 |
// ------ ------ ---- ------- ----- --------- ---------
|
|
Packit |
01d647 |
CrwMapping(0x0805, 0x300a, 0, 0, canonId, decode0x0805, encode0x0805),
|
|
Packit |
01d647 |
CrwMapping(0x080a, 0x2807, 0, 0, canonId, decode0x080a, encode0x080a),
|
|
Packit |
01d647 |
CrwMapping(0x080b, 0x3004, 0, 0x0007, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x0810, 0x2807, 0, 0x0009, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x0815, 0x2804, 0, 0x0006, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x1029, 0x300b, 0, 0x0002, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x102a, 0x300b, 0, 0x0004, canonId, decodeArray, encodeArray),
|
|
Packit |
01d647 |
CrwMapping(0x102d, 0x300b, 0, 0x0001, canonId, decodeArray, encodeArray),
|
|
Packit |
01d647 |
CrwMapping(0x1033, 0x300b, 0, 0x000f, canonId, decodeArray, encodeArray),
|
|
Packit |
01d647 |
CrwMapping(0x1038, 0x300b, 0, 0x0012, canonId, decodeArray, encodeArray),
|
|
Packit |
01d647 |
CrwMapping(0x10a9, 0x300b, 0, 0x00a9, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
// Mapped to Exif.Photo.ColorSpace instead (see below)
|
|
Packit |
01d647 |
//CrwMapping(0x10b4, 0x300b, 0, 0x00b4, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x10b4, 0x300b, 0, 0xa001, exifId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x10b5, 0x300b, 0, 0x00b5, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x10c0, 0x300b, 0, 0x00c0, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x10c1, 0x300b, 0, 0x00c1, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x1807, 0x3002, 0, 0x9206, exifId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x180b, 0x3004, 0, 0x000c, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x180e, 0x300a, 0, 0x9003, exifId, decode0x180e, encode0x180e),
|
|
Packit |
01d647 |
CrwMapping(0x1810, 0x300a, 0, 0xa002, exifId, decode0x1810, encode0x1810),
|
|
Packit |
01d647 |
CrwMapping(0x1817, 0x300a, 4, 0x0008, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
//CrwMapping(0x1818, 0x3002, 0, 0x9204, exifId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x183b, 0x300b, 0, 0x0015, canonId, decodeBasic, encodeBasic),
|
|
Packit |
01d647 |
CrwMapping(0x2008, 0x0000, 0, 0, ifd1Id, decode0x2008, encode0x2008),
|
|
Packit |
01d647 |
// End of list marker
|
|
Packit |
01d647 |
CrwMapping(0x0000, 0x0000, 0, 0x0000, ifdIdNotSet, 0, 0)
|
|
Packit |
01d647 |
}; // CrwMap::crwMapping_[]
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*
|
|
Packit |
01d647 |
CIFF directory hierarchy
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
root
|
|
Packit |
01d647 |
|
|
|
Packit |
01d647 |
300a
|
|
Packit |
01d647 |
|
|
|
Packit |
01d647 |
+----+----+----+----+
|
|
Packit |
01d647 |
| | | | |
|
|
Packit |
01d647 |
2804 2807 3002 3003 300b
|
|
Packit |
01d647 |
|
|
|
Packit |
01d647 |
3004
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
The array is arranged bottom-up so that starting with a directory at the
|
|
Packit |
01d647 |
bottom, the (unique) path to root can be determined in a single loop.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
const CrwSubDir CrwMap::crwSubDir_[] = {
|
|
Packit |
01d647 |
// dir, parent
|
|
Packit |
01d647 |
{ 0x3004, 0x2807 },
|
|
Packit |
01d647 |
{ 0x300b, 0x300a },
|
|
Packit |
01d647 |
{ 0x3003, 0x300a },
|
|
Packit |
01d647 |
{ 0x3002, 0x300a },
|
|
Packit |
01d647 |
{ 0x2807, 0x300a },
|
|
Packit |
01d647 |
{ 0x2804, 0x300a },
|
|
Packit |
01d647 |
{ 0x300a, 0x0000 },
|
|
Packit |
01d647 |
{ 0x0000, 0xffff },
|
|
Packit |
01d647 |
// End of list marker
|
|
Packit |
01d647 |
{ 0xffff, 0xffff }
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
const char CiffHeader::signature_[] = "HEAPCCDR";
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffHeader::~CiffHeader()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
delete pRootDir_;
|
|
Packit |
01d647 |
delete[] pPadding_;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent::~CiffComponent()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (isAllocated_) delete[] pData_;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffEntry::~CiffEntry()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffDirectory::~CiffDirectory()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Components::iterator b = components_.begin();
|
|
Packit |
01d647 |
Components::iterator e = components_.end();
|
|
Packit |
01d647 |
for (Components::iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
delete *i;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::add(AutoPtr component)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
doAdd(component);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffEntry::doAdd(AutoPtr /*component*/)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
throw Error(kerFunctionNotSupported, "CiffEntry::add");
|
|
Packit |
01d647 |
} // CiffEntry::doAdd
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffDirectory::doAdd(AutoPtr component)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
components_.push_back(component.release());
|
|
Packit |
01d647 |
} // CiffDirectory::doAdd
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffHeader::read(const byte* pData, uint32_t size)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (size < 14) throw Error(kerNotACrwImage);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (pData[0] == 'I' && pData[0] == pData[1]) {
|
|
Packit |
01d647 |
byteOrder_ = littleEndian;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if (pData[0] == 'M' && pData[0] == pData[1]) {
|
|
Packit |
01d647 |
byteOrder_ = bigEndian;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
throw Error(kerNotACrwImage);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
offset_ = getULong(pData + 2, byteOrder_);
|
|
Packit |
01d647 |
if (offset_ < 14 || offset_ > size) throw Error(kerNotACrwImage);
|
|
Packit |
01d647 |
if (std::memcmp(pData + 6, signature(), 8) != 0) {
|
|
Packit |
01d647 |
throw Error(kerNotACrwImage);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit Service |
fb147c |
delete[] pPadding_;
|
|
Packit |
01d647 |
pPadding_ = new byte[offset_ - 14];
|
|
Packit |
01d647 |
padded_ = offset_ - 14;
|
|
Packit |
01d647 |
std::memcpy(pPadding_, pData + 14, padded_);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
pRootDir_ = new CiffDirectory;
|
|
Packit |
01d647 |
pRootDir_->readDirectory(pData + offset_, size - offset_, byteOrder_);
|
|
Packit |
01d647 |
} // CiffHeader::read
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::read(const byte* pData,
|
|
Packit |
01d647 |
uint32_t size,
|
|
Packit |
01d647 |
uint32_t start,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
doRead(pData, size, start, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::doRead(const byte* pData,
|
|
Packit |
01d647 |
uint32_t size,
|
|
Packit |
01d647 |
uint32_t start,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit Service |
fb147c |
// We're going read 10 bytes. Make sure they won't be out-of-bounds.
|
|
Packit Service |
fb147c |
enforce(size >= 10 && start <= size - 10, kerNotACrwImage);
|
|
Packit |
01d647 |
tag_ = getUShort(pData + start, byteOrder);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
DataLocId dl = dataLocation();
|
|
Packit |
01d647 |
assert(dl == directoryData || dl == valueData);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (dl == valueData) {
|
|
Packit |
01d647 |
size_ = getULong(pData + start + 2, byteOrder);
|
|
Packit |
01d647 |
offset_ = getULong(pData + start + 6, byteOrder);
|
|
Packit Service |
fb147c |
|
|
Packit Service |
fb147c |
// Make sure that the sub-region does not overlap with the 10 bytes
|
|
Packit Service |
fb147c |
// that we just read. (Otherwise a malicious file could cause an
|
|
Packit Service |
fb147c |
// infinite recursion.) There are two cases two consider because
|
|
Packit Service |
fb147c |
// the sub-region is allowed to be either before or after the 10
|
|
Packit Service |
fb147c |
// bytes in memory.
|
|
Packit Service |
fb147c |
if (offset_ < start) {
|
|
Packit Service |
fb147c |
// Sub-region is before in memory.
|
|
Packit Service |
fb147c |
enforce(size_ <= start - offset_, kerOffsetOutOfRange);
|
|
Packit Service |
fb147c |
} else {
|
|
Packit Service |
fb147c |
// Sub-region is after in memory.
|
|
Packit Service |
fb147c |
enforce(offset_ >= start + 10, kerOffsetOutOfRange);
|
|
Packit Service |
fb147c |
enforce(offset_ <= size, kerOffsetOutOfRange);
|
|
Packit Service |
fb147c |
enforce(size_ <= size - offset_, kerOffsetOutOfRange);
|
|
Packit Service |
fb147c |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (dl == directoryData) {
|
|
Packit |
01d647 |
size_ = 8;
|
|
Packit |
01d647 |
offset_ = start + 2;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
pData_ = pData + offset_;
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
std::cout << " Entry for tag 0x"
|
|
Packit |
01d647 |
<< std::hex << tagId() << " (0x" << tag()
|
|
Packit |
01d647 |
<< "), " << std::dec << size_
|
|
Packit |
01d647 |
<< " Bytes, Offset is " << offset_ << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
} // CiffComponent::doRead
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffDirectory::doRead(const byte* pData,
|
|
Packit |
01d647 |
uint32_t size,
|
|
Packit |
01d647 |
uint32_t start,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
CiffComponent::doRead(pData, size, start, byteOrder);
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
std::cout << "Reading directory 0x" << std::hex << tag() << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit Service |
fb147c |
if (this->offset() + this->size() > size)
|
|
Packit Service |
fb147c |
throw Error(kerOffsetOutOfRange);
|
|
Packit Service |
fb147c |
|
|
Packit |
01d647 |
readDirectory(pData + offset(), this->size(), byteOrder);
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
std::cout << "<---- 0x" << std::hex << tag() << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
} // CiffDirectory::doRead
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffDirectory::readDirectory(const byte* pData,
|
|
Packit |
01d647 |
uint32_t size,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (size < 4)
|
|
Packit |
01d647 |
throw Error(kerCorruptedMetadata);
|
|
Packit |
01d647 |
uint32_t o = getULong(pData + size - 4, byteOrder);
|
|
Packit |
01d647 |
if ( o > size-2 )
|
|
Packit |
01d647 |
throw Error(kerCorruptedMetadata);
|
|
Packit |
01d647 |
uint16_t count = getUShort(pData + o, byteOrder);
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
std::cout << "Directory at offset " << std::dec << o
|
|
Packit |
01d647 |
<<", " << count << " entries \n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
o += 2;
|
|
Packit |
01d647 |
if ( static_cast<uint32_t>(count) * 10 > size-o )
|
|
Packit |
01d647 |
throw Error(kerCorruptedMetadata);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
for (uint16_t i = 0; i < count; ++i) {
|
|
Packit |
01d647 |
uint16_t tag = getUShort(pData + o, byteOrder);
|
|
Packit |
01d647 |
CiffComponent::AutoPtr m;
|
|
Packit |
01d647 |
switch (CiffComponent::typeId(tag)) {
|
|
Packit |
01d647 |
case directory: m = CiffComponent::AutoPtr(new CiffDirectory); break;
|
|
Packit |
01d647 |
default: m = CiffComponent::AutoPtr(new CiffEntry); break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
m->setDir(this->tag());
|
|
Packit |
01d647 |
m->read(pData, size, o, byteOrder);
|
|
Packit |
01d647 |
add(m);
|
|
Packit |
01d647 |
o += 10;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffDirectory::readDirectory
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffHeader::decode(Image& image) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
// Nothing to decode from the header itself, just add correct byte order
|
|
Packit |
01d647 |
if (pRootDir_) pRootDir_->decode(image, byteOrder_);
|
|
Packit |
01d647 |
} // CiffHeader::decode
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::decode(Image& image, ByteOrder byteOrder) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
doDecode(image, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffEntry::doDecode(Image& image, ByteOrder byteOrder) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
CrwMap::decode(*this, image, byteOrder);
|
|
Packit |
01d647 |
} // CiffEntry::doDecode
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffDirectory::doDecode(Image& image, ByteOrder byteOrder) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Components::const_iterator b = components_.begin();
|
|
Packit |
01d647 |
Components::const_iterator e = components_.end();
|
|
Packit |
01d647 |
for (Components::const_iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
(*i)->decode(image, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffDirectory::doDecode
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffHeader::write(Blob& blob) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert( byteOrder_ == littleEndian
|
|
Packit |
01d647 |
|| byteOrder_ == bigEndian);
|
|
Packit |
01d647 |
if (byteOrder_ == littleEndian) {
|
|
Packit |
01d647 |
blob.push_back('I');
|
|
Packit |
01d647 |
blob.push_back('I');
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
blob.push_back('M');
|
|
Packit |
01d647 |
blob.push_back('M');
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
uint32_t o = 2;
|
|
Packit |
01d647 |
byte buf[4];
|
|
Packit |
01d647 |
ul2Data(buf, offset_, byteOrder_);
|
|
Packit |
01d647 |
append(blob, buf, 4);
|
|
Packit |
01d647 |
o += 4;
|
|
Packit |
01d647 |
append(blob, reinterpret_cast<const byte*>(signature_), 8);
|
|
Packit |
01d647 |
o += 8;
|
|
Packit |
01d647 |
// Pad as needed
|
|
Packit |
01d647 |
if (pPadding_) {
|
|
Packit |
01d647 |
assert(padded_ == offset_ - o);
|
|
Packit |
01d647 |
append(blob, pPadding_, padded_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
for (uint32_t i = o; i < offset_; ++i) {
|
|
Packit |
01d647 |
blob.push_back(0);
|
|
Packit |
01d647 |
++o;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (pRootDir_) {
|
|
Packit |
01d647 |
pRootDir_->write(blob, byteOrder_, offset_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
uint32_t CiffComponent::write(Blob& blob,
|
|
Packit |
01d647 |
ByteOrder byteOrder,
|
|
Packit |
01d647 |
uint32_t offset)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return doWrite(blob, byteOrder, offset);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
uint32_t CiffEntry::doWrite(Blob& blob,
|
|
Packit |
01d647 |
ByteOrder /*byteOrder*/,
|
|
Packit |
01d647 |
uint32_t offset)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return writeValueData(blob, offset);
|
|
Packit |
01d647 |
} // CiffEntry::doWrite
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
uint32_t CiffComponent::writeValueData(Blob& blob, uint32_t offset)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (dataLocation() == valueData) {
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
std::cout << " Data for tag 0x" << std::hex << tagId()
|
|
Packit |
01d647 |
<< ", " << std::dec << size_ << " Bytes\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
offset_ = offset;
|
|
Packit |
01d647 |
append(blob, pData_, size_);
|
|
Packit |
01d647 |
offset += size_;
|
|
Packit |
01d647 |
// Pad the value to an even number of bytes
|
|
Packit |
01d647 |
if (size_ % 2 == 1) {
|
|
Packit |
01d647 |
blob.push_back(0);
|
|
Packit |
01d647 |
++offset;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return offset;
|
|
Packit |
01d647 |
} // CiffComponent::writeValueData
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
uint32_t CiffDirectory::doWrite(Blob& blob,
|
|
Packit |
01d647 |
ByteOrder byteOrder,
|
|
Packit |
01d647 |
uint32_t offset)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
std::cout << "Writing directory 0x" << std::hex << tag() << "---->\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
// Ciff offsets are relative to the start of the directory
|
|
Packit |
01d647 |
uint32_t dirOffset = 0;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Value data
|
|
Packit |
01d647 |
const Components::iterator b = components_.begin();
|
|
Packit |
01d647 |
const Components::iterator e = components_.end();
|
|
Packit |
01d647 |
for (Components::iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
dirOffset = (*i)->write(blob, byteOrder, dirOffset);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
const uint32_t dirStart = dirOffset;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Number of directory entries
|
|
Packit |
01d647 |
byte buf[4];
|
|
Packit |
01d647 |
us2Data(buf, static_cast<uint16_t>(components_.size()), byteOrder);
|
|
Packit |
01d647 |
append(blob, buf, 2);
|
|
Packit |
01d647 |
dirOffset += 2;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Directory entries
|
|
Packit |
01d647 |
for (Components::iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
(*i)->writeDirEntry(blob, byteOrder);
|
|
Packit |
01d647 |
dirOffset += 10;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Offset of directory
|
|
Packit |
01d647 |
ul2Data(buf, dirStart, byteOrder);
|
|
Packit |
01d647 |
append(blob, buf, 4);
|
|
Packit |
01d647 |
dirOffset += 4;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Update directory entry
|
|
Packit |
01d647 |
setOffset(offset);
|
|
Packit |
01d647 |
setSize(dirOffset);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
std::cout << "Directory is at offset " << std::dec << dirStart
|
|
Packit |
01d647 |
<< ", " << components_.size() << " entries\n"
|
|
Packit |
01d647 |
<< "<---- 0x" << std::hex << tag() << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return offset + dirOffset;
|
|
Packit |
01d647 |
} // CiffDirectory::doWrite
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::writeDirEntry(Blob& blob, ByteOrder byteOrder) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
std::cout << " Directory entry for tag 0x"
|
|
Packit |
01d647 |
<< std::hex << tagId() << " (0x" << tag()
|
|
Packit |
01d647 |
<< "), " << std::dec << size_
|
|
Packit |
01d647 |
<< " Bytes, Offset is " << offset_ << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
byte buf[4];
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
DataLocId dl = dataLocation();
|
|
Packit |
01d647 |
assert(dl == directoryData || dl == valueData);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (dl == valueData) {
|
|
Packit |
01d647 |
us2Data(buf, tag_, byteOrder);
|
|
Packit |
01d647 |
append(blob, buf, 2);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
ul2Data(buf, size_, byteOrder);
|
|
Packit |
01d647 |
append(blob, buf, 4);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
ul2Data(buf, offset_, byteOrder);
|
|
Packit |
01d647 |
append(blob, buf, 4);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (dl == directoryData) {
|
|
Packit |
01d647 |
// Only 8 bytes fit in the directory entry
|
|
Packit |
01d647 |
assert(size_ <= 8);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
us2Data(buf, tag_, byteOrder);
|
|
Packit |
01d647 |
append(blob, buf, 2);
|
|
Packit |
01d647 |
// Copy value instead of size and offset
|
|
Packit |
01d647 |
append(blob, pData_, size_);
|
|
Packit |
01d647 |
// Pad with 0s
|
|
Packit |
01d647 |
for (uint32_t i = size_; i < 8; ++i) {
|
|
Packit |
01d647 |
blob.push_back(0);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffComponent::writeDirEntry
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffHeader::print(std::ostream& os, const std::string& prefix) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
std::ios::fmtflags f( os.flags() );
|
|
Packit |
01d647 |
os << prefix
|
|
Packit |
01d647 |
<< _("Header, offset") << " = 0x" << std::setw(8) << std::setfill('0')
|
|
Packit |
01d647 |
<< std::hex << std::right << offset_ << "\n";
|
|
Packit |
01d647 |
if (pRootDir_) pRootDir_->print(os, byteOrder_, prefix);
|
|
Packit |
01d647 |
os.flags(f);
|
|
Packit |
01d647 |
} // CiffHeader::print
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::print(std::ostream& os,
|
|
Packit |
01d647 |
ByteOrder byteOrder,
|
|
Packit |
01d647 |
const std::string& prefix) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
doPrint(os, byteOrder, prefix);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::doPrint(std::ostream& os,
|
|
Packit |
01d647 |
ByteOrder byteOrder,
|
|
Packit |
01d647 |
const std::string& prefix) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
os << prefix
|
|
Packit |
01d647 |
<< _("tag") << " = 0x" << std::setw(4) << std::setfill('0')
|
|
Packit |
01d647 |
<< std::hex << std::right << tagId()
|
|
Packit |
01d647 |
<< ", " << _("dir") << " = 0x" << std::setw(4) << std::setfill('0')
|
|
Packit |
01d647 |
<< std::hex << std::right << dir()
|
|
Packit |
01d647 |
<< ", " << _("type") << " = " << TypeInfo::typeName(typeId())
|
|
Packit |
01d647 |
<< ", " << _("size") << " = " << std::dec << size_
|
|
Packit |
01d647 |
<< ", " << _("offset") << " = " << offset_ << "\n";
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Value::AutoPtr value;
|
|
Packit |
01d647 |
if (typeId() != directory) {
|
|
Packit |
01d647 |
value = Value::create(typeId());
|
|
Packit |
01d647 |
value->read(pData_, size_, byteOrder);
|
|
Packit |
01d647 |
if (value->size() < 100) {
|
|
Packit |
01d647 |
os << prefix << *value << "\n";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffComponent::doPrint
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffDirectory::doPrint(std::ostream& os,
|
|
Packit |
01d647 |
ByteOrder byteOrder,
|
|
Packit |
01d647 |
const std::string& prefix) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
CiffComponent::doPrint(os, byteOrder, prefix);
|
|
Packit |
01d647 |
Components::const_iterator b = components_.begin();
|
|
Packit |
01d647 |
Components::const_iterator e = components_.end();
|
|
Packit |
01d647 |
for (Components::const_iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
(*i)->print(os, byteOrder, prefix + " ");
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffDirectory::doPrint
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::setValue(DataBuf buf)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (isAllocated_) {
|
|
Packit Bot |
be4f0c |
delete[] pData_;
|
|
Packit |
01d647 |
pData_ = 0;
|
|
Packit |
01d647 |
size_ = 0;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
isAllocated_ = true;
|
|
Packit |
01d647 |
std::pair<byte *, long> p = buf.release();
|
|
Packit |
01d647 |
pData_ = p.first;
|
|
Packit |
01d647 |
size_ = p.second;
|
|
Packit |
01d647 |
if (size_ > 8 && dataLocation() == directoryData) {
|
|
Packit |
01d647 |
tag_ &= 0x3fff;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffComponent::setValue
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
TypeId CiffComponent::typeId(uint16_t tag)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
TypeId ti = invalidTypeId;
|
|
Packit |
01d647 |
switch (tag & 0x3800) {
|
|
Packit |
01d647 |
case 0x0000: ti = unsignedByte; break;
|
|
Packit |
01d647 |
case 0x0800: ti = asciiString; break;
|
|
Packit |
01d647 |
case 0x1000: ti = unsignedShort; break;
|
|
Packit |
01d647 |
case 0x1800: ti = unsignedLong; break;
|
|
Packit |
01d647 |
case 0x2000: ti = undefined; break;
|
|
Packit |
01d647 |
case 0x2800: // fallthrough
|
|
Packit |
01d647 |
case 0x3000: ti = directory; break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return ti;
|
|
Packit |
01d647 |
} // CiffComponent::typeId
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
DataLocId CiffComponent::dataLocation(uint16_t tag)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
switch (tag & 0xc000) {
|
|
Packit |
01d647 |
case 0x0000: return valueData;
|
|
Packit |
01d647 |
case 0x4000: return directoryData;
|
|
Packit |
01d647 |
default: throw Error(kerCorruptedMetadata);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffComponent::dataLocation
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Finds \em crwTagId in directory \em crwDir, returning a pointer to
|
|
Packit |
01d647 |
the component or 0 if not found.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
CiffComponent* CiffHeader::findComponent(uint16_t crwTagId,
|
|
Packit |
01d647 |
uint16_t crwDir) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (pRootDir_ == 0) return 0;
|
|
Packit |
01d647 |
return pRootDir_->findComponent(crwTagId, crwDir);
|
|
Packit |
01d647 |
} // CiffHeader::findComponent
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent* CiffComponent::findComponent(uint16_t crwTagId,
|
|
Packit |
01d647 |
uint16_t crwDir) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return doFindComponent(crwTagId, crwDir);
|
|
Packit |
01d647 |
} // CiffComponent::findComponent
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent* CiffComponent::doFindComponent(uint16_t crwTagId,
|
|
Packit |
01d647 |
uint16_t crwDir) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (tagId() == crwTagId && dir() == crwDir) {
|
|
Packit |
01d647 |
return const_cast<CiffComponent*>(this);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return 0;
|
|
Packit |
01d647 |
} // CiffComponent::doFindComponent
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent* CiffDirectory::doFindComponent(uint16_t crwTagId,
|
|
Packit |
01d647 |
uint16_t crwDir) const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
CiffComponent* cc = NULL;
|
|
Packit |
01d647 |
const Components::const_iterator b = components_.begin();
|
|
Packit |
01d647 |
const Components::const_iterator e = components_.end();
|
|
Packit |
01d647 |
for (Components::const_iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
cc = (*i)->findComponent(crwTagId, crwDir);
|
|
Packit |
01d647 |
if (cc) return cc;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return 0;
|
|
Packit |
01d647 |
} // CiffDirectory::doFindComponent
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffHeader::add(uint16_t crwTagId, uint16_t crwDir, DataBuf buf)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
CrwDirs crwDirs;
|
|
Packit |
01d647 |
CrwMap::loadStack(crwDirs, crwDir);
|
|
Packit |
01d647 |
uint16_t rootDirectory = crwDirs.top().crwDir_;
|
|
Packit |
01d647 |
UNUSED(rootDirectory);
|
|
Packit |
01d647 |
assert(rootDirectory == 0x0000);
|
|
Packit |
01d647 |
crwDirs.pop();
|
|
Packit |
01d647 |
if (!pRootDir_) pRootDir_ = new CiffDirectory;
|
|
Packit |
01d647 |
if ( pRootDir_) {
|
|
Packit |
01d647 |
CiffComponent* child = pRootDir_->add(crwDirs, crwTagId);
|
|
Packit |
01d647 |
if ( child ) child->setValue(buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffHeader::add
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent* CiffComponent::add(CrwDirs& crwDirs, uint16_t crwTagId)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return doAdd(crwDirs, crwTagId);
|
|
Packit |
01d647 |
} // CiffComponent::add
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent* CiffComponent::doAdd(CrwDirs& /*crwDirs*/, uint16_t /*crwTagId*/)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return 0;
|
|
Packit |
01d647 |
} // CiffComponent::doAdd
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent* CiffDirectory::doAdd(CrwDirs& crwDirs, uint16_t crwTagId)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
/*
|
|
Packit |
01d647 |
add()
|
|
Packit |
01d647 |
if stack not empty
|
|
Packit |
01d647 |
pop from stack
|
|
Packit |
01d647 |
find dir among components
|
|
Packit |
01d647 |
if not found, create it
|
|
Packit |
01d647 |
add()
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
find tag among components
|
|
Packit |
01d647 |
if not found, create it
|
|
Packit |
01d647 |
set value
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
const Components::iterator b = components_.begin();
|
|
Packit |
01d647 |
const Components::iterator e = components_.end();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (!crwDirs.empty()) {
|
|
Packit |
01d647 |
CrwSubDir csd = crwDirs.top();
|
|
Packit |
01d647 |
crwDirs.pop();
|
|
Packit |
01d647 |
// Find the directory
|
|
Packit |
01d647 |
for (Components::iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
if ((*i)->tag() == csd.crwDir_) {
|
|
Packit |
01d647 |
cc_ = *i;
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (cc_ == 0) {
|
|
Packit |
01d647 |
// Directory doesn't exist yet, add it
|
|
Packit |
01d647 |
m_ = AutoPtr(new CiffDirectory(csd.crwDir_, csd.parent_));
|
|
Packit |
01d647 |
cc_ = m_.get();
|
|
Packit |
01d647 |
add(m_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
// Recursive call to next lower level directory
|
|
Packit |
01d647 |
cc_ = cc_->add(crwDirs, crwTagId);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
// Find the tag
|
|
Packit |
01d647 |
for (Components::iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
if ((*i)->tagId() == crwTagId) {
|
|
Packit |
01d647 |
cc_ = *i;
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (cc_ == 0) {
|
|
Packit |
01d647 |
// Tag doesn't exist yet, add it
|
|
Packit |
01d647 |
m_ = AutoPtr(new CiffEntry(crwTagId, tag()));
|
|
Packit |
01d647 |
cc_ = m_.get();
|
|
Packit |
01d647 |
add(m_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return cc_;
|
|
Packit |
01d647 |
} // CiffDirectory::doAdd
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffHeader::remove(uint16_t crwTagId, uint16_t crwDir)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (pRootDir_) {
|
|
Packit |
01d647 |
CrwDirs crwDirs;
|
|
Packit |
01d647 |
CrwMap::loadStack(crwDirs, crwDir);
|
|
Packit |
01d647 |
uint16_t rootDirectory = crwDirs.top().crwDir_;
|
|
Packit |
01d647 |
UNUSED(rootDirectory);
|
|
Packit |
01d647 |
assert(rootDirectory == 0x0000);
|
|
Packit |
01d647 |
crwDirs.pop();
|
|
Packit |
01d647 |
pRootDir_->remove(crwDirs, crwTagId);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffHeader::remove
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::remove(CrwDirs& crwDirs, uint16_t crwTagId)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return doRemove(crwDirs, crwTagId);
|
|
Packit |
01d647 |
} // CiffComponent::remove
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffComponent::doRemove(CrwDirs& /*crwDirs*/, uint16_t /*crwTagId*/)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
// do nothing
|
|
Packit |
01d647 |
} // CiffComponent::doRemove
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CiffDirectory::doRemove(CrwDirs& crwDirs, uint16_t crwTagId)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
const Components::iterator b = components_.begin();
|
|
Packit |
01d647 |
const Components::iterator e = components_.end();
|
|
Packit |
01d647 |
Components::iterator i;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (!crwDirs.empty()) {
|
|
Packit |
01d647 |
CrwSubDir csd = crwDirs.top();
|
|
Packit |
01d647 |
crwDirs.pop();
|
|
Packit |
01d647 |
// Find the directory
|
|
Packit |
01d647 |
for (i = b; i != e; ++i) {
|
|
Packit |
01d647 |
if ((*i)->tag() == csd.crwDir_) {
|
|
Packit |
01d647 |
// Recursive call to next lower level directory
|
|
Packit |
01d647 |
(*i)->remove(crwDirs, crwTagId);
|
|
Packit |
01d647 |
if ((*i)->empty()) components_.erase(i);
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
// Find the tag
|
|
Packit |
01d647 |
for (i = b; i != e; ++i) {
|
|
Packit |
01d647 |
if ((*i)->tagId() == crwTagId) {
|
|
Packit |
01d647 |
// Remove the entry and abort the loop
|
|
Packit |
01d647 |
delete *i;
|
|
Packit |
01d647 |
components_.erase(i);
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CiffDirectory::doRemove
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool CiffComponent::empty() const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return doEmpty();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool CiffComponent::doEmpty() const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return size_ == 0;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool CiffDirectory::doEmpty() const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return components_.empty();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::decode(const CiffComponent& ciffComponent,
|
|
Packit |
01d647 |
Image& image,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
const CrwMapping* cmi = crwMapping(ciffComponent.dir(),
|
|
Packit |
01d647 |
ciffComponent.tagId());
|
|
Packit |
01d647 |
if (cmi && cmi->toExif_) {
|
|
Packit |
01d647 |
cmi->toExif_(ciffComponent, cmi, image, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::decode
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
const CrwMapping* CrwMap::crwMapping(uint16_t crwDir, uint16_t crwTagId)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
for (int i = 0; crwMapping_[i].ifdId_ != ifdIdNotSet; ++i) {
|
|
Packit |
01d647 |
if ( crwMapping_[i].crwDir_ == crwDir
|
|
Packit |
01d647 |
&& crwMapping_[i].crwTagId_ == crwTagId) {
|
|
Packit |
01d647 |
return &(crwMapping_[i]);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return 0;
|
|
Packit |
01d647 |
} // CrwMap::crwMapping
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::decode0x0805(const CiffComponent& ciffComponent,
|
|
Packit |
01d647 |
const CrwMapping* /*pCrwMapping*/,
|
|
Packit |
01d647 |
Image& image,
|
|
Packit |
01d647 |
ByteOrder /*byteOrder*/)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
std::string s(reinterpret_cast<const char*>(ciffComponent.pData()));
|
|
Packit |
01d647 |
image.setComment(s);
|
|
Packit |
01d647 |
} // CrwMap::decode0x0805
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::decode0x080a(const CiffComponent& ciffComponent,
|
|
Packit |
01d647 |
const CrwMapping* /*pCrwMapping*/,
|
|
Packit |
01d647 |
Image& image,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (ciffComponent.typeId() != asciiString) return;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Make
|
|
Packit |
01d647 |
ExifKey key1("Exif.Image.Make");
|
|
Packit |
01d647 |
Value::AutoPtr value1 = Value::create(ciffComponent.typeId());
|
|
Packit |
01d647 |
uint32_t i = 0;
|
|
Packit |
01d647 |
for (; i < ciffComponent.size()
|
|
Packit |
01d647 |
&& ciffComponent.pData()[i] != '\0'; ++i) {
|
|
Packit |
01d647 |
// empty
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
value1->read(ciffComponent.pData(), ++i, byteOrder);
|
|
Packit |
01d647 |
image.exifData().add(key1, value1.get());
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Model
|
|
Packit |
01d647 |
ExifKey key2("Exif.Image.Model");
|
|
Packit |
01d647 |
Value::AutoPtr value2 = Value::create(ciffComponent.typeId());
|
|
Packit |
01d647 |
uint32_t j = i;
|
|
Packit |
01d647 |
for (; i < ciffComponent.size()
|
|
Packit |
01d647 |
&& ciffComponent.pData()[i] != '\0'; ++i) {
|
|
Packit |
01d647 |
// empty
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
value2->read(ciffComponent.pData() + j, i - j + 1, byteOrder);
|
|
Packit |
01d647 |
image.exifData().add(key2, value2.get());
|
|
Packit |
01d647 |
} // CrwMap::decode0x080a
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::decodeArray(const CiffComponent& ciffComponent,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
Image& image,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (ciffComponent.typeId() != unsignedShort) {
|
|
Packit |
01d647 |
return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
long aperture = 0;
|
|
Packit |
01d647 |
long shutterSpeed = 0;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
IfdId ifdId = ifdIdNotSet;
|
|
Packit |
01d647 |
switch (pCrwMapping->tag_) {
|
|
Packit |
01d647 |
case 0x0001: ifdId = canonCsId; break;
|
|
Packit |
01d647 |
case 0x0004: ifdId = canonSiId; break;
|
|
Packit |
01d647 |
case 0x000f: ifdId = canonCfId; break;
|
|
Packit |
01d647 |
case 0x0012: ifdId = canonPiId; break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
assert(ifdId != ifdIdNotSet);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::string groupName(Internal::groupName(ifdId));
|
|
Packit |
01d647 |
uint16_t c = 1;
|
|
Packit |
01d647 |
while (uint32_t(c)*2 < ciffComponent.size()) {
|
|
Packit |
01d647 |
uint16_t n = 1;
|
|
Packit |
01d647 |
ExifKey key(c, groupName);
|
|
Packit |
01d647 |
UShortValue value;
|
|
Packit |
01d647 |
if (ifdId == canonCsId && c == 23 && ciffComponent.size() > 50) n = 3;
|
|
Packit |
01d647 |
value.read(ciffComponent.pData() + c*2, n*2, byteOrder);
|
|
Packit |
01d647 |
image.exifData().add(key, &value);
|
|
Packit |
01d647 |
if (ifdId == canonSiId && c == 21) aperture = value.toLong();
|
|
Packit |
01d647 |
if (ifdId == canonSiId && c == 22) shutterSpeed = value.toLong();
|
|
Packit |
01d647 |
c += n;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (ifdId == canonSiId) {
|
|
Packit |
01d647 |
// Exif.Photo.FNumber
|
|
Packit |
01d647 |
float f = fnumber(canonEv(aperture));
|
|
Packit |
01d647 |
Rational r = floatToRationalCast(f);
|
|
Packit |
01d647 |
URational ur(r.first, r.second);
|
|
Packit |
01d647 |
URationalValue fn;
|
|
Packit |
01d647 |
fn.value_.push_back(ur);
|
|
Packit |
01d647 |
image.exifData().add(ExifKey("Exif.Photo.FNumber"), &fn);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Exif.Photo.ExposureTime
|
|
Packit |
01d647 |
ur = exposureTime(canonEv(shutterSpeed));
|
|
Packit |
01d647 |
URationalValue et;
|
|
Packit |
01d647 |
et.value_.push_back(ur);
|
|
Packit |
01d647 |
image.exifData().add(ExifKey("Exif.Photo.ExposureTime"), &et);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::decodeArray
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::decode0x180e(const CiffComponent& ciffComponent,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
Image& image,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (ciffComponent.size() < 8 || ciffComponent.typeId() != unsignedLong) {
|
|
Packit |
01d647 |
return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
ULongValue v;
|
|
Packit |
01d647 |
v.read(ciffComponent.pData(), 8, byteOrder);
|
|
Packit |
01d647 |
time_t t = v.value_[0];
|
|
Packit Service |
fb147c |
struct tm* tm = std::localtime(&t);
|
|
Packit |
01d647 |
if (tm) {
|
|
Packit |
01d647 |
const size_t m = 20;
|
|
Packit |
01d647 |
char s[m];
|
|
Packit |
01d647 |
std::strftime(s, m, "%Y:%m:%d %H:%M:%S", tm);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
|
|
Packit |
01d647 |
AsciiValue value;
|
|
Packit |
01d647 |
value.read(std::string(s));
|
|
Packit |
01d647 |
image.exifData().add(key, &value);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::decode0x180e
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::decode0x1810(const CiffComponent& ciffComponent,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
Image& image,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (ciffComponent.typeId() != unsignedLong || ciffComponent.size() < 28) {
|
|
Packit |
01d647 |
return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
ExifKey key1("Exif.Photo.PixelXDimension");
|
|
Packit |
01d647 |
ULongValue value1;
|
|
Packit |
01d647 |
value1.read(ciffComponent.pData(), 4, byteOrder);
|
|
Packit |
01d647 |
image.exifData().add(key1, &value1);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
ExifKey key2("Exif.Photo.PixelYDimension");
|
|
Packit |
01d647 |
ULongValue value2;
|
|
Packit |
01d647 |
value2.read(ciffComponent.pData() + 4, 4, byteOrder);
|
|
Packit |
01d647 |
image.exifData().add(key2, &value2);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
int32_t r = getLong(ciffComponent.pData() + 12, byteOrder);
|
|
Packit |
01d647 |
uint16_t o = RotationMap::orientation(r);
|
|
Packit |
01d647 |
image.exifData()["Exif.Image.Orientation"] = o;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
} // CrwMap::decode0x1810
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::decode0x2008(const CiffComponent& ciffComponent,
|
|
Packit |
01d647 |
const CrwMapping* /*pCrwMapping*/,
|
|
Packit |
01d647 |
Image& image,
|
|
Packit |
01d647 |
ByteOrder /*byteOrder*/)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
ExifThumb exifThumb(image.exifData());
|
|
Packit |
01d647 |
exifThumb.setJpegThumbnail(ciffComponent.pData(), ciffComponent.size());
|
|
Packit |
01d647 |
} // CrwMap::decode0x2008
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::decodeBasic(const CiffComponent& ciffComponent,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
Image& image,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
// create a key and value pair
|
|
Packit |
01d647 |
ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
|
|
Packit |
01d647 |
Value::AutoPtr value;
|
|
Packit |
01d647 |
if (ciffComponent.typeId() != directory) {
|
|
Packit |
01d647 |
value = Value::create(ciffComponent.typeId());
|
|
Packit |
01d647 |
uint32_t size = 0;
|
|
Packit |
01d647 |
if (pCrwMapping->size_ != 0) {
|
|
Packit |
01d647 |
// size in the mapping table overrides all
|
|
Packit |
01d647 |
size = pCrwMapping->size_;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if (ciffComponent.typeId() == asciiString) {
|
|
Packit |
01d647 |
// determine size from the data, by looking for the first 0
|
|
Packit |
01d647 |
uint32_t i = 0;
|
|
Packit |
01d647 |
for (; i < ciffComponent.size()
|
|
Packit |
01d647 |
&& ciffComponent.pData()[i] != '\0'; ++i) {
|
|
Packit |
01d647 |
// empty
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
size = ++i;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
// by default, use the size from the directory entry
|
|
Packit |
01d647 |
size = ciffComponent.size();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
value->read(ciffComponent.pData(), size, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
// Add metadatum to exif data
|
|
Packit |
01d647 |
image.exifData().add(key, value.get());
|
|
Packit |
01d647 |
} // CrwMap::decodeBasic
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::loadStack(CrwDirs& crwDirs, uint16_t crwDir)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
for (int i = 0; crwSubDir_[i].crwDir_ != 0xffff; ++i) {
|
|
Packit |
01d647 |
if (crwSubDir_[i].crwDir_ == crwDir) {
|
|
Packit |
01d647 |
crwDirs.push(crwSubDir_[i]);
|
|
Packit |
01d647 |
crwDir = crwSubDir_[i].parent_;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::loadStack
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::encode(CiffHeader* pHead, const Image& image)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
for (const CrwMapping* cmi = crwMapping_; cmi->ifdId_ != ifdIdNotSet; ++cmi) {
|
|
Packit |
01d647 |
if (cmi->fromExif_ != 0) {
|
|
Packit |
01d647 |
cmi->fromExif_(image, cmi, pHead);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::encode
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::encodeBasic(const Image& image,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
CiffHeader* pHead)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
assert(pHead != 0);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Determine the source Exif metadatum
|
|
Packit |
01d647 |
ExifKey ek(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
|
|
Packit |
01d647 |
ExifData::const_iterator ed = image.exifData().findKey(ek);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Set the new value or remove the entry
|
|
Packit |
01d647 |
if (ed != image.exifData().end()) {
|
|
Packit |
01d647 |
DataBuf buf(ed->size());
|
|
Packit |
01d647 |
ed->copy(buf.pData_, pHead->byteOrder());
|
|
Packit |
01d647 |
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::encodeBasic
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::encode0x0805(const Image& image,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
CiffHeader* pHead)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
assert(pHead != 0);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::string comment = image.comment();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_,
|
|
Packit |
01d647 |
pCrwMapping->crwDir_);
|
|
Packit |
01d647 |
if (!comment.empty()) {
|
|
Packit |
01d647 |
uint32_t size = static_cast<uint32_t>(comment.size());
|
|
Packit |
01d647 |
if (cc && cc->size() > size) size = cc->size();
|
|
Packit |
01d647 |
DataBuf buf(size);
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
std::memcpy(buf.pData_, comment.data(), comment.size());
|
|
Packit |
01d647 |
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
if (cc) {
|
|
Packit |
01d647 |
// Just delete the value, do not remove the tag
|
|
Packit |
01d647 |
DataBuf buf(cc->size());
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
cc->setValue(buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::encode0x0805
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::encode0x080a(const Image& image,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
CiffHeader* pHead)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
assert(pHead != 0);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
const ExifKey k1("Exif.Image.Make");
|
|
Packit |
01d647 |
const ExifKey k2("Exif.Image.Model");
|
|
Packit |
01d647 |
const ExifData::const_iterator ed1 = image.exifData().findKey(k1);
|
|
Packit |
01d647 |
const ExifData::const_iterator ed2 = image.exifData().findKey(k2);
|
|
Packit |
01d647 |
const ExifData::const_iterator edEnd = image.exifData().end();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
long size = 0;
|
|
Packit |
01d647 |
if (ed1 != edEnd) size += ed1->size();
|
|
Packit |
01d647 |
if (ed2 != edEnd) size += ed2->size();
|
|
Packit |
01d647 |
if (size != 0) {
|
|
Packit |
01d647 |
DataBuf buf(size);
|
|
Packit |
01d647 |
if (ed1 != edEnd) ed1->copy(buf.pData_, pHead->byteOrder());
|
|
Packit |
01d647 |
if (ed2 != edEnd) ed2->copy(buf.pData_ + ed1->size(), pHead->byteOrder());
|
|
Packit |
01d647 |
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::encode0x080a
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::encodeArray(const Image& image,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
CiffHeader* pHead)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
assert(pHead != 0);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
IfdId ifdId = ifdIdNotSet;
|
|
Packit |
01d647 |
switch (pCrwMapping->tag_) {
|
|
Packit |
01d647 |
case 0x0001: ifdId = canonCsId; break;
|
|
Packit |
01d647 |
case 0x0004: ifdId = canonSiId; break;
|
|
Packit |
01d647 |
case 0x000f: ifdId = canonCfId; break;
|
|
Packit |
01d647 |
case 0x0012: ifdId = canonPiId; break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
assert(ifdId != ifdIdNotSet);
|
|
Packit |
01d647 |
DataBuf buf = packIfdId(image.exifData(), ifdId, pHead->byteOrder());
|
|
Packit |
01d647 |
if (buf.size_ == 0) {
|
|
Packit |
01d647 |
// Try the undecoded tag
|
|
Packit |
01d647 |
encodeBasic(image, pCrwMapping, pHead);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (buf.size_ > 0) {
|
|
Packit |
01d647 |
// Write the number of shorts to the beginning of buf
|
|
Packit |
01d647 |
us2Data(buf.pData_, static_cast<uint16_t>(buf.size_), pHead->byteOrder());
|
|
Packit |
01d647 |
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::encodeArray
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::encode0x180e(const Image& image,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
CiffHeader* pHead)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
assert(pHead != 0);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
time_t t = 0;
|
|
Packit |
01d647 |
const ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
|
|
Packit |
01d647 |
const ExifData::const_iterator ed = image.exifData().findKey(key);
|
|
Packit |
01d647 |
if (ed != image.exifData().end()) {
|
|
Packit |
01d647 |
struct tm tm;
|
|
Packit |
01d647 |
std::memset(&tm, 0x0, sizeof(tm));
|
|
Packit Service |
fb147c |
if ( exifTime(ed->toString().c_str(), &tm) == 0 ) {
|
|
Packit Service |
fb147c |
t=::mktime(&tm;;
|
|
Packit Service |
fb147c |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (t != 0) {
|
|
Packit |
01d647 |
DataBuf buf(12);
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, 12);
|
|
Packit |
01d647 |
ul2Data(buf.pData_, static_cast<uint32_t>(t), pHead->byteOrder());
|
|
Packit |
01d647 |
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::encode0x180e
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::encode0x1810(const Image& image,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
CiffHeader* pHead)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
assert(pHead != 0);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
const ExifKey kX("Exif.Photo.PixelXDimension");
|
|
Packit |
01d647 |
const ExifKey kY("Exif.Photo.PixelYDimension");
|
|
Packit |
01d647 |
const ExifKey kO("Exif.Image.Orientation");
|
|
Packit |
01d647 |
const ExifData &exivData = image.exifData();
|
|
Packit |
01d647 |
const ExifData::const_iterator edX = exivData.findKey(kX);
|
|
Packit |
01d647 |
const ExifData::const_iterator edY = exivData.findKey(kY);
|
|
Packit |
01d647 |
const ExifData::const_iterator edO = exivData.findKey(kO);
|
|
Packit |
01d647 |
const ExifData::const_iterator edEnd = exivData.end();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_,
|
|
Packit |
01d647 |
pCrwMapping->crwDir_);
|
|
Packit |
01d647 |
if (edX != edEnd || edY != edEnd || edO != edEnd) {
|
|
Packit |
01d647 |
uint32_t size = 28;
|
|
Packit Bot |
be4f0c |
if (cc) {
|
|
Packit Bot |
be4f0c |
if (cc->size() < size)
|
|
Packit Bot |
be4f0c |
throw Error(kerCorruptedMetadata);
|
|
Packit Bot |
be4f0c |
size = cc->size();
|
|
Packit Bot |
be4f0c |
}
|
|
Packit |
01d647 |
DataBuf buf(size);
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
if (cc) std::memcpy(buf.pData_ + 8, cc->pData() + 8, cc->size() - 8);
|
|
Packit |
01d647 |
if (edX != edEnd && edX->size() == 4) {
|
|
Packit |
01d647 |
edX->copy(buf.pData_, pHead->byteOrder());
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (edY != edEnd && edY->size() == 4) {
|
|
Packit |
01d647 |
edY->copy(buf.pData_ + 4, pHead->byteOrder());
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
int32_t d = 0;
|
|
Packit |
01d647 |
if (edO != edEnd && edO->count() > 0 && edO->typeId() == unsignedShort) {
|
|
Packit |
01d647 |
d = RotationMap::degrees(static_cast<uint16_t>(edO->toLong()));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
l2Data(buf.pData_ + 12, d, pHead->byteOrder());
|
|
Packit |
01d647 |
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::encode0x1810
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void CrwMap::encode0x2008(const Image& image,
|
|
Packit |
01d647 |
const CrwMapping* pCrwMapping,
|
|
Packit |
01d647 |
CiffHeader* pHead)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
assert(pCrwMapping != 0);
|
|
Packit |
01d647 |
assert(pHead != 0);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
ExifThumbC exifThumb(image.exifData());
|
|
Packit |
01d647 |
DataBuf buf = exifThumb.copy();
|
|
Packit |
01d647 |
if (buf.size_ != 0) {
|
|
Packit |
01d647 |
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // CrwMap::encode0x2008
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// *************************************************************************
|
|
Packit |
01d647 |
// free functions
|
|
Packit |
01d647 |
DataBuf packIfdId(const ExifData& exifData,
|
|
Packit |
01d647 |
IfdId ifdId,
|
|
Packit |
01d647 |
ByteOrder byteOrder)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
const uint16_t size = 1024;
|
|
Packit |
01d647 |
DataBuf buf(size);
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
uint16_t len = 0;
|
|
Packit |
01d647 |
const ExifData::const_iterator b = exifData.begin();
|
|
Packit |
01d647 |
const ExifData::const_iterator e = exifData.end();
|
|
Packit |
01d647 |
for (ExifData::const_iterator i = b; i != e; ++i) {
|
|
Packit |
01d647 |
if (i->ifdId() != ifdId) continue;
|
|
Packit |
01d647 |
const uint16_t s = i->tag()*2 + static_cast<uint16_t>(i->size());
|
|
Packit |
01d647 |
assert(s <= size);
|
|
Packit |
01d647 |
if (len < s) len = s;
|
|
Packit |
01d647 |
i->copy(buf.pData_ + i->tag()*2, byteOrder);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
// Round the size to make it even.
|
|
Packit |
01d647 |
buf.size_ = len + len%2;
|
|
Packit |
01d647 |
return buf;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
}} // namespace Internal, Exiv2
|