@ -20,16 +20,17 @@
*/
*/
/*
/*
File : makernote . cpp
File : makernote . cpp
Version : $ Name : $ $ Revision : 1.1 8 $
Version : $ Name : $ $ Revision : 1.1 9 $
Author ( s ) : Andreas Huggel ( ahu ) < ahuggel @ gmx . net >
Author ( s ) : Andreas Huggel ( ahu ) < ahuggel @ gmx . net >
History : 18 - Feb - 04 , ahu : created
History : 18 - Feb - 04 , ahu : created
*/
*/
// *****************************************************************************
// *****************************************************************************
# include "rcsid.hpp"
# include "rcsid.hpp"
EXIV2_RCSID ( " @(#) $Name: $ $Revision: 1.1 8 $ $RCSfile: makernote.cpp,v $" )
EXIV2_RCSID ( " @(#) $Name: $ $Revision: 1.1 9 $ $RCSfile: makernote.cpp,v $" )
// Define DEBUG_ MAKERNOTE to output debug information to std::cerr
// Define DEBUG_ * to output debug information to std::cerr
# undef DEBUG_MAKERNOTE
# undef DEBUG_MAKERNOTE
# define DEBUG_REGISTRY
// *****************************************************************************
// *****************************************************************************
// included header files
// included header files
@ -42,7 +43,7 @@ EXIV2_RCSID("@(#) $Name: $ $Revision: 1.18 $ $RCSfile: makernote.cpp,v $")
# include <sstream>
# include <sstream>
# include <iomanip>
# include <iomanip>
# if def DEBUG_MAKERNOTE
# if defined DEBUG_MAKERNOTE || defined DEBUG_REGISTRY
# include <iostream>
# include <iostream>
# endif
# endif
@ -50,6 +51,12 @@ EXIV2_RCSID("@(#) $Name: $ $Revision: 1.18 $ $RCSfile: makernote.cpp,v $")
// class member definitions
// class member definitions
namespace Exiv2 {
namespace Exiv2 {
MakerNote : : MakerNote ( const MnTagInfo * pMnTagInfo , bool alloc )
: pMnTagInfo_ ( pMnTagInfo ) , alloc_ ( alloc ) ,
offset_ ( 0 ) , byteOrder_ ( invalidByteOrder )
{
}
std : : string MakerNote : : makeKey ( uint16 tag ) const
std : : string MakerNote : : makeKey ( uint16 tag ) const
{
{
return std : : string ( ExifTags : : ifdItem ( makerIfd ) )
return std : : string ( ExifTags : : ifdItem ( makerIfd ) )
@ -150,6 +157,14 @@ namespace Exiv2 {
< < tagDesc ( tag ) ;
< < tagDesc ( tag ) ;
} // MakerNote::writeMnTagInfo
} // MakerNote::writeMnTagInfo
IfdMakerNote : : IfdMakerNote ( const MakerNote : : MnTagInfo * pMnTagInfo ,
bool alloc )
: MakerNote ( pMnTagInfo , alloc ) ,
absOffset_ ( true ) , adjOffset_ ( 0 ) , ifd_ ( makerIfd , 0 , alloc )
{
}
int IfdMakerNote : : read ( const char * buf ,
int IfdMakerNote : : read ( const char * buf ,
long len ,
long len ,
ByteOrder byteOrder ,
ByteOrder byteOrder ,
@ -159,24 +174,22 @@ namespace Exiv2 {
offset_ = offset ;
offset_ = offset ;
// Set byte order if none is set yet
// Set byte order if none is set yet
if ( byteOrder_ = = invalidByteOrder ) byteOrder_ = byteOrder ;
if ( byteOrder_ = = invalidByteOrder ) byteOrder_ = byteOrder ;
int rc = 0 ;
// Read and check the header (and set offset adjustment)
if ( ! prefix_ . empty ( ) ) {
int rc = readHeader ( buf , len , byteOrder ) ;
// Check if makernote is long enough and starts with prefix
if ( rc = = 0 ) {
if ( len < static_cast < long > ( prefix_ . size ( ) )
rc = checkHeader ( ) ;
| | prefix_ ! = std : : string ( buf , prefix_ . size ( ) ) ) rc = 2 ;
}
if ( ! absOffset_ ) {
// Use offsets relative to the start of the Makernote field
offset = 0 ;
}
}
// Adjust the offset
offset = absOffset_ ? offset + adjOffset_ : adjOffset_ ;
// Read the makernote IFD
if ( rc = = 0 ) {
if ( rc = = 0 ) {
rc = ifd_ . read ( buf + prefix_ . size ( ) ,
rc = ifd_ . read ( buf + headerS ize( ) ,
len - prefix_ . size ( ) ,
len - headerS ize( ) ,
byteOrder_ ,
byteOrder_ ,
offset + prefix_ . size ( ) ) ;
offset ) ;
}
}
if ( rc = = 0 ) {
if ( rc = = 0 ) {
// IfdMakerNote does not support multiple IFDs
// IfdMakerNote currently does not support multiple IFDs
if ( ifd_ . next ( ) ! = 0 ) rc = 3 ;
if ( ifd_ . next ( ) ! = 0 ) rc = 3 ;
}
}
if ( rc = = 0 ) {
if ( rc = = 0 ) {
@ -188,8 +201,8 @@ namespace Exiv2 {
# ifdef DEBUG_MAKERNOTE
# ifdef DEBUG_MAKERNOTE
hexdump ( std : : cerr , buf , len , offset ) ;
hexdump ( std : : cerr , buf , len , offset ) ;
if ( rc = = 0 ) ifd_ . print ( std : : cerr ) ;
if ( rc = = 0 ) ifd_ . print ( std : : cerr ) ;
else std : : cerr < < " IfdMakerNote::read() failed, rc = " < < rc < < " \n " ;
# endif
# endif
return rc ;
return rc ;
} // IfdMakerNote::read
} // IfdMakerNote::read
@ -199,20 +212,39 @@ namespace Exiv2 {
offset_ = offset ;
offset_ = offset ;
// Set byte order if none is set yet
// Set byte order if none is set yet
if ( byteOrder_ = = invalidByteOrder ) byteOrder_ = byteOrder ;
if ( byteOrder_ = = invalidByteOrder ) byteOrder_ = byteOrder ;
long len = 0 ;
long len = 0 ;
if ( ! prefix_ . empty ( ) ) {
len + = copyHeader ( buf ) ;
// Write the prefix string to the Makernote buffer
len + = ifd_ . copy ( buf + len , byteOrder_ , offset_ ) ;
memcpy ( buf , prefix_ . data ( ) , prefix_ . size ( ) ) ;
len + = prefix_ . size ( ) ;
}
if ( ! absOffset_ ) {
// Use offsets relative to the start of the Makernote field
offset = 0 ;
}
len + = ifd_ . copy ( buf + len , byteOrder_ , offset + len ) ;
return len ;
return len ;
} // IfdMakerNote::copy
} // IfdMakerNote::copy
int IfdMakerNote : : readHeader ( const char * buf ,
long len ,
ByteOrder byteOrder )
{
// Default implementation does nothing, assuming there is no header
return 0 ;
}
int IfdMakerNote : : checkHeader ( ) const
{
// Default implementation does nothing, assuming there is no header
return 0 ;
}
long IfdMakerNote : : copyHeader ( char * buf ) const
{
if ( header_ . size_ ! = 0 ) memcpy ( buf , header_ . pData_ , header_ . size_ ) ;
return header_ . size_ ;
}
long IfdMakerNote : : headerSize ( ) const
{
return header_ . size_ ;
}
Entries : : const_iterator IfdMakerNote : : findIdx ( int idx ) const
Entries : : const_iterator IfdMakerNote : : findIdx ( int idx ) const
{
{
return ifd_ . findIdx ( idx ) ;
return ifd_ . findIdx ( idx ) ;
@ -220,7 +252,7 @@ namespace Exiv2 {
long IfdMakerNote : : size ( ) const
long IfdMakerNote : : size ( ) const
{
{
return prefix_ . s ize( ) + ifd_ . size ( ) + ifd_ . dataSize ( ) ;
return headerS ize( ) + ifd_ . size ( ) + ifd_ . dataSize ( ) ;
}
}
MakerNoteFactory * MakerNoteFactory : : pInstance_ = 0 ;
MakerNoteFactory * MakerNoteFactory : : pInstance_ = 0 ;
@ -237,7 +269,7 @@ namespace Exiv2 {
const std : : string & model ,
const std : : string & model ,
CreateFct createMakerNote )
CreateFct createMakerNote )
{
{
# ifdef DEBUG_ MAKERNOTE
# ifdef DEBUG_ REGISTRY
std : : cerr < < " Registering MakerNote create function for \" "
std : : cerr < < " Registering MakerNote create function for \" "
< < make < < " \" and \" " < < model < < " \" . \n " ;
< < make < < " \" and \" " < < model < < " \" . \n " ;
# endif
# endif
@ -276,42 +308,80 @@ namespace Exiv2 {
const std : : string & model ,
const std : : string & model ,
bool alloc ) const
bool alloc ) const
{
{
# ifdef DEBUG_REGISTRY
std : : cerr < < " Entering MakerNoteFactory::create( \" "
< < make < < " \" , \" " < < model < < " \" , "
< < ( alloc = = true ? " true " : " false " ) < < " ) \n " ;
# endif
// loop through each make of the registry to find the best matching make
// loop through each make of the registry to find the best matching make
int matchCount = - 1 ;
int score = 0 ;
ModelRegistry * modelRegistry = 0 ;
ModelRegistry * modelRegistry = 0 ;
# ifdef DEBUG_REGISTRY
std : : string makeMatch ;
std : : cerr < < " Searching make registry... \n " ;
# endif
Registry : : const_iterator end1 = registry_ . end ( ) ;
Registry : : const_iterator end1 = registry_ . end ( ) ;
Registry : : const_iterator pos1 ;
Registry : : const_iterator pos1 ;
for ( pos1 = registry_ . begin ( ) ; pos1 ! = end1 ; + + pos1 ) {
for ( pos1 = registry_ . begin ( ) ; pos1 ! = end1 ; + + pos1 ) {
std : : pair < bool , int > rc = match ( pos1 - > first , make ) ;
int rc = match ( pos1 - > first , make ) ;
if ( rc . first & & rc . second > matchCount ) {
if ( rc > score ) {
matchCount = rc . second ;
score = rc ;
# ifdef DEBUG_REGISTRY
makeMatch = pos1 - > first ;
# endif
modelRegistry = pos1 - > second ;
modelRegistry = pos1 - > second ;
}
}
}
}
if ( modelRegistry = = 0 ) return 0 ;
if ( modelRegistry = = 0 ) return 0 ;
# ifdef DEBUG_REGISTRY
std : : cerr < < " Best match is \" " < < makeMatch < < " \" . \n " ;
# endif
// loop through each model of the model registry to find the best match
// loop through each model of the model registry to find the best match
matchCount = - 1 ;
score = 0 ;
CreateFct createMakerNote = 0 ;
CreateFct createMakerNote = 0 ;
# ifdef DEBUG_REGISTRY
std : : string modelMatch ;
std : : cerr < < " Searching model registry... \n " ;
# endif
ModelRegistry : : const_iterator end2 = modelRegistry - > end ( ) ;
ModelRegistry : : const_iterator end2 = modelRegistry - > end ( ) ;
ModelRegistry : : const_iterator pos2 ;
ModelRegistry : : const_iterator pos2 ;
for ( pos2 = modelRegistry - > begin ( ) ; pos2 ! = end2 ; + + pos2 ) {
for ( pos2 = modelRegistry - > begin ( ) ; pos2 ! = end2 ; + + pos2 ) {
std : : pair < bool , int > rc = match ( pos2 - > first , model ) ;
int rc = match ( pos2 - > first , model ) ;
if ( rc . first & & rc . second > matchCount ) {
if ( rc > score ) {
matchCount = rc . second ;
score = rc ;
# ifdef DEBUG_REGISTRY
modelMatch = pos2 - > first ;
# endif
createMakerNote = pos2 - > second ;
createMakerNote = pos2 - > second ;
}
}
}
}
if ( createMakerNote = = 0 ) return 0 ;
if ( createMakerNote = = 0 ) return 0 ;
# ifdef DEBUG_REGISTRY
std : : cerr < < " Best match is \" " < < modelMatch < < " \" . \n " ;
# endif
return createMakerNote ( alloc ) ;
return createMakerNote ( alloc ) ;
} // MakerNoteFactory::create
} // MakerNoteFactory::create
std : : pair < bool , int > MakerNoteFactory : : match ( const std : : string & regEntry ,
int MakerNoteFactory : : match ( const std : : string & regEntry ,
const std : : string & key )
const std : : string & key )
{
{
# ifdef DEBUG_REGISTRY
std : : cerr < < " Matching registry entry \" " < < regEntry < < " \" ( "
< < regEntry . size ( ) < < " ) with key \" " < < key < < " \" ( "
< < key . size ( ) < < " ): " ;
# endif
// Todo: make the comparisons case insensitive
// Todo: make the comparisons case insensitive
// Handle exact match (this is only necessary because of the different
// return value - the following algorithm also finds exact matches)
if ( regEntry = = key ) {
# ifdef DEBUG_REGISTRY
std : : cerr < < " Exact match (score: " < < key . size ( ) + 2 < < " ) \n " ;
# endif
return key . size ( ) + 2 ;
}
std : : string uKey = key ;
std : : string uKey = key ;
std : : string uReg = regEntry ;
std : : string uReg = regEntry ;
@ -327,7 +397,10 @@ namespace Exiv2 {
uReg . substr ( ei ) : uReg . substr ( ei , pos - ei ) ;
uReg . substr ( ei ) : uReg . substr ( ei , pos - ei ) ;
if ( ki = = std : : string : : npos ) {
if ( ki = = std : : string : : npos ) {
return std : : make_pair ( false , 0 ) ;
# ifdef DEBUG_REGISTRY
std : : cerr < < " Not a match. \n " ;
# endif
return 0 ;
}
}
bool found = false ;
bool found = false ;
@ -372,15 +445,21 @@ namespace Exiv2 {
count + = ss . size ( ) ;
count + = ss . size ( ) ;
}
}
else {
else {
return std : : make_pair ( false , 0 ) ;
# ifdef DEBUG_REGISTRY
std : : cerr < < " Not a match. \n " ;
# endif
return 0 ;
}
}
} // if the substr is not empty
} // if the substr is not empty
ei = pos = = std : : string : : npos ? std : : string : : npos : pos + 1 ;
ei = pos = = std : : string : : npos ? std : : string : : npos : pos + 1 ;
} // while ei doesn't point to the end of the registry entry
} // while ei doesn't point to the end of the registry entry
return std : : make_pair ( true , count ) ;
# ifdef DEBUG_REGISTRY
std : : cerr < < " Match (score: " < < count + 1 < < " ) \n " ;
# endif
return count + 1 ;
} // MakerNoteFactory::match
} // MakerNoteFactory::match