#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_UTILITY);
/* 
 *	objkey.cpp
 *
 *	Copyright (c) 1995 by DataBeam Corporation, Lexington, KY
 *
 *	Abstract:
 *		This is the implementation file for the class CObjectKeyContainer.  This class 
 *		manages the data associated with an Object Key.  Object Key's are used 
 *		to identify a particular application protocol, whether it is standard or
 *		non-standard.  When used to identify a standard protocol, the Object Key
 *		takes the form of an Object ID which is a series of non-negative 
 *		integers.  This type of Object Key is maintained internally through the
 *		use of a Memory object.  When used to identify a non-standard 
 *		protocol, the Object Key takes the form of an H221 non-standard ID which
 *		is an octet string of no fewer than four octets and no more than 255 
 *		octets.  In this case the Object Key is maintained internally by using a
 *		Rogue Wave string object. 
 *
 *	Protected Instance Variables:
 *		m_InternalObjectKey
 *			Structure used to hold the object key data internally.
 *		m_ObjectKeyPDU
 *			Storage for the "PDU" form of the object key.
 *		m_fValidObjectKeyPDU
 *			Flag indicating that memory has been allocated to hold the internal
 *			"PDU" object key.
 *		m_cbDataSize
 *			Variable holding the size of the memory which will be required to
 *			hold any data referenced by the "API" GCCObjectKey structure.
 *
 *	Caveats:
 *		None.
 *
 *	Author:
 *		jbo
 */
#include "objkey.h"

/*
 *	CObjectKeyContainer()
 *
 *	Public Function Description:
 *		This constructor is used to create an CObjectKeyContainer object from
 *		an "API" GCCObjectKey.
 */
CObjectKeyContainer::CObjectKeyContainer(PGCCObjectKey		 	object_key,
						                PGCCError				pRetCode)
:
    CRefCount(MAKE_STAMP_ID('O','b','j','K')),
    m_fValidObjectKeyPDU(FALSE),
    m_cbDataSize(0)
{
	GCCError                rc = GCC_NO_ERROR;
	BOOL    				object_key_is_valid = TRUE;
	UINT					object_id_size;

	m_InternalObjectKey.object_id_key = NULL;
	m_InternalObjectKey.poszNonStandardIDKey = NULL;

	/*
	 * Check to see what type of key is contained in the object key.
	 * Object ID keys will be stored internally in a Memory object and
	 * non-standard ID keys will be stored internally as Octet Strings.
	 */
	if (object_key->key_type == GCC_OBJECT_KEY)
	{
		/*
		 * The key is of type object ID.  Perform a parameter check for a legal
		 * object ID by examining the first two arcs in the object ID.
		 */
		if (object_key->object_id.long_string_length >= MINIMUM_OBJECT_ID_ARCS)
		{
			object_key_is_valid = ValidateObjectIdValues(
					object_key->object_id.long_string[0],
					object_key->object_id.long_string[1]);
		}
		else
		{
			object_key_is_valid = FALSE;
		}

		if (object_key_is_valid)
		{
			/*
			 * The key is of type Object ID.  Determine the amount of memory
			 * required to hold the Object ID and allocate it.  Copy the Object
			 * ID values from the object key passed in into the internal
			 * structure. 
			 */
			m_InternalObjectKey.object_id_length = object_key->object_id.long_string_length;
			object_id_size = m_InternalObjectKey.object_id_length * sizeof(UINT);
            DBG_SAVE_FILE_LINE
			m_InternalObjectKey.object_id_key = new BYTE[object_id_size];
			if (m_InternalObjectKey.object_id_key != NULL)
			{
				::CopyMemory(m_InternalObjectKey.object_id_key,
				             object_key->object_id.long_string,
				             object_id_size);
			}
			else
			{
				ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer: Error allocating memory"));
				rc = GCC_ALLOCATION_FAILURE;
			}
		}
		else
		{
			ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer: Object ID has illegal values."));
			rc = GCC_BAD_OBJECT_KEY;
		}
	}
	else
	{
		/*
		 * The key is non-standard.  Check to make sure the length of the 
		 * non-standard ID is within the allowable limits.
		 */
		if ((object_key->h221_non_standard_id.length >= 
					MINIMUM_NON_STANDARD_ID_LENGTH) &&
			(object_key->h221_non_standard_id.length <= 
					MAXIMUM_NON_STANDARD_ID_LENGTH))
		{
			/*
			 * The key is of type H221 non-standard ID.  Create a new Rogue
			 * Wave string container to hold the non-standard data.
			 */
			if (NULL == (m_InternalObjectKey.poszNonStandardIDKey = ::My_strdupO2(
				 				object_key->h221_non_standard_id.value,
				 				object_key->h221_non_standard_id.length)))
			{
				ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer: Error creating non standard id key"));
				rc = GCC_ALLOCATION_FAILURE;
			}
		}
		else
		{
			ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer:  Non standard ID is outside legal range"));
			rc = GCC_BAD_OBJECT_KEY;
		}
	}

    *pRetCode = rc;
}

