1 /*---------------------------------------------------------------------------* 2 * PANSIFileImpl.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 "errno.h" 21 #include "passert.h" 22 #include "pendian.h" 23 #include "PFileImpl.h" 24 #include "PANSIFileImpl.h" 25 #include "PFileSystem.h" 26 #include "ESR_ReturnCode.h" 27 #include "plog.h" 28 #include "pmemory.h" 29 #include "pstdio.h" 30 #include "ptypes.h" 31 32 #define MTAG NULL 33 34 ESR_ReturnCode PANSIFileCreateImpl(const LCHAR* filename, ESR_BOOL isLittleEndian, PFile** self) 35 { 36 PANSIFileImpl* impl = NULL; 37 ESR_ReturnCode rc; 38 39 impl = NEW(PANSIFileImpl, MTAG); 40 if (impl == NULL) 41 { 42 rc = ESR_OUT_OF_MEMORY; 43 PLogError(ESR_rc2str(rc)); 44 goto CLEANUP; 45 } 46 47 PFileCreateImpl(&impl->Interface.Interface, filename, isLittleEndian); 48 impl->Interface.Interface.close = &PANSIFileCloseImpl; 49 impl->Interface.Interface.clearError = &PANSIFileClearErrorImpl; 50 impl->Interface.Interface.destroy = &PANSIFileDestroyImpl; 51 impl->Interface.Interface.fgetc = &PANSIFileFgetcImpl; 52 impl->Interface.Interface.fgets = &PANSIFileFgetsImpl; 53 impl->Interface.Interface.getPosition = &PANSIFileGetPositionImpl; 54 impl->Interface.Interface.hideMemoryAllocation = &PANSIFileHideMemoryAllocation; 55 impl->Interface.Interface.isEOF = &PANSIFileIsEOFImpl; 56 impl->Interface.Interface.isErrorSet = &PANSIFileIsErrorSetImpl; 57 impl->Interface.Interface.isOpen = &PANSIFileIsOpenImpl; 58 impl->Interface.Interface.open = &PANSIFileOpenImpl; 59 impl->Interface.Interface.read = &PANSIFileReadImpl; 60 impl->Interface.Interface.seek = &PANSIFileSeekImpl; 61 impl->Interface.Interface.flush = &PANSIFileFlushImpl; 62 impl->Interface.Interface.write = &PANSIFileWriteImpl; 63 64 impl->Interface.filename[0] = 0; 65 impl->value = NULL; 66 67 LSTRCAT(impl->Interface.filename, filename); 68 *self = &impl->Interface.Interface; 69 return ESR_SUCCESS; 70 CLEANUP: 71 if (impl != NULL) 72 impl->Interface.Interface.destroy(&impl->Interface.Interface); 73 return rc; 74 } 75 76 ESR_ReturnCode PANSIFileDestroyImpl(PFile* self) 77 { 78 ESR_ReturnCode rc; 79 80 CHK(rc, PFileDestroyImpl(self)); 81 FREE(self); 82 return ESR_SUCCESS; 83 CLEANUP: 84 return rc; 85 } 86 87 88 #ifdef USE_THREAD 89 #define LOCK_MUTEX(rc, impl) \ 90 if (impl->Interface.lock != NULL) \ 91 CHKLOG(rc, PtrdMonitorLock(impl->Interface.lock)); 92 #else 93 #define LOCK_MUTEX(rc, impl) 94 #endif 95 96 97 #ifdef USE_THREAD 98 #define CLEANUP_AND_RETURN(rc, impl) \ 99 if (impl->Interface.lock!=NULL) \ 100 CHKLOG(rc, PtrdMonitorUnlock(impl->Interface.lock)); \ 101 return ESR_SUCCESS; \ 102 CLEANUP: \ 103 if (impl->Interface.lock!=NULL) \ 104 PtrdMonitorUnlock(impl->Interface.lock); \ 105 return rc; 106 #else 107 #define CLEANUP_AND_RETURN(rc, impl) \ 108 return ESR_SUCCESS; \ 109 CLEANUP: \ 110 return rc; 111 #endif 112 113 114 ESR_ReturnCode PANSIFileOpenImpl(PFile* self, const LCHAR* mode) 115 { 116 PANSIFileImpl* impl = (PANSIFileImpl*) self; 117 ESR_ReturnCode rc; 118 119 LOCK_MUTEX(rc, impl); 120 if (impl->value != NULL) 121 { 122 rc = ESR_ALREADY_OPEN; 123 PLogError(ESR_rc2str(rc)); 124 goto CLEANUP; 125 } 126 impl->value = fopen(impl->Interface.filename, mode); 127 128 if (impl->value == NULL) 129 { 130 LCHAR path[P_PATH_MAX]; 131 size_t len; 132 133 len = P_PATH_MAX; 134 CHKLOG(rc, PFileSystemGetcwd(path, &len)); 135 rc = ESR_OPEN_ERROR; 136 /* PLOG_DBG_TRACE((L("%s: filename=%s, cwd=%s"), ESR_rc2str(rc), impl->Interface.filename, path)); */ 137 PLogError(L("%s: filename=%s, cwd=%s"), ESR_rc2str(rc), impl->Interface.filename, path); 138 goto CLEANUP; 139 } 140 CLEANUP_AND_RETURN(rc, impl); 141 } 142 143 ESR_ReturnCode PANSIFileCloseImpl(PFile* self) 144 { 145 PANSIFileImpl* impl = (PANSIFileImpl*) self; 146 ESR_ReturnCode rc; 147 148 LOCK_MUTEX(rc, impl); 149 if (fclose(impl->value) != 0) 150 { 151 rc = ESR_CLOSE_ERROR; 152 PLogMessage(L("%s: file %s, handle"), ESR_rc2str(rc), impl->Interface.filename, impl->value); 153 goto CLEANUP; 154 } 155 impl->value = NULL; 156 CLEANUP_AND_RETURN(rc, impl); 157 } 158 159 ESR_ReturnCode PANSIFileReadImpl(PFile* self, void* buffer, size_t size, size_t* count) 160 { 161 PANSIFileImpl* impl = (PANSIFileImpl*) self; 162 ESR_ReturnCode rc; 163 164 LOCK_MUTEX(rc, impl); 165 if (count == NULL) 166 { 167 rc = ESR_INVALID_ARGUMENT; 168 PLogError(ESR_rc2str(rc)); 169 goto CLEANUP; 170 } 171 172 if (size != 0 && *count != 0) 173 { 174 ESR_BOOL needToSwap; 175 176 *count = fread(buffer, size, *count, impl->value); 177 if (*count == 0 && ferror(impl->value)) 178 { 179 rc = ESR_READ_ERROR; 180 PLogMessage(ESR_rc2str(rc)); 181 goto CLEANUP; 182 } 183 184 #ifdef __LITTLE_ENDIAN 185 needToSwap = !impl->Interface.littleEndian; 186 #else 187 needToSwap = impl->Interface.littleEndian; 188 #endif 189 190 if (needToSwap) 191 swap_byte_order(buffer, *count, size); 192 } 193 else 194 *count = 0; 195 CLEANUP_AND_RETURN(rc, impl); 196 } 197 198 ESR_ReturnCode PANSIFileWriteImpl(PFile* self, void* buffer, size_t size, size_t* count) 199 { 200 PANSIFileImpl* impl = (PANSIFileImpl*) self; 201 ESR_ReturnCode rc; 202 size_t requested = *count; 203 204 LOCK_MUTEX(rc, impl); 205 if (count == NULL) 206 { 207 rc = ESR_INVALID_ARGUMENT; 208 PLogError(ESR_rc2str(rc)); 209 goto CLEANUP; 210 } 211 if (size != 0 && *count != 0) 212 { 213 ESR_BOOL needToSwap; 214 void* temp; 215 216 #ifdef __LITTLE_ENDIAN 217 needToSwap = !impl->Interface.littleEndian; 218 #else 219 needToSwap = impl->Interface.littleEndian; 220 #endif 221 if (needToSwap) 222 { 223 temp = MALLOC(*count * size, MTAG); 224 if (temp == NULL) 225 { 226 rc = ESR_OUT_OF_MEMORY; 227 PLogError(ESR_rc2str(rc)); 228 goto CLEANUP; 229 } 230 memcpy(temp, buffer, *count * size); 231 232 swap_byte_order(temp, *count, size); 233 } 234 else 235 temp = buffer; 236 237 *count = fwrite(temp, size, *count, impl->value); 238 if (needToSwap) 239 { 240 FREE(temp); 241 temp = NULL; 242 } 243 244 if (*count < requested) 245 { 246 rc = ESR_WRITE_ERROR; 247 PLogMessage(ESR_rc2str(rc)); 248 goto CLEANUP; 249 } 250 } 251 else 252 *count = 0; 253 CLEANUP_AND_RETURN(rc, impl); 254 } 255 256 ESR_ReturnCode PANSIFileFlushImpl(PFile* self) 257 { 258 PANSIFileImpl* impl = (PANSIFileImpl*) self; 259 ESR_ReturnCode rc; 260 261 LOCK_MUTEX(rc, impl); 262 if (fflush(impl->value) != 0) 263 { 264 rc = ESR_FLUSH_ERROR; 265 PLogMessage(ESR_rc2str(rc)); 266 goto CLEANUP; 267 } 268 CLEANUP_AND_RETURN(rc, impl); 269 } 270 271 ESR_ReturnCode PANSIFileSeekImpl(PFile* self, long offset, int origin) 272 { 273 PANSIFileImpl* impl = (PANSIFileImpl*) self; 274 ESR_ReturnCode rc; 275 276 LOCK_MUTEX(rc, impl); 277 if (fseek(impl->value, offset, origin) != 0) 278 { 279 rc = ESR_SEEK_ERROR; 280 PLogMessage(ESR_rc2str(rc)); 281 goto CLEANUP; 282 } 283 CLEANUP_AND_RETURN(rc, impl); 284 } 285 286 ESR_ReturnCode PANSIFileGetPositionImpl(PFile* self, size_t* position) 287 { 288 PANSIFileImpl* impl = (PANSIFileImpl*) self; 289 ESR_ReturnCode rc; 290 long pos; 291 292 LOCK_MUTEX(rc, impl); 293 pos = ftell(impl->value); 294 if (pos == -1) 295 { 296 switch (errno) 297 { 298 case EBADF: 299 rc = ESR_INVALID_STATE; 300 PLogError(L("%s: Got EBADF"), rc); 301 goto CLEANUP; 302 case EINVAL: 303 rc = ESR_INVALID_STATE; 304 PLogError(L("%s: Got EINVAL"), rc); 305 goto CLEANUP; 306 default: 307 rc = ESR_INVALID_STATE; 308 PLogError(ESR_rc2str(rc)); 309 goto CLEANUP; 310 } 311 } 312 *position = pos; 313 CLEANUP_AND_RETURN(rc, impl); 314 } 315 316 ESR_ReturnCode PANSIFileIsOpenImpl(PFile* self, ESR_BOOL* isOpen) 317 { 318 PANSIFileImpl* impl = (PANSIFileImpl*) self; 319 ESR_ReturnCode rc; 320 321 LOCK_MUTEX(rc, impl); 322 if (isOpen == NULL) 323 { 324 rc = ESR_INVALID_ARGUMENT; 325 PLogError(ESR_rc2str(rc)); 326 goto CLEANUP; 327 } 328 *isOpen = impl->value != NULL; 329 CLEANUP_AND_RETURN(rc, impl); 330 } 331 332 ESR_ReturnCode PANSIFileIsEOFImpl(PFile* self, ESR_BOOL* isEof) 333 { 334 PANSIFileImpl* impl = (PANSIFileImpl*) self; 335 ESR_ReturnCode rc; 336 337 LOCK_MUTEX(rc, impl); 338 if (isEof == NULL) 339 { 340 rc = ESR_INVALID_ARGUMENT; 341 PLogError(ESR_rc2str(rc)); 342 goto CLEANUP; 343 } 344 #ifdef NO_FEOF 345 { 346 long posCur; /* remember current file position */ 347 long posEnd; /* end of file position */ 348 349 posCur = ftell(impl->value); 350 fseek(impl->value, 0, SEEK_END); 351 posEnd = ftell(impl->value); 352 *isEof = (posCur == posEnd); 353 fseek(impl->value, posCur, SEEK_SET); /* restore position in file */ 354 } 355 #else 356 *isEof = feof(impl->value) != 0; 357 #endif 358 CLEANUP_AND_RETURN(rc, impl); 359 } 360 361 ESR_ReturnCode PANSIFileIsErrorSetImpl(PFile* self, ESR_BOOL* isError) 362 { 363 PANSIFileImpl* impl = (PANSIFileImpl*) self; 364 ESR_ReturnCode rc; 365 366 LOCK_MUTEX(rc, impl); 367 if (isError == NULL) 368 { 369 rc = ESR_INVALID_ARGUMENT; 370 PLogError(ESR_rc2str(rc)); 371 goto CLEANUP; 372 } 373 *isError = ferror(impl->value) != 0; 374 CLEANUP_AND_RETURN(rc, impl); 375 } 376 377 ESR_ReturnCode PANSIFileClearErrorImpl(PFile* self) 378 { 379 PANSIFileImpl* impl = (PANSIFileImpl*) self; 380 ESR_ReturnCode rc; 381 382 LOCK_MUTEX(rc, impl); 383 clearerr(impl->value); 384 CLEANUP_AND_RETURN(rc, impl); 385 } 386 387 ESR_ReturnCode PANSIFileFgetsImpl(PFile* self, LCHAR* string, int n, LCHAR** result) 388 { 389 PANSIFileImpl* impl = (PANSIFileImpl*) self; 390 ESR_ReturnCode rc; 391 LCHAR* temp; 392 393 LOCK_MUTEX(rc, impl); 394 temp = fgets(string, n, impl->value); 395 if (result != NULL) 396 *result = temp; 397 if (temp == NULL && ferror(impl->value)) 398 { 399 rc = ESR_INVALID_STATE; 400 PLogMessage(ESR_rc2str(rc)); 401 goto CLEANUP; 402 } 403 CLEANUP_AND_RETURN(rc, impl); 404 } 405 406 ESR_ReturnCode PANSIFileFgetcImpl(PFile* self, LINT* result) 407 { 408 PANSIFileImpl* impl = (PANSIFileImpl*) self; 409 ESR_ReturnCode rc; 410 411 LOCK_MUTEX(rc, impl); 412 *result = fgetc(impl->value); 413 if (*result == PEOF && ferror(impl->value)) 414 { 415 rc = ESR_INVALID_STATE; 416 PLogMessage(ESR_rc2str(rc)); 417 goto CLEANUP; 418 } 419 CLEANUP_AND_RETURN(rc, impl); 420 } 421 422 ESR_ReturnCode PANSIFileHideMemoryAllocation(PFile* self) 423 { 424 PANSIFileImpl* impl = (PANSIFileImpl*) self; 425 ESR_ReturnCode rc; 426 427 LOCK_MUTEX(rc, impl); 428 rc = PMemLogFree(self); 429 if (rc != ESR_SUCCESS) 430 { 431 pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__); 432 goto CLEANUP; 433 } 434 rc = PMemLogFree(impl->Interface.filename); 435 if (rc != ESR_SUCCESS) 436 { 437 pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__); 438 goto CLEANUP; 439 } 440 #ifdef USE_THREAD 441 rc = PMemLogFree(impl->Interface.lock); 442 if (rc != ESR_SUCCESS) 443 { 444 pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__); 445 goto CLEANUP; 446 } 447 #endif 448 CLEANUP_AND_RETURN(rc, impl); 449 } 450