//---------------------------------------------------------------------------
// Copyright (c) 1991,1992 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.h
//	Generic tool designed to convert arrays of data types from one
// 	type to another
//
// Author: Walt Akers and Danjin Wu
//
// Revision History:
//   rsvcData.cc,v
// Revision 1.3  1998/05/27  16:26:55  chen
// fix a iterator bug on ++ operation
//
// Revision 1.2  1998/01/29  19:10:58  akers
// Ongoing development
//
// Revision 1.1  1998/01/22  17:08:04  akers
// Addition of new NameServer
//
//
//                                       
//--------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rsvcData.h"
#include "rsvcDataStreamer.h"

static char* rsvcStrncpy (char* dst, const char* src, size_t len)
{
  if (strlen (src) + 1 <= len)
    return strncpy (dst, src, len);
  strncpy (dst, src, len - 1);
  dst[len - 1] = 0;
  return dst;
}

// *****************************************************************************
// * rsvc_gcvt:
// *	This overloaded function is being used in conjunction with the 
// *	standard library rsvc_gcvt to correct conversion errors when converting 
// *	float values.
// *****************************************************************************
char * rsvcData::rsvc_gcvt(float value, size_t ndigit, char *buf)
{
  char tbuf[32];
  sprintf(tbuf, "%.7g", value);
  rsvcStrncpy(buf, tbuf, ndigit);
  return buf;
}

char * rsvcData::rsvc_gcvt(double value, size_t ndigit, char * buf)
{
  char tbuf[32];
  sprintf(tbuf, "%.14g", value);
  rsvcStrncpy(buf, tbuf, ndigit);
  return buf;
}

// *****************************************************************************
// * RSVCConverter:
// * 	This is the type definition for all RSVC conversion functions.  These
// *	functions are used to perform data conversion from one RSVC datatype
// *	to another.
// *****************************************************************************
typedef void (*rsvcConverter)(void * input, void * output, size_t nElems);

// *****************************************************************************
// * RSVCConversionMatrix:
// *	This matrix contains the cdev conversion functions necessary to convert
// *	between all cdev data types.  The user requests a conversion routime
// *	by using the enumerated cdevDataType values that represent the from
// *	type and the too type.
// *
// *	For instance:
// *	    To convert from 16 bit integer to 32 bit integer, cdevData would
// *	    use the command... 
// *		cdevConversionMatrix[CDEV_INT16][CDEV_INT32](&in16, &out32, 1);
// *
// *	    To convert an array of 25 floats to an array of 25 doubles, 
// *	    cdevData would use the command...
// *		cdevConversionMatrix[CDEV_FLOAT][CDEV_DOUBLE](in, out, 25)
// *****************************************************************************
extern const rsvcConverter rsvcConversionMatrix [RSVC_INVALID+1][RSVC_INVALID+1];

// *****************************************************************************
// * copy:
// *	This function copies the contents of the rsvcData object specified by 
// *	data into this rsvcData object.  It is used by both the copy constructor 
// *	and by the assignment operator.	
// *****************************************************************************
rsvcData & 
rsvcData::copy (const rsvcData & data)
{
  if(this != (rsvcData *)&data) {
    remove();
    for(rsvcDataEntry *ptr = data.entries; ptr!=0; ptr = ptr->next_) {
      switch(ptr->dataType_) {
      case RSVC_BYTE:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.cval);
	else insert(ptr->tag_, ptr->data_.cptr, ptr->elems_, ptr->dim_);
	break;
	  
      case RSVC_INT16:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.sval);
	else insert(ptr->tag_, ptr->data_.sptr, ptr->elems_, ptr->dim_);
	break;

      case RSVC_UINT16:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.usval);
	else insert(ptr->tag_, ptr->data_.usptr, ptr->elems_, ptr->dim_);
	break;

      case RSVC_INT32:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.lval);
	else insert(ptr->tag_, ptr->data_.lptr, ptr->elems_, ptr->dim_);
	break;
	
      case RSVC_UINT32:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.ulval);
	else insert(ptr->tag_, ptr->data_.ulptr, ptr->elems_, ptr->dim_);
	break;

      case RSVC_FLOAT:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.fval);
	else insert(ptr->tag_, ptr->data_.fptr, ptr->elems_, ptr->dim_);
	break;

      case RSVC_DOUBLE:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.dval);
	else insert(ptr->tag_, ptr->data_.dptr, ptr->elems_, ptr->dim_);
	break;
	  
      case RSVC_STRING:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.str);
	else insert(ptr->tag_, ptr->data_.strarr, ptr->elems_, ptr->dim_);
	break;

      case RSVC_TIMESTAMP:
	if (ptr->dim_==0) insert(ptr->tag_, ptr->data_.ts);
	else insert(ptr->tag_, ptr->data_.tsptr, ptr->elems_, ptr->dim_);	  
	break;

      default:
	break;
      }
    }
  }
  return *this;
}

// ****************************************************************************
// * insert
// *     This function insert entry into data directly
// ****************************************************************************
int
rsvcData::insert (rsvcDataEntry* entry)
{

  rsvcDataEntry *result = 0, *prev = 0;
  
  // *********************************************************************
  // * Walk through the list of rsvcDataEntry objects until a matching
  // * tag is found, or until no more items are available.  
  // *********************************************************************
  for(result=entries; result!=0; prev=result, result = result->next_);

  // *********************************************************************
  // * If result is 0, then a matching entry was not found.  If the 
  // * user has specified create, then create a new entry.  
  // *********************************************************************

  // *************************************************************
  // * The prev flag is used to indicate the last known 
  // * rsvcDataEntry object in the list.  If prev contains 0, 
  // * then the list was empty and must be allocated directly.
  // *************************************************************
  if( prev == 0 ) 
    entries = entry;

  // *************************************************************
  // * Otherwise, the new rsvcDataEntry object should be placed
  // * at the bottom of the list.
  // *************************************************************
  else	
    prev->next_ = entry;
  return RSVC_SUCCESS;
}


// *****************************************************************************
// * lookupTag:
// * 	This function attempts to locate the specified tag within the rsvcData
// *	objects list of rsvcDataEntry objects.  If the tag is found, then 
// *	its associated rsvcDataEntry object will be returned, otherwise,
// *	if the caller has specified a non-zero value in the create flag, then 
// *	the new tag will be added to the list.
// *****************************************************************************
rsvcDataEntry * 
rsvcData::lookupTag(char* tag, int create)
{
  rsvcDataEntry *result = 0, *prev = 0;
  
  // *********************************************************************
  // * Walk through the list of rsvcDataEntry objects until a matching
  // * tag is found, or until no more items are available.  
  // *********************************************************************
  for(result=entries; 
      result!=0 && (strcmp (result->tag_, tag)) != 0;
      prev=result, result = result->next_);

  // *********************************************************************
  // * If result is 0, then a matching entry was not found.  If the 
  // * user has specified create, then create a new entry.  
  // *********************************************************************
  if ( result==0 && create ) {
    // *************************************************************
    // * The prev flag is used to indicate the last known 
    // * rsvcDataEntry object in the list.  If prev contains 0, 
    // * then the list was empty and must be allocated directly.
    // *************************************************************
    if( prev == 0 ) {
      entries = new rsvcDataEntry;
      result  = entries;
    }
    // *************************************************************
    // * Otherwise, the new rsvcDataEntry object should be placed
    // * at the bottom of the list.
    // *************************************************************
    else	{
      prev->next_ = new rsvcDataEntry;
      result       = prev->next_;
    } 
  }

  return result;
}

// *****************************************************************************
// * setupTag:
// * 	Convenience function to allow the rsvcData object to more efficiently
// *	prepare new rsvcDataEntry objects for data insertion.
// *	elemSize is the size of one element in bytes, numElems is the number of
// *	elements to allocate, and numDims is the number of dimensions to create.
// *****************************************************************************
rsvcDataEntry * 
rsvcData::setupTag (char* tag, rsvcDataTypes type, size_t elemSize, 
		    size_t numElems, size_t numDims )
{
  rsvcDataEntry * entry;
  if((entry = lookupTag(tag, 1))!=0) {
    // *************************************************************
    // * If the entry is already populated and the new data is not
    // * multidimensional,  clear the old contents.
    // *************************************************************
    if((strcmp (entry->tag_, tag) == 0) && numDims<=0) entry->clear();
    
    // *************************************************************
    // * If the entry is multidimensional, allocate a new data
    // * block for storing the data.
    // *************************************************************
    if(numDims == 1) 
      entry->allocate(numDims, numElems, elemSize);
    
    // *************************************************************
    // * Populate the entry with the new data.
    // *************************************************************
    rsvcStrncpy (entry->tag_, tag, RSVC_TAG_MAX_LEN);
    entry->dataType_ = type;
  }
  return entry;
}


// *****************************************************************************
// * rsvcData:
// *	Default constructor for the rsvcData object.  Initializes local data.
// *****************************************************************************
rsvcData::rsvcData ( void ) 
:entries (0) 
{
  // empty
}

// *****************************************************************************
// * rsvcData:
// *	Copy constructor.  This constructor duplicates the rsvcData object that 
// *	it has been passed as a parameter.
// *****************************************************************************
rsvcData::rsvcData ( const rsvcData & data )
:entries (0)
{
  copy(data);
}

// *****************************************************************************
// * ~rsvcData:
// *	Default destructor for the rsvcData object.  Deallocates local data.
// *****************************************************************************
rsvcData::~rsvcData( void )
{ 
  remove();
}