/*
 *	CObjectKeyContainer()
 *
 *	Public Function Description:
 *		This constructor is used to create an CObjectKeyContainer object from
 *		a "PDU" Key.
 */
CObjectKeyContainer::CObjectKeyContainer(PKey				object_key,
						                PGCCError			pRetCode)
:
    CRefCount(MAKE_STAMP_ID('O','b','j','K')),
    m_fValidObjectKeyPDU(FALSE),
    m_cbDataSize(0)
{
	GCCError            rc = GCC_NO_ERROR;
	PSetOfObjectID		object_id_set_ptr;
	UINT               *object_id_ptr;
	UINT				object_id_size = 0;
	Int					i = 0;

	m_InternalObjectKey.object_id_key = NULL;
	m_InternalObjectKey.object_id_length = 0;
	m_InternalObjectKey.poszNonStandardIDKey = NULL;

	/*
	 * Check to see what type of key is contained in the object key.
	 * Object ID keys will be stored internally in a Memory object and
	 * non-standard ID keys will be stored internally in Rogue Wave string
	 * containers.
	 */
	if (object_key->choice == OBJECT_CHOSEN)
	{
		/*
		 * Retrieve the first object ID pointer from the "PDU" structure in
		 * preparation for determining how much memory will be needed to hold
		 * the object ID values.
		 */
		object_id_set_ptr = object_key->u.object;

		/*
		 * Loop through the ObjectID structure, adding up the size of the 
		 * string.
		 */
		while (object_id_set_ptr != NULL)
		{
			m_InternalObjectKey.object_id_length++;
			object_id_set_ptr = object_id_set_ptr->next;
		}

		object_id_size = m_InternalObjectKey.object_id_length * sizeof(UINT);

		/*
		 * Allocate the memory to be used to hold the object ID values.
		 */
		DBG_SAVE_FILE_LINE
		m_InternalObjectKey.object_id_key = new BYTE[object_id_size];
		if (m_InternalObjectKey.object_id_key != NULL)
		{
			object_id_ptr = (UINT *) m_InternalObjectKey.object_id_key;

			/*
			 * Again retrieve the first object ID pointer from the "PDU" 
			 * structure in	order to get the values out for saving.
			 */
			object_id_set_ptr = object_key->u.object;

			/*
			 * Loop through the ObjectID structure, getting each object ID
			 * value and saving it in the allocated memory.
			 */
			while (object_id_set_ptr != NULL)
			{
				object_id_ptr[i++] = object_id_set_ptr->value;
				object_id_set_ptr = object_id_set_ptr->next;
			}
		} 
		else
		{
			ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer: Error allocating memory."));
			rc = GCC_ALLOCATION_FAILURE;
		}
	}
	else
	{
		/*
		 * The key is of type H221 non-standard ID so create a new Rogue Wave
		 * string container to hold the data.
		 */
		if (NULL == (m_InternalObjectKey.poszNonStandardIDKey = ::My_strdupO2(
						object_key->u.h221_non_standard.value,
						object_key->u.h221_non_standard.length)))
		{
			ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer: Error creating non standard id key"));
			rc = GCC_ALLOCATION_FAILURE;
		}
	}

    *pRetCode = rc;
}

