//---------------------------------------------------------------------------
// 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: cdevData.h
//	Generic tool designed to convert arrays of data types from one
// 	type to another
//
// Author: Walt Akers and Danjin Wu
//
// Revision History:
//   cdevData.cc,v
// Revision 1.30  1998/04/09  16:06:58  akers
// Corrected problem with cdevDataIterator::operator++
//
// Revision 1.29  1997/08/01  19:06:27  akers
// Added addTag and tagExists feature to the library
//
// Revision 1.28  1997/06/12  19:37:06  akers
// Rest incoming data
//
// Revision 1.27  1997/04/16  19:32:08  akers
// Ongoing development
//
// Revision 1.26  1997/01/14  19:39:30  chen
// add += operator
//
// Revision 1.25  1996/12/06  20:57:06  akers
// Patched minor error
//
// Revision 1.24  1996/11/21  17:02:54  akers
// Ongoing Developement of CDEV 1.5
//
// Revision 1.23  1996/08/26  19:14:02  akers
// Adding cdevData.inserttag callback capabilities
//
// Revision 1.22  1996/08/23  15:34:04  akers
// Added comparison operator to cdevData
//
// Revision 1.21  1996/07/26  15:43:28  akers
// Minor change to copy operator
//
// Revision 1.20  1996/07/12  18:08:38  chen
// change copy and assignment to const cdevData&
//
// Revision 1.19  1995/12/01  21:14:49  danjin
// fix setBounds function
//
// Revision 1.18  1995/11/08  14:30:55  chen
// Fix for Irix5.3
//
// Revision 1.17  1995/10/30  13:33:12  akers
// Added cdev specific version of strncpy
//
// Revision 1.16  1995/10/16  18:14:28  chen
// Fix a bug for SunOs and g++
//
// Revision 1.15  1995/10/06  19:38:42  chen
// Seperate inline functions
//
// Revision 1.14  1995/10/03  19:36:25  chen
// Use new cdevGlobalTagTable Class
//
// Revision 1.13  1995/09/22  21:04:10  danjin
// added cdevDataIterator mechanism
//
// Revision 1.12  1995/09/13  15:27:50  danjin
// added changeTagName(oldtag, newtag) func
//
// Revision 1.11  1995/09/06  18:34:02  danjin
// added time stamp structure and related func
//
// Revision 1.10  1995/08/03  17:07:43  akers
// *** empty log message ***
//
// Revision 1.9  1995/08/03  15:24:23  akers
// Added overloaded double precision gcvt and inlined both gcvt functions
//
// Revision 1.8  1995/08/03  13:59:54  akers
// Added floating point version of gcvt to elliminate conversion errors
//
// Revision 1.7  1995/08/02  20:37:57  akers
// Forced char ** tagged data items to have a NULL value appended ath the end.
//
// Revision 1.6  1995/07/20  14:36:47  akers
// Mispelling in header
//
// Revision 1.5  1995/07/19  20:34:03  akers
// CVS
//
// Revision 1.4  1995/07/14  13:01:10  akers
// Updated version of cdevData source code
//
//
//
//--------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cdevCommon.h>
#include <cdevData.h>
#include <xdrClass.h>
#include <cdevGlobalTagTable.h>

#ifdef _CDEV_NO_INLINE
#include "cdevData.i"
#endif

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

static char *gcvt(double value, size_t ndigit, char * buf)
	{
	char tbuf[32];
	sprintf(tbuf, "%.14g", value);
	cdevStrncpy(buf, tbuf, ndigit);
	return buf;
	}


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

// *****************************************************************************
// * cdevConversionMatrix:
// *	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 cdevConverter cdevConversionMatrix [CDEV_INVALID+1][CDEV_INVALID+1];

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

				case CDEV_INT16:
				if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.sval);
				else insert(ptr->tag_, ptr->data_.sptr, ptr->elems_, ptr->dim_);
				break;

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

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

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

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

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

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

				case CDEV_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(ptr->tag_ && ptr->dim_ && ptr->dataType_<CDEV_INVALID) setBounds(ptr->tag_, ptr->bounds(), ptr->dim_);
			}
		}
	return *this;
	}

// *****************************************************************************
// * tagC2I:
// *	This function converts a character string tag to its associated tag
// *	number.  This function serves only to call the functions and retrieve
// *	the data that are within the cdevGlobalTagTable object.
// *****************************************************************************
int cdevData::tagC2I(char *ctag, int *tag)
	{
	return cdevGlobalTagTable::tagTable()->tagC2I(ctag, tag);
	}

// *****************************************************************************
// * tagI2C:
// *	This function converts an integer tag to its associated character string
// *	name.  This function serves only to call the functions and retrieve the
// *	data that are within the cdevGlobalTagTable object.
// *****************************************************************************
int cdevData::tagI2C(int tag, char * &ctag)
	{
	return cdevGlobalTagTable::tagTable()->tagI2C(tag, ctag);
	}

// *****************************************************************************
// * insertTag:
// *	This function adds a new tag and its associated character string to the
// *	global table of tags.  This function serves only to call the functions
// *	and retrieve the data that are within the cdevGlobalTagTable object.
// *****************************************************************************
void cdevData::insertTag(int tag, char *ctag)
	{
	cdevGlobalTagTable::tagTable()->insertTag(tag, ctag);
	}

// *****************************************************************************
// * cdevData::tagExists:
// *	This function can be called to determine if a tag string has already
// *	been added to the cdevTagTable.  The value returned is a boolean
// *	result that is TRUE (non-zero) if the tag exists or FALSE (0) if not.
// *****************************************************************************
int cdevData::tagExists ( char * ctag )
	{
	return cdevGlobalTagTable::tagTable()->tagExists(ctag);
	}


// *****************************************************************************
// * cdevData::tagExists:
// *	This function can be called to determine if a tag integer has already
// *	been added to the cdevTagTable.  The value returned is a boolean
// *	result that is TRUE (non-zero) if the tag exists or FALSE (0) if not.
// *****************************************************************************
int cdevData::tagExists ( int tag )
	{
	return cdevGlobalTagTable::tagTable()->tagExists(tag);
	}

// *****************************************************************************
// * cdevData::addTag :
// *	This method will add the tag string to the cdevTagTable if it
// *	does not already exist.  Tag Table will start searching for the
// *	next available tag number above 1000.  The value returned by the
// *	function will be the integer that is assigned to the character string
// *	tag.
// *****************************************************************************
int cdevData::addTag ( char * ctag )
	{
	return cdevGlobalTagTable::tagTable()->addTag(ctag);
	}

// ***************************************************************************
// * cdevData::addTagCallback :
// *	This method will add a cdevTagTableCallback object to the list of
// *	classes that should be notified each time a tag is added to the
// *	cdevTagTable.
// ***************************************************************************
void cdevData::addTagCallback ( cdevTagTableCallback * cb )
	{
	cdevGlobalTagTable::tagTable()->addTagCallback(cb);
	}

// ***************************************************************************
// * cdevData::delTagCallback :
// *	This method will remote a cdevTagTableCallback object that was
// *	previously added to the list of callback classes.
// *
// *	Note:	This method does not actually delete the cdevTagTableCallback
// *		object, it merely removes it from the list.  It is the
// *		responsibility of the owner to delete the object when it is
// *		no longer needed.
// ***************************************************************************
void cdevData::delTagCallback ( cdevTagTableCallback * cb )
	{
	cdevGlobalTagTable::tagTable()->delTagCallback(cb);
	}

