/*  ARC - Archive utility - ARCIO

System V Version 1.0 based upon:
    Version 2.30, created on 02/03/86 at 22:56:00

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains the file I/O routines used to manipulate
         an archive.
*/
#include "arc.h"

INT readhdr(hdr,f)                     /* read a header from an archive */
struct heads *hdr;                     /* storage for header */
FILE *f;                               /* archive to read header from */
{
    unsigned char dummy[28];
	INT i,j,k;
    char name[FNLEN];                  /* filename buffer */
    INT try = 0;                       /* retry counter */
    static INT first = 1;              /* true only on first read */

    if(!f)                             /* if archive didn't open */
         return 0;                     /* then pretend it's the end */
    if(feof(f))                        /* if no more data */
         return 0;                     /* then signal end of archive */

    if(fgetc(f)!=ARCMARK)              /* check archive validity */
    {    if(warn)
         {    printf("An entry in %s has a bad header.\n",arcname);
              nerrs++;
         }

         while(!feof(f))
         {    try++;
              if(fgetc(f)==ARCMARK)
              {    ungetc(hdrver=fgetc(f),f);
                   if(hdrver>=0 && hdrver<=ARCVER)
                        break;
              }
         }

         if(feof(f) && first)
              abort("%s is not an archive",arcname);

         if(warn)
              printf("  %d bytes skipped.\n",try);

         if(feof(f))
              return 0;
    }

    hdrver = fgetc(f);                 /* get header version */
    if(hdrver<0)
         abort("Invalid header in archive %s",arcname);
    if(hdrver==0)
         return 0;                     /* note our end of archive marker */
    if(hdrver>ARCVER)
    {    fread(name,sizeof(char),FNLEN,f);
         printf("I don't know how to handle file %s in archive %s\n",
              name,arcname);
         printf("I think you need a newer version of ARC.\n");
         exit(1);
    }

    /* amount to read depends on header type */

    if(hdrver==1)                      /* old style is shorter */
    {    fread(hdr,sizeof(struct heads)-sizeof(long),1,f);
         hdrver = 2;                   /* convert header to new format */
         hdr->length = hdr->size;      /* size is same when not packed */
    }
    else {
	fread(dummy,27,1,f);

	for(i=0;i<13;hdr->name[i]=dummy[i],i++);
	hdr->size = (long)((dummy[16]<<24) + (dummy[15]<<16) + (dummy[14]<<8)
	    + dummy[13]);
	hdr->date = (short)((dummy[18]<<8) + dummy[17]);
	hdr->time = (short)((dummy[20]<<8) + dummy[19]);
	hdr->crc  = (short)((dummy[22]<<8) + dummy[21]);
	hdr->length = (long)((dummy[26]<<24) + (dummy[25]<<16)
	    + (dummy[24]<<8) + dummy[23]);
    }

    first = 0; return 1;               /* we read something */
}

INT writehdr(hdr,f)                    /* write a header to an archive */
struct heads *hdr;                     /* header to write */
FILE *f;                               /* archive to write to */
{
    unsigned char dummy[27];

    fputc(ARCMARK,f);                  /* write out the mark of ARC */
    fputc(hdrver,f);                   /* write out the header version */
    if(!hdrver)                        /* if that's the end */
         return;                       /* then write no more */

    fwrite(hdr->name,1,13,f);
    fputc(hdr->size&255,f);         fputc((hdr->size>>8)&255,f);
    fputc((hdr->size>>16)&255,f);   fputc((hdr->size>>24)&255,f);
    fputc(hdr->date&255,f);         fputc((hdr->date>>8)&255,f);
    fputc(hdr->time&255,f);         fputc((hdr->time>>8)&255,f);
    fputc(hdr->crc&255,f);          fputc((hdr->crc>>8)&255,f);
    fputc(hdr->length&255,f);       fputc((hdr->length>>8)&255,f);
    fputc((hdr->length>>16)&255,f); fputc((hdr->length>>24)&255,f);

    /* note the newest file for updating the archive timestamp */

    if(hdr->date>arcdate
    ||(hdr->date==arcdate && hdr->time>arctime))
    {    arcdate = hdr->date;
         arctime = hdr->time;
    }
}

INT filecopy(f,t,size)                 /* bulk file copier */
FILE *f, *t;                           /* from, to */
long size;                             /* number of bytes */
{
    INT len;                           /* length of a given copy */
    INT putc_tst();

    while(size--)                      /* while more bytes to move */
         putc_tst(fgetc(f),t);
}

INT putc_tst(c,t)                      /* put a character, with tests */
char c;                                /* character to output */
FILE *t;                               /* file to write to */
{
    if(t)
         if(fputc(c,t)==EOF)
              abort("Write fail (disk full?)");
}
