1/*---------------------------------------------------------------------------*
2 *  pstream.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 <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23
24#include <string.h>
25#include "passert.h"
26#include "pstdio.h"
27#include "pmemory.h"
28#include "plog.h"
29
30#ifdef __cplusplus
31extern "C"
32{
33#endif
34
35#ifdef PFILE_VIRTUAL_SUPPORT
36
37#define FILETEXTMODE    0x00
38#define FILEBINARYMODE   0x01
39#define FILEREADMODE    0x00
40#define FILEWRITEMODE    0x02
41
42  /* Open a existed writable file (i.e., the file is not closed yet).
43     At some cases user knows the filename only but does not know the file handle (1),
44     the user could call fopen to open this file again with another file handle (2).
45     He/She could get all the information before the last fflush was called via file handle (1).
46   */
47#define FILEREOPENMODE 0x08
48
49#define ISWRITEMODE(mode)  (((mode)&FILEWRITEMODE)  == FILEWRITEMODE)
50
51#define ISBINARYMODE(mode) (((mode)&FILEBINARYMODE) == FILEBINARYMODE)
52#define ISREOPENMODE(mode) (((mode)&FILEREOPENMODE) == FILEREOPENMODE)
53
54  /*
55    use a double link list to store the data of the writable file.
56    Each entry has 4k space (FILEBUFFERSIZE).
57  */
58#define FILEBUFFERSIZE 4096     /* 4k for each file buffer entry */
59
60  typedef struct FileBufferFrame
61  {
62    unsigned char          *buffer;       /* do not use pointer here and set it the first */
63    size_t                  size;
64    size_t                index;                        /* nth buffer, from 0, 1, ... */
65    struct FileBufferFrame  *prev;
66    struct FileBufferFrame  *next;
67    BOOL                    bMalloc;        /* flag, if the buffer malloced here ? */
68  }
69  FileBufferFrame;
70
71  FileRecord pWritableFileRecTable[] =
72    {
73      {"", 0, 0, 0, 3},
74      {"", 0, 0, 0, 3},
75      {"", 0, 0, 0, 3},
76      {"", 0, 0, 0, 3},
77      {"", 0, 0, 0, 3},
78      {"", 0, 0, 0, 3},
79      {"", 0, 0, 0, 3}
80    };
81  const nWritableFiles = sizeof(pWritableFileRecTable) / sizeof(pWritableFileRecTable[0]);
82
83#ifdef WIN32
84  extern const FileRecord pFileRecTable[];
85  extern const unsigned char pFileStart0[];
86#endif
87
88  const FileRecord *pReadOnlyFileRecTable = NULL;
89  const unsigned char *g_pFirstFile = NULL;
90
91  void SetFileTable(VirtualFileTable *table)
92  {
93#ifdef WIN32
94    pReadOnlyFileRecTable = pFileRecTable;
95    g_pFirstFile = pFileStart0;
96#else
97    if (table)
98    {
99      pReadOnlyFileRecTable = table->pFileTable;
100      g_pFirstFile = table->pFirstFile;
101    }
102#endif
103  }
104
105  /*
106    size: size of buffer.
107    buffer: is NULL, allocate here and set bMalloc as TRUE; otherwise use the external buffer
108  */
109  FileBufferFrame* CreateFileBufferFrame(size_t size, unsigned char *buffer)
110  {
111    FileBufferFrame *fb = NULL;
112
113    /* create FileBufferFrame */
114    fb = (FileBufferFrame *)MALLOC(sizeof(FileBufferFrame), "FileBufferFrame");
115    if (fb)
116    {
117      fb->next = NULL;
118      fb->prev = NULL;
119      fb->index = 0;
120      fb->size = size;
121      fb->bMalloc = FALSE;
122
123      if (buffer)
124        fb->buffer = buffer;
125      else
126      {
127        /* create one buffer frame */
128        if ((fb->buffer = (unsigned char *)MALLOC(size, "FileBufferFrame Buffer")) == NULL)
129        {
130          FREE(fb);
131          return NULL;
132        }
133        fb->bMalloc = TRUE;
134      }
135    }
136    return fb;
137  }
138
139  /* free FileBufferFrames
140     header should be the header of the FileBufferFrame link list
141   */
142  void DeleteFileBuffers(FileBufferFrame *header)
143  {
144    FileBufferFrame *next, *curr;
145
146    passert(header && header->prev == NULL);    /* delete from the beginning */
147
148    curr = header;
149    do
150    {
151      next = curr->next;
152      if (curr->bMalloc)
153        FREE(curr->buffer);
154      FREE(curr);
155      curr = next;
156    }
157    while (next != NULL);
158  }
159
160  void PortFileInit(void)
161  {
162    /* No gPortStdin, gPortStdout, and gPortStderr to initialize. */
163#ifdef WIN32
164    pReadOnlyFileRecTable = pFileRecTable;
165    g_pFirstFile = pFileStart0;
166#endif
167  }
168
169  /* Assume that all files have at least one byte in them, that is length is > 0. */
170  PORT_FILE PortFopen(const char *filename, const char *mode)
171  {
172    char *pfn;
173    const unsigned char *start;
174    int size;
175    int text_mode;
176    int access_mode;
177    int m = 0;
178    PORT_FILE PortFile;
179    FileBufferFrame *curFrame;
180    size_t end;
181
182    passert(filename);
183    passert(mode);
184
185    if (pReadOnlyFileRecTable == NULL)
186    {
187      passert("File Table is not initialized!" == NULL);
188      return NULL;
189    }
190
191    /* support read and write. */
192    if (mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'R') /* w means w+, attaching text */
193    {
194      char fname[80];
195      FileRecord *pCurRec;
196
197      access_mode  = (mode[0] == 'r') ? FILEREADMODE   : FILEWRITEMODE;
198
199      /* access mode: b/t */
200      if (mode[1] == '+')
201        text_mode = (mode[2] == 'b') ? FILEBINARYMODE : FILETEXTMODE;
202      else
203        text_mode = (mode[1] == 'b') ? FILEBINARYMODE : FILETEXTMODE;
204
205      /* Remove the directory path from the filename. */
206      if ((pfn = strrchr(filename, '/')) != NULL || (pfn = strrchr(filename, '\\')) != NULL)
207        strcpy(fname, pfn + 1);
208      else
209        strcpy(fname, filename);
210
211
212      /* Locate the start of the file, by looking through the file record table. */
213      if (access_mode == FILEREADMODE)
214      {
215        pCurRec = (FileRecord *)pReadOnlyFileRecTable;
216        start = g_pFirstFile;
217      }
218      else
219      {
220        pCurRec = (FileRecord *)pWritableFileRecTable;
221      }
222
223      while (pCurRec->size > 0 && strcmp(pCurRec->name, fname) != 0)
224      {
225        /* have to count the read-only file address in order to be best portable */
226        start += pCurRec->size;
227        pCurRec++;
228#ifndef NDEBUG
229        /* just for our internal test for read-only files.
230        if (pCurRec->start != NULL)
231        passert(start == pCurRec->start);
232        */
233#endif
234      }
235
236      m = access_mode | text_mode;
237      /* Do not support reopen the writable file now. */
238      if (access_mode == FILEREADMODE)
239      {
240        if (pCurRec->size == 0)
241        {
242          return NULL;
243        }
244
245        /* Found the file, record it's starting offset and length. */
246        end = pCurRec->end;
247        size = pCurRec->size;
248      }
249      /* writable file, open it the first time; could be text or binary */
250      else if (ISWRITEMODE(access_mode))
251      {
252        /* set the name and mode */
253        strcpy(pCurRec->name, fname);
254        pCurRec->mode = m;
255
256        start = pCurRec->start;
257        passert(start == NULL);
258        end = size = FILEBUFFERSIZE;
259      }
260      else
261      {
262        /* File doesn't exist. */
263        return NULL;
264      }
265      pfn = pCurRec->name;
266    }
267    else
268    {
269      /* Unknown mode */
270      return NULL;
271    }
272
273    /* Open file */
274    /* Create new file handle */
275    PortFile = (PORT_FILE)MALLOC(sizeof(PORT_FILE_HANDLE), "PortFile");
276    if (PortFile == NULL)
277    {
278      return NULL;
279    }
280
281    /* this mode is not tested yet */
282    if (ISREOPENMODE(m))
283    {
284      PortFile->startFrame = (FileBufferFrame *)start;
285    }
286    else
287    {
288      PortFile->startFrame = CreateFileBufferFrame(size, (unsigned char *)start);
289      if (ISWRITEMODE(m))
290      {
291        start = (const unsigned char *)PortFile->startFrame;
292      }
293    }
294
295    if (PortFile->startFrame == NULL)
296    {
297      FREE(PortFile);
298      return NULL;
299    }
300
301    PortFile->endFrame = PortFile->curFrame = PortFile->startFrame;
302
303    /* Mark that this file handle is for flash memory */
304    PortFile->filename = pfn;
305    PortFile->curPos = PortFile->curFrame->buffer;
306    PortFile->endPos = PortFile->curPos + end;
307
308    /* set the PortFile->endPos */
309    curFrame = PortFile->curFrame;
310    while (end > 0)
311    {
312      if (end > curFrame->size)
313      {
314        curFrame = curFrame->next;
315        passert(end > curFrame->size);
316        end -= curFrame->size;
317        passert(curFrame);
318      }
319      else
320      {
321        /* only reopen the writable file comes here */
322        PortFile->endPos = curFrame->buffer + end;
323        break;
324      }
325    }
326
327    PortFile->eof = 0; /* File must have at least one byte in it. */
328    PortFile->size =  size;
329    PortFile->mode =  m;
330
331    return PortFile;
332  }
333
334  int PortFclose(PORT_FILE PortFile)
335  {
336    passert(PortFile);
337
338    /* for reopen mode, do not delete the FileBufferFrame. Delete it by who created it */
339    if (ISWRITEMODE(PortFile->mode) && !ISREOPENMODE(PortFile->mode))  /* writable file */
340    {
341      int i = 0;
342      FileRecord *pCurRec = (FileRecord *)pWritableFileRecTable;
343
344      /* find the file record in memory */
345      for (i = 0; i < nWritableFiles; i++)
346      {
347        if (PortFile->size > 0 &&
348            PortFile->filename[0] != '\0' &&
349            strcmp(pCurRec->name, PortFile->filename) == 0
350           )
351        {
352          /* The parameter SREC.Recognizer.osi_log_level in par file control the output
353            # BIT 0 -> BASIC logging
354            # BIT 1 -> AUDIO waveform logging
355            # BIT 2 -> ADD WORD logging
356            # e.g. value is 3 = BASIC+AUDIO logging, no ADDWORD
357            SREC.Recognizer.osi_log_level = 7;
358
359            Do not control here
360          */
361          /*
362          SaveFileToDisk(PortFile);
363          */
364
365          pCurRec->name[0] = '\0';
366          pCurRec->start = NULL;
367          pCurRec->end = 0;
368          pCurRec->size = 0;
369
370          break;
371        }
372        pCurRec++;
373      }
374    }
375
376    DeleteFileBuffers(PortFile->startFrame);
377    FREE(PortFile);
378    return 0;
379  }
380
381  /*
382   * Returns the number of items read
383   */
384  size_t PortFread(void *buffer, size_t size, size_t count, PORT_FILE PortFile)
385  {
386    unsigned char *bufferPtr = (unsigned char *)buffer;
387    int cbRemain = size * count;
388    int cbAvail, minSize;
389    FileBufferFrame *curFrame = PortFile->curFrame;
390
391    passert(buffer);
392    passert(PortFile);
393
394    if (PortFile->eof == 1)
395    {
396      return 0;
397    }
398
399    while (cbRemain > 0)
400    {
401      if (PortFile->endPos == PortFile->curPos)  /* end of file */
402        break;
403
404      if (PortFile->curPos == curFrame->buffer + curFrame->size) /* end of this frame */
405      {
406        /* go to next frame */
407        curFrame = PortFile->curFrame = curFrame->next;
408        PortFile->curPos = curFrame->buffer;
409      }
410
411      if (curFrame == PortFile->endFrame)  /* last frame */
412        cbAvail = PortFile->endPos - PortFile->curPos;
413      else
414        cbAvail = curFrame->size - (PortFile->curPos - curFrame->buffer);
415
416      minSize = cbRemain < cbAvail ? cbRemain : cbAvail;
417      passert(minSize >= 0);
418
419      cbRemain -= minSize;
420      while (minSize-- > 0)
421        *bufferPtr++ = *PortFile->curPos++;
422    }
423
424    if (PortFile->curPos == PortFile->endPos)
425    {
426      PortFile->eof = 1;
427    }
428    /*
429    #ifdef __BIG_ENDIAN
430     if (!bNativeEnding)
431     {
432      swap_byte_order((char *)buffer, count, size);
433     }
434    #endif
435    */
436    return count - cbRemain / size;
437  }
438
439  /*
440   * Returns the number of items written
441   */
442  size_t PortFwrite(const void *data, size_t size, size_t count, PORT_FILE PortFile)
443  {
444    int cbWrite = size * count;
445    int cbAvail, minSize;
446    unsigned char *buffer = (unsigned char *)data;
447    FileBufferFrame *curFrame;
448
449    if (PortFile == NULL)
450      return 0;
451
452    curFrame = PortFile->curFrame;
453
454    /* write data until the end of the internal buffer */
455    if (PortFile->eof == 1)
456    {
457      /* TODO: should return 0, but it will cause infinite loop */
458      return 0;
459    }
460
461    /* why sub 1 ? */
462    while (cbWrite > 0)
463    {
464      if (PortFile->curPos == curFrame->buffer + curFrame->size) /* end of this frame */
465      {
466        if (curFrame->next == NULL)
467        {
468          /* assign a new space */
469          FileBufferFrame *nextFrame = CreateFileBufferFrame(FILEBUFFERSIZE, NULL);
470          if (nextFrame)
471          {
472            curFrame->next = nextFrame;
473            nextFrame->prev = curFrame;
474            nextFrame->index = curFrame->index + 1;
475
476            curFrame = PortFile->curFrame = nextFrame;
477            PortFile->endFrame = nextFrame;
478            PortFile->curPos = PortFile->endPos = nextFrame->buffer;
479
480            PortFile->size += FILEBUFFERSIZE;
481          }
482          else
483          {
484            return count -cbWrite / size;
485          }
486        }
487        else
488          curFrame = curFrame->next;
489      }
490
491      /* available space in current frame */
492      cbAvail = curFrame->size - (PortFile->curPos - curFrame->buffer);
493      minSize = cbWrite < cbAvail ? cbWrite : cbAvail;
494
495      memcpy((char *)PortFile->curPos, buffer, minSize);
496      buffer += minSize;
497      PortFile->curPos += minSize;
498      /* in case the write is not adding to the end */
499      if (curFrame == PortFile->endFrame && PortFile->endPos < PortFile->curPos)
500        PortFile->endPos = PortFile->curPos;
501      cbWrite -= minSize;
502    }
503
504    return count;
505  }
506
507  /*
508   * Returns 0 on success, non-zero on failure
509   */
510  int PortFseek(PORT_FILE PortFile, long offset, int origin)
511  {
512    int retval = 0;
513    int cbAvail, minSize;
514    FileBufferFrame *curFrame;
515
516    passert(PortFile);
517
518    /* Clear eof flag */
519    PortFile->eof = 0;
520
521    switch (origin)
522    {
523      case SEEK_CUR:
524        break;
525      case SEEK_END:
526        PortFile->curFrame = PortFile->endFrame;
527        PortFile->curPos = PortFile->endPos;
528        break;
529      case SEEK_SET:
530        PortFile->curFrame = PortFile->startFrame;
531        PortFile->curPos = PortFile->startFrame->buffer;
532        break;
533      default:
534        retval = 0; /* Error, unknown origin type */
535        break;
536    }
537
538    curFrame = PortFile->curFrame;
539
540    while (offset != 0)
541    {
542      if (offset > 0)
543      {
544        if (PortFile->endPos <= PortFile->curPos)  /* end of file */
545          break;
546
547        if (PortFile->curPos == curFrame->buffer + curFrame->size) /* end of this frame */
548        {
549          /* go to next frame */
550          curFrame = curFrame->next;
551          if (curFrame == NULL)
552            break;
553          PortFile->curFrame = curFrame->next;
554          PortFile->curPos = curFrame->buffer;
555        }
556        if (curFrame == PortFile->endFrame)  /* last frame */
557          cbAvail = PortFile->endPos - PortFile->curPos;
558        else
559          cbAvail = curFrame->size - (PortFile->curPos - curFrame->buffer);
560
561        minSize = offset < cbAvail ? offset : cbAvail;
562
563        PortFile->curPos += minSize;
564        offset -= minSize;
565      }
566      else
567      {
568        if (PortFile->startFrame->buffer == PortFile->curPos)  /* start of file */
569          break;
570
571        if (PortFile->curPos <= curFrame->buffer) /* start of this frame */
572        {
573          /* go to next frame */
574          curFrame = curFrame->next;
575          if (curFrame == NULL)
576            break;
577          PortFile->curFrame = curFrame;
578          PortFile->curPos = curFrame->buffer + curFrame->size;
579        }
580        cbAvail = PortFile->curPos - curFrame->buffer;
581
582        minSize = -offset < cbAvail ? -offset : cbAvail;
583
584        PortFile->curPos -= minSize;
585        offset += minSize;
586      }
587    }
588    return retval;
589  }
590
591  /*
592   * Returns current file position
593   */
594  long PortFtell(PORT_FILE PortFile)
595  {
596    int size;
597    FileBufferFrame *curFrame = PortFile->curFrame;
598
599    passert(PortFile);
600
601    /* current Frame size */
602    size = PortFile->curPos - curFrame->buffer;
603
604    /* previous frame size */
605    while (curFrame = curFrame->prev)
606      size += curFrame->size;
607
608    return size;
609  }
610
611  int PortVfprintf(PORT_FILE PortFile, const char *format, va_list argptr)
612  {
613    char message[2*2048] = "";
614
615    /* Print formatted message to buffer */
616    vsprintf(message, format, argptr);
617
618    if (PortFile == NULL)
619    {
620      /* TODO: HECK to screen */
621#ifndef NDEBUG
622      printf(message);
623#endif
624      return 0;
625    }
626
627    passert(strlen(message) < 2*2048);
628    /* TO DO, seems at case fprintf(pf, "whatever"), message is empty! */
629    if (strlen(message) == 0)
630      return 0;
631    else
632      return PortFwrite(message, sizeof(char), strlen(message), PortFile);
633  }
634
635  /*
636   * Returns current file position
637   */
638  int PortFprintf(PORT_FILE PortFile, const char* format, ...)
639  {
640    va_list log_va_list;
641    int ret = 0;
642
643    /* Start variable argument list */
644    va_start(log_va_list, format);
645
646    /* Print formatted message to buffer */
647    ret = PortVfprintf(PortFile, format, log_va_list);
648
649    /* End variable argument list */
650    va_end(log_va_list);
651
652    return ret;
653  }
654
655  /*
656   * Returns string or NULL if error
657   */
658  char *PortFgets(char *string, int n, PORT_FILE PortFile)
659  {
660    int cbToRead = n - 1;
661    BOOL done = FALSE;
662    char *retString = NULL;
663    int i;
664
665    passert(string);
666    passert(n);
667    passert(PortFile);
668
669
670    if (PortFile->eof == 1)
671    {
672      return NULL;
673    }
674
675
676    /* Search for \n only! */
677    for (i = 0; i < cbToRead && !done; i++)
678    {
679      if (PortFile->curPos >= PortFile->endPos)
680      {
681        PortFile->eof = 1;
682        done = TRUE;
683        break;
684      }
685      else if (*PortFile->curPos == '\n')
686      {
687        if (retString == NULL)
688        {
689          retString = string;
690        }
691        retString[i] = '\n';
692        PortFile->curPos++;
693        done = TRUE;
694      }
695      else
696      {
697        if (retString == NULL)
698        {
699          retString = string;
700        }
701        retString[i] = *PortFile->curPos++;
702      }
703    }
704    if (retString != NULL)
705    {
706      retString[i] = '\0';
707    }
708    return retString;
709  }
710
711  /*
712   * Returns string or NULL if error
713   */
714  int PortFflush(PORT_FILE PortFile)
715  {
716    if (PortFile == NULL)
717    {
718      return -1;
719    }
720
721
722    /* call fflush before reopen a writable file */
723    if (ISWRITEMODE(PortFile->mode))  /* writable file */
724    {
725      FileRecord *pCurRec = (FileRecord *)pWritableFileRecTable;
726
727      /* find the file record in memory */
728      do
729      {
730        if (strcmp(pCurRec->name, PortFile->filename) == 0)
731        {
732          /* assgin it as startFrame, so others could get information when reopen it */
733          pCurRec->start = (unsigned char *)PortFile->startFrame;
734          pCurRec->end = PortFile->size - PortFile->endFrame->size +
735                         (PortFile->endPos - PortFile->endFrame->buffer);
736          pCurRec->size = PortFile->size;
737          pCurRec->mode = PortFile->mode;
738
739          break;
740        }
741        pCurRec++;
742      }
743      while (pCurRec->size > 0);
744    }
745    return 0;
746  }
747
748
749  int PortFeof(PORT_FILE PortFile)
750  {
751    passert(PortFile);
752
753    return PortFile->eof;
754  }
755
756  /*
757   * Returns character or EOF
758   */
759  int PortFgetc(PORT_FILE PortFile)
760  {
761    int c;
762
763    passert(PortFile);
764
765    if (PortFile->eof == 1)
766    {
767      return EOF;
768    }
769    else
770    {
771      c = (int) * PortFile->curPos++;
772
773      if (PortFile->curPos >= PortFile->endPos)
774      {
775        PortFile->eof = 1;
776      }
777    }
778    return c;
779  }
780
781  /*
782   * Returns 0 if no error
783   */
784  int PortFerror(PORT_FILE PortFile)
785  {
786    passert(PortFile);
787
788    return 0;
789  }
790
791  void PortClearerr(PORT_FILE PortFile)
792  {
793    PortFile->eof = 0;
794  }
795
796  /*
797   * Returns current file position
798   */
799  int PortFscanf(PORT_FILE PortFile, const char* format, ...)
800  {
801    passert(PortFile);
802
803    (void)format;
804
805    /* Not supported. */
806    passert(FALSE);
807    return 0;
808  }
809
810  void PortRewind(PORT_FILE PortFile)
811  {
812    passert(PortFile);
813
814    PortFile->curFrame = PortFile->startFrame;
815    PortFile->curPos = PortFile->startFrame->buffer;
816
817    PortFile->eof = 0;
818  }
819
820  /*
821   * NULL if it fails, otherwise a valid file pointer
822   */
823  PORT_FILE PortFreopen(const char *path, const char *mode, PORT_FILE PortFile)
824  {
825    /* does not support reopen writable file */
826    if (PortFclose(PortFile) == 0)
827    {
828      PortFile = PortFopen(path, mode);
829      return PortFile;
830    }
831    return NULL;
832  }
833
834  char* PortGetcwd(char *buffer, int maxlen)
835  {
836    if (maxlen >= 1)
837      buffer[0] = '\0';
838    else
839      return NULL;
840
841    return buffer;
842  }
843
844  int PortMkdir(const char *dirname)
845  {
846    return 0;
847  }
848
849#ifdef XANAVI_PROJECT
850
851  int PortSaveFileToDisk(PORT_FILE PortFile, const char *path, const char *fname)
852  {
853    /* ### start mod */
854
855    FILE *fp = NULL; /* real file handle */
856    char fullfname[256], data[256];
857    char mode[3];
858    const char *file;
859    int size;
860
861    if (fname == NULL)
862      file = PortFile->filename;
863    else
864      file = fname;
865
866    if (path == NULL)
867    {
868      PLogMessage("trying to save file %s...\n", file);
869      sprintf(fullfname, "%s", file);
870    }
871    else
872    {
873      PLogMessage("trying to save file %s to %s...\n", file, path);
874      sprintf(fullfname, "%s/%s", path, file);
875    }
876
877    if (ISBINARYMODE(PortFile->mode))  /* binary file, the wav file */
878    {
879      sprintf(mode, "wb");
880    }
881    else
882    {
883      sprintf(mode, "w");
884    }
885
886    if ((fp = fopen(fullfname, mode)) != NULL)
887    {
888      PortRewind(PortFile);
889
890      while ((size = PortFread(data, 1, 256, PortFile)) > 0)
891      {
892        fwrite(data, 1, size, fp);
893      }
894      fclose(fp);
895    }
896    else
897    {
898      PLogError(L("Error to fopen %s with mode %s\n\n"), fullfname, mode);
899      return -1;
900    }
901    return 0;
902  }
903
904  int PortLoadFileFromDisk(PORT_FILE PortFile, const char *filename, const char *mode)
905  {
906    FILE *fp;
907    int size;
908    char data[256];
909
910    passert(PortFile);
911
912    if (filename == NULL)
913      filename = PortFile->filename;
914
915    if (mode == NULL)
916    {
917      data[0] = 'r';
918      if (ISBINARYMODE(PortFile->mode))
919        data[1] = 'b';
920      else
921        data[1] = '\0';
922      data[2] = '\0';
923      mode = data;
924    }
925
926    fp = fopen(filename, mode);
927
928    if (fp == NULL)   /* do not have the file, it is fine */
929      return 0;
930
931    while ((size = fread(data, 1, 256, fp)) > 0)
932      PortFwrite(data, 1, size, PortFile);
933
934    fclose(fp);
935    /* go to the beginning of the file */
936    PortFseek(PortFile, 0, SEEK_SET);
937
938    return 0;
939  }
940
941  int XanaviSaveFileToDisk(PORT_FILE PortFile)
942  {
943    const char *tail;
944    int lenny;
945
946    passert(PortFile);
947
948    /* UG has to be 8.3 format! */
949    lenny = strlen(PortFile->filename);
950    if (lenny > 10)
951      tail = PortFile->filename + (lenny - 11);
952    else
953      tail = PortFile->filename;
954    /* printf( "8.3 filename is %s.\n", tail ); */
955
956    /* the 8.3 format has truncated the path in PortFile->filename,
957       should get the direcotry from par file
958       cmdline.DataCaptureDirectory                  = /CFC
959       TODO: here use /CFC directly to save time
960    */
961    return PortSaveFileToDisk(PortFile, "/CFC", tail);
962  }
963
964  int XanaviLoadFileFromDisk(PORT_FILE PortFile)
965  {
966    char fname[256];
967    char mode[3];
968
969    passert(PortFile);
970
971    sprintf(fname, "/CFC/%s", PortFile->filename);
972
973    mode[0] = 'r';
974    if (ISBINARYMODE(PortFile->mode))
975      mode[1] = 'b';
976    else
977      mode[1] = '\0';
978
979    mode[2] = '\0';
980
981    return PortLoadFileFromDisk(PortFile, fname, mode);
982  }
983
984#endif
985#endif /* STATIC_FILE_SYSTME */
986
987#ifdef __cplusplus
988}
989#endif
990
991