// *****************************************************************************
// * cdevData::readTagTable :
// *	This method allows the caller to obtain a list of tag names and
// *	integers that are currently stored in this tag table.
// *
// *	Note:	This method will allocate an array of integers and an array of
// *		character string pointers.  The strings that are stored in the
// *		string array will be the actual strings from within the
// *		tag table and should not be deleted...
// *
// *		The data allocated becomes the property of the caller and must
// *		be deleted when it is no longer needed... the correct syntax to
// *		delete these items is...
// *
// *			delete tags;
// *			delete ctags;
// *
// *		This will delete the array, however, it will leave the
// *		individual array elements intact.
// *****************************************************************************
int cdevData::readTagTable ( int * &tags, char ** &ctags, int &ntags )
	{
	return cdevGlobalTagTable::tagTable()->readTagTable(tags, ctags, ntags);
	}


// *****************************************************************************
// * lookupTag:
// * 	This function attempts to locate the specified tag within the cdevData
// *	objects list of cdevDataEntry objects.  If the tag is found, then
// *	its associated cdevDataEntry 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.
// *****************************************************************************
cdevDataEntry * cdevData::lookupTag(int tag, int create)
	{
	cdevDataEntry *result = NULL, *prev = NULL;

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

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

	return result;
	}

// *****************************************************************************
// * setupTag:
// * 	Convenience function to allow the cdevData object to more efficiently
// *	prepare new cdevDataEntry 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.
// *****************************************************************************
cdevDataEntry * cdevData::setupTag (int tag, cdevDataTypes type, size_t elemSize,
	size_t numElems, size_t numDims )
	{
	cdevDataEntry * entry;
	if((entry = lookupTag(tag, 1))!=NULL)
		{
		// *************************************************************
		// * If the entry is already populated and the new data is not
		// * multidimensional,  clear the old contents.
		// *************************************************************
		if(entry->tag_ == tag && numDims<=0) entry->clear();

		// *************************************************************
		// * If the entry is multidimensional, allocate a new data
		// * block for storing the data.
		// *************************************************************
		if(numDims > 0)
			{
			entry->allocate(numDims, numElems, elemSize);
			if(numDims > 0)
				{
				cdevBounds * bounds = entry->bounds();
				// *****************************************************
				// * Set the first cdevBounds structure to indicate the
				// * entire array.  Subsequent structures (if any),
				// * should indicate an offset of 0 and a length of 1.
				// *****************************************************
				bounds[0].offset = 0;
				bounds[0].length = numElems;
				for(int i = 1; i < numDims; i++)
					{
					bounds[i].offset = 0;
					bounds[i].length = 1;
					}
				}
			}

		// *************************************************************
		// * Populate the entry with the new data.
		// *************************************************************
		entry->tag_	 = tag;
		entry->dataType_ = type;
		}
	return entry;
	}


// *****************************************************************************
// * cdevData:
// *	Default constructor for the cdevData object.  Initializes local data.
// *****************************************************************************
cdevData::cdevData ( void ) : entries(NULL)
	{
	}

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

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

// *****************************************************************************
// * xdrSize:
// *	Calculates the size of the XDR Buffer necessary to store the cdevData
// *	object.  This function may be used to determine the size of a
// *	preallocated buffer for storing the xdr representation of a cdevData
// *	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 cdevData::xdrSize  (size_t * bufLen, size_t * elementCount)
	{
	cdevDataEntry * ptr            = entries;
	int             xdrDataSize    = 0;
	int             cdevElementCnt = 0;
	int             i;

	// ************************************#
	// * CALCULATE THE SIZE OF THE BUFFER  #
	// ************************************#
	// *************************************
	// * Add the size of the tag count int *
	// *************************************
	xdrDataSize += XDR_Sizeof(cdevElementCnt);

	// *************************************
	// * Add the size of each valid item   *
	// *************************************
	for(ptr=entries; ptr!=NULL; ptr = ptr->next_)
		{
		// *****************************
		// * Do not process entries    *
		// * with CDEV_INVALID as the  *
		// * dataType or 0 as the tag. *
		// *****************************
		if(ptr->dataType_==CDEV_INVALID || ptr->tag_==0) continue;

		// *****************************
		// * Calculate the number of   *
		// * elements in this tagged   *
		// * data item.                *
		// *****************************
		int numElements = ptr->dim_!=0?ptr->elems_:1;

		// *****************************
		// * Increment the counter     *
		// *****************************
		cdevElementCnt++;

		// *****************************
		// * Add the size of the       *
		// * cdevDataEntries tag_,     *
		// * dataType_, dim_, elems_.  *
		// *****************************
		xdrDataSize += 4 * XDR_Sizeof((int)1);

		// *****************************
		// * Add the size of the       *
		// * cdevBounds data.          *
		// *****************************
		xdrDataSize += ptr->dim_ * (XDR_Sizeof((int)1) * 2);

		// *****************************
		// * Add the size of the data  *
		// *****************************
		if     (ptr->dataType_==CDEV_BYTE)   xdrDataSize += numElements * XDR_Sizeof((unsigned char)'c');
		else if(ptr->dataType_==CDEV_INT16)  xdrDataSize += numElements * XDR_Sizeof((short)1);
		else if(ptr->dataType_==CDEV_UINT16) xdrDataSize += numElements * XDR_Sizeof((unsigned short)1);
		else if(ptr->dataType_==CDEV_INT32)  xdrDataSize += numElements * XDR_Sizeof((long)1);
		else if(ptr->dataType_==CDEV_UINT32) xdrDataSize += numElements * XDR_Sizeof((unsigned long)1);
		else if(ptr->dataType_==CDEV_FLOAT)  xdrDataSize += numElements * XDR_Sizeof((float)1);
		else if(ptr->dataType_==CDEV_DOUBLE) xdrDataSize += numElements * XDR_Sizeof((double)1);
		else if(ptr->dataType_==CDEV_STRING)
			{
			if(numElements==1) xdrDataSize += XDR_Sizeof(ptr->data_.str);
			else for(i=0; i<numElements; i++) xdrDataSize += XDR_Sizeof(ptr->data_.strarr[i]);
			}
		else if(ptr->dataType_==CDEV_TIMESTAMP) xdrDataSize += numElements * XDR_Sizeof(ptr->data_.ts);
		}

	*elementCount = cdevElementCnt;
	*bufLen       = xdrDataSize;

	return *bufLen>0?CDEV_SUCCESS:CDEV_ERROR;
	}


