From 11993b3b5520cc3aa5c63e6c4bc2e13f3f3980f4 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Wed, 15 Mar 2017 21:30:55 +0000 Subject: [PATCH] #1271 Thanks to Ben for reporting this and providing the patch. --- include/exiv2/orfimage.hpp | 1 + include/exiv2/rafimage.hpp | 1 + include/exiv2/riffvideo.hpp | 6 + include/exiv2/rw2image.hpp | 1 + src/cr2image.cpp | 2 + src/orfimage.cpp | 17 +++ src/rafimage.cpp | 214 ++++++++++++++++++++++++++++++++++-- src/riffvideo.cpp | 83 ++++++++++++++ src/rw2image.cpp | 17 +++ src/webpimage.cpp | 5 +- 10 files changed, 336 insertions(+), 11 deletions(-) diff --git a/include/exiv2/orfimage.hpp b/include/exiv2/orfimage.hpp index 1b2e1146..7d467467 100644 --- a/include/exiv2/orfimage.hpp +++ b/include/exiv2/orfimage.hpp @@ -79,6 +79,7 @@ namespace Exiv2 { //! @name Manipulators //@{ + void printStructure(std::ostream& out, PrintStructureOption option,int depth); void readMetadata(); void writeMetadata(); /*! diff --git a/include/exiv2/rafimage.hpp b/include/exiv2/rafimage.hpp index 0552386a..cf6542b9 100644 --- a/include/exiv2/rafimage.hpp +++ b/include/exiv2/rafimage.hpp @@ -78,6 +78,7 @@ namespace Exiv2 { //! @name Manipulators //@{ + void printStructure(std::ostream& out, PrintStructureOption option,int depth); void readMetadata(); /*! @brief Todo: Write metadata back to the image. This method is not diff --git a/include/exiv2/riffvideo.hpp b/include/exiv2/riffvideo.hpp index 5305011d..1eac859e 100644 --- a/include/exiv2/riffvideo.hpp +++ b/include/exiv2/riffvideo.hpp @@ -71,6 +71,7 @@ namespace Exiv2 { //! @name Manipulators //@{ + void printStructure(std::ostream& out, PrintStructureOption option,int depth); void readMetadata(); void writeMetadata(); //@} @@ -185,9 +186,14 @@ namespace Exiv2 { RiffVideo(const RiffVideo& rhs); //! Assignment operator RiffVideo& operator=(const RiffVideo& rhs); + bool equalsRiffTag(Exiv2::DataBuf& buf ,const char* str); //@} private: + const static int RIFF_TAG_SIZE; + const static char* RIFF_CHUNK_HEADER_ICCP; + const static char* RIFF_CHUNK_HEADER_EXIF; + const static char* RIFF_CHUNK_HEADER_XMP; //! Variable to check the end of metadata traversing. bool continueTraversing_; //! Variable which stores current stream being processsed. diff --git a/include/exiv2/rw2image.hpp b/include/exiv2/rw2image.hpp index 63d50b32..fe5a5dbd 100644 --- a/include/exiv2/rw2image.hpp +++ b/include/exiv2/rw2image.hpp @@ -76,6 +76,7 @@ namespace Exiv2 { //! @name Manipulators //@{ + void printStructure(std::ostream& out, PrintStructureOption option,int depth); void readMetadata(); /*! @brief Todo: Write metadata back to the image. This method is not diff --git a/src/cr2image.cpp b/src/cr2image.cpp index b6fa3150..2907426c 100644 --- a/src/cr2image.cpp +++ b/src/cr2image.cpp @@ -107,6 +107,8 @@ namespace Exiv2 { throw Error(3, "CR2"); } clearMetadata(); + std::ofstream devnull; + printStructure(devnull, kpsRecursive, 0); ByteOrder bo = Cr2Parser::decode(exifData_, iptcData_, xmpData_, diff --git a/src/orfimage.cpp b/src/orfimage.cpp index 3f5a424a..c5165911 100644 --- a/src/orfimage.cpp +++ b/src/orfimage.cpp @@ -89,6 +89,21 @@ namespace Exiv2 { throw(Error(32, "Image comment", "ORF")); } + void OrfImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) { + std::cout << "ORF IMAGE" << std::endl; + if (io_->open() != 0) throw Error(9, io_->path(), strError()); + // Ensure that this is the correct image type + if ( imageType() == ImageType::none ) + if (!isOrfType(*io_, false)) { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(15); + } + + io_->seek(0,BasicIo::beg); + + printTiffStructure(io(),out,option,depth-1); + } // OrfImage::printStructure + void OrfImage::readMetadata() { #ifdef DEBUG @@ -104,6 +119,8 @@ namespace Exiv2 { throw Error(3, "ORF"); } clearMetadata(); + std::ofstream devnull; + printStructure(devnull, kpsRecursive, 0); ByteOrder bo = OrfParser::decode(exifData_, iptcData_, xmpData_, diff --git a/src/rafimage.cpp b/src/rafimage.cpp index b883e4e3..65742a35 100644 --- a/src/rafimage.cpp +++ b/src/rafimage.cpp @@ -34,6 +34,7 @@ EXIV2_RCSID("@(#) $Id$") #include "rafimage.hpp" #include "tiffimage.hpp" +#include "image_int.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" @@ -95,6 +96,189 @@ namespace Exiv2 { throw(Error(32, "Image comment", "RAF")); } + void RafImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) { + if (io_->open() != 0) { + throw Error(9, io_->path(), strError()); + } + // Ensure this is the correct image type + if (!isRafType(*io_, true)) { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "RAF"); + } + bool bPrint = option==kpsBasic || option==kpsRecursive; + if ( bPrint ) { + io_->seek(0,BasicIo::beg); // rewind + + if ( bPrint ) { + out << Internal::indent(depth) + << "STRUCTURE OF RAF FILE: " + << io().path() + << std::endl; + out << Internal::indent(depth) + << Internal::stringFormat(" Length | Offset | Payload") + << std::endl; + } + + byte magicdata [17]; + io_->read(magicdata, 16); + magicdata[16] = 0; + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 16, 0) + << "Magic number : " + << std::string((char*)&magicdata) + << std::endl; + } + + byte data1 [5]; + io_->read(data1, 4); + data1[4] = 0; + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 4, 16) + << "data 1 : " + << std::string((char*)&data1) + << std::endl; + } + + byte data2 [9]; + io_->read(data2, 8); + data2[8] = 0; + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 8, 20) + << "data 2 : " + << std::string((char*)&data2) + << std::endl; + } + + byte camdata [33]; + io_->read(camdata, 32); + camdata[32] = 0; + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 32, 28) + << "camera : " + << std::string((char*)&camdata) + << std::endl; + } + + byte dir_version [5]; + io_->read(dir_version, 4); + dir_version[4] = 0; + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 4, 60) + << "dir version : " + << std::string((char*)&dir_version) + << std::endl; + } + + byte unknown [20]; + io_->read(unknown, 20); + + byte jpg_img_offset [4]; + io_->read(jpg_img_offset, 4); + byte jpg_img_length [4]; + io_->read(jpg_img_length, 4); + long jpg_img_off = Exiv2::getULong((const byte *) jpg_img_offset, bigEndian); + long jpg_img_len = Exiv2::getULong((const byte *) jpg_img_length, bigEndian); + std::stringstream j_off; + std::stringstream j_len; + j_off << jpg_img_off; + j_len << jpg_img_len; + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 4, 84) + << "JPEG Image Offset : " + << j_off.str() + << std::endl; + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 4, 88) + << "JPEG Image Length : " + << j_len.str() + << std::endl; + } + + byte cfa_header_offset [4]; + io_->read(cfa_header_offset, 4); + byte cfa_header_length [4]; + io_->read(cfa_header_length, 4); + long cfa_hdr_off = Exiv2::getULong((const byte *) cfa_header_offset, bigEndian); + long cfa_hdr_len = Exiv2::getULong((const byte *) cfa_header_length, bigEndian); + std::stringstream ch_off; + std::stringstream ch_len; + ch_off << cfa_hdr_off; + ch_len << cfa_hdr_len; + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 4, 92) + << "CFA Header Offset : " + << ch_off.str() + << std::endl; + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 4, 96) + << "CFA Header Length : " + << ch_len.str() + << std::endl; + } + + byte cfa_offset [4]; + io_->read(cfa_offset, 4); + byte cfa_length [4]; + io_->read(cfa_length, 4); + long cfa_off = Exiv2::getULong((const byte *) cfa_offset, bigEndian); + long cfa_len = Exiv2::getULong((const byte *) cfa_length, bigEndian); + std::stringstream c_off; + std::stringstream c_len; + c_off << cfa_off; + c_len << cfa_len; + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 4, 100) + << "CFA Offset : " + << c_off.str() + << std::endl; + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", 4, 104) + << "CFA Length : " + << c_len.str() + << std::endl; + } + + io_->seek(jpg_img_off, BasicIo::beg); // rewind + DataBuf payload(16); // header is different from chunks + io_->read(payload.pData_, payload.size_); + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", jpg_img_len, jpg_img_off) + << "jpg image / exif : " + << Internal::binaryToString(payload, payload.size_) + << std::endl; + } + + io_->seek(cfa_hdr_off, BasicIo::beg); // rewind + io_->read(payload.pData_, payload.size_); + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", cfa_hdr_len, cfa_hdr_off) + << "CFA Header: " + << Internal::binaryToString(payload, payload.size_) + << std::endl; + } + + io_->seek(cfa_off, BasicIo::beg); // rewind + io_->read(payload.pData_, payload.size_); + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %8u | %8u | ", cfa_len, cfa_off) + << "CFA : " + << Internal::binaryToString(payload, payload.size_) + << std::endl; + } + } + } // RafImage::printStructure + void RafImage::readMetadata() { #ifdef DEBUG @@ -107,20 +291,32 @@ namespace Exiv2 { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "RAF"); } - byte const* pData = io_->mmap(); - long size = io_->size(); - if (size < 88 + 4) throw Error(14); // includes the test for -1 - uint32_t const start = getULong(pData + 84, bigEndian) + 12; - if (static_cast(size) < start) throw Error(14); + clearMetadata(); + + io_->seek(84,BasicIo::beg); + byte jpg_img_offset [4]; + io_->read(jpg_img_offset, 4); + byte jpg_img_length [4]; + io_->read(jpg_img_length, 4); + long jpg_img_off = Exiv2::getULong((const byte *) jpg_img_offset, bigEndian); + long jpg_img_len = Exiv2::getULong((const byte *) jpg_img_length, bigEndian); + + DataBuf buf(jpg_img_len - 12); + io_->seek(jpg_img_off + 12,BasicIo::beg); + io_->read(buf.pData_, buf.size_ - 12); + if (io_->error() || io_->eof()) throw Error(14); + + io_->seek(0,BasicIo::beg); // rewind + ByteOrder bo = TiffParser::decode(exifData_, iptcData_, xmpData_, - pData + start, - size - start); + buf.pData_, + buf.size_); - exifData_["Exif.Image2.JPEGInterchangeFormat"] = getULong(pData + 84, bigEndian); - exifData_["Exif.Image2.JPEGInterchangeFormatLength"] = getULong(pData + 88, bigEndian); + exifData_["Exif.Image2.JPEGInterchangeFormat"] = getULong(jpg_img_offset, bigEndian); + exifData_["Exif.Image2.JPEGInterchangeFormatLength"] = getULong(jpg_img_length, bigEndian); setByteOrder(bo); } // RafImage::readMetadata diff --git a/src/riffvideo.cpp b/src/riffvideo.cpp index 91ea2d1b..1edbbe56 100644 --- a/src/riffvideo.cpp +++ b/src/riffvideo.cpp @@ -41,6 +41,7 @@ EXIV2_RCSID("@(#) $Id$") #include "tags_int.hpp" #include "types.hpp" #include "tiffimage_int.hpp" +#include "image_int.hpp" // + standard includes #include @@ -516,6 +517,88 @@ namespace Exiv2 { return "video/riff"; } + const int RiffVideo::RIFF_TAG_SIZE = 0x4; + const char* RiffVideo::RIFF_CHUNK_HEADER_ICCP = "ICCP"; + const char* RiffVideo::RIFF_CHUNK_HEADER_EXIF = "EXIF"; + const char* RiffVideo::RIFF_CHUNK_HEADER_XMP = "XMP "; + + /*! + @brief Function used to check equality of a Tags with a + particular string (ignores case while comparing). + @param buf Data buffer that will contain Tag to compare + @param str char* Pointer to string + @return Returns true if the buffer value is equal to string. + */ + bool RiffVideo::equalsRiffTag(Exiv2::DataBuf& buf, const char* str) { + for(int i = 0; i < 4; i++ ) + if(toupper(buf.pData_[i]) != str[i]) + return false; + return true; + } + + void RiffVideo::printStructure(std::ostream& out, PrintStructureOption option, int depth) { + if (io_->open() != 0) { + throw Error(9, io_->path(), strError()); + } + // Ensure this is the correct image type + if (!isRiffType(*io_, true)) { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "RIFF"); + } + + bool bPrint = option==kpsBasic || option==kpsRecursive; + if ( bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase ) { + byte data [RIFF_TAG_SIZE * 2]; + io_->read(data, RIFF_TAG_SIZE * 2); + uint64_t filesize = Exiv2::getULong(data + RIFF_TAG_SIZE, littleEndian); + DataBuf chunkId(5) ; + chunkId.pData_[4] = '\0' ; + + if ( bPrint ) { + out << Internal::indent(depth) + << "STRUCTURE OF RIFF FILE: " + << io().path() + << std::endl; + out << Internal::indent(depth) + << Internal::stringFormat(" Chunk | Length | Offset | Payload") + << std::endl; + } + + io_->seek(0,BasicIo::beg); // rewind + while ( !io_->eof() && (uint64_t) io_->tell() < filesize) { + uint64_t offset = (uint64_t) io_->tell(); + byte size_buff[RIFF_TAG_SIZE]; + io_->read(chunkId.pData_, RIFF_TAG_SIZE); + io_->read(size_buff, RIFF_TAG_SIZE); + long size = Exiv2::getULong(size_buff, littleEndian); + DataBuf payload(offset?size:RIFF_TAG_SIZE); // header is different from chunks + io_->read(payload.pData_, payload.size_); + + if ( bPrint ) { + out << Internal::indent(depth) + << Internal::stringFormat(" %s | %12u | %12u | ", (const char*)chunkId.pData_,size,(uint32_t)offset) + << Internal::binaryToString(payload,payload.size_>32?32:payload.size_) + << std::endl; + } + + if ( equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_EXIF) && option==kpsRecursive ) { + // create memio object with the payload, then print the structure + BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(payload.pData_,payload.size_)); + printTiffStructure(*p,out,option,depth); + } + + bool bPrintPayload = (equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_XMP) && option==kpsXMP) + || (equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_ICCP) && option==kpsIccProfile) + ; + if ( bPrintPayload ) { + out.write((const char*) payload.pData_,payload.size_); + } + + if ( offset && io_->tell() % 2 ) io_->seek(+1, BasicIo::cur); // skip padding byte on sub-chunks + } + } + } // RiffVideo::printStructure + void RiffVideo::writeMetadata() { } // RiffVideo::writeMetadata diff --git a/src/rw2image.cpp b/src/rw2image.cpp index a25a42bb..95f3b28e 100644 --- a/src/rw2image.cpp +++ b/src/rw2image.cpp @@ -100,6 +100,21 @@ namespace Exiv2 { throw(Error(32, "Image comment", "RW2")); } + void Rw2Image::printStructure(std::ostream& out, PrintStructureOption option, int depth) { + std::cout << "RW2 IMAGE" << std::endl; + if (io_->open() != 0) throw Error(9, io_->path(), strError()); + // Ensure that this is the correct image type + if ( imageType() == ImageType::none ) + if (!isRw2Type(*io_, false)) { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(15); + } + + io_->seek(0,BasicIo::beg); + + printTiffStructure(io(),out,option,depth-1); + } // Rw2Image::printStructure + void Rw2Image::readMetadata() { #ifdef DEBUG @@ -115,6 +130,8 @@ namespace Exiv2 { throw Error(3, "RW2"); } clearMetadata(); + std::ofstream devnull; + printStructure(devnull, kpsRecursive, 0); ByteOrder bo = Rw2Parser::decode(exifData_, iptcData_, xmpData_, diff --git a/src/webpimage.cpp b/src/webpimage.cpp index 810c6ca7..e4057d6c 100644 --- a/src/webpimage.cpp +++ b/src/webpimage.cpp @@ -412,8 +412,9 @@ namespace Exiv2 { void WebPImage::printStructure(std::ostream& out, PrintStructureOption option,int depth) { - if (io_->open() != 0) throw Error(9, io_->path(), strError()); - IoCloser closer(*io_); + if (io_->open() != 0) { + throw Error(9, io_->path(), strError()); + } // Ensure this is the correct image type if (!isWebPType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(14);