//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
//-----------------------------------------------------------------------------
//
// Description:
//      rsvc data streamer class
//
// Author:  Jie Chen
//
// Revision History:
//   rsvcDataStreamer.cc,v
// Revision 1.1  1998/01/22  17:08:08  akers
// Addition of new NameServer
//
//
//
#include "rsvcErr.h"
#include "rsvcDataStreamer.h"

// ******************************************************************
// float and double conversion routines
// not portable yet especially for VAX machines
// ******************************************************************
static float htonf (float f)
{
  float fret;
  long *p = (long *)&f;
  long  nl = htonl (*p);
  fret = *(float *)&nl;
  return fret;
}

static float ntohf (float f)
{
  float fret;

  long *p = (long *)&f;
  long  nl = ntohl (*p);
  fret = *(float *)&nl;
  return fret;
}

static double htond (double d)
{
  long *lp, *lq;
  long *dp, *dq;
  double   ret;

  // move high byte first
  lp = lq = (long *)&d;
  lp++; 

  dp = dq = (long *)&ret;
  *dp = htonl (*lp);
  
  lp--; dp++;
  *dp = htonl (*lp);

  ret = *(double *)dq;
  return ret;
}

static double ntohd (double d)
{
  long *lp, *lq;
  long *dp, *dq;
  double   ret;

  // low byte of incoming data should be high byte of host native data
  lp = lq = (long *)&d;
  dp = dq = (long *)&ret;
  dp++;

  *dp = ntohl (*lp);
  
  lp++; dp--;
  *dp = ntohl (*lp);

  ret = *(double *)dq;
  return ret;
}

static rsvc_TS_STAMP htonts (rsvc_TS_STAMP& ts)
{
  rsvc_TS_STAMP rts;

  rts.secPastEpoch = htonl (ts.secPastEpoch);
  rts.nsec         = htonl (ts.nsec);
  return rts;
}

static rsvc_TS_STAMP ntohts (rsvc_TS_STAMP& ts)
{
  rsvc_TS_STAMP rts;

  rts.secPastEpoch = ntohl (ts.secPastEpoch);
  rts.nsec         = ntohl (ts.nsec);
  return rts;
}


rsvcDataStreamer::rsvcDataStreamer (char* buffer, size_t buflen,
				    int   dealloc)
:buffer_ (buffer), buflen_ (buflen), dealloc_ (dealloc), pos_ (0),
 err_ (RSVC_SUCCESS)
{
#ifdef _TRACE_OBJECTS
  printf ("Create rsvcDataStreamer Class Object\n");
#endif
}

rsvcDataStreamer::~rsvcDataStreamer (void)
{
#ifdef _TRACE_OBJECTS
  printf ("Delete rsvcDataStreamer Class Object\n");
#endif
  if (dealloc_)
    if (buffer_) {
      delete []buffer_;
      buffer_ = 0;
    }
}

char*
rsvcDataStreamer::buffer (void) const
{
  return buffer_;
}

size_t
rsvcDataStreamer::bufferLength (void) const
{
  return buflen_;
}

int
rsvcDataStreamer::streamStatus (void) const
{
  return err_;
}


//===============================================================
// Implementation of rsvcDataStreamWriter
//===============================================================
rsvcDataStreamWriter::rsvcDataStreamWriter (char* buffer, size_t size,
					    int dealloc)
:rsvcDataStreamer (buffer, size, dealloc)
{
#ifdef _TRACE_OBJECTS
  printf ("    Create rsvcDataStreamWriter Class Object\n");
#endif
}

rsvcDataStreamWriter::~rsvcDataStreamWriter (void)
{
#ifdef _TRACE_OBJECTS
  printf ("    Delete rsvcDataStreamWriter Class Object\n");
#endif
}

int
rsvcDataStreamWriter::write (char c)
{
  long tmp = (long)c;
  return write (tmp);
}

int
rsvcDataStreamWriter::write (unsigned char c)
{
  long tmp = (long)c;
  return write (tmp);
}

int
rsvcDataStreamWriter::write (short c)
{
  long tmp = (long)c;
  return write (tmp);
}

int
rsvcDataStreamWriter::write (unsigned short c)
{
  long tmp = (long)c;
  return write (tmp);
}


int
rsvcDataStreamWriter::write (int c)
{
  long tmp = (long)c;
  return write (tmp);
}

