@ -61,7 +61,13 @@ EXIV2_RCSID("@(#) $Id$")
# include <unistd.h> // for getpid, stat
# endif
// MSVC doesn't provide mode_t
# ifdef _MSC_VER
typedef unsigned short mode_t ;
# endif
# if defined WIN32 && !defined __CYGWIN__
# include <windows.h>
# include <io.h>
# endif
@ -73,137 +79,298 @@ namespace Exiv2 {
{
}
FileIo : : FileIo ( const std : : string & path )
//! Internal Pimpl structure of class FileIo.
class FileIo : : Impl {
public :
Impl ( const std : : string & path ) ; //!< Constructor
# ifdef EXV_UNICODE_PATH
Impl ( const std : : wstring & wpath ) ; //!< Constructor
# endif
// Enumeration
enum OpMode { opRead , opWrite , opSeek } ;
# ifdef EXV_UNICODE_PATH
enum WpMode { wpStandard , wpUnicode } ;
# endif
// DATA
std : : string path_ ;
# ifdef EXV_UNICODE_PATH
std : : wstring wpath_ ;
WpMode wpMode_ ;
# endif
std : : string openMode_ ;
FILE * fp_ ;
OpMode opMode_ ;
# if defined WIN32 && !defined __CYGWIN__
HANDLE hFile_ ; // Duplicated fd
HANDLE hMap_ ; // Handle from CreateFileMapping
# endif
byte * pMappedArea_ ;
size_t mappedLength_ ;
bool isMalloced_ ; //!< Is the mapped area allocated?
bool isWriteable_ ; //!< Can the mapped area be written to?
// TYPES
//! Simple struct stat wrapper for internal use
struct StructStat {
StructStat ( ) : st_mode ( 0 ) , st_size ( 0 ) { }
mode_t st_mode ; //!< Permissions
off_t st_size ; //!< Size
} ;
// METHODS
/*!
@ brief Switch to a new access mode , reopening the file if needed .
Optimized to only reopen the file when it is really necessary .
@ param opMode The mode to switch to .
@ return 0 if successful
*/
int switchMode ( OpMode opMode ) ;
//! stat wrapper for internal use
int stat ( StructStat & buf ) const ;
private :
// NOT IMPLEMENTED
Impl ( const Impl & rhs ) ; //!< Copy constructor
Impl & operator = ( const Impl & rhs ) ; //!< Assignment
} ; // class FileIo::Impl
FileIo : : Impl : : Impl ( const std : : string & path )
: path_ ( path ) ,
# ifdef EXV_UNICODE_PATH
wpMode_ ( wpStandard ) ,
# endif
fp_ ( 0 ) , opMode_ ( opSeek ) ,
# if defined WIN32 && !defined __CYGWIN__
hFile_ ( 0 ) , hMap_ ( 0 ) ,
# endif
pMappedArea_ ( 0 ) , mappedLength_ ( 0 ) , isMalloced_ ( false ) , isWriteable_ ( false )
{
}
# ifdef EXV_UNICODE_PATH
FileIo : : FileIo ( const std : : wstring & wpath )
FileIo : : Impl: : Impl ( const std : : wstring & wpath )
: wpath_ ( wpath ) ,
wpMode_ ( wpUnicode ) ,
fp_ ( 0 ) , opMode_ ( opSeek ) ,
# if defined WIN32 && !defined __CYGWIN__
hFile_ ( 0 ) , hMap_ ( 0 ) ,
# endif
pMappedArea_ ( 0 ) , mappedLength_ ( 0 ) , isMalloced_ ( false ) , isWriteable_ ( false )
{
}
# endif
int FileIo : : Impl : : switchMode ( OpMode opMode )
{
assert ( fp_ ! = 0 ) ;
if ( opMode_ = = opMode ) return 0 ;
OpMode oldOpMode = opMode_ ;
opMode_ = opMode ;
bool reopen = true ;
switch ( opMode ) {
case opRead :
// Flush if current mode allows reading, else reopen (in mode "r+b"
// as in this case we know that we can write to the file)
if ( openMode_ [ 0 ] = = ' r ' | | openMode_ [ 1 ] = = ' + ' ) reopen = false ;
break ;
case opWrite :
// Flush if current mode allows writing, else reopen
if ( openMode_ [ 0 ] ! = ' r ' | | openMode_ [ 1 ] = = ' + ' ) reopen = false ;
break ;
case opSeek :
reopen = false ;
break ;
}
if ( ! reopen ) {
// Don't do anything when switching _from_ opSeek mode; we
// flush when switching _to_ opSeek.
if ( oldOpMode = = opSeek ) return 0 ;
// Flush. On msvcrt fflush does not do the job
std : : fseek ( fp_ , 0 , SEEK_CUR ) ;
return 0 ;
}
// Reopen the file
long offset = std : : ftell ( fp_ ) ;
if ( offset = = - 1 ) return - 1 ;
// 'Manual' open("r+b") to avoid munmap()
if ( fp_ ! = 0 ) {
std : : fclose ( fp_ ) ;
fp_ = 0 ;
}
openMode_ = " r+b " ;
opMode_ = opSeek ;
fp_ = std : : fopen ( path_ . c_str ( ) , openMode_ . c_str ( ) ) ;
if ( ! fp_ ) return 1 ;
return std : : fseek ( fp_ , offset , SEEK_SET ) ;
} // FileIo::Impl::switchMode
int FileIo : : Impl : : stat ( StructStat & buf ) const
{
int ret = 0 ;
# ifdef EXV_UNICODE_PATH
if ( wpMode_ = = wpUnicode ) {
struct _stat st ;
ret = : : _wstat ( wpath_ . c_str ( ) , & st ) ;
if ( 0 = = ret ) {
buf . st_size = st . st_size ;
buf . st_mode = st . st_mode ;
}
}
else
# endif
{
struct stat st ;
ret = : : stat ( path_ . c_str ( ) , & st ) ;
if ( 0 = = ret ) {
buf . st_size = st . st_size ;
buf . st_mode = st . st_mode ;
}
}
return ret ;
} // FileIo::Impl::stat
FileIo : : FileIo ( const std : : string & path )
: p_ ( new Impl ( path ) )
{
}
# ifdef EXV_UNICODE_PATH
FileIo : : FileIo ( const std : : wstring & wpath )
: p_ ( new Impl ( wpath ) )
{
}
# endif
FileIo : : ~ FileIo ( )
{
close ( ) ;
delete p_ ;
}
int FileIo : : munmap ( )
{
int rc = 0 ;
if ( pMappedArea_ ! = 0 ) {
if ( p _- > p MappedArea_ ! = 0 ) {
# if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP
if ( : : munmap ( pMappedArea_ , mappedLength_ ) ! = 0 ) {
if ( : : munmap ( p _- > p MappedArea_, p_ - > mappedLength_ ) ! = 0 ) {
rc = 1 ;
}
# elif defined WIN32 && !defined __CYGWIN__
UnmapViewOfFile ( p_ - > pMappedArea_ ) ;
CloseHandle ( p_ - > hMap_ ) ;
p_ - > hMap_ = 0 ;
CloseHandle ( p_ - > hFile_ ) ;
p_ - > hFile_ = 0 ;
# else
if ( isWriteable_ ) {
write ( pMappedArea_ , mappedLength_ ) ;
if ( p_- > isWriteable_) {
write ( p _- > p MappedArea_, p_ - > mappedLength_ ) ;
}
if ( isMalloced_ ) {
delete [ ] pMappedArea_ ;
isMalloced_ = false ;
if ( p_- > isMalloced_) {
delete [ ] p _- > p MappedArea_;
p_- > isMalloced_ = false ;
}
# endif
}
if ( isWriteable_ ) {
if ( fp_ ! = 0 ) switchMode ( opRead ) ;
isWriteable_ = false ;
if ( p_- > isWriteable_) {
if ( p_- > fp_ ! = 0 ) p_- > switchMode( Impl : : opRead ) ;
p_- > isWriteable_ = false ;
}
pMappedArea_ = 0 ;
mappedLength_ = 0 ;
p _- > p MappedArea_ = 0 ;
p_- > mappedLength_ = 0 ;
return rc ;
}
byte * FileIo : : mmap ( bool isWriteable )
{
assert ( fp_ ! = 0 ) ;
assert ( p_- > fp_ ! = 0 ) ;
if ( munmap ( ) ! = 0 ) {
throw Error ( 2 , path_ , strError ( ) , " munmap " ) ;
throw Error ( 2 , p _- > p ath_, strError ( ) , " munmap " ) ;
}
mappedLength_ = size ( ) ;
isWriteable_ = isWriteable ;
p_ - > mappedLength_ = size ( ) ;
p_ - > isWriteable_ = isWriteable ;
if ( p_ - > isWriteable_ & & p_ - > switchMode ( Impl : : opWrite ) ! = 0 ) return 0 ;
# if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP
int prot = PROT_READ ;
if ( isWriteable_ ) {
if ( p_- > isWriteable_) {
prot | = PROT_WRITE ;
if ( switchMode ( opWrite ) ! = 0 ) return 0 ;
}
void * rc = : : mmap ( 0 , mappedLength_ , prot , MAP_SHARED , fileno ( fp_ ) , 0 ) ;
void * rc = : : mmap ( 0 , p_- > mappedLength_, prot , MAP_SHARED , fileno ( p_ - > fp_ ) , 0 ) ;
if ( MAP_FAILED = = rc ) {
throw Error ( 2 , path_ , strError ( ) , " mmap " ) ;
}
pMappedArea_ = static_cast < byte * > ( rc ) ;
# else
// Workaround for platforms without mmap: Read the file into memory
DataBuf buf ( static_cast < long > ( mappedLength_ ) ) ;
read ( buf . pData_ , buf . size_ ) ;
if ( error ( ) | | eof ( ) ) throw Error ( 2 , path_ , strError ( ) , " FileIo::mmap " ) ;
pMappedArea_ = buf . release ( ) . first ;
isMalloced_ = true ;
# endif
return pMappedArea_ ;
throw Error ( 2 , p_ - > path_ , strError ( ) , " mmap " ) ;
}
p_ - > pMappedArea_ = static_cast < byte * > ( rc ) ;
int FileIo : : stat ( StructStat & buf ) const
{
int ret = 0 ;
# ifdef EXV_UNICODE_PATH
if ( wpMode_ = = wpUnicode ) {
struct _stat st ;
ret = : : _wstat ( wpath_ . c_str ( ) , & st ) ;
if ( 0 = = ret ) {
buf . st_size = st . st_size ;
buf . st_mode = st . st_mode ;
# elif defined WIN32 && !defined __CYGWIN__
// Windows implementation
// TODO: An attempt to map a file with a length of 0 (zero) fails with
// an error code of ERROR_FILE_INVALID.
// Applications should test for files with a length of 0 (zero) and
// reject those files.
DWORD dwAccess = FILE_MAP_READ ;
DWORD flProtect = PAGE_READONLY ;
if ( isWriteable ) {
dwAccess = FILE_MAP_WRITE ;
flProtect = PAGE_READWRITE ;
}
HANDLE hPh = GetCurrentProcess ( ) ;
HANDLE hFd = ( HANDLE ) _get_osfhandle ( fileno ( p_ - > fp_ ) ) ;
if ( hFd = = INVALID_HANDLE_VALUE ) {
throw Error ( 2 , p_ - > path_ , " MSG1 " , " _get_osfhandle " ) ;
}
else
# endif
{
struct stat st ;
ret = : : stat ( path_ . c_str ( ) , & st ) ;
if ( 0 = = ret ) {
buf . st_size = st . st_size ;
buf . st_mode = st . st_mode ;
if ( ! DuplicateHandle ( hPh , hFd , hPh , & p_ - > hFile_ , 0 , false , DUPLICATE_SAME_ACCESS ) ) {
throw Error ( 2 , p_ - > path_ , " MSG2 " , " DuplicateHandle " ) ;
}
p_ - > hMap_ = CreateFileMapping ( p_ - > hFile_ , 0 , flProtect , 0 , p_ - > mappedLength_ , 0 ) ;
if ( p_ - > hMap_ = = 0 ) {
throw Error ( 2 , p_ - > path_ , " MSG3 " , " CreateFileMapping " ) ;
}
return ret ;
void * rc = MapViewOfFile ( p_ - > hMap_ , dwAccess , 0 , 0 , 0 ) ;
if ( rc = = 0 ) {
throw Error ( 2 , p_ - > path_ , " MSG4 " , " CreateFileMapping " ) ;
}
p_ - > pMappedArea_ = static_cast < byte * > ( rc ) ;
# else
// Workaround for platforms without mmap: Read the file into memory
DataBuf buf ( static_cast < long > ( p_ - > mappedLength_ ) ) ;
read ( buf . pData_ , buf . size_ ) ;
if ( error ( ) | | eof ( ) ) throw Error ( 2 , p_ - > path_ , strError ( ) , " FileIo::mmap " ) ;
p_ - > pMappedArea_ = buf . release ( ) . first ;
p_ - > isMalloced_ = true ;
# endif
return p_ - > pMappedArea_ ;
}
BasicIo : : AutoPtr FileIo : : temporary ( ) const
{
BasicIo : : AutoPtr basicIo ;
StructStat buf ;
int ret = stat ( buf ) ;
Impl: : StructStat buf ;
int ret = p_- > stat( buf ) ;
// If file is > 1MB then use a file, otherwise use memory buffer
if ( ret ! = 0 | | buf . st_size > 1048576 ) {
pid_t pid = : : getpid ( ) ;
std : : auto_ptr < FileIo > fileIo ;
# ifdef EXV_UNICODE_PATH
if ( wpMode_ = = wpUnicode ) {
std : : wstring tmpname = wpath_ + s2ws ( toString ( pid ) ) ;
if ( p_- > wpMode_ = = Impl : : wpUnicode ) {
std : : wstring tmpname = p_- > wpath_ + s2ws ( toString ( pid ) ) ;
fileIo = std : : auto_ptr < FileIo > ( new FileIo ( tmpname ) ) ;
}
else
# endif
{
std : : string tmpname = p ath_ + toString ( pid ) ;
std : : string tmpname = p _- > p ath_ + toString ( pid ) ;
fileIo = std : : auto_ptr < FileIo > ( new FileIo ( tmpname ) ) ;
}
if ( fileIo - > open ( " w+b " ) ! = 0 ) {
throw Error ( 10 , p ath_, " w+b " , strError ( ) ) ;
throw Error ( 10 , p _- > p ath_, " w+b " , strError ( ) ) ;
}
basicIo = fileIo ;
}
@ -214,74 +381,26 @@ namespace Exiv2 {
return basicIo ;
}
int FileIo : : switchMode ( OpMode opMode )
{
assert ( fp_ ! = 0 ) ;
if ( opMode_ = = opMode ) return 0 ;
OpMode oldOpMode = opMode_ ;
opMode_ = opMode ;
bool reopen = true ;
switch ( opMode ) {
case opRead :
// Flush if current mode allows reading, else reopen (in mode "r+b"
// as in this case we know that we can write to the file)
if ( openMode_ [ 0 ] = = ' r ' | | openMode_ [ 1 ] = = ' + ' ) reopen = false ;
break ;
case opWrite :
// Flush if current mode allows writing, else reopen
if ( openMode_ [ 0 ] ! = ' r ' | | openMode_ [ 1 ] = = ' + ' ) reopen = false ;
break ;
case opSeek :
reopen = false ;
break ;
}
if ( ! reopen ) {
// Don't do anything when switching _from_ opSeek mode; we
// flush when switching _to_ opSeek.
if ( oldOpMode = = opSeek ) return 0 ;
// Flush. On msvcrt fflush does not do the job
std : : fseek ( fp_ , 0 , SEEK_CUR ) ;
return 0 ;
}
// Reopen the file
long offset = std : : ftell ( fp_ ) ;
if ( offset = = - 1 ) return - 1 ;
// 'Manual' open("r+b") to avoid munmap()
if ( fp_ ! = 0 ) {
std : : fclose ( fp_ ) ;
fp_ = 0 ;
}
openMode_ = " r+b " ;
opMode_ = opSeek ;
fp_ = std : : fopen ( path_ . c_str ( ) , openMode_ . c_str ( ) ) ;
if ( ! fp_ ) return 1 ;
return std : : fseek ( fp_ , offset , SEEK_SET ) ;
}
long FileIo : : write ( const byte * data , long wcount )
{
assert ( fp_ ! = 0 ) ;
if ( switchMode( opWrite ) ! = 0 ) return 0 ;
return ( long ) std : : fwrite ( data , 1 , wcount , fp_) ;
assert ( p_ - > fp_ ! = 0 ) ;
if ( p_ - > switchMode ( Impl : : opWrite ) ! = 0 ) return 0 ;
return ( long ) std : : fwrite ( data , 1 , wcount , p_ - > fp_ ) ;
}
long FileIo : : write ( BasicIo & src )
{
assert ( fp_ ! = 0 ) ;
assert ( p_ - > fp_ ! = 0 ) ;
if ( static_cast < BasicIo * > ( this ) = = & src ) return 0 ;
if ( ! src . isopen ( ) ) return 0 ;
if ( switchMode( opWrite ) ! = 0 ) return 0 ;
if ( p_ - > switchMode ( Impl : : opWrite ) ! = 0 ) return 0 ;
byte buf [ 4096 ] ;
long readCount = 0 ;
long writeCount = 0 ;
long writeTotal = 0 ;
while ( ( readCount = src . read ( buf , sizeof ( buf ) ) ) ) {
writeTotal + = writeCount = ( long ) std : : fwrite ( buf , 1 , readCount , fp_) ;
writeTotal + = writeCount = ( long ) std : : fwrite ( buf , 1 , readCount , p_ - > fp_ ) ;
if ( writeCount ! = readCount ) {
// try to reset back to where write stopped
src . seek ( writeCount - readCount , BasicIo : : cur ) ;
@ -294,8 +413,8 @@ namespace Exiv2 {
void FileIo : : transfer ( BasicIo & src )
{
const bool wasOpen = ( fp_ ! = 0 ) ;
const std : : string lastMode ( openMode_) ;
const bool wasOpen = ( p_- > fp_ ! = 0 ) ;
const std : : string lastMode ( p_- > openMode_) ;
FileIo * fileIo = dynamic_cast < FileIo * > ( & src ) ;
if ( fileIo ) {
@ -305,15 +424,15 @@ namespace Exiv2 {
if ( open ( " w+b " ) ! = 0 ) {
// Remove the (temporary) file
# ifdef EXV_UNICODE_PATH
if ( fileIo - > wpMode_ = = wpUnicode ) {
: : _wremove ( fileIo - > wpath_. c_str ( ) ) ;
if ( fileIo - > p_- > wpMode_ = = Impl : : wpUnicode ) {
: : _wremove ( fileIo - > p_- > wpath_. c_str ( ) ) ;
}
else
# endif
{
: : remove ( fileIo - > p ath_. c_str ( ) ) ;
: : remove ( fileIo - > p _- > p ath_. c_str ( ) ) ;
}
throw Error ( 10 , p ath_, " w+b " , strError ( ) ) ;
throw Error ( 10 , p _- > p ath_, " w+b " , strError ( ) ) ;
}
close ( ) ;
@ -322,13 +441,13 @@ namespace Exiv2 {
char * pf = 0 ;
# ifdef EXV_UNICODE_PATH
wchar_t * wpf = 0 ;
if ( wpMode_ = = wpUnicode ) {
wpf = const_cast < wchar_t * > ( wpath_. c_str ( ) ) ;
if ( p_- > wpMode_ = = Impl : : wpUnicode ) {
wpf = const_cast < wchar_t * > ( p_- > wpath_. c_str ( ) ) ;
}
else
# endif
{
pf = const_cast < char * > ( p ath_. c_str ( ) ) ;
pf = const_cast < char * > ( p _- > p ath_. c_str ( ) ) ;
}
// Get the permissions of the file, or linked-to file, on platforms which have lstat
@ -346,13 +465,13 @@ namespace Exiv2 {
}
origStMode = buf1 . st_mode ;
DataBuf lbuf ; // So that the allocated memory is freed. Must have same scope as pf
// In case p ath_ is a symlink, get the path of the linked-to file
// In case p _->p ath_ is a symlink, get the path of the linked-to file
if ( statOk & & S_ISLNK ( buf1 . st_mode ) ) {
lbuf . alloc ( buf1 . st_size + 1 ) ;
memset ( lbuf . pData_ , 0x0 , lbuf . size_ ) ;
pf = reinterpret_cast < char * > ( lbuf . pData_ ) ;
if ( : : readlink ( p ath_. c_str ( ) , pf , lbuf . size_ - 1 ) = = - 1 ) {
throw Error ( 2 , p ath_, strError ( ) , " readlink " ) ;
if ( : : readlink ( p _- > p ath_. c_str ( ) , pf , lbuf . size_ - 1 ) = = - 1 ) {
throw Error ( 2 , p _- > p ath_, strError ( ) , " readlink " ) ;
}
// We need the permissions of the file, not the symlink
if ( : : stat ( pf , & buf1 ) = = - 1 ) {
@ -364,8 +483,8 @@ namespace Exiv2 {
origStMode = buf1 . st_mode ;
}
# else // EXV_HAVE_LSTAT
StructStat buf1 ;
if ( stat( buf1 ) = = - 1 ) {
Impl: : StructStat buf1 ;
if ( p_- > stat( buf1 ) = = - 1 ) {
statOk = false ;
}
origStMode = buf1 . st_mode ;
@ -373,14 +492,14 @@ namespace Exiv2 {
// MSVCRT rename that does not overwrite existing files
# ifdef EXV_UNICODE_PATH
if ( wpMode_ = = wpUnicode ) {
if ( p_- > wpMode_ = = Impl : : wpUnicode ) {
if ( fileExists ( wpf ) & & : : _wremove ( wpf ) ! = 0 ) {
throw Error ( 2 , wpf , strError ( ) , " ::_wremove " ) ;
}
if ( : : _wrename ( fileIo - > wpath_. c_str ( ) , wpf ) = = - 1 ) {
throw Error ( 17 , ws2s ( fileIo - > wpath_) , wpf , strError ( ) ) ;
if ( : : _wrename ( fileIo - > p_- > wpath_. c_str ( ) , wpf ) = = - 1 ) {
throw Error ( 17 , ws2s ( fileIo - > p_- > wpath_) , wpf , strError ( ) ) ;
}
: : _wremove ( fileIo - > wpath_. c_str ( ) ) ;
: : _wremove ( fileIo - > p_- > wpath_. c_str ( ) ) ;
// Check permissions of new file
struct _stat buf2 ;
if ( statOk & & : : _wstat ( wpf , & buf2 ) = = - 1 ) {
@ -397,17 +516,17 @@ namespace Exiv2 {
# endif
}
}
} // if ( wpMode_ == wpUnicode)
} // if ( p_-> wpMode_ == Impl:: wpUnicode)
else
# endif // EXV_UNICODE_PATH
{
if ( fileExists ( pf ) & & : : remove ( pf ) ! = 0 ) {
throw Error ( 2 , pf , strError ( ) , " ::remove " ) ;
}
if ( : : rename ( fileIo - > p ath_. c_str ( ) , pf ) = = - 1 ) {
throw Error ( 17 , fileIo - > p ath_, pf , strError ( ) ) ;
if ( : : rename ( fileIo - > p _- > p ath_. c_str ( ) , pf ) = = - 1 ) {
throw Error ( 17 , fileIo - > p _- > p ath_, pf , strError ( ) ) ;
}
: : remove ( fileIo - > p ath_. c_str ( ) ) ;
: : remove ( fileIo - > p _- > p ath_. c_str ( ) ) ;
// Check permissions of new file
struct stat buf2 ;
if ( statOk & & : : stat ( pf , & buf2 ) = = - 1 ) {
@ -429,7 +548,7 @@ namespace Exiv2 {
else {
// Generic handling, reopen both to reset to start
if ( open ( " w+b " ) ! = 0 ) {
throw Error ( 10 , p ath_, " w+b " , strError ( ) ) ;
throw Error ( 10 , p _- > p ath_, " w+b " , strError ( ) ) ;
}
if ( src . open ( ) ! = 0 ) {
throw Error ( 9 , src . path ( ) , strError ( ) ) ;
@ -440,24 +559,24 @@ namespace Exiv2 {
if ( wasOpen ) {
if ( open ( lastMode ) ! = 0 ) {
throw Error ( 10 , p ath_, lastMode , strError ( ) ) ;
throw Error ( 10 , p _- > p ath_, lastMode , strError ( ) ) ;
}
}
else close ( ) ;
if ( error ( ) | | src . error ( ) ) throw Error ( 18 , p ath_, strError ( ) ) ;
if ( error ( ) | | src . error ( ) ) throw Error ( 18 , p _- > p ath_, strError ( ) ) ;
}
int FileIo : : putb ( byte data )
{
assert ( fp_ ! = 0 ) ;
if ( switchMode( opWrite ) ! = 0 ) return EOF ;
return putc ( data , fp_) ;
assert ( p_- > fp_ ! = 0 ) ;
if ( p_- > switchMode( Impl : : opWrite ) ! = 0 ) return EOF ;
return putc ( data , p_- > fp_) ;
}
int FileIo : : seek ( long offset , Position pos )
{
assert ( fp_ ! = 0 ) ;
assert ( p_- > fp_ ! = 0 ) ;
int fileSeek = 0 ;
switch ( pos ) {
@ -466,30 +585,29 @@ namespace Exiv2 {
case BasicIo : : end : fileSeek = SEEK_END ; break ;
}
if ( switchMode( opSeek ) ! = 0 ) return 1 ;
return std : : fseek ( fp_, offset , fileSeek ) ;
if ( p_- > switchMode( Impl : : opSeek ) ! = 0 ) return 1 ;
return std : : fseek ( p_- > fp_, offset , fileSeek ) ;
}
long FileIo : : tell ( ) const
{
assert ( fp_ ! = 0 ) ;
return std : : ftell ( fp_) ;
assert ( p_- > fp_ ! = 0 ) ;
return std : : ftell ( p_- > fp_) ;
}
long FileIo : : size ( ) const
{
// Flush and commit only if the file is open for writing
if ( fp_ ! = 0 & & ( openMode_[ 0 ] ! = ' r ' | | openMode_ [ 1 ] = = ' + ' ) ) {
std : : fflush ( fp_) ;
if ( p_- > fp_ ! = 0 & & ( p_- > openMode_[ 0 ] ! = ' r ' | | p_ - > openMode_ [ 1 ] = = ' + ' ) ) {
std : : fflush ( p_- > fp_) ;
# if defined WIN32 && !defined __CYGWIN__
// This is required on msvcrt before stat after writing to a file
_commit ( _fileno ( fp_) ) ;
_commit ( _fileno ( p_- > fp_) ) ;
# endif
}
StructStat buf ;
int ret = stat( buf ) ;
Impl: : StructStat buf ;
int ret = p_- > stat( buf ) ;
if ( ret ! = 0 ) return - 1 ;
return buf . st_size ;
@ -504,40 +622,40 @@ namespace Exiv2 {
int FileIo : : open ( const std : : string & mode )
{
close ( ) ;
openMode_ = mode ;
opMode_ = opSeek ;
p_- > openMode_ = mode ;
p_- > opMode_ = Impl : : opSeek ;
# ifdef EXV_UNICODE_PATH
if ( wpMode_ = = wpUnicode ) {
fp_ = : : _wfopen ( wpath_ . c_str ( ) , s2ws ( mode ) . c_str ( ) ) ;
if ( p_- > wpMode_ = = Impl : : wpUnicode ) {
p_- > fp_ = : : _wfopen ( p_ - > wpath_ . c_str ( ) , s2ws ( mode ) . c_str ( ) ) ;
}
else
# endif
{
fp_ = : : fopen ( path_ . c_str ( ) , mode . c_str ( ) ) ;
p_- > fp_ = : : fopen ( p_ - > path_ . c_str ( ) , mode . c_str ( ) ) ;
}
if ( ! fp_) return 1 ;
if ( ! p_- > fp_) return 1 ;
return 0 ;
}
bool FileIo : : isopen ( ) const
{
return fp_ ! = 0 ;
return p_- > fp_ ! = 0 ;
}
int FileIo : : close ( )
{
int rc = 0 ;
if ( munmap ( ) ! = 0 ) rc = 2 ;
if ( fp_ ! = 0 ) {
if ( std : : fclose ( fp_) ! = 0 ) rc | = 1 ;
fp_= 0 ;
if ( p_- > fp_ ! = 0 ) {
if ( std : : fclose ( p_- > fp_) ! = 0 ) rc | = 1 ;
p_- > fp_= 0 ;
}
return rc ;
}
DataBuf FileIo : : read ( long rcount )
{
assert ( fp_ ! = 0 ) ;
assert ( p_- > fp_ ! = 0 ) ;
DataBuf buf ( rcount ) ;
long readCount = read ( buf . pData_ , buf . size_ ) ;
buf . size_ = readCount ;
@ -546,46 +664,46 @@ namespace Exiv2 {
long FileIo : : read ( byte * buf , long rcount )
{
assert ( fp_ ! = 0 ) ;
if ( switchMode( opRead ) ! = 0 ) return 0 ;
return ( long ) std : : fread ( buf , 1 , rcount , fp_) ;
assert ( p_- > fp_ ! = 0 ) ;
if ( p_- > switchMode( Impl : : opRead ) ! = 0 ) return 0 ;
return ( long ) std : : fread ( buf , 1 , rcount , p_- > fp_) ;
}
int FileIo : : getb ( )
{
assert ( fp_ ! = 0 ) ;
if ( switchMode( opRead ) ! = 0 ) return EOF ;
return getc ( fp_) ;
assert ( p_- > fp_ ! = 0 ) ;
if ( p_- > switchMode( Impl : : opRead ) ! = 0 ) return EOF ;
return getc ( p_- > fp_) ;
}
int FileIo : : error ( ) const
{
return fp_ ! = 0 ? ferror ( fp_ ) : 0 ;
return p_- > fp_ ! = 0 ? ferror ( p_ - > fp_ ) : 0 ;
}
bool FileIo : : eof ( ) const
{
assert ( fp_ ! = 0 ) ;
return feof ( fp_) ! = 0 ;
assert ( p_- > fp_ ! = 0 ) ;
return feof ( p_- > fp_) ! = 0 ;
}
std : : string FileIo : : path ( ) const
{
# ifdef EXV_UNICODE_PATH
if ( wpMode_ = = wpUnicode ) {
return ws2s ( wpath_) ;
if ( p_- > wpMode_ = = Impl : : wpUnicode ) {
return ws2s ( p_- > wpath_) ;
}
# endif
return p ath_;
return p _- > p ath_;
}
# ifdef EXV_UNICODE_PATH
std : : wstring FileIo : : wpath ( ) const
{
if ( wpMode_ = = wpStandard ) {
return s2ws ( p ath_) ;
if ( p_- > wpMode_ = = Impl : : wpStandard ) {
return s2ws ( p _- > p ath_) ;
}
return wpath_;
return p_- > wpath_;
}
# endif
@ -627,7 +745,7 @@ namespace Exiv2 {
if ( ! isMalloced_ ) {
// Minimum size for 1st block is 32kB
long size = std: : max ( 32768 * ( 1 + need / 32768 ) , size_ ) ;
long size = EXV_MAX ( 32768 * ( 1 + need / 32768 ) , size_ ) ;
byte * data = ( byte * ) std : : malloc ( size ) ;
std : : memcpy ( data , data_ , size_ ) ;
data_ = data ;
@ -773,7 +891,7 @@ namespace Exiv2 {
long MemIo : : read ( byte * buf , long rcount )
{
long avail = size_ - idx_ ;
long allow = std: : min ( rcount , avail ) ;
long allow = EXV_MIN ( rcount , avail ) ;
std : : memcpy ( buf , & data_ [ idx_ ] , allow ) ;
idx_ + = allow ;
if ( rcount > avail ) eof_ = true ;