// *****************************************************************************
// * asciiDump:
// *	This function will dump the contents of the rsvcData object to the
// *	user specified file descriptor.
// *****************************************************************************
#ifdef _WIN32
void rsvcData::asciiDump (long osfHandle)
{
  int fd = _open_osfhandle(osfHandle, _O_WRONLY | _O_APPEND );
  FILE* fp = _fdopen (fd, "a");
#else
void rsvcData::asciiDump ( FILE * fp )
{
#endif
  rsvcDataEntry * entry;
  char tagText[RSVC_INVALID+1][20];
  int  i;
  
  // *************************************
  // * Load the names of the dataTypes   *
  // *************************************
  sprintf(tagText[RSVC_BYTE],    "8 Bit Integer");
  sprintf(tagText[RSVC_INT16],   "16 Bit Integer");
  sprintf(tagText[RSVC_UINT16],  "Unsigned 16 Bit Int");
  sprintf(tagText[RSVC_INT32],   "32 Bit Integer");
  sprintf(tagText[RSVC_UINT32],  "Unsigned 32 Bit Int");
  sprintf(tagText[RSVC_FLOAT],   "Float");
  sprintf(tagText[RSVC_DOUBLE],  "Double");
  sprintf(tagText[RSVC_STRING],  "Char String");
  sprintf(tagText[RSVC_TIMESTAMP],  "Time Stamp");
  sprintf(tagText[RSVC_INVALID], "Invalid Data");

  for(entry=entries; entry!=0; entry=entry->next_)
    {
      fprintf(fp, "Tag Name:  %s\n",  entry->tag_); 
      fprintf(fp, "Data Type: %s", tagText[entry->dataType_]);
      fprintf(fp, "[%i]", entry->elems_);

      fprintf(fp, "\nValues:    ");

      switch(entry->dataType_)
	{
	case RSVC_BYTE:
	  if(entry->dim_==0) fprintf(fp, "% 4i", entry->data_.cval);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "% 4i%s", entry->data_.cptr[i], 
		    (i%13==12)?"\n           ":" ");
	  break;
	  
	case RSVC_INT16:
	  if(entry->dim_==0) fprintf(fp, "% 6hi", entry->data_.sval);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "% 6hi%s", entry->data_.sptr[i], 
		    (i%9==8)?"\n           ":" ");
	  break;
	  
	case RSVC_UINT16:
	  if(entry->dim_==0) fprintf(fp, "% 6hu", entry->data_.usval);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "% 6hu%s", entry->data_.usptr[i], 
		    (i%9==8)?"\n           ":" ");
	  break;
	  
	case RSVC_INT32:
	  if(entry->dim_==0) fprintf(fp, "% 8li", entry->data_.lval);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "% 8li%s", entry->data_.lptr[i], 
		    (i%7==6)?"\n           ":" ");
	  break;
	  
	case RSVC_UINT32:
	  if(entry->dim_==0) fprintf(fp, "% 8lu", entry->data_.ulval);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "% 8lu%s", entry->data_.ulptr[i], 
		    (i%7==6)?"\n           ":" ");
	  break;

	case RSVC_FLOAT:
	  if(entry->dim_==0) fprintf(fp, "% 12.5f", entry->data_.fval);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "% 12.5f%s", entry->data_.fptr[i], 
		    (i%5==4)?"\n           ":" ");
	  break;
	  
	case RSVC_DOUBLE:
	  if(entry->dim_==0) fprintf(fp, "% 14.7f", entry->data_.dval);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "% 14.7f%s", entry->data_.dptr[i], 
		    (i%4==3)?"\n           ":" ");
	  break;
	  
	case RSVC_STRING:
	  if(entry->dim_==0) fprintf(fp, "%s\n", entry->data_.str);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "%s\n           ", entry->data_.strarr[i]);
	  break;
	  
	case RSVC_TIMESTAMP:
	  if(entry->dim_==0) 
	    fprintf(fp, "%u sec and %u nsec \n", 
		    entry->data_.ts.secPastEpoch, entry->data_.ts.nsec);
	  else for(i=0; i<entry->elems_; i++)
	    fprintf(fp, "%u sec and %u nsec \n", 
	   	    entry->data_.tsptr[i].secPastEpoch, entry->data_.tsptr[i].nsec);
	  break;
	  
	case RSVC_INVALID:
	  break;
	}	
      fprintf(fp, "\n\n");
    }
  fflush (fp);
#ifdef _WIN32
  _commit (fd);
#endif
}


// *****************************************************************************
// * streamSize:
// *	Calculates the size of the Buffer necessary to store the rsvcData 
// *	object.  This function may be used to determine the size of a 
// *	preallocated buffer for storing the xdr representation of a rsvcData
// *	object.  The bufLen parameter will receive the size of the buffer, and
// *	the elementCount variable will receive the number of elements that will
// * 	be stored in the buffer.
// *****************************************************************************
int 
rsvcData::streamSize  (size_t * bufLen, size_t * elementCount)
{
  rsvcDataEntry * ptr            = entries;
  int             dataSize       = 0;
  int             rsvcElementCnt = 0;
  int             i;
  
  // ************************************#
  // * CALCULATE THE SIZE OF THE BUFFER  #
  // ************************************#
  
  // *************************************
  // * First is magic number             *
  // *************************************
  dataSize  += rsvcStreamSize (_RSVC_MAGIC_NUM);

  // *************************************
  // * Add the size of the tag count int *
  // *************************************
  dataSize +=  rsvcStreamSize (rsvcElementCnt);

  // *************************************
  // * Add the size of each valid item   *
  // *************************************
  for(ptr=entries; ptr!=0; ptr = ptr->next_)
    { 
      // *****************************
      // * Do not process entries    *
      // * with RSVC_INVALID as the  *
      // * dataType or 0 as the tag. *
      // *****************************
      if(ptr->dataType_==RSVC_INVALID || ptr->tag_[0] ==0) continue;
      
      // *****************************
      // * Calculate the number of   *
      // * elements in this tagged   *
      // * data item.                *
      // *****************************
      int numElements = ptr->dim_!=0?ptr->elems_:1;
      
      // *****************************
      // * Increment the counter     *
      // ***************************** 
      rsvcElementCnt++;
      
      // *****************************
      // * Add the size of the       *
      // * rsvcDataEntries tag_,     *
      // *****************************
      dataSize += rsvcStreamSize ((void *)ptr->tag_, RSVC_TAG_MAX_LEN);
      
      //******************************
      // * dataType_, dim_, elems_.  * 
      // *****************************
      dataSize += 3 *  rsvcStreamSize ((int)1);
      
      // *****************************
      // * Add the size of the data  *
      // *****************************
      if (ptr->dataType_==RSVC_BYTE)   
	dataSize += numElements * rsvcStreamSize ((char)1);
      else if(ptr->dataType_==RSVC_INT16)  
	dataSize += numElements * rsvcStreamSize ((short)1);
      else if(ptr->dataType_==RSVC_UINT16) 
	dataSize += numElements *  rsvcStreamSize ((unsigned short)1);
      else if(ptr->dataType_==RSVC_INT32)  
	dataSize += numElements *  rsvcStreamSize ((int)1);
      else if(ptr->dataType_==RSVC_UINT32) 
	dataSize += numElements *  rsvcStreamSize ((unsigned int)1);
      else if(ptr->dataType_==RSVC_FLOAT)  
	dataSize += numElements * rsvcStreamSize ((float) 1.0);
      else if(ptr->dataType_==RSVC_DOUBLE) 
	dataSize += numElements * rsvcStreamSize ((double)1.0);
      else if(ptr->dataType_==RSVC_STRING)
	{
	  if(numElements==1) 
	    dataSize += rsvcStreamSize (ptr->data_.str);
	  else 
	    for(i=0; i<numElements; i++) 
	      dataSize += rsvcStreamSize (ptr->data_.strarr[i]);
	}
      else if(ptr->dataType_==RSVC_TIMESTAMP) 
	dataSize += numElements * rsvcStreamSize (ptr->data_.ts);
    }
  
  *elementCount = rsvcElementCnt;
  *bufLen       = dataSize;
  
  return *bufLen>0?RSVC_SUCCESS:RSVC_ERROR;
}

