Close files before calling FileIo::size() (which uses stat). This is necessary on Win32 it seems. Fixes bug #428. Changed default mode of FileIo::open to "rb" and added FileIo::switchMode. Fixes bug #429. Added a hack to make test output of exiv2-test.sh more readable on MinGW.

v0.27.3
Andreas Huggel 20 years ago
parent b8e809195c
commit 1b41ce9931

@ -45,6 +45,7 @@ EXIV2_RCSID("@(#) $Id$");
#include "error.hpp"
// + standard includes
#include <string>
#include <cassert>
#include <cstdio> // for remove()
#include <sys/types.h> // for stat()
@ -94,33 +95,65 @@ namespace Exiv2 {
return basicIo;
}
long FileIo::write(const byte* data, long wcount )
int FileIo::switchMode(OpMode opMode)
{
assert(fp_ != 0);
if (opMode_ == opMode) return 0;
bool reopen = true;
std::string mode = "r+b";
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_.substr(0, 2) == "w+"
|| openMode_.substr(0, 2) == "a+") reopen = false;
break;
case opWrite:
// Flush if current mode allows writing, else reopen
if ( openMode_.substr(0, 2) == "r+"
|| openMode_[0] == 'w'
|| openMode_[0] == 'a') 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 (opMode_ == opSeek) return 0;
// ANSI C requires a flush or seek when switching
// between read and write modes.
if (opMode_ == opRead) {
// on msvcrt fflush does not do the job
// Flush. On msvcrt fflush does not do the job
fseek(fp_, 0, SEEK_CUR);
opMode_ = opMode;
return 0;
}
opMode_ = opWrite;
// Reopen the file
long offset = ftell(fp_);
if (offset == -1) return -1;
if (open(mode) != 0) return 1;
opMode_ = opMode;
return fseek(fp_, offset, SEEK_SET);
}
long FileIo::write(const byte* data, long wcount)
{
assert(fp_ != 0);
if (switchMode(opWrite) != 0) return 0;
return (long)fwrite(data, 1, wcount, fp_);
}
long FileIo::write(BasicIo& src)
{
assert(fp_ != 0);
if (static_cast<BasicIo*>(this)==&src) return 0;
if (static_cast<BasicIo*>(this) == &src) return 0;
if (!src.isopen()) return 0;
// ANSI C requires a flush or seek when switching
// between read and write modes.
if (opMode_ == opRead) {
// on msvcrt fflush does not do the job
fseek(fp_, 0, SEEK_CUR);
}
opMode_ = opWrite;
if (switchMode(opWrite) != 0) return 0;
byte buf[4096];
long readCount = 0;
@ -182,11 +215,7 @@ namespace Exiv2 {
int FileIo::putb(byte data)
{
assert(fp_ != 0);
if (opMode_ == opRead) {
// on msvcrt fflush does not do the job
fseek(fp_, 0, SEEK_CUR);
}
opMode_ = opWrite;
if (switchMode(opWrite) != 0) return EOF;
return putc(data, fp_);
}
@ -218,6 +247,10 @@ namespace Exiv2 {
long FileIo::size() const
{
#if defined WIN32 && !defined __CYGWIN__
// On msvcrt stat only works if the file is not open, or so it seems
assert(fp_ == 0);
#endif
if (fp_ != 0) {
fflush(fp_);
}
@ -230,8 +263,8 @@ namespace Exiv2 {
int FileIo::open()
{
// Default open is in read-write binary mode
return open("r+b");
// Default open is in read-only binary mode
return open("rb");
}
int FileIo::open(const std::string& mode)
@ -273,24 +306,14 @@ namespace Exiv2 {
long FileIo::read(byte* buf, long rcount)
{
assert(fp_ != 0);
if (opMode_ == opWrite) {
// on msvcrt fflush does not do the job
fseek(fp_, 0, SEEK_CUR);
}
opMode_ = opRead;
if (switchMode(opRead) != 0) return 0;
return (long)fread(buf, 1, rcount, fp_);
}
int FileIo::getb()
{
assert(fp_ != 0);
if (opMode_ == opWrite) {
// on msvcrt fflush does not do the job
fseek(fp_, 0, SEEK_CUR);
}
opMode_ = opRead;
if (switchMode(opRead) != 0) return EOF;
return getc(fp_);
}

@ -295,7 +295,7 @@ namespace Exiv2 {
*/
int open(const std::string& mode);
/*!
@brief Open the file using using the default access mode of "r+b".
@brief Open the file using using the default access mode of "rb".
This method can also be used to "reopen" a file which will flush
any unwritten data and reset the IO position to the start.
@return 0 if successful;<BR>
@ -406,6 +406,8 @@ namespace Exiv2 {
/*!
@brief Flush any buffered writes and get the current file size
in bytes.
@note On Win32 systems the file must be closed prior to calling this
function.
@return Size of the file in bytes;<BR>
-1 if failure;
*/
@ -445,6 +447,16 @@ namespace Exiv2 {
std::string openMode_;
FILE *fp_;
OpMode opMode_;
// 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);
}; // class FileIo
/*!
@ -622,7 +634,7 @@ namespace Exiv2 {
ByteVector data_;
ByteVector::size_type idx_;
//METHODS
// METHODS
void checkSize(long wcount);
}; // class MemIo
} // namespace Exiv2

@ -73,6 +73,11 @@ try {
memIo1.seek(0, BasicIo::beg);
fileOut1.write(memIo1);
// On Win32 files must be closed before stat
memIo1.close();
fileIn.close();
fileOut1.close();
// Make sure they are all the same size
if(fileIn.size() != memIo1.size() || memIo1.size() != fileOut1.size()) {
std::cerr << argv[0] <<
@ -97,7 +102,10 @@ try {
if (rc != 0) return rc;
// Another test of reading and writing
fileOut1.seek(0, BasicIo::beg);
if (fileOut1.open() != 0) {
throw Error(9, fileOut1.path(), strError());
}
memIo2.seek(0, BasicIo::beg);
FileIo fileOut2(argv[3]);
if (fileOut2.open("w+b") != 0) {
@ -146,13 +154,18 @@ int WriteReadSeek(BasicIo &io)
std::cerr << ": WRS initial write failed\n";
return 2;
}
// On Win32 files must be closed before stat
io.close();
if (io.size() != len1) {
std::cerr << ": WRS size is not " << len1 << "\n";
return 2;
}
io.seek(-len1, BasicIo::cur);
if (io.open() != 0) {
throw Error(9, io.path(), strError());
}
int c = EOF;
memset(buf, -1, sizeof(buf));

@ -93,6 +93,12 @@ diff iii kkk
) > $results 2>&1
if [ `../config/config.guess` = "i686-pc-mingw32" ] ; then
sed 's,\\,/,g' $results > ${results}-new
mv -f ${results}-new $results
unix2dos -q $results
fi
diff -q -w $diffargs $results $good
rc=$?
if [ $rc -eq 0 ] ; then

Loading…
Cancel
Save