//===========================================================================
// @(#) $Name: arts++-1-1-a12 $
// @(#) $Id: ArtsPrimitive.hh,v 1.2 2004/04/21 23:51:29 kkeys Exp $
//===========================================================================
//  Copyright Notice
//
//  By accessing this software, arts++, you are duly informed
//  of and agree to be bound by the conditions described below in this
//  notice:
//
//  This software product, arts++, is developed by Daniel W. McRobb, and
//  copyrighted(C) 1998 by the University of California, San Diego
//  (UCSD), with all rights reserved.  UCSD administers the CAIDA grant,
//  NCR-9711092, under which part of this code was developed.
//
//  There is no charge for arts++ software.  You can redistribute it
//  and/or modify it under the terms of the GNU Lesser General Public
//  License, Version 2.1, February 1999, which is incorporated by
//  reference herein.
//
//  arts++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF
//  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use
//  of it will not infringe on any third party's intellectual
//  property rights.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with arts++.  Copies can also be obtained from:
//
//    http://www.gnu.org/copyleft/lesser.html
//
//  or by writing to:
//
//  Free Software Foundation, Inc.
//  59 Temple Place, Suite 330
//  Boston, MA 02111-1307
//  USA
//
//  Or contact:
//
//    info@caida.org
//===========================================================================

#ifndef _ARTSPRIMITIVE_HH_
#define _ARTSPRIMITIVE_HH_

extern "C" {
#include <unistd.h>
#include "caida_t.h"
#include "artslocal.h"
}

#ifdef HAVE_IOSTREAM
  #include <iostream>
#else
  #include <iostream.h>
#endif

//---------------------------------------------------------------------------
//  class ArtsPrimitive
//---------------------------------------------------------------------------
//!  This class provides read/write routines for multi-byte integer data,
//!  floats and doubles.  It also provides generic robust read/write
//!  routines for sockets (FdWrite() and FdRead()).  All of the routines
//!  except FdWrite() and FdRead() assume that contents of an iostream or
//!  file descriptor are always in network byte order.  Hence the Write*
//!  member functions for integer types convert to network byte order
//!  from host byte order before outputting to an ostream or file
//!  descriptor and the Read* member functions for integer types convert
//!  from network byte order to host byte order after reading from an
//!  istream or file descriptor.
//!
//!  The routines for floats and doubles use XDR under the hood.  Hence
//!  the on-the-wire (or disk) format for these types is always 4 bytes
//!  for floats, 8 bytes for doubles (in IEEE format, see RFC 1832 and/or
//!  ANSI/IEEE Standard 754-1985).  For the multi-byte integer types, the
//!  routines will handle run length encoded (RLE) values, but the caller
//!  is responsible for passing in the correct length (and
//!  reading/writing the length itself).
//---------------------------------------------------------------------------
class ArtsPrimitive
{
public:
  
  //-------------------------------------------------------------------------
  //        int FdWrite(int fd, const void *ptr, int numBytes) const
  //.........................................................................
  //!  Writes numBytes of the data pointed to by ptr to the file
  //!  descriptor fd.  This is really just a wrapper around the UNIX
  //!  write() system call, but we try to write all of numBytes until
  //!  an error occurs (instead of just returning a short byte count).
  //!  This is mostly useful when dealing with sockets (where fd is
  //!  a socket file descriptor), but is used internally as well (to
  //!  unify socket and file handling).
  //-------------------------------------------------------------------------
  int FdWrite(int fd, const void *ptr, int numBytes) const;
  
  //-------------------------------------------------------------------------
  //         int FdRead(int fd, void *ptr, int numBytes) const
  //.........................................................................
  //!  Reads numBytes from fd into ptr.  This is really just a wrapper
  //!  around the UNIX read() system call, but we try to read all of
  //!  numBytes until an error occurs (instead of just returning a short
  //!  byte count).  This is mostly useful when dealing with sockets
  //!  (where fd is a socket file descriptor), but is used internally
  //!  as well (to unify socket and file handling).
  //-------------------------------------------------------------------------
  int FdRead(int fd, void *ptr, int numBytes) const;
  
