/*---------------------------------------------------------------------------*
* PANSIFileImpl.c *
* *
* Copyright 2007, 2008 Nuance Communciations, Inc. *
* *
* Licensed under the Apache License, Version 2.0 (the 'License'); *
* you may not use this file except in compliance with the License. *
* *
* You may obtain a copy of the License at *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an 'AS IS' BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
*---------------------------------------------------------------------------*/
#include "errno.h"
#include "passert.h"
#include "pendian.h"
#include "PFileImpl.h"
#include "PANSIFileImpl.h"
#include "PFileSystem.h"
#include "ESR_ReturnCode.h"
#include "plog.h"
#include "pmemory.h"
#include "pstdio.h"
#include "ptypes.h"
#define MTAG NULL
ESR_ReturnCode PANSIFileCreateImpl(const LCHAR* filename, ESR_BOOL isLittleEndian, PFile** self)
{
PANSIFileImpl* impl = NULL;
ESR_ReturnCode rc;
impl = NEW(PANSIFileImpl, MTAG);
if (impl == NULL)
{
rc = ESR_OUT_OF_MEMORY;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
PFileCreateImpl(&impl->Interface.Interface, filename, isLittleEndian);
impl->Interface.Interface.close = &PANSIFileCloseImpl;
impl->Interface.Interface.clearError = &PANSIFileClearErrorImpl;
impl->Interface.Interface.destroy = &PANSIFileDestroyImpl;
impl->Interface.Interface.fgetc = &PANSIFileFgetcImpl;
impl->Interface.Interface.fgets = &PANSIFileFgetsImpl;
impl->Interface.Interface.getPosition = &PANSIFileGetPositionImpl;
impl->Interface.Interface.hideMemoryAllocation = &PANSIFileHideMemoryAllocation;
impl->Interface.Interface.isEOF = &PANSIFileIsEOFImpl;
impl->Interface.Interface.isErrorSet = &PANSIFileIsErrorSetImpl;
impl->Interface.Interface.isOpen = &PANSIFileIsOpenImpl;
impl->Interface.Interface.open = &PANSIFileOpenImpl;
impl->Interface.Interface.read = &PANSIFileReadImpl;
impl->Interface.Interface.seek = &PANSIFileSeekImpl;
impl->Interface.Interface.flush = &PANSIFileFlushImpl;
impl->Interface.Interface.write = &PANSIFileWriteImpl;
impl->Interface.filename[0] = 0;
impl->value = NULL;
LSTRCAT(impl->Interface.filename, filename);
*self = &impl->Interface.Interface;
return ESR_SUCCESS;
CLEANUP:
if (impl != NULL)
impl->Interface.Interface.destroy(&impl->Interface.Interface);
return rc;
}
ESR_ReturnCode PANSIFileDestroyImpl(PFile* self)
{
ESR_ReturnCode rc;
CHK(rc, PFileDestroyImpl(self));
FREE(self);
return ESR_SUCCESS;
CLEANUP:
return rc;
}
#ifdef USE_THREAD
#define LOCK_MUTEX(rc, impl) \
if (impl->Interface.lock != NULL) \
CHKLOG(rc, PtrdMonitorLock(impl->Interface.lock));
#else
#define LOCK_MUTEX(rc, impl)
#endif
#ifdef USE_THREAD
#define CLEANUP_AND_RETURN(rc, impl) \
if (impl->Interface.lock!=NULL) \
CHKLOG(rc, PtrdMonitorUnlock(impl->Interface.lock)); \
return ESR_SUCCESS; \
CLEANUP: \
if (impl->Interface.lock!=NULL) \
PtrdMonitorUnlock(impl->Interface.lock); \
return rc;
#else
#define CLEANUP_AND_RETURN(rc, impl) \
return ESR_SUCCESS; \
CLEANUP: \
return rc;
#endif
ESR_ReturnCode PANSIFileOpenImpl(PFile* self, const LCHAR* mode)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
if (impl->value != NULL)
{
rc = ESR_ALREADY_OPEN;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
impl->value = fopen(impl->Interface.filename, mode);
if (impl->value == NULL)
{
LCHAR path[P_PATH_MAX];
size_t len;
len = P_PATH_MAX;
CHKLOG(rc, PFileSystemGetcwd(path, &len));
rc = ESR_OPEN_ERROR;
/* PLOG_DBG_TRACE((L("%s: filename=%s, cwd=%s"), ESR_rc2str(rc), impl->Interface.filename, path)); */
PLogError(L("%s: filename=%s, cwd=%s"), ESR_rc2str(rc), impl->Interface.filename, path);
goto CLEANUP;
}
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileCloseImpl(PFile* self)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
if (fclose(impl->value) != 0)
{
rc = ESR_CLOSE_ERROR;
PLogMessage(L("%s: file %s, handle"), ESR_rc2str(rc), impl->Interface.filename, impl->value);
goto CLEANUP;
}
impl->value = NULL;
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileReadImpl(PFile* self, void* buffer, size_t size, size_t* count)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
if (count == NULL)
{
rc = ESR_INVALID_ARGUMENT;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
if (size != 0 && *count != 0)
{
ESR_BOOL needToSwap;
*count = fread(buffer, size, *count, impl->value);
if (*count == 0 && ferror(impl->value))
{
rc = ESR_READ_ERROR;
PLogMessage(ESR_rc2str(rc));
goto CLEANUP;
}
#ifdef __LITTLE_ENDIAN
needToSwap = !impl->Interface.littleEndian;
#else
needToSwap = impl->Interface.littleEndian;
#endif
if (needToSwap)
swap_byte_order(buffer, *count, size);
}
else
*count = 0;
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileWriteImpl(PFile* self, void* buffer, size_t size, size_t* count)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
size_t requested = *count;
LOCK_MUTEX(rc, impl);
if (count == NULL)
{
rc = ESR_INVALID_ARGUMENT;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
if (size != 0 && *count != 0)
{
ESR_BOOL needToSwap;
void* temp;
#ifdef __LITTLE_ENDIAN
needToSwap = !impl->Interface.littleEndian;
#else
needToSwap = impl->Interface.littleEndian;
#endif
if (needToSwap)
{
temp = MALLOC(*count * size, MTAG);
if (temp == NULL)
{
rc = ESR_OUT_OF_MEMORY;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
memcpy(temp, buffer, *count * size);
swap_byte_order(temp, *count, size);
}
else
temp = buffer;
*count = fwrite(temp, size, *count, impl->value);
if (needToSwap)
{
FREE(temp);
temp = NULL;
}
if (*count < requested)
{
rc = ESR_WRITE_ERROR;
PLogMessage(ESR_rc2str(rc));
goto CLEANUP;
}
}
else
*count = 0;
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileFlushImpl(PFile* self)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
if (fflush(impl->value) != 0)
{
rc = ESR_FLUSH_ERROR;
PLogMessage(ESR_rc2str(rc));
goto CLEANUP;
}
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileSeekImpl(PFile* self, long offset, int origin)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
if (fseek(impl->value, offset, origin) != 0)
{
rc = ESR_SEEK_ERROR;
PLogMessage(ESR_rc2str(rc));
goto CLEANUP;
}
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileGetPositionImpl(PFile* self, size_t* position)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
long pos;
LOCK_MUTEX(rc, impl);
pos = ftell(impl->value);
if (pos == -1)
{
switch (errno)
{
case EBADF:
rc = ESR_INVALID_STATE;
PLogError(L("%s: Got EBADF"), rc);
goto CLEANUP;
case EINVAL:
rc = ESR_INVALID_STATE;
PLogError(L("%s: Got EINVAL"), rc);
goto CLEANUP;
default:
rc = ESR_INVALID_STATE;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
}
*position = pos;
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileIsOpenImpl(PFile* self, ESR_BOOL* isOpen)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
if (isOpen == NULL)
{
rc = ESR_INVALID_ARGUMENT;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
*isOpen = impl->value != NULL;
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileIsEOFImpl(PFile* self, ESR_BOOL* isEof)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
if (isEof == NULL)
{
rc = ESR_INVALID_ARGUMENT;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
#ifdef NO_FEOF
{
long posCur; /* remember current file position */
long posEnd; /* end of file position */
posCur = ftell(impl->value);
fseek(impl->value, 0, SEEK_END);
posEnd = ftell(impl->value);
*isEof = (posCur == posEnd);
fseek(impl->value, posCur, SEEK_SET); /* restore position in file */
}
#else
*isEof = feof(impl->value) != 0;
#endif
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileIsErrorSetImpl(PFile* self, ESR_BOOL* isError)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
if (isError == NULL)
{
rc = ESR_INVALID_ARGUMENT;
PLogError(ESR_rc2str(rc));
goto CLEANUP;
}
*isError = ferror(impl->value) != 0;
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileClearErrorImpl(PFile* self)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
clearerr(impl->value);
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileFgetsImpl(PFile* self, LCHAR* string, int n, LCHAR** result)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LCHAR* temp;
LOCK_MUTEX(rc, impl);
temp = fgets(string, n, impl->value);
if (result != NULL)
*result = temp;
if (temp == NULL && ferror(impl->value))
{
rc = ESR_INVALID_STATE;
PLogMessage(ESR_rc2str(rc));
goto CLEANUP;
}
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileFgetcImpl(PFile* self, LINT* result)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
*result = fgetc(impl->value);
if (*result == PEOF && ferror(impl->value))
{
rc = ESR_INVALID_STATE;
PLogMessage(ESR_rc2str(rc));
goto CLEANUP;
}
CLEANUP_AND_RETURN(rc, impl);
}
ESR_ReturnCode PANSIFileHideMemoryAllocation(PFile* self)
{
PANSIFileImpl* impl = (PANSIFileImpl*) self;
ESR_ReturnCode rc;
LOCK_MUTEX(rc, impl);
rc = PMemLogFree(self);
if (rc != ESR_SUCCESS)
{
pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
goto CLEANUP;
}
rc = PMemLogFree(impl->Interface.filename);
if (rc != ESR_SUCCESS)
{
pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
goto CLEANUP;
}
#ifdef USE_THREAD
rc = PMemLogFree(impl->Interface.lock);
if (rc != ESR_SUCCESS)
{
pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
goto CLEANUP;
}
#endif
CLEANUP_AND_RETURN(rc, impl);
}