diff --git a/src/exif.cpp b/src/exif.cpp index fd0780a7..4040e204 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -255,7 +255,7 @@ namespace Exiv2 { } return 0; - } // TiffThumbnail::read + } // TiffThumbnail::setDataArea const char* TiffThumbnail::format() const { @@ -478,104 +478,123 @@ namespace Exiv2 { pIfd0_ = new Ifd(ifd0Id, 0, false); assert(pIfd0_ != 0); rc = pIfd0_->read(pData_, size_, pTiffHeader_->offset(), byteOrder()); - if (rc) return rc; + if (rc) return rc; // no point to continue if there is no IFD0 delete pExifIfd_; - pExifIfd_ = new Ifd(exifIfdId, 0, false); - assert(pExifIfd_ != 0); + pExifIfd_ = 0; + std::auto_ptr tmpExif(new Ifd(exifIfdId, 0, false)); + assert(tmpExif.get() != 0); // Find and read ExifIFD sub-IFD of IFD0 - rc = pIfd0_->readSubIfd(*pExifIfd_, pData_, size_, byteOrder(), 0x8769); - if (rc) return rc; - // Find MakerNote in ExifIFD, create a MakerNote class - Ifd::iterator pos = pExifIfd_->findTag(0x927c); - Ifd::iterator make = pIfd0_->findTag(0x010f); - Ifd::iterator model = pIfd0_->findTag(0x0110); - if ( pos != pExifIfd_->end() - && make != pIfd0_->end() && model != pIfd0_->end()) { - // Todo: The conversion to string assumes that there is a \0 at the end - // Todo: How to avoid the cast (is that a MSVC thing?) - pMakerNote_ = MakerNoteFactory::create( - reinterpret_cast(make->data()), - reinterpret_cast(model->data()), - false, - pos->data(), - pos->size(), - byteOrder(), - pExifIfd_->offset() + pos->offset()).release(); - } - // Read the MakerNote - if (pMakerNote_) { - rc = pMakerNote_->read(pData_, size_, - pExifIfd_->offset() + pos->offset(), - byteOrder()); - if (rc) { + rc = pIfd0_->readSubIfd(*tmpExif, pData_, size_, byteOrder(), 0x8769); + if (0 == rc) { + pExifIfd_ = tmpExif.release(); + } + if (pExifIfd_) { + // Find MakerNote in ExifIFD, create a MakerNote class + Ifd::iterator pos = pExifIfd_->findTag(0x927c); + Ifd::iterator make = pIfd0_->findTag(0x010f); + Ifd::iterator model = pIfd0_->findTag(0x0110); + delete pMakerNote_; + pMakerNote_ = 0; + MakerNote::AutoPtr tmpMakerNote; + if ( pos != pExifIfd_->end() + && make != pIfd0_->end() && model != pIfd0_->end()) { + // Todo: The conversion to string assumes that there is a \0 at the end + // Todo: How to avoid the cast (is that a MSVC thing?) + tmpMakerNote = MakerNoteFactory::create( + reinterpret_cast(make->data()), + reinterpret_cast(model->data()), + false, + pos->data(), + pos->size(), + byteOrder(), + pExifIfd_->offset() + pos->offset()); + } + // Read the MakerNote + if (tmpMakerNote.get() != 0) { + rc = tmpMakerNote->read(pData_, size_, + pExifIfd_->offset() + pos->offset(), + byteOrder()); + if (0 == rc) { + pMakerNote_ = tmpMakerNote.release(); + } + else { #ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: Failed to read Makernote, rc = " - << rc << "\n"; + std::cerr << "Warning: Failed to read Makernote, rc = " + << rc << "\n"; #endif - delete pMakerNote_; - pMakerNote_ = 0; + } + } + // If we successfully parsed the MakerNote, delete the raw MakerNote, + // the parsed MakerNote is the primary MakerNote from now on + if (pMakerNote_) { + pExifIfd_->erase(pos); } - } - // If we successfully parsed the MakerNote, delete the raw MakerNote, - // the parsed MakerNote is the primary MakerNote from now on - if (pMakerNote_) { - pExifIfd_->erase(pos); - } - delete pIopIfd_; - pIopIfd_ = new Ifd(iopIfdId, 0, false); - assert(pIopIfd_ != 0); - // Find and read Interoperability IFD in ExifIFD - rc = pExifIfd_->readSubIfd(*pIopIfd_, pData_, size_, byteOrder(), 0xa005); - if (rc) return rc; + delete pIopIfd_; + pIopIfd_ = 0; + std::auto_ptr tmpIop(new Ifd(iopIfdId, 0, false)); + assert(tmpIop.get() != 0); + // Find and read Interoperability IFD in ExifIFD + rc = pExifIfd_->readSubIfd(*tmpIop, pData_, size_, byteOrder(), 0xa005); + if (0 == rc) { + pIopIfd_ = tmpIop.release(); + } + } // if (pExifIfd_) delete pGpsIfd_; - pGpsIfd_ = new Ifd(gpsIfdId, 0, false); - assert(pGpsIfd_ != 0); + pGpsIfd_ = 0; + std::auto_ptr tmpGps(new Ifd(gpsIfdId, 0, false)); + assert(tmpGps.get() != 0); // Find and read GPSInfo sub-IFD in IFD0 - rc = pIfd0_->readSubIfd(*pGpsIfd_, pData_, size_, byteOrder(), 0x8825); - if (rc) return rc; + rc = pIfd0_->readSubIfd(*tmpGps, pData_, size_, byteOrder(), 0x8825); + if (0 == rc) { + pGpsIfd_ = tmpGps.release(); + } delete pIfd1_; - pIfd1_ = new Ifd(ifd1Id, 0, false); - assert(pIfd1_ != 0); + pIfd1_ = 0; + std::auto_ptr tmpIfd1(new Ifd(ifd1Id, 0, false)); + assert(tmpIfd1.get() != 0); // Read IFD1 if (pIfd0_->next()) { - rc = pIfd1_->read(pData_, size_, pIfd0_->next(), byteOrder()); - if (rc) return rc; - } - // Find and delete ExifIFD sub-IFD of IFD1 - pos = pIfd1_->findTag(0x8769); - if (pos != pIfd1_->end()) { - pIfd1_->erase(pos); - rc = 7; + rc = tmpIfd1->read(pData_, size_, pIfd0_->next(), byteOrder()); + if (0 == rc) { + pIfd1_ = tmpIfd1.release(); + } } - // Find and delete GPSInfo sub-IFD in IFD1 - pos = pIfd1_->findTag(0x8825); - if (pos != pIfd1_->end()) { - pIfd1_->erase(pos); - rc = 7; + if (pIfd1_) { + // Find and delete ExifIFD sub-IFD of IFD1 + Ifd::iterator pos = pIfd1_->findTag(0x8769); + if (pos != pIfd1_->end()) { + pIfd1_->erase(pos); + rc = 7; + } + // Find and delete GPSInfo sub-IFD in IFD1 + pos = pIfd1_->findTag(0x8825); + if (pos != pIfd1_->end()) { + pIfd1_->erase(pos); + rc = 7; + } } // Copy all entries from the IFDs and the MakerNote to the metadata exifMetadata_.clear(); add(pIfd0_->begin(), pIfd0_->end(), byteOrder()); - add(pExifIfd_->begin(), pExifIfd_->end(), byteOrder()); + if (pExifIfd_) add(pExifIfd_->begin(), pExifIfd_->end(), byteOrder()); if (pMakerNote_) { add(pMakerNote_->begin(), pMakerNote_->end(), (pMakerNote_->byteOrder() == invalidByteOrder ? byteOrder() : pMakerNote_->byteOrder())); } - add(pIopIfd_->begin(), pIopIfd_->end(), byteOrder()); - add(pGpsIfd_->begin(), pGpsIfd_->end(), byteOrder()); - add(pIfd1_->begin(), pIfd1_->end(), byteOrder()); + if (pIopIfd_) add(pIopIfd_->begin(), pIopIfd_->end(), byteOrder()); + if (pGpsIfd_) add(pGpsIfd_->begin(), pGpsIfd_->end(), byteOrder()); + if (pIfd1_) add(pIfd1_->begin(), pIfd1_->end(), byteOrder()); // Read the thumbnail (but don't worry whether it was successful or not) readThumbnail(); return rc; } // ExifData::load - DataBuf ExifData::copy() { DataBuf buf; @@ -861,8 +880,7 @@ namespace Exiv2 { bool ExifData::stdThumbPosition() const { - if ( pIfd0_ == 0 || pExifIfd_ == 0 || pIopIfd_ == 0 - || pGpsIfd_ == 0 || pIfd1_ == 0) return true; + if (pIfd1_ == 0) return true; // Todo: There is still an invalid assumption here: The data of an IFD // can be stored in multiple non-contiguous blocks. In this case, @@ -874,20 +892,25 @@ namespace Exiv2 { if (thumbnail.get()) { long maxOffset; maxOffset = std::max(pIfd0_->offset(), pIfd0_->dataOffset()); - maxOffset = std::max(maxOffset, pExifIfd_->offset()); - maxOffset = std::max(maxOffset, pExifIfd_->dataOffset() - + pExifIfd_->dataSize()); + if (pExifIfd_) { + maxOffset = std::max(maxOffset, pExifIfd_->offset()); + maxOffset = std::max(maxOffset, pExifIfd_->dataOffset() + + pExifIfd_->dataSize()); + } if (pMakerNote_) { maxOffset = std::max(maxOffset, pMakerNote_->offset() + pMakerNote_->size()); } - maxOffset = std::max(maxOffset, pIopIfd_->offset()); - maxOffset = std::max(maxOffset, pIopIfd_->dataOffset() - + pIopIfd_->dataSize()); - maxOffset = std::max(maxOffset, pGpsIfd_->offset()); - maxOffset = std::max(maxOffset, pGpsIfd_->dataOffset() - + pGpsIfd_->dataSize()); - + if (pIopIfd_) { + maxOffset = std::max(maxOffset, pIopIfd_->offset()); + maxOffset = std::max(maxOffset, pIopIfd_->dataOffset() + + pIopIfd_->dataSize()); + } + if (pGpsIfd_) { + maxOffset = std::max(maxOffset, pGpsIfd_->offset()); + maxOffset = std::max(maxOffset, pGpsIfd_->dataOffset() + + pGpsIfd_->dataSize()); + } if ( maxOffset > pIfd1_->offset() || maxOffset > pIfd1_->dataOffset() && pIfd1_->dataOffset() > 0) rc = false; @@ -975,8 +998,9 @@ namespace Exiv2 { bool ExifData::updateEntries() { - if ( pIfd0_ == 0 || pExifIfd_ == 0 || pIopIfd_ == 0 - || pGpsIfd_ == 0 || pIfd1_ == 0) return false; + if (pIfd0_ == 0 || pExifIfd_ == 0 || pIopIfd_ == 0 || pGpsIfd_ == 0) { + return false; + } if (!this->compatible()) return false; bool compatible = true; @@ -990,8 +1014,9 @@ namespace Exiv2 { } compatible &= updateRange(pIopIfd_->begin(), pIopIfd_->end(), byteOrder()); compatible &= updateRange(pGpsIfd_->begin(), pGpsIfd_->end(), byteOrder()); - compatible &= updateRange(pIfd1_->begin(), pIfd1_->end(), byteOrder()); - + if (pIfd1_) { + compatible &= updateRange(pIfd1_->begin(), pIfd1_->end(), byteOrder()); + } return compatible; } // ExifData::updateEntries