#include "precomp.h"
#include "fsdiag.h"
DEBUG_FILEZONE(ZONE_T120_GCCNC);

/* 
 *	userdata.cpp
 *
 *	Copyright (c) 1995 by DataBeam Corporation, Lexington, KY
 *
 *	Abstract:
 *		This is the implementation file for the class CUserDataListContainer. CUserDataListContainer
 *		objects are used to maintain user data elements. A user data element
 *		consists of an Object Key and an optional octet string.  The Object
 *		Key data is maintained internally by this class by using an
 *		CObjectKeyContainer container.  The optional octet string data is maintained
 *		internally through the use of a Rogue Wave string container.
 *
 *	Protected Instance Variables:
 *		m_UserDataItemList
 *			List of structures used to hold the user data internally.
 *		m_pSetOfUserDataPDU
 *			Storage for the "PDU" form of the user data.
 *		m_cbDataSize
 *			Variable holding the size of the memory which will be required to
 *			hold any data referenced by the "API" GCCUserData structure.
 *
 *	Caveats:
 *		None.
 *
 *	Author:
 *		jbo
 */

#include "userdata.h"
#include "clists.h"

USER_DATA::~USER_DATA(void)
{
	if (NULL != key)
    {
        key->Release();
    }
	delete poszOctetString;
}

/*
 *	CUserDataListContainer()
 *
 *	Public Function Description
 *		This CUserDataListContainer constructor is used to create a CUserDataListContainer object
 *		from "API" data.  The constructor immediately copies the user data 
 *		passed in as a list of "GCCUserData" structures into it's internal form
 *		where a Rogue Wave container holds the data in the form of 
 *		USER_DATA structures.
 */
CUserDataListContainer::
CUserDataListContainer(UINT cMembers, PGCCUserData *user_data_list, PGCCError pRetCode)
:
    CRefCount(MAKE_STAMP_ID('U','r','D','L')),
    m_UserDataItemList(DESIRED_MAX_USER_DATA_ITEMS),
    m_cbDataSize(0),
    m_pSetOfUserDataPDU(NULL)
{
	/*
	 * Copy the user data into the internal structures.
	 */
	*pRetCode = CopyUserDataList(cMembers, user_data_list);
}

/*
 *	CUserDataListContainer()
 *
 *	Public Function Description
 *		This CUserDataListContainer constructor is used to create a CUserDataListContainer object 
 *		from data passed in as a "PDU" SetOfUserData structure.  The user
 *		data is copied into it's internal form where a Rogue Wave container 
 *		holds the data in the form of USER_DATA structures.
 */
CUserDataListContainer::
CUserDataListContainer(PSetOfUserData set_of_user_data, PGCCError pRetCode)
:
    CRefCount(MAKE_STAMP_ID('U','r','D','L')),
    m_UserDataItemList(DESIRED_MAX_USER_DATA_ITEMS),
    m_cbDataSize(0),
    m_pSetOfUserDataPDU(NULL)
{
	/*
	 * Copy the user data into the internal structures.
	 */
	*pRetCode = UnPackUserDataFromPDU(set_of_user_data);
}

/*
 *	CUserDataListContainer()
 *
 *	Public Function Description
 *		This CUserDataListContainer copy constructor is used to create a CUserDataListContainer 
 *		object from	another CUserDataListContainer object.  The constructor immediately
 *		copies the user data passed in into it's internal form where a Rogue 
 *		Wave list holds the data in the form of USER_DATA structures.
 */
