Home | History | Annotate | Download | only in src
      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
     31 extern "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