/*
** pktsav.c for  in 
** 
** Made by 
** Login   <vianney@epita.fr>
** 
** Started on  Wed Sep  1 06:40:03 1999 
** Last update Thu Oct 28 20:19:09 1999 
*/
#include <fcntl.h>
#include "pkt.h"
#include "pat_pat.h"
#include "pktsav.h"

/* saves a packet into a portable format.
   Check pkt_sav.h to see the .pkt file format.
   Returns 0 if OK. Might return various errors such as ERR_PAT_OPEN */
t_status		pkt_save(pkt,fname)
t_pkt			*pkt;
char			*fname;		/* File name */
{
  FILE			*f;
  char			buf[BUFSIZ];
  t_status		status;

  if ((f = fopen(fname,"w+")) == NULL)
    return (ERR_PAT_OPEN);
  fprintf(f,"%s\n",PKT_SAV_COOKIE);
  buf[0] = 0;
  if ((status = pat_to_str(pkt->pat,
			   buf,
			   sizeof (buf))) != 0)
    return (status);
  fprintf(f,"%s\n",buf);
  fprintf(f,"%d\n",pkt->len);
  fprintf(f,"%d\n",pkt->netlen);
  buf[0] = 0;
  if ((status = timestamp_to_str(&(pkt->timestamp),
				 0,
				 buf,
				 sizeof (buf),
				 FALSE)) != 0)
    return (status);
  fprintf(f,"%s\n",buf);
  buf[0] = 0;
  if ((status = buf_to_xdata_str(pkt->buf,
				 pkt->len,
				 8,
				 "\n",
				 " ",
				 buf,
				 sizeof (buf))) != 0)
    return (status);
  fprintf(f,"%s\n",buf);
  fclose(f);
#ifdef DEBUG
  if (PAT_VERB(VERB_PAT_PKTSAV))
    fprintf(stderr,"+pktsav+ saved %s successfully\n",fname);
#endif
  return (0);
}

t_vec			*pkt_load_to_vec(fname,status)
char			*fname;
t_status		*status;
{
  int			fd;
  t_parse_lines_context	plc;
  char			wordbuf[STR_BUFSIZ];
  
  if ((fd = open(fname,O_RDONLY)) < 0)
    {
      (*status) = ERR_PAT_OPEN;
      return (NULL);
    }
  if ((plc.vec = PAT_VEC_NEW(status)) == NULL)
    {      
      close(fd);
      return (NULL);
    }
  plc.wordbuf = wordbuf;
  plc.wordbuflen = sizeof (wordbuf);
  plc.wordseps = "";
  plc.lineseps = "\n";
  parse_lines_init(&plc);
  while (1)
    {
      char		buf[BUFSIZ];
      int		cc;
      
      if ((cc = read(fd,buf,sizeof (buf))) < 0)
	{
	  (*status) = ERR_PAT_READ;
	  break ;
	}
      if (cc == 0)
	{
	  (*status) = 0;
	  break ;
	}
      if (((*status) = parse_lines(&plc,buf,cc)) != 0)
	{
	  break ;
	}
    }
  if (((*status) = parse_lines_finnish(&plc)) != 0)
   goto bad;
  close(fd);
  return (plc.vec);
bad:
  VEC_FOR(plc.vec,t_vec *vec_str)
    {
      vec_str_delete(vec_str);
    }
  VEC_ENDFOR;
  vec_delete(plc.vec);
  close(fd);
  return (NULL);  
}

/* loads a packet from a portable format.
   Check pkt_sav.h to see the .pkt file format.
   Returns 0 if OK. Might return various errors such as ERR_PAT_OPEN,
   ERR_PAT_BADFMT if file cookie doesn't match,
   ERR_PAT_NEEDMORE if file is
   truncated, ERR_PAT_ZEROLEN if packet buffer length is 0,
   ERR_PAT_BADMATCH if bytes loaded are != from specified length */
t_status		pkt_load(pkt,fname,alloc_proc,free_proc)
t_pkt			*pkt;
char			*fname;		/* File name */
t_alloc_proc		alloc_proc;	/* Alloc method */
t_free_proc		free_proc;	/* Free method */	
{
  t_vec			*vec;
  t_status		status;
  int			i;
  t_vec			*vec_str;
  char			*buf;
  t_pat			*pat;
  int			len;
  int			netlen;
  struct timeval	ts;
  char			*linebuf;
  int			linelen;
  int			linemaxlen;
  int			bytesloaded;

#define NEXTLINE	if (i > VEC_COUNT(vec))\
  {\
     status = ERR_PAT_NEED_MORE;\
     goto bad;\
   }\
      vec_str = VEC_AT(vec,i++);

#ifdef DEBUG
  if (PAT_VERB(VERB_PAT_PKTSAV))
    fprintf(stderr,"+pktsav+ loading %s\n",fname);
#endif			
  if ((vec = pkt_load_to_vec(fname,
			     &status)) == NULL)
    return (status);
  buf = NULL;
  i = 0;
  NEXTLINE;
  if (strcmp(VEC_AT(vec_str,0),PKT_SAV_COOKIE))
    {
      status = ERR_PAT_BAD_FMT;
      goto bad;
    }
  NEXTLINE;
  if ((pat = pat_from_str(VEC_AT(vec_str,0),
			  &status)) == NULL)
    {
      goto bad;
    }
  NEXTLINE;
  if ((len = atoi(VEC_AT(vec_str,0))) < 1)
    {
      status = ERR_PAT_ZERO_LEN;
      goto bad;
    }
  NEXTLINE;
  netlen = atoi(VEC_AT(vec_str,0));
  NEXTLINE;
  timestamp_from_str(VEC_AT(vec_str,0),&ts);
  if ((buf = alloc_proc(len,
			"pat",
			"pkt_load:buf",
			&status)) == NULL)
    goto bad;
  bzero(buf,len);
  linebuf = buf;
  linelen = 0;
  linemaxlen = len;
  bytesloaded = 0;
  VEC_FOR_FROM(vec,i,t_vec *vec_str)
    {
      if ((status = xdata_to_buf(VEC_AT(vec_str,0),
				 linebuf,
				 &linelen,
				 linemaxlen)) != 0)
	goto bad;
      linebuf += linelen;
      linemaxlen -= linelen;
      bytesloaded += linelen;
    }
  VEC_ENDFOR;
  assert(bytesloaded <= len);
  if (bytesloaded != len)
    {
      status = ERR_PAT_BAD_MATCH;
      goto bad;
    }
  free_proc(pkt->buf,
	    "pat",
	    "*:buf");
  pkt->buf = buf;
  pkt->len = len;
  pkt->netlen = netlen;
  pkt->pat = pat;
  bcopy((char *)(&ts),(char *)(&(pkt->timestamp)),sizeof (struct timeval));
#ifdef DEBUG
  if (PAT_VERB(VERB_PAT_PKTSAV))
    fprintf(stderr,"+pktsav+ loaded %s successfully (pkt is %d bytes len)\n",
	    fname,pkt->len);
#endif
  status = 0;
  goto end;
bad:
  if (buf)
    free_proc(buf,
	      "pat",
	      "buf");
end:
  VEC_FOR(vec,t_vec *vec_str)
    {
      vec_str_delete(vec_str);
    }
  VEC_ENDFOR;
  vec_delete(vec);
  return (status);
}