CUserDataListContainer::
CUserDataListContainer(CUserDataListContainer *user_data_list, PGCCError pRetCode)
:
    CRefCount(MAKE_STAMP_ID('U','r','D','L')),
    m_UserDataItemList(DESIRED_MAX_USER_DATA_ITEMS),
    m_cbDataSize(0),
    m_pSetOfUserDataPDU(NULL)
{
	GCCError		rc;
	USER_DATA       *user_data_info_ptr;
	USER_DATA       *lpUsrDataInfo;

	/*
	 * Set up an iterator for the internal list of "info" structures in the
	 * CUserDataListContainer object to be copied.
	 */
	user_data_list->m_UserDataItemList.Reset();

	/*
	 * Copy each USER_DATA structure contained in the CUserDataListContainer object to
	 * be copied.
	 */
	while (NULL != (lpUsrDataInfo = user_data_list->m_UserDataItemList.Iterate()))
	{
		/*
		 * Create a new USER_DATA structure to hold each element of the new
		 * CUserDataListContainer object.  Report an error if creation of this structure
		 * fails.
		 */
		DBG_SAVE_FILE_LINE
		user_data_info_ptr = new USER_DATA;
		if (user_data_info_ptr != NULL)
		{
		    user_data_info_ptr->poszOctetString = NULL;

			/*
			 * Go ahead and insert the pointer to the USER_DATA structure
			 * into the internal Rogue Wave list.
			 */
			m_UserDataItemList.Append(user_data_info_ptr);

			/*
			 * Create a new CObjectKeyContainer object to hold the "key" using the 
			 * copy constructor for the CObjectKeyContainer class.  Check to be sure
			 * construction of the object is successful.  Note that validation
			 * of the object key data is not done here since this would be done
			 * when the original CUserDataListContainer object was created.
			 */
    		DBG_SAVE_FILE_LINE
			user_data_info_ptr->key = new CObjectKeyContainer(lpUsrDataInfo->key, &rc);
			if ((NULL != user_data_info_ptr->key) && (GCC_NO_ERROR == rc))
			{
    			/*
    			 * If an octet string exists, create a new Rogue Wave string to hold
    			 * the octet string portion	of the "key" and copy the octet string 
    			 * from the old CUserDataListContainer object into the new USER_DATA 
    			 * structure.
    			 */
    			if (lpUsrDataInfo->poszOctetString != NULL)
    			{
    				if (NULL == (user_data_info_ptr->poszOctetString =
    									::My_strdupO(lpUsrDataInfo->poszOctetString)))
    				{
    					ERROR_OUT(("UserData::UserData: can't create octet string"));
    					rc = GCC_ALLOCATION_FAILURE;
    					goto MyExit;
    				}
    			}
    			else
    			{
    				ASSERT(NULL == user_data_info_ptr->poszOctetString);
    			}
			}
            else
			{
				ERROR_OUT(("UserData::UserData: Error creating new ObjectKeyData"));
				rc = GCC_ALLOCATION_FAILURE;
				goto MyExit;
			}
		}
		else
		{
			ERROR_OUT(("UserData::UserData: can't create USER_DATA"));
			rc = GCC_ALLOCATION_FAILURE;
			goto MyExit;
		}
	}

    rc = GCC_NO_ERROR;

MyExit:

    *pRetCode = rc;
}

/*
 *	~CUserDataListContainer()
 *
 *	Public Function Description
 *		This is the destructor for the CUserDataListContainer class.  It is used to
 *		clean up any memory allocated during the life of this object.
 */
CUserDataListContainer::
~CUserDataListContainer(void)
{
	/*
	 * Free any PDU data which may have not been freed.
	 */
	if (m_pSetOfUserDataPDU)
    {
		FreeUserDataListPDU();
    }

	/*
	 * Set up an iterator to use for iterating through the internal Rogue
	 * Wave list of USER_DATA structures.
	 */
	USER_DATA  *pUserDataItem;
	m_UserDataItemList.Reset();
	while (NULL != (pUserDataItem = m_UserDataItemList.Iterate()))
	{
		/*
		 * Delete any memory being referenced in the USER_DATA structure.
		 */
		delete pUserDataItem;
	}
}


/*
 *	LockUserDataList ()
 *
 *	Public Function Description:
 *		This routine locks the user data list and determines the amount of
 *		memory referenced by the "API" user data list structures.
 */