  //------------------------------------------------------------------------
  //  WriteUint16(std::ostream & os, const uint16_t & value, uint8_t len) const
  //........................................................................
  //!  Writes len (1 or 2) bytes of an uint16_t value to an ostream in
  //!  network byte order.  The caller's passed-in value is assumed to be
  //!  in host byte order.  The len field is useful for cases where an
  //!  uint16_t value can be stored in a single byte and both reader and
  //!  writer know this ahead of time.  Legal len values are 1 and 2.
  //!  Returns the ostream.
  //------------------------------------------------------------------------
  std::ostream & WriteUint16(std::ostream & os, const uint16_t & value,
                        uint8_t len) const;
  
  //-------------------------------------------------------------------------
  //   int WriteUint16(int fd, const uint16_t & value, uint8_t len) const
  //.........................................................................
  //!  Writes len (1 or 2) bytes of an uint16_t value to a file descriptor
  //!  in network byte order.  The caller's passed-in value is assumed to be
  //!  in host byte order.  The len field is useful for cases where an
  //!  uint16_t value can be stored in a single byte and both reader and
  //!  writer know this ahead of time.  Legal len values are 1 and 2.
  //!  Returns the number of bytes written on success, -1 on failure.
  //-------------------------------------------------------------------------
  int WriteUint16(int fd, const uint16_t & value, uint8_t len) const;
  
  //------------------------------------------------------------------------
  //   ReadUint16(std::istream & is, uint16_t & value, uint8_t len) const
  //........................................................................
  //!  Reads len (1 or 2) bytes from an ostream and converts the contents
  //!  from network byte order to host byte order, storing the result in
  //!  value.  Returns the istream.
  //------------------------------------------------------------------------
  std::istream & ReadUint16(std::istream & is, uint16_t & value, uint8_t len) const;

  //-------------------------------------------------------------------------
  //      int ReadUint16(int fd, uint16_t & value, uint8_t len) const
  //.........................................................................
  //!  Reads len (1 or 2) bytes from a file descriptor and converts the
  //!  contents from network byte order to host byte order, storing the
  //!  result in value.  Returns the number of bytes read on success, -1
  //!  on failure.
  //-------------------------------------------------------------------------
  int ReadUint16(int fd, uint16_t & value, uint8_t len) const;
  
  //------------------------------------------------------------------------
  //  WriteUint32(std::ostream & os, const uint32_t & value, uint8_t len) const
  //........................................................................
  //!  Writes len (1, 2 or 4) bytes of an uint32_t to an ostream in network
  //!  byte order.  The caller's passed-in value is assumed to be in host
  //!  byte order.  The len field is useful for cases where an uint32_t
  //!  value can be stored in less than 4 bytes and both reader and writer
  //!  know this ahead of time.  Returns the ostream.
  //------------------------------------------------------------------------
  std::ostream & WriteUint32(std::ostream & os, const uint32_t & value,
                        uint8_t len) const;

  //-------------------------------------------------------------------------
  //   int WriteUint32(int fd, const uint32_t & value, uint8_t len) const
  //.........................................................................
  //!  Writes len (1, 2 or 4) bytes of an uint32_t to a file descriptor
  //!  in network byte order.  The caller's passed-in value is assumed to
  //!  be in host byte order.  The len field is useful for cases where an
  //!  uint32_t value can be stored in less than 4 bytes and both reader
  //!  and writer know this ahead of time.  Returns the number of bytes
  //!  written on success, -1 on failure.
  //-------------------------------------------------------------------------
  int WriteUint32(int fd, const uint32_t & value, uint8_t len) const;
  
  //------------------------------------------------------------------------
  //   ReadUint32(std::istream & is, uint32_t & value, uint8_t len) const
  //........................................................................
  //!  Reads len (1, 2 or 4) bytes from an ostream and converts the contents
  //!  from network byte order to host byte order, storing the result in
  //!  value.  Returns the istream.
  //------------------------------------------------------------------------
  std::istream & ReadUint32(std::istream & is, uint32_t & value, uint8_t len) const;

