#922. Added options -pS and -pX to exiv2(.exe). Still to deal with -dI

v0.27.3
Robin Mills 10 years ago
parent 00f2c6cebd
commit 6c113871ef

@ -178,6 +178,8 @@ namespace Action {
void printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image); void printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image);
//! Print the label for a summary line //! Print the label for a summary line
void printLabel(const std::string& label) const; void printLabel(const std::string& label) const;
//! Print image Structure information
int printStructure(std::ostream& out,Exiv2::printStructureOption_e option);
/*! /*!
@brief Print one summary line with a label (if provided) and requested @brief Print one summary line with a label (if provided) and requested
data. A line break is printed only if a label is provided. data. A line break is printed only if a label is provided.

@ -71,6 +71,11 @@ namespace Exiv2 {
//! List of native previews. This is meant to be used only by the PreviewManager. //! List of native previews. This is meant to be used only by the PreviewManager.
typedef std::vector<NativePreview> NativePreviewList; typedef std::vector<NativePreview> NativePreviewList;
/*!
@brief options for printStructure
*/
typedef enum { kpsNone, kpsBasic, kpsXMP } printStructureOption_e ;
/*! /*!
@brief Abstract base class defining the interface for an image. This is @brief Abstract base class defining the interface for an image. This is
the top-level interface to the Exiv2 library. the top-level interface to the Exiv2 library.
@ -107,7 +112,7 @@ namespace Exiv2 {
@throw Error if reading of the file fails or the image data is @throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type). not valid (does not look like data of the specific image type).
*/ */
virtual void printStructure(); virtual void printStructure(std::ostream& out,printStructureOption_e option=kpsNone);
/*! /*!
@brief Read all metadata supported by a specific image format from the @brief Read all metadata supported by a specific image format from the
image. Before this method is called, the image metadata will be image. Before this method is called, the image metadata will be
@ -450,7 +455,7 @@ namespace Exiv2 {
class EXIV2API ImageFactory { class EXIV2API ImageFactory {
friend bool Image::good() const; friend bool Image::good() const;
public: public:
/*! /*!
@brief Create the appropriate class type implemented BasicIo based on the protocol of the input. @brief Create the appropriate class type implemented BasicIo based on the protocol of the input.
"-" path implies the data from stdin and it is handled by StdinIo. "-" path implies the data from stdin and it is handled by StdinIo.
@ -466,7 +471,7 @@ namespace Exiv2 {
*/ */
static BasicIo::AutoPtr createIo(const std::string& path, bool useCurl = true); static BasicIo::AutoPtr createIo(const std::string& path, bool useCurl = true);
#ifdef EXV_UNICODE_PATH #ifdef EXV_UNICODE_PATH
/*! /*!
@brief Like createIo() but accepts a unicode path in an std::wstring. @brief Like createIo() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows. @note This function is only available on Windows.
*/ */