/*
 *	CObjectKeyContainer()
 *
 *	Public Function Description:
 *		This copy constructor is used to create a new CObjectKeyContainer object from
 *		another CObjectKeyContainer object.
 */
CObjectKeyContainer::CObjectKeyContainer(CObjectKeyContainer	*object_key,
						                PGCCError				pRetCode)
:
    CRefCount(MAKE_STAMP_ID('O','b','j','K')),
    m_fValidObjectKeyPDU(FALSE),
    m_cbDataSize(0)
{
	GCCError    rc = GCC_NO_ERROR;
	UINT		object_id_size;

	m_InternalObjectKey.object_id_key = NULL;
	m_InternalObjectKey.poszNonStandardIDKey = NULL;

	/*
	 * If an object ID "key" exists for the CObjectKeyContainer to be copied,
	 * allocate memory to hold the object ID "key" information internally.
	 * Check to make sure construction of the object is successful.
	 */
	if (object_key->m_InternalObjectKey.object_id_key != NULL)
	{
		/*
		 * The key is of type Object ID.
		 */
		m_InternalObjectKey.object_id_length = object_key->m_InternalObjectKey.object_id_length;
		object_id_size = m_InternalObjectKey.object_id_length * sizeof(UINT);

        DBG_SAVE_FILE_LINE
		m_InternalObjectKey.object_id_key = new BYTE[object_id_size];
		if (m_InternalObjectKey.object_id_key != NULL)
		{
			::CopyMemory(m_InternalObjectKey.object_id_key,
			             object_key->m_InternalObjectKey.object_id_key,
			             object_id_size);
		}
		else
		{
			ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer: Error allocating memory"));
			rc = GCC_ALLOCATION_FAILURE;
		}
	}
	else if (object_key->m_InternalObjectKey.poszNonStandardIDKey != NULL)
	{
		/*
		 * If a non-standard ID "key" exists for the CObjectKeyContainer to be copied,
		 * create a new Rogue Wave string to hold the non-standard "key" 
		 * information internally.  Check to make sure construction of the
		 * object is successful.
		 */
		if (NULL == (m_InternalObjectKey.poszNonStandardIDKey = ::My_strdupO(
							object_key->m_InternalObjectKey.poszNonStandardIDKey)))
		{
			ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer: Error creating new non standard id key"));
			rc = GCC_ALLOCATION_FAILURE;
		}
	}
	else
	{
		/*
		 * At least one of the internal pointers for the passed in object key 
		 * must be valid.
		 */
		ERROR_OUT(("CObjectKeyContainer::CObjectKeyContainer: Bad input parameters"));
		rc = GCC_BAD_OBJECT_KEY;
	}

    *pRetCode = rc;
}

/*
 *	~CObjectKeyContainer()
 *
 *	Public Function Description
 *		The CObjectKeyContainer destructor is responsible for freeing any memory
 *		allocated to hold the object key data.
 *
 */
CObjectKeyContainer::~CObjectKeyContainer(void)
{
	/*
	 * If "PDU" data has been allocated for this object, free it now.
	 */
	if (m_fValidObjectKeyPDU)
	{
		FreeObjectKeyDataPDU();
	}

	/* 
	 * Delete any object key data held internally.
	 */
	delete m_InternalObjectKey.object_id_key;
	delete m_InternalObjectKey.poszNonStandardIDKey;
}

/*
 *	LockObjectKeyData ()
 *
 *	Public Function Description:
 *		This routine locks the object key data and determines the amount of
 *		memory referenced by the "API" object key data structure.
 */
