summaryrefslogtreecommitdiff
path: root/source/XMPFiles_IO.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/XMPFiles_IO.cpp')
-rw-r--r--source/XMPFiles_IO.cpp132
1 files changed, 110 insertions, 22 deletions
diff --git a/source/XMPFiles_IO.cpp b/source/XMPFiles_IO.cpp
index e2eccd6..6de8666 100644
--- a/source/XMPFiles_IO.cpp
+++ b/source/XMPFiles_IO.cpp
@@ -16,12 +16,46 @@
#include "source/XMPFiles_IO.hpp"
#include "source/XIO.hpp"
+
+#define EMPTY_FILE_PATH ""
+#define XMP_FILESIO_STATIC_START try { int a;
+#define XMP_FILESIO_STATIC_END1(errorCallbackPtr, filePath, severity) \
+ a = 1; \
+ } catch ( XMP_Error & error ) { \
+ if ( (errorCallbackPtr) != NULL ) (errorCallbackPtr)->NotifyClient ( (severity), error, (filePath) ); \
+ else throw; \
+ }
+#define XMP_FILESIO_START try { int b;
+#define XMP_FILESIO_END1(severity) \
+ b = 1; \
+ } catch ( XMP_Error & error ) { \
+ if ( errorCallback != NULL ) errorCallback->NotifyClient ( (severity), error, filePath.c_str() ); \
+ else throw; \
+ }
+#define XMP_FILESIO_END2(filePath, severity) \
+ b = 1; \
+ } catch ( XMP_Error & error ) { \
+ if ( errorCallback != NULL ) errorCallback->NotifyClient ( (severity), error, (filePath) ); \
+ else throw; \
+ }
+#define XMP_FILESIO_STATIC_NOTIFY_ERROR(errorCallbackPtr, filePath, severity, error) \
+ if ( (errorCallbackPtr) != NULL ) errorCallbackPtr->NotifyClient ( (severity), (error), (filePath) );
+#define XMP_FILESIO_NOTIFY_ERROR(filePath, severity, error) \
+ XMP_FILESIO_STATIC_NOTIFY_ERROR(errorCallback, (filePath), (severity), (error))
+
+
// =================================================================================================
// XMPFiles_IO::New_XMPFiles_IO
// ============================
-XMPFiles_IO* XMPFiles_IO::New_XMPFiles_IO ( const char* filePath, bool readOnly )
+/* class static */
+XMPFiles_IO * XMPFiles_IO::New_XMPFiles_IO (
+ const char * filePath,
+ bool readOnly,
+ GenericErrorCallback * _errorCallback,
+ XMP_ProgressTracker * _progressTracker )
{
+ XMP_FILESIO_STATIC_START
Host_IO::FileRef hostFile = Host_IO::noFileRef;
switch ( Host_IO::GetFileMode ( filePath ) ) {
@@ -31,14 +65,20 @@ XMPFiles_IO* XMPFiles_IO::New_XMPFiles_IO ( const char* filePath, bool readOnly
case Host_IO::kFMode_DoesNotExist:
break;
default:
- XMP_Throw ( "New_XMPFiles_IO, path must be a file or not exist", kXMPErr_BadParam );
+ XMP_Throw ( "New_XMPFiles_IO, path must be a file or not exist", kXMPErr_FilePathNotAFile );
+ }
+ if ( hostFile == Host_IO::noFileRef ) {
+ XMP_Error error (kXMPErr_NoFile, "New_XMPFiles_IO, file does not exist");
+ XMP_FILESIO_STATIC_NOTIFY_ERROR ( _errorCallback, filePath, kXMPErrSev_Recoverable, error );
+ return 0;
}
- if ( hostFile == Host_IO::noFileRef ) return 0;
Host_IO::Rewind ( hostFile ); // Make sure offset really is 0.
- XMPFiles_IO* newFile = new XMPFiles_IO ( hostFile, filePath, readOnly );
+ XMPFiles_IO * newFile = new XMPFiles_IO ( hostFile, filePath, readOnly, _errorCallback, _progressTracker );
return newFile;
+ XMP_FILESIO_STATIC_END1 ( _errorCallback, filePath, kXMPErrSev_FileFatal )
+ return NULL;
} // XMPFiles_IO::New_XMPFiles_IO
@@ -46,13 +86,26 @@ XMPFiles_IO* XMPFiles_IO::New_XMPFiles_IO ( const char* filePath, bool readOnly
// XMPFiles_IO::XMPFiles_IO
// ========================
-XMPFiles_IO::XMPFiles_IO ( Host_IO::FileRef hostFile, const char* _filePath, bool _readOnly )
- : readOnly(_readOnly), filePath(_filePath), fileRef(hostFile), currOffset(0), isTemp(false), derivedTemp(0)
+XMPFiles_IO::XMPFiles_IO (
+ Host_IO::FileRef hostFile,
+ const char * _filePath,
+ bool _readOnly,
+ GenericErrorCallback * _errorCallback,
+ XMP_ProgressTracker * _progressTracker )
+ : readOnly(_readOnly)
+ , filePath(_filePath)
+ , fileRef(hostFile)
+ , currOffset(0)
+ , isTemp(false)
+ , derivedTemp(0)
+ , errorCallback(_errorCallback)
+ , progressTracker(_progressTracker)
{
+ XMP_FILESIO_START
XMP_Assert ( this->fileRef != Host_IO::noFileRef );
this->currLength = Host_IO::Length ( this->fileRef );
-
+ XMP_FILESIO_END2 ( _filePath, kXMPErrSev_FileFatal )
} // XMPFiles_IO::XMPFiles_IO
// =================================================================================================
@@ -61,25 +114,26 @@ XMPFiles_IO::XMPFiles_IO ( Host_IO::FileRef hostFile, const char* _filePath, boo
XMPFiles_IO::~XMPFiles_IO()
{
-
try {
+ XMP_FILESIO_START
if ( this->derivedTemp != 0 ) this->DeleteTemp();
if ( this->fileRef != Host_IO::noFileRef ) Host_IO::Close ( this->fileRef );
if ( this->isTemp && (! this->filePath.empty()) ) Host_IO::Delete ( this->filePath.c_str() );
+ XMP_FILESIO_END1 ( kXMPErrSev_Recoverable )
} catch ( ... ) {
// All of the above is fail-safe cleanup, ignore problems.
}
-
} // XMPFiles_IO::~XMPFiles_IO
// =================================================================================================
// XMPFiles_IO::operator=
// ======================
-void XMPFiles_IO::operator= ( const XMP_IO& in )
+void XMPFiles_IO::operator = ( const XMP_IO& in )
{
-
+ XMP_FILESIO_START
XMP_Throw ( "No assignment for XMPFiles_IO", kXMPErr_InternalFailure );
+ XMP_FILESIO_END1 ( kXMPErrSev_OperationFatal )
}; // XMPFiles_IO::operator=
@@ -87,8 +141,9 @@ void XMPFiles_IO::operator= ( const XMP_IO& in )
// XMPFiles_IO::Read
// =================
-XMP_Uns32 XMPFiles_IO::Read ( void* buffer, XMP_Uns32 count, bool readAll /* = false */ )
+XMP_Uns32 XMPFiles_IO::Read ( void * buffer, XMP_Uns32 count, bool readAll /* = false */ )
{
+ XMP_FILESIO_START
XMP_Assert ( this->fileRef != Host_IO::noFileRef );
XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
@@ -104,6 +159,8 @@ XMP_Uns32 XMPFiles_IO::Read ( void* buffer, XMP_Uns32 count, bool readAll /* = f
this->currOffset += amountRead;
return amountRead;
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+ return 0;
} // XMPFiles_IO::Read
@@ -111,24 +168,35 @@ XMP_Uns32 XMPFiles_IO::Read ( void* buffer, XMP_Uns32 count, bool readAll /* = f
// XMPFiles_IO::Write
// ==================
-void XMPFiles_IO::Write ( const void* buffer, XMP_Uns32 count )
+void XMPFiles_IO::Write ( const void * buffer, XMP_Uns32 count )
{
+ XMP_FILESIO_START
XMP_Assert ( this->fileRef != Host_IO::noFileRef );
XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
XMP_Assert ( this->currOffset <= this->currLength );
try {
+ if ( this->readOnly )
+ XMP_Throw ( "New_XMPFiles_IO, write not permitted on read only file", kXMPErr_FilePermission );
Host_IO::Write ( this->fileRef, buffer, count );
+ if ( this->progressTracker != 0 ) this->progressTracker->AddWorkDone ( (float) count );
} catch ( ... ) {
- // Make sure the internal state reflects partial writes.
- this->currOffset = Host_IO::Offset ( this->fileRef );
- this->currLength = Host_IO::Length ( this->fileRef );
+ try {
+ // we should try to maintain the state as best as possible
+ // but no exception should escape from this backup plan.
+ // Make sure the internal state reflects partial writes.
+ this->currOffset = Host_IO::Offset ( this->fileRef );
+ this->currLength = Host_IO::Length ( this->fileRef );
+ } catch ( ... ) {
+ // don't do anything
+ }
throw;
}
this->currOffset += count;
if ( this->currOffset > this->currLength ) this->currLength = this->currOffset;
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
} // XMPFiles_IO::Write
@@ -138,6 +206,7 @@ void XMPFiles_IO::Write ( const void* buffer, XMP_Uns32 count )
XMP_Int64 XMPFiles_IO::Seek ( XMP_Int64 offset, SeekMode mode )
{
+ XMP_FILESIO_START
XMP_Assert ( this->fileRef != Host_IO::noFileRef );
XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
@@ -162,6 +231,8 @@ XMP_Int64 XMPFiles_IO::Seek ( XMP_Int64 offset, SeekMode mode )
XMP_Assert ( this->currOffset == newOffset );
return this->currOffset;
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal );
+ return -1;
} // XMPFiles_IO::Seek
@@ -171,10 +242,11 @@ XMP_Int64 XMPFiles_IO::Seek ( XMP_Int64 offset, SeekMode mode )
XMP_Int64 XMPFiles_IO::Length()
{
+ XMP_FILESIO_START
XMP_Assert ( this->fileRef != Host_IO::noFileRef );
XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
-
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
return this->currLength;
} // XMPFiles_IO::Length
@@ -185,10 +257,14 @@ XMP_Int64 XMPFiles_IO::Length()
void XMPFiles_IO::Truncate ( XMP_Int64 length )
{
+ XMP_FILESIO_START
XMP_Assert ( this->fileRef != Host_IO::noFileRef );
XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
+ if ( this->readOnly )
+ XMP_Throw ( "New_XMPFiles_IO, truncate not permitted on read only file", kXMPErr_FilePermission );
+
XMP_Enforce ( length <= this->currLength );
Host_IO::SetEOF ( this->fileRef, length );
@@ -198,6 +274,7 @@ void XMPFiles_IO::Truncate ( XMP_Int64 length )
// ! Seek to the expected offset, some versions of Host_IO::SetEOF implicitly seek to EOF.
Host_IO::Seek ( this->fileRef, this->currOffset, kXMP_SeekFromStart );
XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
} // XMPFiles_IO::Truncate
@@ -207,6 +284,7 @@ void XMPFiles_IO::Truncate ( XMP_Int64 length )
XMP_IO* XMPFiles_IO::DeriveTemp()
{
+ XMP_FILESIO_START
XMP_Assert ( this->fileRef != Host_IO::noFileRef );
if ( this->derivedTemp != 0 ) return this->derivedTemp;
@@ -214,8 +292,12 @@ XMP_IO* XMPFiles_IO::DeriveTemp()
if ( this->readOnly ) {
XMP_Throw ( "XMPFiles_IO::DeriveTemp, can't derive from read-only", kXMPErr_InternalFailure );
}
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+
+ std::string tempPath;
- std::string tempPath = Host_IO::CreateTemp ( this->filePath.c_str() );
+ XMP_FILESIO_START
+ tempPath = Host_IO::CreateTemp ( this->filePath.c_str() );
XMPFiles_IO* newTemp = XMPFiles_IO::New_XMPFiles_IO ( tempPath.c_str(), Host_IO::openReadWrite );
if ( newTemp == 0 ) {
@@ -225,7 +307,8 @@ XMP_IO* XMPFiles_IO::DeriveTemp()
newTemp->isTemp = true;
this->derivedTemp = newTemp;
-
+ newTemp->progressTracker = this->progressTracker; // Automatically track writes to the temp file.
+ XMP_FILESIO_END2 ( tempPath.c_str(), kXMPErrSev_FileFatal )
return this->derivedTemp;
} // XMPFiles_IO::DeriveTemp
@@ -236,9 +319,10 @@ XMP_IO* XMPFiles_IO::DeriveTemp()
void XMPFiles_IO::AbsorbTemp()
{
+ XMP_FILESIO_START
XMP_Assert ( this->fileRef != Host_IO::noFileRef );
- XMPFiles_IO* temp = this->derivedTemp;
+ XMPFiles_IO * temp = this->derivedTemp;
if ( temp == 0 ) {
XMP_Throw ( "XMPFiles_IO::AbsorbTemp, no temp to absorb", kXMPErr_InternalFailure );
}
@@ -253,6 +337,7 @@ void XMPFiles_IO::AbsorbTemp()
this->fileRef = Host_IO::Open ( this->filePath.c_str(), Host_IO::openReadWrite );
this->currLength = Host_IO::Length ( this->fileRef );
this->currOffset = 0;
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
} // XMPFiles_IO::AbsorbTemp
@@ -262,7 +347,8 @@ void XMPFiles_IO::AbsorbTemp()
void XMPFiles_IO::DeleteTemp()
{
- XMPFiles_IO* temp = this->derivedTemp;
+ XMP_FILESIO_START
+ XMPFiles_IO * temp = this->derivedTemp;
if ( temp != 0 ) {
@@ -280,6 +366,7 @@ void XMPFiles_IO::DeleteTemp()
this->derivedTemp = 0;
}
+ XMP_FILESIO_END2 ( this->derivedTemp->filePath.c_str(), kXMPErrSev_FileFatal )
} // XMPFiles_IO::DeleteTemp
@@ -289,11 +376,12 @@ void XMPFiles_IO::DeleteTemp()
void XMPFiles_IO::Close()
{
-
+ XMP_FILESIO_START
if ( this->fileRef != Host_IO::noFileRef ) {
Host_IO::Close ( this->fileRef );
this->fileRef = Host_IO::noFileRef;
}
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
} // XMPFiles_IO::Close