| /*---------------------------------------------------------------------------* |
| * 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); |
| } |