|
|
|
@ -23,26 +23,26 @@
|
|
|
|
|
#define EXIV2_DEBUG_MESSAGES
|
|
|
|
|
|
|
|
|
|
// included header files
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "bmffimage.hpp"
|
|
|
|
|
|
|
|
|
|
#include "basicio.hpp"
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "error.hpp"
|
|
|
|
|
#include "futils.hpp"
|
|
|
|
|
#include "image.hpp"
|
|
|
|
|
#include "image_int.hpp"
|
|
|
|
|
#include "safe_op.hpp"
|
|
|
|
|
#include "tiffimage.hpp"
|
|
|
|
|
#include "tiffimage_int.hpp"
|
|
|
|
|
#include "bmffimage.hpp"
|
|
|
|
|
#include "basicio.hpp"
|
|
|
|
|
#include "error.hpp"
|
|
|
|
|
#include "futils.hpp"
|
|
|
|
|
#include "types.hpp"
|
|
|
|
|
#include "safe_op.hpp"
|
|
|
|
|
#include "unused.h"
|
|
|
|
|
|
|
|
|
|
// + standard includes
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
struct BmffBoxHeader
|
|
|
|
|
{
|
|
|
|
@ -72,7 +72,6 @@ struct BmffBoxHeader
|
|
|
|
|
#define TAG_cmt3 0x434D5433 /**< canonID */
|
|
|
|
|
#define TAG_cmt4 0x434D5434 /**< gpsID */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// *****************************************************************************
|
|
|
|
|
// class member definitions
|
|
|
|
|
namespace Exiv2
|
|
|
|
@ -92,24 +91,20 @@ namespace Exiv2
|
|
|
|
|
class Iloc
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Iloc(uint32_t ID=0,uint32_t start=0,uint32_t length=0)
|
|
|
|
|
: ID_ (ID)
|
|
|
|
|
, start_ (start )
|
|
|
|
|
, length_ (length)
|
|
|
|
|
{};
|
|
|
|
|
Iloc(uint32_t ID = 0, uint32_t start = 0, uint32_t length = 0) : ID_(ID), start_(start), length_(length){};
|
|
|
|
|
virtual ~Iloc(){};
|
|
|
|
|
|
|
|
|
|
uint32_t ID_;
|
|
|
|
|
uint32_t start_;
|
|
|
|
|
uint32_t length_;
|
|
|
|
|
|
|
|
|
|
std::string toString(long address=0) const {
|
|
|
|
|
std::string toString(long address = 0) const
|
|
|
|
|
{
|
|
|
|
|
return Internal::stringFormat("ID = %d from,length = %d,%d", ID_, start_ + address, length_);
|
|
|
|
|
}
|
|
|
|
|
}; // class Iloc
|
|
|
|
|
|
|
|
|
|
BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */)
|
|
|
|
|
: Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io)
|
|
|
|
|
BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io)
|
|
|
|
|
{
|
|
|
|
|
pixelWidth_ = 0;
|
|
|
|
|
pixelHeight_ = 0;
|
|
|
|
@ -136,33 +131,27 @@ namespace Exiv2
|
|
|
|
|
|
|
|
|
|
bool BmffImage::superBox(uint32_t box)
|
|
|
|
|
{
|
|
|
|
|
return box == TAG_moov
|
|
|
|
|
|| box == TAG_dinf
|
|
|
|
|
|| box == TAG_iprp
|
|
|
|
|
|| box == TAG_ipco
|
|
|
|
|
|| box == TAG_meta
|
|
|
|
|
|| box == TAG_iinf
|
|
|
|
|
|| box == TAG_iloc
|
|
|
|
|
;
|
|
|
|
|
return box == TAG_moov || box == TAG_dinf || box == TAG_iprp || box == TAG_ipco || box == TAG_meta ||
|
|
|
|
|
box == TAG_iinf || box == TAG_iloc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BmffImage::fullBox(uint32_t box)
|
|
|
|
|
{
|
|
|
|
|
return box == TAG_meta
|
|
|
|
|
|| box == TAG_iinf
|
|
|
|
|
|| box == TAG_iloc
|
|
|
|
|
;
|
|
|
|
|
return box == TAG_meta || box == TAG_iinf || box == TAG_iloc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string BmffImage::mimeType() const
|
|
|
|
|
{
|
|
|
|
|
switch (fileType)
|
|
|
|
|
{
|
|
|
|
|
case TAG_avif: return "image/avif";
|
|
|
|
|
switch (fileType) {
|
|
|
|
|
case TAG_avif:
|
|
|
|
|
return "image/avif";
|
|
|
|
|
case TAG_heic:
|
|
|
|
|
case TAG_heif: return "image/heif";
|
|
|
|
|
case TAG_crx : return "image/x-canon-cr3";
|
|
|
|
|
default : return "image/generic";
|
|
|
|
|
case TAG_heif:
|
|
|
|
|
return "image/heif";
|
|
|
|
|
case TAG_crx:
|
|
|
|
|
return "image/x-canon-cr3";
|
|
|
|
|
default:
|
|
|
|
|
return "image/generic";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -188,15 +177,15 @@ namespace Exiv2
|
|
|
|
|
visits_.insert(address);
|
|
|
|
|
|
|
|
|
|
BmffBoxHeader box = {0, 0};
|
|
|
|
|
if ( io_->read((byte*)&box, sizeof(box)) != sizeof(box)) return result;
|
|
|
|
|
if (io_->read((byte*)&box, sizeof(box)) != sizeof(box))
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
box.length = getLong((byte*)&box.length, bigEndian);
|
|
|
|
|
box.type = getLong((byte*)&box.type, bigEndian);
|
|
|
|
|
#ifdef EXIV2_DEBUG_MESSAGES
|
|
|
|
|
bool bLF = true;
|
|
|
|
|
std::cerr << indent(depth) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type)
|
|
|
|
|
<< Internal::stringFormat(" %8ld->%u ",address,box.length)
|
|
|
|
|
;
|
|
|
|
|
<< Internal::stringFormat(" %8ld->%u ", address, box.length);
|
|
|
|
|
#endif
|
|
|
|
|
if (box.length == 1) {
|
|
|
|
|
DataBuf data(8);
|
|
|
|
@ -227,10 +216,8 @@ namespace Exiv2
|
|
|
|
|
skip += 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (box.type)
|
|
|
|
|
{
|
|
|
|
|
case TAG_ftyp:
|
|
|
|
|
{
|
|
|
|
|
switch (box.type) {
|
|
|
|
|
case TAG_ftyp: {
|
|
|
|
|
fileType = getLong(data.pData_, bigEndian);
|
|
|
|
|
#ifdef EXIV2_DEBUG_MESSAGES
|
|
|
|
|
std::cerr << "Brand: " << toAscii(fileType);
|
|
|
|
@ -238,8 +225,7 @@ namespace Exiv2
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
// 8.11.6.1
|
|
|
|
|
case TAG_iinf:
|
|
|
|
|
{
|
|
|
|
|
case TAG_iinf: {
|
|
|
|
|
#ifdef EXIV2_DEBUG_MESSAGES
|
|
|
|
|
std::cerr << std::endl;
|
|
|
|
|
bLF = false;
|
|
|
|
@ -256,7 +242,8 @@ namespace Exiv2
|
|
|
|
|
// 8.11.6.2
|
|
|
|
|
case TAG_infe: { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0
|
|
|
|
|
/* getLong (data.pData_+skip,bigEndian) ; */ skip += 4;
|
|
|
|
|
uint16_t ID = getShort(data.pData_+skip,bigEndian) ; skip+=2;
|
|
|
|
|
uint16_t ID = getShort(data.pData_ + skip, bigEndian);
|
|
|
|
|
skip += 2;
|
|
|
|
|
/* getShort(data.pData_+skip,bigEndian) ; */ skip += 2; // protection
|
|
|
|
|
std::string name((const char*)data.pData_ + skip);
|
|
|
|
|
if (name.find("Exif") == 0) { // "Exif" or "ExifExif"
|
|
|
|
@ -267,7 +254,6 @@ namespace Exiv2
|
|
|
|
|
#endif
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case TAG_moov:
|
|
|
|
|
case TAG_iprp:
|
|
|
|
|
case TAG_ipco:
|
|
|
|
@ -304,9 +290,11 @@ namespace Exiv2
|
|
|
|
|
#else
|
|
|
|
|
skip++;
|
|
|
|
|
#endif
|
|
|
|
|
uint32_t itemCount = version < 2 ? getShort(data.pData_+skip,bigEndian) : getLong(data.pData_+skip,bigEndian);
|
|
|
|
|
uint32_t itemCount =
|
|
|
|
|
version < 2 ? getShort(data.pData_ + skip, bigEndian) : getLong(data.pData_ + skip, bigEndian);
|
|
|
|
|
skip += version < 2 ? 2 : 4;
|
|
|
|
|
if ( itemCount && itemCount < box.length/14 && offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) {
|
|
|
|
|
if (itemCount && itemCount < box.length / 14 && offsetSize == 4 && lengthSize == 4 &&
|
|
|
|
|
((box.length - 16) % itemCount) == 0) {
|
|
|
|
|
#ifdef EXIV2_DEBUG_MESSAGES
|
|
|
|
|
std::cerr << std::endl;
|
|
|
|
|
bLF = false;
|
|
|
|
@ -315,14 +303,15 @@ namespace Exiv2
|
|
|
|
|
uint32_t base = skip;
|
|
|
|
|
for (uint32_t i = 0; i < itemCount; i++) {
|
|
|
|
|
skip = base + i * step; // move in 16 or 14 byte steps
|
|
|
|
|
uint32_t ID = version > 2 ? getLong(data.pData_+skip,bigEndian) : getShort(data.pData_+skip,bigEndian);
|
|
|
|
|
uint32_t ID = version > 2 ? getLong(data.pData_ + skip, bigEndian)
|
|
|
|
|
: getShort(data.pData_ + skip, bigEndian);
|
|
|
|
|
uint32_t offset = getLong(data.pData_ + skip + step - 8, bigEndian);
|
|
|
|
|
uint32_t ldata = getLong(data.pData_ + skip + step - 4, bigEndian);
|
|
|
|
|
#ifdef EXIV2_DEBUG_MESSAGES
|
|
|
|
|
std::cerr << indent(depth)
|
|
|
|
|
<< Internal::stringFormat("%8ld | %8u | ext | %4u | %6u,%6u",address+skip,step,ID,offset,ldata)
|
|
|
|
|
<< std::endl
|
|
|
|
|
;
|
|
|
|
|
<< Internal::stringFormat("%8ld | %8u | ext | %4u | %6u,%6u", address + skip, step,
|
|
|
|
|
ID, offset, ldata)
|
|
|
|
|
<< std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
ilocs_[ID] = Iloc(ID, offset, ldata);
|
|
|
|
|
}
|
|
|
|
@ -331,12 +320,12 @@ namespace Exiv2
|
|
|
|
|
|
|
|
|
|
case TAG_ispe: {
|
|
|
|
|
skip += 4;
|
|
|
|
|
int width = (int) getLong(data.pData_ + skip, bigEndian); skip+=4;
|
|
|
|
|
int height = (int) getLong(data.pData_ + skip, bigEndian); skip+=4;
|
|
|
|
|
int width = (int)getLong(data.pData_ + skip, bigEndian);
|
|
|
|
|
skip += 4;
|
|
|
|
|
int height = (int)getLong(data.pData_ + skip, bigEndian);
|
|
|
|
|
skip += 4;
|
|
|
|
|
#ifdef EXIV2_DEBUG_MESSAGES
|
|
|
|
|
std::cerr << "pixelWidth_, pixelHeight_ = "
|
|
|
|
|
<< Internal::stringFormat("%d, %d", width, height)
|
|
|
|
|
;
|
|
|
|
|
std::cerr << "pixelWidth_, pixelHeight_ = " << Internal::stringFormat("%d, %d", width, height);
|
|
|
|
|
// HEIC files can have multiple ispe records
|
|
|
|
|
// Store largest width/height
|
|
|
|
|
if (width > pixelWidth_ && height > pixelHeight_) {
|
|
|
|
@ -346,8 +335,7 @@ namespace Exiv2
|
|
|
|
|
#endif
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case TAG_uuid:
|
|
|
|
|
{
|
|
|
|
|
case TAG_uuid: {
|
|
|
|
|
DataBuf uuid(16);
|
|
|
|
|
io_->read(uuid.pData_, uuid.size_);
|
|
|
|
|
std::string name = uuidName(uuid);
|
|
|
|
@ -361,18 +349,29 @@ namespace Exiv2
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case TAG_cmt1: parseTiff(Internal::Tag::root ,box.length); break;
|
|
|
|
|
case TAG_cmt2: parseTiff(Internal::Tag::cr3_exif,box.length); break;
|
|
|
|
|
case TAG_cmt3: parseTiff(Internal::Tag::cr3_mn ,box.length); break;
|
|
|
|
|
case TAG_cmt4: parseTiff(Internal::Tag::cr3_gps ,box.length); break;
|
|
|
|
|
|
|
|
|
|
default: {} ; /* do nothing */
|
|
|
|
|
case TAG_cmt1:
|
|
|
|
|
parseTiff(Internal::Tag::root, box.length);
|
|
|
|
|
break;
|
|
|
|
|
case TAG_cmt2:
|
|
|
|
|
parseTiff(Internal::Tag::cr3_exif, box.length);
|
|
|
|
|
break;
|
|
|
|
|
case TAG_cmt3:
|
|
|
|
|
parseTiff(Internal::Tag::cr3_mn, box.length);
|
|
|
|
|
break;
|
|
|
|
|
case TAG_cmt4:
|
|
|
|
|
parseTiff(Internal::Tag::cr3_gps, box.length);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: {
|
|
|
|
|
}; /* do nothing */
|
|
|
|
|
}
|
|
|
|
|
#ifdef EXIV2_DEBUG_MESSAGES
|
|
|
|
|
if ( bLF ) std::cerr << std::endl;
|
|
|
|
|
if (bLF)
|
|
|
|
|
std::cerr << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
// return address of next box
|
|
|
|
|
if ( box.length != 1 ) result = static_cast<long>(address + box.length);
|
|
|
|
|
if (box.length != 1)
|
|
|
|
|
result = static_cast<long>(address + box.length);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
@ -402,14 +401,14 @@ namespace Exiv2
|
|
|
|
|
|
|
|
|
|
void BmffImage::readMetadata()
|
|
|
|
|
{
|
|
|
|
|
if (io_->open() != 0)
|
|
|
|
|
{
|
|
|
|
|
if (io_->open() != 0) {
|
|
|
|
|
throw Error(kerDataSourceOpenFailed, io_->path(), strError());
|
|
|
|
|
}
|
|
|
|
|
IoCloser closer(*io_);
|
|
|
|
|
// Ensure that this is the correct image type
|
|
|
|
|
if (!isBmffType(*io_, false)) {
|
|
|
|
|
if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
|
|
|
|
|
if (io_->error() || io_->eof())
|
|
|
|
|
throw Error(kerFailedToReadImageData);
|
|
|
|
|
throw Error(kerNotAnImage, "BMFF");
|
|
|
|
|
}
|
|
|
|
|
ilocs_.clear();
|
|
|
|
@ -452,8 +451,7 @@ namespace Exiv2
|
|
|
|
|
Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create)
|
|
|
|
|
{
|
|
|
|
|
Image::AutoPtr image(new BmffImage(io, create));
|
|
|
|
|
if (!image->good())
|
|
|
|
|
{
|
|
|
|
|
if (!image->good()) {
|
|
|
|
|
image.reset();
|
|
|
|
|
}
|
|
|
|
|
return image;
|
|
|
|
@ -461,8 +459,7 @@ namespace Exiv2
|
|
|
|
|
|
|
|
|
|
bool isBmffType(BasicIo& iIo, bool advance)
|
|
|
|
|
{
|
|
|
|
|
if (!enabled)
|
|
|
|
|
{
|
|
|
|
|
if (!enabled) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const int32_t len = 12;
|
|
|
|
|