@ -150,7 +150,7 @@ namespace Exiv2 {
public: public:
//! @name Manipulators //! @name Manipulators
//@{ //@{
void printStructure(); void printStructure(std::ostream& out,printStructureOption_e option);
void readMetadata(); void readMetadata();
void writeMetadata(); void writeMetadata();
//@} //@}

@ -84,7 +84,7 @@ namespace Exiv2
//! @name Manipulators //! @name Manipulators
//@{ //@{
void printStructure(); void printStructure(std::ostream& out,printStructureOption_e option);
void readMetadata(); void readMetadata();
void writeMetadata(); void writeMetadata();
//@} //@}

@ -237,10 +237,12 @@ namespace Action {
path_ = path; path_ = path;
int rc = 0; int rc = 0;
switch (Params::instance().printMode_) { switch (Params::instance().printMode_) {
case Params::pmSummary: rc = printSummary(); break; case Params::pmSummary: rc = printSummary(); break;
case Params::pmList: rc = printList(); break; case Params::pmList: rc = printList(); break;
case Params::pmComment: rc = printComment(); break; case Params::pmComment: rc = printComment(); break;
case Params::pmPreview: rc = printPreviewList(); break; case Params::pmPreview: rc = printPreviewList(); break;
case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic); break;
case Params::pmXMP: rc = printStructure(std::cout,Exiv2::kpsXMP); break;
} }
return rc; return rc;
} }
@ -250,6 +252,19 @@ namespace Action {
return 1; return 1;
} // Print::run } // Print::run
int Print::printStructure(std::ostream& out,Exiv2::printStructureOption_e option)
{
if (!Exiv2::fileExists(path_, true)) {
std::cerr << path_ << ": "
<< _("Failed to open the file\n");
return -1;
}
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
assert(image.get() != 0);
image->printStructure(out,option);
return 0;
}
int Print::printSummary() int Print::printSummary()
{ {
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_, true)) {

@ -3,7 +3,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" other parameters are allowed: see man(7), man(1)
.TH EXIV2 1 "Mar 11, 2015" .TH EXIV2 1 "Mar 27, 2015"
.\" Please adjust this date whenever revising the manpage. .\" Please adjust this date whenever revising the manpage.
.\" .\"
.\" Some roff macros, for reference: .\" Some roff macros, for reference:
@ -231,6 +231,10 @@ x : XMP properties (\-PXkyct)
c : JPEG comment c : JPEG comment
.br .br
p : list available image previews, sorted by preview image size in pixels p : list available image previews, sorted by preview image size in pixels
.br
S : print image structure information (jpg and png only)
.br
X : print "raw" XMP (jpg and png only)
.TP .TP
.B \-P \fIflgs\fP .B \-P \fIflgs\fP
Print flags for fine control of the tag list ('print' action). Allows Print flags for fine control of the tag list ('print' action). Allows

@ -296,6 +296,8 @@ void Params::help(std::ostream& os) const
<< _(" x : XMP properties (-PXkyct)\n") << _(" x : XMP properties (-PXkyct)\n")
<< _(" c : JPEG comment\n") << _(" c : JPEG comment\n")
<< _(" p : list available previews\n") << _(" p : list available previews\n")
<< _(" S : print structure of image\n")
<< _(" X : extract XMP from image\n")
<< _(" -P flgs Print flags for fine control of tag lists ('print' action):\n") << _(" -P flgs Print flags for fine control of tag lists ('print' action):\n")
<< _(" E : include Exif tags in the list\n") << _(" E : include Exif tags in the list\n")
<< _(" I : IPTC datasets\n") << _(" I : IPTC datasets\n")
@ -555,8 +557,10 @@ int Params::evalPrint(const std::string& optarg)
case 'h': rc = evalPrintFlags("Exgnycsh"); break; case 'h': rc = evalPrintFlags("Exgnycsh"); break;
case 'i': rc = evalPrintFlags("Ikyct"); break; case 'i': rc = evalPrintFlags("Ikyct"); break;
case 'x': rc = evalPrintFlags("Xkyct"); break; case 'x': rc = evalPrintFlags("Xkyct"); break;
case 'c': action_ = Action::print; printMode_ = pmComment; break; case 'c': action_ = Action::print; printMode_ = pmComment ; break;
case 'p': action_ = Action::print; printMode_ = pmPreview; break; case 'p': action_ = Action::print; printMode_ = pmPreview ; break;
case 'S': action_ = Action::print; printMode_ = pmStructure; break;
case 'X': action_ = Action::print; printMode_ = pmXMP ; break;
default: default:
std::cerr << progname() << ": " << _("Unrecognized print mode") << " `" std::cerr << progname() << ": " << _("Unrecognized print mode") << " `"
<< optarg << "'\n"; << optarg << "'\n";

@ -144,7 +144,9 @@ public:
pmSummary, pmSummary,
pmList, pmList,
pmComment, pmComment,
pmPreview pmPreview,
pmStructure,
pmXMP
}; };
//! Individual items to print, bitmap //! Individual items to print, bitmap