// *****************************************************************************
// * streamOut:
// *	This function encapsulates the contents of the rsvcData class into a 
// *	binary stream.  This function allocates the buffer and returns the new 
// *	buffer and the buffer size.
// *****************************************************************************
int 
rsvcData::streamOut ( char ** buf, size_t * bufLen )
{	
  size_t count = 0;
  int    st = RSVC_SUCCESS;
  
  // ************************************#
  // * Calculate the size of the buffer  #
  // ************************************#
  if ((st = streamSize(bufLen, &count)) != RSVC_SUCCESS)
    return st;
  
  // ************************************#
  // * Allocate the buffer and call the  #
  // * export function.                  #
  // ************************************#
  if((*buf = new char[*bufLen])!=0) streamOut (*buf, *bufLen, count);
  
  return buf==0?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * streamOut
// *	This function encapsulates the contents of the rsvcData class into a 
// *	preallocated binary stream.  The buf parameter contains the address of 
// *	the caller allocated buffer, the bufLen parameter specifies the size
// *	of the buffer, and the count parameter specifies the number of tagged 
// *	data items that will be copied from the rsvcData object into the
// *	binary stream.
// *****************************************************************************
int 
rsvcData::streamOut ( char * buf, size_t bufLen, size_t count)
{
  rsvcDataEntry * ptr;
  int             dataSize       = bufLen;
  int             rsvcElementCnt = count;
  int             i; 
  int             idx = 0;
  // float        ftmp;
  // double       dtmp;
  int             rsvcError = RSVC_SUCCESS;

  // create stream writer without deleting buffer
  rsvcDataStreamWriter writer (buf, bufLen, 0);
  
  // ************************************#
  // * Transfer the data to the buffer   #
  // ************************************#

  // *************************************
  // * Write magic number first          *
  // *************************************
  if ((rsvcError = writer.write (_RSVC_MAGIC_NUM)) != RSVC_SUCCESS)
    return rsvcError;

  // *************************************
  // * Write the number of elements      *
  // *************************************
  if ((rsvcError = writer.write (rsvcElementCnt)) != RSVC_SUCCESS)
    return rsvcError;
  
  // *************************************
  // * Write each valid item.            *
  // *************************************
  for(ptr = entries; ptr != 0 && rsvcError == RSVC_SUCCESS; ptr = ptr->next_)
    {
      // *****************************
      // * Do not process entries    *
      // * with RSVC_INVALID as the  *
      // * dataType or 0 as the tag. *
      // *****************************
      if(ptr->dataType_==RSVC_INVALID || ptr->tag_==0) continue;
      
      // *****************************
      // * Calculate the number of   *
      // * elements in this tagged   *
      // * data item.                *
      // *****************************
      int numElements = ptr->dim_!=0?ptr->elems_:1;
      
      // *****************************
      // * Decrement the counter     *
      // ***************************** 
      rsvcElementCnt--;
      
      // *****************************
      // * Write the tag_,           *
      // * write  dataType_          *
      // * dim_, and elems_ of the   *
      // * rsvcDataEntry object.     * 
      // *****************************
      
      if (writer.write ((void *)ptr->tag_, RSVC_TAG_MAX_LEN) != RSVC_SUCCESS ||
	  writer.write (ptr->dataType_) != RSVC_SUCCESS ||
	  writer.write (ptr->dim_) != RSVC_SUCCESS ||
	  writer.write (ptr->elems_) != RSVC_SUCCESS) {
	rsvcError = RSVC_ERROR;
	return rsvcError;
      }

      // *****************************
      // * Write the data            *
      // *****************************
      if (ptr->dataType_==RSVC_BYTE) {
	if(numElements==1) 
	  rsvcError = writer.write (ptr->data_.cval);
	else {
	  for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 
	    rsvcError = writer.write (ptr->data_.cptr[i]);
	}
      }
      else if(ptr->dataType_==RSVC_INT16)       
	{
	  if(numElements==1) 
	    rsvcError = writer.write (ptr->data_.sval);
	  else {
	    for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 
	      rsvcError = writer.write (ptr->data_.sptr[i]);
	  }
	}
      else if(ptr->dataType_==RSVC_UINT16)       
	{
	  if(numElements==1) 
	    rsvcError = writer.write (ptr->data_.usval);
	  else {
	    for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 
	      rsvcError = writer.write (ptr->data_.usptr[i]);
	  }
	}
      else if(ptr->dataType_==RSVC_INT32)       
	{
	  if(numElements==1) 
	    rsvcError = writer.write (ptr->data_.lval);
	  else {
	    for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 
	      rsvcError = writer.write (ptr->data_.lptr[i]);
	  }
	}
      else if(ptr->dataType_==RSVC_UINT32)       
	{
	  if(numElements==1) 
	    rsvcError = writer.write (ptr->data_.ulval);
	  else {
	    for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 
	      rsvcError = writer.write (ptr->data_.ulptr[i]);
	  }
	}
      else if(ptr->dataType_==RSVC_FLOAT)
	{
	  if(numElements==1) 
	    rsvcError = writer.write (ptr->data_.fval);	    
	  else {
	    for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 	    
	      rsvcError = writer.write (ptr->data_.fptr[i]);
	  }
	}
      else if(ptr->dataType_==RSVC_DOUBLE)
	{
	  if(numElements==1) 
	    rsvcError = writer.write (ptr->data_.dval);
	  else {
	    for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 
	      rsvcError = writer.write (ptr->data_.dptr[i]);
	  }
	}
      else if(ptr->dataType_==RSVC_STRING) 
	{
	  if(numElements==1) 
	    rsvcError = writer.write (ptr->data_.str);
	  else {
	    for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 
	      rsvcError = writer.write (ptr->data_.strarr[i]);
	  }
	}
      else if(ptr->dataType_==RSVC_TIMESTAMP) 
	{
	  // rsvc_TS_STAMP tmpts;
	  if(numElements==1) 
	    rsvcError = writer.write (ptr->data_.ts);
	  else {
	    for(i=0; i<numElements && rsvcError == RSVC_SUCCESS; i++) 
	      rsvcError = writer.write (ptr->data_.tsptr[i]);
	  }
	}
    }
  
  return rsvcError;
}

// *****************************************************************************
// * streamIn
// *	This function populates the rsvcData class using the contents of a 
// *    binary buffer that has bee created by the xdrExport function.
// *****************************************************************************
int 
rsvcData::streamIn ( char * buf, size_t bufLen)
{
  int        rsvcElementCnt;
  int        i, j;
  int        rsvcError = RSVC_SUCCESS;

  if(buf==0 || bufLen==0) return RSVC_INVALIDARG;

  rsvcDataStreamReader reader (buf, bufLen, 0);
  // *************************************
  // * Deallocate any data previously    *
  // * assigned to the rsvcData class.   *
  // *************************************
  remove();

  // *************************************
  // * Read the magic number from buffer *
  // *************************************
  long magic;
  
  if (reader.read (magic) != RSVC_SUCCESS || magic != _RSVC_MAGIC_NUM) {
    printf ("Magic number mismatch 0x%x != 0x%x\n", magic, _RSVC_MAGIC_NUM);
    rsvcError = RSVC_ERROR;
    return rsvcError;
  }
  
  // *************************************
  // * Read the element count from the   *
  // * buffer.                           *
  // *************************************
  rsvcError = reader.read (rsvcElementCnt);
  
  // *************************************
  // * Process each tagged element in    *
  // * the buffer.                       *
  // *************************************
  for(i=0; i<rsvcElementCnt && rsvcError==RSVC_SUCCESS; i++)
    {
      char          tag_[RSVC_TAG_MAX_LEN];
      rsvcDataTypes dataType_;
      size_t        dim_;
      size_t        elems_;

      // *****************************
      // * Read the data definition  *
      // * information from the data *
      // * stream.                   *
      // *****************************
      if(reader.read((void *)tag_, RSVC_TAG_MAX_LEN) != RSVC_SUCCESS ||
	 reader.read((int &)dataType_) != RSVC_SUCCESS ||
	 reader.read((int &)dim_) != RSVC_SUCCESS      ||
	 reader.read((int &)elems_) != RSVC_SUCCESS) 
	rsvcError = RSVC_ERROR;

      if(rsvcError==RSVC_SUCCESS)
	{		
	  // *****************************
	  // * Calculate the number of   *
	  // * elements in this tagged   *
	  // * data item.                *
	  // *****************************
	  int numElements = dim_!=0?elems_:1;
	  rsvcDataEntry * entry;
	  
	  switch(dataType_) {
	  case RSVC_BYTE:
	    if((entry = setupTag(tag_, dataType_, sizeof(BYTE), 
				 numElements, dim_))!=0) {
	      if(numElements==1) 
		rsvcError = reader.read(entry->data_.cval);
	      else for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++) 
		rsvcError = reader.read(entry->data_.cptr[j]);
	    }
	    break;
	      
	  case RSVC_INT16:
	    if((entry = setupTag(tag_, dataType_, sizeof(short), 
				 numElements, dim_))!=0) {
	      if(numElements==1) 
		rsvcError = reader.read(entry->data_.sval);
	      else 
		for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++)
		  rsvcError = reader.read (entry->data_.sptr[j]);
	    }
	    break;
	      
	  case RSVC_UINT16:
	    if((entry = setupTag(tag_, dataType_, sizeof(unsigned short), 
				 numElements, dim_))!=0) {
	      if(numElements==1) 
		rsvcError = reader.read (entry->data_.usval);
	      else 
		for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++)
		  rsvcError = reader.read(entry->data_.usptr[j]);
	    }
	    break;
	      
	  case RSVC_INT32:
	    if((entry = setupTag(tag_, dataType_, sizeof(long), 
				 numElements, dim_))!=0) {

	      if(numElements==1) 
		rsvcError = reader.read (entry->data_.lval);
	      else 
		for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++)
		  rsvcError = reader.read(entry->data_.lptr[j]);
	    }
	    break;
	      
	  case RSVC_UINT32:
	    if((entry = setupTag(tag_, dataType_, sizeof(unsigned long), 
				 numElements, dim_))!=0) {
	      if(numElements==1) 
		rsvcError = reader.read(entry->data_.ulval);
	      else 
		for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++)
		  rsvcError = reader.read (entry->data_.ulptr[j]);
	    }
	    break;
	      
	  case RSVC_FLOAT:
	    if((entry = setupTag(tag_, dataType_, sizeof(float), 
				 numElements, dim_))!=0) {
	      if(numElements==1) 
		rsvcError = reader.read (entry->data_.fval);
	      else 
		for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++)
		  rsvcError = reader.read (entry->data_.fptr[j]);
	    }
	    break;
	      
	  case RSVC_DOUBLE:
	    if((entry = setupTag(tag_, dataType_, sizeof(double), 
				 numElements, dim_))!=0) {
	      if(numElements==1) 
		rsvcError = reader.read (entry->data_.dval);
	      else for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++)
		rsvcError = reader.read (entry->data_.dptr[j]);
	    }
	    break;
	      
	  case RSVC_STRING:
	    {
	      char ** ptr = new char *[numElements];
	      memset(ptr, 0, sizeof(char *)*numElements);
	      
	      for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++) {
		rsvcError = reader.read (ptr[j]);
	      }
	      
	      if(rsvcError==RSVC_SUCCESS) {
		if(dim_==0) insert(tag_, *ptr);
		else        insert(tag_, ptr, numElements, dim_);
	      }
	      for(j=0; j<numElements; j++) 
		if(ptr[j]!=0) 
		  delete []ptr[j];
	      delete []ptr;
	    }
	    break;
	      
	  case RSVC_TIMESTAMP:
	    if((entry = setupTag(tag_, dataType_, sizeof(rsvc_TS_STAMP), 
				 numElements, dim_))!=0) {
	      if(numElements==1) 
		rsvcError = reader.read (entry->data_.ts);
	      else 
		for(j=0; j<numElements && rsvcError==RSVC_SUCCESS; j++)
		  rsvcError = reader.read (entry->data_.tsptr[j]);
	    }
	    break;

	  case RSVC_INVALID:
	    break;
	  }
	}

    }
  
  return rsvcError;
}

// *****************************************************************************
// * remove:
// *	Removes the all rsvcDataEntry objects from the rsvcData object.
// *****************************************************************************
void rsvcData::remove( void )
{
  while(entries!=0)
    {
      rsvcDataEntry * ptr = entries;
      entries = ptr->next_;
      delete ptr;
    }
}