UINT CUserDataListContainer::
LockUserDataList(void)
{
	/*
	 * If this is the first time this routine is called, determine the size of 
	 * the memory required to hold the data.  Otherwise, just increment the 
	 * lock count.
	 */
	if (Lock() == 1)
	{
		USER_DATA *lpUsrDataInfo;
		/*
		 * Set aside memory to hold the pointers to the GCCUserData structures
		 * as well as the structures themselves.  The "sizeof" the structure 
		 * must be rounded to an even four-byte boundary.
		 */
		m_cbDataSize = m_UserDataItemList.GetCount() * 
				(sizeof(PGCCUserData) + ROUNDTOBOUNDARY(sizeof(GCCUserData)) );

		m_UserDataItemList.Reset();
	 	while (NULL != (lpUsrDataInfo = m_UserDataItemList.Iterate()))
		{
			/*
			 * Lock the data for the object keys, adding the amount of memory
			 * necessary to hold the object key data to the total memory size.
			 */
			m_cbDataSize += lpUsrDataInfo->key->LockObjectKeyData();

			/*
			 * Check to see if this user data element contains the optional
			 * user data octet string.  Add the space to hold it if it exists.
			 */
			if (lpUsrDataInfo->poszOctetString != NULL)
			{
				/*
				 * Since the user data structure contains a pointer to a
				 * OSTR structure, we must add the amount of memory
				 * needed to hold the structure as well as the string data.
				 */
				m_cbDataSize += ROUNDTOBOUNDARY(sizeof(OSTR));

				/*
				 * The data referenced by the octet string is just the byte
				 * length of the octet string.
				 */
				m_cbDataSize += ROUNDTOBOUNDARY(lpUsrDataInfo->poszOctetString->length);
			}
		}
	}

	return m_cbDataSize;
}

/*
 *	GetUserDataList	()
 *
 *	Public Function Description:
 *		This routine retrieves user data elements contained in the user data
 *		object and returns them in the "API" form of a list of pointers to 
 *		"GCCUserData" structures.  The number of user data elements contained 
 *		in this object is also returned.
 */