@ -68,6 +68,8 @@ EXIV2_RCSID("@(#) $Id$")
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#include <iostream>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef _MSC_VER #ifdef _MSC_VER
@ -160,7 +162,7 @@ namespace Exiv2 {
Image::~Image() Image::~Image()
{ {
} }
void Image::printStructure() void Image::printStructure(std::ostream&, printStructureOption_e)
{ {
} }
@ -435,13 +437,13 @@ namespace Exiv2 {
return BasicIo::AutoPtr(new XPathIo(path)); // may throw return BasicIo::AutoPtr(new XPathIo(path)); // may throw
return BasicIo::AutoPtr(new FileIo(path)); return BasicIo::AutoPtr(new FileIo(path));
UNUSED(useCurl); UNUSED(useCurl);
} // ImageFactory::createIo } // ImageFactory::createIo
#ifdef EXV_UNICODE_PATH #ifdef EXV_UNICODE_PATH
BasicIo::AutoPtr ImageFactory::createIo(const std::wstring& wpath, bool useCurl) BasicIo::AutoPtr ImageFactory::createIo(const std::wstring& wpath, bool useCurl)
{ {
Protocol fProt = fileProtocol(wpath); Protocol fProt = fileProtocol(wpath);
#if EXV_USE_SSH == 1 #if EXV_USE_SSH == 1
if (fProt == pSsh || fProt == pSftp) { if (fProt == pSsh || fProt == pSftp) {

@ -507,7 +507,7 @@ namespace Exiv2 {
} }
} // JpegBase::readMetadata } // JpegBase::readMetadata
void JpegBase::printStructure() void JpegBase::printStructure(std::ostream& out,printStructureOption_e option)
{ {
if (io_->open() != 0) throw Error(9, io_->path(), strError()); if (io_->open() != 0) throw Error(9, io_->path(), strError());
// Ensure that this is the correct image type // Ensure that this is the correct image type
@ -515,90 +515,116 @@ namespace Exiv2 {
if (io_->error() || io_->eof()) throw Error(14); if (io_->error() || io_->eof()) throw Error(14);
throw Error(15); throw Error(15);
} }
// nemonic for markers if ( option == kpsBasic || option == kpsXMP ) {
std::string nm[256] ; char sbuff[80];
nm[0xd8]="SOI" ;
nm[0xd9]="EOI" ; // nemonic for markers
nm[0xda]="SOS" ; std::string nm[256] ;
nm[0xdb]="DQT" ; nm[0xd8]="SOI" ;
nm[0xdd]="DRI" ; nm[0xd9]="EOI" ;
nm[0xfe]="COM" ; nm[0xda]="SOS" ;
nm[0xdb]="DQT" ;
// 0xe0 .. 0xef are APPn nm[0xdd]="DRI" ;
// 0xc0 .. 0xcf are SOFn (except 4) nm[0xfe]="COM" ;
nm[0xc4]="DHT" ;
for ( int i = 0 ; i <= 15 ; i++ ) { // 0xe0 .. 0xef are APPn
char MN[10]; // 0xc0 .. 0xcf are SOFn (except 4)
sprintf(MN,"APP%d",i); nm[0xc4]="DHT" ;
nm[0xe0+i] = MN; for ( int i = 0 ; i <= 15 ; i++ ) {
if ( i != 4 ) { char MN[10];
sprintf(MN,"SOF%d",i); sprintf(MN,"APP%d",i);
nm[0xc0+i] = MN; nm[0xe0+i] = MN;
if ( i != 4 ) {
sprintf(MN,"SOF%d",i);
nm[0xc0+i] = MN;
}
} }
}
// Container for the signature // Container for the signature
const long bufMinSize = 36; const long bufMinSize = 36;
long bufRead = 0, startSig = 0; long bufRead = 0, startSig = 0;
DataBuf buf(bufMinSize); DataBuf buf(bufMinSize);
// Read section marker
int marker = advanceToMarker();
if (marker < 0) throw Error(15);
if ( option == kpsBasic ) out << " offset | marker | length | signature" << std::endl ;
while (1) {
// print marker bytes
sprintf(sbuff,"%8ld %#02x %-5s",io_->tell(), marker,nm[marker].c_str());
if ( option == kpsBasic ) out << sbuff;
if ( marker == eoi_ ) break ;
// Read size and signature
std::memset(buf.pData_, 0x0, buf.size_);
bufRead = io_->read(buf.pData_, bufMinSize);
if (io_->error()) throw Error(14);
if (bufRead < 2) throw Error(15);
uint16_t size = 0;
sbuff[0]=0;
// not all markers have size field.
if( ( marker >= sof0_ && marker <= sof15_)
|| ( marker >= app0_ && marker <= (app0_ | 0x0F))
|| marker == dht_
|| marker == dqt_
|| marker == dri_
|| marker == com_
|| marker == sos_
){
size = getUShort(buf.pData_, bigEndian);
sprintf(sbuff,"%7d ", size);
} else {
sprintf(sbuff," ");
}
if ( option == kpsBasic ) out << sbuff ;
// only print the signature for appn
if (marker >= app0_ && marker <= (app0_ | 0x0F)) {
char http[5];
http[4]=0;
memcpy(http,buf.pData_+2,4);
if ( option == kpsXMP && strncmp(http,"http",4) == 0 ) {
// http://ns.adobe.com/xap/1.0/
if ( size > 0 ) {
io_->seek(-bufRead , BasicIo::cur);
byte* xmp = new byte[size+1];
io_->read(xmp,size);
int start = 0 ;
while (xmp[start]) start++; start++;
xmp[size]=0;
out << xmp + start << std::endl;
delete [] xmp;
bufRead = size;
}
} else if ( option == kpsBasic ) {
startSig = size>0?2:0;
int endSig = size?size:bufRead;
if (endSig > 32) endSig = 32 ;
while (startSig++ < endSig ) {
byte c = buf.pData_[startSig-1] ;
c = (' '<=c && c<128) ? c : '.' ;
out << (char) c ;
// else endSig = startSig;
}
}
}
// Read section marker
int marker = advanceToMarker();
if (marker < 0) throw Error(15);
printf("STRUCTURE OF FILE:\n"); // Skip the segment if the size is known
printf(" offset | marker | size | signature\n"); if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14);
while (1) {
// print marker bytes if ( option == kpsBasic ) out << std::endl;
printf("%8ld %#02x %-5s",io_->tell(), marker,nm[marker].c_str()); // sos_ is immediately followed by entropy-coded data & eoi_
if ( marker == eoi_ ) break ; if (marker == sos_) break;
// Read size and signature // Read the beginning of the next segment
std::memset(buf.pData_, 0x0, buf.size_); marker = advanceToMarker();
bufRead = io_->read(buf.pData_, bufMinSize); }
if (io_->error()) throw Error(14);
if (bufRead < 2) throw Error(15);
uint16_t size = 0;
// not all markers have size field.
if( ( marker >= sof0_ && marker <= sof15_)
|| ( marker >= app0_ && marker <= (app0_ | 0x0F))
|| marker == dht_
|| marker == dqt_
|| marker == dri_
|| marker == com_
|| marker == sos_
){
size = getUShort(buf.pData_, bigEndian);
printf("%7d ", size);
} else {
printf(" ");
}
// only print the signature for appn
if (marker >= app0_ && marker <= (app0_ | 0x0F)) {
startSig = size>0?2:0;
int endSig = size?size:bufRead;
if (endSig > 32) endSig = 32 ;
while (startSig++ < endSig ) {
int c = buf.pData_[startSig-1] ;
printf("%c", (' '<=c && c<128) ? c : '.' );
// else endSig = startSig;
}
}
// Skip the segment if the size is known
if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14);
printf("\n");
// sos_ is immediately followed by entropy-coded data & eoi_
if (marker == sos_) break;
// Read the beginning of the next segment
marker = advanceToMarker();
} }
printf("-----------------\n");
} }
void JpegBase::writeMetadata() void JpegBase::writeMetadata()