UINT CObjectKeyContainer::LockObjectKeyData(void)
{
	/*
	 * If this is the first time this routine is called, determine the size of 
	 * the memory required to hold the data referenced by the object key
	 * structure.  Otherwise, just increment the lock count.
	 */
	if (Lock() == 1)
	{
		/*
		 * Determine the amount of space required to hold the data referenced
		 * by the "API" Object Key structure.
		 */
		if (m_InternalObjectKey.object_id_key != NULL)
		{
			/*
			 * Since the object ID is just a series of "longs" without a NULL
			 * terminator, we do not want to include a NULL terminator when 
			 * determining the length.
			 */
			m_cbDataSize = m_InternalObjectKey.object_id_length * sizeof(UINT);
		}
		else
		{
			/*
			 * The data referenced by the non-standard object key is just the
			 * length of the octet string.
			 */
			m_cbDataSize = m_InternalObjectKey.poszNonStandardIDKey->length;
		}

		/*
		 * Force the size to be on a four-byte boundary.
		 */
		m_cbDataSize = ROUNDTOBOUNDARY(m_cbDataSize);
	}

	return m_cbDataSize;
}

/*
 *	GetGCCObjectKeyData ()
 *
 *	Public Function Description:
 *		This routine retrieves object key data in the form of an "API"
 *		GCCObjectKey.  This routine is called after "locking" the object 
 *		key data.
 */
UINT CObjectKeyContainer::GetGCCObjectKeyData(
								PGCCObjectKey 		object_key,
								LPBYTE				memory)
{
	UINT	cbDataSizeToRet = 0;
	UINT   *object_id_ptr;

	/*
	 * If the object key data has been locked, fill in the output structure and
	 * the data referenced by the structure.  Otherwise, report that the object
	 * key has yet to be locked into the "API" form.
	 */ 
	if (GetLockCount() > 0)
	{
		/*
		 * Fill in the output length parameter which indicates how much data
		 * referenced outside the structure will be written.
		 */
		cbDataSizeToRet = m_cbDataSize;

		if (m_InternalObjectKey.object_id_key != NULL)
		{
			/*
			 * The object key is a standard type.  Set the object key type 
			 * and the length of the long string. The length set here does 
			 * not include a NULL terminator.
			 */
			object_key->key_type = GCC_OBJECT_KEY;
			object_key->object_id.long_string_length = (USHORT) m_InternalObjectKey.object_id_length;

			/*
			 * Set the offset for the long string equal to the memory pointer
			 * passed in since it will be the first data referenced by the 
			 * object key structure.
			 */
			object_key->object_id.long_string = (ULONG *) memory;

			/*
			 * Now retrieve the memory pointer and copy the long string data 
			 * from the internal memory object.  
			 */		
			object_id_ptr = (UINT *) m_InternalObjectKey.object_id_key;

			::CopyMemory(memory, object_id_ptr, 
						m_InternalObjectKey.object_id_length * sizeof (UINT));
		}
		else if (m_InternalObjectKey.poszNonStandardIDKey != NULL)
		{
			/*
			 * The object key is a non-standard type.  Set the object key 
			 * type and the length of the octet string.
			 */
			object_key->key_type = GCC_H221_NONSTANDARD_KEY;
			object_key->h221_non_standard_id.length =
						m_InternalObjectKey.poszNonStandardIDKey->length;

			/*
			 * Set the offset for the octet string equal to the memory pointer
			 * passed in since it will be the first data referenced by the 
			 * object key structure.
			 */
			object_key->h221_non_standard_id.value = memory;

			/*
			 * Now copy the octet string data from the internal Rogue Wave
			 * string into the object key structure held in memory.
			 */		
			::CopyMemory(memory, m_InternalObjectKey.poszNonStandardIDKey->value,
									m_InternalObjectKey.poszNonStandardIDKey->length);
		}
		else
		{
			ERROR_OUT(("CObjectKeyContainer::LockObjectKeyData: Error, no valid internal data"));
		}
	}
	else
	{
		object_key = NULL;
		ERROR_OUT(("CObjectKeyContainer::GetGCCObjectKeyData: Error Data Not Locked"));
	}

	return cbDataSizeToRet;
}

/*
 *	UnLockObjectKeyData ()
 *
 *	Public Function Description:
 *		This routine decrements the lock count and frees the memory associated
 *		with the "API" object key once the lock count reaches zero.
 */
void CObjectKeyContainer::UnLockObjectKeyData(void)
{
    Unlock();
}