UINT CUserDataListContainer::
GetUserDataList(USHORT *number_of_members, PGCCUserData **user_data_list, LPBYTE memory)
{
	UINT			cbDataSizeToRet = 0;
	UINT			data_length = 0;
	Int				user_data_counter = 0;
	PGCCUserData	user_data_ptr;
	
	/*
	 * If the user data has been locked, fill in the output parameters and
	 * the data referenced by the pointers.  Otherwise, report that the object
	 * has yet to be locked into the "API" form.
	 */ 
	if (GetLockCount() > 0)
	{
		USER_DATA  *lpUsrDataInfo;
		/*
		 * Fill in the output length parameter which indicates how much data
		 * referenced outside the structure will be written.
		 */
		cbDataSizeToRet = m_cbDataSize;

		/*
		 * Fill in the number of user data entities and save a pointer to the 
		 * memory location passed in.  This is where the pointers to the 
		 * GCCUserData structures will be written.  The actual structures will 
		 * be written into memory immediately following the list of pointers.
		 */
		*number_of_members = (USHORT) m_UserDataItemList.GetCount();

		*user_data_list = (PGCCUserData *)memory;

		/*
		 * Save the amount of memory needed to hold the list of pointers
		 * as well as the actual user data structures.
		 */
		data_length = m_UserDataItemList.GetCount() * sizeof(PGCCUserData);

		/*
		 * Move the memory pointer past the list of user data pointers.  This 
		 * is where the first user data structure will be written.
		 */
		memory += data_length;

		/*
		 * Iterate through the internal list of USER_DATA structures,
		 * building "API" GCCUserData structures in memory.
		 */
		m_UserDataItemList.Reset();
		while (NULL != (lpUsrDataInfo = m_UserDataItemList.Iterate()))
		{
			/*
			 * Save the pointer to the user data structure in the list 
			 * of pointers.
			 */
			user_data_ptr = (PGCCUserData)memory;
			(*user_data_list)[user_data_counter++] = user_data_ptr;

			/*
			 * Move the memory pointer past the user data structure.  This is 
			 * where the object key data and octet string data will be written.
			 */
			memory += ROUNDTOBOUNDARY(sizeof(GCCUserData));

			/*
			 * Fill in the user data structure starting with the object key.
			 */
			data_length = lpUsrDataInfo->key->GetGCCObjectKeyData(&user_data_ptr->key, memory);

			/*
			 * Move the memory pointer past the object key data.  This is 
			 * where the octet string structure will be written, if it exists.
			 * If the octet string does exist, save the memory pointer in the 
			 * user data structure's octet string pointer and fill in the 
			 * elements of the octet string structure.  Otherwise, set the
			 * octet string pointer to NULL.
			 */
			memory += data_length;

			if (lpUsrDataInfo->poszOctetString == NULL)
            {
				user_data_ptr->octet_string = NULL;
            }
			else
			{
				user_data_ptr->octet_string = (LPOSTR) memory;

				/*
				 * Move the memory pointer past the octet string structure.  
				 * This is where the actual string data for the octet string 
				 * will be written.
				 */
				memory += ROUNDTOBOUNDARY(sizeof(OSTR));

				/*
				 * Write the octet string data into memory and set the octet 
				 * string structure pointer and length.
				 */
				user_data_ptr->octet_string->length =
					lpUsrDataInfo->poszOctetString->length;
				user_data_ptr->octet_string->value = (LPBYTE)memory;

				/*
				 * Now copy the octet string data from the internal Rogue Wave
				 * string into the object key structure held in memory.
				 */		
				::CopyMemory(memory, lpUsrDataInfo->poszOctetString->value,
							lpUsrDataInfo->poszOctetString->length);

				/*
				 * Move the memory pointer past the octet string data.
				 */
				memory += ROUNDTOBOUNDARY(user_data_ptr->octet_string->length);
			}
		}
	}
	else
	{
    	*user_data_list = NULL;
		*number_of_members = 0;
		ERROR_OUT(("CUserDataListContainer::GetUserDataList: Error Data Not Locked"));
	}
	
	return cbDataSizeToRet;
}

/*
 *	UnLockUserDataList	()
 *
 *	Public Function Description:
 *		This routine is used to "unlock" the "API" data for this object.  This
 *		results in the lock count for this object being decremented.  When the
 *		lock count transitions from 1 to 0, a check is made to determine 
 *		whether the object has been freed through a call to 
 *		FreeUserDataList.  If so, the object will automatically delete
 *		itself.
 */
void CUserDataListContainer::
UnLockUserDataList(void)
{
	USER_DATA  *user_data_info_ptr;

	if (Unlock(FALSE) == 0)
	{
		/*
		 * Unlock any memory locked for the CObjectKeyContainer objects in the
		 * internal USER_DATA structures.
		 */
		m_UserDataItemList.Reset();
		while (NULL != (user_data_info_ptr = m_UserDataItemList.Iterate()))
		{
			/*
			 * Unlock any CObjectKeyContainer memory being referenced in the 
			 * USER_DATA structure.
			 */
			if (user_data_info_ptr->key != NULL)
			{
				user_data_info_ptr->key->UnLockObjectKeyData ();
			}
		}
	}

    // we have to call Release() because we used Unlock(FALSE)
    Release();
}

/*
 *	GetUserDataPDU	()
 *
 *	Public Function Description:
 *		This routine converts the user data from it's internal form of a list
 *		of USER_DATA structures into the "PDU" form which can be passed in
 *		to the ASN.1 encoder.  A pointer to a "PDU" "SetOfUserData" structure is 
 *		returned.
 */