// *****************************************************************************
// * xdrExport:
// *	This function encapsulates the contents of the cdevData class into a
// *	binary stream.  This function allocates the buffer and returns the new
// *	buffer and the buffer size.
// *****************************************************************************
int cdevData::xdrExport ( char ** buf, size_t * bufLen )
	{
	size_t count = 0;

	// ************************************#
	// * Calculate the size of the buffer  #
	// ************************************#
	xdrSize(bufLen, &count);

	// ************************************#
	// * Allocate the buffer and call the  #
	// * export function.                  #
	// ************************************#
	if((*buf = new char[*bufLen])!=NULL) xdrExport(*buf, *bufLen, count);

	return buf==NULL?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * xdrExport:
// *	This function encapsulates the contents of the cdevData 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 cdevData object into the
// *	binary stream.
// *****************************************************************************
int cdevData::xdrExport ( char * buf, size_t bufLen, size_t count)
	{
	cdevDataEntry * ptr;
	XDR_Writer      writer;
	int             xdrDataSize    = bufLen;
	int             cdevElementCnt = count;
	int             i;

	// ************************************#
	// * Allocate the buffer               #
	// ************************************#
	writer.attachData(buf, bufLen);

	// ************************************#
	// * Transfer the data to the buffer   #
	// ************************************#
	// *************************************
	// * Write the number of elements      *
	// *************************************
	writer.put(cdevElementCnt);

	// *************************************
	// * Write each valid item.            *
	// *************************************
	for(ptr = entries; ptr != NULL; ptr = ptr->next_)
		{
		// *****************************
		// * Do not process entries    *
		// * with CDEV_INVALID as the  *
		// * dataType or 0 as the tag. *
		// *****************************
		if(ptr->dataType_==CDEV_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     *
		// *****************************
		cdevElementCnt--;

		// *****************************
		// * Write the tag_, dataType_ *
		// * dim_, and elems_ of the   *
		// * cdevDataEntry object.     *
		// *****************************
		writer.put((int)ptr->tag_);
		writer.put((int)ptr->dataType_);
		writer.put((int)ptr->dim_);
		writer.put((int)ptr->elems_);

		// *****************************
		// * Write the cdevBounds      *
		// * values asssociated with   *
		// * the cdevDataEntry (if any)*
		// *****************************
		cdevBounds * bounds = ptr->bounds();
		for(i=0; i<ptr->dim_; i++)
			{
			writer.put((int)bounds[i].offset);
			writer.put((int)bounds[i].length);
			}

		// *****************************
		// * Write the data            *
		// *****************************
		if     (ptr->dataType_==CDEV_BYTE)
			{
			if(numElements==1) writer.put(ptr->data_.cval);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.cptr[i]);
			}
		else if(ptr->dataType_==CDEV_INT16)
			{
			if(numElements==1) writer.put(ptr->data_.sval);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.sptr[i]);
			}
		else if(ptr->dataType_==CDEV_UINT16)
			{
			if(numElements==1) writer.put(ptr->data_.usval);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.usptr[i]);
			}
		else if(ptr->dataType_==CDEV_INT32)
			{
			if(numElements==1) writer.put(ptr->data_.lval);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.lptr[i]);
			}
		else if(ptr->dataType_==CDEV_UINT32)
			{
			if(numElements==1) writer.put(ptr->data_.ulval);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.ulptr[i]);
			}
		else if(ptr->dataType_==CDEV_FLOAT)
			{
			if(numElements==1) writer.put(ptr->data_.fval);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.fptr[i]);
			}
		else if(ptr->dataType_==CDEV_DOUBLE)
			{
			if(numElements==1) writer.put(ptr->data_.dval);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.dptr[i]);
			}
		else if(ptr->dataType_==CDEV_STRING)
			{
			if(numElements==1) writer.put(ptr->data_.str);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.strarr[i]);
			}
		else if(ptr->dataType_==CDEV_TIMESTAMP)
			{
			if(numElements==1) writer.put(ptr->data_.ts);
			else for(i=0; i<numElements; i++) writer.put(ptr->data_.tsptr[i]);
			}
		}

	// *************************************
	// * Detach the data from the writer   *
	// * object before the object is       *
	// * destroyed.                        *
	// *************************************
	writer.detachData();

	return CDEV_SUCCESS;
	}

