/***************************************************************************
 *                                                                         *
 *   READPFN.C                                                             *
 *                                                                         *
 *   Copyright (c) 1996-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   This function reads a compiled profanity list into memory.  The       *
 *   caller must provide the buffer to be read into.                       *
 *                                                                         *
 *                                           - J. Alvrus    2/29/96        *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"

#define FILREV "$Revision: 7 $"

#ifdef GCWINNT
extern CHAR *profList[26];

INT                                /*   error code                         */
readpfn(                           /* read profanity data file             */
const CHAR *filnam,                /*   profanity data file path+name      */
CHAR **pfnbuf)                     /*   ptr to pfn list buffer (or NULL)   */
{
     CHAR *tmpList[26];
     CHAR *c;
     INT i;
     USHORT *offsets;
     FILE *fp;
     struct ffblk fb;
     CHAR *tmpbuf;

     if (!fndfile(&fb,(CHAR *)filnam,0)) {
          return(RDPFN_FOPEN);
     }
     if (fb.ff_fsize > PFN_MAXALC) {
          return(RDPFN_INVALID);
     }
     if (fb.ff_fsize < 26*sizeof(USHORT)) {
          return(RDPFN_OVERFLOW);
     }
     if ((fp=fopen(filnam,FOPRB)) == NULL) {
          return(RDPFN_FOPEN);
     }
     tmpbuf=alcmem((size_t)fb.ff_fsize);
     if (fread(tmpbuf,1,fb.ff_fsize,fp) != fb.ff_fsize) {
          fclose(fp);
          free(tmpbuf);
          return(RDPFN_EOF);
     }
     offsets=(USHORT *)tmpbuf;
     if (offsets[0] != 0) {
          fclose(fp);
          free(tmpbuf);
          return(RDPFN_INVALID);
     }
     if (tmpbuf[fb.ff_fsize-1] != '\0') {  // null termination for 'z' entry
          fclose(fp);
          free(tmpbuf);
          return(RDPFN_INVALID);
     }
     for (i=0 ; i < 26 ; i++) {
          if (offsets[i] < fb.ff_fsize-(26*sizeof(USHORT))) {
               tmpList[i]=&tmpbuf[offsets[i]+(26*sizeof(USHORT))];
          }
          else {
               fclose(fp);
               free(tmpbuf);
               return(RDPFN_OVERFLOW);
          }
          if (i > 0) {
               if (tmpList[i] <= tmpList[i-1]) {
                    fclose(fp);
                    free(tmpbuf);
                    return(RDPFN_INVALID);
               }
               if (*(tmpList[i]-1) != '\0') { // null term. for 'a'-'y' entries
                    fclose(fp);
                    free(tmpbuf);
                    return(RDPFN_INVALID);
               }
          }
     }
     for (i=0 ; i < 26 ; i++) {
          c=tmpList[i];
          for ( ; *c != '\0' ; c++) {
               if (*c > 3 && !islower(*c)) {
                    fclose(fp);
                    free(tmpbuf);
                    return(RDPFN_INVALID);
               }
          }
     }
     memmove(profList,tmpList,sizeof(profList));
     if (pfnbuf != NULL) {
          *pfnbuf=tmpbuf;
     }
     return(RDPFN_OK);
}
#else
extern CHAR *pfnlst;

INT                                /*   error code                         */
readpfn(                           /* read profanity data file             */
const CHAR *filnam,                /*   profanity data file path+name      */
CHAR **pfnbuf)                     /*   ptr to pfn list buffer (or NULL)   */
{
     INT i,ofsidx,c;
     USHORT *offsets;
     CHAR *list;
     FILE *fp;
     struct ffblk fb;
     CHAR *tmpbuf;

     if (!fndfile(&fb,(CHAR *)filnam,0)) {
          return(RDPFN_FOPEN);
     }
     if (fb.ff_fsize > PFN_MAXALC) {
          return(RDPFN_INVALID);
     }
     if (fb.ff_fsize < 26*sizeof(USHORT)) {
          return(RDPFN_OVERFLOW);
     }
     if ((fp=fopen(filnam,FOPRB)) == NULL) {
          return(RDPFN_FOPEN);
     }
     tmpbuf=alcmem((size_t)fb.ff_fsize);
     offsets=(USHORT *)tmpbuf;
     for (i=0 ; i < 26 ; ++i) {
          if (fread(&offsets[i],1,sizeof(USHORT),fp) != sizeof(USHORT)) {
               fclose(fp);
               return(RDPFN_EOF);
          }
     }
     if (offsets[0] != 0) {
          fclose(fp);
          return(RDPFN_INVALID);
     }
     i=0;
     ofsidx=0;
     list=(CHAR *)&offsets[26];
     while ((c=fgetc(fp)) != EOF) {
          if (i+26*sizeof(USHORT) >= fb.ff_fsize) {
               fclose(fp);
               return(RDPFN_OVERFLOW);
          }
          if ((c > 3 && !islower(c)) || ofsidx >= 26) {
               fclose(fp);
               return(RDPFN_INVALID);
          }
          if (c == 0) {
               ++ofsidx;
               if (ofsidx < 26 && offsets[ofsidx] != i+1) {
                    fclose(fp);
                    return(RDPFN_INVALID);
               }
          }
          list[i++]=c;
     }
     fclose(fp);
     if (ofsidx != 26) {
          return(RDPFN_EOF);
     }
     pfnlst=tmpbuf;
     if (pfnbuf != NULL) {
          *pfnbuf=tmpbuf;
     }
     return(RDPFN_OK);
}
#endif // GCWINNT