GCCError CUserDataListContainer::
GetUserDataPDU(PSetOfUserData *set_of_user_data)
{
	GCCError				rc = GCC_NO_ERROR;
	PSetOfUserData			new_pdu_user_data_ptr;
	PSetOfUserData			old_pdu_user_data_ptr = NULL;

	/*
	 * If this is the first time that PDU data has been requested then we must
	 * fill in the internal PDU structure and copy it into the structure pointed
	 * to by the output parameter.  On subsequent calls to "GetPDU" we can just
	 * copy the internal PDU structure into the structure pointed to by the
	 * output parameter.
	 */
	if (NULL == m_pSetOfUserDataPDU)
	{
		USER_DATA  *lpUsrDataInfo;

		/*
		 * Iterate through the list of USER_DATA structures, converting 
		 * each into "PDU" form and saving the pointers in the linked list of 
		 * "SetsOfUserData".
		 */
		m_UserDataItemList.Reset();
		while (NULL != (lpUsrDataInfo = m_UserDataItemList.Iterate()))
		{
			DBG_SAVE_FILE_LINE
			new_pdu_user_data_ptr = new SetOfUserData;

			/*
			 * If an allocation failure occurs, call the routine which will
			 * iterate through the list freeing any data which had been
			 * allocated.
			 */
			if (new_pdu_user_data_ptr == NULL)
			{
				ERROR_OUT(("CUserDataListContainer::GetUserDataPDU: Allocation error, cleaning up"));
				rc = GCC_ALLOCATION_FAILURE;
				break;
			}

			//
			// Ensure everything is clean.
			//
			::ZeroMemory(new_pdu_user_data_ptr, sizeof(SetOfUserData));

			/*
			 * The first time through, set the PDU structure pointer equal
			 * to the first SetOfUserData created.  On subsequent loops, set
			 * the structure's "next" pointer equal to the new structure.
			 */
			if (m_pSetOfUserDataPDU == NULL)
			{
				m_pSetOfUserDataPDU = new_pdu_user_data_ptr;
			}
			else
            {
				old_pdu_user_data_ptr->next = new_pdu_user_data_ptr;
            }

			old_pdu_user_data_ptr = new_pdu_user_data_ptr;

			/*
			 * Initialize the new "next" pointer to NULL and convert the
			 * user data element.
			 */
			new_pdu_user_data_ptr->next = NULL;

			if (ConvertUserDataInfoToPDUUserData(lpUsrDataInfo, new_pdu_user_data_ptr) != GCC_NO_ERROR)
			{
				ERROR_OUT(("UserData::GetUserDataPDU: can't convert USER_DATA to PDU"));
				rc = GCC_ALLOCATION_FAILURE;
				break;
			}
		}

		if (GCC_NO_ERROR != rc)
		{
			FreeUserDataListPDU();
			ASSERT(NULL == m_pSetOfUserDataPDU);
		}
	}

	/*
	 * Copy the internal PDU structure into the structure pointed to by the
	 * output parameter.
	 */
	*set_of_user_data = m_pSetOfUserDataPDU;

	return rc;
}

/*
 *	FreeUserDataListPDU	()
 *
 *	Public Function Description:
 *		This routine frees any data which was allocated as a result of a call
 *		to "GetUserDataPDU" which was called in order to build up a "PDU"
 *		structure holding the user data.
 */
void CUserDataListContainer::
FreeUserDataListPDU(void)
{
	PSetOfUserData		pdu_user_data_set;
	PSetOfUserData		next_pdu_user_data_set;
	USER_DATA           *lpUsrDataInfo;

	/*
	 * Check to make sure "PDU" data has been allocated for this object.
	 */
	if (NULL != m_pSetOfUserDataPDU)
	{
		pdu_user_data_set = m_pSetOfUserDataPDU;
        m_pSetOfUserDataPDU = NULL; // so no one can use it now.

		/*
		 * Loop through the list, freeing the user data associated with 
		 * each structure contained in the list.
		 */
		while (pdu_user_data_set != NULL)
		{
			next_pdu_user_data_set = pdu_user_data_set->next;
			delete pdu_user_data_set;
			pdu_user_data_set = next_pdu_user_data_set;
		}
	}
	else
	{
		TRACE_OUT(("CUserDataListContainer::FreeUserDataListPDU: Error PDU data not allocated"));
	}

	/*
	 * Iterate through the internal list, telling each CObjectKeyContainer object
	 * to free any PDU data which it has allocated.
	 */
	m_UserDataItemList.Reset();
	while (NULL != (lpUsrDataInfo = m_UserDataItemList.Iterate()))
	{
		if (lpUsrDataInfo->key != NULL)
        {
			lpUsrDataInfo->key->FreeObjectKeyDataPDU();
        }
	}
}

