Merge pull request #618 from piponazo/fix597

Fix #597
v0.27.3
Luis Díaz Más 7 years ago committed by GitHub
commit a11e198e64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -113,6 +113,8 @@ namespace Exiv2
void doWriteMetadata(BasicIo& oIo);
//@}
std::string profileName_;
}; // class PngImage
// *****************************************************************************

@ -23,7 +23,6 @@
*/
// *****************************************************************************
// #define DEBUG
// included header files
#include "config.h"
@ -43,8 +42,7 @@
#include <cstring>
#include <iostream>
#include <cassert>
// #define DEBUG
#include <cstdio>
// JPEG-2000 box types
const uint32_t kJp2BoxTypeJp2Header = 0x6a703268; // 'jp2h'

@ -215,9 +215,7 @@ namespace Exiv2 {
if (io_->open() != 0) {
throw Error(kerDataSourceOpenFailed, io_->path(), strError());
}
// Ensure that this is the correct image type
if (!isPngType(*io_, true)) {
if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
throw Error(kerNotAnImage, "PNG");
}
@ -391,6 +389,20 @@ namespace Exiv2 {
}
}
void readChunk(DataBuf& buffer, BasicIo& io)
{
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Position: " << io.tell() << std::endl;
#endif
long bufRead = io.read(buffer.pData_, buffer.size_);
if (io.error()) {
throw Error(kerFailedToReadImageData);
}
if (bufRead != buffer.size_) {
throw Error(kerInputDataReadFailed);
}
}
void PngImage::readMetadata()
{
#ifdef DEBUG
@ -401,127 +413,85 @@ namespace Exiv2 {
throw Error(kerDataSourceOpenFailed, io_->path(), strError());
}
IoCloser closer(*io_);
// Ensure that this is the correct image type
if (!isPngType(*io_, true))
{
if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
if (!isPngType(*io_, true)) {
throw Error(kerNotAnImage, "PNG");
}
clearMetadata();
const long imgSize = (long) io_->size();
DataBuf cheaderBuf(8); // Chunk header size : 4 bytes (data size) + 4 bytes (chunk type).
DataBuf cheaderBuf(8); // Chunk header: 4 bytes (data size) + 4 bytes (chunk type).
while(!io_->eof())
{
// Read chunk header.
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Position: " << io_->tell() << std::endl;
#endif
std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_);
long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_);
if (io_->error()) {
throw Error(kerFailedToReadImageData);
}
if (bufRead != cheaderBuf.size_) {
throw Error(kerInputDataReadFailed);
}
readChunk(cheaderBuf, *io_); // Read chunk header.
// Decode chunk data length.
uint32_t dataOffset = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian);
uint32_t chunkLength = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian);
long pos = io_->tell();
if (pos == -1 ||
dataOffset > uint32_t(0x7FFFFFFF) ||
static_cast<long>(dataOffset) > imgSize - pos) {
chunkLength > uint32_t(0x7FFFFFFF) ||
static_cast<long>(chunkLength) > imgSize - pos) {
throw Exiv2::Error(kerFailedToReadImageData);
}
std::string chunkType(reinterpret_cast<char *>(cheaderBuf.pData_) + 4, 4);
#ifdef DEBUG
std::string chunkName(reinterpret_cast<char *>(cheaderBuf.pData_) + 4, 4);
std::cout << "Exiv2::PngImage::readMetadata: chunk name: " << chunkName << std::endl;
std::cout << "Exiv2::PngImage::readMetadata: chunk type: " << chunkType
<< " length: " << chunkLength << std::endl;
#endif
/// \todo analyse remaining chunks of the standard
// Perform a chunk triage for item that we need.
if (!memcmp(cheaderBuf.pData_ + 4, "IEND", 4) ||
!memcmp(cheaderBuf.pData_ + 4, "IHDR", 4) ||
!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4) ||
!memcmp(cheaderBuf.pData_ + 4, "zTXt", 4) ||
!memcmp(cheaderBuf.pData_ + 4, "iTXt", 4) ||
!memcmp(cheaderBuf.pData_ + 4, "iCCP", 4))
{
// Extract chunk data.
DataBuf cdataBuf(dataOffset);
bufRead = io_->read(cdataBuf.pData_, dataOffset);
if (io_->error()) {
throw Error(kerFailedToReadImageData);
}
if (bufRead != (long)dataOffset) {
throw Error(kerInputDataReadFailed);
}
if (!memcmp(cheaderBuf.pData_ + 4, "IEND", 4))
{
// Last chunk found: we stop parsing.
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Found IEND chunk with length: " << dataOffset << std::endl;
#endif
return;
}
else if (!memcmp(cheaderBuf.pData_ + 4, "IHDR", 4))
{
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Found IHDR chunk with length: " << dataOffset << std::endl;
#endif
if (cdataBuf.size_ >= 8) {
PngChunk::decodeIHDRChunk(cdataBuf, &pixelWidth_, &pixelHeight_);
if (chunkType == "IEND" || chunkType == "IHDR" || chunkType == "tEXt" || chunkType == "zTXt" ||
chunkType == "iTXt" || chunkType == "iCCP") {
DataBuf chunkData(chunkLength);
readChunk(chunkData, *io_); // Extract chunk data.
if (chunkType == "IEND") {
return; // Last chunk found: we stop parsing.
} else if (chunkType == "IHDR" && chunkData.size_ >= 8) {
PngChunk::decodeIHDRChunk(chunkData, &pixelWidth_, &pixelHeight_);
} else if (chunkType == "tEXt") {
PngChunk::decodeTXTChunk(this, chunkData, PngChunk::tEXt_Chunk);
} else if (chunkType == "zTXt") {
PngChunk::decodeTXTChunk(this, chunkData, PngChunk::zTXt_Chunk);
} else if (chunkType == "iTXt") {
PngChunk::decodeTXTChunk(this, chunkData, PngChunk::iTXt_Chunk);
} else if (chunkType == "iCCP") {
// The ICC profile name can vary from 1-79 characters.
uint32_t iccOffset = 0;
while (iccOffset < 80 && iccOffset < chunkLength) {
if (chunkData.pData_[iccOffset++] == 0x00) {
break;
}
}
}
else if (!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4))
{
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Found tEXt chunk with length: " << dataOffset << std::endl;
#endif
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::tEXt_Chunk);
}
else if (!memcmp(cheaderBuf.pData_ + 4, "zTXt", 4))
{
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Found zTXt chunk with length: " << dataOffset << std::endl;
#endif
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::zTXt_Chunk);
}
else if (!memcmp(cheaderBuf.pData_ + 4, "iTXt", 4))
{
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Found iTXt chunk with length: " << dataOffset << std::endl;
#endif
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::iTXt_Chunk);
}
else if (!memcmp(cheaderBuf.pData_ + 4, "iCCP", 4))
{
zlibToDataBuf(cdataBuf.pData_ +12+1,dataOffset-13,iccProfile_); // +1 = 'compressed' flag
profileName_ = std::string(reinterpret_cast<char *>(chunkData.pData_), iccOffset-1);
++iccOffset; // +1 = 'compressed' flag
zlibToDataBuf(chunkData.pData_ + iccOffset, chunkLength - iccOffset, iccProfile_);
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Found iCCP chunk length: " << dataOffset << std::endl;
std::cout << "Exiv2::PngImage::readMetadata: iccProfile.size_ : " << iccProfile_.size_ << std::endl;
std::cout << "Exiv2::PngImage::readMetadata: profile name: " << profileName_ << std::endl;
std::cout << "Exiv2::PngImage::readMetadata: iccProfile.size_ (uncompressed) : "
<< iccProfile_.size_ << std::endl;
#endif
}
// Set dataOffset to null like chunk data have been extracted previously.
dataOffset = 0;
// Set chunkLength to 0 in case we have read a supported chunk type. Otherwise, we need to seek the
// file to the next chunk position.
chunkLength = 0;
}
// Move to the next chunk: chunk data size + 4 CRC bytes.
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Seek to offset: " << dataOffset + 4 << std::endl;
std::cout << "Exiv2::PngImage::readMetadata: Seek to offset: " << chunkLength + 4 << std::endl;
#endif
io_->seek(dataOffset + 4 , BasicIo::cur);
io_->seek(chunkLength + 4 , BasicIo::cur);
if (io_->error() || io_->eof()) {
throw Error(kerFailedToReadImageData);
}
}
} // PngImage::readMetadata
void PngImage::writeMetadata()
@ -550,10 +520,7 @@ namespace Exiv2 {
std::cout << "Exiv2::PngImage::doWriteMetadata: tmp file created " << outIo.path() << "\n";
#endif
// Ensure that this is the correct image type
if (!isPngType(*io_, true))
{
if (io_->error() || io_->eof()) throw Error(kerInputDataReadFailed);
if (!isPngType(*io_, true)) {
throw Error(kerNoImageInInputData);
}
@ -652,24 +619,26 @@ namespace Exiv2 {
DataBuf compressed;
if ( zlibToCompressed(iccProfile_.pData_,iccProfile_.size_,compressed) ) {
const byte* header = (const byte*) "ICC PROFILE\0\0" ; // \0 = default compression
const byte* nullComp = (const byte*) "\0\0";
const byte* type = (const byte*) "iCCP";
uint32_t headerLen = 13 ;
uint32_t typeLen = 4;
uint32_t chunkLength = headerLen + compressed.size_ ;
const uint32_t nameLength = static_cast<uint32_t>(profileName_.size());
const uint32_t chunkLength = nameLength + 2 + compressed.size_ ;
byte length[4];
ul2Data (length,chunkLength,bigEndian);
// calculate CRC
uLong tmp = crc32(0L, Z_NULL, 0);
tmp = crc32(tmp, (const Bytef*)header ,headerLen);
tmp = crc32(tmp, (const Bytef*)type, 4);
tmp = crc32(tmp, (const Bytef*)profileName_.data(), nameLength);
tmp = crc32(tmp, (const Bytef*)nullComp, 2);
tmp = crc32(tmp, (const Bytef*)compressed.pData_,compressed.size_);
byte crc[4];
ul2Data(crc, tmp, bigEndian);
if( outIo.write(length,4) != 4
|| outIo.write(type ,typeLen) != (long) typeLen
|| outIo.write(header,headerLen) != (long) headerLen
if( outIo.write(length, 4) != 4
|| outIo.write(type, 4) != 4
|| outIo.write(reinterpret_cast<const byte*>(profileName_.data()), nameLength) != nameLength
|| outIo.write(nullComp,2) != 2
|| outIo.write (compressed.pData_,compressed.size_) != compressed.size_
|| outIo.write(crc,4) != 4
){
@ -677,7 +646,7 @@ namespace Exiv2 {
}
#ifdef DEBUG
std::cout << "Exiv2::PngImage::doWriteMetadata: build iCCP"
<< " chunk (length: " << compressed.size_ + headerLen << ")" << std::endl;
<< " chunk (length: " << compressed.size_ + chunkLength << ")" << std::endl;
#endif
}
}
@ -754,6 +723,9 @@ namespace Exiv2 {
bool isPngType(BasicIo& iIo, bool advance)
{
if (iIo.error() || iIo.eof()) {
throw Error(kerInputDataReadFailed);
}
const int32_t len = 8;
byte buf[len];
iIo.read(buf, len);

@ -310,7 +310,7 @@ STRUCTURE OF PNG FILE: ReaganLargePng.png
33 | iTXt | 31 | Description.....x.KLJNIMK..... | 0xc1fefec8
76 | zTXt | 8461 | Raw profile type exif..x...iv. | 0x91fbf6a0
8549 | zTXt | 636 | Raw profile type iptc..x..TKn. | 0x4e5178d3
9197 | iCCP | 1159185 | ICC PROFILE..x...uP.[..9@.HB.D | 0x4a90a7d7
9197 | iCCP | 1159185 | ICC profile..x...uP.[..9@.HB.D | 0xd3dbe519
1168394 | iTXt | 7156 | XML:com.adobe.xmp.....<?xpacke | 0x8d6d70ba
1175562 | gAMA | 4 | .... | 0x0bfc6105
1175578 | bKGD | 6 | ...... | 0xa0bda793
@ -329,7 +329,7 @@ STRUCTURE OF PNG FILE: ReaganLargePng.png
8 | IHDR | 13 | ............ | 0x8cf910c3
33 | zTXt | 8461 | Raw profile type exif..x...iv. | 0x91fbf6a0
8506 | zTXt | 636 | Raw profile type iptc..x..TKn. | 0x4e5178d3
9154 | iCCP | 1159185 | ICC PROFILE..x...uP.[..9@.HB.D | 0x4a90a7d7
9154 | iCCP | 1159185 | ICC profile..x...uP.[..9@.HB.D | 0xd3dbe519
1168351 | iTXt | 7156 | XML:com.adobe.xmp.....<?xpacke | 0x8d6d70ba
1175519 | gAMA | 4 | .... | 0x0bfc6105
1175535 | bKGD | 6 | ...... | 0xa0bda793
@ -347,7 +347,7 @@ STRUCTURE OF PNG FILE: ReaganLargePng.png
8 | IHDR | 13 | ............ | 0x8cf910c3
33 | zTXt | 8461 | Raw profile type exif..x...iv. | 0x91fbf6a0
8506 | zTXt | 636 | Raw profile type iptc..x..TKn. | 0x4e5178d3
9154 | iCCP | 1159185 | ICC PROFILE..x...uP.[..9@.HB.D | 0x4a90a7d7
9154 | iCCP | 1159185 | ICC profile..x...uP.[..9@.HB.D | 0xd3dbe519
1168351 | iTXt | 7156 | XML:com.adobe.xmp.....<?xpacke | 0x8d6d70ba
1175519 | gAMA | 4 | .... | 0x0bfc6105
1175535 | bKGD | 6 | ...... | 0xa0bda793
@ -366,7 +366,7 @@ STRUCTURE OF PNG FILE: ReaganLargePng.png
33 | iTXt | 31 | Description.....x.KLJNIMK..... | 0xc1fefec8
76 | zTXt | 8461 | Raw profile type exif..x...iv. | 0x91fbf6a0
8549 | zTXt | 636 | Raw profile type iptc..x..TKn. | 0x4e5178d3
9197 | iCCP | 1159185 | ICC PROFILE..x...uP.[..9@.HB.D | 0x4a90a7d7
9197 | iCCP | 1159185 | ICC profile..x...uP.[..9@.HB.D | 0xd3dbe519
1168394 | iTXt | 7156 | XML:com.adobe.xmp.....<?xpacke | 0x8d6d70ba
1175562 | gAMA | 4 | .... | 0x0bfc6105
1175578 | bKGD | 6 | ...... | 0xa0bda793
@ -385,7 +385,7 @@ STRUCTURE OF PNG FILE: ReaganLargePng.png
8 | IHDR | 13 | ............ | 0x8cf910c3
33 | zTXt | 8461 | Raw profile type exif..x...iv. | 0x91fbf6a0
8506 | zTXt | 636 | Raw profile type iptc..x..TKn. | 0x4e5178d3
9154 | iCCP | 1159185 | ICC PROFILE..x...uP.[..9@.HB.D | 0x4a90a7d7
9154 | iCCP | 1159185 | ICC profile..x...uP.[..9@.HB.D | 0xd3dbe519
1168351 | iTXt | 7156 | XML:com.adobe.xmp.....<?xpacke | 0x8d6d70ba
1175519 | gAMA | 4 | .... | 0x0bfc6105
1175535 | bKGD | 6 | ...... | 0xa0bda793
@ -403,7 +403,7 @@ STRUCTURE OF PNG FILE: ReaganLargePng.png
8 | IHDR | 13 | ............ | 0x8cf910c3
33 | zTXt | 8461 | Raw profile type exif..x...iv. | 0x91fbf6a0
8506 | zTXt | 636 | Raw profile type iptc..x..TKn. | 0x4e5178d3
9154 | iCCP | 293 | ICC PROFILE..x.c``2ptqre.``..+ | 0x5116d227
9154 | iCCP | 293 | ICC profile..x.c``2ptqre.``..+ | 0x7d41600b
9459 | iTXt | 7156 | XML:com.adobe.xmp.....<?xpacke | 0x8d6d70ba
16627 | gAMA | 4 | .... | 0x0bfc6105
16643 | bKGD | 6 | ...... | 0xa0bda793
@ -422,7 +422,7 @@ STRUCTURE OF PNG FILE: ReaganLargePng.png
33 | iTXt | 31 | Description.....x.KLJNIMK..... | 0xc1fefec8
76 | zTXt | 8461 | Raw profile type exif..x...iv. | 0x91fbf6a0
8549 | zTXt | 636 | Raw profile type iptc..x..TKn. | 0x4e5178d3
9197 | iCCP | 293 | ICC PROFILE..x.c``2ptqre.``..+ | 0x5116d227
9197 | iCCP | 293 | ICC profile..x.c``2ptqre.``..+ | 0x7d41600b
9502 | iTXt | 7156 | XML:com.adobe.xmp.....<?xpacke | 0x8d6d70ba
16670 | gAMA | 4 | .... | 0x0bfc6105
16686 | bKGD | 6 | ...... | 0xa0bda793
@ -441,7 +441,7 @@ STRUCTURE OF PNG FILE: ReaganLargePng.png
8 | IHDR | 13 | ............ | 0x8cf910c3
33 | zTXt | 8461 | Raw profile type exif..x...iv. | 0x91fbf6a0
8506 | zTXt | 636 | Raw profile type iptc..x..TKn. | 0x4e5178d3
9154 | iCCP | 293 | ICC PROFILE..x.c``2ptqre.``..+ | 0x5116d227
9154 | iCCP | 293 | ICC profile..x.c``2ptqre.``..+ | 0x7d41600b
9459 | iTXt | 7156 | XML:com.adobe.xmp.....<?xpacke | 0x8d6d70ba
16627 | gAMA | 4 | .... | 0x0bfc6105
16643 | bKGD | 6 | ...... | 0xa0bda793

Loading…
Cancel
Save