  //-------------------------------------------------------------------------
  //      int ReadUint32(int fd, uint32_t & value, uint8_t len) const
  //.........................................................................
  //!  Reads len (1, 2 or 4) bytes from a file descriptor and converts
  //!  the contents from network byte order to host byte order, storing
  //!  the result in value.  Returns the number of bytes read on success,
  //!  -1 on failure.
  //-------------------------------------------------------------------------
  int ReadUint32(int fd, uint32_t & value, uint8_t len) const;
  
  //------------------------------------------------------------------------
  //  WriteUint64(std::ostream & os, const uint64_t & value, uint8_t len) const
  //........................................................................
  //!  Writes len (1, 2, 4 or 8) bytes of an uint32_t to an ostream in
  //!  network byte order.  The caller's passed-in value is assumed to be
  //!  in host byte order.  The len field is useful for cases where an
  //!  uint64_t value can be stored in less than 8 bytes and both reader
  //!  and writer know this ahead of time.  Returns the ostream.
  //------------------------------------------------------------------------
  std::ostream & WriteUint64(std::ostream & os, const uint64_t & value,
                        uint8_t len) const;

  //-------------------------------------------------------------------------
  //   int WriteUint64(int fd, const uint64_t & value, uint8_t len) const
  //.........................................................................
  //!  Writes len (1, 2, 4 or 8) bytes of an uint32_t to a file
  //!  descriptor in network byte order.  The caller's passed-in value is
  //!  assumed to be in host byte order.  The len field is useful for
  //!  cases where an uint64_t value can be stored in less than 8 bytes
  //!  and both reader and writer know this ahead of time.  Returns the
  //!  number of bytes written on success, -1 on failure.
  //-------------------------------------------------------------------------
  int WriteUint64(int fd, const uint64_t & value, uint8_t len) const;
  
  //------------------------------------------------------------------------
  //    ReadUint64(std::istream & is, uint64_t & value, uint8_t len) const
  //........................................................................
  //!  Reads len (1, 2, 4 or 8) bytes from an ostream and converts the
  //!  contents from network byte order to host byte order, storing the
  //!  result in value.  Returns the istream.
  //------------------------------------------------------------------------
  std::istream & ReadUint64(std::istream & is, uint64_t & value, uint8_t len) const;

  //-------------------------------------------------------------------------
  //       int ReadUint64(int fd, uint64_t & value, uint8_t len) const
  //.........................................................................
  //!  Reads len (1, 2, 4 or 8) bytes from a file descriptor and converts
  //!  the contents from network byte order to host byte order, storing
  //!  the result in value.  Returns the number of bytes read on success,
  //!  -1 on failure.
  //-------------------------------------------------------------------------
  int ReadUint64(int fd, uint64_t & value, uint8_t len) const;

  //-------------------------------------------------------------------------
  //     std::istream & ReadIpv4Network(std::istream & is, ipv4addr_t & value,
  //                               uint8_t len) const
  //.........................................................................
  //!  Reads len (1, 2, 3 or 4) bytes from an istream and stores the
  //!  results in value.  This function permits reading network addresses
  //!  in shortened form; a class B network, for example, can be stored
  //!  in only 2 bytes on disk.
  //-------------------------------------------------------------------------
  std::istream & ReadIpv4Network(std::istream & is, ipv4addr_t & value,
                            uint8_t len) const;

  //-------------------------------------------------------------------------
  //   int ReadIpv4Network(int fd, ipv4addr_t & value, uint8_t len) const
  //.........................................................................
  //!  Reads len (1, 2, 3 or 4) bytes from a file descriptor and stores the
  //!  results in value.  This function permits reading network addresses
  //!  in shortened form; a class B network, for example, can be stored in
  //!  only 2 bytes on disk.
  //-------------------------------------------------------------------------
  int ReadIpv4Network(int fd, ipv4addr_t & value, uint8_t len) const;

