#922 -pS and -pX support for TIFF. Added formatters to Image class and use them from {jpg/png/tiff}image.cpp
This commit is contained in:
parent
23de41d333
commit
40ffba6033
@ -412,6 +412,16 @@ namespace Exiv2 {
|
||||
bool writeXmpFromPacket() const;
|
||||
//! Return list of native previews. This is meant to be used only by the PreviewManager.
|
||||
const NativePreviewList& nativePreviews() const;
|
||||
/*!
|
||||
@brief format a string in the pattern of \em sprintf \em .
|
||||
*/
|
||||
std::string stringFormat(const std::string fmt, ...) const;
|
||||
|
||||
/*!
|
||||
@brief format binary for display in \em printStructure() \em .
|
||||
*/
|
||||
std::string binaryToString(DataBuf& buf,size_t size,size_t start=0) const;
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
@ -351,6 +351,47 @@ namespace Exiv2 {
|
||||
return ImageFactory::checkMode(imageType_, metadataId);
|
||||
}
|
||||
|
||||
std::string Image::stringFormat(const std::string fmt, ...) const
|
||||
{
|
||||
std::string result;
|
||||
|
||||
int need = fmt.size()*4; // initial guess
|
||||
char* buffer = new char[need]; // allocate a buffer
|
||||
va_list ap; // variable arg list
|
||||
|
||||
va_start(ap, fmt);
|
||||
need=vsnprintf(buffer, need, fmt.c_str(), ap);
|
||||
va_end(ap);
|
||||
|
||||
if (need < 0) { // make buffer bigger
|
||||
delete[] buffer;
|
||||
buffer = new char[need+2];
|
||||
va_start(ap, fmt);
|
||||
need=vsnprintf(buffer, need, fmt.c_str(), ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
if ( need > 0 ) result = std::string(buffer) ;
|
||||
|
||||
delete[] buffer; // free buffer
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Image::binaryToString(DataBuf& buf,size_t size,size_t start /* = 0 */) const
|
||||
{
|
||||
std::string result = "";
|
||||
byte* buff = buf.pData_;
|
||||
|
||||
size += start;
|
||||
|
||||
while (start < size) {
|
||||
int c = (int) buff[start++] ;
|
||||
if (c < ' ' || c > 127) c = '.' ;
|
||||
result += (char) c ;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
AccessMode ImageFactory::checkMode(int type, MetadataId metadataId)
|
||||
{
|
||||
const Registry* r = find(registry, type);
|
||||
|
||||
101
src/jpgimage.cpp
101
src/jpgimage.cpp
@ -509,13 +509,13 @@ namespace Exiv2 {
|
||||
|
||||
bool isBlank(std::string& s)
|
||||
{
|
||||
for ( std::size_t i = 0 ; i < s.length() ; i++ )
|
||||
if ( s[i] != ' ' )
|
||||
return false ;
|
||||
return true ;
|
||||
for ( std::size_t i = 0 ; i < s.length() ; i++ )
|
||||
if ( s[i] != ' ' )
|
||||
return false ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
#define REPORT_MARKER if ( option == kpsBasic ) { sprintf(sbuff,"%8ld | %#02x %-5s",io_->tell(), marker,nm[marker].c_str()); out << sbuff; }
|
||||
#define REPORT_MARKER if ( option == kpsBasic ) out << stringFormat("%8ld | %#02x %-5s",io_->tell(), marker,nm[marker].c_str())
|
||||
|
||||
void JpegBase::printStructure(std::ostream& out,printStructureOption_e option)
|
||||
{
|
||||
@ -527,9 +527,8 @@ namespace Exiv2 {
|
||||
}
|
||||
|
||||
if ( option == kpsBasic || option == kpsXMP ) {
|
||||
char sbuff[80];
|
||||
|
||||
// nemonic for markers
|
||||
// nmonic for markers
|
||||
std::string nm[256] ;
|
||||
nm[0xd8]="SOI" ;
|
||||
nm[0xd9]="EOI" ;
|
||||
@ -554,9 +553,8 @@ namespace Exiv2 {
|
||||
// Container for the signature
|
||||
bool bExtXMP = false;
|
||||
long bufRead = 0;
|
||||
long startSig = 0;
|
||||
const long bufMinSize = 36;
|
||||
DataBuf buf(bufMinSize);
|
||||
DataBuf buf(bufMinSize);
|
||||
|
||||
// Read section marker
|
||||
int marker = advanceToMarker();
|
||||
@ -566,12 +564,12 @@ namespace Exiv2 {
|
||||
bool first= true;
|
||||
while (!done) {
|
||||
// print marker bytes
|
||||
if ( first && option == kpsBasic ) {
|
||||
if ( first && option == kpsBasic ) {
|
||||
out << "STRUCTURE OF JPEG FILE: " << io_->path() << std::endl;
|
||||
out << " address | marker | length | signature" << std::endl ;
|
||||
REPORT_MARKER;
|
||||
}
|
||||
first = false;
|
||||
out << " address | marker | length | data" << std::endl ;
|
||||
REPORT_MARKER;
|
||||
}
|
||||
first = false;
|
||||
|
||||
// Read size and signature
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
@ -579,7 +577,6 @@ namespace Exiv2 {
|
||||
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_)
|
||||
@ -591,16 +588,15 @@ namespace Exiv2 {
|
||||
|| marker == sos_
|
||||
){
|
||||
size = getUShort(buf.pData_, bigEndian);
|
||||
sprintf(sbuff," | %7d ", size);
|
||||
}
|
||||
if ( option == kpsBasic ) out << sbuff ;
|
||||
if ( option == kpsBasic ) out << stringFormat(" | %7d ", size);
|
||||
|
||||
// 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 ) {
|
||||
if ( option == kpsXMP && std::strcmp(http,"http") == 0 ) {
|
||||
// http://ns.adobe.com/xap/1.0/
|
||||
if ( size > 0 ) {
|
||||
io_->seek(-bufRead , BasicIo::cur);
|
||||
@ -613,53 +609,46 @@ namespace Exiv2 {
|
||||
// the first extended block is a copy of the Standard block.
|
||||
// a robust implementation enables extended blocks to be out of sequence
|
||||
if ( ! bExtXMP ) {
|
||||
while (xmp[start]) start++; start++;
|
||||
if ( ::strstr((char*)xmp+start,"HasExtendedXMP") ) {
|
||||
start = size ; // ignore this packet, we'll get on the next time around
|
||||
bExtXMP = true;
|
||||
}
|
||||
while (xmp[start]) start++; start++;
|
||||
if ( ::strstr((char*)xmp+start,"HasExtendedXMP") ) {
|
||||
start = size ; // ignore this packet, we'll get on the next time around
|
||||
bExtXMP = true;
|
||||
}
|
||||
} else {
|
||||
start = 2+35+32+4+4; // Adobe Spec, p19
|
||||
start = 2+35+32+4+4; // Adobe Spec, p19
|
||||
}
|
||||
xmp[size]=0;
|
||||
|
||||
// #922: Remove blank lines.
|
||||
#if 1
|
||||
out << xmp + start; // this is all we need to output without the blank line dance.
|
||||
#else
|
||||
// #922: Remove blank lines.
|
||||
// cut the xmp into (non blank) lines
|
||||
// out << xmp + start; // this is all we need to output without the blank line dance.
|
||||
std::vector<std::string> lines ;
|
||||
std::string s((char*)xmp+start);
|
||||
char nl = '\n';
|
||||
|
||||
while( s.length() )
|
||||
{
|
||||
std::size_t end = s.find(nl);
|
||||
if ( end != std::string::npos )
|
||||
{
|
||||
std::string line = s.substr(0,end);
|
||||
if ( !isBlank(line) )
|
||||
lines.push_back(line+nl);
|
||||
s = s.substr(end+1,std::string::npos);
|
||||
} else {
|
||||
lines.push_back(s);
|
||||
s="";
|
||||
}
|
||||
}
|
||||
for ( size_t l = 0 ; l < lines.size() ; l++ ) out << lines[l];
|
||||
|
||||
{
|
||||
std::size_t end = s.find(nl);
|
||||
if ( end != std::string::npos )
|
||||
{
|
||||
std::string line = s.substr(0,end);
|
||||
if ( !isBlank(line) )
|
||||
lines.push_back(line+nl);
|
||||
s = s.substr(end+1,std::string::npos);
|
||||
} else {
|
||||
lines.push_back(s);
|
||||
s="";
|
||||
}
|
||||
}
|
||||
for ( size_t l = 0 ; l < lines.size() ; l++ ) out << lines[l];
|
||||
#endif
|
||||
delete [] xmp;
|
||||
bufRead = size;
|
||||
}
|
||||
} else if ( option == kpsBasic ) {
|
||||
startSig = size>0?2:0;
|
||||
int endSig = size?size:bufRead;
|
||||
if (endSig > 32) endSig = 32 ;
|
||||
out << "| ";
|
||||
while (startSig++ < endSig ) {
|
||||
byte c = buf.pData_[startSig-1] ;
|
||||
c = (' '<=c && c<128) ? c : '.' ;
|
||||
out << (char) c ;
|
||||
// else endSig = startSig;
|
||||
}
|
||||
out << "| " << binaryToString(buf,32,size>0?2:0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -670,14 +659,14 @@ namespace Exiv2 {
|
||||
|
||||
if (marker == sos_)
|
||||
// sos_ is immediately followed by entropy-coded data & eoi_
|
||||
done = true;
|
||||
done = true;
|
||||
else {
|
||||
// Read the beginning of the next segment
|
||||
marker = advanceToMarker();
|
||||
REPORT_MARKER;
|
||||
// Read the beginning of the next segment
|
||||
marker = advanceToMarker();
|
||||
REPORT_MARKER;
|
||||
if ( marker == eoi_ ) {
|
||||
if ( option == kpsBasic ) out << std::endl;
|
||||
done = true;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,13 +109,18 @@ namespace Exiv2 {
|
||||
|
||||
if ( option == kpsBasic || option == kpsXMP ) {
|
||||
|
||||
if ( option == kpsBasic ) out << "index | chunk_type | length | data" << std::endl;
|
||||
if ( option == kpsBasic ) {
|
||||
out << "STRUCTURE OF PNG FILE: " << io_->path() << std::endl;
|
||||
out << " address | index | chunk_type | length | data" << std::endl;
|
||||
}
|
||||
|
||||
long index = 0;
|
||||
const long imgSize = io_->size();
|
||||
DataBuf cheaderBuf(8);
|
||||
|
||||
while( !io_->eof() && ::strcmp(chType,"IEND") ) {
|
||||
size_t address = io_->tell();
|
||||
|
||||
std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_);
|
||||
long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_);
|
||||
if (io_->error()) throw Error(14);
|
||||
@ -132,31 +137,24 @@ namespace Exiv2 {
|
||||
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;
|
||||
size_t blen = 32 ;
|
||||
size_t dOff = dataOffset;
|
||||
std::string dataString ;
|
||||
|
||||
if ( dataOffset > blen ) {
|
||||
io_->read(buff,blen);
|
||||
DataBuf buff(blen+1);
|
||||
io_->read(buff.pData_,blen);
|
||||
dataOffset -= blen ;
|
||||
for ( size_t i = 0 ; i < blen ; i++ ) {
|
||||
int c = buff[i] ;
|
||||
buff[i] = (' '<=c && c<128) ? c : '.' ;
|
||||
}
|
||||
dataString = binaryToString(buff,blen);
|
||||
}
|
||||
|
||||
char sbuff[80];
|
||||
sprintf(sbuff,"%5ld %12s %8lu %s\n", index++,chType,dOff,buff);
|
||||
if ( option == kpsBasic ) out << sbuff;
|
||||
if ( option == kpsBasic ) out << stringFormat("%8llu | %5ld | %10s |%8lu | ",address, index++,chType,dOff) << dataString << std::endl;
|
||||
|
||||
// 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 ) {
|
||||
|
||||
if ( option == kpsXMP && dataString.find(key)==0 ) {
|
||||
#if defined(_MSC_VER)
|
||||
io_->seek(-static_cast<int64_t>(blen) , BasicIo::cur);
|
||||
#else
|
||||
@ -166,8 +164,8 @@ namespace Exiv2 {
|
||||
byte* xmp = new byte[dataOffset+5];
|
||||
io_->read(xmp,dataOffset+4);
|
||||
xmp[dataOffset]=0;
|
||||
while ( xmp[start] == 0 ) start++;
|
||||
out << xmp+start << std::endl;
|
||||
while ( xmp[start] == 0 ) start++; // crawl over the '\0' bytes between XML:....\0\0<xml stuff
|
||||
out << xmp+start; // output the xml
|
||||
delete [] xmp;
|
||||
dataOffset = 0;
|
||||
}
|
||||
|
||||
@ -323,138 +323,113 @@ namespace Exiv2 {
|
||||
|
||||
static uint16_t byteSwap2(DataBuf& buf,size_t offset,bool bSwap)
|
||||
{
|
||||
uint16_t v;
|
||||
char* p = (char*) &v;
|
||||
p[0] = buf.pData_[offset];
|
||||
p[1] = buf.pData_[offset+1];
|
||||
return byteSwap(v,bSwap);
|
||||
uint16_t v;
|
||||
char* p = (char*) &v;
|
||||
p[0] = buf.pData_[offset];
|
||||
p[1] = buf.pData_[offset+1];
|
||||
return byteSwap(v,bSwap);
|
||||
}
|
||||
|
||||
static uint32_t byteSwap4(DataBuf& buf,size_t offset,bool bSwap)
|
||||
{
|
||||
uint32_t v;
|
||||
char* p = (char*) &v;
|
||||
p[0] = buf.pData_[offset];
|
||||
p[1] = buf.pData_[offset+1];
|
||||
p[2] = buf.pData_[offset+2];
|
||||
p[3] = buf.pData_[offset+3];
|
||||
return byteSwap(v,bSwap);
|
||||
uint32_t v;
|
||||
char* p = (char*) &v;
|
||||
p[0] = buf.pData_[offset];
|
||||
p[1] = buf.pData_[offset+1];
|
||||
p[2] = buf.pData_[offset+2];
|
||||
p[3] = buf.pData_[offset+3];
|
||||
return byteSwap(v,bSwap);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf
|
||||
static std::string stringFormat(const std::string fmt_str, ...) {
|
||||
int n = ((int)fmt_str.size()) * 2; /* Reserve two times as much as the length of the fmt_str */
|
||||
char* formatted;
|
||||
std::string str;
|
||||
va_list ap;
|
||||
bool ok = true;
|
||||
do {
|
||||
formatted = new char[n];
|
||||
strcpy(&formatted[0], fmt_str.c_str());
|
||||
va_start(ap, fmt_str);
|
||||
int final = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
|
||||
va_end(ap);
|
||||
ok = final < 0 || final >= n;
|
||||
if (ok) {
|
||||
n += abs(final - n + 1);
|
||||
}
|
||||
else {
|
||||
str = std::string(formatted);
|
||||
}
|
||||
delete[] formatted;
|
||||
} while (ok);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string stringValue(byte* buff,size_t size)
|
||||
{
|
||||
std::string result = "";
|
||||
size_t start = 0 ;
|
||||
bool bLong = size > 32;
|
||||
if ( bLong ) size = 32 ;
|
||||
|
||||
while (start < size ) {
|
||||
int c = (int) buff[start++] ;
|
||||
if (c < ' ' || c > 127) c = '.' ;
|
||||
result += (char) c ;
|
||||
}
|
||||
return result + (bLong ? " ..." : "") ;
|
||||
}
|
||||
|
||||
std::string rationalValue(byte* buff,size_t size)
|
||||
{
|
||||
std::string result = "";
|
||||
size_t start = 0 ;
|
||||
if (size > 32) size = 32 ;
|
||||
|
||||
while (start < size ) {
|
||||
int c = (int) buff[start++] ;
|
||||
if (c < ' ' || c > 127) c = '.' ;
|
||||
result += (char) c ;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* typeName(uint16_t tag)
|
||||
{
|
||||
//! List of TIFF image tags
|
||||
const char* result = NULL;
|
||||
switch (tag ) {
|
||||
case 1 : result = "BYTE" ; break;
|
||||
case 2 : result = "ASCII" ; break;
|
||||
case 3 : result = "SHORT" ; break;
|
||||
case 4 : result = "LONG" ; break;
|
||||
case 5 : result = "RATIONAL" ; break;
|
||||
case 6 : result = "SBYTE" ; break;
|
||||
case 7 : result = "UNDEFINED" ; break;
|
||||
case 8 : result = "SSHORT" ; break;
|
||||
case 9 : result = "SLONG" ; break;
|
||||
case 10 : result = "SRATIONAL" ; break;
|
||||
case 11 : result = "FLOAT" ; break;
|
||||
case 12 : result = "DOUBLE" ; break;
|
||||
default : result = "unknown" ; break;
|
||||
const char* result = NULL;
|
||||
switch (tag ) {
|
||||
case Exiv2::unsignedByte : result = "BYTE" ; break;
|
||||
case Exiv2::asciiString : result = "ASCII" ; break;
|
||||
case Exiv2::unsignedShort : result = "SHORT" ; break;
|
||||
case Exiv2::unsignedLong : result = "LONG" ; break;
|
||||
case Exiv2::unsignedRational : result = "RATIONAL" ; break;
|
||||
case Exiv2::signedByte : result = "SBYTE" ; break;
|
||||
case Exiv2::undefined : result = "UNDEFINED" ; break;
|
||||
case Exiv2::signedShort : result = "SSHORT" ; break;
|
||||
case Exiv2::signedLong : result = "SLONG" ; break;
|
||||
case Exiv2::signedRational : result = "SRATIONAL" ; break;
|
||||
case Exiv2::tiffFloat : result = "FLOAT" ; break;
|
||||
case Exiv2::tiffDouble : result = "DOUBLE" ; break;
|
||||
default : result = "unknown" ; break;
|
||||
}
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* tagName(uint16_t tag,size_t nMaxLength)
|
||||
{
|
||||
const char* result = NULL;
|
||||
const char* result = NULL;
|
||||
|
||||
// build a static map of tags for fast search
|
||||
static std::map<int,std::string> tags;
|
||||
// build a static map of tags for fast search
|
||||
static std::map<int,std::string> tags;
|
||||
static bool init = true;
|
||||
static char buffer[80];
|
||||
|
||||
if ( init ) {
|
||||
int idx;
|
||||
int idx;
|
||||
const TagInfo* ti ;
|
||||
for (ti = Exiv2:: mnTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Exiv2:: iopTagList(), 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::exifTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Exiv2:: mnTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Exiv2:: iopTagList(), 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::exifTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
}
|
||||
init = false;
|
||||
|
||||
try {
|
||||
result = tags[tag].c_str();
|
||||
if ( nMaxLength > sizeof(buffer) )
|
||||
nMaxLength = sizeof(buffer) - 2;
|
||||
strncpy(buffer,result,nMaxLength);
|
||||
result = buffer;
|
||||
result = tags[tag].c_str();
|
||||
if ( nMaxLength > sizeof(buffer) -2 )
|
||||
nMaxLength = sizeof(buffer) -2;
|
||||
strncpy(buffer,result,nMaxLength);
|
||||
result = buffer;
|
||||
} catch ( ... ) {}
|
||||
|
||||
return result ;
|
||||
}
|
||||
|
||||
static bool isStringType(uint16_t type)
|
||||
{
|
||||
return type == Exiv2::asciiString
|
||||
|| type == Exiv2::unsignedByte
|
||||
|| type == Exiv2::signedByte
|
||||
;
|
||||
}
|
||||
static bool isStringType(uint16_t type)
|
||||
{
|
||||
return type == Exiv2::asciiString
|
||||
|| type == Exiv2::unsignedByte
|
||||
|| type == Exiv2::signedByte
|
||||
;
|
||||
}
|
||||
static bool isShortType(uint16_t type) {
|
||||
return type == Exiv2::unsignedShort
|
||||
|| type == Exiv2::signedShort
|
||||
;
|
||||
}
|
||||
static bool isLongType(uint16_t type) {
|
||||
return type == Exiv2::unsignedLong
|
||||
|| type == Exiv2::signedLong
|
||||
;
|
||||
}
|
||||
static bool isRationalType(uint16_t type) {
|
||||
return type == Exiv2::unsignedRational
|
||||
|| type == Exiv2::signedRational
|
||||
;
|
||||
}
|
||||
static bool is2ByteType(uint16_t type)
|
||||
{
|
||||
return isShortType(type);
|
||||
}
|
||||
static bool is4ByteType(uint16_t type)
|
||||
{
|
||||
return isLongType(type)
|
||||
|| isRationalType(type)
|
||||
;
|
||||
}
|
||||
static bool isPrintXMP(uint16_t type,Exiv2::printStructureOption_e option)
|
||||
{
|
||||
return type == 700 && option == kpsXMP;
|
||||
}
|
||||
|
||||
void TiffImage::printStructure(std::ostream& out,Exiv2::printStructureOption_e option)
|
||||
{
|
||||
@ -466,72 +441,100 @@ namespace Exiv2 {
|
||||
}
|
||||
|
||||
if ( option == kpsBasic || option == kpsXMP ) {
|
||||
io_->seek(0,BasicIo::beg);
|
||||
// buffer
|
||||
const size_t bufSize = 32;
|
||||
DataBuf buf(bufSize);
|
||||
io_->seek(0,BasicIo::beg);
|
||||
// buffer
|
||||
const size_t dirSize = 32;
|
||||
DataBuf dir(dirSize);
|
||||
|
||||
// read header (we already know for certain that we have a Tiff file)
|
||||
io_->read(buf.pData_, 8);
|
||||
// read header (we already know for certain that we have a Tiff file)
|
||||
io_->read(dir.pData_, 8);
|
||||
char c = (char) dir.pData_[0] ;
|
||||
#if __LITTLE_ENDIAN__
|
||||
bool bSwap = buf.pData_[0] == 'M';
|
||||
bool bSwap = c == 'M';
|
||||
#else
|
||||
bool bSwap = buf.pData_[0] == 'I';
|
||||
bool bSwap = c == 'I';
|
||||
#endif
|
||||
if ( option == kpsBasic ) {
|
||||
// out << string_format("count = %u\n",count);
|
||||
out << "STRUCTURE OF TIFF FILE: " << io_->path() << std::endl;
|
||||
out << " address | tag | type | count | offset | value\n";
|
||||
}
|
||||
if ( option == kpsBasic ) {
|
||||
out << stringFormat("STRUCTURE OF TIFF FILE (%c%c): ",c,c) << io_->path() << std::endl;
|
||||
out << " address | tag | type | count | offset | value\n";
|
||||
}
|
||||
|
||||
uint32_t offset = byteSwap4(buf,4,bSwap);
|
||||
while ( offset ) {
|
||||
// if ( option == kpsBasic ) out << stringFormat("bSwap, offset = %d %u\n",bSwap,offset);
|
||||
uint32_t start = byteSwap4(dir,4,bSwap);
|
||||
while ( start ) {
|
||||
// if ( option == kpsBasic ) out << stringFormat("bSwap, start = %d %u\n",bSwap,offset);
|
||||
|
||||
// Read top of dictionary
|
||||
io_->seek(offset,BasicIo::beg);
|
||||
io_->read(buf.pData_, 2);
|
||||
uint16_t count = byteSwap2(buf,0,bSwap);
|
||||
// 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 < count ; i ++ ) {
|
||||
io_->read(buf.pData_, 12);
|
||||
uint16_t Tag = byteSwap2(buf,0,bSwap);
|
||||
uint16_t Type = byteSwap2(buf,2,bSwap);
|
||||
uint32_t Count = byteSwap4(buf,4,bSwap);
|
||||
uint32_t Offset = byteSwap4(buf,8,bSwap);
|
||||
if ( option == kpsBasic ) {
|
||||
uint32_t address = offset + 2 + i*12 ;
|
||||
out << stringFormat("%8u | %#06x %-20s |%10s |%9u |%9u | ",address,Tag,tagName(Tag,20),typeName(Type),Count,Offset);
|
||||
if ( isStringType(Type) ) {
|
||||
size_t restore = io_->tell();
|
||||
io_->seek(Offset,BasicIo::beg);
|
||||
size_t size = Count > bufSize ? bufSize : Count;
|
||||
io_->read(buf.pData_,size );
|
||||
io_->seek(restore,BasicIo::beg);
|
||||
out << stringValue(buf.pData_,Count);
|
||||
} else if ( Count == 1 && Type == Exiv2::unsignedShort ) {
|
||||
out << byteSwap2(buf,8,bSwap);
|
||||
} else if ( Count == 1 && Type == Exiv2::unsignedLong ) {
|
||||
out << byteSwap2(buf,8,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);
|
||||
|
||||
out << std::endl;
|
||||
}
|
||||
if ( Tag == 700 ) {
|
||||
const long bSize = (long) Count;
|
||||
DataBuf buf(bSize+1);
|
||||
size_t restore = io_->tell();
|
||||
io_->seek(Offset,BasicIo::beg);
|
||||
io_->read(buf.pData_,bSize);
|
||||
io_->seek(restore,BasicIo::beg);
|
||||
buf.pData_[bSize]=0;
|
||||
if ( option == kpsXMP ) out << (char*) &buf.pData_[0];
|
||||
}
|
||||
}
|
||||
io_->read(buf.pData_, 4);
|
||||
offset = byteSwap4(buf,0,bSwap);
|
||||
} // while offset
|
||||
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
|
||||
;
|
||||
size_t pad = isStringType(type) ? 1 : 0;
|
||||
size_t size = isStringType(type) ? 1
|
||||
: is2ByteType(type) ? 2
|
||||
: is4ByteType(type) ? 4
|
||||
: 1
|
||||
;
|
||||
|
||||
DataBuf buf(size*kount + pad); // 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 << 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++ ) {
|
||||
out << sp << byteSwap2(buf,k*size+(bSwap?2:0),bSwap) << "/" << byteSwap2(buf,k*size+(bSwap?0:2),bSwap);
|
||||
sp = " ";
|
||||
}
|
||||
} else if ( isStringType(type) ) {
|
||||
out << sp << 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…
Reference in New Issue
Block a user