int
rsvcDataStreamWriter::write (unsigned int c)
{
  long tmp = (long)c;
  return write (tmp);
}

int
rsvcDataStreamWriter::write (long c)
{
  long tmp = htonl (c);
  if (pos_ + rsvcStreamSize (c) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: write overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }
  memcpy (&(buffer_[pos_]), &tmp, rsvcStreamSize (c));
  pos_ += rsvcStreamSize (c);

  return RSVC_SUCCESS;
}

int
rsvcDataStreamWriter::write (unsigned long c)
{
  long tmp = (long)c;
  return write (tmp);
}

int
rsvcDataStreamWriter::write (float c)
{
  float ftmp = htonf (c);

  if (pos_ + rsvcStreamSize (c) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: write float overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }
  memcpy (&(buffer_[pos_]), &ftmp, rsvcStreamSize (c));
  pos_ += rsvcStreamSize (c);

  return RSVC_SUCCESS;  
}

int
rsvcDataStreamWriter::write (double c)
{
  double dtmp = htond (c);

  if (pos_ + rsvcStreamSize (c) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: write double overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }
  memcpy (&(buffer_[pos_]), &dtmp, rsvcStreamSize (c));

  pos_ += rsvcStreamSize (c);
#ifdef _RSVC_DEBUG
  printf ("Write cursor is %d\n", pos_);
#endif
  return RSVC_SUCCESS;  
}

int
rsvcDataStreamWriter::write (char* str)
{
  size_t slen = strlen (str) + 1;
  size_t rlen = _RSVC_RNDUP (slen);  
  size_t len  = sizeof (long) + _RSVC_RNDUP (slen);

  if (pos_ + len > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: write string %s overflow buffer at %d with bufsize %d\n",
	     str, pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }

  // write size of string first
  write ((long)rlen);

  memcpy (&(buffer_[pos_]), str, slen);
  pos_ += slen;

  if (rlen > slen) 
    memset (&(buffer_[pos_]), 0, rlen - slen);
  pos_ += (rlen - slen);

  return RSVC_SUCCESS;
}

int
rsvcDataStreamWriter::write (void* data, size_t len)
{
  size_t rlen = _RSVC_RNDUP (len);
  size_t wlen = sizeof (long) + rlen;

  if (pos_ + wlen > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: write void * overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }  

  // write out size of data first
  write ((long)rlen);

  memcpy (&(buffer_[pos_]), data, len);
  pos_ += len;

  if (rlen > len)
    memset (&(buffer_[pos_]), 0, rlen - len);

  pos_ += (rlen - len);

  return RSVC_SUCCESS;
}

int
rsvcDataStreamWriter::write (rsvc_TS_STAMP& ts)
{
  rsvc_TS_STAMP tts = htonts (ts);
  
  if (pos_ + rsvcStreamSize (ts) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: write TS overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }
  memcpy (&(buffer_[pos_]), &tts, rsvcStreamSize (ts));
  pos_ += rsvcStreamSize (ts);

  return RSVC_SUCCESS; 
}

//===============================================================
// Implementation of rsvcDataStreamReader
//===============================================================
rsvcDataStreamReader::rsvcDataStreamReader (char* buffer, size_t buflen,
					    int dealloc)
:rsvcDataStreamer (buffer, buflen, dealloc)
{
#ifdef _TRACE_OBJECTS
  printf ("    Create rsvcDataStreamReader Class Object\n");
#endif
}

rsvcDataStreamReader::~rsvcDataStreamReader (void)
{
#ifdef _TRACE_OBJECTS
  printf ("    Delete rsvcDataStreamReader Class Object\n");
#endif
}


int
rsvcDataStreamReader::read (char& c)
{
  long tmp;
  int  st;
  
  if ((st = read (tmp)) == RSVC_SUCCESS)
    c = (char)tmp;
  else
    c = 0;

  return st;
}

int
rsvcDataStreamReader::read (unsigned char& c)
{
  long tmp;
  int  st;
  
  if ((st = read (tmp)) == RSVC_SUCCESS)
    c = (unsigned char)tmp;
  else
    c = 0;

  return st;
}

int
rsvcDataStreamReader::read (short & c)
{
  long tmp;
  int  st;
  
  if ((st = read (tmp)) == RSVC_SUCCESS)
    c = (short)tmp;
  else
    c = 0;

  return st;
}

