r1108 Recursively dump an image (exiv2 -pR file...)

v0.27.3
Robin Mills 10 years ago
parent b7607c34db
commit fd5e983746

@ -113,7 +113,7 @@ namespace Exiv2 {
not valid (does not look like data of the specific image type). not valid (does not look like data of the specific image type).
@caution This function is not thread safe and intended for exiv2 -pS for debugging. @caution This function is not thread safe and intended for exiv2 -pS for debugging.
*/ */
virtual void printStructure(std::ostream& out, PrintStructureOption option =kpsNone); virtual void printStructure(std::ostream& out, PrintStructureOption option =kpsNone, int depth=0);
/*! /*!
@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

@ -159,7 +159,7 @@ namespace Exiv2 {
not valid (does not look like data of the specific image type). not valid (does not look like data of the specific image type).
@caution This function is not thread safe and intended for exiv2 -pS for debugging. @caution This function is not thread safe and intended for exiv2 -pS for debugging.
*/ */
void printStructure(std::ostream& out, PrintStructureOption option); void printStructure(std::ostream& out, PrintStructureOption option,int depth);
//@} //@}
protected: protected:

@ -93,7 +93,7 @@ namespace Exiv2
not valid (does not look like data of the specific image type). not valid (does not look like data of the specific image type).
@caution This function is not thread safe and intended for exiv2 -pS for debugging. @caution This function is not thread safe and intended for exiv2 -pS for debugging.
*/ */
void printStructure(std::ostream& out, PrintStructureOption option); void printStructure(std::ostream& out, PrintStructureOption option,int depth);
//@} //@}
//! @name Accessors //! @name Accessors

@ -91,9 +91,23 @@ namespace Exiv2 {
@brief Print out the structure of image file. @brief Print out the structure of image file.
@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).
@caution This function is not thread safe and intended for exiv2 -pS for debugging. @caution This function is not thread safe and intended for exiv2 -p{S|R} as a file debugging aid
*/ */
void printStructure(std::ostream& out, PrintStructureOption option); void printStructure(std::ostream& out, PrintStructureOption option,int depth=-1);
/*!
@brief Print out the structure of image file.
@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).
@caution This function is not thread safe. See TiffImage::printStructure for more details
*/
static void printTiffStructure(BasicIo& io,std::ostream& out, PrintStructureOption option,int depth);
/*!
@brief Print out the structure of a TIFF IFD
@caution This function is not thread safe. See TiffImage::printStructure for more details
*/
static void printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,size_t start,bool bSwap,char c,int depth);
/*! /*!
@brief Not supported. TIFF format does not contain a comment. @brief Not supported. TIFF format does not contain a comment.

@ -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 "Dec 29, 2015" .TH EXIV2 1 "Jan 5, 2016"
.\" 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:
@ -175,9 +175,9 @@ fmt Default format is %Y%m%d_%H%M%S.
lvl d | i | i | w | e lvl d | i | i | w | e
debug, info, warning, error debug, info, warning, error
mod s | a | t | v | h | i | x | c | p | i | S | X : mod s | a | t | v | h | i | x | c | p | i | C | R | S | X :
summary, add, translated, vanilla, hex ... summary, add, translated, vanilla, hex ...
iptc ,xmp, comment, preview, Structure,XMP raw iptc ,xmp, comment, preview, ICC, Recursive, Structure, raw XMP
tgt a | c | e | i | t | x tgt a | c | e | i | t | x
all, comment, exif, iptc, thumb, xmp all, comment, exif, iptc, thumb, xmp
@ -315,9 +315,13 @@ 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 .br
S : print image structure information (jpg, png and tiff only) C : print image ICC Profile (jpg only)
.br .br
X : print "raw" XMP (jpg, png and tiff only) R : print image structure recursively (jpg, tiff only)
.br
S : print image structure information (jpg, png, tiff only)
.br
X : print "raw" XMP (jpg, png, tiff 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

@ -169,7 +169,7 @@ namespace Exiv2 {
{ {
} }
void Image::printStructure(std::ostream&, PrintStructureOption) void Image::printStructure(std::ostream&, PrintStructureOption,int /*depth*/)
{ {
throw Error(13, io_->path()); throw Error(13, io_->path());
} }