  //-------------------------------------------------------------------------
  //    std::ostream & WriteIpv4Network(std::ostream & os, const ipv4addr_t & value,   
  //                               uint8_t len) const
  //.........................................................................
  //!  Writes len bytes of value to an ostream.  When using this function,
  //!  the idea is that you're storing a byte-counted IP address, which
  //!  means you can store a network address with the minimum required
  //!  space (a class B network in 2 bytes, for example).  Returns the
  //!  number of bytes written.  Always writes in network byte order.
  //-------------------------------------------------------------------------
  std::ostream & WriteIpv4Network(std::ostream & os, const ipv4addr_t & value,
                             uint8_t len) const;

  //-------------------------------------------------------------------------
  //       int WriteIpv4Network(int fd, const ipv4addr_t & value,
  //                            uint8_t len) const
  //.........................................................................
  //!  Writes len bytes of value to a file descriptor.  When using this
  //!  function, the idea is that you're storing a byte-counted IP address,
  //!  which means you can store a network address with the minimum
  //!  required space (a class B network in 2 bytes, for example).  Returns
  //!  the number of bytes written.  Always writes in network byte order.
  //-------------------------------------------------------------------------
  int WriteIpv4Network(int fd, const ipv4addr_t & value, uint8_t len) const;

  //-------------------------------------------------------------------------
  //         std::istream & ReadFloat(std::istream & is, float & value) const
  //.........................................................................
  //  UNTESTED
  //  Reads a float from an istream, using XDR.  Returns the istream.
  //-------------------------------------------------------------------------
  std::istream & ReadFloat(std::istream & is, float & value) const;
  
  //-------------------------------------------------------------------------
  //               int ReadFloat(int fd, float & value) const
  //.........................................................................
  //  UNTESTED
  //  Reads a float from a file descriptor, using XDR.  Returns the
  //  number of bytes read on success (should be 4), -1 on error.
  //-------------------------------------------------------------------------
  int ReadFloat(int fd, float & value) const;
  
  //-------------------------------------------------------------------------
  //          std::ostream & WriteFloat(std::ostream & os, float value) const
  //.........................................................................
  //  UNTESTED
  //  Writes a float to an ostream, using XDR.  Returns the ostream.
  //-------------------------------------------------------------------------
  std::ostream & WriteFloat(std::ostream & os, float value) const;
  
  //-------------------------------------------------------------------------
  //                int WriteFloat(int fd, float value) const
  //.........................................................................
  //  UNTESTED
  //  Writes a float to a file descriptor, using XDR.  Returns the
  //  number of bytes written on success (should be 4), -1 on error.
  //-------------------------------------------------------------------------
  int WriteFloat(int fd, float value) const;

  //-------------------------------------------------------------------------
  //        std::istream & ReadDouble(std::istream & is, double & value) const
  //.........................................................................
  //  UNTESTED
  //  Reads a souble from an istream, using XDR.  Returns the istream.
  //-------------------------------------------------------------------------
  std::istream & ReadDouble(std::istream & is, double & value) const;
  
  //-------------------------------------------------------------------------
  //              int ReadDouble(int fd, double & value) const;              
  //.........................................................................
  //  UNTESTED
  //  Reads a double from a file descriptor, using XDR.  Returns the
  //  number of bytes read on success (should be 8), -1 on failure.
  //-------------------------------------------------------------------------
  int ReadDouble(int fd, double & value) const;
  
  //-------------------------------------------------------------------------
  //         std::ostream & WriteDouble(std::ostream & os, double value) const
  //.........................................................................
  //  UNTESTED
  //  Writes a double to an ostream, using XDR.  Returns the ostream.
  //-------------------------------------------------------------------------
  std::ostream & WriteDouble(std::ostream & os, double value) const;
  
  //-------------------------------------------------------------------------
  //               int WriteDouble(int fd, double value) const
  //.........................................................................
  //  UNTESTED
  //  Writes a double to a file descriptor, using XDR.  Returns the
  //  number of bytes written on success (should be 8), -1 on error.
  //-------------------------------------------------------------------------
  int WriteDouble(int fd, double value) const;
  
};

extern ArtsPrimitive g_ArtsLibInternal_Primitive;

#endif  /*  _ARTSPRIMITIVE_HH_  */