// *****************************************************************************
// * remove:
// *	Removes a specified tagged data item from the rsvcData object.
// *****************************************************************************
void rsvcData::remove(char* tag)
{
  rsvcDataEntry *result = 0, *prev = 0;
  
  // *********************************************************************
  // * Walk through the list of rsvcDataEntry objects until a matching
  // * tag is found, or until no more items are available.  
  // *********************************************************************
  for(result=entries; 
      result!=0 && strcmp (result->tag_, tag) != 0;
      prev=result, result = result->next_);

  if(result!=0)
    {
      if(prev!=0) prev->next_ = result->next_;
      else           entries     = result->next_;
      delete result;
    }
}

// *********************************************************************
// * changeTag:
// * 	Replace a new tag with the old one within the
// *	rsvcData object. If the old one can not be not found,
// *	RSVC_NOTFOUND is returned. If the new tag has already
// *    been found in that rsvcData object, RSVC_ERROR is returned.
// *********************************************************************
int rsvcData::changeTag(char* oldTag, char* newTag)
{
  int result;
  rsvcDataEntry *entry;
  if((entry=lookupTag(oldTag)) == 0) result = RSVC_NOTFOUND;
  else {
    if( lookupTag(newTag) != 0) result = RSVC_ERROR;
    else {
      rsvcStrncpy (entry->tag_, newTag, RSVC_TAG_MAX_LEN);
      result = RSVC_SUCCESS;
    }
  }
  return result;
}

// *********************************************************************
// * dupWithTag:
// * 	copy data with tag 'old_tag' to tag 'new_tag'. 
// *	rsvcData object. If the old one can not be not found,
// *	RSVC_NOTFOUND is returned. If the new tag has already
// *    been found in that rsvcData object, RSVC_ERROR is returned.
// *********************************************************************
int rsvcData::dupWithTag (char* old_tag, char* new_tag)
{
  int result;
  rsvcDataEntry* entry;
  rsvcDataEntry* newentry;
  
  if ((entry = lookupTag (old_tag)) == 0) 
    result = RSVC_NOTFOUND;
  else {
    if (lookupTag (new_tag) != 0)
      result = RSVC_ERROR;
    else {
      newentry = new rsvcDataEntry (*entry);
      rsvcStrncpy (newentry->tag_, new_tag, RSVC_TAG_MAX_LEN);
      // now put this entry into the list
      newentry->next_ = entries;
      entries = newentry;
      result = RSVC_SUCCESS;
    }
  }
  return result;
}

// *****************************************************************************
// * getType:
// * 	Retrieves the rsvcDataTypes of the referenced tagged data item.
// *	If no item with that tag is within the rsvcData object, then
// *	RSVC_INVALID is returned.
// *****************************************************************************
rsvcDataTypes rsvcData::getType(char* tag)
{
  rsvcDataEntry * entry = lookupTag(tag);
  return entry==0?RSVC_INVALID:entry->dataType_;
}

// *****************************************************************************
// * getDim:
// *	Obtains the number of dimensions in the specified tagged data
// *	item.  Returns RSVC_SUCCESS if the tagged item exists, otherwise,
// *	RSVC_NOTFOUND is returned.
// *****************************************************************************
int rsvcData::getDim(char* tag, size_t *dim) 
{
  rsvcDataEntry * entry = lookupTag(tag);
  *dim = entry==0?0:entry->dim_;
  return entry==0?RSVC_NOTFOUND:RSVC_SUCCESS;
}