@ -35,6 +35,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "config.h" #include "config.h"
#include "jpgimage.hpp" #include "jpgimage.hpp"
#include "tiffimage.hpp"
#include "image_int.hpp" #include "image_int.hpp"
#include "error.hpp" #include "error.hpp"
#include "futils.hpp" #include "futils.hpp"
@ -516,9 +517,9 @@ namespace Exiv2 {
return true ; return true ;
} }
#define REPORT_MARKER if ( option == kpsBasic ) out << Internal::stringFormat("%8ld | %#02x %-5s",io_->tell(), marker,nm[marker].c_str()) #define REPORT_MARKER if ( (option == kpsBasic||option == kpsRecursive) ) out << Internal::stringFormat("%8ld | %#02x %-5s",io_->tell(), marker,nm[marker].c_str())
void JpegBase::printStructure(std::ostream& out, PrintStructureOption option) void JpegBase::printStructure(std::ostream& out, PrintStructureOption option,int depth)
{ {
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
@ -570,7 +571,8 @@ namespace Exiv2 {
out << " address | marker | length | data" << std::endl ; out << " address | marker | length | data" << std::endl ;
REPORT_MARKER; REPORT_MARKER;
} }
first = false; first = false;
bool bLF = option == kpsBasic||option == kpsRecursive;
// Read size and signature // Read size and signature
std::memset(buf.pData_, 0x0, buf.size_); std::memset(buf.pData_, 0x0, buf.size_);
@ -590,7 +592,7 @@ namespace Exiv2 {
){ ){
size = getUShort(buf.pData_, bigEndian); size = getUShort(buf.pData_, bigEndian);
} }
if ( option == kpsBasic ) out << Internal::stringFormat(" | %7d ", size); if ( option == kpsBasic||option==kpsRecursive ) out << Internal::stringFormat(" | %7d ", size);
// only print the signature for appn // only print the signature for appn
if (marker >= app0_ && marker <= (app0_ | 0x0F)) { if (marker >= app0_ && marker <= (app0_ | 0x0F)) {
@ -637,15 +639,43 @@ namespace Exiv2 {
bufRead = size; bufRead = size;
delete [] icc; delete [] icc;
} }
} else if ( option == kpsBasic ) { } else if ( option == kpsBasic||option==kpsRecursive ) {
out << "| " << Internal::binaryToString(buf,32,size>0?2:0); out << "| " << Internal::binaryToString(buf,size>32?32:size,size>0?2:0);
}
// for MPF: http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
if( (option == kpsRecursive && marker == (app0_+1) && std::strcmp(http,"Exif")==0 )
|| (option == kpsRecursive && marker == (app0_+2) && std::strcmp(http,"MPF" )==0 )
) {
// extract Exif data block which is tiff formatted
if ( size > 0 ) {
out << std::endl;
// allocate storage and current file position
byte* exif = new byte[size];
size_t restore = io_->tell();
// copy the data to memory
io_->seek(-bufRead , BasicIo::cur);
io_->read(exif,size);
std::size_t start = std::strcmp(http,"Exif")==0 ? 8 : 6;
// create a copy on write memio object with the data, then print the structure
BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(exif+start,size-start));
TiffImage::printTiffStructure(*p,out,option,depth);
// restore and clean up
io_->seek(restore,Exiv2::BasicIo::beg);
delete [] exif;
bLF = false;
}
} }
} }
// Skip the segment if the size is known // Skip the segment if the size is known
if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14); if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14);
if ( option == kpsBasic ) out << std::endl; if ( bLF ) out << std::endl;
if (marker == sos_) if (marker == sos_)
// sos_ is immediately followed by entropy-coded data & eoi_ // sos_ is immediately followed by entropy-coded data & eoi_

