• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PANSIFileCreateImpl(const LCHAR * filename,ESR_BOOL isLittleEndian,PFile ** self)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 
PANSIFileDestroyImpl(PFile * self)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 
PANSIFileOpenImpl(PFile * self,const LCHAR * mode)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 
PANSIFileCloseImpl(PFile * self)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 
PANSIFileReadImpl(PFile * self,void * buffer,size_t size,size_t * count)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 
PANSIFileWriteImpl(PFile * self,void * buffer,size_t size,size_t * count)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 
PANSIFileFlushImpl(PFile * self)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 
PANSIFileSeekImpl(PFile * self,long offset,int origin)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 
PANSIFileGetPositionImpl(PFile * self,size_t * position)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 
PANSIFileIsOpenImpl(PFile * self,ESR_BOOL * isOpen)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 
PANSIFileIsEOFImpl(PFile * self,ESR_BOOL * isEof)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 
PANSIFileIsErrorSetImpl(PFile * self,ESR_BOOL * isError)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 
PANSIFileClearErrorImpl(PFile * self)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 
PANSIFileFgetsImpl(PFile * self,LCHAR * string,int n,LCHAR ** result)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 
PANSIFileFgetcImpl(PFile * self,LINT * result)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 
PANSIFileHideMemoryAllocation(PFile * self)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