// *****************************************************************************
// * xdrImport:
// *	This function populates the cdevData class using the contents of a
// *    binary buffer that has bee created by the xdrExport function.
// *****************************************************************************
int cdevData::xdrImport ( char * buf, size_t bufLen)
	{
	XDR_Reader reader;
	int        cdevElementCnt;
	int        i, j;
	int        xdrError = CDEV_SUCCESS;

	if(buf==NULL || bufLen==0) return CDEV_INVALIDARG;

	// *************************************
	// * Transfer the data buffers to the  *
	// * XDR_Reader class.                 *
	// *************************************
	reader.attachData(buf, bufLen);

	// *************************************
	// * Deallocate any data previously    *
	// * assigned to the cdevData class.   *
	// *************************************
	remove();

	// *************************************
	// * Read the element count from the   *
	// * buffer.                           *
	// *************************************
	if(reader.get(cdevElementCnt)==0) xdrError = CDEV_ERROR;

	// *************************************
	// * Process each tagged element in    *
	// * the buffer.                       *
	// *************************************
	for(i=0; i<cdevElementCnt && xdrError==CDEV_SUCCESS; i++)
		{
		int           tag_;
		cdevDataTypes dataType_;
		size_t        dim_;
		size_t        elems_;
		cdevBounds * bounds = NULL;

		// *****************************
		// * Read the data definition  *
		// * information from the data *
		// * stream.                   *
		// *****************************
		if(!reader.get(tag_)             ||
			!reader.get((int &)dataType_) ||
			!reader.get((int &)dim_)      ||
			!reader.get((int &)elems_))
			{
			xdrError = CDEV_ERROR;
			}
		else
			{
			if(dim_!=0)
				{
				// *****************************
				// * Allocate a sufficient     *
				// * number of cdevBounds      *
				// * structures to hold the    *
				// * bounds data.              *
				// *****************************
				bounds = new cdevBounds[dim_];
				for(j=0; j<dim_ && xdrError==CDEV_SUCCESS; j++)
					{
					if(!reader.get((int &)bounds[j].offset) ||
						!reader.get((int &)bounds[j].length))
						{
						xdrError = CDEV_ERROR;
						}
					}
				}
			}
		if(xdrError==CDEV_SUCCESS)
			{
			// *****************************
			// * Calculate the number of   *
			// * elements in this tagged   *
			// * data item.                *
			// *****************************
			int numElements = dim_!=0?elems_:1;
			cdevDataEntry * entry;

			switch(dataType_)
				{
				case CDEV_BYTE:
				if((entry = setupTag(tag_, dataType_, sizeof(BYTE), numElements, dim_))!=NULL)
					{
					if(numElements==1) xdrError = reader.get(entry->data_.cval)?CDEV_SUCCESS:CDEV_ERROR;
					else for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(entry->data_.cptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					}
				break;

				case CDEV_INT16:
				if((entry = setupTag(tag_, dataType_, sizeof(short), numElements, dim_))!=NULL)
					{
					if(numElements==1) xdrError = reader.get(entry->data_.sval)?CDEV_SUCCESS:CDEV_ERROR;
					else for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(entry->data_.sptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					}
				break;

				case CDEV_UINT16:
				if((entry = setupTag(tag_, dataType_, sizeof(unsigned short), numElements, dim_))!=NULL)
					{
					if(numElements==1) xdrError = reader.get(entry->data_.usval)?CDEV_SUCCESS:CDEV_ERROR;
					else for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(entry->data_.usptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					}
				break;

				case CDEV_INT32:
				if((entry = setupTag(tag_, dataType_, sizeof(long), numElements, dim_))!=NULL)
					{
					if(numElements==1) xdrError = reader.get(entry->data_.lval)?CDEV_SUCCESS:CDEV_ERROR;
					else for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(entry->data_.lptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					}
				break;

				case CDEV_UINT32:
				if((entry = setupTag(tag_, dataType_, sizeof(unsigned long), numElements, dim_))!=NULL)
					{
					if(numElements==1) xdrError = reader.get(entry->data_.ulval)?CDEV_SUCCESS:CDEV_ERROR;
					else for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(entry->data_.ulptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					}
				break;

				case CDEV_FLOAT:
				if((entry = setupTag(tag_, dataType_, sizeof(float), numElements, dim_))!=NULL)
					{
					if(numElements==1) xdrError = reader.get(entry->data_.fval)?CDEV_SUCCESS:CDEV_ERROR;
					else for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(entry->data_.fptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					}
				break;

				case CDEV_DOUBLE:
				if((entry = setupTag(tag_, dataType_, sizeof(double), numElements, dim_))!=NULL)
					{
					if(numElements==1) xdrError = reader.get(entry->data_.dval)?CDEV_SUCCESS:CDEV_ERROR;
					else for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(entry->data_.dptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					}
				break;

				case CDEV_STRING:
					{
					char ** ptr = new char *[numElements];
					memset(ptr, 0, sizeof(char *)*numElements);

					for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(&ptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					if(xdrError==CDEV_SUCCESS)
						{
						if(dim_==0) insert(tag_, *ptr);
						else        insert(tag_, ptr, numElements, dim_);
						}
					for(j=0; j<numElements; j++) if(ptr[j]!=NULL) delete ptr[j];
					delete ptr;
					}
				break;

				case CDEV_TIMESTAMP:
				if((entry = setupTag(tag_, dataType_, sizeof(cdev_TS_STAMP), numElements, dim_))!=NULL)
					{
					if(numElements==1) xdrError = reader.get(entry->data_.ts)?CDEV_SUCCESS:CDEV_ERROR;
					else for(j=0; j<numElements && xdrError==CDEV_SUCCESS; j++)
						{
						xdrError = reader.get(entry->data_.tsptr[j])?CDEV_SUCCESS:CDEV_ERROR;
						}
					}
				break;

				case CDEV_INVALID:
				break;
				}
			if(dim_!=0 && xdrError==CDEV_SUCCESS) setBounds(tag_, bounds, dim_);
			}

		if(bounds!=NULL) delete bounds;
		}

	// *************************************
	// * Divorce the data from the reader  *
	// * object before the object is       *
	// * destroyed.                        *
	// *************************************
	reader.detachData();

	return xdrError;
	}

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

// *****************************************************************************
// * remove:
// *	Removes a specified tagged data item from the cdevData object.
// *****************************************************************************
void cdevData::remove(int tag)
	{
	cdevDataEntry *result = NULL, *prev = NULL;

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

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

// *********************************************************************
// * changeTag:
// * 	Replace a new tag with the old one within the
// *	cdevData object. If the old one can not be not found,
// *	CDEV_NOTFOUND is returned. If the new tag has already
// *    been found in that cdevData object, CDEV_ERROR is returned.
// *********************************************************************
int cdevData::changeTag(int oldTag, int newTag)
	{
	int result;
	cdevDataEntry *entry;
	if((entry=lookupTag(oldTag)) == NULL) result = CDEV_NOTFOUND;
	else
		{
		if( lookupTag(newTag) != NULL) result = CDEV_ERROR;
		else
			{
			entry->tag_ = newTag;
			result = CDEV_SUCCESS;
			}
		}
	return result;
	}

int cdevData::changeTag(int oldTag, char *c_newTag)
	{
	int tag;
	return tagC2I(c_newTag, &tag)?CDEV_NOTFOUND:changeTag(oldTag, tag);
	}

int cdevData::changeTag(char *c_oldTag, int newTag)
	{
	int tag;
	return tagC2I(c_oldTag, &tag)?CDEV_NOTFOUND:changeTag(tag, newTag);
	}

int cdevData::changeTag(char *c_oldTag, char *c_newTag)
	{
	int tag1, tag2;
	if ( (tagC2I(c_oldTag, &tag1)==0) && (tagC2I(c_newTag, &tag2)==0) )
		return ( changeTag(tag1, tag2) );
	else
	return CDEV_NOTFOUND;
	}


// *****************************************************************************
// * getType:
// * 	Retrieves the cdevDataTypes of the referenced tagged data item.
// *	If no item with that tag is within the cdevData object, then
// *	CDEV_INVALID is returned.
// *****************************************************************************
cdevDataTypes cdevData::getType(int tag)
	{
	cdevDataEntry * entry = lookupTag(tag);
	return entry==NULL?CDEV_INVALID:entry->dataType_;
	}

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

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

// *****************************************************************************
// * getBounds:
// *	Obtains the bounding dimensions of a cdevDataEntry array.  The
// * 	integer array passed as the bounds parameter must be allocated
// *	by the caller.  The number of integers required is 2 times the
// *	number of dimensions.  The len parameter specifies the actual
// *	number of integers allocated.
// *****************************************************************************
int cdevData::getBounds( int tag, size_t * bounds, size_t len )
	{
	cdevDataEntry * entry = lookupTag(tag);
	memset(bounds, 0, len*sizeof(size_t));
	if(entry!=NULL && entry->dim_>0)
		{
		int i;
		cdevBounds * entryBounds = entry->bounds();
		len = (len/2 < entry->dim_) ? len/2 : entry->dim_;
		for(i=0; i<len; i++)
			{
			bounds[i]   = entryBounds[i].offset;
			bounds[i+1] = entryBounds[i].length;
			}
		}
	return entry==NULL?CDEV_NOTFOUND:CDEV_SUCCESS;
	}

// *****************************************************************************
// * getBounds:
// *	Obtains the bounding dimensions of a cdevDataEntry array.  The
// *	cdevBounds structure passed as the bounds parameter must be
// *	allocated by the caller.  The numBounds variable indicates the
// *	number of cdevBounds structures allocated by the caller.
// *****************************************************************************
int cdevData::getBounds( int tag, cdevBounds * bounds, size_t numBounds )
	{
	cdevDataEntry * entry = lookupTag(tag);
	memset(bounds, 0, numBounds*sizeof(cdevBounds));
	if(entry!=NULL && entry->dim_ > 0)
		{
		int i;
		cdevBounds * entryBounds = entry->bounds();
		numBounds = (numBounds<entry->dim_) ? numBounds : entry->dim_;
		for(i=0; i<numBounds; i++)
			{
			bounds[i].offset = entryBounds[i].offset;
			bounds[i].length = entryBounds[i].length;
			}
		}
	return entry==NULL?CDEV_NOTFOUND:CDEV_SUCCESS;
	}

// *****************************************************************************
// * setBounds:
// *	Allows the caller to set the dimensions of a multidimensional
// *	tagged data item.  The number of integers required is 2 times the
// *	number of dimensions, the first being the offset and the second
// *	being the length of the dimension.  The len parameter specifies
// *	the actual number of integers submitted.
// *****************************************************************************
int cdevData::setBounds(int tag, size_t * bounds, size_t len)
	{
	int result;
	cdevDataEntry * entry = lookupTag(tag);
	if(entry!=NULL && entry->dim_>0)
		{
		int i;
		int actualItems=1;

		cdevBounds * entryBounds = entry->bounds();
		len = (len/2 < entry->dim_) ? len/2 : entry->dim_;

		for(i=0; i<len; i++) actualItems *= bounds[i*2+1];
		if(actualItems != entry->elems_)
			{
			char * ctag;
			cdevGlobalTagTable::tagTable()->tagI2C(tag, ctag);
			result = CDEV_INVALIDARG;
			}
		else
			{
			int j = 0;
			for(i=0; i<len; i++)
				{
				entryBounds[i].offset = bounds[j++];
				entryBounds[i].length = bounds[j++];
				}
			result = CDEV_SUCCESS;
			}
		}
	else result = CDEV_NOTFOUND;
	return result;
	}

// *****************************************************************************
// * setBounds:
// *	Allows the caller to set the dimensions of a multidimensional
// *	tagged data item.  The numBounds variable indicates the number
// *	of cdevBounds structures submitted by the user.
// *****************************************************************************
int cdevData::setBounds(int tag, cdevBounds * bounds, size_t numBounds)
	{
	int result;
	cdevDataEntry * entry = lookupTag(tag);
	if(entry!=NULL && entry->dim_ > 0)
		{
		int i;
		int actualItems = 1;

		cdevBounds * entryBounds = entry->bounds();
		numBounds = (numBounds<entry->dim_) ? numBounds : entry->dim_;

		for(i=0; i<numBounds; i++) actualItems *= bounds[i].length;
		if(actualItems != entry->elems_)
			{
			char * ctag;
			cdevGlobalTagTable::tagTable()->tagI2C(tag, ctag);
			result = CDEV_INVALIDARG;
			}
		else
			{
			for(i=0; i<numBounds; i++)
				{
				entryBounds[i].offset = bounds[i].offset;
				entryBounds[i].length = bounds[i].length;
				}
			result = CDEV_SUCCESS;
			}
		}
	else result = CDEV_NOTFOUND;
	return result;
	}

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

	if((entry = setupTag(tag, CDEV_BYTE, sizeof(char), 1, 0))!=NULL)
		{
		entry->data_.cval= data;
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}


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

	if((entry = setupTag(tag, CDEV_INT16, sizeof(short), 1, 0))!=NULL)
		{
		entry->data_.sval= data;
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

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

	if((entry = setupTag(tag, CDEV_UINT16, sizeof(unsigned short), 1, 0))!=NULL)
		{
		entry->data_.usval= data;
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

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

	if((entry = setupTag(tag, CDEV_INT32, sizeof(long), 1, 0))!=NULL)
		{
		entry->data_.lval= data;
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

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

	if((entry = setupTag(tag, CDEV_UINT32, sizeof(long), 1, 0))!=NULL)
		{
		entry->data_.ulval= data;
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

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

	if((entry = setupTag(tag, CDEV_FLOAT, sizeof(float), 1, 0))!=NULL)
		{
		entry->data_.fval= data;
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

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

	if((entry = setupTag(tag, CDEV_DOUBLE, sizeof(double), 1, 0))!=NULL)
		{
		entry->data_.dval= data;
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * insert:
// *	Allows the caller to insert a time stamp value into a cdevDataEntry
// *	object as a tagged data item.
// *****************************************************************************
int cdevData::insert ( int tag, cdev_TS_STAMP data )
	{
	cdevDataEntry * entry;

	if((entry = setupTag(tag, CDEV_TIMESTAMP, sizeof(cdev_TS_STAMP), 1, 0))!=NULL)
		{
		entry->data_.ts.secPastEpoch = data.secPastEpoch;
		entry->data_.ts.nsec = data.nsec;
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}


// *****************************************************************************
// * insert:
// *	The following function allows the insertion of characters arrays of data
// *	into a cdevData 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 cdevData::insert (int tag, BYTE * data, size_t len, size_t ndim)
	{
	cdevDataEntry * entry;

	if(len==1 && data!=NULL)       return insert(tag, *data);
	else if(len<=0 || data==NULL)  return CDEV_INVALIDARG;
	else if((entry = setupTag(tag, CDEV_BYTE, sizeof(char), len, ndim))!=NULL)
		{
		memcpy(entry->data_.cptr, data, len*sizeof(char));
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of short int arrays of data
// *	into a cdevData 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 cdevData::insert (int tag, short * data, size_t len, size_t ndim)
	{
	cdevDataEntry * entry;

	if(len==1 && data!=NULL)       return insert(tag, *data);
	else if(len<=0 || data==NULL)  return CDEV_INVALIDARG;
	else if((entry = setupTag(tag, CDEV_INT16, sizeof(short), len, ndim))!=NULL)
		{
		memcpy(entry->data_.sptr, data, len*sizeof(short));
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of unsigned short int arrays
// *	of data into a cdevData 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 cdevData::insert (int tag, unsigned short * data, size_t len, size_t ndim)
	{
	cdevDataEntry * entry;

	if(len==1 && data!=NULL)       return insert(tag, *data);
	else if(len<=0 || data==NULL)  return CDEV_INVALIDARG;
	else if((entry = setupTag(tag, CDEV_UINT16, sizeof(unsigned short), len, ndim))!=NULL)
		{
		memcpy(entry->data_.usptr, data, len*sizeof(unsigned short));
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of long int arrays of data
// *	into a cdevData 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 cdevData::insert (int tag, long * data, size_t len, size_t ndim)
	{
	cdevDataEntry * entry;

	if(len==1 && data!=NULL)       return insert(tag, *data);
	else if(len<=0 || data==NULL)  return CDEV_INVALIDARG;
	else if((entry = setupTag(tag, CDEV_INT32, sizeof(long), len, ndim))!=NULL)
		{
		memcpy(entry->data_.lptr, data, len*sizeof(long));
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of unsigned long int arrays
// *	of data into a cdevData 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 cdevData::insert (int tag, unsigned long * data, size_t len, size_t ndim)
	{
	cdevDataEntry * entry;

	if(len==1 && data!=NULL)       return insert(tag, *data);
	else if(len<=0 || data==NULL)  return CDEV_INVALIDARG;
	else if((entry = setupTag(tag, CDEV_UINT32, sizeof(unsigned long), len, ndim))!=NULL)
		{
		memcpy(entry->data_.ulptr, data, len*sizeof(unsigned long));
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of float arrays of data
// *	into a cdevData 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 cdevData::insert (int tag, float * data, size_t len, size_t ndim)
	{
	cdevDataEntry * entry;

	if(len==1 && data!=NULL)       return insert(tag, *data);
	else if(len<=0 || data==NULL)  return CDEV_INVALIDARG;
	else if((entry = setupTag(tag, CDEV_FLOAT, sizeof(float), len, ndim))!=NULL)
		{
		memcpy(entry->data_.fptr, data, len*sizeof(float));
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of double arrays of data
// *	into a cdevData 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 cdevData::insert (int tag, double * data, size_t len, size_t ndim)
	{
	cdevDataEntry * entry;

	if(len==1 && data!=NULL)       return insert(tag, *data);
	else if(len<=0 || data==NULL)  return CDEV_INVALIDARG;
	else if((entry = setupTag(tag, CDEV_DOUBLE, sizeof(double), len, ndim))!=NULL)
		{
		memcpy(entry->data_.dptr, data, len*sizeof(double));
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}

// *****************************************************************************
// * insert:
// *	The following function allows the insertion of a character string into
// *	a cdevData 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 cdevDataEntry object, it has no
// *	cdevBounds information associated with it.
// *****************************************************************************
int cdevData::insert ( int tag, char * data )
	{
	cdevDataEntry * entry;
	int result = CDEV_ERROR;
	int len    = data!=NULL?strlen(data)+1:0;

	if(len>0 && (entry = lookupTag(tag, 1))!=NULL)
		{
		// *************************************************************
		// * 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 cdevDataEntry object will still
		// * be used.
		// *************************************************************
		entry->allocate(0, len, sizeof(char));

		// *************************************************************
		// * Populate the entry with the new data.
		// *************************************************************
		entry->tag_	 = tag;
		entry->dataType_ = CDEV_STRING;
		memcpy(entry->data_.str, data, len);
		result = CDEV_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
// *	cdevBounds data associated within it.
// *****************************************************************************
int cdevData::insert ( int tag, char ** data, size_t len, size_t ndim )
	{
	int result = CDEV_SUCCESS;
	cdevDataEntry * entry;

	// *********************************************************************
	// * If the user specified len is invalid (or 0 by default), walk
	// * through the array of pointers until NULL is found.
	// *********************************************************************
	if(len<=0) for(len=0; data && data[len]!=NULL; len++);
	if(len==0) result = CDEV_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 NULL 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 cdevDataEntry with the user specified strings.
		// *************************************************************
		if((entry = setupTag(tag, CDEV_STRING, sizeof(char), dataLen, ndim))!=NULL)
			{
			// *****************************************************
			// * Immediately following the setupTag call, the bounds
			// * member of the cdevDataEntry object will contain
			// * the dataLen value (total bytes) rather than the
			// * len value (total strings).  Correct this problem
			// * before continuing.
			// *****************************************************
			entry->bounds()[0].length = len;
			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]=NULL;
			}
		else result = CDEV_ERROR;
		}
	return result;
	}


// *****************************************************************************
// * insert:
// *	The following function allows the insertion of a time_stamp arrays of
// *	data into a cdevData 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 cdevData::insert ( int tag, cdev_TS_STAMP *data, size_t len, size_t ndim )
	{
	cdevDataEntry * entry;

	if(len==1 && data!=NULL)       return insert(tag, *data);
	else if(len<=0 || data==NULL)  return CDEV_INVALIDARG;
	else if((entry = setupTag(tag, CDEV_TIMESTAMP, sizeof(cdev_TS_STAMP), len, ndim))!=NULL)
		{
		memcpy(entry->data_.tsptr, data, len*sizeof(cdev_TS_STAMP));
		}
	return (entry==NULL)?CDEV_ERROR:CDEV_SUCCESS;
	}


// *****************************************************************************
// * get:
// *	This function retrieves a character value specified by tag from the
// *	cdevData 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 cdevData::get(int tag, BYTE * data)
	{
	int result, nelem=1;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_BYTE]
			(entry->data_.vptr, data, entry->elems_);
		else	cdevConversionMatrix[entry->dataType_][CDEV_BYTE]
		(&entry->data_, data, 1);

		result = CDEV_SUCCESS;
		}
	return result;
	}

// *****************************************************************************
// * get:
// *	This function retrieves an short integer value specified by tag from the
// *	cdevData 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 cdevData::get(int tag, short * data)
	{
	int result, nelem=1;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_INT16]
			(entry->data_.vptr, data, entry->elems_);
		else	cdevConversionMatrix[entry->dataType_][CDEV_INT16]
		(&entry->data_, data, 1);

		result = CDEV_SUCCESS;
		}
	return result;
	}

// *****************************************************************************
// * get:
// *	This function retrieves an unsigned short integer value specified by tag
// *	from the cdevData 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 cdevData::get(int tag, unsigned short * data)
	{
	int result, nelem=1;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_UINT16]
			(entry->data_.vptr, data, entry->elems_);
		else	cdevConversionMatrix[entry->dataType_][CDEV_UINT16]
		(&entry->data_, data, 1);

		result = CDEV_SUCCESS;
		}
	return result;
	}

// *****************************************************************************
// * get:
// *	This function retrieves an long integer value specified by tag from the
// *	cdevData 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 cdevData::get(int tag, long * data)
	{
	int result, nelem=1;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_INT32]
			(entry->data_.vptr, data, entry->elems_);
		else	cdevConversionMatrix[entry->dataType_][CDEV_INT32]
		(&entry->data_, data, 1);

		result = CDEV_SUCCESS;
		}
	return result;
	}

// *****************************************************************************
// * get:
// *	This function retrieves an unsigned long integer value specified by tag
// *	from the cdevData 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 cdevData::get(int tag, unsigned long * data)
	{
	int result, nelem=1;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_UINT32]
			(entry->data_.vptr, data, entry->elems_);
		else	cdevConversionMatrix[entry->dataType_][CDEV_UINT32]
		(&entry->data_, data, 1);

		result = CDEV_SUCCESS;
		}
	return result;
	}

// *****************************************************************************
// * get:
// *	This function retrieves a floating point value specified by tag from the
// *	cdevData 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 cdevData::get(int tag, float * data)
	{
	int result, nelem=1;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_FLOAT]
			(entry->data_.vptr, data, entry->elems_);
		else	cdevConversionMatrix[entry->dataType_][CDEV_FLOAT]
		(&entry->data_, data, 1);

		result = CDEV_SUCCESS;
		}
	return result;
	}


// *****************************************************************************
// * get:
// *	This function retrieves a double float value specified by tag from the
// *	cdevData 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 cdevData::get(int tag, double * data)
	{
	int result, nelem=1;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_DOUBLE]
			(entry->data_.vptr, data, entry->elems_);
		else	cdevConversionMatrix[entry->dataType_][CDEV_DOUBLE]
		(&entry->data_, data, 1);

		result = CDEV_SUCCESS;
		}
	return result;
	}

// *****************************************************************************
// * get:
// *	This function retrieves a time stamp value specified by tag from the
// *	cdevData object.
// *****************************************************************************
int cdevData::get(int tag, cdev_TS_STAMP * data)
	{
	int result;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_TIMESTAMP]
			(entry->data_.vptr, data, entry->elems_);
		else
		cdevConversionMatrix[entry->dataType_][CDEV_TIMESTAMP]
		(&entry->data_, data, 1);
		result = CDEV_SUCCESS;
		}
	return result;
	}


// *****************************************************************************
// * get:
// *	This function retrieves a char string value specified by tag from the
// *	cdevData object.  For simplicity, this method operates differently
// *	than the other get methods.
// *****************************************************************************
int cdevData::get(int tag, char * data, size_t len)
	{
	int nelem = 1, result = CDEV_NOTFOUND, i;
	cdevDataEntry * entry;
	if(data!=NULL && (entry=lookupTag(tag, 0))!=NULL)
		{
		if(entry->dim_ > 0)
			{
			cdevBounds * bounds = entry->bounds();
			for(i=0; i<entry->dim_; i++) nelem *= bounds[i].length;
			}

		switch(entry->dataType_)
			{
			case CDEV_BYTE:
			if(nelem==1) sprintf(data, "%.*s", len, ltoa(entry->data_.cval));
			else sprintf(data, "%.*s", len, ltoa(*entry->data_.str));
			break;
			case CDEV_INT16:
			if(nelem==1) sprintf(data, "%.*s", len, ltoa(entry->data_.sval));
			else sprintf(data, "%.*s", len, ltoa(*entry->data_.sptr));
			break;
			case CDEV_UINT16:
			if(nelem==1) sprintf(data, "%.*s", len, ultoa(entry->data_.usval));
			else sprintf(data, "%.*s", len, ultoa(*entry->data_.usptr));
			break;
			case CDEV_INT32:
			if(nelem==1) sprintf(data, "%.*s", len, ltoa(entry->data_.lval));
			else sprintf(data, "%.*s", len, ltoa(*entry->data_.lptr));
			break;
			case CDEV_UINT32:
			if(nelem==1) sprintf(data, "%.*s", len, ultoa(entry->data_.ulval));
			else sprintf(data, "%.*s", len, ultoa(*entry->data_.ulptr));
			break;
			case CDEV_FLOAT:
			if(nelem==1) gcvt(entry->data_.fval, len, data);
			else gcvt(*entry->data_.fptr, len, data);
			break;
			case CDEV_DOUBLE:
			if(nelem==1) gcvt(entry->data_.dval, len, data);
			else gcvt(*entry->data_.dptr, len, data);
			break;
			case CDEV_STRING:
			if(nelem==1) cdevStrncpy(data, entry->data_.str, len);
			else cdevStrncpy(data, entry->data_.strarr[0], len);
			data[len-1] = 0;
			break;
			case CDEV_TIMESTAMP:
			if(nelem==1)
				cdevStrncpy(data, ctime((time_t *)&(entry->data_.ts.secPastEpoch)), len);
			data[len-1] = 0;
			break;

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

// *****************************************************************************
// * get:
// *	This function retrieves a char string array specified by tag from the
// *	cdevData object.  For simplicity, this method operates differently
// *	than the other get methods.
// *****************************************************************************
int cdevData::get(int tag, char ** data)
	{
	int result, nelem=1;
	cdevDataEntry * entry;

	if(data==NULL) result = CDEV_INVALIDARG;
	else if((entry=lookupTag(tag, 0))==NULL) result = CDEV_NOTFOUND;
	else
		{
		if(entry->dim_ > 0)
			cdevConversionMatrix[entry->dataType_][CDEV_STRING]
			(entry->data_.vptr, data, entry->elems_);
		else	cdevConversionMatrix[entry->dataType_][CDEV_STRING]
		(&entry->data_, data, 1);

		result = CDEV_SUCCESS;
		}
	return result;
	}

// *****************************************************************************
// * find:
// *	Allows the user to directly extract a pointer to the internal data
// *	buffer that the cdevDataEntry object uses to store data.
// *****************************************************************************
int cdevData::find(int tag, void* &data)
	{
	int result = CDEV_NOTFOUND;
	cdevDataEntry * entry;
	if((entry=lookupTag(tag, 0))!=NULL)
		{
		if(entry->dim_>0 || entry->dataType_==CDEV_STRING) data = entry->data_.vptr;
		else data = &entry->data_;
		result = CDEV_SUCCESS;
		}
	else data = NULL;
	return result;
	}


// *****************************************************************************
// * operator == :
// *	This method will allow the caller to rapidly determine if two cdevData
// *	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 cdevDataEntry objects
// *	that are stored in each object and will use their embedded comparison
// *	operators to compare the contents of each of them.
// *****************************************************************************
int cdevData::operator == ( cdevData & data )
	{
	int result = 1;
	cdevDataEntry *entry1, *entry2;
	int entry1Cnt=0, entry2Cnt=0;

	for(entry1=entries; entry1!=NULL; entry1=entry1->next_) entry1Cnt++;
	for(entry2=data.entries; entry2!=NULL; entry2=entry2->next_) entry2Cnt++;
	if(entry1Cnt==entry2Cnt)
		{
		result = 0;
		for(entry1=entries; !result && entry1!=NULL; entry1=entry1->next_)
			{
			if((entry2 = data.lookupTag(entry1->tag_))!=NULL)
				{
				result = !(entry1->operator == (*entry2));
				}
			else result = -1;
			}
		}
	return !result;
	}

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

			case CDEV_INT16:
			if(ptr->dim_==0) insert(ptr->tag_, ptr->data_.sval);
			else insert(ptr->tag_, ptr->data_.sptr, ptr->elems_, ptr->dim_);
			break;

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

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

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

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

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

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

			case CDEV_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(ptr->tag_ && ptr->dim_ && ptr->dataType_<CDEV_INVALID)
			setBounds(ptr->tag_, ptr->bounds(), ptr->dim_);
		}
	return *this;
	}


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

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

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

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

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

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

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

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

// *****************************************************************************
// * cdevConvert:
// *	8 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void cdevConvert_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]));
		}
	}

// *****************************************************************************
// * cdevConvert:
// *	8 Bit Integer to Timestamp Conversion Facilities
// *****************************************************************************
void cdevConvert_BYTE_to_TIMESTAMP ( void * input, void * output, size_t nElems )
	{
	while(nElems>0)
		{
		nElems--;
		((cdev_TS_STAMP *)output)[nElems].secPastEpoch = (unsigned long)((BYTE *)input)[nElems];
		((cdev_TS_STAMP *)output)[nElems].nsec = 0;
		}
	}

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

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

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

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

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

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

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

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

// *****************************************************************************
// * cdevConvert:
// *	16 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void cdevConvert_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]));
		}
	}

// *****************************************************************************
// * cdevConvert:
// *	16 Bit Integer to Timestamp Conversion Facilities
// *****************************************************************************
void cdevConvert_INT16_to_TIMESTAMP ( void * input, void * output, size_t nElems )
	{
	while(nElems>0)
		{
		nElems--;
		((cdev_TS_STAMP *)output)[nElems].secPastEpoch = (unsigned long)((short *)input)[nElems];
		((cdev_TS_STAMP *)output)[nElems].nsec = 0;
		}
	}

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

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

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

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

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

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

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

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

// *****************************************************************************
// * cdevConvert:
// *	Unsigned 16 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void cdevConvert_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]));
		}
	}

// *****************************************************************************
// * cdevConvert:
// *	Unsigned 16 Bit Integer to Timestamp Conversion Facilities
// *****************************************************************************
void cdevConvert_UINT16_to_TIMESTAMP ( void * input, void * output, size_t nElems )
	{
	while(nElems>0)
		{
		nElems--;
		((cdev_TS_STAMP *)output)[nElems].secPastEpoch=(unsigned long)((unsigned short *)input)[nElems];
		((cdev_TS_STAMP *)output)[nElems].nsec = 0;
		}
	}

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

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

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

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

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

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

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

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

// *****************************************************************************
// * cdevConvert:
// *	32 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void cdevConvert_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]));
		}
	}

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

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

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

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

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

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

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

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

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

// *****************************************************************************
// * cdevConvert:
// *	Unsigned 32 Bit Integer to String Array Conversion Facilities
// *****************************************************************************
void cdevConvert_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]));
		}
	}

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	}

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

	}

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

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

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

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