int
rsvcDataStreamReader::read (unsigned short& c)
{
  long tmp;
  int  st;
  
  if ((st = read (tmp)) == RSVC_SUCCESS)
    c = (unsigned short)tmp;
  else
    c = 0;

  return st;
}

int
rsvcDataStreamReader::read (int& c)
{
  long tmp;
  int  st;
  
  if ((st = read (tmp)) == RSVC_SUCCESS) 
    c = (int)tmp;
  else
    c = 0;

  return st;
}

int
rsvcDataStreamReader::read (unsigned int& c)
{
  long tmp;
  int  st;
  
  if ((st = read (tmp)) == RSVC_SUCCESS)
    c = (unsigned int)tmp;
  else
    c = 0;

  return st;
}

int
rsvcDataStreamReader::read (long& c)
{
  long tmp;
  
  if (pos_ + sizeof (c) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: read long overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }
  
  memcpy (&tmp, &(buffer_[pos_]), sizeof (long));
  pos_ += sizeof (long);

  c = ntohl (tmp);
  return RSVC_SUCCESS;
}

int
rsvcDataStreamReader::read (unsigned long& c)
{
  long tmp;
  int  st;
  
  if ((st = read (tmp)) == RSVC_SUCCESS)
    c = (unsigned long)tmp;
  else
    c = 0;

  return st;
}

int
rsvcDataStreamReader::read (float& c)
{
  float ftmp;

  if (pos_ + rsvcStreamSize (c) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: read float overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }
  memcpy (&ftmp, &(buffer_[pos_]), rsvcStreamSize (c));
  pos_ += rsvcStreamSize (c);

  c = ntohf (ftmp);

  return RSVC_SUCCESS;
}

int
rsvcDataStreamReader::read (double& c)
{
  double dtmp;

  if (pos_ + rsvcStreamSize (c) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: read double overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }
  memcpy (&dtmp, &(buffer_[pos_]), rsvcStreamSize (c));
  pos_ += rsvcStreamSize (c);
  
  c = ntohd (dtmp);

  return RSVC_SUCCESS;
}

int
rsvcDataStreamReader::read (rsvc_TS_STAMP & ts)
{
  rsvc_TS_STAMP tts;

  if (pos_ + rsvcStreamSize (ts) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: read TS overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    err_ = RSVC_ERROR;
    return err_;
  }
  memcpy (&tts, &(buffer_[pos_]), rsvcStreamSize (ts));
  pos_ += rsvcStreamSize (ts);

  ts = ntohts (tts);
  return RSVC_SUCCESS;
}

int
rsvcDataStreamReader::read (char* & str)
{
  long str_size = 0;
  int  st = RSVC_SUCCESS;

  if (pos_ + sizeof (long) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: read string header overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
    st = err_ = RSVC_ERROR;
    return err_;
  }

  if ((st = read (str_size)) == RSVC_SUCCESS) {
    if (pos_ + str_size > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: read string overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif
      err_ = RSVC_ERROR;
      return err_;
    }

    if (str_size > 0) {
      str = new char[str_size];
      memcpy (str, &(buffer_[pos_]), (unsigned int)str_size);
      pos_ += (int)str_size;
    }
    else {
      str = 0;
      err_ = st = RSVC_ERROR;
    }
  }
  else {
    str = 0;
    st = err_ = RSVC_ERROR;
  }
  return st;
}

int
rsvcDataStreamReader::read (void* data, size_t size)
{
  long data_size = 0;
  int  st = RSVC_SUCCESS;

  if (pos_ + sizeof (long) > buflen_) {
#ifdef _RSVC_DEBUG
    fprintf (stderr, "Fatal Error: read void * header overflow buffer at %d with bufsize %d\n",
	     pos_, buflen_);
#endif 
    st = err_ = RSVC_ERROR;
    return err_;
  }

  if ((st = read (data_size)) == RSVC_SUCCESS) {
    if (pos_ + data_size > buflen_) {
#ifdef _RSVC_DEBUG
      fprintf (stderr, "Fatal Error: read void * overflow buffer at %d with bufsize %d\n",
	       pos_, buflen_);
#endif 
      st = err_ = RSVC_ERROR;
      return err_;
    }
    if (data_size > 0) {
      memcpy (data, &(buffer_[pos_]), size);
      pos_ += (int)data_size;
    }
    else 
      st = err_ = RSVC_ERROR;
  }
  return st;  
}