/*
 *	GetObjectKeyDataPDU ()
 *
 *	Public Function Description:
 *		This routine converts the object key from it's internal form of an
 *		OBJECT_KEY structure into the "PDU" form which can be passed in
 *		to the ASN.1 encoder.  A pointer to a "PDU" "Key" structure is 
 *		returned.
 */
GCCError CObjectKeyContainer::GetObjectKeyDataPDU(PKey object_key)
{
	PSetOfObjectID			new_object_id_ptr;
	PSetOfObjectID			old_object_id_ptr;
	UINT                   *object_id_string;
	GCCError				rc = GCC_NO_ERROR;
	UINT					i;

	/*
	 * Set the loop pointer to NULL to avoid a compiler warning.
	 */
    old_object_id_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 (m_fValidObjectKeyPDU == FALSE)
	{
		m_fValidObjectKeyPDU = TRUE;

		/*
		 * Fill in the "PDU" object key after checking to see what form of 
		 * key exists in the internal structure.
		 */
		if (m_InternalObjectKey.object_id_key != NULL)
		{
			/*
			 * The key is an object ID so set the choice accordingly and 
			 * initialize the PDU object pointer to NULL.  Get the pointer to
			 * the internal list of object key values stored in the memory
			 * object.
			 */
			m_ObjectKeyPDU.choice = OBJECT_CHOSEN;
			m_ObjectKeyPDU.u.object = NULL;

			object_id_string = (UINT *) m_InternalObjectKey.object_id_key;

			/*
			 * The "PDU" structure "ObjectID" is a linked list of unsigned
			 * longs.  Retrieve the Object ID values from the internal memory
			 * object and fill in the "ObjectID" structure. 
			 */
			for (i=0; i<m_InternalObjectKey.object_id_length; i++)
			{
				DBG_SAVE_FILE_LINE
				new_object_id_ptr = new SetOfObjectID;
				if (new_object_id_ptr != NULL)
				{
					/*
					 * The first time through the new pointer is saved in the
					 * PDU structure.  On subsequent iterations, the previous
					 * "next" pointer is set equal to the new pointer.
					 */
					if (m_ObjectKeyPDU.u.object == NULL)
                    {
						m_ObjectKeyPDU.u.object = new_object_id_ptr;
                    }
					else
                    {
						old_object_id_ptr->next = new_object_id_ptr;
                    }

                    old_object_id_ptr = new_object_id_ptr;

					/*
					 * Save the actual Object ID value.
					 */
					new_object_id_ptr->value = object_id_string[i];
					new_object_id_ptr->next = NULL;
				}
				else
				{
					ERROR_OUT(("CObjectKeyContainer::GetObjectKeyDataPDU: creating new ObjectID"));
					rc = GCC_ALLOCATION_FAILURE;
					break;
				}
			}
		}
		else if (m_InternalObjectKey.poszNonStandardIDKey != NULL)
		{
			/*
			 * The key is a non-standard ID so convert the internal Rogue Wave
			 * string into the "PDU" non-standard ID.
			 */
			m_ObjectKeyPDU.choice = H221_NON_STANDARD_CHOSEN;
			m_ObjectKeyPDU.u.h221_non_standard.length =
					m_InternalObjectKey.poszNonStandardIDKey->length;

			::CopyMemory(m_ObjectKeyPDU.u.h221_non_standard.value,
							m_InternalObjectKey.poszNonStandardIDKey->value,
							m_InternalObjectKey.poszNonStandardIDKey->length);
		}
		else
		{
			/*
			 * The constructors make sure that at least one of the internal
			 * pointers is valid so this should never be encountered.
			 */
			ERROR_OUT(("CObjectKeyContainer::GetObjectKeyDataPDU: No valid m_InternalObjectKey"));
			rc = GCC_ALLOCATION_FAILURE;
		}
	}

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

	return rc;
}

/*
 *	FreeObjectKeyDataPDU ()
 *
 *	Public Function Description:
 *		This routine is used to free the object key data held internally in
 *		the "PDU" form of a "Key".
 */