// *****************************************************************************
// * cdevConvert:
// *	String Array to String Array Conversion Facilities
// *****************************************************************************
void cdevConvert_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]);
		}
	}

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

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


// *****************************************************************************
// * cdevConvert:
// *	Time Stamp to 8 Bit Integer Conversion Facilities
// *****************************************************************************
void cdevConvert_TIMESTAMP_to_BYTE ( void * input, void * output, size_t nElems )
	{
	while(nElems>0)
		{
		nElems--;
		((char *)output)[nElems] = (char)(((cdev_TS_STAMP *)input)[nElems].secPastEpoch);
		}
	}

// *****************************************************************************
// * cdevConvert:
// *	Time Stamp to 16 Bit Integer Conversion Facilities
// *****************************************************************************
void cdevConvert_TIMESTAMP_to_INT16 ( void * input, void * output, size_t nElems )
	{
	while(nElems>0)
		{
		nElems--;
		((short *)output)[nElems] = (short)(((cdev_TS_STAMP *)input)[nElems].secPastEpoch);
		}
	}

// *****************************************************************************
// * cdevConvert:
// *	Time Stamp to Unsigned 16 Bit Integer Conversion Facilities
// *****************************************************************************
void cdevConvert_TIMESTAMP_to_UINT16 ( void * input, void * output, size_t nElems )
	{
	while(nElems>0)
		{
		nElems--;
		((unsigned short *)output)[nElems]=
			(unsigned short)(((cdev_TS_STAMP *)input)[nElems].secPastEpoch);
		}
	}

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

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

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

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