// *****************************************************************************
// * getElems:
// *	Obtains the number of elements in the specified tagged data
// *	item.  Returns RSVC_SUCCESS if the tagged item exists, otherwise,
// *	RSVC_NOTFOUND is returned.
// *****************************************************************************
int rsvcData::getElems(char* tag, size_t *elems)
{
  rsvcDataEntry * entry = lookupTag(tag);
  *elems = entry==0?0:(entry->dim_>0?entry->elems_:1);
  return entry==0?RSVC_NOTFOUND:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar character value into a rsvcDataEntry
// *	object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, BYTE data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_BYTE, sizeof(char), 1, 0))!=0) 
    { 
      entry->data_.cval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}


// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar short int value into a rsvcDataEntry
// *	object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, short data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_INT16, sizeof(short), 1, 0))!=0) 
    { 
      entry->data_.sval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar unsigned short int value into a 
// *	rsvcDataEntry object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, unsigned short data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_UINT16, sizeof(unsigned short), 1, 0))!=0) 
    { 
      entry->data_.usval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}


// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar long int value into a rsvcDataEntry
// *	object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, int data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_INT32, sizeof(long), 1, 0))!=0) 
    { 
      entry->data_.lval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar unsigned long int value into a 
// *	rsvcDataEntry object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, unsigned int data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_UINT32, sizeof(long), 1, 0))!=0) 
    { 
      entry->data_.ulval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar long int value into a rsvcDataEntry
// *	object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, long data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_INT32, sizeof(long), 1, 0))!=0) 
    { 
      entry->data_.lval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar unsigned long int value into a 
// *	rsvcDataEntry object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, unsigned long data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_UINT32, sizeof(long), 1, 0))!=0) 
    { 
      entry->data_.ulval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar float value into a rsvcDataEntry
// *	object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, float data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_FLOAT, sizeof(float), 1, 0))!=0) 
    { 
      entry->data_.fval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a scalar double value into a rsvcDataEntry
// *	object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert(char* tag, double data) 
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_DOUBLE, sizeof(double), 1, 0))!=0) 
    { 
      entry->data_.dval= data; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a time stamp value into a rsvcDataEntry
// *	object as a tagged data item.  
// *****************************************************************************
int rsvcData::insert ( char* tag, rsvc_TS_STAMP data )
{
  rsvcDataEntry * entry;

  if((entry = setupTag(tag, RSVC_TIMESTAMP, sizeof(rsvc_TS_STAMP), 1, 0))!=0) 
    { 
      entry->data_.ts.secPastEpoch = data.secPastEpoch; 
      entry->data_.ts.nsec = data.nsec; 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}


// *****************************************************************************
// * insert:
// *	The following function allows the insertion of characters arrays of data
// *	into a rsvcData object.  The len variable contains the total number of 
// *	elements to be inserted, the ndim variable indicates the number of 
// *	dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, BYTE * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_BYTE, sizeof(char), len, ndim))!=0) 
    { 
      memcpy(entry->data_.cptr, data, len*sizeof(char)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of short int arrays of data
// *	into a rsvcData object.  The len variable contains the total number of 
// *	elements to be inserted, the ndim variable indicates the number of 
// *	dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, short * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_INT16, sizeof(short), len, ndim))!=0) 
    { 
      memcpy(entry->data_.sptr, data, len*sizeof(short)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of unsigned short int arrays 
// *	of data into a rsvcData object.  The len variable contains the total 
// *	number of elements to be inserted, the ndim variable indicates the 
// *	number of dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, unsigned short * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_UINT16, sizeof(unsigned short), len, ndim))!=0) 
    { 
      memcpy(entry->data_.usptr, data, len*sizeof(unsigned short)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}


// *****************************************************************************
// * insert:
// *	The following function allows the insertion of long int arrays of data
// *	into a rsvcData object.  The len variable contains the total number of 
// *	elements to be inserted, the ndim variable indicates the number of 
// *	dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, int * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_INT32, sizeof(long), len, ndim))!=0) 
    { 
      memcpy(entry->data_.lptr, data, len*sizeof(long)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of unsigned long int arrays 
// *	of data into a rsvcData object.  The len variable contains the total 
// *	number of elements to be inserted, the ndim variable indicates the 
// *	number of dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, unsigned int * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_UINT32, sizeof(unsigned long), len, ndim))!=0) 
    { 
      memcpy(entry->data_.ulptr, data, len*sizeof(unsigned long)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}


// *****************************************************************************
// * insert:
// *	The following function allows the insertion of long int arrays of data
// *	into a rsvcData object.  The len variable contains the total number of 
// *	elements to be inserted, the ndim variable indicates the number of 
// *	dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, long * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_INT32, sizeof(long), len, ndim))!=0) 
    { 
      memcpy(entry->data_.lptr, data, len*sizeof(long)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of unsigned long int arrays 
// *	of data into a rsvcData object.  The len variable contains the total 
// *	number of elements to be inserted, the ndim variable indicates the 
// *	number of dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, unsigned long * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_UINT32, sizeof(unsigned long), len, ndim))!=0) 
    { 
      memcpy(entry->data_.ulptr, data, len*sizeof(unsigned long)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of float arrays of data
// *	into a rsvcData object.  The len variable contains the total number of 
// *	elements to be inserted, the ndim variable indicates the number of 
// *	dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, float * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_FLOAT, sizeof(float), len, ndim))!=0) 
    { 
      memcpy(entry->data_.fptr, data, len*sizeof(float)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of double arrays of data
// *	into a rsvcData object.  The len variable contains the total number of 
// *	elements to be inserted, the ndim variable indicates the number of 
// *	dimensions in the array.
// *****************************************************************************
int rsvcData::insert (char* tag, double * data, size_t len, size_t ndim)
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_DOUBLE, sizeof(double), len, ndim))!=0) 
    { 
      memcpy(entry->data_.dptr, data, len*sizeof(double)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of a character string into
// *	a rsvcData object.  The length of the string is calculated using the
// *	strlen function.  It is important to note, that although this data item
// *	uses the array_ block within the rsvcDataEntry object, it has no 
// *	rsvcBounds information associated with it.
// *****************************************************************************
int rsvcData::insert (char* tag, char * data )
{
  rsvcDataEntry * entry;
  int result = RSVC_ERROR;
  int len    = data!=0?strlen(data)+1:0;
  
  if(len>0 && (entry = lookupTag(tag, 1))!=0) {
    // *************************************************************
    // * Allocate a new data block for storing the character string.
    // * Note that the number of dimensions will be zero, but the
    // * array_ element within the rsvcDataEntry object will still
    // * be used.
    // *************************************************************
    entry->allocate(0, len, sizeof(char));

    // *************************************************************
    // * Populate the entry with the new data.
    // *************************************************************
    rsvcStrncpy (entry->tag_, tag, RSVC_TAG_MAX_LEN);
    entry->dataType_ = RSVC_STRING;
    memcpy(entry->data_.str, data, len);
    result = RSVC_SUCCESS;
  }	
  return result;
}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of an array of character
// *	strings.  Unlike the individual character string, this data may have
// *	rsvcBounds data associated within it.
// *****************************************************************************
int rsvcData::insert (char* tag, char ** data, size_t len, size_t ndim )
{
  int result = RSVC_SUCCESS;
  rsvcDataEntry * entry;

  // *********************************************************************
  // * If the user specified len is invalid (or 0 by default), walk 
  // * through the array of pointers until 0 is found.
  // *********************************************************************
  if(len<=0) for(len=0; data && data[len]!=0; len++);
  if(len==0) result = RSVC_INVALIDARG;
  else if(len==1) result = insert(tag, *data);
  else
    {
      int    i;
      size_t dataLen = 0;

      // *************************************************************
      // * To determine the data space needed to store an array of
      // * character strings, the function must calculate the length
      // * of each character string (plus one for the 0 terminator),
      // * then add in the space necessary to store the pointers.
      // *************************************************************
      for(i=0; i<len; i++) dataLen += strlen(data[i])+1;
      dataLen += (len+1)*sizeof(char *);
      
      // *************************************************************
      // * Populate the rsvcDataEntry with the user specified strings.
      // *************************************************************
      if((entry = setupTag(tag, RSVC_STRING, sizeof(char), dataLen, ndim))!=0)
	{
	  // *****************************************************
	  // * Immediately following the setupTag call, the bounds
	  // * member of the rsvcDataEntry object will contain
	  // * the dataLen value (total bytes) rather than the
	  // * len value (total strings).  Correct this problem
	  // * before continuing.
	  // *****************************************************
	  entry->elems_             = len;
	  entry->bytes_             = 4;
	  
	  // *****************************************************
	  // * Set the pointer within the string array to point
	  // * to the extra memory allocated at the end of the
	  // * entry->data_.strarr block.  Then copy the new data
	  // * into the string array.
	  // *****************************************************
	  char ** ptr = entry->data_.strarr;
	  ptr[0]      = (char *)(&entry->data_.strarr[len+1]);
	  strcpy(ptr[0], data[0]);
	  for(i=1; i<len; i++)
	    {
	      ptr[i] = ptr[i-1]+strlen(ptr[i-1])+1;
	      strcpy(ptr[i], data[i]);
	    }
	  ptr[len]=0;
	}
      else result = RSVC_ERROR;
    }
  return result;
}


// *****************************************************************************
// * insert:
// *	The following function allows the insertion of a time_stamp arrays of 
// *	data into a rsvcData object.  The len variable contains the total number 
// *	of elements to be inserted, the ndim variable indicates the number of 
// *	dimensions in the array. 
// *****************************************************************************
int rsvcData::insert (char* tag, rsvc_TS_STAMP *data, size_t len, size_t ndim )
{
  rsvcDataEntry * entry;

  if(len==1 && data!=0)       return insert(tag, *data);
  else if(len<=0 || data==0)  return RSVC_INVALIDARG;
  else if((entry = setupTag(tag, RSVC_TIMESTAMP, sizeof(rsvc_TS_STAMP), len, ndim))!=0) 
    { 
      memcpy(entry->data_.tsptr, data, len*sizeof(rsvc_TS_STAMP)); 
    }
  return (entry==0)?RSVC_ERROR:RSVC_SUCCESS;
}


// *****************************************************************************
// * get:
// *	This function retrieves a character value specified by tag from the
// *	rsvcData object.  This value may be either scalar or an array.  If the
// *	data is an array, the user must have preallocated sufficient space to
// *	store the data.
// *****************************************************************************
int rsvcData::get(char* tag, BYTE * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_BYTE]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_BYTE]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}

// *****************************************************************************
// * get:
// *	This function retrieves an short integer value specified by tag from the
// *	rsvcData object.  This value may be either scalar or an array.  If the
// *	data is an array, the user must have preallocated sufficient space to
// *	store the data.
// *****************************************************************************
int rsvcData::get(char* tag, short * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_INT16]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_INT16]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}

// *****************************************************************************
// * get:
// *	This function retrieves an unsigned short integer value specified by tag 
// *	from the rsvcData object.  This value may be either scalar or an array.  
// *	If the data is an array, the user must have preallocated sufficient 
// *	space to store the data.
// *****************************************************************************
int rsvcData::get(char* tag, unsigned short * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_UINT16]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_UINT16]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}

// *****************************************************************************
// * get:
// *	This function retrieves an long integer value specified by tag from the
// *	rsvcData object.  This value may be either scalar or an array.  If the
// *	data is an array, the user must have preallocated sufficient space to
// *	store the data.
// *****************************************************************************
int rsvcData::get(char* tag, int * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_INT32]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_INT32]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}

// *****************************************************************************
// * get:
// *	This function retrieves an unsigned long integer value specified by tag 
// *	from the rsvcData object.  This value may be either scalar or an array.  
// *	If the data is an array, the user must have preallocated sufficient 
// *	space to store the data.
// *****************************************************************************
int rsvcData::get(char* tag, unsigned int * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_UINT32]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_UINT32]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}


// *****************************************************************************
// * get:
// *	This function retrieves an long integer value specified by tag from the
// *	rsvcData object.  This value may be either scalar or an array.  If the
// *	data is an array, the user must have preallocated sufficient space to
// *	store the data.
// *****************************************************************************
int rsvcData::get(char* tag, long * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_INT32]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_INT32]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}

// *****************************************************************************
// * get:
// *	This function retrieves an unsigned long integer value specified by tag 
// *	from the rsvcData object.  This value may be either scalar or an array.  
// *	If the data is an array, the user must have preallocated sufficient 
// *	space to store the data.
// *****************************************************************************
int rsvcData::get(char* tag, unsigned long * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_UINT32]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_UINT32]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}

// *****************************************************************************
// * get:
// *	This function retrieves a floating point value specified by tag from the
// *	rsvcData object.  This value may be either scalar or an array.  If the
// *	data is an array, the user must have preallocated sufficient space to
// *	store the data.
// *****************************************************************************
int rsvcData::get(char* tag, float * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_FLOAT]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_FLOAT]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}


// *****************************************************************************
// * get:
// *	This function retrieves a double float value specified by tag from the
// *	rsvcData object.  This value may be either scalar or an array.  If the
// *	data is an array, the user must have preallocated sufficient space to
// *	store the data.
// *****************************************************************************
int rsvcData::get(char* tag, double * data) 
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_DOUBLE]
	(entry->data_.vptr, data, entry->elems_);
    else	rsvcConversionMatrix[entry->dataType_][RSVC_DOUBLE]
      (&entry->data_, data, 1);

    result = RSVC_SUCCESS;
  }
  return result;
}

// *****************************************************************************
// * get:
// *	This function retrieves a time stamp value specified by tag from the
// *	rsvcData object. 
// *****************************************************************************
int rsvcData::get(char* tag, rsvc_TS_STAMP * data) 
{
  int result;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else	{
    if(entry->dim_ > 0)
      rsvcConversionMatrix[entry->dataType_][RSVC_TIMESTAMP]
    	(entry->data_.vptr, data, entry->elems_);
    else 
      rsvcConversionMatrix[entry->dataType_][RSVC_TIMESTAMP]
        (&entry->data_, data, 1);
    result = RSVC_SUCCESS;
  }
  return result;
}


// *****************************************************************************
// * get:
// *	This function retrieves a char string value specified by tag from the
// *	rsvcData object.  For simplicity, this method operates differently
// *	than the other get methods.
// *****************************************************************************
int rsvcData::get(char* tag, char * data, size_t len) 
{
  int nelem = 1, result = RSVC_NOTFOUND;
  rsvcDataEntry * entry;
  if(data!=0 && (entry=lookupTag(tag, 0))!=0) 
    {
      if(entry->dim_ > 0)nelem = entry->elems_;

      switch(entry->dataType_)
	{
	case RSVC_BYTE:
	  if(nelem==1) sprintf(data, "%.*s", len, ltoa(entry->data_.cval));
	  else sprintf(data, "%.*s", len, ltoa(*entry->data_.str));
	  break;
	case RSVC_INT16:
	  if(nelem==1) sprintf(data, "%.*s", len, ltoa(entry->data_.sval));
	  else sprintf(data, "%.*s", len, ltoa(*entry->data_.sptr));
	  break;
	case RSVC_UINT16:
	  if(nelem==1) sprintf(data, "%.*s", len, ultoa(entry->data_.usval));
	  else sprintf(data, "%.*s", len, ultoa(*entry->data_.usptr));
	  break;
	case RSVC_INT32:
	  if(nelem==1) sprintf(data, "%.*s", len, ltoa(entry->data_.lval));
	  else sprintf(data, "%.*s", len, ltoa(*entry->data_.lptr));
	  break;
	case RSVC_UINT32:
	  if(nelem==1) sprintf(data, "%.*s", len, ultoa(entry->data_.ulval));
	  else sprintf(data, "%.*s", len, ultoa(*entry->data_.ulptr));
	  break;
	case RSVC_FLOAT:
	  if(nelem==1) rsvc_gcvt(entry->data_.fval, len, data);
	  else rsvc_gcvt(*entry->data_.fptr, len, data);
	  break;
	case RSVC_DOUBLE:
	  if(nelem==1) rsvc_gcvt(entry->data_.dval, len, data);
	  else rsvc_gcvt(*entry->data_.dptr, len, data);
	  break;		
	case RSVC_STRING:
	  if(nelem==1) rsvcStrncpy(data, entry->data_.str, len);
	  else rsvcStrncpy(data, entry->data_.strarr[0], len);
	  data[len-1] = 0;
	  break;
	case RSVC_TIMESTAMP:
	  if(nelem==1) 
	    rsvcStrncpy(data, ctime((time_t *)&(entry->data_.ts.secPastEpoch)), len);
	  data[len-1] = 0;
	  break;

	default:
	  break;
	}		
      result = RSVC_SUCCESS;
    }
  return result;
}

