• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
PFileCreateImpl(PFile * self,const LCHAR * filename,ESR_BOOL isLittleEndian)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 
PFileDestroyImpl(PFile * self)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 
PFileGetFilenameImpl(PFile * self,LCHAR * filename,size_t * len)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 
PFileVfprintfImpl(PFile * self,int * result,const LCHAR * format,va_list args)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