// *****************************************************************************
// * cdevConvert:
// *	Time Stamp to Char String Conversion Facilities
// *****************************************************************************
void cdevConvert_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 *)(&(((cdev_TS_STAMP *)input)[nElems].secPastEpoch))) );
		}
	}

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

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

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

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

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

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

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

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

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

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

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

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


// *****************************************************************************
// * cdevConversionMatrix:
// *	Instanciation of the conversion matrix defined at the beginning of this
// *	file.
// *****************************************************************************
const cdevConverter cdevConversionMatrix [CDEV_INVALID+1][CDEV_INVALID+1] =
	{
		{
		cdevConvert_BYTE_to_BYTE,
		cdevConvert_BYTE_to_INT16,
		cdevConvert_BYTE_to_UINT16,
		cdevConvert_BYTE_to_INT32,
		cdevConvert_BYTE_to_UINT32,
		cdevConvert_BYTE_to_FLOAT,
		cdevConvert_BYTE_to_DOUBLE,
		cdevConvert_BYTE_to_STRING,
		cdevConvert_BYTE_to_TIMESTAMP,
		cdevConvert_BYTE_to_INVALID
		},
		{
		cdevConvert_INT16_to_BYTE,
		cdevConvert_INT16_to_INT16,
		cdevConvert_INT16_to_UINT16,
		cdevConvert_INT16_to_INT32,
		cdevConvert_INT16_to_UINT32,
		cdevConvert_INT16_to_FLOAT,
		cdevConvert_INT16_to_DOUBLE,
		cdevConvert_INT16_to_STRING,
		cdevConvert_INT16_to_TIMESTAMP,
		cdevConvert_INT16_to_INVALID,
		},
		{
		cdevConvert_UINT16_to_BYTE,
		cdevConvert_UINT16_to_INT16,
		cdevConvert_UINT16_to_UINT16,
		cdevConvert_UINT16_to_INT32,
		cdevConvert_UINT16_to_UINT32,
		cdevConvert_UINT16_to_FLOAT,
		cdevConvert_UINT16_to_DOUBLE,
		cdevConvert_UINT16_to_STRING,
		cdevConvert_UINT16_to_TIMESTAMP,
		cdevConvert_UINT16_to_INVALID,
		},
		{
		cdevConvert_INT32_to_BYTE,
		cdevConvert_INT32_to_INT16,
		cdevConvert_INT32_to_UINT16,
		cdevConvert_INT32_to_INT32,
		cdevConvert_INT32_to_UINT32,
		cdevConvert_INT32_to_FLOAT,
		cdevConvert_INT32_to_DOUBLE,
		cdevConvert_INT32_to_STRING,
		cdevConvert_INT32_to_TIMESTAMP,
		cdevConvert_INT32_to_INVALID,
		},
		{
		cdevConvert_UINT32_to_BYTE,
		cdevConvert_UINT32_to_INT16,
		cdevConvert_UINT32_to_UINT16,
		cdevConvert_UINT32_to_INT32,
		cdevConvert_UINT32_to_UINT32,
		cdevConvert_UINT32_to_FLOAT,
		cdevConvert_UINT32_to_DOUBLE,
		cdevConvert_UINT32_to_STRING,
		cdevConvert_UINT32_to_TIMESTAMP,
		cdevConvert_UINT32_to_INVALID,
		},
		{
		cdevConvert_FLOAT_to_BYTE,
		cdevConvert_FLOAT_to_INT16,
		cdevConvert_FLOAT_to_UINT16,
		cdevConvert_FLOAT_to_INT32,
		cdevConvert_FLOAT_to_UINT32,
		cdevConvert_FLOAT_to_FLOAT,
		cdevConvert_FLOAT_to_DOUBLE,
		cdevConvert_FLOAT_to_STRING,
		cdevConvert_FLOAT_to_TIMESTAMP,
		cdevConvert_FLOAT_to_INVALID,
		},
		{
		cdevConvert_DOUBLE_to_BYTE,
		cdevConvert_DOUBLE_to_INT16,
		cdevConvert_DOUBLE_to_UINT16,
		cdevConvert_DOUBLE_to_INT32,
		cdevConvert_DOUBLE_to_UINT32,
		cdevConvert_DOUBLE_to_FLOAT,
		cdevConvert_DOUBLE_to_DOUBLE,
		cdevConvert_DOUBLE_to_STRING,
		cdevConvert_DOUBLE_to_TIMESTAMP,
		cdevConvert_DOUBLE_to_INVALID,
		},
		{
		cdevConvert_STRING_to_BYTE,
		cdevConvert_STRING_to_INT16,
		cdevConvert_STRING_to_UINT16,
		cdevConvert_STRING_to_INT32,
		cdevConvert_STRING_to_UINT32,
		cdevConvert_STRING_to_FLOAT,
		cdevConvert_STRING_to_DOUBLE,
		cdevConvert_STRING_to_STRING,
		cdevConvert_STRING_to_TIMESTAMP,
		cdevConvert_STRING_to_INVALID,
		},
		{
		cdevConvert_TIMESTAMP_to_BYTE,
		cdevConvert_TIMESTAMP_to_INT16,
		cdevConvert_TIMESTAMP_to_UINT16,
		cdevConvert_TIMESTAMP_to_INT32,
		cdevConvert_TIMESTAMP_to_UINT32,
		cdevConvert_TIMESTAMP_to_FLOAT,
		cdevConvert_TIMESTAMP_to_DOUBLE,
		cdevConvert_TIMESTAMP_to_STRING,
		cdevConvert_TIMESTAMP_to_TIMESTAMP,
		cdevConvert_TIMESTAMP_to_INVALID,
		},
		{
		cdevConvert_INVALID_to_BYTE,
		cdevConvert_INVALID_to_INT16,
		cdevConvert_INVALID_to_UINT16,
		cdevConvert_INVALID_to_INT32,
		cdevConvert_INVALID_to_UINT32,
		cdevConvert_INVALID_to_FLOAT,
		cdevConvert_INVALID_to_DOUBLE,
		cdevConvert_INVALID_to_STRING,
		cdevConvert_INVALID_to_TIMESTAMP,
		cdevConvert_INVALID_to_INVALID,
		}
	};


