#579: Implemented mmap for Windows directly in FileIo and made that class use the Pimpl idiom (#510) to de-clutter the interface. Unrelated: Added EXV_MIN/MAX macros, allow iconv config in commercial version.
This commit is contained in:
parent
db0a5b8338
commit
83cd2efab9
@ -25,11 +25,11 @@
|
||||
native language is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
#endif /* !EXV_COMMERCIAL_VERSION */
|
||||
|
||||
/* Define to 1 if you have the `iconv' function. */
|
||||
#undef HAVE_ICONV
|
||||
|
||||
#endif /* !EXV_COMMERCIAL_VERSION */
|
||||
|
||||
/* Define to `const' or to empty, depending on the second argument of `iconv'. */
|
||||
#undef ICONV_CONST
|
||||
|
||||
|
||||
@ -573,21 +573,6 @@ copy/y ..\..\..\zlib-1.2.3\projects\visualc6\Win32_DLL_Release\zlib1.dll $(OutDi
|
||||
<File
|
||||
RelativePath="..\include\exv_msvc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mmap.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\sys\mman.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\sys\socket.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\sys\types.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\winposix_export.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
|
||||
@ -43,14 +43,11 @@ typedef int pid_t;
|
||||
native language is requested. */
|
||||
# undef EXV_ENABLE_NLS
|
||||
|
||||
#endif /* !EXV_COMMERCIAL_VERSION */
|
||||
|
||||
/* Define to 1 if you have the `iconv' function. */
|
||||
# undef EXV_HAVE_ICONV
|
||||
|
||||
/* Define to 1 to enable conversion of UCS2 encoded Windows tags to UTF-8. */
|
||||
# undef EXV_HAVE_PRINTUCS2
|
||||
|
||||
#endif /* !EXV_COMMERCIAL_VERSION */
|
||||
|
||||
/* Define as 1 if you have the `zlib' library. (0 to omit zlib) [png support] */
|
||||
#define HAVE_LIBZ 1
|
||||
|
||||
@ -72,16 +69,11 @@ typedef int pid_t;
|
||||
/* Windows unicode path support */
|
||||
#define EXV_UNICODE_PATH
|
||||
|
||||
/* Define to 1 if you have the "sys/mman.h header file (and supporting code of course) */
|
||||
/* At this time (between 0.18.1 and 0.19) this is used by TIFF files to avoid reading */
|
||||
/* the total file into memory returning in a 6x improvement in exiv2 on 2mb tiff files */
|
||||
#define EXV_HAVE_SYS_MMAN_H 1
|
||||
#ifdef EXV_HAVE_SYS_MMAN_H
|
||||
#if EXV_HAVE_SYS_MMAN_H
|
||||
#define EXV_HAVE_MMAP 1
|
||||
#define EXV_HAVE_MUNMAP 1
|
||||
#endif
|
||||
#endif
|
||||
/* Define to 1 if you have the `mmap' function. */
|
||||
/* #undef EXV_HAVE_MMAP */
|
||||
|
||||
/* Define to 1 if you have the `munmap' function. */
|
||||
/* #undef EXV_HAVE_MUNMAP */
|
||||
|
||||
/* Shared library support */
|
||||
#ifdef EXV_HAVE_DLL
|
||||
|
||||
@ -1,57 +0,0 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
|
||||
|
||||
These sources are based on ftp://g.oswego.edu/pub/misc/malloc.c
|
||||
file by Doug Lea, released to the public domain.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KDEWIN_SYS_MMAN_H
|
||||
#define KDEWIN_SYS_MMAN_H
|
||||
|
||||
// include everywhere
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PROT_NONE 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
|
||||
/* These values don't really matter in windows mmap emulation */
|
||||
#define MAP_FILE 0
|
||||
#define MAP_SHARED 1
|
||||
#define MAP_PRIVATE 2
|
||||
#define MAP_TYPE 0xF
|
||||
#define MAP_FIXED 0x10
|
||||
#define MAP_ANONYMOUS 0x20
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
|
||||
KDEWIN32_EXPORT void *mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
|
||||
KDEWIN32_EXPORT int munmap(void *start, size_t length);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // KDEWIN_SYS_MMAN_H
|
||||
@ -1,7 +0,0 @@
|
||||
#ifndef _sys_socket_h_
|
||||
#define _sys_socket_h_
|
||||
|
||||
// rmills
|
||||
// minimum to enable mmap.cpp to compile without change
|
||||
|
||||
#endif
|
||||
@ -1,8 +0,0 @@
|
||||
#ifndef _types_h_
|
||||
#define _types_h_
|
||||
// rmills
|
||||
// minimum required by exiv2
|
||||
//
|
||||
#include "winposix_export.h"
|
||||
#endif
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
#ifndef _WINPOSIX_EXPORT_H_
|
||||
#define _WINPOSIX_EXPORT_H_
|
||||
|
||||
// rmills
|
||||
// msvc/include/winposix_export.h
|
||||
//
|
||||
// I'm very appreciative and respectful of the work of Jaroslaw Staniek <js@iidea.pl>
|
||||
// in the KDE libraries where I found msvc/src/mmap.cpp and msvc/mman.h
|
||||
//
|
||||
// http://websvn.kde.org/trunk/KDE/kdelibs/win/include/msvc/sys/mman.h?revision=517357&view=markup&pathrev=519502
|
||||
// http://websvn.kde.org/trunk/KDE/kdelibs/win/src/mmap.c?revision=519502&view=markup&pathrev=519502
|
||||
|
||||
// I have commented 2 essential tiny changes in mmap.cpp to make it compile with MSVC
|
||||
// I've also added a dummy sys/socket.h and sys/types.h file to keep everybody happy!
|
||||
//
|
||||
// the contents of this file are the minimum required to enable exiv2 to compile link and execute the mmap.cpp code
|
||||
//
|
||||
|
||||
#ifndef ENOTSUP
|
||||
#define ENOTSUP 911
|
||||
#endif
|
||||
|
||||
#ifndef off_t
|
||||
#define off_t size_t
|
||||
#endif
|
||||
|
||||
#ifndef KDEWIN32_EXPORT
|
||||
#define KDEWIN32_EXPORT
|
||||
#endif
|
||||
|
||||
// give MSVC 7.1 (VS 2003 .Net) encouragement to ignore _set_errno !
|
||||
#if _MSC_VER < 1400
|
||||
#ifndef _set_errno
|
||||
#define _set_errno(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,196 +0,0 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
Copyright (c) 2006 Christian Ehrlicher <ch.ehrlicher@gmx.de>
|
||||
|
||||
These sources are based on ftp://g.oswego.edu/pub/misc/malloc.c
|
||||
file by Doug Lea, released to the public domain.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <winposix_export.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <io.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifndef SECTION_MAP_EXECUTE_EXPLICIT
|
||||
//not defined in the February 2003 version of the Platform SDK
|
||||
#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020
|
||||
#endif
|
||||
|
||||
#ifndef FILE_MAP_EXECUTE
|
||||
//not defined in the February 2003 version of the Platform SDK
|
||||
#define FILE_MAP_EXECUTE SECTION_MAP_EXECUTE_EXPLICIT
|
||||
#endif
|
||||
|
||||
#define MUNMAP_FAILURE (-1)
|
||||
|
||||
#define USE_MALLOC_LOCK 1
|
||||
|
||||
struct mmapInfos {
|
||||
HANDLE hFile; // the duplicated fd
|
||||
HANDLE hMap; // handle returned by CreateFileMapping
|
||||
void* start; // ptr returned by MapViewOfFile
|
||||
};
|
||||
|
||||
CRITICAL_SECTION cs;
|
||||
|
||||
// rmills - only change is to add long to the following 2 lines
|
||||
static long g_curMMapInfos = 0;
|
||||
static long g_maxMMapInfos = -1;
|
||||
static struct mmapInfos *g_mmapInfos = NULL;
|
||||
#define NEW_MMAP_STRUCT_CNT 10
|
||||
|
||||
static int mapProtFlags(int flags, DWORD *dwAccess)
|
||||
{
|
||||
if ( ( flags & PROT_READ ) == PROT_READ ) {
|
||||
if ( ( flags & PROT_WRITE ) == PROT_WRITE ) {
|
||||
*dwAccess = FILE_MAP_WRITE;
|
||||
if ( ( flags & PROT_EXEC ) == PROT_EXEC ) {
|
||||
return PAGE_EXECUTE_READWRITE;
|
||||
}
|
||||
return PAGE_READWRITE;
|
||||
}
|
||||
if ( ( flags & PROT_EXEC ) == PROT_EXEC ) {
|
||||
*dwAccess = FILE_MAP_EXECUTE;
|
||||
return PAGE_EXECUTE_READ;
|
||||
}
|
||||
*dwAccess = FILE_MAP_READ;
|
||||
return PAGE_READONLY;
|
||||
}
|
||||
if ( ( flags & PROT_WRITE ) == PROT_WRITE ) {
|
||||
*dwAccess = FILE_MAP_COPY;
|
||||
return PAGE_WRITECOPY;
|
||||
}
|
||||
if ( ( flags & PROT_EXEC ) == PROT_EXEC ) {
|
||||
*dwAccess = FILE_MAP_EXECUTE;
|
||||
return PAGE_EXECUTE_READ;
|
||||
}
|
||||
*dwAccess = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
|
||||
{
|
||||
struct mmapInfos mmi;
|
||||
DWORD dwAccess;
|
||||
DWORD flProtect;
|
||||
HANDLE hfd;
|
||||
|
||||
if ( g_maxMMapInfos == -1 ) {
|
||||
g_maxMMapInfos = 0;
|
||||
InitializeCriticalSection( &cs );
|
||||
}
|
||||
|
||||
flProtect = mapProtFlags( flags, &dwAccess );
|
||||
if ( flProtect == 0 ) {
|
||||
_set_errno( EINVAL );
|
||||
return MAP_FAILED;
|
||||
}
|
||||
// we don't support this atm
|
||||
if ( prot == MAP_FIXED ) {
|
||||
_set_errno( ENOTSUP );
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
if ( fd == -1 ) {
|
||||
_set_errno( EBADF );
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
hfd = (HANDLE)_get_osfhandle( fd );
|
||||
if ( hfd == INVALID_HANDLE_VALUE )
|
||||
return MAP_FAILED;
|
||||
|
||||
if ( !DuplicateHandle( GetCurrentProcess(), hfd, GetCurrentProcess(),
|
||||
&mmi.hFile, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
|
||||
#ifdef _DEBUG
|
||||
DWORD dwLastErr = GetLastError();
|
||||
#endif
|
||||
return MAP_FAILED;
|
||||
}
|
||||
mmi.hMap = CreateFileMapping( mmi.hFile, NULL, flProtect,
|
||||
0, length, NULL );
|
||||
if ( mmi.hMap == 0 ) {
|
||||
_set_errno( EACCES );
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
mmi.start = MapViewOfFile( mmi.hMap, dwAccess, 0, offset, 0 );
|
||||
if ( mmi.start == 0 ) {
|
||||
DWORD dwLastErr = GetLastError();
|
||||
if ( dwLastErr == ERROR_MAPPED_ALIGNMENT )
|
||||
_set_errno( EINVAL );
|
||||
else
|
||||
_set_errno( EACCES );
|
||||
return MAP_FAILED;
|
||||
}
|
||||
EnterCriticalSection( &cs );
|
||||
if ( g_mmapInfos == NULL ) {
|
||||
g_maxMMapInfos = NEW_MMAP_STRUCT_CNT;
|
||||
g_mmapInfos = ( struct mmapInfos* )calloc( g_maxMMapInfos,
|
||||
sizeof( struct mmapInfos ) );
|
||||
}
|
||||
if( g_curMMapInfos == g_maxMMapInfos) {
|
||||
g_maxMMapInfos += NEW_MMAP_STRUCT_CNT;
|
||||
g_mmapInfos = ( struct mmapInfos* )realloc( g_mmapInfos,
|
||||
g_maxMMapInfos * sizeof( struct mmapInfos ) );
|
||||
}
|
||||
memcpy( &g_mmapInfos[g_curMMapInfos], &mmi, sizeof( struct mmapInfos) );
|
||||
g_curMMapInfos++;
|
||||
|
||||
LeaveCriticalSection( &cs );
|
||||
|
||||
return mmi.start;
|
||||
}
|
||||
|
||||
int munmap(void *start, size_t length)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for( i = 0; i < g_curMMapInfos; i++ ) {
|
||||
if( g_mmapInfos[i].start == start )
|
||||
break;
|
||||
}
|
||||
if( i == g_curMMapInfos ) {
|
||||
_set_errno( EINVAL );
|
||||
return -1;
|
||||
}
|
||||
|
||||
UnmapViewOfFile( g_mmapInfos[i].start );
|
||||
CloseHandle( g_mmapInfos[i].hMap );
|
||||
CloseHandle( g_mmapInfos[i].hFile );
|
||||
|
||||
EnterCriticalSection( &cs );
|
||||
for( j = i + 1; j < g_curMMapInfos; j++ ) {
|
||||
memcpy( &g_mmapInfos[ j - 1 ], &g_mmapInfos[ j ],
|
||||
sizeof( struct mmapInfos ) );
|
||||
}
|
||||
g_curMMapInfos--;
|
||||
|
||||
if( g_curMMapInfos == 0 ) {
|
||||
free( g_mmapInfos );
|
||||
g_mmapInfos = NULL;
|
||||
g_maxMMapInfos = 0;
|
||||
}
|
||||
LeaveCriticalSection( &cs );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -25,7 +25,7 @@ try {
|
||||
throw Error(10, path, "rb", strError());
|
||||
}
|
||||
// Map it to memory
|
||||
const byte* pData = file.mmap();
|
||||
const Exiv2::byte* pData = file.mmap();
|
||||
long size = file.size();
|
||||
DataBuf buf(size);
|
||||
// Read from the memory mapped region
|
||||
|
||||
512
src/basicio.cpp
512
src/basicio.cpp
@ -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,148 +79,89 @@ 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
|
||||
FileIo::~FileIo()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
int FileIo::munmap()
|
||||
{
|
||||
int rc = 0;
|
||||
if (pMappedArea_ != 0) {
|
||||
#if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP
|
||||
if (::munmap(pMappedArea_, mappedLength_) != 0) {
|
||||
rc = 1;
|
||||
}
|
||||
#else
|
||||
if (isWriteable_) {
|
||||
write(pMappedArea_, mappedLength_);
|
||||
}
|
||||
if (isMalloced_) {
|
||||
delete[] pMappedArea_;
|
||||
isMalloced_ = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (isWriteable_) {
|
||||
if (fp_ != 0) switchMode(opRead);
|
||||
isWriteable_ = false;
|
||||
}
|
||||
pMappedArea_ = 0;
|
||||
mappedLength_ = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
byte* FileIo::mmap(bool isWriteable)
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
if (munmap() != 0) {
|
||||
throw Error(2, path_, strError(), "munmap");
|
||||
}
|
||||
mappedLength_ = size();
|
||||
isWriteable_ = isWriteable;
|
||||
#if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP
|
||||
int prot = PROT_READ;
|
||||
if (isWriteable_) {
|
||||
prot |= PROT_WRITE;
|
||||
if (switchMode(opWrite) != 0) return 0;
|
||||
}
|
||||
void* rc = ::mmap(0, mappedLength_, prot, MAP_SHARED, fileno(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_;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
BasicIo::AutoPtr FileIo::temporary() const
|
||||
{
|
||||
BasicIo::AutoPtr basicIo;
|
||||
|
||||
StructStat buf;
|
||||
int ret = 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));
|
||||
fileIo = std::auto_ptr<FileIo>(new FileIo(tmpname));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
std::string tmpname = path_ + toString(pid);
|
||||
fileIo = std::auto_ptr<FileIo>(new FileIo(tmpname));
|
||||
}
|
||||
if (fileIo->open("w+b") != 0) {
|
||||
throw Error(10, path_, "w+b", strError());
|
||||
}
|
||||
basicIo = fileIo;
|
||||
}
|
||||
else {
|
||||
basicIo.reset(new MemIo);
|
||||
}
|
||||
|
||||
return basicIo;
|
||||
}
|
||||
|
||||
int FileIo::switchMode(OpMode opMode)
|
||||
int FileIo::Impl::switchMode(OpMode opMode)
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
if (opMode_ == opMode) return 0;
|
||||
@ -260,28 +207,200 @@ namespace Exiv2 {
|
||||
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 (p_->pMappedArea_ != 0) {
|
||||
#if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP
|
||||
if (::munmap(p_->pMappedArea_, 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 (p_->isWriteable_) {
|
||||
write(p_->pMappedArea_, p_->mappedLength_);
|
||||
}
|
||||
if (p_->isMalloced_) {
|
||||
delete[] p_->pMappedArea_;
|
||||
p_->isMalloced_ = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (p_->isWriteable_) {
|
||||
if (p_->fp_ != 0) p_->switchMode(Impl::opRead);
|
||||
p_->isWriteable_ = false;
|
||||
}
|
||||
p_->pMappedArea_ = 0;
|
||||
p_->mappedLength_ = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
byte* FileIo::mmap(bool isWriteable)
|
||||
{
|
||||
assert(p_->fp_ != 0);
|
||||
if (munmap() != 0) {
|
||||
throw Error(2, p_->path_, strError(), "munmap");
|
||||
}
|
||||
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 (p_->isWriteable_) {
|
||||
prot |= PROT_WRITE;
|
||||
}
|
||||
void* rc = ::mmap(0, p_->mappedLength_, prot, MAP_SHARED, fileno(p_->fp_), 0);
|
||||
if (MAP_FAILED == rc) {
|
||||
throw Error(2, p_->path_, strError(), "mmap");
|
||||
}
|
||||
p_->pMappedArea_ = static_cast<byte*>(rc);
|
||||
|
||||
#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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
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;
|
||||
|
||||
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 (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_->path_ + toString(pid);
|
||||
fileIo = std::auto_ptr<FileIo>(new FileIo(tmpname));
|
||||
}
|
||||
if (fileIo->open("w+b") != 0) {
|
||||
throw Error(10, p_->path_, "w+b", strError());
|
||||
}
|
||||
basicIo = fileIo;
|
||||
}
|
||||
else {
|
||||
basicIo.reset(new MemIo);
|
||||
}
|
||||
|
||||
return basicIo;
|
||||
}
|
||||
|
||||
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->path_.c_str());
|
||||
::remove(fileIo->p_->path_.c_str());
|
||||
}
|
||||
throw Error(10, path_, "w+b", strError());
|
||||
throw Error(10, p_->path_, "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*>(path_.c_str());
|
||||
pf = const_cast<char*>(p_->path_.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 path_ is a symlink, get the path of the linked-to file
|
||||
// In case p_->path_ 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(path_.c_str(), pf, lbuf.size_ - 1) == -1) {
|
||||
throw Error(2, path_, strError(), "readlink");
|
||||
if (::readlink(p_->path_.c_str(), pf, lbuf.size_ - 1) == -1) {
|
||||
throw Error(2, p_->path_, 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->path_.c_str(), pf) == -1) {
|
||||
throw Error(17, fileIo->path_, pf, strError());
|
||||
if (::rename(fileIo->p_->path_.c_str(), pf) == -1) {
|
||||
throw Error(17, fileIo->p_->path_, pf, strError());
|
||||
}
|
||||
::remove(fileIo->path_.c_str());
|
||||
::remove(fileIo->p_->path_.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, path_, "w+b", strError());
|
||||
throw Error(10, p_->path_, "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, path_, lastMode, strError());
|
||||
throw Error(10, p_->path_, lastMode, strError());
|
||||
}
|
||||
}
|
||||
else close();
|
||||
|
||||
if (error() || src.error()) throw Error(18, path_, strError());
|
||||
if (error() || src.error()) throw Error(18, p_->path_, 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 path_;
|
||||
return p_->path_;
|
||||
}
|
||||
|
||||
#ifdef EXV_UNICODE_PATH
|
||||
std::wstring FileIo::wpath() const
|
||||
{
|
||||
if (wpMode_ == wpStandard) {
|
||||
return s2ws(path_);
|
||||
if (p_->wpMode_ == Impl::wpStandard) {
|
||||
return s2ws(p_->path_);
|
||||
}
|
||||
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;
|
||||
|
||||
@ -35,15 +35,6 @@
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdio>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
// MSVC doesn't provide mode_t
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned short mode_t;
|
||||
#endif
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
@ -505,44 +496,9 @@ namespace Exiv2 {
|
||||
//! Assignment operator
|
||||
FileIo& operator=(const FileIo& rhs);
|
||||
|
||||
// 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_;
|
||||
|
||||
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
|
||||
*/
|
||||
EXV_DLLLOCAL int switchMode(OpMode opMode);
|
||||
//! stat wrapper for internal use
|
||||
EXV_DLLLOCAL int stat(StructStat& buf) const;
|
||||
// Pimpl idiom
|
||||
class Impl;
|
||||
Impl* p_;
|
||||
|
||||
}; // class FileIo
|
||||
|
||||
|
||||
@ -635,7 +635,7 @@ namespace Exiv2 {
|
||||
assert(def != 0);
|
||||
|
||||
uint16_t tag = static_cast<uint16_t>(idx / cfg()->tagStep());
|
||||
int32_t sz = std::min(def->size(tag, cfg()->group_), TiffEntryBase::doSize() - idx);
|
||||
int32_t sz = EXV_MIN(def->size(tag, cfg()->group_), TiffEntryBase::doSize() - idx);
|
||||
TiffComponent::AutoPtr tc = TiffCreator::create(tag, cfg()->group_);
|
||||
TiffBinaryElement* tp = dynamic_cast<TiffBinaryElement*>(tc.get());
|
||||
// The assertion typically fails if a component is not configured in
|
||||
@ -1674,13 +1674,13 @@ namespace Exiv2 {
|
||||
|
||||
uint32_t idx = 0;
|
||||
for (Components::const_iterator i = elements_.begin(); i != elements_.end(); ++i) {
|
||||
idx = std::max(idx, (*i)->tag() * cfg()->tagStep());
|
||||
idx = EXV_MAX(idx, (*i)->tag() * cfg()->tagStep());
|
||||
idx += (*i)->size();
|
||||
}
|
||||
if (cfg()->hasFillers_ && def()) {
|
||||
const ArrayDef* lastDef = def() + defSize() - 1;
|
||||
uint16_t lastTag = static_cast<uint16_t>(lastDef->idx_ / cfg()->tagStep());
|
||||
idx = std::max(idx, lastDef->idx_ + lastDef->size(lastTag, cfg()->group_));
|
||||
idx = EXV_MAX(idx, lastDef->idx_ + lastDef->size(lastTag, cfg()->group_));
|
||||
}
|
||||
return idx;
|
||||
|
||||
|
||||
@ -73,6 +73,10 @@ typedef __int32 int32_t;
|
||||
*/
|
||||
#define EXV_CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
|
||||
|
||||
// Simple min and max macros
|
||||
#define EXV_MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define EXV_MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
// *****************************************************************************
|
||||
// forward declarations
|
||||
struct tm;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user