#1230 Fixes to read tiff with web-ready. Includes the BasicIo expiremental API readUnmarked() and markRead() which I will remove later.
This commit is contained in:
parent
cdb5eecc6b
commit
f5956d5db2
@ -18,13 +18,9 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*!
|
||||
@file basicio.hpp
|
||||
@brief Simple binary IO abstraction
|
||||
@version $Rev: 3091 $
|
||||
@author Brad Schick (brad)
|
||||
<a href="mailto:brad@robotbattle.com">brad@robotbattle.com</a>
|
||||
@date 04-Dec-04, brad: created
|
||||
/*
|
||||
File: basicio.hpp
|
||||
Version: $Rev: 4633 $
|
||||
*/
|
||||
#ifndef BASICIO_HPP_
|
||||
#define BASICIO_HPP_
|
||||
@ -97,6 +93,7 @@ namespace Exiv2 {
|
||||
Nonzero if failure.
|
||||
*/
|
||||
virtual int open() = 0;
|
||||
|
||||
/*!
|
||||
@brief Close the IO source. After closing a BasicIo instance can not
|
||||
be read or written. Closing flushes any unwritten data. It is
|
||||
@ -259,6 +256,18 @@ namespace Exiv2 {
|
||||
*/
|
||||
virtual BasicIo::AutoPtr temporary() const = 0;
|
||||
|
||||
/*!
|
||||
@brief markBlocks that we know for certain are not metadata
|
||||
@note This method is designed to enable TIFF files to mark StripOffsets/StringByteCounts
|
||||
*/
|
||||
virtual void markRead(long offset,long count);
|
||||
|
||||
/*!
|
||||
@brief read all blocks that are not marked
|
||||
@note This method is designed to enable TIFF file to read everything except the markRead blocks!
|
||||
*/
|
||||
virtual void readUnmarked();
|
||||
|
||||
/*!
|
||||
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory
|
||||
for parts of the file that contain image-date (non-metadata/pixel data)
|
||||
@ -945,6 +954,13 @@ namespace Exiv2 {
|
||||
Nonzero if failure.
|
||||
*/
|
||||
virtual int open();
|
||||
|
||||
virtual void markRead(long offset,long count);
|
||||
|
||||
virtual void readUnmarked();
|
||||
|
||||
byte* bigBlock_;
|
||||
|
||||
/*!
|
||||
@brief Reset the IO position to the start. It does not release the data.
|
||||
@return 0 if successful;<BR>
|
||||
@ -1097,6 +1113,7 @@ namespace Exiv2 {
|
||||
are all downloaded from the remote file to memory.
|
||||
*/
|
||||
virtual void populateFakeData();
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
@ -318,6 +318,42 @@ namespace Exiv2 {
|
||||
little-endian byte order (II) is used by default.
|
||||
*/
|
||||
void setByteOrder(ByteOrder byteOrder);
|
||||
|
||||
/*!
|
||||
@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).
|
||||
*/
|
||||
void printTiffStructure(BasicIo& io,std::ostream& out, PrintStructureOption option,int depth,size_t offset=0);
|
||||
|
||||
/*!
|
||||
@brief Print out the structure of a TIFF IFD
|
||||
*/
|
||||
void printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,uint32_t start,bool bSwap,char c,int depth);
|
||||
|
||||
/*!
|
||||
@brief is the host platform bigEndian
|
||||
*/
|
||||
bool isBigEndianPlatform();
|
||||
|
||||
/*!
|
||||
@brief is the host platform littleEndian
|
||||
*/
|
||||
bool isLittleEndianPlatform();
|
||||
bool isStringType(uint16_t type);
|
||||
bool isShortType(uint16_t type);
|
||||
bool isLongType(uint16_t type);
|
||||
bool isRationalType(uint16_t type);
|
||||
bool is2ByteType(uint16_t type);
|
||||
bool is4ByteType(uint16_t type);
|
||||
bool isPrintXMP(uint16_t type, Exiv2::PrintStructureOption option);
|
||||
bool isPrintICC(uint16_t type, Exiv2::PrintStructureOption option);
|
||||
|
||||
uint32_t byteSwap(uint32_t value,bool bSwap);
|
||||
uint16_t byteSwap(uint16_t value,bool bSwap);
|
||||
uint16_t byteSwap2(DataBuf& buf,size_t offset,bool bSwap);
|
||||
uint32_t byteSwap4(DataBuf& buf,size_t offset,bool bSwap);
|
||||
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
@ -452,6 +488,9 @@ namespace Exiv2 {
|
||||
int pixelHeight_; //!< image pixel height
|
||||
NativePreviewList nativePreviews_; //!< list of native previews
|
||||
|
||||
std::vector<long> stripOffsets; //!< StripOffset data
|
||||
std::vector<long> stripByteCounts ; //!< StripByteCount data
|
||||
|
||||
private:
|
||||
//! @name NOT implemented
|
||||
//@{
|
||||
|
||||
@ -18,14 +18,11 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*!
|
||||
@file tiffimage.hpp
|
||||
@brief Class TiffImage
|
||||
@version $Rev: 3090 $
|
||||
@author Andreas Huggel (ahu)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@date 15-Mar-06, ahu: created
|
||||
/*
|
||||
File: tiffimage.hpp
|
||||
Version: $Rev: 4633 $
|
||||
*/
|
||||
|
||||
#ifndef TIFFIMAGE_HPP_
|
||||
#define TIFFIMAGE_HPP_
|
||||
|
||||
@ -95,20 +92,6 @@ namespace Exiv2 {
|
||||
*/
|
||||
virtual 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,size_t offset=0);
|
||||
|
||||
/*!
|
||||
@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,uint32_t start,bool bSwap,char c,int depth);
|
||||
|
||||
/*!
|
||||
@brief Not supported. TIFF format does not contain a comment.
|
||||
Calling this function will throw an Error(32).
|
||||
|
||||
110
src/basicio.cpp
110
src/basicio.cpp
@ -21,8 +21,6 @@
|
||||
/*
|
||||
File: basicio.cpp
|
||||
Version: $Rev$
|
||||
Author(s): Brad Schick (brad) <brad@robotbattle.com>
|
||||
History: 04-Dec-04, brad: created
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid_int.hpp"
|
||||
@ -86,6 +84,10 @@ namespace Exiv2 {
|
||||
{
|
||||
}
|
||||
|
||||
void BasicIo::markRead(long /*offset*/,long /*count*/) { return ; }
|
||||
|
||||
void BasicIo::readUnmarked() { return ; }
|
||||
|
||||
//! Internal Pimpl structure of class FileIo.
|
||||
class FileIo::Impl {
|
||||
public:
|
||||
@ -620,25 +622,25 @@ namespace Exiv2 {
|
||||
|
||||
std::string FileIo::temporaryPath()
|
||||
{
|
||||
static int count = 0 ;
|
||||
char sCount[12];
|
||||
sprintf(sCount,"_%d",count++);
|
||||
static int count = 0 ;
|
||||
char sCount[12];
|
||||
sprintf(sCount,"_%d",count++);
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW__)
|
||||
char lpTempPathBuffer[MAX_PATH];
|
||||
GetTempPath(MAX_PATH,lpTempPathBuffer);
|
||||
std::string tmp(lpTempPathBuffer);
|
||||
tmp += "\\";
|
||||
GetTempPath(MAX_PATH,lpTempPathBuffer);
|
||||
std::string tmp(lpTempPathBuffer);
|
||||
tmp += "\\";
|
||||
#else
|
||||
std::string tmp = "/tmp/";
|
||||
std::string tmp = "/tmp/";
|
||||
#endif
|
||||
|
||||
pid_t pid = ::getpid();
|
||||
std::string result = tmp + toString(pid) + sCount ;
|
||||
if ( Exiv2::fileExists(result) ) std::remove(result.c_str());
|
||||
pid_t pid = ::getpid();
|
||||
std::string result = tmp + toString(pid) + sCount ;
|
||||
if ( Exiv2::fileExists(result) ) std::remove(result.c_str());
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
long FileIo::write(const byte* data, long wcount)
|
||||
{
|
||||
@ -1562,6 +1564,7 @@ namespace Exiv2 {
|
||||
bool isMalloced_; //!< Was the blocksMap_ allocated?
|
||||
bool eof_; //!< EOF indicator
|
||||
Protocol protocol_; //!< the protocol of url
|
||||
uint32_t totalRead_;
|
||||
|
||||
// METHODS
|
||||
/*!
|
||||
@ -1604,7 +1607,7 @@ namespace Exiv2 {
|
||||
|
||||
RemoteIo::Impl::Impl(const std::string& url, size_t blockSize)
|
||||
: path_(url), blockSize_(blockSize), blocksMap_(0), size_(0),
|
||||
idx_(0), isMalloced_(false), eof_(false), protocol_(fileProtocol(url))
|
||||
idx_(0), isMalloced_(false), eof_(false), protocol_(fileProtocol(url)),totalRead_(0)
|
||||
{
|
||||
}
|
||||
#ifdef EXV_UNICODE_PATH
|
||||
@ -1663,6 +1666,7 @@ namespace Exiv2 {
|
||||
int RemoteIo::open()
|
||||
{
|
||||
close(); // reset the IO position
|
||||
bigBlock_ = NULL;
|
||||
if (p_->isMalloced_ == false) {
|
||||
long length = p_->getFileLength();
|
||||
if (length < 0) { // unable to get the length of remote file, get the whole file content.
|
||||
@ -1693,12 +1697,68 @@ namespace Exiv2 {
|
||||
return 0; // means OK
|
||||
}
|
||||
|
||||
void RemoteIo::markRead(long offset,long count)
|
||||
{
|
||||
// std::cout << "RemoteIo::markRead offset = " << offset << " count = " << count << std::endl;
|
||||
int blockLow = (offset )/p_->blockSize_ ;
|
||||
int blockHigh = (offset + count )/p_->blockSize_ ;
|
||||
for ( int block = blockLow+1 ; block < blockHigh-1 ; block++ ) {
|
||||
p_->blocksMap_[block].markKnown(p_->blockSize_);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteIo::readUnmarked()
|
||||
{
|
||||
long blockSize = p_->blockSize_;
|
||||
int nBlocks = (p_->size_ + blockSize -1) / blockSize ;
|
||||
#ifdef DEBUG
|
||||
int nRead = 0;
|
||||
int nHigh = 0;
|
||||
int nGulp = 0;
|
||||
int nBytes = 0;
|
||||
for ( int block = 0 ; block < nBlocks ; block++ ) {
|
||||
if ( p_->blocksMap_[block].isNone() ) {
|
||||
nRead++ ;
|
||||
nHigh = block;
|
||||
}
|
||||
}
|
||||
std::cerr << "RemoteIo::readUnmarked nBlocks = " << nBlocks << " nRead = " << nRead << " nHigh = " << nHigh << std::endl;
|
||||
for ( int block = 0 ; block < nBlocks ; block ++ ) {
|
||||
char x = 'X';
|
||||
if ( p_->blocksMap_[block].isNone() ) x='.';
|
||||
if ( p_->blocksMap_[block].isInMem() ) x='R';
|
||||
if ( p_->blocksMap_[block].isKnown() ) x='-';
|
||||
std::cerr << x ;
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
for ( int block = 0 ; block < nBlocks ; block ++ ) {
|
||||
if ( p_->blocksMap_[block].isNone() ) {
|
||||
int b = block;
|
||||
if ( b < (nBlocks -1)) while ( p_->blocksMap_[b+1].isNone() && b < nBlocks ) b++;
|
||||
seek(block*blockSize,BasicIo::beg);
|
||||
read(blockSize);
|
||||
#ifdef DEBUG
|
||||
nBytes += blockSize*(b-block+1);
|
||||
nGulp ++ ;
|
||||
#endif
|
||||
block = b ;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::cerr << "RemoteIo::readUnmarked nGulp = " << nGulp << " nBytes = " << nBytes << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
int RemoteIo::close()
|
||||
{
|
||||
if (p_->isMalloced_) {
|
||||
p_->eof_ = false;
|
||||
p_->idx_ = 0;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::cerr << "RemoteIo::close totalRead_ = " << p_->totalRead_ << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1746,7 +1806,6 @@ namespace Exiv2 {
|
||||
blockIndex++;
|
||||
}
|
||||
|
||||
|
||||
// find $right
|
||||
findDiff = false;
|
||||
blockIndex = nBlocks - 1;
|
||||
@ -1802,6 +1861,7 @@ namespace Exiv2 {
|
||||
{
|
||||
assert(p_->isMalloced_);
|
||||
if (p_->eof_) return 0;
|
||||
p_->totalRead_ += rcount;
|
||||
|
||||
size_t allow = EXV_MIN(rcount, (long)( p_->size_ - p_->idx_));
|
||||
size_t lowBlock = p_->idx_ /p_->blockSize_;
|
||||
@ -1900,7 +1960,23 @@ namespace Exiv2 {
|
||||
|
||||
byte* RemoteIo::mmap(bool /*isWriteable*/)
|
||||
{
|
||||
return NULL;
|
||||
long nRealData = 0 ;
|
||||
if ( !bigBlock_ ) {
|
||||
int blockSize = p_->blockSize_;
|
||||
int blocks = (p_->size_ + blockSize -1)/blockSize ;
|
||||
bigBlock_ = new byte[blocks*blockSize] ;
|
||||
for ( int block = 0 ; block < blocks ; block ++ ) {
|
||||
void* p = p_->blocksMap_[block].getData();
|
||||
if ( p ) {
|
||||
nRealData += blockSize ;
|
||||
memcpy(bigBlock_+(block*blockSize),p,blockSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::cerr << "RemoteIo::mmap nRealData = " << nRealData << std::endl;
|
||||
#endif
|
||||
return bigBlock_;
|
||||
}
|
||||
|
||||
int RemoteIo::munmap()
|
||||
|
||||
@ -21,9 +21,6 @@
|
||||
/*
|
||||
File: cr2image.cpp
|
||||
Version: $Rev$
|
||||
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
|
||||
History: 22-Apr-06, ahu: created
|
||||
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid_int.hpp"
|
||||
@ -86,10 +83,9 @@ namespace Exiv2 {
|
||||
{
|
||||
if (io_->open() != 0) throw Error(9, io_->path(), strError());
|
||||
io_->seek(0,BasicIo::beg);
|
||||
TiffImage::printTiffStructure(io(),out,option,depth-1);
|
||||
printTiffStructure(io(),out,option,depth-1);
|
||||
}
|
||||
|
||||
|
||||
void Cr2Image::setComment(const std::string& /*comment*/)
|
||||
{
|
||||
// not supported
|
||||
|
||||
334
src/image.cpp
334
src/image.cpp
@ -44,6 +44,9 @@ EXIV2_RCSID("@(#) $Id$")
|
||||
#endif // EXV_HAVE_LIBZ
|
||||
#include "rafimage.hpp"
|
||||
#include "tiffimage.hpp"
|
||||
#include "tiffimage_int.hpp"
|
||||
#include "tiffcomposite_int.hpp"
|
||||
#include "tiffvisitor_int.hpp"
|
||||
#include "webpimage.hpp"
|
||||
#include "orfimage.hpp"
|
||||
#include "gifimage.hpp"
|
||||
@ -51,6 +54,8 @@ EXIV2_RCSID("@(#) $Id$")
|
||||
#include "tgaimage.hpp"
|
||||
#include "bmpimage.hpp"
|
||||
#include "jp2image.hpp"
|
||||
#include "nikonmn_int.hpp"
|
||||
|
||||
#ifdef EXV_ENABLE_VIDEO
|
||||
#include "matroskavideo.hpp"
|
||||
#include "quicktimevideo.hpp"
|
||||
@ -170,6 +175,335 @@ namespace Exiv2 {
|
||||
throw Error(13, io_->path());
|
||||
}
|
||||
|
||||
bool Image::isStringType(uint16_t type)
|
||||
{
|
||||
return type == Exiv2::asciiString
|
||||
|| type == Exiv2::unsignedByte
|
||||
|| type == Exiv2::signedByte
|
||||
|| type == Exiv2::undefined
|
||||
;
|
||||
}
|
||||
bool Image::isShortType(uint16_t type) {
|
||||
return type == Exiv2::unsignedShort
|
||||
|| type == Exiv2::signedShort
|
||||
;
|
||||
}
|
||||
bool Image::isLongType(uint16_t type) {
|
||||
return type == Exiv2::unsignedLong
|
||||
|| type == Exiv2::signedLong
|
||||
;
|
||||
}
|
||||
bool Image::isRationalType(uint16_t type) {
|
||||
return type == Exiv2::unsignedRational
|
||||
|| type == Exiv2::signedRational
|
||||
;
|
||||
}
|
||||
bool Image::is2ByteType(uint16_t type)
|
||||
{
|
||||
return isShortType(type);
|
||||
}
|
||||
bool Image::is4ByteType(uint16_t type)
|
||||
{
|
||||
return isLongType(type)
|
||||
|| isRationalType(type)
|
||||
;
|
||||
}
|
||||
bool Image::isPrintXMP(uint16_t type, Exiv2::PrintStructureOption option)
|
||||
{
|
||||
return type == 700 && option == kpsXMP;
|
||||
}
|
||||
bool Image::isPrintICC(uint16_t type, Exiv2::PrintStructureOption option)
|
||||
{
|
||||
return type == 0x8773 && option == kpsIccProfile;
|
||||
}
|
||||
|
||||
bool Image::isBigEndianPlatform()
|
||||
{
|
||||
union {
|
||||
uint32_t i;
|
||||
char c[4];
|
||||
} e = { 0x01000000 };
|
||||
|
||||
return e.c[0]?true:false;
|
||||
}
|
||||
bool Image::isLittleEndianPlatform() { return !isBigEndianPlatform(); }
|
||||
|
||||
uint32_t Image::byteSwap(uint32_t value,bool bSwap)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
result |= (value & 0x000000FF) << 24;
|
||||
result |= (value & 0x0000FF00) << 8;
|
||||
result |= (value & 0x00FF0000) >> 8;
|
||||
result |= (value & 0xFF000000) >> 24;
|
||||
return bSwap ? result : value;
|
||||
}
|
||||
|
||||
uint16_t Image::byteSwap(uint16_t value,bool bSwap)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
result |= (value & 0x00FF) << 8;
|
||||
result |= (value & 0xFF00) >> 8;
|
||||
return bSwap ? result : value;
|
||||
}
|
||||
|
||||
uint16_t Image::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 Image::byteSwap(v,bSwap);
|
||||
}
|
||||
|
||||
uint32_t Image::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 Image::byteSwap(v,bSwap);
|
||||
}
|
||||
|
||||
static const char* tagName(uint16_t tag,size_t nMaxLength)
|
||||
{
|
||||
const char* result = NULL;
|
||||
|
||||
// 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;
|
||||
const TagInfo* ti ;
|
||||
for (ti = Internal:: mnTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Internal:: iopTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Internal:: gpsTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Internal:: ifdTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Internal::exifTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Internal:: mpfTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Internal::Nikon1MakerNote::tagList(), 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) -2 )
|
||||
nMaxLength = sizeof(buffer) -2;
|
||||
strncpy(buffer,result,nMaxLength);
|
||||
result = buffer;
|
||||
} catch ( ... ) {}
|
||||
|
||||
return result ;
|
||||
}
|
||||
|
||||
static const char* typeName(uint16_t tag)
|
||||
{
|
||||
//! List of TIFF image tags
|
||||
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;
|
||||
}
|
||||
|
||||
void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,uint32_t start,bool bSwap,char c,int depth)
|
||||
{
|
||||
depth++;
|
||||
bool bFirst = true ;
|
||||
|
||||
// buffer
|
||||
const size_t dirSize = 32;
|
||||
DataBuf dir(dirSize);
|
||||
bool bPrint = option == kpsBasic || option == kpsRecursive;
|
||||
|
||||
do {
|
||||
// Read top of directory
|
||||
io.seek(start,BasicIo::beg);
|
||||
io.read(dir.pData_, 2);
|
||||
uint16_t dirLength = byteSwap2(dir,0,bSwap);
|
||||
|
||||
bool tooBig = dirLength > 500;
|
||||
|
||||
if ( bFirst && bPrint ) {
|
||||
out << Internal::indent(depth) << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ",c,c) << io.path() << std::endl;
|
||||
if ( tooBig ) out << Internal::indent(depth) << "dirLength = " << dirLength << std::endl;
|
||||
}
|
||||
if (tooBig) break;
|
||||
|
||||
// Read the dictionary
|
||||
for ( int i = 0 ; i < dirLength ; i ++ ) {
|
||||
if ( bFirst && bPrint ) {
|
||||
out << Internal::indent(depth)
|
||||
<< " address | tag | "
|
||||
<< " type | count | offset | value\n";
|
||||
}
|
||||
bFirst = false;
|
||||
|
||||
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
|
||||
uint32_t kount = isPrintXMP(tag,option) ? count // haul in all the data
|
||||
: isPrintICC(tag,option) ? count // ditto
|
||||
: isStringType(type) ? (count > 32 ? 32 : count) // restrict long arrays
|
||||
: count > 5 ? 5
|
||||
: count
|
||||
;
|
||||
uint32_t pad = isStringType(type) ? 1 : 0;
|
||||
uint32_t size = isStringType(type) ? 1
|
||||
: is2ByteType(type) ? 2
|
||||
: is4ByteType(type) ? 4
|
||||
: 1
|
||||
;
|
||||
|
||||
// if ( offset > io.size() ) offset = 0; // Denial of service?
|
||||
DataBuf buf(size*count + pad); // allocate a buffer
|
||||
std::memcpy(buf.pData_,dir.pData_+8,4); // copy dir[8:11] into buffer (short strings)
|
||||
if ( count*size > 4 ) { // read into buffer
|
||||
size_t restore = io.tell(); // save
|
||||
io.seek(offset,BasicIo::beg); // position
|
||||
io.read(buf.pData_,count*size);// read
|
||||
io.seek(restore,BasicIo::beg); // restore
|
||||
}
|
||||
|
||||
if ( bPrint ) {
|
||||
uint32_t address = start + 2 + i*12 ;
|
||||
out << Internal::indent(depth)
|
||||
<< Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%10u | "
|
||||
,address,tag,tagName(tag,25),typeName(type),count,offset);
|
||||
if ( isShortType(type) ){
|
||||
for ( size_t k = 0 ; k < kount ; k++ ) {
|
||||
out << sp << byteSwap2(buf,k*size,bSwap);
|
||||
sp = " ";
|
||||
}
|
||||
} else if ( isLongType(type) ){
|
||||
for ( size_t k = 0 ; k < kount ; k++ ) {
|
||||
out << sp << byteSwap4(buf,k*size,bSwap);
|
||||
sp = " ";
|
||||
}
|
||||
// populate strips and bytes
|
||||
if ( tag == 0x0111 ) {
|
||||
for ( size_t k = 0 ; k < count ; k++ ) // stripOffsets
|
||||
stripOffsets.push_back(byteSwap4(buf,k*size,bSwap));
|
||||
}
|
||||
if ( tag == 0x0117 ) {
|
||||
for ( size_t k = 0 ; k < count ; k++ ) // stripByteCounts
|
||||
stripByteCounts.push_back(byteSwap4(buf,k*size,bSwap));
|
||||
}
|
||||
|
||||
} else if ( isRationalType(type) ){
|
||||
for ( size_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 ( isLittleEndianPlatform() ) {
|
||||
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 == 0x014a/*SubIFDs*/ ) ) {
|
||||
for ( size_t k = 0 ; k < count ; k++ ) {
|
||||
size_t restore = io.tell();
|
||||
uint32_t offset = byteSwap4(buf,k*size,bSwap);
|
||||
printIFDStructure(io,out,option,offset,bSwap,c,depth);
|
||||
io.seek(restore,BasicIo::beg);
|
||||
}
|
||||
} else if ( option == kpsRecursive && tag == 0x83bb /* IPTCNAA */ ) {
|
||||
size_t restore = io.tell(); // save
|
||||
io.seek(offset,BasicIo::beg); // position
|
||||
byte* bytes=new byte[count] ; // allocate memory
|
||||
io.read(bytes,count) ; // read
|
||||
io.seek(restore,BasicIo::beg); // restore
|
||||
IptcData::printStructure(out,bytes,count,depth);
|
||||
delete[] bytes; // free
|
||||
} else if ( option == kpsRecursive && tag == 0x927c /* MakerNote */ && count > 10) {
|
||||
uint32_t jump= 10 ;
|
||||
byte bytes[20] ;
|
||||
const char* chars = (const char*) &bytes[0] ;
|
||||
size_t restore = io.tell(); // save
|
||||
io.seek(offset,BasicIo::beg); // position
|
||||
io.read(bytes,jump ) ; // read
|
||||
bytes[jump]=0 ;
|
||||
if ( ::strcmp("Nikon",chars) == 0 ) {
|
||||
// tag is an embedded tiff
|
||||
byte* bytes=new byte[count-jump] ; // allocate memory
|
||||
io.read(bytes,count-jump) ; // read
|
||||
MemIo memIo(bytes,count-jump) ; // create a file
|
||||
printTiffStructure(memIo,out,option,depth);
|
||||
delete[] bytes ; // free
|
||||
}
|
||||
io.seek(restore,BasicIo::beg); // restore
|
||||
}
|
||||
}
|
||||
|
||||
if ( isPrintXMP(tag,option) ) {
|
||||
buf.pData_[count]=0;
|
||||
out << (char*) buf.pData_;
|
||||
}
|
||||
if ( isPrintICC(tag,option) ) {
|
||||
out.write((const char*)buf.pData_,count);
|
||||
}
|
||||
}
|
||||
io.read(dir.pData_, 4);
|
||||
start = tooBig ? 0 : byteSwap4(dir,0,bSwap);
|
||||
out.flush();
|
||||
} while (start) ;
|
||||
|
||||
if ( bPrint ) {
|
||||
out << Internal::indent(depth) << "END " << io.path() << std::endl;
|
||||
}
|
||||
depth--;
|
||||
}
|
||||
|
||||
void Image::printTiffStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,int depth,size_t offset /*=0*/)
|
||||
{
|
||||
if ( option == kpsBasic || option == kpsXMP || option == kpsRecursive || option == kpsIccProfile ) {
|
||||
// buffer
|
||||
const size_t dirSize = 32;
|
||||
DataBuf dir(dirSize);
|
||||
|
||||
// read header (we already know for certain that we have a Tiff file)
|
||||
io.read(dir.pData_, 8);
|
||||
char c = (char) dir.pData_[0] ;
|
||||
bool bSwap = ( c == 'M' && isLittleEndianPlatform() )
|
||||
|| ( c == 'I' && isBigEndianPlatform() )
|
||||
;
|
||||
uint32_t start = byteSwap4(dir,4,bSwap);
|
||||
printIFDStructure(io,out,option,start+(uint32_t)offset,bSwap,c,depth);
|
||||
}
|
||||
}
|
||||
|
||||
void Image::clearMetadata()
|
||||
{
|
||||
clearExifData();
|
||||
|
||||
@ -553,7 +553,7 @@ namespace Exiv2
|
||||
&& (rawData.pData_[0]=='I' || rawData.pData_[0]=='M' )
|
||||
) {
|
||||
BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(rawData.pData_,rawData.size_));
|
||||
TiffImage::printTiffStructure(*p,out,option,depth);
|
||||
printTiffStructure(*p,out,option,depth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -769,7 +769,7 @@ namespace Exiv2 {
|
||||
} else {
|
||||
// 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));
|
||||
if ( start < max ) TiffImage::printTiffStructure(*p,out,option,depth);
|
||||
if ( start < max ) printTiffStructure(*p,out,option,depth);
|
||||
}
|
||||
|
||||
// restore and clean up
|
||||
|
||||
@ -64,19 +64,7 @@ const unsigned char pgfBlank[] = { 0x50,0x47,0x46,0x36,0x10,0x00,0x00,0x00,0x01,
|
||||
|
||||
namespace Exiv2 {
|
||||
|
||||
// http://en.wikipedia.org/wiki/Endianness
|
||||
static bool isBigEndian()
|
||||
{
|
||||
union {
|
||||
uint32_t i;
|
||||
char c[4];
|
||||
} e = { 0x01000000 };
|
||||
|
||||
return e.c[0]?true:false;
|
||||
}
|
||||
// static bool isLittleEndian() { return !isBigEndian(); }
|
||||
|
||||
static uint32_t byteSwap(uint32_t value,bool bSwap)
|
||||
static uint32_t byteSwap_(uint32_t value,bool bSwap)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
result |= (value & 0x000000FF) << 24;
|
||||
@ -85,31 +73,14 @@ namespace Exiv2 {
|
||||
result |= (value & 0xFF000000) >> 24;
|
||||
return bSwap ? result : value;
|
||||
}
|
||||
/*
|
||||
static uint16_t byteSwap(uint16_t value,bool bSwap)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
result |= (value & 0x00FF) << 8;
|
||||
result |= (value & 0xFF00) >> 8;
|
||||
return bSwap ? result : value;
|
||||
}
|
||||
|
||||
static uint16_t byteSwap2(Exiv2::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);
|
||||
}
|
||||
*/
|
||||
static uint32_t byteSwap(Exiv2::DataBuf& buf,size_t offset,bool bSwap)
|
||||
static uint32_t byteSwap_(Exiv2::DataBuf& buf,size_t offset,bool bSwap)
|
||||
{
|
||||
uint32_t v;
|
||||
char* p = (char*) &v;
|
||||
int i;
|
||||
for ( i = 0 ; i < 4 ; i++ ) p[i] = buf.pData_[offset+i];
|
||||
uint32_t result = byteSwap(v,bSwap);
|
||||
uint32_t result = byteSwap_(v,bSwap);
|
||||
p = (char*) &result;
|
||||
for ( i = 0 ; i < 4 ; i++ ) buf.pData_[offset+i] = p[i];
|
||||
return result;
|
||||
@ -117,7 +88,7 @@ namespace Exiv2 {
|
||||
|
||||
PgfImage::PgfImage(BasicIo::AutoPtr io, bool create)
|
||||
: Image(ImageType::pgf, mdExif | mdIptc| mdXmp | mdComment, io)
|
||||
, bSwap_(isBigEndian())
|
||||
, bSwap_(isBigEndianPlatform())
|
||||
{
|
||||
if (create)
|
||||
{
|
||||
@ -251,7 +222,7 @@ namespace Exiv2 {
|
||||
uint32_t newHeaderSize = header.size_ + imgSize;
|
||||
DataBuf buffer(4);
|
||||
memcpy (buffer.pData_, &newHeaderSize, 4);
|
||||
byteSwap(buffer,0,bSwap_);
|
||||
byteSwap_(buffer,0,bSwap_);
|
||||
if (outIo.write(buffer.pData_, 4) != 4) throw Error(21);
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -304,7 +275,7 @@ namespace Exiv2 {
|
||||
if (iIo.error()) throw Error(14);
|
||||
if (bufRead != buffer.size_) throw Error(20);
|
||||
|
||||
int headerSize = (int) byteSwap(buffer,0,bSwap_);
|
||||
int headerSize = (int) byteSwap_(buffer,0,bSwap_);
|
||||
if (headerSize <= 0 ) throw Error(22);
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -323,8 +294,8 @@ namespace Exiv2 {
|
||||
|
||||
DataBuf work(8); // don't disturb the binary data - doWriteMetadata reuses it
|
||||
memcpy (work.pData_,header.pData_,8);
|
||||
width = byteSwap(work,0,bSwap_);
|
||||
height = byteSwap(work,4,bSwap_);
|
||||
width = byteSwap_(work,0,bSwap_);
|
||||
height = byteSwap_(work,4,bSwap_);
|
||||
|
||||
/* NOTE: properties not yet used
|
||||
byte nLevels = buffer.pData_[8];
|
||||
|
||||
@ -334,7 +334,7 @@ namespace Exiv2 {
|
||||
if ( bExif ) {
|
||||
// create memio object with the data, then print the structure
|
||||
BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(parsedBuf.pData_+6,parsedBuf.size_-6));
|
||||
TiffImage::printTiffStructure(*p,out,option,depth);
|
||||
printTiffStructure(*p,out,option,depth);
|
||||
}
|
||||
if ( bIptc ) {
|
||||
IptcData::printStructure(out,parsedBuf.pData_,parsedBuf.size_,depth);
|
||||
|
||||
@ -41,6 +41,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||
#include "error.hpp"
|
||||
#include "futils.hpp"
|
||||
#include "types.hpp"
|
||||
#include "basicio.hpp"
|
||||
#include "i18n.h" // NLS support.
|
||||
|
||||
// + standard includes
|
||||
@ -183,6 +184,25 @@ namespace Exiv2 {
|
||||
throw Error(3, "TIFF");
|
||||
}
|
||||
clearMetadata();
|
||||
|
||||
// recursively print the structure to /dev/null to ensure all metadata is in memory
|
||||
// must be recursive to handle NEFs which stores the raw image in a subIFDs
|
||||
std::ofstream devnull;
|
||||
printStructure(devnull,kpsRecursive,0);
|
||||
#ifdef DEBUG
|
||||
assert(stripOffsets.size() == stripByteCounts.size());
|
||||
int ignored =0 ;
|
||||
for ( int strip = 0 ; strip < stripOffsets.size() ; strip ++ )
|
||||
ignored += stripByteCounts[strip];
|
||||
std::cout << "TiffImage::readMetadata ignored = " << ignored << " size = " << io().size() << std::endl;
|
||||
#endif
|
||||
#if 0
|
||||
assert(stripOffsets.size() == stripByteCounts.size());
|
||||
// tell io_ to ignore the strips and read everything else into memory
|
||||
for ( size_t strip = 0 ; strip < stripOffsets.size() ; strip ++ )
|
||||
io_->markRead(stripOffsets[strip],stripByteCounts[strip]);
|
||||
io_->readUnmarked();
|
||||
#endif
|
||||
ByteOrder bo = TiffParser::decode(exifData_,
|
||||
iptcData_,
|
||||
xmpData_,
|
||||
@ -327,157 +347,6 @@ namespace Exiv2 {
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool isBigEndian()
|
||||
{
|
||||
union {
|
||||
uint32_t i;
|
||||
char c[4];
|
||||
} e = { 0x01000000 };
|
||||
|
||||
return e.c[0]?true:false;
|
||||
}
|
||||
bool isLittleEndian() { return !isBigEndian(); }
|
||||
|
||||
|
||||
// http://en.wikipedia.org/wiki/Endianness
|
||||
static uint32_t byteSwap(uint32_t value,bool bSwap)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
result |= (value & 0x000000FF) << 24;
|
||||
result |= (value & 0x0000FF00) << 8;
|
||||
result |= (value & 0x00FF0000) >> 8;
|
||||
result |= (value & 0xFF000000) >> 24;
|
||||
return bSwap ? result : value;
|
||||
}
|
||||
|
||||
static uint16_t byteSwap(uint16_t value,bool bSwap)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
result |= (value & 0x00FF) << 8;
|
||||
result |= (value & 0xFF00) >> 8;
|
||||
return bSwap ? result : value;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static const char* typeName(uint16_t tag)
|
||||
{
|
||||
//! List of TIFF image tags
|
||||
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;
|
||||
}
|
||||
|
||||
static const char* tagName(uint16_t tag,size_t nMaxLength)
|
||||
{
|
||||
const char* result = NULL;
|
||||
|
||||
// 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;
|
||||
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:: mpfTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Nikon1MakerNote::tagList(), 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) -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
|
||||
|| type == Exiv2::undefined
|
||||
;
|
||||
}
|
||||
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 option)
|
||||
{
|
||||
return type == 700 && option == kpsXMP;
|
||||
}
|
||||
static bool isPrintICC(uint16_t type, Exiv2::PrintStructureOption option)
|
||||
{
|
||||
return type == 0x8773 && option == kpsIccProfile;
|
||||
}
|
||||
|
||||
#define MIN(a,b) ((a)<(b))?(b):(a)
|
||||
|
||||
void TiffImage::printStructure(std::ostream& out, Exiv2::PrintStructureOption option,int depth)
|
||||
{
|
||||
if (io_->open() != 0) throw Error(9, io_->path(), strError());
|
||||
@ -493,178 +362,6 @@ namespace Exiv2 {
|
||||
printTiffStructure(io(),out,option,depth-1);
|
||||
}
|
||||
|
||||
void TiffImage::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,uint32_t start,bool bSwap,char c,int depth)
|
||||
{
|
||||
depth++;
|
||||
bool bFirst = true ;
|
||||
|
||||
// buffer
|
||||
const size_t dirSize = 32;
|
||||
DataBuf dir(dirSize);
|
||||
bool bPrint = option == kpsBasic || option == kpsRecursive;
|
||||
|
||||
do {
|
||||
// Read top of directory
|
||||
io.seek(start,BasicIo::beg);
|
||||
io.read(dir.pData_, 2);
|
||||
uint16_t dirLength = byteSwap2(dir,0,bSwap);
|
||||
|
||||
bool tooBig = dirLength > 500;
|
||||
|
||||
if ( bFirst && bPrint ) {
|
||||
out << Internal::indent(depth) << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ",c,c) << io.path() << std::endl;
|
||||
if ( tooBig ) out << Internal::indent(depth) << "dirLength = " << dirLength << std::endl;
|
||||
}
|
||||
if (tooBig) break;
|
||||
|
||||
// Read the dictionary
|
||||
for ( int i = 0 ; i < dirLength ; i ++ ) {
|
||||
if ( bFirst && bPrint ) {
|
||||
out << Internal::indent(depth)
|
||||
<< " address | tag | "
|
||||
<< " type | count | offset | value\n";
|
||||
}
|
||||
bFirst = false;
|
||||
|
||||
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
|
||||
uint32_t kount = isPrintXMP(tag,option) ? count // haul in all the data
|
||||
: isPrintICC(tag,option) ? count // ditto
|
||||
: isStringType(type) ? (count > 32 ? 32 : count) // restrict long arrays
|
||||
: count > 5 ? 5
|
||||
: count
|
||||
;
|
||||
uint32_t pad = isStringType(type) ? 1 : 0;
|
||||
uint32_t size = isStringType(type) ? 1
|
||||
: is2ByteType(type) ? 2
|
||||
: is4ByteType(type) ? 4
|
||||
: 1
|
||||
;
|
||||
|
||||
// if ( offset > io.size() ) offset = 0; // Denial of service?
|
||||
DataBuf buf(MIN(size*kount + pad,48)); // allocate a buffer
|
||||
std::memcpy(buf.pData_,dir.pData_+8,4); // copy dir[8:11] into buffer (short strings)
|
||||
if ( count*size > 4 ) { // 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
|
||||
}
|
||||
|
||||
uint32_t Offset = isLongType(type) ? byteSwap4(buf,0,bSwap) : 0 ;
|
||||
|
||||
if ( bPrint ) {
|
||||
uint32_t address = start + 2 + i*12 ;
|
||||
out << Internal::indent(depth)
|
||||
<< Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%10u | "
|
||||
,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 ( option == kpsRecursive && (tag == 0x8769 /* ExifTag */ || tag == 0x014a/*SubIFDs*/ ) ) {
|
||||
size_t restore = io.tell();
|
||||
printIFDStructure(io,out,option,Offset,bSwap,c,depth);
|
||||
io.seek(restore,BasicIo::beg);
|
||||
} else if ( option == kpsRecursive && tag == 0x83bb /* IPTCNAA */ ) {
|
||||
size_t restore = io.tell(); // save
|
||||
io.seek(offset,BasicIo::beg); // position
|
||||
byte* bytes=new byte[count] ; // allocate memory
|
||||
io.read(bytes,count) ; // read
|
||||
io.seek(restore,BasicIo::beg); // restore
|
||||
IptcData::printStructure(out,bytes,count,depth);
|
||||
delete[] bytes; // free
|
||||
} else if ( option == kpsRecursive && tag == 0x927c /* MakerNote */ && count > 10) {
|
||||
uint32_t jump= 10 ;
|
||||
byte bytes[20] ;
|
||||
const char* chars = (const char*) &bytes[0] ;
|
||||
size_t restore = io.tell(); // save
|
||||
io.seek(offset,BasicIo::beg); // position
|
||||
io.read(bytes,jump ) ; // read
|
||||
bytes[jump]=0 ;
|
||||
if ( ::strcmp("Nikon",chars) == 0 ) {
|
||||
// tag is an embedded tiff
|
||||
byte* bytes=new byte[count-jump] ; // allocate memory
|
||||
io.read(bytes,count-jump) ; // read
|
||||
MemIo memIo(bytes,count-jump) ; // create a file
|
||||
printTiffStructure(memIo,out,option,depth);
|
||||
delete[] bytes ; // free
|
||||
}
|
||||
io.seek(restore,BasicIo::beg); // restore
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( isPrintXMP(tag,option) ) {
|
||||
buf.pData_[count]=0;
|
||||
out << (char*) buf.pData_;
|
||||
}
|
||||
if ( isPrintICC(tag,option) ) {
|
||||
out.write((const char*)buf.pData_,count);
|
||||
}
|
||||
}
|
||||
io.read(dir.pData_, 4);
|
||||
start = tooBig ? 0 : byteSwap4(dir,0,bSwap);
|
||||
out.flush();
|
||||
} while (start) ;
|
||||
|
||||
if ( bPrint ) {
|
||||
out << Internal::indent(depth) << "END " << io.path() << std::endl;
|
||||
}
|
||||
depth--;
|
||||
}
|
||||
|
||||
void TiffImage::printTiffStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,int depth,size_t offset /*=0*/)
|
||||
{
|
||||
if ( option == kpsBasic || option == kpsXMP || option == kpsRecursive || option == kpsIccProfile ) {
|
||||
// buffer
|
||||
const size_t dirSize = 32;
|
||||
DataBuf dir(dirSize);
|
||||
|
||||
// read header (we already know for certain that we have a Tiff file)
|
||||
io.read(dir.pData_, 8);
|
||||
char c = (char) dir.pData_[0] ;
|
||||
bool bSwap = ( c == 'M' && isLittleEndian() )
|
||||
|| ( c == 'I' && isBigEndian() )
|
||||
;
|
||||
|
||||
uint32_t start = byteSwap4(dir,4,bSwap)+(uint32_t)offset;
|
||||
printIFDStructure(io,out,option,start,bSwap,c,depth);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
// Shortcuts for the newTiffBinaryArray templates.
|
||||
|
||||
@ -19,11 +19,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*
|
||||
File: webpimage.cpp
|
||||
Version: $Rev: 3845 $
|
||||
Author(s): Ben Touchette <draekko.software+exiv2@gmail.com>
|
||||
History: 10-Aug-16
|
||||
Credits: See header file
|
||||
File: webpimage.cpp
|
||||
Version: $Rev: 4633 $
|
||||
*/
|
||||
/*
|
||||
Google's WEBP container spec can be found at the link below:
|
||||
@ -461,7 +458,7 @@ namespace Exiv2 {
|
||||
if ( equalsWebPTag(chunkId, WEBP_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_));
|
||||
TiffImage::printTiffStructure(*p,out,option,depth);
|
||||
printTiffStructure(*p,out,option,depth);
|
||||
}
|
||||
|
||||
bool bPrintPayload = (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_XMP) && option==kpsXMP)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user