1 /*---------------------------------------------------------------------------* 2 * PFileImpl.c * 3 * * 4 * Copyright 2007, 2008 Nuance Communciations, Inc. * 5 * * 6 * Licensed under the Apache License, Version 2.0 (the 'License'); * 7 * you may not use this file except in compliance with the License. * 8 * * 9 * You may obtain a copy of the License at * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, software * 13 * distributed under the License is distributed on an 'AS IS' BASIS, * 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 * See the License for the specific language governing permissions and * 16 * limitations under the License. * 17 * * 18 *---------------------------------------------------------------------------*/ 19 20 #include "passert.h" 21 #include "pendian.h" 22 #include "PFileImpl.h" 23 #include "PFileSystem.h" 24 #include "plog.h" 25 #include "pmemory.h" 26 #include "pstdio.h" 27 #include "ptypes.h" 28 29 #define MTAG NULL 30 31 32 /** 33 * Initializes variables declared in the superinterface. 34 */ 35 ESR_ReturnCode PFileCreateImpl(PFile* self, const LCHAR* filename, ESR_BOOL isLittleEndian) 36 { 37 PFileImpl* impl = (PFileImpl*) self; 38 ESR_ReturnCode rc; 39 #ifdef USE_THREAD 40 ESR_BOOL threadingEnabled; 41 #endif 42 43 #ifdef USE_THREAD 44 impl->lock = NULL; 45 #endif 46 impl->littleEndian = isLittleEndian; 47 48 impl->Interface.destroy = &PFileDestroyImpl; 49 impl->Interface.getFilename = &PFileGetFilenameImpl; 50 impl->Interface.vfprintf = &PFileVfprintfImpl; 51 impl->filename = MALLOC(sizeof(LCHAR) * (LSTRLEN(filename) + 1), MTAG); 52 53 if (impl->filename == NULL) 54 { 55 rc = ESR_OUT_OF_MEMORY; 56 PLogError(ESR_rc2str(rc)); 57 goto CLEANUP; 58 } 59 LSTRCPY(impl->filename, filename); 60 61 #ifdef USE_THREAD 62 rc = PtrdIsEnabled(&threadingEnabled); 63 if (rc != ESR_SUCCESS) 64 { 65 pfprintf(PSTDERR, L("[%s:%d] PtrdIsEnabled failed with %s\n"), __FILE__, __LINE__, ESR_rc2str(rc)); 66 goto CLEANUP; 67 } 68 if (threadingEnabled) 69 { 70 rc = PtrdMonitorCreate(&impl->lock); 71 if (rc != ESR_SUCCESS) 72 goto CLEANUP; 73 } 74 #endif 75 return ESR_SUCCESS; 76 CLEANUP: 77 self->destroy(self); 78 return rc; 79 } 80 81 82 #ifdef USE_THREAD 83 #define LOCK_MUTEX(rc, impl) \ 84 if (impl->lock != NULL) \ 85 CHKLOG(rc, PtrdMonitorLock(impl->lock)); 86 #else 87 #define LOCK_MUTEX(rc, impl) 88 #endif 89 90 91 #ifdef USE_THREAD 92 #define CLEANUP_AND_RETURN(rc, impl) \ 93 if (impl->lock!=NULL) \ 94 CHKLOG(rc, PtrdMonitorUnlock(impl->lock)); \ 95 return ESR_SUCCESS; \ 96 CLEANUP: \ 97 if (impl->lock!=NULL) \ 98 PtrdMonitorUnlock(impl->lock); \ 99 return rc; 100 #else 101 #define CLEANUP_AND_RETURN(rc, impl) \ 102 return ESR_SUCCESS; \ 103 CLEANUP: \ 104 return rc; 105 #endif 106 107 108 ESR_ReturnCode PFileDestroyImpl(PFile* self) 109 { 110 PFileImpl* impl = (PFileImpl*) self; 111 ESR_ReturnCode rc; 112 ESR_BOOL isOpen; 113 114 LOCK_MUTEX(rc, impl); 115 CHKLOG(rc, self->isOpen(self, &isOpen)); 116 if (isOpen) 117 CHKLOG(rc, self->close(self)); 118 if (impl->filename) 119 { 120 FREE(impl->filename); 121 impl->filename = NULL; 122 } 123 #ifdef USE_THREAD 124 if (impl->lock != NULL) 125 { 126 PtrdMonitorUnlock(impl->lock); 127 rc = PtrdMonitorDestroy(impl->lock); 128 if (rc != ESR_SUCCESS) 129 goto CLEANUP; 130 } 131 #endif 132 return ESR_SUCCESS; 133 CLEANUP: 134 #ifdef USE_THREAD 135 if (impl->lock != NULL) 136 PtrdMonitorUnlock(impl->lock); 137 #endif 138 return rc; 139 } 140 141 ESR_ReturnCode PFileGetFilenameImpl(PFile* self, LCHAR* filename, size_t* len) 142 { 143 PFileImpl* impl = (PFileImpl*) self; 144 ESR_ReturnCode rc; 145 146 if (self == NULL || len == NULL) 147 { 148 PLogError(L("ESR_INVALID_ARGUMENT")); 149 return ESR_INVALID_ARGUMENT; 150 } 151 LOCK_MUTEX(rc, impl); 152 if (LSTRLEN(impl->filename) + 1 > *len) 153 { 154 *len = LSTRLEN(impl->filename) + 1; 155 rc = ESR_BUFFER_OVERFLOW; 156 goto CLEANUP; 157 } 158 LSTRCPY(filename, impl->filename); 159 CLEANUP_AND_RETURN(rc, impl); 160 } 161 162 ESR_ReturnCode PFileVfprintfImpl(PFile* self, int* result, const LCHAR* format, va_list args) 163 { 164 ESR_ReturnCode rc; 165 ESR_BOOL isOpen; 166 #define BUFFER_SIZE 5120 167 static LCHAR buffer[BUFFER_SIZE]; 168 size_t len; 169 170 if (self == NULL) 171 { 172 PLogError(L("ESR_INVALID_ARGUMENT")); 173 return ESR_INVALID_ARGUMENT; 174 } 175 176 CHKLOG(rc, self->isOpen(self, &isOpen)); 177 if (!isOpen) 178 { 179 rc = ESR_OPEN_ERROR; 180 PLogError(L("%s: cannot operate on closed file"), ESR_rc2str(rc)); 181 goto CLEANUP; 182 } 183 184 /* 185 * fprintf() is computationally expensive, so we compute its output without grabbing a lock 186 * and only lock while actually writing the results into the file. 187 */ 188 if (result != NULL) 189 *result = vsprintf(buffer, format, args); 190 else 191 vsprintf(buffer, format, args); 192 len = LSTRLEN(buffer); 193 passert(len < BUFFER_SIZE); 194 195 CHKLOG(rc, self->write(self, buffer, sizeof(LCHAR), &len)); 196 return ESR_SUCCESS; 197 CLEANUP: 198 return rc; 199 } 200