@ -91,7 +91,7 @@ namespace Exiv2 {
return "image/png"; return "image/png";
} }
void PngImage::printStructure() void PngImage::printStructure(std::ostream& out,printStructureOption_e option)
{ {
if (io_->open() != 0) { if (io_->open() != 0) {
throw Error(9, io_->path(), strError()); throw Error(9, io_->path(), strError());
@ -103,34 +103,75 @@ namespace Exiv2 {
throw Error(3, "PNG"); throw Error(3, "PNG");
} }
printf("index | chunk_type | chunk_size\n"); char chType[5];
long index = 0, i = 0; chType[0]=0;
const long imgSize = io_->size(); chType[4]=0;
DataBuf cheaderBuf(8);
while(!io_->eof()) { if ( option == kpsBasic || option == kpsXMP ) {
std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_);
long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_);
if (io_->error()) throw Error(14);
if (bufRead != cheaderBuf.size_) throw Error(20);
// Decode chunk data length. if ( option == kpsBasic ) out << "index | chunk_type | length | data" << std::endl;
uint32_t dataOffset = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian);
long pos = io_->tell();
if ( pos == -1
|| dataOffset > uint32_t(0x7FFFFFFF)
|| static_cast<long>(dataOffset) > imgSize - pos) throw Exiv2::Error(14);
printf("%5ld ", index); long index = 0;
for (i = 4; i < 8; i++) const long imgSize = io_->size();
printf("%c", cheaderBuf.pData_[i]); DataBuf cheaderBuf(8);
printf(" %u\n", dataOffset);
index++; while( !io_->eof() && ::strcmp(chType,"IEND") ) {
io_->seek(dataOffset + 4 , BasicIo::cur); std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_);
if (io_->error() || io_->eof()) throw Error(14); long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_);
} if (io_->error()) throw Error(14);
if (bufRead != cheaderBuf.size_) throw Error(20);
// Decode chunk data length.
uint32_t dataOffset = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian);
long pos = io_->tell();
if ( pos == -1
|| dataOffset > uint32_t(0x7FFFFFFF)
|| static_cast<long>(dataOffset) > imgSize - pos) throw Exiv2::Error(14);
for (int i = 4; i < 8; i++) {
chType[i-4]=cheaderBuf.pData_[i];
}
byte buff[32];
size_t blen = sizeof(buff)-1;
buff [blen] = 0;
buff [ 0] = 0;
size_t dOff = dataOffset;
if ( dataOffset > blen ) {
io_->read(buff,blen);
dataOffset -= blen ;
for ( size_t i = 0 ; i < blen ; i++ ) {
int c = buff[i] ;
buff[i] = (' '<=c && c<128) ? c : '.' ;
}
}
char sbuff[80];
sprintf(sbuff,"%5ld %12s %8lu %s\n", index++,chType,dOff,buff);
if ( option == kpsBasic ) out << sbuff;
// for XMP, back up and read the whole block
const char* key = "XML:com.adobe.xmp" ;
int start = ::strlen(key);
buff[start] = 0;
if ( option == kpsXMP && ::strcmp((const char*)buff,key) == 0 ) {
io_->seek(-blen , BasicIo::cur);
dataOffset = dOff ;
byte* xmp = new byte[dataOffset+5];
io_->read(xmp,dataOffset+4);
xmp[dataOffset]=0;
while ( xmp[start] == 0 ) start++;
out << xmp+start << std::endl;
delete [] xmp;
dataOffset = 0;
}
if ( dataOffset ) io_->seek(dataOffset + 4 , BasicIo::cur);
if (io_->error()) throw Error(14);
}
}
} }
void PngImage::readMetadata() void PngImage::readMetadata()

Loading…
Cancel
Save