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