Added check for JPEG APP segments >64k, removed 16bit size limitation for IRBs. Fixes bug #480.

v0.27.3
Andreas Huggel 19 years ago
parent 8db4ded68c
commit 900adcd5a8

@ -110,6 +110,7 @@ BINSRC = addmoddel.cpp \
iptcprint.cpp \ iptcprint.cpp \
iptctest.cpp \ iptctest.cpp \
key-test.cpp \ key-test.cpp \
largeiptc-test.cpp \
makernote-test.cpp \ makernote-test.cpp \
taglist.cpp \ taglist.cpp \
write-test.cpp \ write-test.cpp \

@ -78,6 +78,7 @@ namespace Exiv2 {
ErrMsg( 34, "%1: Not supported"), // %1=function ErrMsg( 34, "%1: Not supported"), // %1=function
ErrMsg( 35, "ImageFactory registry full"), ErrMsg( 35, "ImageFactory registry full"),
ErrMsg( 36, "Failed to decode %1 metadata"), // %1=type of metadata (Exif, IPTC) ErrMsg( 36, "Failed to decode %1 metadata"), // %1=type of metadata (Exif, IPTC)
ErrMsg( 37, "Size of %1 JPEG segment is larger than 65535 bytes"), // %1=type of metadata (Exif, IPTC, JPEG comment)
// Last error message (message is not used) // Last error message (message is not used)
ErrMsg( -2, "(Unknown Error)") ErrMsg( -2, "(Unknown Error)")

@ -71,8 +71,8 @@ namespace Exiv2 {
long sizePsData, long sizePsData,
uint16_t psTag, uint16_t psTag,
const byte** record, const byte** record,
uint16_t *const sizeHdr, uint32_t *const sizeHdr,
uint16_t *const sizeData) uint32_t *const sizeData)
{ {
assert(record); assert(record);
assert(sizeHdr); assert(sizeHdr);
@ -95,12 +95,12 @@ namespace Exiv2 {
if (position >= sizePsData) return -2; if (position >= sizePsData) return -2;
// Data is also padded to be even // Data is also padded to be even
long dataSize = getULong(pPsData + position, bigEndian); uint32_t dataSize = getULong(pPsData + position, bigEndian);
position += 4; position += 4;
if (dataSize > sizePsData - position) return -2; if (dataSize > static_cast<uint32_t>(sizePsData - position)) return -2;
if (type == psTag) { if (type == psTag) {
*sizeData = static_cast<uint16_t>(dataSize); *sizeData = dataSize;
*sizeHdr = psSize + 10; *sizeHdr = psSize + 10;
*record = hrd; *record = hrd;
return 0; return 0;
@ -113,8 +113,8 @@ namespace Exiv2 {
int Photoshop::locateIptcIrb(const byte* pPsData, int Photoshop::locateIptcIrb(const byte* pPsData,
long sizePsData, long sizePsData,
const byte** record, const byte** record,
uint16_t *const sizeHdr, uint32_t *const sizeHdr,
uint16_t *const sizeData) uint32_t *const sizeData)
{ {
return locateIrb(pPsData, sizePsData, iptc_, return locateIrb(pPsData, sizePsData, iptc_,
record, sizeHdr, sizeData); record, sizeHdr, sizeData);
@ -131,17 +131,17 @@ namespace Exiv2 {
else hexdump(std::cerr, pPsData, sizePsData); else hexdump(std::cerr, pPsData, sizePsData);
#endif #endif
const byte* record = pPsData; const byte* record = pPsData;
uint16_t sizeIptc = 0; uint32_t sizeIptc = 0;
uint16_t sizeHdr = 0; uint32_t sizeHdr = 0;
// Safe to call with zero psData.size_ // Safe to call with zero psData.size_
Photoshop::locateIptcIrb(pPsData, sizePsData, Photoshop::locateIptcIrb(pPsData, sizePsData,
&record, &sizeHdr, &sizeIptc); &record, &sizeHdr, &sizeIptc);
Blob psBlob; Blob psBlob;
// Data is rounded to be even // Data is rounded to be even
const uint16_t sizeOldData = sizeHdr + sizeIptc + (sizeIptc & 1); const uint32_t sizeOldData = sizeHdr + sizeIptc + (sizeIptc & 1);
const uint16_t sizeFront = static_cast<uint16_t>(record - pPsData); const uint32_t sizeFront = record - pPsData;
const uint16_t sizeEnd = static_cast<uint16_t>(sizePsData - sizeFront - sizeOldData); const uint32_t sizeEnd = sizePsData - sizeFront - sizeOldData;
// Write data before old record. // Write data before old record.
if (sizePsData > 0 && sizeFront > 0) { if (sizePsData > 0 && sizeFront > 0) {
@ -309,8 +309,8 @@ namespace Exiv2 {
io_->read(psData.pData_, psData.size_); io_->read(psData.pData_, psData.size_);
if (io_->error() || io_->eof()) throw Error(14); if (io_->error() || io_->eof()) throw Error(14);
const byte *record = 0; const byte *record = 0;
uint16_t sizeIptc = 0; uint32_t sizeIptc = 0;
uint16_t sizeHdr = 0; uint32_t sizeHdr = 0;
// Find actual Iptc data within the APP13 segment // Find actual Iptc data within the APP13 segment
if (!Photoshop::locateIptcIrb(psData.pData_, psData.size_, if (!Photoshop::locateIptcIrb(psData.pData_, psData.size_,
&record, &sizeHdr, &sizeIptc)) { &record, &sizeHdr, &sizeIptc)) {
@ -465,8 +465,10 @@ namespace Exiv2 {
// Write COM marker, size of comment, and string // Write COM marker, size of comment, and string
tmpBuf[0] = 0xff; tmpBuf[0] = 0xff;
tmpBuf[1] = com_; tmpBuf[1] = com_;
us2Data(tmpBuf + 2,
static_cast<uint16_t>(comment_.length()+3), bigEndian); if (comment_.length() + 3 > 0xffff) throw Error(37, "JPEG comment");
us2Data(tmpBuf + 2, static_cast<uint16_t>(comment_.length() + 3), bigEndian);
if (outIo.write(tmpBuf, 4) != 4) throw Error(21); if (outIo.write(tmpBuf, 4) != 4) throw Error(21);
if (outIo.write((byte*)comment_.data(), (long)comment_.length()) if (outIo.write((byte*)comment_.data(), (long)comment_.length())
!= (long)comment_.length()) throw Error(21); != (long)comment_.length()) throw Error(21);
@ -476,14 +478,16 @@ namespace Exiv2 {
} }
if (exifData_.count() > 0) { if (exifData_.count() > 0) {
// Write APP1 marker, size of APP1 field, Exif id and Exif data // Write APP1 marker, size of APP1 field, Exif id and Exif data
DataBuf rawExif(exifData_.copy()); DataBuf rawExif = exifData_.copy();
tmpBuf[0] = 0xff; tmpBuf[0] = 0xff;
tmpBuf[1] = app1_; tmpBuf[1] = app1_;
us2Data(tmpBuf + 2,
static_cast<uint16_t>(rawExif.size_+8), if (rawExif.size_ + 8 > 0xffff) throw Error(37, "Exif");
bigEndian); us2Data(tmpBuf + 2, static_cast<uint16_t>(rawExif.size_ + 8), bigEndian);
memcpy(tmpBuf + 4, exifId_, 6); memcpy(tmpBuf + 4, exifId_, 6);
if (outIo.write(tmpBuf, 10) != 10) throw Error(21); if (outIo.write(tmpBuf, 10) != 10) throw Error(21);
// Write new Exif data buffer
if ( outIo.write(rawExif.pData_, rawExif.size_) if ( outIo.write(rawExif.pData_, rawExif.size_)
!= rawExif.size_) throw Error(21); != rawExif.size_) throw Error(21);
if (outIo.error()) throw Error(21); if (outIo.error()) throw Error(21);
@ -499,6 +503,8 @@ namespace Exiv2 {
// Write APP13 marker, new size, and ps3Id // Write APP13 marker, new size, and ps3Id
tmpBuf[0] = 0xff; tmpBuf[0] = 0xff;
tmpBuf[1] = app13_; tmpBuf[1] = app13_;
if (newPsData.size_ + 16 > 0xffff) throw Error(37, "IPTC");
us2Data(tmpBuf + 2, static_cast<uint16_t>(newPsData.size_ + 16), bigEndian); us2Data(tmpBuf + 2, static_cast<uint16_t>(newPsData.size_ + 16), bigEndian);
memcpy(tmpBuf + 4, Photoshop::ps3Id_, 14); memcpy(tmpBuf + 4, Photoshop::ps3Id_, 14);
if (outIo.write(tmpBuf, 18) != 18) throw Error(21); if (outIo.write(tmpBuf, 18) != 18) throw Error(21);

@ -87,16 +87,16 @@ namespace Exiv2 {
long sizePsData, long sizePsData,
uint16_t psTag, uint16_t psTag,
const byte **record, const byte **record,
uint16_t *const sizeHdr, uint32_t *const sizeHdr,
uint16_t *const sizeData); uint32_t *const sizeData);
/*! /*!
@brief Forwards to locateIrb() with \em psTag = \em iptc_ @brief Forwards to locateIrb() with \em psTag = \em iptc_
*/ */
static int locateIptcIrb(const byte *pPsData, static int locateIptcIrb(const byte *pPsData,
long sizePsData, long sizePsData,
const byte **record, const byte **record,
uint16_t *const sizeHdr, uint32_t *const sizeHdr,
uint16_t *const sizeData); uint32_t *const sizeData);
/*! /*!
@brief Set the new IPTC IRB, keeps existing IRBs but removes the @brief Set the new IPTC IRB, keeps existing IRBs but removes the
IPTC block if there is no new IPTC data to write. IPTC block if there is no new IPTC data to write.

@ -0,0 +1,71 @@
// ***************************************************************** -*- C++ -*-
// Test for large (>65535 bytes) IPTC buffer
#include "iptc.hpp"
#include "image.hpp"
#include "jpgimage.hpp"
#include "futils.hpp"
#include <iostream>
#include <cassert>
int main(int argc, char* const argv[])
try {
if (argc != 3) {
std::cout << "Usage: " << argv[0] << " image datafile\n";
return 1;
}
std::string file(argv[1]);
std::string data(argv[2]);
// Read data file into data buffer
Exiv2::FileIo io(data);
if (io.open() != 0) {
throw Exiv2::Error(9, io.path(), Exiv2::strError());
}
Exiv2::DataBuf buf(io.size());
std::cout << "Reading " << buf.size_ << " bytes from " << data << "\n";
io.read(buf.pData_, buf.size_);
if (io.error() || io.eof()) throw Exiv2::Error(14);
// Read metadata from file
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file);
assert(image.get() != 0);
image->readMetadata();
// Set Preview field to the content of the data file
Exiv2::DataValue value;
value.read(buf.pData_, buf.size_);
Exiv2::IptcData& iptcData = image->iptcData();
std::cout << "IPTC fields: " << iptcData.size() << "\n";
iptcData["Iptc.Application2.Preview"] = value;
std::cout << "IPTC fields: " << iptcData.size() << "\n";
// Set IRB, compare with IPTC raw data
Exiv2::DataBuf irb = Exiv2::Photoshop::setIptcIrb(0, 0, iptcData);
std::cout << "IRB buffer : " << irb.size_ << "\n";
const Exiv2::byte* record;
uint32_t sizeHdr;
uint32_t sizeData;
Exiv2::Photoshop::locateIptcIrb(irb.pData_, irb.size_, &record, &sizeHdr, &sizeData);
Exiv2::DataBuf rawIptc = iptcData.copy();
std::cout << "Comparing IPTC and IRB size... ";
if (static_cast<uint32_t>(rawIptc.size_) != sizeData) {
std::cout << "not ";
}
std::cout << "ok\n";
std::cout << "Comparing IPTC and IRB data... ";
if (0 != memcmp(rawIptc.pData_, record + sizeHdr, sizeData)) {
std::cout << "not ";
}
std::cout << "ok\n";
// Set Iptc data and write it to the file
image->writeMetadata();
return 0;
}
catch (Exiv2::AnyError& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

@ -190,8 +190,8 @@ namespace Exiv2 {
assert(pImage_ != 0); assert(pImage_ != 0);
if (!object->pData()) return; if (!object->pData()) return;
byte const* record = 0; byte const* record = 0;
uint16_t sizeHdr = 0; uint32_t sizeHdr = 0;
uint16_t sizeData = 0; uint32_t sizeData = 0;
if (0 != Photoshop::locateIptcIrb(object->pData(), object->size(), if (0 != Photoshop::locateIptcIrb(object->pData(), object->size(),
&record, &sizeHdr, &sizeData)) { &record, &sizeHdr, &sizeData)) {
return; return;

@ -58,6 +58,10 @@ num=479
filename=`prep_file $num` filename=`prep_file $num`
$binpath/exiv2 -pt $filename $binpath/exiv2 -pt $filename
num=480
filename=`prep_file $num`
$binpath/largeiptc-test $filename ../data/smiley1.jpg.ixgd
) > $results 2>&1 ) > $results 2>&1
if [ x`which unix2dos.exe` != x ]; then if [ x`which unix2dos.exe` != x ]; then

@ -235,3 +235,11 @@ Exif.Image.0x9286 Undefined 264 (Binary value suppre
Exif.Photo.ExifVersion Undefined 4 48 50 50 48 Exif.Photo.ExifVersion Undefined 4 48 50 50 48
Exif.Photo.PixelXDimension Short 1 3173 Exif.Photo.PixelXDimension Short 1 3173
Exif.Photo.PixelYDimension Short 1 2011 Exif.Photo.PixelYDimension Short 1 2011
------> Bug 480 <-------
Reading 67070 bytes from ../data/smiley1.jpg.ixgd
IPTC fields: 0
IPTC fields: 67079
IRB buffer : 67092
Comparing IPTC and IRB size... ok
Comparing IPTC and IRB data... ok
Caught Exiv2 exception 'Size of IPTC JPEG segment is larger than 65535 bytes'

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Loading…
Cancel
Save