1/*---------------------------------------------------------------------------*
2 *  PFile.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 "LCHAR.h"
21#include "pendian.h"
22#include "PFile.h"
23#include "PFileSystem.h"
24#include "plog.h"
25#include "pstdio.h"
26
27
28ESR_ReturnCode PFileDestroy(PFile* self)
29{
30  if (self == NULL)
31  {
32    PLogError(L("ESR_INVALID_ARGUMENT"));
33    return ESR_INVALID_ARGUMENT;
34  }
35  return self->destroy(self);
36}
37
38ESR_ReturnCode PFileOpen(PFile* self, const LCHAR* mode)
39{
40  if (self == NULL)
41  {
42    PLogError(L("ESR_INVALID_ARGUMENT"));
43    return ESR_INVALID_ARGUMENT;
44  }
45  return self->open(self, mode);
46}
47
48ESR_ReturnCode PFileClose(PFile* self)
49{
50  if (self == NULL)
51  {
52    PLogError(L("ESR_INVALID_ARGUMENT"));
53    return ESR_INVALID_ARGUMENT;
54  }
55  return self->close(self);
56}
57
58ESR_ReturnCode PFileRead(PFile* self, void* buffer, size_t size, size_t* count)
59{
60  if (self == NULL)
61  {
62    PLogError(L("ESR_INVALID_ARGUMENT"));
63    return ESR_INVALID_ARGUMENT;
64  }
65  return self->read(self, buffer, size, count);
66}
67
68ESR_ReturnCode PFileWrite(PFile* self, void* buffer, size_t size, size_t* count)
69{
70  if (self == NULL)
71  {
72    PLogError(L("ESR_INVALID_ARGUMENT"));
73    return ESR_INVALID_ARGUMENT;
74  }
75  return self->write(self, buffer, size, count);
76}
77
78ESR_ReturnCode PFileFlush(PFile* self)
79{
80  if (self == NULL)
81  {
82    PLogError(L("ESR_INVALID_ARGUMENT"));
83    return ESR_INVALID_ARGUMENT;
84  }
85  return self->flush(self);
86}
87
88ESR_ReturnCode PFileSeek(PFile* self, long offset, int origin)
89{
90  if (self == NULL)
91  {
92    PLogError(L("ESR_INVALID_ARGUMENT"));
93    return ESR_INVALID_ARGUMENT;
94  }
95  return self->seek(self, offset, origin);
96}
97
98
99ESR_ReturnCode PFileGetPosition(PFile* self, size_t* position)
100{
101  if (self == NULL)
102  {
103    PLogError(L("ESR_INVALID_ARGUMENT"));
104    return ESR_INVALID_ARGUMENT;
105  }
106  return self->getPosition(self, position);
107}
108
109ESR_ReturnCode PFileIsOpen(PFile* self, ESR_BOOL* isOpen)
110{
111  if (self == NULL)
112  {
113    PLogError(L("ESR_INVALID_ARGUMENT"));
114    return ESR_INVALID_ARGUMENT;
115  }
116  return self->isOpen(self, isOpen);
117}
118
119ESR_ReturnCode PFileIsEOF(PFile* self, ESR_BOOL* isEof)
120{
121  if (self == NULL)
122  {
123    PLogError(L("ESR_INVALID_ARGUMENT"));
124    return ESR_INVALID_ARGUMENT;
125  }
126  return self->isEOF(self, isEof);
127}
128
129ESR_ReturnCode PFileGetFilename(PFile* self, LCHAR* filename, size_t* len)
130{
131  ESR_ReturnCode rc;
132
133  if (self == NULL)
134  {
135    PLogError(L("ESR_INVALID_ARGUMENT"));
136    return ESR_INVALID_ARGUMENT;
137  }
138  rc = self->getFilename(self, filename, len);
139  return rc;
140}
141
142ESR_ReturnCode PFileIsErrorSet(PFile* self, ESR_BOOL* isError)
143{
144  if (self == NULL)
145  {
146    PLogError(L("ESR_INVALID_ARGUMENT"));
147    return ESR_INVALID_ARGUMENT;
148  }
149  return self->isErrorSet(self, isError);
150}
151
152ESR_ReturnCode PFileClearError(PFile* self)
153{
154  if (self == NULL)
155  {
156    PLogError(L("ESR_INVALID_ARGUMENT"));
157    return ESR_INVALID_ARGUMENT;
158  }
159  return self->clearError(self);
160}
161
162ESR_ReturnCode PFileVfprintf(PFile* self, int* result, const LCHAR* format, va_list args)
163{
164  ESR_ReturnCode rc;
165
166  if (self == NULL)
167  {
168    PLogError(L("ESR_INVALID_ARGUMENT"));
169    return ESR_INVALID_ARGUMENT;
170  }
171  rc = self->vfprintf(self, result, format, args);
172  return rc;
173}
174
175ESR_ReturnCode PFileFgetc(PFile* self, LINT* result)
176{
177  if (self == NULL)
178  {
179    PLogError(L("ESR_INVALID_ARGUMENT"));
180    return ESR_INVALID_ARGUMENT;
181  }
182  return self->fgetc(self, result);
183}
184
185ESR_ReturnCode PFileFgets(PFile* self, LCHAR* string, int n, LCHAR** result)
186{
187  if (self == NULL)
188  {
189    PLogError(L("ESR_INVALID_ARGUMENT"));
190    return ESR_INVALID_ARGUMENT;
191  }
192  return self->fgets(self, string, n, result);
193}
194
195ESR_ReturnCode PFileReadInt(PFile* self, int* value)
196{
197  LCHAR number[MAX_INT_DIGITS+1];
198  size_t i, bufferSize, count, totalRead = 0;
199  ESR_ReturnCode rc;
200
201  /* Skip whitespace before token */
202  do
203  {
204    count = pfread(number, sizeof(LCHAR), MAX_INT_DIGITS, self);
205    totalRead += count;
206    if (count < MAX_INT_DIGITS)
207    {
208      if (pferror(self))
209      {
210        rc = ESR_READ_ERROR;
211        PLogError(ESR_rc2str(rc));
212        goto CLEANUP;
213      }
214      else
215      {
216        rc = ESR_INVALID_STATE;
217        PLogError(L("%s: reached end of file before finding token"), ESR_rc2str(rc));
218        goto CLEANUP;
219      }
220    }
221    /* locate first non-whitespace character */
222    for (i = 0; i < count && LISSPACE(number[i]); ++i);
223  }
224  while (i == count);
225  bufferSize = count - i;
226
227  /* Fill remainder of buffer */
228  if (bufferSize < MAX_INT_DIGITS)
229  {
230    count = pfread(number + bufferSize, sizeof(LCHAR), MAX_INT_DIGITS - bufferSize, self);
231    bufferSize += count;
232    totalRead += count;
233    if (count < MAX_INT_DIGITS - bufferSize && pferror(self))
234    {
235      rc = ESR_READ_ERROR;
236      PLogError(ESR_rc2str(rc));
237      goto CLEANUP;
238    }
239  }
240
241  /* locate first whitespace character */
242  for (i = 0; i < bufferSize && !LISSPACE(number[i]); ++i);
243  if (i < bufferSize)
244  {
245    /* unread anything after the token */
246    if (PFileSeek(self, - (int)(bufferSize - i), SEEK_CUR))
247    {
248      rc = ESR_SEEK_ERROR;
249      PLogError(ESR_rc2str(rc));
250    }
251    totalRead -= bufferSize - i;
252    number[i] = L('\0');
253  }
254
255  if (number[0] != L('-') && !LISDIGIT(number[0]))
256  {
257    rc = ESR_INVALID_STATE;
258    PLogError(L("%s: token was not number (%s)"), ESR_rc2str(rc), number);
259    goto CLEANUP;
260  }
261
262  CHKLOG(rc, lstrtoi(number, value, 10));
263  return rc;
264CLEANUP:
265  if (PFileSeek(self,  - (int) count, SEEK_CUR))
266    PLogError(L("ESR_SEEK_ERROR"));
267  return rc;
268}
269
270ESR_ReturnCode PFileReadLCHAR(PFile* self, LCHAR* value, size_t len)
271{
272  size_t i, bufferSize, count, totalRead = 0;
273  ESR_ReturnCode rc = ESR_SUCCESS;
274
275  /* Skip whitespace before token */
276  do
277  {
278    count = pfread(value, sizeof(LCHAR), len, self);
279    totalRead += count;
280    if (count < len)
281    {
282      if (pferror(self))
283      {
284        rc = ESR_READ_ERROR;
285        PLogError(ESR_rc2str(rc));
286        goto CLEANUP;
287      }
288      else
289      {
290        rc = ESR_INVALID_STATE;
291        PLogError(L("%s: reached end of file before finding token"), ESR_rc2str(rc));
292        goto CLEANUP;
293      }
294    }
295    /* locate first non-whitespace character */
296    for (i = 0; i < count && LISSPACE(value[i]); ++i);
297  }
298  while (i == count);
299  bufferSize = count - i;
300
301  /* Fill remainder of buffer */
302  if (bufferSize < len)
303  {
304    count = pfread(value + bufferSize, sizeof(LCHAR), len - bufferSize, self);
305    bufferSize += count;
306    totalRead += count;
307    if (count < len - bufferSize && pferror(self))
308    {
309      rc = ESR_READ_ERROR;
310      PLogError(ESR_rc2str(rc));
311      goto CLEANUP;
312    }
313  }
314
315  /* locate first whitespace character */
316  for (i = 0; i < bufferSize && !LISSPACE(value[i]); ++i);
317  if (i < bufferSize)
318  {
319    /* unread anything after the token */
320    if (PFileSeek(self, -(int)(bufferSize - i), SEEK_CUR))
321    {
322      rc = ESR_SEEK_ERROR;
323      PLogError(ESR_rc2str(rc));
324    }
325    totalRead -= bufferSize - i;
326    value[i] = L('\0');
327  }
328  return rc;
329CLEANUP:
330  if (PFileSeek(self, - (int) count, SEEK_CUR))
331    PLogError(L("ESR_SEEK_ERROR"));
332  return rc;
333}
334
335PFile* pfopen(const LCHAR* filename, const LCHAR* mode)
336{
337  PFile* result;
338  ESR_ReturnCode rc;
339  ESR_BOOL isLittleEndian;
340
341#if __BYTE_ORDER==__LITTLE_ENDIAN
342  isLittleEndian = ESR_TRUE;
343#else
344  isLittleEndian = ESR_FALSE;
345#endif
346
347  rc = PFileSystemCreatePFile(filename, isLittleEndian, &result);
348  if (rc != ESR_SUCCESS)
349    return NULL;
350  rc = result->open(result, mode);
351  if (rc != ESR_SUCCESS)
352  {
353    result->destroy(result);
354    return NULL;
355  }
356  return result;
357}
358
359size_t pfread(void* buffer, size_t size, size_t count, PFile* stream)
360{
361  ESR_ReturnCode rc;
362
363  rc = PFileRead(stream, buffer, size, &count);
364  if (rc != ESR_SUCCESS)
365    return 0;
366  return count;
367}
368
369size_t pfwrite(const void* buffer, size_t size, size_t count, PFile* stream)
370{
371  ESR_ReturnCode rc;
372
373  rc = PFileWrite(stream, buffer, size, &count);
374  if (rc != ESR_SUCCESS)
375    return 0;
376  return count;
377}
378
379int pfclose(PFile* stream)
380{
381  ESR_ReturnCode rc;
382
383  rc = PFileDestroy(stream);
384  if (rc != ESR_SUCCESS)
385    return PEOF;
386  return 0;
387}
388
389void prewind(PFile* stream)
390{
391  PFileSeek(stream, 0, SEEK_SET);
392}
393
394int pfseek(PFile* stream, long offset, int origin)
395{
396  ESR_ReturnCode rc;
397
398  rc = PFileSeek(stream, offset, origin);
399  if (rc != ESR_SUCCESS)
400    return 1;
401  return 0;
402}
403
404long pftell(PFile* stream)
405{
406  size_t result;
407  ESR_ReturnCode rc;
408
409  rc = PFileGetPosition(stream, &result);
410  if (rc != ESR_SUCCESS)
411    return -1;
412  return result;
413}
414
415int pfeof(PFile* stream)
416{
417  ESR_BOOL eof;
418
419  PFileIsEOF(stream, &eof);
420  if (!eof)
421    return 0;
422  return 1;
423}
424
425int pferror(PFile* stream)
426{
427  ESR_BOOL error;
428
429  PFileIsErrorSet(stream, &error);
430  if (!error)
431    return 0;
432  return 1;
433}
434
435void pclearerr(PFile* stream)
436{
437  PFileClearError(stream);
438}
439
440int pfflush(PFile* stream)
441{
442  ESR_ReturnCode rc;
443
444  rc = PFileFlush(stream);
445  if (rc != ESR_SUCCESS)
446    return PEOF;
447  return 0;
448}
449
450LCHAR* pfgets(LCHAR* string, int n, PFile* self)
451{
452  LCHAR* result;
453  ESR_ReturnCode rc;
454
455  rc = PFileFgets(self, string, n, &result);
456  if (rc != ESR_SUCCESS)
457    return NULL;
458  return result;
459}
460
461LINT pfgetc(PFile* self)
462{
463  LINT result;
464  ESR_ReturnCode rc;
465
466  rc = PFileFgetc(self, &result);
467  if (rc != ESR_SUCCESS)
468    return PEOF;
469  return result;
470}
471
472int pfprintf(PFile* stream, const LCHAR* format, ...)
473{
474#ifdef FINAL_RELEASE
475  return 0;
476#else
477  va_list args;
478  int result;
479  ESR_ReturnCode rc;
480
481  va_start(args, format);
482  rc = PFileVfprintf(stream, &result, format, args);
483  va_end(args);
484  if (rc != ESR_SUCCESS)
485    return -1;
486  return result;
487#endif
488}
489
490int pvfprintf(PFile* stream, const LCHAR* format, va_list argptr)
491{
492#ifdef FINAL_RELEASE
493  return 0;
494#else
495  int result;
496  ESR_ReturnCode rc;
497
498  rc = PFileVfprintf(stream, &result, format, argptr);
499  if (rc != ESR_SUCCESS)
500    return -1;
501  return result;
502#endif
503}
504
505int pprintf(const LCHAR* format, ...)
506{
507#ifdef FINAL_RELEASE
508  return 0;
509#else
510  va_list args;
511  int result;
512  ESR_ReturnCode rc;
513
514  va_start(args, format);
515  rc = PFileVfprintf(PSTDOUT, &result, format, args);
516  va_end(args);
517  if (rc != ESR_SUCCESS)
518    return -1;
519  return result;
520#endif
521}
522