// *****************************************************************************
// * get:
// *	This function retrieves a char string array specified by tag from the
// *	rsvcData object.  For simplicity, this method operates differently
// *	than the other get methods.
// *****************************************************************************
int rsvcData::get(char* tag, char ** data)
{
  int result, nelem=1;
  rsvcDataEntry * entry;
  
  if(data==0) result = RSVC_INVALIDARG;
  else if((entry=lookupTag(tag, 0))==0) result = RSVC_NOTFOUND;
  else
    {
      if(entry->dim_ > 0)
	rsvcConversionMatrix[entry->dataType_][RSVC_STRING]
	  (entry->data_.vptr, data, entry->elems_);
      else	rsvcConversionMatrix[entry->dataType_][RSVC_STRING]
	(&entry->data_, data, 1);

      result = RSVC_SUCCESS;
    }
  return result;
}

// *****************************************************************************
// * find:
// *	Allows the user to directly extract a pointer to the internal data
// *	buffer that the rsvcDataEntry object uses to store data.
// *****************************************************************************
int rsvcData::find(char* tag, void* &data) 
{
  int result = RSVC_NOTFOUND;
  rsvcDataEntry * entry;
  if((entry=lookupTag(tag, 0))!=0) 
    {
      if(entry->dim_>0 || entry->dataType_==RSVC_STRING) data = entry->data_.vptr;
      else data = &entry->data_;
      result = RSVC_SUCCESS;
    }	
  else data = 0;
  return result;
}

// *********************************************************************
// * replace:
// *  This function allows part or all taged values being replaced
// *  by other taged values represented by a rsvcData
// *********************************************************************  
int 
rsvcData::replace (const rsvcData& data)
{
  void* dptr = 0;
  int   found = 0;
  for(rsvcDataEntry *ptr = data.entries; ptr!=0; ptr = ptr->next_) {
    if (find (ptr->tag_, dptr) == RSVC_SUCCESS) {
      found = 1;
      remove (ptr->tag_);
      switch(ptr->dataType_) {
      case RSVC_BYTE:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.cval);
	else insert(ptr->tag_, ptr->data_.cptr, ptr->elems_, ptr->dim_);
	break;
	  
      case RSVC_INT16:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.sval);
	else insert(ptr->tag_, ptr->data_.sptr, ptr->elems_, ptr->dim_);
	break;

      case RSVC_UINT16:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.usval);
	else insert(ptr->tag_, ptr->data_.usptr, ptr->elems_, ptr->dim_);
	break;
      
      case RSVC_INT32:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.lval);
	else insert(ptr->tag_, ptr->data_.lptr, ptr->elems_, ptr->dim_);
	break;
	
      case RSVC_UINT32:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.ulval);
	else insert(ptr->tag_, ptr->data_.ulptr, ptr->elems_, ptr->dim_);
	break;
      
      case RSVC_FLOAT:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.fval);
	else insert(ptr->tag_, ptr->data_.fptr, ptr->elems_, ptr->dim_);
	break;

      case RSVC_DOUBLE:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.dval);
	else insert(ptr->tag_, ptr->data_.dptr, ptr->elems_, ptr->dim_);
	break;
	  
      case RSVC_STRING:
	if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.str);
	else insert(ptr->tag_, ptr->data_.strarr, ptr->elems_, ptr->dim_);
	break;

      case RSVC_TIMESTAMP:
	if (ptr->dim_==0) insert(ptr->tag_, ptr->data_.ts);
	else insert(ptr->tag_, ptr->data_.tsptr, ptr->elems_, ptr->dim_);	  
	break;

      default:
	break;
      }
    }
  }
  if (found)
    return RSVC_SUCCESS;
  return RSVC_ERROR;
}  


// *****************************************************************************
// * operator == :
// *	This method will allow the caller to rapidly determine if two rsvcData
// *	objects contain identical fields and values...
// *
// *	In the first step, the method will count the total number of fields in
// *	both objects...  if they are not equal an error will be returned...
// *
// *	Next the method will begin getting pointers to the rsvcDataEntry objects
// *	that are stored in each object and will use their embedded comparison
// *	operators to compare the contents of each of them.
// *****************************************************************************
int rsvcData::operator == ( rsvcData & data )
{
  int result = 1;
  rsvcDataEntry *entry1, *entry2;
  int entry1Cnt=0, entry2Cnt=0;
  
  for(entry1=entries; entry1!=0; entry1=entry1->next_) entry1Cnt++;
  for(entry2=data.entries; entry2!=0; entry2=entry2->next_) entry2Cnt++;
  if(entry1Cnt==entry2Cnt)
    {
      result = 0;
      for(entry1=entries; !result && entry1!=0; entry1=entry1->next_)
	{
	  if((entry2 = data.lookupTag(entry1->tag_))!=0)
	    {
	      result = !(entry1->operator == (*entry2));
	    }
	  else result = -1;
	}
    }
  return !result;
}

// *****************************************************************************
// * Assignment  operation:
// * This operation will reassign data object to another object
// *****************************************************************************
rsvcData&
rsvcData::operator = (const rsvcData& data)
{
  return copy (data);
}

// *****************************************************************************
// * Append operation:
// * This operation will append a rsvcData onto an existing rsvcData
// * and return this object. If there is confilicts among tags, the
// * appended one wins
// *****************************************************************************
rsvcData& 
rsvcData::operator += (const rsvcData& data)
{
  for(rsvcDataEntry *ptr = data.entries; ptr!=0; ptr = ptr->next_) {
    switch(ptr->dataType_) {
    case RSVC_BYTE:
      if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.cval);
      else insert(ptr->tag_, ptr->data_.cptr, ptr->elems_, ptr->dim_);
      break;
	  
    case RSVC_INT16:
      if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.sval);
      else insert(ptr->tag_, ptr->data_.sptr, ptr->elems_, ptr->dim_);
      break;

    case RSVC_UINT16:
      if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.usval);
      else insert(ptr->tag_, ptr->data_.usptr, ptr->elems_, ptr->dim_);
      break;
      
    case RSVC_INT32:
      if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.lval);
      else insert(ptr->tag_, ptr->data_.lptr, ptr->elems_, ptr->dim_);
      break;

    case RSVC_UINT32:
      if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.ulval);
      else insert(ptr->tag_, ptr->data_.ulptr, ptr->elems_, ptr->dim_);
      break;
      
    case RSVC_FLOAT:
      if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.fval);
      else insert(ptr->tag_, ptr->data_.fptr, ptr->elems_, ptr->dim_);
      break;

    case RSVC_DOUBLE:
      if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.dval);
      else insert(ptr->tag_, ptr->data_.dptr, ptr->elems_, ptr->dim_);
      break;
	  
    case RSVC_STRING:
      if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.str);
      else insert(ptr->tag_, ptr->data_.strarr, ptr->elems_, ptr->dim_);
      break;

    case RSVC_TIMESTAMP:
      if (ptr->dim_==0) insert(ptr->tag_, ptr->data_.ts);
      else insert(ptr->tag_, ptr->data_.tsptr, ptr->elems_, ptr->dim_);	  
      break;

    default:
      break;
    }
  }
  return *this;
}
  

