Home | History | Annotate | Download | only in src
      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