#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:
Robin Mills 2016-10-17 15:48:42 +00:00
parent cdb5eecc6b
commit f5956d5db2
12 changed files with 529 additions and 419 deletions

View File

@ -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:

View File

@ -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
//@{

View File

@ -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).

View File

@ -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()

View File

@ -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

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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

View File

@ -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];

View File

@ -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);

View File

@ -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.

View File

@ -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)