~ubuntu-branches/ubuntu/precise/exiv2/precise

« back to all changes in this revision

Viewing changes to src/tiffvisitor.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Mercatante
  • Date: 2006-12-07 18:40:10 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20061207184010-0ouu8v0dr8nznob9
Tags: 0.12-0ubuntu1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 */
21
21
/*
22
22
  File:      tiffvisitor.cpp
23
 
  Version:   $Rev: 808 $
 
23
  Version:   $Rev: 943 $
24
24
  Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
25
25
  History:   11-Apr-06, ahu: created
26
26
 */
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 $")
30
30
 
31
31
// *****************************************************************************
32
32
// included header files
36
36
# include "exv_conf.h"
37
37
#endif
38
38
 
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
56
57
namespace Exiv2 {
57
58
 
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    }
66
 
    };
67
 
 
68
 
    bool TiffDecoderInfo::operator==(const TiffDecoderInfo::Key& key) const
69
 
    {
70
 
        std::string make(make_);
71
 
        return    ("*" == make || make == key.m_.substr(0, make.length()))
72
 
               && (Tag::all == extendedTag_ || key.e_ == extendedTag_)
73
 
               && key.g_ == group_;
74
 
    }
75
 
 
76
59
    void TiffFinder::init(uint16_t tag, uint16_t group)
77
60
    {
78
61
        tag_ = tag;
135
118
 
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)
 
123
        : pImage_(pImage), 
 
124
          pRoot_(pRoot),
 
125
          findDecoderFct_(findDecoderFct),
 
126
          threshold_(threshold)
140
127
    {
141
128
        // Find camera make
142
129
        TiffFinder finder(0x010f, Group::ifd0);
162
149
        decodeTiffEntry(object);
163
150
    }
164
151
 
165
 
    void TiffMetadataDecoder::visitDirectory(TiffDirectory* object)
 
152
    void TiffMetadataDecoder::visitDirectory(TiffDirectory* /*object*/)
166
153
    {
167
154
        // Nothing to do
168
155
    }
177
164
        if (!object->mn_) decodeTiffEntry(object);
178
165
    }
179
166
 
180
 
    void TiffMetadataDecoder::visitIfdMakernote(TiffIfdMakernote* object)
 
167
    void TiffMetadataDecoder::visitIfdMakernote(TiffIfdMakernote* /*object*/)
181
168
    {
182
169
        // Nothing to do
183
170
    }
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)) {
210
197
            return;
252
239
            groupType_[object->group()] = object->pValue()->toLong();
253
240
        }
254
241
 
255
 
        const TiffDecoderInfo* td = find(tiffDecoderInfo_,
256
 
            TiffDecoderInfo::Key(make_, object->tag(), object->group()));
257
 
        if (td) {
258
 
            // skip decoding if td->decoderFct_ == 0
259
 
            if (td->decoderFct_) {
260
 
                EXV_CALL_MEMBER_FN(*this, td->decoderFct_)(object);
261
 
            }
262
 
            return;
 
242
        const DecoderFct decoderFct = findDecoderFct_(make_, 
 
243
                                                      object->tag(),
 
244
                                                      object->group());
 
245
        // skip decoding if decoderFct == 0
 
246
        if (decoderFct) {
 
247
            EXV_CALL_MEMBER_FN(*this, decoderFct)(object);
263
248
        }
 
249
    } // TiffMetadataDecoder::decodeTiffEntry
 
250
 
 
251
    void TiffMetadataDecoder::decodeStdTiffEntry(const TiffEntryBase* object)
 
252
    {
 
253
        assert(object !=0);
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
293
283
 
294
284
    } // TiffMetadataDecoder::addExifTag
295
285
 
296
 
    void TiffMetadataDecoder::visitArrayEntry(TiffArrayEntry* object)
 
286
    void TiffMetadataDecoder::visitArrayEntry(TiffArrayEntry* /*object*/)
297
287
    {
298
288
        // Nothing to do
299
289
    }
359
349
        }