@ -48,6 +48,8 @@ EXIV2_RCSID("@(#) $Id$")
#include <iostream> #include <iostream>
#include <cassert> #include <cassert>
#include <zlib.h> // To uncompress IccProfiles
// Signature from front of PNG file // Signature from front of PNG file
const unsigned char pngSignature[8] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; const unsigned char pngSignature[8] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
@ -92,7 +94,47 @@ namespace Exiv2 {
return "image/png"; return "image/png";
} }
void PngImage::printStructure(std::ostream& out, PrintStructureOption option) static void zlibUncompress(const byte* compressedText,
unsigned int compressedTextSize,
DataBuf& arr)
{
uLongf uncompressedLen = compressedTextSize * 2; // just a starting point
int zlibResult;
int dos = 0;
do {
arr.alloc(uncompressedLen);
zlibResult = uncompress((Bytef*)arr.pData_,
&uncompressedLen,
compressedText,
compressedTextSize);
if (zlibResult == Z_OK) {
assert((uLongf)arr.size_ >= uncompressedLen);
arr.size_ = uncompressedLen;
}
else if (zlibResult == Z_BUF_ERROR) {
// the uncompressedArray needs to be larger
uncompressedLen *= 2;
// DoS protection. can't be bigger than 64k
if (uncompressedLen > 131072) {
if (++dos > 1) break;
uncompressedLen = 131072;
}
}
else {
// something bad happened
throw Error(14);
}
}
while (zlibResult == Z_BUF_ERROR);
if (zlibResult != Z_OK) {
throw Error(14);
}
}
void PngImage::printStructure(std::ostream& out, PrintStructureOption option, int /*depth*/)
{ {
if (io_->open() != 0) { if (io_->open() != 0) {
throw Error(9, io_->path(), strError()); throw Error(9, io_->path(), strError());
@ -104,7 +146,7 @@ namespace Exiv2 {
throw Error(3, "PNG"); throw Error(3, "PNG");
} }
if ( option == kpsIccProfile || option == kpsRecursive ) { if ( option == kpsRecursive || option == kpsIccProfile ) { // disable kpsIccProfile because decompress isn't working!
throw Error(13, io_->path()); throw Error(13, io_->path());
} }
@ -112,7 +154,7 @@ namespace Exiv2 {
chType[0]=0; chType[0]=0;
chType[4]=0; chType[4]=0;
if ( option == kpsBasic || option == kpsXMP ) { if ( option == kpsBasic || option == kpsXMP || option == kpsIccProfile ) {
if ( option == kpsBasic ) { if ( option == kpsBasic ) {
out << "STRUCTURE OF PNG FILE: " << io_->path() << std::endl; out << "STRUCTURE OF PNG FILE: " << io_->path() << std::endl;
@ -154,24 +196,38 @@ namespace Exiv2 {
} }
if ( option == kpsBasic ) out << Internal::stringFormat("%8d | %5d | %10s |%8d | ",(uint32_t)address, index++,chType,dOff) << dataString << std::endl; if ( option == kpsBasic ) out << Internal::stringFormat("%8d | %5d | %10s |%8d | ",(uint32_t)address, index++,chType,dOff) << dataString << std::endl;
// for XMP, back up and read the whole block
// for XMP and ICC, back up and read the whole block
const char* key = "XML:com.adobe.xmp" ; const char* key = "XML:com.adobe.xmp" ;
size_t start = ::strlen(key); size_t start = ::strlen(key);
if ( option == kpsXMP && dataString.find(key)==0 ) { if( (option == kpsXMP && dataString.find(key)==0)
|| (option == kpsIccProfile && std::strcmp(chType,"iCCP")==0)
){
#if defined(_MSC_VER) #if defined(_MSC_VER)
io_->seek(-static_cast<int64_t>(blen) , BasicIo::cur); io_->seek(-static_cast<int64_t>(blen) , BasicIo::cur);
#else #else
io_->seek(-static_cast<long>(blen) , BasicIo::cur); io_->seek(-static_cast<long>(blen) , BasicIo::cur);
#endif #endif
dataOffset = dOff ; dataOffset = dOff ;
byte* xmp = new byte[dataOffset+5]; if ( option == kpsXMP ) {
io_->read(xmp,dataOffset+4); byte* xmp = new byte[dataOffset+5];
xmp[dataOffset]=0; io_->read(xmp,dataOffset+4);
while ( xmp[start] == 0 ) start++; // crawl over the '\0' bytes between XML:....\0\0<xml stuff xmp[dataOffset]=0;
out << xmp+start; // output the xml while ( xmp[start] == 0 ) start++; // crawl over the '\0' bytes between XML:....\0\0<xml stuff
delete [] xmp; out << xmp+start; // output the xml
dataOffset = 0; delete [] xmp;
dataOffset = 0; // we've read the data, so don't seek past the block
} else if ( option == kpsIccProfile ) {
byte* icc = new byte[dataOffset];
io_->read(icc,dataOffset);
DataBuf decompressed;
size_t name_l = std::strlen((const char*)icc)+1; // length of profile name
zlibUncompress(icc+name_l,dataOffset-name_l,decompressed);
out.write((const char*)decompressed.pData_,decompressed.size_);
delete [] icc;
dataOffset = 0;
}
} }
if ( dataOffset ) io_->seek(dataOffset + 4 , BasicIo::cur); if ( dataOffset ) io_->seek(dataOffset + 4 , BasicIo::cur);

@ -85,6 +85,7 @@ namespace Exiv2 {
{ exifId, "Exif", "Photo", exifTagList }, { exifId, "Exif", "Photo", exifTagList },
{ gpsId, "GPSInfo", "GPSInfo", gpsTagList }, { gpsId, "GPSInfo", "GPSInfo", gpsTagList },
{ iopId, "Iop", "Iop", iopTagList }, { iopId, "Iop", "Iop", iopTagList },
{ mpfId, "MPF", "MPF", mpfTagList },
{ subImage1Id, "SubImage1", "SubImage1", ifdTagList }, { subImage1Id, "SubImage1", "SubImage1", ifdTagList },
{ subImage2Id, "SubImage2", "SubImage2", ifdTagList }, { subImage2Id, "SubImage2", "SubImage2", ifdTagList },
{ subImage3Id, "SubImage3", "SubImage3", ifdTagList }, { subImage3Id, "SubImage3", "SubImage3", ifdTagList },
@ -2118,11 +2119,81 @@ namespace Exiv2 {
iopId, iopTags, asciiString, -1, printValue) iopId, iopTags, asciiString, -1, printValue)
}; };
// MPF Tags http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
static const TagInfo mpfTagInfo[] = {
TagInfo(0xb000, "MPFVersion", N_("MPFVersion"),
N_("MPF Version"),
mpfId, iopTags, asciiString, 0, printValue),
TagInfo(0xb001, "MPFNumberOfImages", N_("MPFNumberOfImages"),
N_("MPF Number of Images"),
mpfId, iopTags, undefined, -1, printExifVersion),
TagInfo(0xb002, "MPFImageList", N_("MPFImageList"),
N_("MPF Image List"),
mpfId, iopTags, asciiString, 0, printValue),
TagInfo(0xb003, "MPFImageUIDList", N_("MPFImageUIDList "),
N_("MPF Image UID List"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb004, "MPFTotalFrames", N_("MPFTotalFrames"),
N_("MPF Total Frames"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb101, "MPFIndividualNum", N_("MPFIndividualNum"),
N_("MPF Individual Num"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb201, "MPFPanOrientation", N_("MPFPanOrientation"),
N_("MPFPanOrientation"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb202, "MPFPanOverlapH", N_("MPFPanOverlapH"),
N_("MPF Pan Overlap Horizonal"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb203, "MPFPanOverlapV", N_("MPFPanOverlapV"),
N_("MPF Pan Overlap Vertical"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb204, "MPFBaseViewpointNum", N_("MPFBaseViewpointNum"),
N_("MPF Base Viewpoint Number"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb205, "MPFConvergenceAngle", N_("MPFConvergenceAngle"),
N_("MPF Convergence Angle"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb206, "MPFBaselineLength", N_("MPFBaselineLength"),
N_("MPF Baseline Length"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb207, "MPFVerticalDivergence", N_("MPFVerticalDivergence"),
N_("MPF Vertical Divergence"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb208, "MPFAxisDistanceX", N_("MPFAxisDistanceX"),
N_("MPF Axis Distance X"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb209, "MPFAxisDistanceY", N_("MPFAxisDistanceY"),
N_("MPF Axis Distance Y"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb20a, "MPFAxisDistanceZ", N_("MPFAxisDistanceZ"),
N_("MPF Axis Distance Z"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb20b, "MPFYawAngle", N_("MPFYawAngle"),
N_("MPF Yaw Angle"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb20c, "MPFPitchAngle", N_("MPFPitchAngle"),
N_("MPF Pitch Angle"),
mpfId, iopTags, unsignedLong, 1, printValue),
TagInfo(0xb20d, "MPFRollAngle", N_("MPFRollAngle"),
N_("MPF Roll Angle"),
mpfId, iopTags, unsignedLong, 1, printValue),
// End of list marker
TagInfo(0xffff, "(UnknownIopTag)", N_("Unknown MPF tag"),
N_("Unknown MPF tag"),
mpfId, iopTags, asciiString, -1, printValue)
};
const TagInfo* iopTagList() const TagInfo* iopTagList()
{ {
return iopTagInfo; return iopTagInfo;
} }
const TagInfo* mpfTagList()
{
return mpfTagInfo;
}
// Synthesized Exiv2 Makernote info Tags (read-only) // Synthesized Exiv2 Makernote info Tags (read-only)
static const TagInfo mnTagInfo[] = { static const TagInfo mnTagInfo[] = {
TagInfo(0x0001, "Offset", N_("Offset"), TagInfo(0x0001, "Offset", N_("Offset"),

@ -62,6 +62,7 @@ namespace Exiv2 {
exifId, exifId,
gpsId, gpsId,
iopId, iopId,
mpfId,
subImage1Id, subImage1Id,
subImage2Id, subImage2Id,
subImage3Id, subImage3Id,
@ -304,6 +305,8 @@ namespace Exiv2 {
const TagInfo* gpsTagList(); const TagInfo* gpsTagList();
//! Return read-only list of built-in Exiv2 Makernote info tags //! Return read-only list of built-in Exiv2 Makernote info tags
const TagInfo* mnTagList(); const TagInfo* mnTagList();
//! Return read-only list of built-in mfp Tags http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
const TagInfo* mpfTagList();
//! Return the group id for a group name //! Return the group id for a group name
IfdId groupId(const std::string& groupName); IfdId groupId(const std::string& groupName);

@ -393,6 +393,7 @@ namespace Exiv2 {
for (ti = Exiv2:: gpsTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; for (ti = Exiv2:: gpsTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
for (ti = Exiv2:: ifdTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; for (ti = Exiv2:: ifdTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
for (ti = Exiv2::exifTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; for (ti = Exiv2::exifTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
for (ti = Exiv2:: mpfTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
} }
init = false; init = false;
@ -446,7 +447,14 @@ namespace Exiv2 {
#define MIN(a,b) ((a)<(b))?(b):(a) #define MIN(a,b) ((a)<(b))?(b):(a)
void TiffImage::printStructure(std::ostream& out, Exiv2::PrintStructureOption option) static std::string indent(int depth)
{
std::string result;
while ( depth -- ) result += " ";
return result;
}
void TiffImage::printStructure(std::ostream& out, Exiv2::PrintStructureOption option,int depth)
{ {
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
@ -455,113 +463,138 @@ namespace Exiv2 {
throw Error(15); throw Error(15);
} }
if ( option == kpsIccProfile || option == kpsRecursive ) { if ( option == kpsIccProfile ) {
throw Error(13, io_->path()); throw Error(13, io_->path());
}
io_->seek(0,BasicIo::beg);
printTiffStructure(io(),out,option,depth-1);
}
void TiffImage::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,size_t start,bool bSwap,char c,int depth)
{
depth++;
if ( option == kpsBasic || option == kpsRecursive ) {
out << indent(depth) << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ",c,c) << io.path() << std::endl;
out << indent(depth) << " address | tag | type | count | offset | value\n";
} }
// buffer
const size_t dirSize = 32;
DataBuf dir(dirSize);
while ( start ) {
// if ( option == kpsBasic ) out << Internal::stringFormat("bSwap, start = %d %u\n",bSwap,offset);
// Read top of directory
io.seek(start,BasicIo::beg);
io.read(dir.pData_, 2);
uint16_t dirLength = byteSwap2(dir,0,bSwap);
// Read the dictionary
for ( int i = 0 ; i < dirLength ; i ++ ) {
io.read(dir.pData_, 12);
uint16_t tag = byteSwap2(dir,0,bSwap);
uint16_t type = byteSwap2(dir,2,bSwap);
uint32_t count = byteSwap4(dir,4,bSwap);
uint32_t offset = byteSwap4(dir,8,bSwap);
std::string sp = "" ; // output spacer
//prepare to print the value
uint16_t kount = isPrintXMP(tag,option) ? count // restrict long arrays
: isStringType(type) ? (count > 32 ? 32 : count)
: count > 5 ? 5
: count
;
uint32_t pad = isStringType(type) ? 1 : 0;
uint32_t size = isStringType(type) ? 1
: is2ByteType(type) ? 2
: is4ByteType(type) ? 4
: 1
;
uint32_t Offset = 0 ; // used by ExifTag == 0x8769 && MakerNote == 0x927c to locate an FID
// if ( offset > io.size() ) offset = 0;
DataBuf buf(MIN(size*kount + pad,48)); // allocate a buffer
if ( isStringType(type) || count*size > 4 ) { // data is in the directory => read into buffer
size_t restore = io.tell(); // save
io.seek(offset,BasicIo::beg); // position
io.read(buf.pData_,kount*size);// read
io.seek(restore,BasicIo::beg); // restore
} else { // move data from directory to the buffer
std::memcpy(buf.pData_,dir.pData_+8,12);
}
if ( option == kpsBasic || option == kpsRecursive ) {
uint32_t address = start + 2 + i*12 ;
out << indent(depth) << Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%9u | ",address,tag,tagName(tag,25),typeName(type),count,offset);
if ( isShortType(type) ){
for ( uint16_t k = 0 ; k < kount ; k++ ) {
out << sp << byteSwap2(buf,k*size,bSwap);
sp = " ";
}
} else if ( isLongType(type) ){
for ( uint16_t k = 0 ; k < kount ; k++ ) {
out << sp << byteSwap4(buf,k*size,bSwap);
if ( k == 0 ) Offset = byteSwap4(buf,k*size,bSwap) ;
sp = " ";
}
} else if ( isRationalType(type) ){
for ( uint16_t k = 0 ; k < kount ; k++ ) {
uint16_t a = byteSwap2(buf,k*size+0,bSwap);
uint16_t b = byteSwap2(buf,k*size+2,bSwap);
if ( isLittleEndian() ) {
if ( bSwap ) out << sp << b << "/" << a;
else out << sp << a << "/" << b;
} else {
if ( bSwap ) out << sp << a << "/" << b;
else out << sp << b << "/" << a;
}
sp = " ";
}
} else if ( isStringType(type) ) {
out << sp << Internal::binaryToString(buf, kount);
}
sp = kount == count ? "" : " ...";
out << sp << std::endl;
if ( option == kpsRecursive
&& (tag == 0x8769 /* ExifTag */ || tag == 0x927c /* MakerNote */)
){
size_t restore = io.tell();
printIFDStructure(io,out,option,Offset,bSwap,c,depth);
io.seek(restore,BasicIo::beg);
}
}
if ( option == kpsBasic || option == kpsXMP ) { if ( isPrintXMP(tag,option) ) {
io_->seek(0,BasicIo::beg); buf.pData_[count]=0;
out << (char*) buf.pData_;
}
}
io.read(dir.pData_, 4);
start = byteSwap4(dir,0,bSwap);
out.flush();
} // while start
depth--;
}
void TiffImage::printTiffStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,int depth)
{
if ( option == kpsBasic || option == kpsXMP || option == kpsRecursive ) {
// buffer // buffer
const size_t dirSize = 32; const size_t dirSize = 32;
DataBuf dir(dirSize); DataBuf dir(dirSize);
// read header (we already know for certain that we have a Tiff file) // read header (we already know for certain that we have a Tiff file)
io_->read(dir.pData_, 8); io.read(dir.pData_, 8);
char c = (char) dir.pData_[0] ; char c = (char) dir.pData_[0] ;
bool bSwap = ( c == 'M' && isLittleEndian() ) bool bSwap = ( c == 'M' && isLittleEndian() )
|| ( c == 'I' && isBigEndian() ) || ( c == 'I' && isBigEndian() )
; ;
if ( option == kpsBasic ) {
out << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ",c,c) << io_->path() << std::endl;
out << " address | tag | type | count | offset | value\n";
}
uint32_t start = byteSwap4(dir,4,bSwap); uint32_t start = byteSwap4(dir,4,bSwap);
while ( start ) { printIFDStructure(io,out,option,start,bSwap,c,depth);
// if ( option == kpsBasic ) out << Internal::stringFormat("bSwap, start = %d %u\n",bSwap,offset);
// Read top of directory
io_->seek(start,BasicIo::beg);
io_->read(dir.pData_, 2);
uint16_t dirLength = byteSwap2(dir,0,bSwap);
// Read the dictionary
for ( int i = 0 ; i < dirLength ; i ++ ) {
io_->read(dir.pData_, 12);
uint16_t tag = byteSwap2(dir,0,bSwap);
uint16_t type = byteSwap2(dir,2,bSwap);
uint32_t count = byteSwap4(dir,4,bSwap);
uint32_t offset = byteSwap4(dir,8,bSwap);
std::string sp = "" ; // output spacer
//prepare to print the value
uint16_t kount = isPrintXMP(tag,option) ? count // restrict long arrays
: isStringType(type) ? (count > 32 ? 32 : count)
: count > 5 ? 5
: count
;
uint32_t pad = isStringType(type) ? 1 : 0;
uint32_t size = isStringType(type) ? 1
: is2ByteType(type) ? 2
: is4ByteType(type) ? 4
: 1
;
DataBuf buf(MIN(size*kount + pad,48)); // allocate a buffer
if ( isStringType(type) || count*size > 4 ) { // data is in the directory => read into buffer
size_t restore = io_->tell(); // save
io_->seek(offset,BasicIo::beg); // position
io_->read(buf.pData_,kount*size);// read
io_->seek(restore,BasicIo::beg); // restore
} else { // move data from directory to the buffer
std::memcpy(buf.pData_,dir.pData_+8,12);
}
if ( option == kpsBasic ) {
uint32_t address = start + 2 + i*12 ;
out << Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%9u | ",address,tag,tagName(tag,25),typeName(type),count,offset);
if ( isShortType(type) ){
for ( uint16_t k = 0 ; k < kount ; k++ ) {
out << sp << byteSwap2(buf,k*size,bSwap);
sp = " ";
}
} else if ( isLongType(type) ){
for ( uint16_t k = 0 ; k < kount ; k++ ) {
out << sp << byteSwap4(buf,k*size,bSwap);
sp = " ";
}
} else if ( isRationalType(type) ){
for ( uint16_t k = 0 ; k < kount ; k++ ) {
uint16_t a = byteSwap2(buf,k*size+0,bSwap);
uint16_t b = byteSwap2(buf,k*size+2,bSwap);
if ( isLittleEndian() ) {
if ( bSwap ) out << sp << b << "/" << a;
else out << sp << a << "/" << b;
} else {
if ( bSwap ) out << sp << a << "/" << b;
else out << sp << b << "/" << a;
}
sp = " ";
}
} else if ( isStringType(type) ) {
out << sp << Internal::binaryToString(buf, kount);
}
sp = kount == count ? "" : " ...";
out << sp << std::endl;
}
if ( isPrintXMP(tag,option) ) {
buf.pData_[count]=0;
out << (char*) buf.pData_;
}
}
io_->read(dir.pData_, 4);
start = byteSwap4(dir,0,bSwap);
} // while offset
} }
} }

Loading…
Cancel
Save