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