#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);
//! Print the label for a summary line
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
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.
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
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
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
image. Before this method is called, the image metadata will be
@ -450,7 +455,7 @@ namespace Exiv2 {
class EXIV2API ImageFactory {
friend bool Image::good() const;
public:
/*!
/*!
@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.
@ -466,7 +471,7 @@ namespace Exiv2 {
*/
static BasicIo::AutoPtr createIo(const std::string& path, bool useCurl = true);
#ifdef EXV_UNICODE_PATH
/*!
/*!
@brief Like createIo() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/

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

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

@ -237,10 +237,12 @@ namespace Action {
path_ = path;
int rc = 0;
switch (Params::instance().printMode_) {
case Params::pmSummary: rc = printSummary(); break;
case Params::pmList: rc = printList(); break;
case Params::pmComment: rc = printComment(); break;
case Params::pmPreview: rc = printPreviewList(); break;
case Params::pmSummary: rc = printSummary(); break;
case Params::pmList: rc = printList(); break;
case Params::pmComment: rc = printComment(); 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;
}
@ -250,6 +252,19 @@ namespace Action {
return 1;
} // 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()
{
if (!Exiv2::fileExists(path_, true)) {

@ -3,7 +3,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" 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.
.\"
.\" Some roff macros, for reference:
@ -231,6 +231,10 @@ x : XMP properties (\-PXkyct)
c : JPEG comment
.br
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
.B \-P \fIflgs\fP
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")
<< _(" c : JPEG comment\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")
<< _(" E : include Exif tags in the list\n")
<< _(" I : IPTC datasets\n")
@ -555,8 +557,10 @@ int Params::evalPrint(const std::string& optarg)
case 'h': rc = evalPrintFlags("Exgnycsh"); break;
case 'i': rc = evalPrintFlags("Ikyct"); break;
case 'x': rc = evalPrintFlags("Xkyct"); break;
case 'c': action_ = Action::print; printMode_ = pmComment; break;
case 'p': action_ = Action::print; printMode_ = pmPreview; break;
case 'c': action_ = Action::print; printMode_ = pmComment ; 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:
std::cerr << progname() << ": " << _("Unrecognized print mode") << " `"
<< optarg << "'\n";

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

@ -68,6 +68,8 @@ EXIV2_RCSID("@(#) $Id$")
#include <cstdio>
#include <cstring>
#include <cassert>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _MSC_VER
@ -160,7 +162,7 @@ namespace Exiv2 {
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 FileIo(path));
UNUSED(useCurl);
} // ImageFactory::createIo
#ifdef EXV_UNICODE_PATH
BasicIo::AutoPtr ImageFactory::createIo(const std::wstring& wpath, bool useCurl)
{
{
Protocol fProt = fileProtocol(wpath);
#if EXV_USE_SSH == 1
if (fProt == pSsh || fProt == pSftp) {

@ -507,7 +507,7 @@ namespace Exiv2 {
}
} // JpegBase::readMetadata
void JpegBase::printStructure()
void JpegBase::printStructure(std::ostream& out,printStructureOption_e option)
{
if (io_->open() != 0) throw Error(9, io_->path(), strError());
// Ensure that this is the correct image type
@ -515,90 +515,116 @@ namespace Exiv2 {
if (io_->error() || io_->eof()) throw Error(14);
throw Error(15);
}
// nemonic for markers
std::string nm[256] ;
nm[0xd8]="SOI" ;
nm[0xd9]="EOI" ;
nm[0xda]="SOS" ;
nm[0xdb]="DQT" ;
nm[0xdd]="DRI" ;
nm[0xfe]="COM" ;
// 0xe0 .. 0xef are APPn
// 0xc0 .. 0xcf are SOFn (except 4)
nm[0xc4]="DHT" ;
for ( int i = 0 ; i <= 15 ; i++ ) {
char MN[10];
sprintf(MN,"APP%d",i);
nm[0xe0+i] = MN;
if ( i != 4 ) {
sprintf(MN,"SOF%d",i);
nm[0xc0+i] = MN;
if ( option == kpsBasic || option == kpsXMP ) {
char sbuff[80];
// nemonic for markers
std::string nm[256] ;
nm[0xd8]="SOI" ;
nm[0xd9]="EOI" ;
nm[0xda]="SOS" ;
nm[0xdb]="DQT" ;
nm[0xdd]="DRI" ;
nm[0xfe]="COM" ;
// 0xe0 .. 0xef are APPn
// 0xc0 .. 0xcf are SOFn (except 4)
nm[0xc4]="DHT" ;
for ( int i = 0 ; i <= 15 ; i++ ) {
char MN[10];
sprintf(MN,"APP%d",i);
nm[0xe0+i] = MN;
if ( i != 4 ) {
sprintf(MN,"SOF%d",i);
nm[0xc0+i] = MN;
}
}
}
// Container for the signature
const long bufMinSize = 36;
long bufRead = 0, startSig = 0;
DataBuf buf(bufMinSize);
// Container for the signature
const long bufMinSize = 36;
long bufRead = 0, startSig = 0;
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");
printf(" offset | marker | size | signature\n");
while (1) {
// print marker bytes
printf("%8ld %#02x %-5s",io_->tell(), marker,nm[marker].c_str());
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;
// 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();
// Skip the segment if the size is known
if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14);
if ( option == kpsBasic ) out << std::endl;
// 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()

@ -91,7 +91,7 @@ namespace Exiv2 {
return "image/png";
}
void PngImage::printStructure()
void PngImage::printStructure(std::ostream& out,printStructureOption_e option)
{
if (io_->open() != 0) {
throw Error(9, io_->path(), strError());
@ -103,34 +103,75 @@ namespace Exiv2 {
throw Error(3, "PNG");
}
printf("index | chunk_type | chunk_size\n");
long index = 0, i = 0;
const long imgSize = io_->size();
DataBuf cheaderBuf(8);
char chType[5];
chType[0]=0;
chType[4]=0;
while(!io_->eof()) {
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);
if ( option == kpsBasic || option == kpsXMP ) {
// 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);
if ( option == kpsBasic ) out << "index | chunk_type | length | data" << std::endl;
printf("%5ld ", index);
for (i = 4; i < 8; i++)
printf("%c", cheaderBuf.pData_[i]);
printf(" %u\n", dataOffset);
long index = 0;
const long imgSize = io_->size();
DataBuf cheaderBuf(8);
index++;
io_->seek(dataOffset + 4 , BasicIo::cur);
if (io_->error() || io_->eof()) throw Error(14);
}
while( !io_->eof() && ::strcmp(chType,"IEND") ) {
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.
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()

Loading…
Cancel
Save