360
350
    } // TiffPrinter::visitDirectoryNext
361
351
 
362
 
    void TiffPrinter::visitDirectoryEnd(TiffDirectory* object)
 
352
    void TiffPrinter::visitDirectoryEnd(TiffDirectory* /*object*/)
363
353
    {
364
354
        // Nothing to do
365
355
    } // TiffPrinter::visitDirectoryEnd
376
366
        else os_ << prefix() << "Makernote ";
377
367
    } // TiffPrinter::visitMnEntry
378
368
 
379
 
    void TiffPrinter::visitIfdMakernote(TiffIfdMakernote* object)
 
369
    void TiffPrinter::visitIfdMakernote(TiffIfdMakernote* /*object*/)
380
370
    {
381
371
        // Nothing to do
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);
500
 
            }
501
 
#ifndef SUPPRESS_WARNINGS
502
 
            else {
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";
508
 
            }
509
 
#endif
 
486
            setDataArea(object, te->pValue());
510
487
        }
511
 
 
512
488
    }
513
489
 
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);
527
 
            }
528
 
#ifndef SUPPRESS_WARNINGS
529
 
            else {
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";
535
 
            }
536
 
#endif
537
 
        }
538
 
 
 
499
            setDataArea(te, object->pValue());
 
500
        }
 
501
    }
 
502
 
 
503
    void TiffReader::setDataArea(TiffEntryBase* pOffsetEntry, const Value* pSize)
 
504
    {
 
505
        assert(pOffsetEntry);
 
506
        assert(pSize);
 
507
 
 
508
        Value* pOffset = pOffsetEntry->pValue_;
 
509
        assert(pOffset);
 
510
 
 
511
        long size = 0;
 
512
        for (long i = 0; i < pSize->count(); ++i) {
 
513
            size += pSize->toLong(i);
 
514
        }
 
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)
 
520
            - offset != size) {
 
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";
 
527
#endif
 
528
            return;
 
529
        }
 
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";
 
537
#endif
 
538
            return;
 
539
        }
 
540
        pOffset->setDataArea(pData_ + baseOffset() + offset, size);
539
541
    }
540
542
 
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";
553
555
#endif
554
556
            return;
555
557
        }
556
558
        const uint16_t n = getUShort(p, byteOrder());
557
559
        p += 2;
 
560
        // Sanity check with an "unreasonably" large number
 
561
        if (n > 256) {
 
562
#ifndef SUPPRESS_WARNINGS
 
563
            std::cerr << "Error: " 
 
564
                      << "Directory " << object->groupName() << " with " 
 
565
                      << n << " entries considered invalid; not read.\n";
 
566
#endif
 
567
            return;
 
568
        }
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";
565
576
#endif
566
577
                return;
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";
581
592
#endif
582
593
                return;
583
594
        }
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";
603
614
#endif
604
615
                    return;
605
616
                }
701
712
 
702
713
    } // TiffReader::visitIfdMakernote
703
714
 
704
 
    void TiffReader::visitIfdMakernoteEnd(TiffIfdMakernote* object)
 
715
    void TiffReader::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/)
705
716
    {
706
717
        // Reset state (byte order, create function, offset) back to that
707
718
        // for the image
726
737
        // Component already has tag
727
738
        p += 2;
728
739
        object->type_ = getUShort(p, byteOrder());
729
 
        // todo: check type
 
740
        long typeSize = TypeInfo::typeSize(object->typeId());
 
741
        if (0 == typeSize) {
 
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";
 
749
#endif
 
750
            return;
 
751
        }
730
752
        p += 2;
731
753
        object->count_ = getULong(p, byteOrder());
732
754
        p += 4;
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)
751
773
                return;
752
774
            }
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
771
793
            }
772
794
        }
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) {
 
802
            t = comment;
 
803
        }
 
804
        Value::AutoPtr v = Value::create(t);
774
805
        if (v.get()) {
775
806
            v->read(object->pData(), object->size(), byteOrder());
776
807
            object->pValue_ = v.release();