// *****************************************************************************
// *cdevDataIterator:
// *
// *****************************************************************************
cdevDataIterator::cdevDataIterator(cdevData* data)
	{
	dataobj_ = data;
	cur_ = 0;
	}

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

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

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

int cdevDataIterator::tag(void)
	{
	return (cur_!=0)?cur_->tag_:0;
	}

// *****************************************************************************
// * 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

// *****************************************************************************
// * asciiDump:
// *	This function will dump the contents of the cdevData object to the
// *	user specified file descriptor.
// *****************************************************************************
#ifdef _WIN32
void cdevData::asciiDump ( long osfHandle )
	{
	int    fd = _open_osfhandle(osfHandle, _O_WRONLY | _O_APPEND );
	FILE * fp = _fdopen ( fd, "a");
#else
void cdevData::asciiDump ( FILE * fp )
	{
#endif

	cdevDataEntry * entry;
	char tagText[CDEV_INVALID+1][20];

	// *************************************
	// * Load the names of the dataTypes   *
	// *************************************
	sprintf(tagText[CDEV_BYTE],    "8 Bit Integer");
	sprintf(tagText[CDEV_INT16],   "16 Bit Integer");
	sprintf(tagText[CDEV_UINT16],  "Unsigned 16 Bit Int");
	sprintf(tagText[CDEV_INT32],   "32 Bit Integer");
	sprintf(tagText[CDEV_UINT32],  "Unsigned 32 Bit Int");
	sprintf(tagText[CDEV_FLOAT],   "Float");
	sprintf(tagText[CDEV_DOUBLE],  "Double");
	sprintf(tagText[CDEV_STRING],  "Char String");
	sprintf(tagText[CDEV_TIMESTAMP],  "Time Stamp");
	sprintf(tagText[CDEV_INVALID], "Invalid Data");

	for(entry=entries; entry!=NULL; entry=entry->next_)
		{
		char * tagName;
		int i;

		cdevGlobalTagTable::tagTable()->tagI2C(entry->tag_, tagName);

		fprintf(fp, "Tag:       %-5i\n", entry->tag_);
		fprintf(fp, "Tag Name:  %s\n",  tagName);
		fprintf(fp, "Data Type: %s", tagText[entry->dataType_]);
		for(i=0; i<entry->dim_; i++)
			{
			fprintf(fp, "[%i]", entry->bounds()[i].length);
			}
		fprintf(fp, "\nValues:    ");

		switch(entry->dataType_)
			{
			case CDEV_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 CDEV_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 CDEV_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 CDEV_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 CDEV_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 CDEV_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 CDEV_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 CDEV_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 CDEV_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 CDEV_INVALID:
			break;
			}
		fprintf(fp, "\n\n");
		}
	fflush(fp);
#ifdef _WIN32
	_commit(fd);
#endif
	}