// *****************************************************************************
// * rsvc Conversion Utilities
// *	These functions are incorporated into the rsvcConversionMatrix and are
// *	used to convert between rsvcDataTypes.  Because these functions are 
// *	defined for use specifically within the rsvcData object, they are not
// *	declared in the header file and should not be used by external modules
// *	or applications.
// *
// *	All rsvc function sthat use these utilities should access them through
// *	the rsvcConversionMatrix array as described at the beginning of this
// *	file.
// *****************************************************************************

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_BYTE ( void * input, void * output, size_t nElems )
{
  memcpy(output, input, nElems*sizeof(char));
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_INT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((short *)output)[nElems] = (short)((BYTE *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_UINT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned short *)output)[nElems] = (unsigned short)((BYTE *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_INT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((long *)output)[nElems]  = (long)((BYTE *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_UINT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned long *)output)[nElems]  = (unsigned long)((BYTE *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to Float Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_FLOAT ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((float *)output)[nElems] = (float)((BYTE *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to Double Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_DOUBLE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((double *)output)[nElems] = (double)((BYTE *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_STRING ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((char **)output)[nElems] = new char[strlen(ltoa(((BYTE *)input)[nElems]))+1];
    strcpy(((char **)output)[nElems], ltoa(((BYTE *)input)[nElems]));
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to Timestamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_BYTE_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch = (unsigned long)((BYTE *)input)[nElems];
    ((rsvc_TS_STAMP *)output)[nElems].nsec = 0;
  }
  fprintf(stderr, "warning: Byte converts to timestamp struct, data may be invalid\n");
}

// *****************************************************************************
// * rsvcConvert:
// *	8 Bit Integer to Invalid Conversion Facilities... Does nothing
// *****************************************************************************
void rsvcConvert_BYTE_to_INVALID ( void *, void *, size_t )
{
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_BYTE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((char *)output)[nElems] = (char)((short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_INT16 ( void * input, void * output, size_t nElems )
{
  memcpy(output, input, nElems*sizeof(short));
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_UINT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((unsigned short *)output)[nElems]  = (unsigned short)((short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_INT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((long *)output)[nElems]  = (long)((short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_UINT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((unsigned long *)output)[nElems]  = (unsigned long)((short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to Float Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_FLOAT ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((float *)output)[nElems] = (float)((short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to Double Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_DOUBLE ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((double *)output)[nElems] = (double)((short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_STRING ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((char **)output)[nElems] = new char[strlen(ltoa(((short *)input)[nElems]))+1];
    strcpy(((char **)output)[nElems], ltoa(((short *)input)[nElems]));
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to Timestamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT16_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch = (unsigned long)((short *)input)[nElems];
    ((rsvc_TS_STAMP *)output)[nElems].nsec = 0;
  }
  fprintf(stderr, "warning: INT16 converts to timestamp struct, data may be invalid\n");
}

// *****************************************************************************
// * rsvcConvert:
// *	16 Bit Integer to Invalid Conversion Facilities... Does Nothing
// *****************************************************************************
void rsvcConvert_INT16_to_INVALID ( void *, void *, size_t )
{
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_BYTE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((char *)output)[nElems] = (char)((unsigned short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_INT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((short *)output)[nElems]  = (unsigned short)((unsigned short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_UINT16 ( void * input, void * output, size_t nElems )
{
  memcpy(output, input, nElems*sizeof(unsigned short));
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_INT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((long *)output)[nElems]  = (long)((unsigned short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_UINT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((unsigned long *)output)[nElems]  = (unsigned long)((unsigned short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to Float Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_FLOAT ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((float *)output)[nElems] = (float)((unsigned short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to Double Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_DOUBLE ( void * input, void * output, size_t nElems )
{
  while(nElems>0){
    nElems--; ((double *)output)[nElems] = (double)((unsigned short *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_STRING ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((char **)output)[nElems] = new char[strlen(ultoa(((unsigned short *)input)[nElems]))+1];
    strcpy(((char **)output)[nElems], ultoa(((unsigned short *)input)[nElems]));
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to Timestamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT16_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch=(unsigned long)((unsigned short *)input)[nElems];
    ((rsvc_TS_STAMP *)output)[nElems].nsec = 0;
  }
  fprintf(stderr, "warning: UINT16 converts to timestamp struct, data may be invalid\n");
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 16 Bit Integer to Invalid Conversion Facilities... Does Nothing
// *****************************************************************************
void rsvcConvert_UINT16_to_INVALID ( void *, void *, size_t )
{
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_BYTE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((char *)output)[nElems] = (char)((long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_INT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((short *)output)[nElems]  = (short)((long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_UINT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned short *)output)[nElems]  = (unsigned short)((long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_INT32 ( void * input, void * output, size_t nElems )
{
  memcpy(output, input, nElems*sizeof(long));
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_UINT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned long *)output)[nElems]  = (unsigned long)((long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to Float Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_FLOAT ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((float *)output)[nElems] = (float)((long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to Double Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_DOUBLE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((double *)output)[nElems] = (double)((long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_STRING ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((char **)output)[nElems] = new char[strlen(ltoa(((long *)input)[nElems]))+1];
    strcpy(((char **)output)[nElems], ltoa(((long *)input)[nElems]));
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to Timestamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_INT32_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch=(unsigned long)((long *)input)[nElems];
    ((rsvc_TS_STAMP *)output)[nElems].nsec = 0;
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	32 Bit Integer to Invalid Conversion Facilities... Does Nothing
// *****************************************************************************
void rsvcConvert_INT32_to_INVALID ( void *, void *, size_t )
{
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_BYTE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((char *)output)[nElems] = (char)((unsigned long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_INT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((short *)output)[nElems]  = (short)((unsigned long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_UINT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned short *)output)[nElems]  = (unsigned short)((unsigned long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_INT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((long *)output)[nElems]  = (unsigned long)((unsigned long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_UINT32 ( void * input, void * output, size_t nElems )
{
  memcpy(output, input, nElems*sizeof(unsigned long));
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to Float Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_FLOAT ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((float *)output)[nElems] = (float)((unsigned long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to Double Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_DOUBLE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((double *)output)[nElems] = (double)((unsigned long *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_STRING ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((char **)output)[nElems] = new char[strlen(ultoa(((unsigned long *)input)[nElems]))+1];
    strcpy(((char **)output)[nElems], ultoa(((unsigned long *)input)[nElems]));
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to Timestamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_UINT32_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch=((unsigned long *)input)[nElems];
    ((rsvc_TS_STAMP *)output)[nElems].nsec = 0;
  }
}


// *****************************************************************************
// * rsvcConvert:
// *	Unsigned 32 Bit Integer to Invalid Conversion Facilities... Does Nothing
// *****************************************************************************
void rsvcConvert_UINT32_to_INVALID ( void *, void *, size_t )
{
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_BYTE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((char *)output)[nElems] = (char)((float *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_INT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((short *)output)[nElems]  = (short)((float *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_UINT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned short *)output)[nElems]  = (unsigned short)((float *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_INT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((long *)output)[nElems] = (long)((float *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_UINT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned long *)output)[nElems] = (unsigned long)((float *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to Float Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_FLOAT ( void * input, void * output, size_t nElems )
{
  memcpy(output, input, nElems*sizeof(float));
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to Double Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_DOUBLE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((double *)output)[nElems] = (double)((float *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to String Array Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_STRING ( void * input, void * output, size_t nElems )
{
  char buf[32];
  while(nElems>0) {
    nElems--;
    rsvcData::rsvc_gcvt(((float *)input)[nElems], (size_t)32, buf);
    ((char **)output)[nElems] = new char[strlen(buf)+1];
    strcpy(((char **)output)[nElems], buf);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	 Floating Point to Timestamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_FLOAT_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch=(unsigned long)((float *)input)[nElems];
    ((rsvc_TS_STAMP *)output)[nElems].nsec =
      (unsigned long)(((float)((float *)input)[nElems]-(unsigned long)((float *)input)[nElems])*1000000000);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Floating Point to Invalid  Conversion Facilities... Does Nothing
// *****************************************************************************
void rsvcConvert_FLOAT_to_INVALID ( void *, void *, size_t )
{
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_BYTE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((char *)output)[nElems] = (char)((double *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_INT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((short *)output)[nElems]  = (short)((double *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_UINT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned short *)output)[nElems]  = (unsigned short)((double *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_INT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((long *)output)[nElems] = (long)((double *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_UINT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned long *)output)[nElems] = (unsigned long)((double *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to Float Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_FLOAT ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((float *)output)[nElems] = (float)((double *)input)[nElems];
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to Double Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_DOUBLE ( void * input, void * output, size_t nElems )
{
  memcpy(output, input, nElems*sizeof(double));
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to String Array Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_STRING ( void * input, void * output, size_t nElems )
{
  char buf[32];
  while(nElems>0) {
    nElems--;
    rsvcData::rsvc_gcvt(((double *)input)[nElems], 32, buf);
    ((char **)output)[nElems] = new char[strlen(buf)+1];
    strcpy(((char **)output)[nElems], buf);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	 Double Floating Point to Timestamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_DOUBLE_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch=
      (unsigned long)((double *)input)[nElems];
    ((rsvc_TS_STAMP *)output)[nElems].nsec = 
      (unsigned long)(((double)((double *)input)[nElems]-(unsigned long)((double *)input)[nElems])*1000000000);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Double Floating Point to Invalid Conversion Facilities... Does Nothing
// *****************************************************************************
void rsvcConvert_DOUBLE_to_INVALID ( void *, void *, size_t )
{
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_BYTE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((char *)output)[nElems] = (char)atof(((char **)input)[nElems]);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_INT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((short *)output)[nElems] = (short)atof(((char **)input)[nElems]);
  }
  
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_UINT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned short *)output)[nElems] = (unsigned short)atof(((char **)input)[nElems]);
  }
  
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_INT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((long *)output)[nElems] = (long)atof(((char **)input)[nElems]);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_UINT32 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((unsigned long *)output)[nElems] = (unsigned long)atof(((char **)input)[nElems]);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to Float Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_FLOAT ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((float *)output)[nElems] = (float)atof(((char **)input)[nElems]);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to Double Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_DOUBLE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; ((double *)output)[nElems] = (double)atof(((char **)input)[nElems]);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to String Array Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_STRING ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((char **)output)[nElems] = new char[strlen(((char **)input)[nElems])+1];
    strcpy(((char **)output)[nElems], ((char **)input)[nElems]);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to Timestamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_STRING_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    double tmp = atof(((char **)input)[nElems]);
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch=(unsigned long)tmp;
    ((rsvc_TS_STAMP *)output)[nElems].nsec =(unsigned long)((tmp-(unsigned long)tmp)*1000000000);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	String Array to Invalid Conversion Facilities... Does Nothing
// *****************************************************************************
void rsvcConvert_STRING_to_INVALID ( void *, void *, size_t )
{
}


// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_BYTE ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((char *)output)[nElems] = (char)(((rsvc_TS_STAMP *)input)[nElems].secPastEpoch);
  }
  fprintf(stderr, "warning: Timestamp struct converts to Byte, data may be invalid\n");
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_INT16 ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((short *)output)[nElems] = (short)(((rsvc_TS_STAMP *)input)[nElems].secPastEpoch);
  }
  fprintf(stderr, "warning: Timestamp struct converts to INT16, data may be invalid\n");
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_UINT16 ( void * input, void * output, size_t nElems )
{      
  while(nElems>0) {
    nElems--; 
    ((unsigned short *)output)[nElems]=
      (unsigned short)(((rsvc_TS_STAMP *)input)[nElems].secPastEpoch);
  }
  fprintf(stderr, "warning: Timestamp struct converts to UINT16, data may be invalid\n");
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_INT32 ( void * input, void * output, size_t nElems )
{      
  while(nElems>0) {
    nElems--; 
    ((long *)output)[nElems]=
      (long)(((rsvc_TS_STAMP *)input)[nElems].secPastEpoch);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to Unsigned 32 Bit Integer Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_UINT32 ( void * input, void * output, size_t nElems )
{      
  while(nElems>0) {
    nElems--; 
    ((unsigned long *)output)[nElems]=
      ((rsvc_TS_STAMP *)input)[nElems].secPastEpoch;
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to Floating Point Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_FLOAT ( void * input, void * output, size_t nElems )
{      
  while(nElems>0) {
    nElems--; 
    ((float *)output)[nElems]=
      (float)(((rsvc_TS_STAMP *)input)[nElems].secPastEpoch+
	      ((rsvc_TS_STAMP *)input)[nElems].nsec/1000000000.);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to Doouble Floating Point Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_DOUBLE ( void * input, void * output, size_t nElems )
{      
  while(nElems>0) {
    nElems--; 
    ((double *)output)[nElems]=
      (double)(((rsvc_TS_STAMP *)input)[nElems].secPastEpoch+
	       ((rsvc_TS_STAMP *)input)[nElems].nsec/1000000000.);
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to Char String Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_STRING ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((char **)output)[nElems] = new char[30];
    strcpy( ((char **)output)[nElems], 
	   ctime((time_t *)(&(((rsvc_TS_STAMP *)input)[nElems].secPastEpoch))) );
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to Time Stamp Conversion Facilities
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_TIMESTAMP ( void * input, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch =
      ((rsvc_TS_STAMP *)input)[nElems].secPastEpoch;
    ((rsvc_TS_STAMP *)output)[nElems].nsec =
      ((rsvc_TS_STAMP *)input)[nElems].nsec;
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Time Stamp to Invalid Conversion Facilities...Dose Nothing
// *****************************************************************************
void rsvcConvert_TIMESTAMP_to_INVALID ( void *, void *, size_t )
{
} 

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to 8 Bit Integer Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_BYTE ( void *, void * output, size_t nElems )
{
  memset((char *)output, 0, nElems*sizeof(char));
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to 16 Bit Integer Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_INT16 ( void *, void * output, size_t nElems )
{
  memset((short *)output, 0, nElems*sizeof(short));
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to Unsigned 16 Bit Integer Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_UINT16 ( void *, void * output, size_t nElems )
{
  memset((short *)output, 0, nElems*sizeof(unsigned short));
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to 32 Bit Integer Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_INT32 ( void *, void * output, size_t nElems )
{
  memset((long *)output, 0, nElems*sizeof(long));
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to Unsigned 32 Bit Integer Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_UINT32 ( void *, void * output, size_t nElems )
{
  memset((long *)output, 0, nElems*sizeof(unsigned long));
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to Float Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_FLOAT ( void *, void * output, size_t nElems )
{
  memset((float *)output, 0, nElems*sizeof(float));
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to Double Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_DOUBLE ( void *, void * output, size_t nElems )
{
  memset((double *)output, 0, nElems*sizeof(double));
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to String Array Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_STRING ( void *, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--;
    ((char **)output)[nElems] = 0;
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to Timestamp Conversion Facilities... Clears Output
// *****************************************************************************
void rsvcConvert_INVALID_to_TIMESTAMP ( void *, void * output, size_t nElems )
{
  while(nElems>0) {
    nElems--; 
    ((rsvc_TS_STAMP *)output)[nElems].secPastEpoch=0;
    ((rsvc_TS_STAMP *)output)[nElems].nsec =0;
  }
}

// *****************************************************************************
// * rsvcConvert:
// *	Invalid to Invalid Conversion Facilities... Does Nothing
// *****************************************************************************
void rsvcConvert_INVALID_to_INVALID ( void *, void *, size_t )
{
}


// *****************************************************************************
// * rsvcConversionMatrix:
// *	Instanciation of the conversion matrix defined at the beginning of this
// *	file.
// *****************************************************************************
const rsvcConverter rsvcConversionMatrix [RSVC_INVALID+1][RSVC_INVALID+1] =
{
  {
    rsvcConvert_BYTE_to_BYTE, 
    rsvcConvert_BYTE_to_INT16, 
    rsvcConvert_BYTE_to_UINT16, 
    rsvcConvert_BYTE_to_INT32, 
    rsvcConvert_BYTE_to_UINT32, 
    rsvcConvert_BYTE_to_FLOAT, 
    rsvcConvert_BYTE_to_DOUBLE, 
    rsvcConvert_BYTE_to_STRING, 
    rsvcConvert_BYTE_to_TIMESTAMP,
    rsvcConvert_BYTE_to_INVALID
    },
  {
    rsvcConvert_INT16_to_BYTE, 
    rsvcConvert_INT16_to_INT16, 
    rsvcConvert_INT16_to_UINT16, 
    rsvcConvert_INT16_to_INT32, 
    rsvcConvert_INT16_to_UINT32, 
    rsvcConvert_INT16_to_FLOAT, 
    rsvcConvert_INT16_to_DOUBLE, 
    rsvcConvert_INT16_to_STRING,
    rsvcConvert_INT16_to_TIMESTAMP, 
    rsvcConvert_INT16_to_INVALID,
  },
  {
    rsvcConvert_UINT16_to_BYTE, 
    rsvcConvert_UINT16_to_INT16, 
    rsvcConvert_UINT16_to_UINT16, 
    rsvcConvert_UINT16_to_INT32, 
    rsvcConvert_UINT16_to_UINT32, 
    rsvcConvert_UINT16_to_FLOAT, 
    rsvcConvert_UINT16_to_DOUBLE, 
    rsvcConvert_UINT16_to_STRING,
    rsvcConvert_UINT16_to_TIMESTAMP, 
    rsvcConvert_UINT16_to_INVALID,
  },
  {	
    rsvcConvert_INT32_to_BYTE, 
    rsvcConvert_INT32_to_INT16, 
    rsvcConvert_INT32_to_UINT16, 
    rsvcConvert_INT32_to_INT32, 
    rsvcConvert_INT32_to_UINT32, 
    rsvcConvert_INT32_to_FLOAT, 
    rsvcConvert_INT32_to_DOUBLE, 
    rsvcConvert_INT32_to_STRING, 
    rsvcConvert_INT32_to_TIMESTAMP,
    rsvcConvert_INT32_to_INVALID,
  },	
  {	
    rsvcConvert_UINT32_to_BYTE, 
    rsvcConvert_UINT32_to_INT16, 
    rsvcConvert_UINT32_to_UINT16, 
    rsvcConvert_UINT32_to_INT32, 
    rsvcConvert_UINT32_to_UINT32, 
    rsvcConvert_UINT32_to_FLOAT, 
    rsvcConvert_UINT32_to_DOUBLE, 
    rsvcConvert_UINT32_to_STRING,
    rsvcConvert_UINT32_to_TIMESTAMP, 
    rsvcConvert_UINT32_to_INVALID,
  },	
  {
    rsvcConvert_FLOAT_to_BYTE, 
    rsvcConvert_FLOAT_to_INT16, 
    rsvcConvert_FLOAT_to_UINT16, 
    rsvcConvert_FLOAT_to_INT32, 
    rsvcConvert_FLOAT_to_UINT32, 
    rsvcConvert_FLOAT_to_FLOAT, 
    rsvcConvert_FLOAT_to_DOUBLE, 
    rsvcConvert_FLOAT_to_STRING,
    rsvcConvert_FLOAT_to_TIMESTAMP, 
    rsvcConvert_FLOAT_to_INVALID,
  },	
  {
    rsvcConvert_DOUBLE_to_BYTE, 
    rsvcConvert_DOUBLE_to_INT16, 
    rsvcConvert_DOUBLE_to_UINT16, 
    rsvcConvert_DOUBLE_to_INT32, 
    rsvcConvert_DOUBLE_to_UINT32, 
    rsvcConvert_DOUBLE_to_FLOAT, 
    rsvcConvert_DOUBLE_to_DOUBLE, 
    rsvcConvert_DOUBLE_to_STRING,
    rsvcConvert_DOUBLE_to_TIMESTAMP,
    rsvcConvert_DOUBLE_to_INVALID,
  },	
  {
    rsvcConvert_STRING_to_BYTE, 
    rsvcConvert_STRING_to_INT16, 
    rsvcConvert_STRING_to_UINT16, 
    rsvcConvert_STRING_to_INT32, 
    rsvcConvert_STRING_to_UINT32, 
    rsvcConvert_STRING_to_FLOAT, 
    rsvcConvert_STRING_to_DOUBLE, 
    rsvcConvert_STRING_to_STRING, 
    rsvcConvert_STRING_to_TIMESTAMP,
    rsvcConvert_STRING_to_INVALID,
  },       
  {
    rsvcConvert_TIMESTAMP_to_BYTE,
    rsvcConvert_TIMESTAMP_to_INT16,
    rsvcConvert_TIMESTAMP_to_UINT16,
    rsvcConvert_TIMESTAMP_to_INT32,
    rsvcConvert_TIMESTAMP_to_UINT32,
    rsvcConvert_TIMESTAMP_to_FLOAT,
    rsvcConvert_TIMESTAMP_to_DOUBLE,
    rsvcConvert_TIMESTAMP_to_STRING,
    rsvcConvert_TIMESTAMP_to_TIMESTAMP,
    rsvcConvert_TIMESTAMP_to_INVALID, 
  },
  {
    rsvcConvert_INVALID_to_BYTE, 
    rsvcConvert_INVALID_to_INT16, 
    rsvcConvert_INVALID_to_UINT16, 
    rsvcConvert_INVALID_to_INT32, 
    rsvcConvert_INVALID_to_UINT32, 
    rsvcConvert_INVALID_to_FLOAT, 
    rsvcConvert_INVALID_to_DOUBLE, 
    rsvcConvert_INVALID_to_STRING,
    rsvcConvert_INVALID_to_TIMESTAMP,
    rsvcConvert_INVALID_to_INVALID,
  }
};


// *****************************************************************************
// *rsvcDataIterator:
// *	
// *****************************************************************************
rsvcDataIterator::rsvcDataIterator(rsvcData* data) { 
  dataobj_ = data;
  cur_ = 0;
}

int rsvcDataIterator::init() {
  if (dataobj_) {
    cur_ = dataobj_->entries;
    return cur_ != 0; }
  else { return 0; }
}

int rsvcDataIterator::operator !() { 
  return cur_ != 0; 
}    

int rsvcDataIterator::operator ++() {
  if (cur_)
    cur_ = cur_->next_;
  return cur_ != 0;
} 

const char* rsvcDataIterator::tag(void) {
  return (cur_!=0)?cur_->tag_:0;
}

rsvcDataEntry *
rsvcDataIterator::operator () (void)
{
  return cur_;
}


// *****************************************************************************
// * ltoa and ultoa
// *	Supporing routines for non hpux platform
// *    the return values point to static data whose content is overwritten by
// *     each call
// *****************************************************************************
#ifndef hpux
char *ltoa (long val)
{
  static char ltoabuf[80];

  sprintf (ltoabuf,"%ld", val);

  return ltoabuf;
}

char *ultoa (unsigned long val)
{
  static char ultoabuf[80];

  sprintf (ultoabuf,"%lu", val);

  return ultoabuf;
}
#endif