/*
 *	GCCError	CopyUserDataList ( 	UINT					number_of_members,
 *									PGCCUserData	*		user_data_list)
 *
 *	Private member function of CUserDataListContainer.
 *
 *	Function Description:
 *		This routine copies the user data passed in as "API" data into it's
 *		internal form where the Rogue Wave m_UserDataItemList holds the data
 *		in the form of USER_DATA structures.
 *
 *	Formal Parameters:
 *		number_of_members	(i) The number of elements in the user data list.
 *		user_datalist		(i)	The list holding the user data to store.
 *
 *	Return Value:
 *		GCC_NO_ERROR					-	No error.
 *		GCC_ALLOCATION_FAILURE			- 	Error creating an object using the
 *												"new" operator.
 *		GCC_BAD_USER_DATA				-	The user data passed in contained
 *												an invalid object key.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
GCCError CUserDataListContainer::
CopyUserDataList(UINT number_of_members, PGCCUserData *user_data_list)
{
	GCCError				rc = GCC_NO_ERROR;
	USER_DATA			    *user_data_info_ptr;
	UINT					i;
	LPOSTR      			octet_string_ptr;

	/*
	 * Return an error if no user data is passed in.
	 */
	if (number_of_members == 0)
		return (GCC_BAD_USER_DATA);

	for (i = 0; i < number_of_members; i++)
	{
		/*
		 * Create a new "info" structure to hold the user data internally.
		 */
		DBG_SAVE_FILE_LINE
		user_data_info_ptr = new USER_DATA;
		if (user_data_info_ptr != NULL)
		{
		    user_data_info_ptr->poszOctetString = NULL;

			/*
			 * Create a new CObjectKeyContainer object which will be used to store
			 * the "key" portion of the object data internally.
			 */
    		DBG_SAVE_FILE_LINE
			user_data_info_ptr->key = new CObjectKeyContainer(&user_data_list[i]->key, &rc);
			if (user_data_info_ptr->key == NULL)
			{
				ERROR_OUT(("UserData::CopyUserDataList: Error creating new CObjectKeyContainer"));
				rc = GCC_ALLOCATION_FAILURE;
				goto MyExit;
			}
			else if (rc != GCC_NO_ERROR)
			{
				ERROR_OUT(("UserData::CopyUserDataList: Error creating new CObjectKeyContainer - bad data"));
				goto MyExit;
    		}

			/*
			 * Store the optional user data octet string in the list.
			 */
			octet_string_ptr = user_data_list[i]->octet_string;

			if ((octet_string_ptr != NULL) && (rc == GCC_NO_ERROR))
			{
				/*
				 * Create a new Rogue Wave string container to hold the
				 * octet string.
				 */
				if (NULL == (user_data_info_ptr->poszOctetString = ::My_strdupO2(
									octet_string_ptr->value,
									octet_string_ptr->length)))
				{	
					ERROR_OUT(("UserData::CopyUserDataList: can't create octet string"));
					rc = GCC_ALLOCATION_FAILURE;
					goto MyExit;
				}
			}
			else
			{
				ASSERT(NULL == user_data_info_ptr->poszOctetString);
			}
		}
		else
		{
			ERROR_OUT(("UserData::CopyUserDataList: can't create USER_DATA"));
			rc = GCC_ALLOCATION_FAILURE;
			goto MyExit;
		}

		/*
		 * Insert the pointer to the USER_DATA structure into the Rogue Wave list.
		 */
		m_UserDataItemList.Append(user_data_info_ptr);
	}