void CObjectKeyContainer::FreeObjectKeyDataPDU(void)
{
	PSetOfObjectID		set_of_object_id;
	PSetOfObjectID		next_set_of_object_id;

	if (m_fValidObjectKeyPDU)
	{
		/*
		 * Set the flag indicating that PDU object key data is no longer
		 * allocated.
		 */
		m_fValidObjectKeyPDU = FALSE;

		if (m_ObjectKeyPDU.choice == OBJECT_CHOSEN)
		{
            for (set_of_object_id = m_ObjectKeyPDU.u.object;
                    set_of_object_id != NULL;
					set_of_object_id = next_set_of_object_id)
            {
				next_set_of_object_id = set_of_object_id->next;
				delete set_of_object_id;
			}
		}
	}
}

/*
 *	operator== ()
 *
 *	Public Function Description:
 *		This routine is used to compare two CObjectKeyContainer objects to determine
 *		if they are equal in value.
 */
BOOL operator==(const CObjectKeyContainer& object_key_1, const CObjectKeyContainer& object_key_2)
{
	UINT       *object_id_1, *object_id_2;
	UINT		i;
	BOOL    	rc = FALSE;
	
	/*
	 * Check to make sure that both the object ID key and the non-standard
	 * ID key are equal.
	 */
	if ((object_key_1.m_InternalObjectKey.object_id_key != NULL) && 
			(object_key_2.m_InternalObjectKey.object_id_key != NULL))
	{
		if (object_key_1.m_InternalObjectKey.object_id_length == 
				object_key_2.m_InternalObjectKey.object_id_length)
		{
			object_id_1 = (UINT *) object_key_1.m_InternalObjectKey.object_id_key;
			object_id_2 = (UINT *) object_key_2.m_InternalObjectKey.object_id_key;

			/*
			 * Compare each Object ID value to make sure they are equal.
			 */
			rc = TRUE;
			for (i=0; i<object_key_1.m_InternalObjectKey.object_id_length; i++)
			{
				if (object_id_1[i] != object_id_2[i])
				{
					rc = FALSE;
					break;
				}
			}
		}
	} 
	else
	if (0 == My_strcmpO(object_key_1.m_InternalObjectKey.poszNonStandardIDKey,
						object_key_2.m_InternalObjectKey.poszNonStandardIDKey))
	{
		rc = TRUE;
	} 

	return rc;
}

/*
 *	BOOL    	ValidateObjectIdValues (	UINT		first_arc,
 *											UINT		second_arc);
 *
 *	Private member function of CObjectKeyContainer.
 *
 *	Function Description:
 *		This routine is used to determine whether or not the values for the
 *		object ID component of the object key are valid.
 *
 *	Formal Parameters:
 *		first_arc			(i) The first integer value of the Object ID.
 *		second_arc			(i) The second integer value of the Object ID.
 *
 *	Return Value:
 *		TRUE				-	The first two arcs of the Object ID are valid.
 *		FALSE				- 	The first two arcs of the Object ID are not 
 *									valid.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
BOOL CObjectKeyContainer::ValidateObjectIdValues(UINT first_arc, UINT second_arc)
{
	BOOL rc = FALSE;

	if (first_arc == ITUT_IDENTIFIER)
	{
		if (0 <= second_arc && second_arc <= 4)
		{
			rc = TRUE;
		} 
	}
	else if (first_arc == ISO_IDENTIFIER)
	{
		if ((second_arc == 0L) ||
			(second_arc == 2L) ||
			(second_arc == 3L))
		{
			rc = TRUE;
		} 
	}
	else if (first_arc == JOINT_ISO_ITUT_IDENTIFIER)
	{
		/*
		 * Referring to ISO/IEC 8824-1 : 1994 (E) Annex B:
		 * Join assignment of OBJECT IDENTIFIER component values are assigned
		 * and agreed from time to time by ISO and ITU-T to identify areas of
		 * joint ISO/ITU-T standardization activity, in accordance with the
		 * procedures of .... ANSI.  So we just let them all through for now.
		 */
		rc = TRUE;
	}
	else
	{
		ERROR_OUT(("ObjectKeyData::ValidateObjectIdValues: ObjectID is invalid"));
	}

	return rc;
}

