22
22
File: tiffvisitor.cpp
24
24
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
25
25
History: 11-Apr-06, ahu: created
27
27
// *****************************************************************************
28
28
#include "rcsid.hpp"
29
EXIV2_RCSID("@(#) $Id: tiffvisitor.cpp 808 2006-06-01 15:09:39Z ahuggel $");
29
EXIV2_RCSID("@(#) $Id: tiffvisitor.cpp 943 2006-11-06 15:48:14Z ahuggel $")
31
31
// *****************************************************************************
32
32
// included header files
36
36
# include "exv_conf.h"
39
#include "tiffvisitor.hpp"
40
#include "tiffcomposite.hpp"
39
#include "tiffcomposite.hpp" // Do not change the order of these 2 includes,
40
#include "tiffvisitor.hpp" // see bug #487
41
#include "tiffparser.hpp"
41
42
#include "makernote2.hpp"
42
43
#include "exif.hpp"
43
44
#include "iptc.hpp"
55
56
// class member definitions
58
// TIFF Decoder table for special decoding requirements
59
const TiffDecoderInfo TiffMetadataDecoder::tiffDecoderInfo_[] = {
60
{ "*", Tag::all, Group::ignr, 0 }, // Do not decode tags with group == Group::ignr
61
{ "OLYMPUS", 0x0100, Group::olympmn, &TiffMetadataDecoder::decodeOlympThumb },
62
{ "*", 0x014a, Group::ifd0, 0 }, // Todo: Controversial, causes problems with Exiftool
63
{ "*", Tag::all, Group::sub0_0, &TiffMetadataDecoder::decodeSubIfd },
64
{ "*", Tag::all, Group::sub0_1, &TiffMetadataDecoder::decodeSubIfd },
65
{ "*", 0x8649, Group::ifd0, &TiffMetadataDecoder::decodeIrbIptc }
68
bool TiffDecoderInfo::operator==(const TiffDecoderInfo::Key& key) const
70
std::string make(make_);
71
return ("*" == make || make == key.m_.substr(0, make.length()))
72
&& (Tag::all == extendedTag_ || key.e_ == extendedTag_)
76
59
void TiffFinder::init(uint16_t tag, uint16_t group)
136
119
TiffMetadataDecoder::TiffMetadataDecoder(Image* pImage,
137
120
TiffComponent* const pRoot,
121
FindDecoderFct findDecoderFct,
138
122
uint32_t threshold)
139
: pImage_(pImage), pRoot_(pRoot), threshold_(threshold)
125
findDecoderFct_(findDecoderFct),
126
threshold_(threshold)
141
128
// Find camera make
142
129
TiffFinder finder(0x010f, Group::ifd0);
203
190
assert(pImage_ != 0);
204
191
if (!object->pData()) return;
205
192
byte const* record = 0;
206
uint16_t sizeHdr = 0;
207
uint16_t sizeData = 0;
193
uint32_t sizeHdr = 0;
194
uint32_t sizeData = 0;
208
195
if (0 != Photoshop::locateIptcIrb(object->pData(), object->size(),
209
196
&record, &sizeHdr, &sizeData)) {
252
239
groupType_[object->group()] = object->pValue()->toLong();
255
const TiffDecoderInfo* td = find(tiffDecoderInfo_,
256
TiffDecoderInfo::Key(make_, object->tag(), object->group()));
258
// skip decoding if td->decoderFct_ == 0
259
if (td->decoderFct_) {
260
EXV_CALL_MEMBER_FN(*this, td->decoderFct_)(object);
242
const DecoderFct decoderFct = findDecoderFct_(make_,
245
// skip decoding if decoderFct == 0
247
EXV_CALL_MEMBER_FN(*this, decoderFct)(object);
249
} // TiffMetadataDecoder::decodeTiffEntry
251
void TiffMetadataDecoder::decodeStdTiffEntry(const TiffEntryBase* object)
264
254
assert(pImage_ != 0);
265
255
// "Normal" tag has low priority: only decode if it doesn't exist yet.
266
256
// Todo: ExifKey should have an appropriate c'tor, it should not be
376
366
else os_ << prefix() << "Makernote ";
377
367
} // TiffPrinter::visitMnEntry
379
void TiffPrinter::visitIfdMakernote(TiffIfdMakernote* object)
369
void TiffPrinter::visitIfdMakernote(TiffIfdMakernote* /*object*/)
382
372
} // TiffPrinter::visitIfdMakernote
493
483
pRoot_->accept(finder);
494
484
TiffEntryBase* te = dynamic_cast<TiffEntryBase*>(finder.result());
495
485
if (te && te->pValue()) {
496
long size = te->pValue()->toLong();
497
long offset = object->pValue()->toLong();
498
if (baseOffset() + offset + size <= size_) {
499
object->pValue_->setDataArea(pData_ + baseOffset() + offset, size);
501
#ifndef SUPPRESS_WARNINGS
503
std::cerr << "Warning: "
504
<< "Directory " << object->groupName()
505
<< ", entry 0x" << std::setw(4)
506
<< std::setfill('0') << std::hex << object->tag()
507
<< " Data area exceeds data buffer, ignoring it.\n";
486
setDataArea(object, te->pValue());
514
490
void TiffReader::visitSizeEntry(TiffSizeEntry* object)
520
496
pRoot_->accept(finder);
521
497
TiffEntryBase* te = dynamic_cast<TiffEntryBase*>(finder.result());
522
498
if (te && te->pValue()) {
523
long offset = te->pValue()->toLong();
524
long size = object->pValue()->toLong();
525
if (baseOffset() + offset + size <= size_) {
526
te->pValue_->setDataArea(pData_ + baseOffset() + offset, size);
528
#ifndef SUPPRESS_WARNINGS
530
std::cerr << "Warning: "
531
<< "Directory " << object->groupName()
532
<< ", entry 0x" << std::setw(4)
533
<< std::setfill('0') << std::hex << object->tag()
534
<< " Data area exceeds data buffer, ignoring it.\n";
499
setDataArea(te, object->pValue());
503
void TiffReader::setDataArea(TiffEntryBase* pOffsetEntry, const Value* pSize)
505
assert(pOffsetEntry);
508
Value* pOffset = pOffsetEntry->pValue_;
512
for (long i = 0; i < pSize->count(); ++i) {
513
size += pSize->toLong(i);
515
long offset = pOffset->toLong(0);
516
// Todo: Remove limitation of Jpeg writer: strips must be contiguous
517
// Until then we check: last offset + last size - first offset == size?
518
if ( pOffset->toLong(pOffset->count()-1)
519
+ pSize->toLong(pSize->count()-1)
521
#ifndef SUPPRESS_WARNINGS
522
std::cerr << "Warning: "
523
<< "Directory " << pOffsetEntry->groupName()
524
<< ", entry 0x" << std::setw(4)
525
<< std::setfill('0') << std::hex << pOffsetEntry->tag()
526
<< " Data area is not contiguous, ignoring it.\n";
530
if (baseOffset() + offset + size > size_) {
531
#ifndef SUPPRESS_WARNINGS
532
std::cerr << "Warning: "
533
<< "Directory " << pOffsetEntry->groupName()
534
<< ", entry 0x" << std::setw(4)
535
<< std::setfill('0') << std::hex << pOffsetEntry->tag()
536
<< " Data area exceeds data buffer, ignoring it.\n";
540
pOffset->setDataArea(pData_ + baseOffset() + offset, size);
541
543
void TiffReader::visitDirectory(TiffDirectory* object)
548
550
if (p + 2 > pLast_) {
549
551
#ifndef SUPPRESS_WARNINGS
550
552
std::cerr << "Error: "
551
<< "Directory " << object->groupName() << ": "
552
<< " IFD exceeds data buffer, cannot read entry count.\n";
553
<< "Directory " << object->groupName()
554
<< ": IFD exceeds data buffer, cannot read entry count.\n";
556
558
const uint16_t n = getUShort(p, byteOrder());
560
// Sanity check with an "unreasonably" large number
562
#ifndef SUPPRESS_WARNINGS
563
std::cerr << "Error: "
564
<< "Directory " << object->groupName() << " with "
565
<< n << " entries considered invalid; not read.\n";
558
569
for (uint16_t i = 0; i < n; ++i) {
559
570
if (p + 12 > pLast_) {
560
571
#ifndef SUPPRESS_WARNINGS
561
572
std::cerr << "Error: "
562
<< "Directory " << object->groupName() << ": "
563
<< " IFD entry " << i
573
<< "Directory " << object->groupName()
574
<< ": IFD entry " << i
564
575
<< " lies outside of the data buffer.\n";
576
587
if (p + 4 > pLast_) {
577
588
#ifndef SUPPRESS_WARNINGS
578
589
std::cerr << "Error: "
579
<< "Directory " << object->groupName() << ": "
580
<< " IFD exceeds data buffer, cannot read next pointer.\n";
590
<< "Directory " << object->groupName()
591
<< ": IFD exceeds data buffer, cannot read next pointer.\n";
598
609
if (baseOffset() + next > size_) {
599
610
#ifndef SUPPRESS_WARNINGS
600
611
std::cerr << "Error: "
601
<< "Directory " << object->groupName() << ": "
602
<< " Next pointer is out of bounds.\n";
612
<< "Directory " << object->groupName()
613
<< ": Next pointer is out of bounds.\n";
702
713
} // TiffReader::visitIfdMakernote
704
void TiffReader::visitIfdMakernoteEnd(TiffIfdMakernote* object)
715
void TiffReader::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/)
706
717
// Reset state (byte order, create function, offset) back to that
726
737
// Component already has tag
728
739
object->type_ = getUShort(p, byteOrder());
740
long typeSize = TypeInfo::typeSize(object->typeId());
742
#ifndef SUPPRESS_WARNINGS
743
std::cerr << "Error: Directory " << object->groupName()
744
<< ", entry 0x" << std::setw(4)
745
<< std::setfill('0') << std::hex << object->tag()
746
<< " has an invalid type:\n"
747
<< "Type = " << std::dec << object->type_
748
<< "; skipping entry.\n";
731
753
object->count_ = getULong(p, byteOrder());
733
object->size_ = TypeInfo::typeSize(object->typeId()) * object->count();
755
object->size_ = typeSize * object->count();
734
756
object->offset_ = getULong(p, byteOrder());
735
757
object->pData_ = p;
736
758
if (object->size() > 4) {
737
759
if (baseOffset() + object->offset() >= size_) {
738
760
#ifndef SUPPRESS_WARNINGS
739
761
std::cerr << "Error: Offset of "
740
<< "directory " << object->groupName() << ", "
741
<< " entry 0x" << std::setw(4)
762
<< "directory " << object->groupName()
763
<< ", entry 0x" << std::setw(4)
742
764
<< std::setfill('0') << std::hex << object->tag()
743
765
<< " is out of bounds:\n"
744
766
<< "Offset = 0x" << std::setw(8)
753
775
object->pData_ = pData_ + baseOffset() + object->offset();
754
if (object->pData() + object->size() > pLast_) {
776
if (object->size() > static_cast<uint32_t>(pLast_ - object->pData())) {
755
777
#ifndef SUPPRESS_WARNINGS
756
778
std::cerr << "Warning: Upper boundary of data for "
757
779
<< "directory " << object->groupName()
770
792
// todo: adjust count_, make size_ a multiple of typeSize
773
Value::AutoPtr v = Value::create(object->typeId());
795
// On the fly type conversion for Exif.Photo.UserComment
796
// Todo: This should be somewhere else, maybe in a Value factory
797
// which takes a Key and Type
798
TypeId t = TypeId(object->typeId());
799
if ( object->tag() == 0x9286
800
&& object->group() == Group::exif
801
&& object->typeId() == undefined) {
804
Value::AutoPtr v = Value::create(t);
775
806
v->read(object->pData(), object->size(), byteOrder());
776
807
object->pValue_ = v.release();