MyExit:

    if (GCC_NO_ERROR != rc)
    {
        delete user_data_info_ptr;
    }

	return rc;
}

/*
 *	GCCError	UnPackUserDataFromPDU (PSetOfUserData		set_of_user_data)
 *
 *	Private member function of CUserDataListContainer.
 *
 *	Function Description:
 *		This routine unpacks the user data from the "PDU" form into the
 *		internal form which is maintained as a Rogue Wave list of USER_DATA
 *		structures.
 *
 *	Formal Parameters:
 *		set_of_user_data	(i) The "PDU" user data list to copy.
 *
 *	Return Value:
 *		GCC_NO_ERROR					-	No error.
 *		GCC_ALLOCATION_FAILURE			- 	Error creating an object using the
 *												"new" operator.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
GCCError CUserDataListContainer::
UnPackUserDataFromPDU(PSetOfUserData set_of_user_data)
{
	PSetOfUserData		pUserData;
	GCCError			rc = GCC_NO_ERROR;

    for (pUserData = set_of_user_data; NULL != pUserData; pUserData = pUserData->next)
	{ 
		/*
		 * Convert the user data elements into the internal format which
		 * is a USER_DATA structure and insert the pointers to the 
		 * USER_DATA structures into the m_UserDataItemList.
		 */  
		if (ConvertPDUDataToInternal(pUserData) != GCC_NO_ERROR)
		{
			ERROR_OUT(("CUserDataListContainer::UnPackUserDataFromPDU: Error converting PDU data to internal"));
			rc = GCC_ALLOCATION_FAILURE;
			break;
		}
	}

	return rc;
}

/*
 *	GCCError	ConvertPDUDataToInternal ( PSetOfUserData		user_data_ptr)
 *
 *	Private member function of CUserDataListContainer.
 *
 *	Function Description:
 *		This routine converts an individual user data element from the "PDU" 
 *		structure form into	the internal form which is a USER_DATA	
 *		structure.
 *
 *	Formal Parameters:
 *		user_data_ptr		(i) The "PDU" user data list to copy.
 *
 *	Return Value:
 *		GCC_NO_ERROR					-	No error.
 *		GCC_ALLOCATION_FAILURE			- 	Error creating an object using the
 *												"new" operator.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
GCCError CUserDataListContainer::
ConvertPDUDataToInternal(PSetOfUserData user_data_ptr)
{
	USER_DATA   		*user_data_info_ptr;
	GCCError			rc = GCC_NO_ERROR;

	DBG_SAVE_FILE_LINE
	user_data_info_ptr = new USER_DATA;
	if (user_data_info_ptr != NULL)
	{
	    user_data_info_ptr->poszOctetString = NULL;

		/*
		 * Create a new CObjectKeyContainer object which will be used to store the
		 * "key" portion of the user data internally.  If an error occurs
		 * constructing the key report it.  Otherwise, check for any user data
		 * which may need to be stored.	 Note that any error in creating the 
		 * CObjectKeyContainer object is reported as an allocation failure.  An error
		 * could occur if a bad object	key was received as PDU data but this 
		 * would have originated from some other provider since we validate all
		 * object keys created locally.  We therefore report it as an allocation
		 * failure.
		 */
		DBG_SAVE_FILE_LINE
		user_data_info_ptr->key = new CObjectKeyContainer(&user_data_ptr->user_data_element.key, &rc);
		if ((user_data_info_ptr->key == NULL) || (rc != GCC_NO_ERROR))
		{
			ERROR_OUT(("UserData::ConvertPDUDataToInternal: Error creating new CObjectKeyContainer"));
			rc = GCC_ALLOCATION_FAILURE;
			goto MyExit;
		}
		else
		{
			/*
			 * The object key was successfully saved so store any actual user 
			 * data in the list if it is present.
			 */
			if (user_data_ptr->user_data_element.bit_mask & USER_DATA_FIELD_PRESENT)
			{
				if (NULL == (user_data_info_ptr->poszOctetString = ::My_strdupO2(
								user_data_ptr->user_data_element.user_data_field.value,
								user_data_ptr->user_data_element.user_data_field.length)))
				{	
					ERROR_OUT(("UserData::ConvertPDUDataToInternal: can't create octet string"));
					rc = GCC_ALLOCATION_FAILURE;
					goto MyExit;
				}
			}
			else
			{
				ASSERT(NULL == user_data_info_ptr->poszOctetString);
			}
		}

		/*
		 * Initialize the structure pointers to NULL and insert the pointer
		 * to the USER_DATA structure into the Rogue Wave list.
		 */
		m_UserDataItemList.Append(user_data_info_ptr);
	}
	else
	{
		ERROR_OUT(("UserData::ConvertPDUDataToInternal: can't create USER_DATA"));
		rc = GCC_ALLOCATION_FAILURE;
		// goto MyExit;
	}

MyExit:

    if (GCC_NO_ERROR != rc)
    {
        delete user_data_info_ptr;
    }

	return rc;
}

/*
 *	GCCError	ConvertUserDataInfoToPDUUserData (	
 *									USER_DATA		*user_data_info_ptr,
 *									PSetOfUserData		pdu_user_data_ptr)
 *
 *	Private member function of CUserDataListContainer.
 *
 *	Function Description:
 *		This routine converts the user data from the internal form which is a 
 *		USER_DATA structure into the "PDU" structure form "SetOfUserData".
 *
 *	Formal Parameters:
 *		user_data_info_ptr	(i) The internal user data structure to convert.
 *		pdu_user_data_ptr	(o)	The structure to hold the PDU data after
 *									conversion.
 *
 *	Return Value:
 *		GCC_NO_ERROR					-	No error.
 *		GCC_ALLOCATION_FAILURE			- 	Error creating an object using the
 *												"new" operator.
 *		GCC_INVALID_PARAMETER			-	The internal key pointer was
 *												corrupted.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
GCCError CUserDataListContainer::
ConvertUserDataInfoToPDUUserData(USER_DATA *user_data_info_ptr, PSetOfUserData pdu_user_data_ptr)
{
	GCCError rc = GCC_NO_ERROR;

	/*
	 * Initialize the user data bit mask to zero.
	 */
	pdu_user_data_ptr->user_data_element.bit_mask = 0;

	/*
	 * Fill in the octet string pointer and length if the octet string 
	 * exists.  Set the bit mask indicating that the string exists.
	 */
	if (user_data_info_ptr->poszOctetString != NULL)
	{
		pdu_user_data_ptr->user_data_element.user_data_field.value =
				user_data_info_ptr->poszOctetString->value;
		pdu_user_data_ptr->user_data_element.user_data_field.length =
				user_data_info_ptr->poszOctetString->length;

		pdu_user_data_ptr->user_data_element.bit_mask |= USER_DATA_FIELD_PRESENT;
	}
	
	/*
	 * Fill in the object key data.
	 */
	if (user_data_info_ptr->key != NULL)
	{
		/*
		 * Retrieve the "PDU" object key data from the internal CObjectKeyContainer
		 * object.
		 */
		if (user_data_info_ptr->key->GetObjectKeyDataPDU (
				&pdu_user_data_ptr->user_data_element.key) != GCC_NO_ERROR)
		{
			rc = GCC_ALLOCATION_FAILURE;
		}
	}
	else
	{
		ERROR_OUT(("UserData::ConvertUserDataInfoToPDUUserData: no valid UserDataInfo key"));
		rc = GCC_INVALID_PARAMETER;
	}

	return rc;
}