/***********************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/*   (c) Copyright Systems Integration Specialists Company, Inc.,	*/
/*      	  1986 - 2008, All Rights Reserved.		        */
/*									*/
/*		    PROPRIETARY AND CONFIDENTIAL			*/
/*									*/
/* MODULE NAME : mmsdata.c						*/
/* PRODUCT(S)  : MMSEASE						*/
/*									*/
/* MODULE DESCRIPTION : 						*/
/*	This module contains the functions employed by the virtual	*/
/*	machine for translating ASN.1 data (from the MMS 'Data'         */
/*	production) to local data, and vice versa.			*/
/*									*/
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE :				*/
/*									*/
/* MODIFICATION LOG :							*/
/*  Date     Who   Rev			Comments			*/
/* --------  ---  ------   -------------------------------------------	*/
/* 08/26/09  JRB     31    Avoid moving constructed bstr, ostr data.	*/
/*			   Del undocumented BAD_DATA, INTERNAL errcodes.*/
/* 07/21/09  JRB     30    Chk new asn1r_bitstr_truncated flag.		*/
/* 06/25/09  MDE     29    Fixed octet string overwrite hole		*/
/* 05/01/08  JRB     28    ms_asn1_to_local: return error from decoder.	*/
/* 04/09/08  JRB     27    wr_prim_dat: fail if BVstring, OVstring len<0*/
/* 01/29/08  EJV     26    Use S_FMT_PTR macro to log pointers.		*/
/* 08/09/06  JRB     25    Add ms_local_to_asn1_2.			*/
/*			   Log TDL & data if wr_prim_dat fails.		*/
/* 03/22/06  EJV     24    RT_GENERAL_TIME: cast datptr to (time_t *).	*/
/* 10/29/04  JRB     23    Use ms_is_rt_prim, safer than el_tag range chk*/
/* 01/20/04  MDE     22    Changed some MLOG_ERR to MLOG_NERR		*/
/* 01/14/04  JRB     21    ms_local_to_asn1: stop encoding if		*/
/*			   asn1r_encode_overrun flag is set.		*/
/* 10/13/03  JRB     20    asn1r_magic error: Chg assert to err return.	*/
/* 04/14/03  JRB     19    Eliminate compiler warnings.			*/
/* 03/31/03  JRB     18    Add UTF8string support (see RT_UTF8_STRING).	*/
/*			   Use new RT_MAX_PRIM_TAG in range chk.	*/
/*			   asn1r_get_bitstr: add max_bits arg.		*/
/* 12/12/02  JRB     17    Verify aCtx using asn1r_magic.		*/
/* 07/12/02  JRB     16    Log Local Data Type (TDL) & maybe ASN.1 data	*/
/*			   if conversion fails.				*/
/* 01/23/02  JRB     15    Simplify use of usr_info (fixes QNX compile)	*/
/* 12/06/01  JRB     14    Convert to use ASN1R (re-entrant ASN1).	*/
/*			   Add ASN1_DEC_CTXT arg to ms_loc*_to_asn1.	*/
/*			   Add function ms_local_to_asn1_easy.		*/
/*			   On decode, replace globals with ..usr_info[].*/
/*			   Use macros to access usr_info[], more readable.*/
/*			   Pass datptr,rt_ptr as args to wr_prim_dat.	*/
/*			   Delete all locks, functions now thread-safe.	*/
/* 11/14/01  EJV     13    Added support for new MMS type UtcTime:	*/
/*			   added get_utc_time_prim func;		*/
/*			   ms_local_to_asn1: replaced RT_BOOLEANARRAY	*/
/*			     with RT_UTC_TIME in range check;		*/
/*			   wr_prim_dat: added case for RT_UTC_TIME;	*/
/* 09/22/00  DSF     12    Truncate extended prim bitstrings		*/
/* 09/13/99  MDE     11    Added SD_CONST modifiers			*/
/* 03/11/98  MDE     10    Removed NEST_RT_TYPES			*/
/* 02/10/98  MDE     09    No longer use runtime type 'loops' element	*/
/* 12/10/97  MDE     08    Cast for call to get_i8			*/
/* 09/05/97  MDE     07    Minor logging changes			*/
/* 08/15/97  MDE     06    BTOD handling changes			*/
/* 08/14/97  MDE     05    Fixed get_bcd_prim (ST_CHAR -> ST_INT8)	*/
/* 07/02/97  MDE     04    Check for ASN.1 encode overrun		*/
/* 06/19/97  MDE     03    Added 64 bit integer support			*/
/* 06/10/97  MDE     02    Removed stub functions (AA, AA Data)		*/
/* 06/09/97  MDE     01    Modified Runtime Type handling		*/
/* 04/02/97  DTL   7.00    MMSEASE 7.0 release. See MODL70.DOC for	*/
/*			   history.					*/
/************************************************************************/

#include "glbtypes.h"

#include "sysincs.h"
#include "glbsem.h"

#include "mmsdefs.h"
#include "mms_pvar.h"
#include "mms_vvar.h"
#include "asn1defs.h"
#if defined(_S_TEST_PROBES)
#include "stestprb.h"
#endif

/************************************************************************/
/* For debug version, use a static pointer to avoid duplication of 	*/
/* __FILE__ strings.							*/

#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif

/************************************************************************/
/* DEC_INFO - structure to store temporary decode information.		*/
/************************************************************************/
typedef struct
  {
  ST_INT arr_loop_level;
  ST_INT *arr_loops;
  SD_CONST RUNTIME_TYPE *rt_ptr;	/* current RUNTIME_TYPE struct	*/
  SD_CONST RUNTIME_TYPE *rt_end;	/* last RUNTIME_TYPE struct	*/
  ST_CHAR *datptr;			/* decoded data destination	*/
  } DEC_INFO;

/************************************************************************/
/* Local functions for ASN1 decode.					*/
/************************************************************************/
static ST_VOID assign_tags (ASN1_DEC_CTXT *aCtx);
static ST_RET  wr_prim_dat (ASN1_ENC_CTXT *aCtx, ST_CHAR *datptr, SD_CONST RUNTIME_TYPE *rt_ptr);
static ST_VOID get_bstr_cstr   (ASN1_DEC_CTXT *aCtx); 	/* for constructed bitstrings	*/
static ST_VOID bs_cstr_done    (ASN1_DEC_CTXT *aCtx);
static ST_VOID get_ostr_cstr   (ASN1_DEC_CTXT *aCtx); 	/* for constructed octetstrings */
static ST_VOID os_cstr_done    (ASN1_DEC_CTXT *aCtx);
static ST_VOID get_bool_prim   (ASN1_DEC_CTXT *aCtx); 	/* for boolean primitives	*/
static ST_VOID get_bitstr_prim (ASN1_DEC_CTXT *aCtx); 	/* for bitstring primitives	*/
static ST_VOID get_int_prim    (ASN1_DEC_CTXT *aCtx); 	/* for integer primitives	*/
static ST_VOID get_uint_prim   (ASN1_DEC_CTXT *aCtx); 	/* for unsigned integers	*/
static ST_VOID get_float_prim  (ASN1_DEC_CTXT *aCtx); 	/* for float primitives 	*/
static ST_VOID get_octstr_prim (ASN1_DEC_CTXT *aCtx); 	/* for octet string primitives	*/
static ST_VOID get_vstr_prim   (ASN1_DEC_CTXT *aCtx); 	/* for visible string primitives*/
static ST_VOID get_gtime_prim  (ASN1_DEC_CTXT *aCtx); 	/* for generalized time 	*/
static ST_VOID get_btime_prim  (ASN1_DEC_CTXT *aCtx); 	/* for binary time primitives	*/
static ST_VOID get_utc_time_prim (ASN1_DEC_CTXT *aCtx);	/* for UTC time primitives	*/
static ST_VOID get_bcd_prim    (ASN1_DEC_CTXT *aCtx); 	/* for binary coded decimal	*/
static ST_VOID get_utf8_prim   (ASN1_DEC_CTXT *aCtx);	/* for Unicode UTF8string	*/
static ST_VOID arr_start	    (ASN1_DEC_CTXT *aCtx);
static ST_VOID str_start	    (ASN1_DEC_CTXT *aCtx);
static ST_VOID arr_done_fun    (ASN1_DEC_CTXT *aCtx);
static ST_VOID str_done_fun    (ASN1_DEC_CTXT *aCtx);
static ST_VOID data_asn1_decode_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID data_dec_err (ASN1_DEC_CTXT *aCtx,ST_RET); 	/* for type definition error	*/

static ST_VOID _log_data_type (SD_CONST RUNTIME_TYPE *rt_head, ST_INT rt_num);

#if defined(_S_TEST_PROBES)

static ST_RET _wr_constructed_bitstring (ASN1_ENC_CTXT *aCtx, ST_CHAR *datptr, 
					 SD_CONST RUNTIME_TYPE *rt_ptr);

static ST_RET _wr_constructed_octetstring (ASN1_ENC_CTXT *aCtx, ST_CHAR *datptr, 
					 SD_CONST RUNTIME_TYPE *rt_ptr);

#endif

/************************************************************************/
/*			ms_asn1_to_locl 				*/
/* Function to convert an MMS ASN.1 'Data' entity into local blocked    */
/* data.  Uses the ASN1DE decode tools to check the received data	*/
/* against the expected data for the selected type using the runtime	*/
/* type table for that type.  Returns 0 if the decode is OK, else an	*/
/* error code.								*/
/************************************************************************/

#ifndef MMS_LITE

ST_RET ms_asn1_to_locl (NAMED_TYPE *tptr, ST_UCHAR *asn1ptr,
			ST_INT asn1len, ST_CHAR *dptr)
  {
  if (!tptr->rt_num)		/* check to make sure some components	*/
    {
    MLOG_NERR0 ("Named type has no runtime elements");
    return (MVE_RT_TYPE);		/* 0 length typedef is error		*/
    }
  return (ms_asn1_to_local (tptr->rt_head,tptr->rt_num,
                                             asn1ptr,asn1len,dptr));
  }

#endif

/************************************************************************/
/*			ms_asn1_to_local 				*/
/************************************************************************/

ST_RET ms_asn1_to_local (SD_CONST RUNTIME_TYPE *rt_head, ST_INT rt_num, 
			 ST_UCHAR *asn1ptr, ST_INT asn1len, ST_CHAR *dptr)
  {
ST_RET ret;
ST_INT arr_loop_buf[ASN1_MAX_LEVEL];
ASN1_DEC_CTXT aCtx;
DEC_INFO decInfo;	/* temporary storage for decode info.		*/

  /* Set initial values in decInfo.			*/ 
  decInfo.arr_loop_level = 0;
  decInfo.arr_loops = arr_loop_buf;
  decInfo.rt_ptr = rt_head;		/* point to head rt_block	*/
  decInfo.rt_end = decInfo.rt_ptr + rt_num;	/* done when pointer is here*/
  decInfo.datptr = dptr;	/* datptr is the running dest pointer.	*/

  /* Initialize the decode context "aCtx" and call "asn1r_decode_asn1".	*/
  memset (&aCtx, 0, sizeof (ASN1_DEC_CTXT));	/* CRITICAL: start clean.*/
  aCtx.usr_info[0] = &decInfo;	/* save ptr to decInfo in context.	*/
  aCtx.asn1r_decode_method = ASN1_TAG_METHOD;	/* select tag method	*/
  aCtx.asn1r_decode_done_fun = asn1r_done_err;/* not legal to be done at this time	*/
  aCtx.asn1r_err_fun = data_dec_err;	/* parse error => call to data_dec_err	*/

  assign_tags (&aCtx);		/* set up tags allowed by 1st rt_block	*/
  asn1r_decode_asn1 (&aCtx,asn1ptr,asn1len);/* decode entire ASN.1 'Data' entity    */

  if (aCtx.asn1r_pdu_dec_err == NO_DECODE_ERR)/* check for sucess or return error	*/
    ret = SD_SUCCESS;
  else
    {
    MLOG_NERR0 ("ASN.1 to Local data conversion error. ASN.1 data to convert:");
    if (mms_debug_sel & MMS_LOG_NERR)
      {			/* use ALWAYSH but only if NERR enabled*/
      MLOG_ALWAYSH (asn1len, asn1ptr);
      }
    /* Conversion failed, try to log the type used for the conversion.	*/
    _log_data_type (rt_head, rt_num);

    ret = aCtx.asn1r_pdu_dec_err;	/* Just return ASN.1 decode error*/
    }

  return (ret);
  }

/************************************************************************/
/*			     assign_tags				*/
/* Function to assign tags to the ASN1DE tools based on what's expected */
/* in the runtime_type definition table.  At the beginning of the 'Data'*/
/* entity, a DataAccessError type is allowed.  WARNING: This function	*/
/* requires that the current rt_block NOT be an end-of-array or end-of- */
/* structure rt_block.	If so, it will return an error. 		*/
/************************************************************************/

static ST_VOID assign_tags (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  if (decInfo->rt_ptr < decInfo->rt_end)	/* if elements to look at	*/
    {
    if (decInfo->rt_ptr->el_tag == RT_ARR_END)	/* treat case of array ending*/
      {
      if (--decInfo->arr_loops[decInfo->arr_loop_level] > 0) /* if need to do next ar elmnt	*/
	decInfo->rt_ptr -= decInfo->rt_ptr->u.arr.num_rt_blks; /* mv rtPtr to start of arr	*/
      else
        --decInfo->arr_loop_level;
      }

    switch (decInfo->rt_ptr->el_tag)
      {
      case RT_ARR_START :
	ASN1R_TAG_ADD (aCtx,CTX|CONSTR,1,arr_start); /* expecting an array cstr	*/
      break;

      case RT_STR_START :
	ASN1R_TAG_ADD (aCtx,CTX|CONSTR,2,str_start); /* expecting an struct cstr	*/
      break;

      case RT_BOOL :
	ASN1R_TAG_ADD (aCtx,CTX,3,get_bool_prim);	
      break;

      case RT_BIT_STRING :			
	ASN1R_TAG_ADD (aCtx,CTX,4,get_bitstr_prim);
	ASN1R_TAG_ADD (aCtx,CTX|CONSTR,4,get_bstr_cstr);
      break;

      case RT_INTEGER :			
	ASN1R_TAG_ADD (aCtx,CTX,5,get_int_prim);
      break;

      case RT_UNSIGNED : 			
	ASN1R_TAG_ADD (aCtx,CTX,6,get_uint_prim);
      break;

#ifdef FLOAT_DATA_SUPPORT
      case RT_FLOATING_POINT : 		
	ASN1R_TAG_ADD (aCtx,CTX,7,get_float_prim);
      break;
#endif

      case RT_OCTET_STRING : 		
	ASN1R_TAG_ADD (aCtx,CTX,9,get_octstr_prim);
	ASN1R_TAG_ADD (aCtx,CTX|CONSTR,9,get_ostr_cstr);
      break;

      case RT_VISIBLE_STRING : 		
	ASN1R_TAG_ADD (aCtx,CTX,10,get_vstr_prim);
      break;

#ifdef TIME_DATA_SUPPORT
      case RT_GENERAL_TIME : 		
	ASN1R_TAG_ADD (aCtx,CTX,11,get_gtime_prim);
      break;
#endif

#ifdef BTOD_DATA_SUPPORT
      case RT_BINARY_TIME : 		
	ASN1R_TAG_ADD (aCtx,CTX,12,get_btime_prim);
      break;
#endif

      case RT_BCD : 			
	ASN1R_TAG_ADD (aCtx,CTX,13,get_bcd_prim);
      break;

      case RT_UTC_TIME : 		
	ASN1R_TAG_ADD (aCtx,CTX,17,get_utc_time_prim);
      break;

      case RT_UTF8_STRING : 		
	ASN1R_TAG_ADD (aCtx,CTX,RT_UTF8_STRING,get_utf8_prim);
      break;

      case RT_ARR_END :			/* array done			*/
	aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = arr_done_fun; /* the arr cstr must be done*/
      break;

      case RT_STR_END :			/* structure done		*/
	aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = str_done_fun; /* the str cstr must be done*/
      break;

      default : 			/* should not be any other tag	*/
        MLOG_NERR0 ("Bad tag in runtime type");
	asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
	return;
      break;
      }
    }
  else					/* no more elements to do	*/
    {
    aCtx->asn1r_decode_done = SD_TRUE;	/* terminate decode		*/
    aCtx->asn1r_decode_done_fun = data_asn1_decode_done; /* ok to be done now		*/
    }
  }
/******************************************************************
Function name:     	 
Author:          	YDF
Version:         	V1.00
Date:        		2008-5-14
Description:    	改进例程中的ms_asn1_to_local函数       
Input   Parameter: 	NULL 	 
Return  Parameter: 	NULL  
Modify  History:       
    		       <Author>  <Date>      <Modification>
   		            ydf       2008-05-014  首次版本创建 
*******************************************************************/
static ST_VOID assign_tags_new (ASN1_DEC_CTXT *aCtx);
ST_RET ms_asn1_to_local_new (ST_UCHAR  tag, ST_INT16  size,ST_INT rt_num,
			ST_UCHAR *asn1ptr, ST_INT asn1len, ST_CHAR *dptr)
{
ST_RET ret;
ST_INT arr_loop_buf[ASN1_MAX_LEVEL];
ASN1_DEC_CTXT aCtx;
DEC_INFO decInfo;	/* temporary storage for decode info.		*/
RUNTIME_TYPE rt_head;
   
  rt_head.el_tag=tag;
  rt_head.el_size=size;
  /* Set initial values in decInfo.			*/ 
  decInfo.arr_loop_level = 0;
  decInfo.arr_loops = arr_loop_buf;
  decInfo.rt_ptr = &rt_head;		/* point to head rt_block	*/	
  decInfo.rt_end = decInfo.rt_ptr + rt_num;	/* done when pointer is here*/
  decInfo.datptr = dptr;	/* datptr is the running dest pointer.	*/

  /* Initialize the decode context "aCtx" and call "asn1r_decode_asn1".	*/
  memset (&aCtx, 0, sizeof (ASN1_DEC_CTXT));	/* CRITICAL: start clean.*/
  aCtx.usr_info[0] = &decInfo;	/* save ptr to decInfo in context.	*/
  aCtx.asn1r_decode_method = ASN1_TAG_METHOD;	/* select tag method	*/
  aCtx.asn1r_decode_done_fun = asn1r_done_err;/* not legal to be done at this time	*/
  aCtx.asn1r_err_fun = data_dec_err;	/* parse error => call to data_dec_err	*/

  assign_tags_new (&aCtx);		/* set up tags allowed by 1st rt_block	*/
  asn1r_decode_asn1 (&aCtx,asn1ptr,asn1len);/* decode entire ASN.1 'Data' entity    */
  
  if (aCtx.asn1r_pdu_dec_err == NO_DECODE_ERR)/* check for sucess or return error	*/
    ret = SD_SUCCESS;
  else
    {
 /*   MLOG_NERR0 ("ASN.1 to Local data conversion error. ASN.1 data to convert:");
    if (mms_debug_sel & MMS_LOG_NERR)
      {			 use ALWAYSH but only if NERR enabled
      MLOG_ALWAYSH (asn1len, asn1ptr);
      }*/
    /* Conversion failed, try to log the type used for the conversion.	
    _log_data_type (rt_head, rt_num); ydf add */

    ret = MVE_DATA_CONVERT;
    }

  return (ret);
}


/*****************************************************************
Function name:     	
Author:          	YDF
Version:         	V1.00
Date:        		2008-5-14
Description:    	改进例程中的assign_tags函数       
Input   Parameter: 	NULL 	 
Return  Parameter: 	NULL  
Modify  History:       
    		       <Author>  <Date>      <Modification>
   		            ydf       2008-05-014  首次版本创建 
*******************************************************************/
static ST_VOID assign_tags_new (ASN1_DEC_CTXT *aCtx)
  {
  DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  if (decInfo->rt_ptr < decInfo->rt_end)	/* if elements to look at	*/
    {
/*	  printk("decInfo->rt_ptr->el_tag = %x ", decInfo->rt_ptr->el_tag);*/
    switch (decInfo->rt_ptr->el_tag)
      {
      case RT_ARR_START :
	ASN1R_TAG_ADD (aCtx,CTX|CONSTR,1,arr_start); /* expecting an array cstr	*/
      break;

      case RT_STR_START :
	ASN1R_TAG_ADD (aCtx,CTX|CONSTR,2,str_start); /* expecting an struct cstr	*/
      break;

      case RT_BOOL :
	ASN1R_TAG_ADD (aCtx,CTX,3,get_bool_prim);	
      break;

      case RT_BIT_STRING :			
	ASN1R_TAG_ADD (aCtx,CTX,4,get_bitstr_prim);
	ASN1R_TAG_ADD (aCtx,CTX|CONSTR,4,get_bstr_cstr);
      break;

      case RT_INTEGER :			
	ASN1R_TAG_ADD (aCtx,CTX,5,get_int_prim);
      break;

      case RT_UNSIGNED : 			
	ASN1R_TAG_ADD (aCtx,CTX,6,get_uint_prim);
      break;

#ifdef FLOAT_DATA_SUPPORT
      case RT_FLOATING_POINT : 		
	ASN1R_TAG_ADD (aCtx,CTX,7,get_float_prim);
      break;
#endif

      case RT_OCTET_STRING : 		
	ASN1R_TAG_ADD (aCtx,CTX,9,get_octstr_prim);
	ASN1R_TAG_ADD (aCtx,CTX|CONSTR,9,get_ostr_cstr);
      break;

      case RT_VISIBLE_STRING : 		
	ASN1R_TAG_ADD (aCtx,CTX,10,get_vstr_prim);
      break;

#ifdef TIME_DATA_SUPPORT
      case RT_GENERAL_TIME : 		
	ASN1R_TAG_ADD (aCtx,CTX,11,get_gtime_prim);
      break;
#endif

#ifdef BTOD_DATA_SUPPORT
      case RT_BINARY_TIME : 		
	ASN1R_TAG_ADD (aCtx,CTX,12,get_btime_prim);
      break;
#endif

      case RT_BCD : 			
	ASN1R_TAG_ADD (aCtx,CTX,13,get_bcd_prim);
      break;

      case RT_UTC_TIME : 		
	ASN1R_TAG_ADD (aCtx,CTX,17,get_utc_time_prim);
      break;

      case RT_UTF8_STRING : 		
	ASN1R_TAG_ADD (aCtx,CTX,RT_UTF8_STRING,get_utf8_prim);
      break;

      case RT_ARR_END :			/* array done			*/
	aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = arr_done_fun; /* the arr cstr must be done*/
      break;

      case RT_STR_END :			/* structure done		*/
	aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = str_done_fun; /* the str cstr must be done*/
      break;

      default : 			/* should not be any other tag	*/
 /*       MLOG_NERR0 ("Bad tag in runtime type"); 
	asn1r_set_dec_err (aCtx,INTERNAL);*/
	return;
      break;
      }
    }
  else					/* no more elements to do	*/
    {
    	aCtx->asn1r_decode_done = SD_TRUE;	/* terminate decode		*/
    	aCtx->asn1r_decode_done_fun = data_asn1_decode_done; /* ok to be done now		*/
    }
  }

/************************************************************************/
/*			   arr_start					*/
/* This is the function called when an array cstr is starting		*/
/************************************************************************/

static ST_VOID arr_start (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("arr_start");

/* initialize the loop counter for the array				*/

  ++decInfo->arr_loop_level;
  decInfo->arr_loops[decInfo->arr_loop_level] = decInfo->rt_ptr->u.arr.num_elmnts;

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);		/* setup to get next element		*/
  }


/************************************************************************/
/*			   arr_done_fun 				*/
/* This is the cstr done function called when an array cstr is done	*/
/************************************************************************/

static ST_VOID arr_done_fun (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("arr_done_fun");

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer 		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);		/* setup to get next element		*/
  }


/************************************************************************/
/*			   str_start					*/
/* This is the function called when an struct cstr is starting		*/
/************************************************************************/

static ST_VOID str_start (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("str_start");

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);		/* setup to get next element		*/
  }

/************************************************************************/
/*			   str_done_fun 				*/
/* This is the cstr done function called when an struct cstr is done	*/
/************************************************************************/

static ST_VOID str_done_fun (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("str_done_fun");

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);		/* setup to get next element		*/
  }


/************************************************************************/
/*			   get_bstr_cstr				*/
/* State function to extract a boolean value from an asn1 data element. */
/************************************************************************/

static ST_VOID get_bstr_cstr (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_bstr_cstr");

  aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = bs_cstr_done;

  /* Pass different data pointer for fixed len or variable len bitstring.*/
  if (decInfo->rt_ptr->u.p.el_len >=0)	/* fixed length		*/
    asn1r_get_bitstr_cstr (aCtx,abs (decInfo->rt_ptr->u.p.el_len), (ST_UCHAR *) decInfo->datptr);
  else					/* variable length	*/
    asn1r_get_bitstr_cstr (aCtx,abs (decInfo->rt_ptr->u.p.el_len), (ST_UCHAR *) decInfo->datptr + sizeof (ST_INT16));
  }                        

/************************************************************************/
/*			bs_cstr_done					*/
/* This function is called when an bit string constructor is 		*/
/* completed OK. Need to reset the decode state machine.		*/
/************************************************************************/

static ST_VOID bs_cstr_done (ASN1_DEC_CTXT *aCtx)
  {
ST_INT abs_len;
ST_INT abs_count;
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/

  abs_count = abs (decInfo->rt_ptr->u.p.el_len);
  abs_len = (abs_count+7) / 8;

/* determine whether octect string is fixed or variable length		*/

  if (decInfo->rt_ptr->u.p.el_len >=0)	/* fixed length			*/
    {
    if (aCtx->asn1r_bitstr_truncated || aCtx->asn1r_bitcount != abs_count)
      {
      MLOG_NERR0 ("Fixed length bit string mismatch");
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
      return;
      }
    }
  else		/* variable length bit string				*/
    {
    /* Set length.	*/
    *((ST_INT16 *)decInfo->datptr) = (ST_INT16) aCtx->asn1r_bitcount;
    }

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer 		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);		/* Assign tags for next data elt*/
  }


/************************************************************************/
/*			   get_ostr_cstr				*/
/* State function to extract an octet string from an asn1 data element. */
/************************************************************************/

static ST_VOID get_ostr_cstr (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_ostr_cstr");

  aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = os_cstr_done;

  /* Pass different data pointer for fixed len or variable len octetstring.*/
  if (decInfo->rt_ptr->u.p.el_len >=0)	/* fixed length		*/
    asn1r_get_octstr_cstr (aCtx,abs (decInfo->rt_ptr->u.p.el_len), (ST_UCHAR *) decInfo->datptr);
  else					/* variable length	*/
    asn1r_get_octstr_cstr (aCtx,abs (decInfo->rt_ptr->u.p.el_len), (ST_UCHAR *) decInfo->datptr + sizeof (ST_INT16));
  }

/************************************************************************/
/*			os_cstr_done					*/
/* This function is called when an octet string constructor is 		*/
/* completed OK. Need to reset the decode state machine.		*/
/************************************************************************/

static ST_VOID os_cstr_done (ASN1_DEC_CTXT *aCtx)
  {
ST_INT abs_len;
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/

  abs_len = abs (decInfo->rt_ptr->u.p.el_len);

/* determine whether octect string is fixed or variable length		*/

  if (decInfo->rt_ptr->u.p.el_len >=0)	/* fixed length			*/
    {
    if (aCtx->asn1r_octetcount != abs_len)
      {
      MLOG_NERR0 ("Fixed length octet string mismatch");
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
      return;
      }
    }
  else		/* variable length octet string				*/
    {
    /* Set length.	*/
    *((ST_INT16 *)decInfo->datptr) = (ST_INT16) aCtx->asn1r_octetcount;	
    }

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer    	*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);		/* Assign tags for next data elt*/
  }


/************************************************************************/
/*			   get_bool_prim				*/
/* State function to extract a boolean prim from an asn1 data element.	*/
/************************************************************************/

static ST_VOID get_bool_prim   (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_bool_prim");

  if (asn1r_get_bool (aCtx,(ST_UCHAR *)decInfo->datptr))	/* Get the boolean length	*/
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);		/* checked by get function	*/

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer    	*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);		/* continue the parse		*/
  }

/************************************************************************/
/*			   get_bitstr_prim				*/
/* State function to extract an bitstring prim from an asn1 data element*/
/************************************************************************/

static ST_VOID get_bitstr_prim    (ASN1_DEC_CTXT *aCtx)
  {
ST_INT abs_len;
ST_INT abs_count;
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/

  MLOG_CDEC0 ("get_bitstr_prim");

  abs_count = abs (decInfo->rt_ptr->u.p.el_len);
  abs_len = CALC_BIT_LEN (abs_count);

/* determine whether bitstring is fixed or variable length		*/
  if (decInfo->rt_ptr->u.p.el_len >= 0)
    {
    if (asn1r_get_bitstr (aCtx,(ST_UCHAR *)decInfo->datptr, abs_count))
      {
      MLOG_CDEC0 ("Bitstring decode failed");
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
      }
    else if (aCtx->asn1r_bitstr_truncated || aCtx->asn1r_bitcount != abs_count)
      {
      /* For 'fixed length' bitstr, length must match expected length.	*/
      /* If bitstr truncated, this implies length DID NOT match.	*/
      MLOG_CDEC0 ("Bitstring length incorrect");
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
      }
    }
  else		/* variable length octet string				*/
    {
    if (asn1r_get_bitstr (aCtx,(ST_UCHAR *)decInfo->datptr + sizeof (ST_INT16), abs_count))
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
    else
      {
      *((ST_INT16 *)decInfo->datptr) = (ST_INT16) aCtx->asn1r_bitcount;
      }
    }

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer    	*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

/************************************************************************/
/*			   get_int_prim 				*/
/* State function to extract an integer prim from an asn1 data element. */
/************************************************************************/

static ST_VOID get_int_prim    (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_int_prim");

   switch (decInfo->rt_ptr -> u.p.el_len)	/* determine length	       */
     {
     case 1 :			       /* one byte int		       */
       if (asn1r_get_i8 (aCtx,(ST_INT8 *)decInfo->datptr)) /* write a single byte	       */
	 asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     break;

     case 2 :			       /* two byte int		       */
       if (asn1r_get_i16 (aCtx,(ST_INT16 *)decInfo->datptr)) /* read 16 bit integer       */
	 asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     break;

     case 4 :			      /* four byte integer	       */
       if (asn1r_get_i32 (aCtx,(ST_INT32 *)decInfo->datptr))/* read 4 bytes*/
	 asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     break;

#ifdef INT64_SUPPORT
     case 8 :			      /* eight byte integer	       */
       if (asn1r_get_i64 (aCtx,(ST_INT64 *)decInfo->datptr))/* read 8 bytes*/
	 asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     break;
#endif

     default :
       MLOG_NERR0 ("Invalid integer size in RT");
       asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);	/* no other lengths are valid*/
       return;
     }

  decInfo->datptr += decInfo->rt_ptr->el_size; 	/* Adjust data pointer	*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

/************************************************************************/
/*			   get_uint_prim				*/
/* State function to extract an unsigned integer prim from an asn1 data */
/* element.								*/
/************************************************************************/

static ST_VOID get_uint_prim   (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_uint_prim");

   switch (decInfo->rt_ptr -> u.p.el_len) 	/* determine length	       */
     {
     case 1 :			       /* one byte int		       */
       if (asn1r_get_u8 (aCtx,(ST_UCHAR *)decInfo->datptr)) /* write a single byte	       */
	    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     break;

     case 2 :			       /* two byte int		       */
       if (asn1r_get_u16 (aCtx,(ST_UINT16 *)decInfo->datptr)) /* read 16 bit integer 	*/
         {
	 asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
         }   
     break;

     case 4 :			      /* four byte integer	       */
       if (asn1r_get_u32 (aCtx,(ST_UINT32 *)decInfo->datptr))/* read 4 bytes*/
	 asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     break;

#ifdef INT64_SUPPORT
     case 8 :			      /* eight byte integer	       */
       if (asn1r_get_u64 (aCtx,(ST_UINT64 *)decInfo->datptr))/* read 8 bytes*/
	 asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     break;
#endif

     default :
       MLOG_NERR0 ("Invalid integer size in RT");
       asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);	/* no other lengths are valid*/
       return;
     }
  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

/************************************************************************/
/*			   get_float_prim				*/
/* State function to extract a floating point primitive from an asn1	*/
/* data element.							*/
/************************************************************************/

#ifdef FLOAT_DATA_SUPPORT

static ST_VOID get_float_prim  (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_float_prim");

  if (decInfo->rt_ptr -> u.p.el_len == 8)
    {
    if (asn1r_get_double (aCtx,(ST_DOUBLE *)decInfo->datptr))
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
    }
  else if (decInfo->rt_ptr -> u.p.el_len == 4)
    {
    if (asn1r_get_float (aCtx,(ST_FLOAT *)decInfo->datptr))
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
    }
  else
    {
    MLOG_NERR0 ("Bad float size in RT");
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
    return;
    }

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer    	*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

#endif

/************************************************************************/
/*			   get_octstr_prim				*/
/* State function to extract an octet string primitive from an asn1	*/
/* data element.							*/
/************************************************************************/

static ST_VOID get_octstr_prim (ASN1_DEC_CTXT *aCtx)
  {
ST_INT abs_len;
ST_INT var_len;	/* variable length octetstring decoded length	*/
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/

  MLOG_CDEC0 ("get_octstr_prim");

  abs_len = abs (decInfo->rt_ptr->u.p.el_len);

  if (decInfo->rt_ptr->u.p.el_len >= 0)	/* fixed length	*/
    {
    if (asn1r_get_octstr_fixlen (aCtx,(ST_UCHAR *) decInfo->datptr, abs_len))
      {
      MLOG_NERR0 ("Fixed length octet string decode error");
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
      return;
      }
    }
  else					/* variable length	*/
    {
    if (asn1r_get_octstr_varlen (aCtx,(ST_UCHAR *) decInfo->datptr + sizeof (ST_INT16), abs_len, &var_len))
      {
      MLOG_NERR0 ("Variable length octet string decode error");
      asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
      return;
      }
    else
      {
      *((ST_INT16 *)decInfo->datptr) = (ST_INT16) var_len;
      }
    }

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer    	*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

/************************************************************************/
/*			   get_vstr_prim				*/
/* State function to extract a visible string primitive from an asn1	*/
/* data element.							*/
/************************************************************************/

static ST_VOID get_vstr_prim   (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_vstr_prim");

/* When the u.p.el_len is positive the v-string is of fixed length 	*/
/* meaning that the aCtx->asn1r_elmnt_len has to be equal.  It is ok for the 	*/
/* u.p.el_len to be negative.  When this is encountered it means that 	*/
/* the v_string	is of variable length, the aCtx->asn1r_elmnt_len has to be <= 	*/
/* u.p.el_len to be valid.						*/

  if (((decInfo->rt_ptr -> u.p.el_len > 0) && 
       (aCtx->asn1r_elmnt_len != decInfo->rt_ptr->u.p.el_len)) ||
       (aCtx->asn1r_elmnt_len > abs (decInfo->rt_ptr -> u.p.el_len)) || 
       (asn1r_get_vstr (aCtx,decInfo->datptr)))
    {
    MLOG_NERR0 ("Vstring size or content problem");
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
    return;
    }
					/* v-strings are null term'd	*/
  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

/************************************************************************/
/*			   get_utf8_prim				*/
/* State function to extract a Unicode UTF8string primitive from an	*/
/* ASN.1 data element.							*/
/************************************************************************/

static ST_VOID get_utf8_prim   (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_utf8_prim");

/* If "el_len" is positive, the string is "fixed length" and this is the
 * number of characters.
 * If "el_len" is negative, the string is "variable length" and
 * "abs(el_len)" is the "maximum" number of characters.
 * Pass "el_len" to the ASN.1 function and it will take care of all len chks.
 */

  if (asn1r_get_utf8 (aCtx,decInfo->datptr,decInfo->rt_ptr->u.p.el_len))
    {
    MLOG_NERR0 ("Unicode UTF8(V)string decode error");
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
    return;
    }
  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer	*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

/************************************************************************/
/*			   get_gtime_prim				*/
/* State function to extract a generalized time primitive from an asn1	*/
/* data element.							*/
/************************************************************************/

#ifdef TIME_DATA_SUPPORT

static ST_VOID get_gtime_prim  (ASN1_DEC_CTXT *aCtx)
  {
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/
  MLOG_CDEC0 ("get_gtime_prim");

  if (asn1r_get_time (aCtx,(time_t *)decInfo->datptr))
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer    	*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

#endif

/************************************************************************/
/*			   get_btime_prim				*/
/* State function to extract a binary time primitive from an asn1 data	*/
/* element.								*/
/************************************************************************/

#ifdef BTOD_DATA_SUPPORT

static ST_VOID get_btime_prim  (ASN1_DEC_CTXT *aCtx)
  {
MMS_BTOD btod_data;
ST_INT32 *i32_ptr;
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/

  MLOG_CDEC0 ("get_btime_prim");

  if (asn1r_get_btod (aCtx,&btod_data))
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
  else if (btod_data.form != decInfo->rt_ptr->u.p.el_len)
    {
    MLOG_NERR0 ("BTOD form mismatch");
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
    return;
    }
  else
    {
    i32_ptr = (ST_INT32 *) decInfo->datptr;
    *i32_ptr = btod_data.ms;
    if (btod_data.form == MMS_BTOD6)
      {
      ++i32_ptr;
      *i32_ptr = btod_data.day;
      }
    decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer    	*/
    decInfo->rt_ptr++;		/* point to next runtime element	*/
    assign_tags (aCtx);
    }
  }

#endif

/************************************************************************/
/*			   get_bcd_prim 				*/
/* State function to extract a binary coded decimal primitive from an	*/
/* asn1 data element.							*/
/************************************************************************/

static ST_VOID get_bcd_prim    (ASN1_DEC_CTXT *aCtx)
  {
ST_INT32 range;
ST_INT8	 btemp;
ST_INT16 stemp;
ST_INT32 ltemp;
ST_INT   i;
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/

  range = 0;

  MLOG_CDEC0 ("get_bcd_prim");

/* we have to calculate the legal range of digits this bcd type will    */
/* fit in.                                                              */

   for (i = 0; i < decInfo->rt_ptr->u.p.el_len; i++)
      range = (range * 10) + 9;

   if (decInfo->rt_ptr -> u.p.el_len <= 2)	/* determine length	       */
     {
     if (asn1r_get_i8 (aCtx,&btemp))	/* get a two nibble value	*/
       asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     if ((btemp > (ST_CHAR)range) ||  /* is it in range		*/
          (btemp < 0))
       {
       MLOG_NERR0 ("BCD value out of range");
       asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
       return;
       }
     else
       memcpy (decInfo->datptr, &btemp, sizeof (ST_CHAR)); /* copy good data*/
     }
   else if (decInfo->rt_ptr -> u.p.el_len <= 4)
     {
     if (asn1r_get_i16 (aCtx,&stemp))		/* read 4 nibble BCD	*/
       asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     if ((stemp > (ST_INT16) range) || (stemp < 0))
       {
       MLOG_NERR0 ("BCD value out of range");
       asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
       return;
       }
     else
       memcpy (decInfo->datptr, &stemp, sizeof (ST_INT16)); /* copy good data	*/
     }
   else if (decInfo->rt_ptr -> u.p.el_len <= 8)
     {
     if (asn1r_get_i32 (aCtx,&ltemp))		/* read 4 bytes	*/
       asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
     if ((ltemp > range) || (ltemp < 0))
       {
       MLOG_NERR0 ("BCD value out of range");
       asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
       return;
       }
     else
       memcpy (decInfo->datptr, &ltemp, sizeof (ST_INT32)); /* copy good data*/
     }
   else
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);	     /* no other lengths are valid*/

  decInfo->datptr += decInfo->rt_ptr->el_size; /* Adjust data pointer		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

/************************************************************************/
/*			   get_utc_time_prim				*/
/* State function to extract a UTC time primitive from an asn1 data	*/
/* element.								*/
/************************************************************************/

static ST_VOID get_utc_time_prim  (ASN1_DEC_CTXT *aCtx)
  {
MMS_UTC_TIME utc_time;
DEC_INFO *decInfo = (DEC_INFO *) aCtx->usr_info[0];	/* get saved ptr*/

  MLOG_CDEC0 ("get_utc_time_prim");

  if (asn1r_get_utc_time (aCtx, &utc_time))
    asn1r_set_dec_err (aCtx,MVE_DATA_CONVERT);
  else
    /* just copy the whole struct */
    memcpy (decInfo->datptr, (ST_CHAR *)&utc_time, sizeof (MMS_UTC_TIME));

  decInfo->datptr += decInfo->rt_ptr->el_size;	/* Adjust data pointer		*/
  decInfo->rt_ptr++;		/* point to next runtime element	*/
  assign_tags (aCtx);
  }

/************************************************************************/
/*			    data_asn1_decode_done				*/
/* Function called when the end of the ASN.1 'Data' entity is           */
/* detected.  Checks this against the runtime type table.		*/
/************************************************************************/

static ST_VOID data_asn1_decode_done (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("data_asn1_decode_done");
  }

/************************************************************************/
/*			     data_dec_err				*/
/* Function called when an invalid tag is encountered in the ASN.1	*/
/* 'Data' entity.  Stops the parse with a fatal error.                  */
/************************************************************************/

static ST_VOID data_dec_err (ASN1_DEC_CTXT *aCtx, ST_RET err)
  {
  MLOG_CDEC1 ("data_dec_err %d", err);
  /* NOTE: error already set. DO NOT call asn1r_set_dec_err.		*/
  /*       DO NOT set (aCtx->asn1r_pdu_dec_err).			*/
  }

/************************************************************************/
/************************************************************************/
/************************************************************************/
/* Block data to ASN.1 data section					*/
/* Assumes that the ASN.1 tools have been initialized.			*/
/************************************************************************/
/************************************************************************/
/*			ms_locl_to_asn1 				*/
/* Construct a 'data' element (ASN.1) from blocked data.                */
/* The user passes a pointer to the blocked data and the type def,	*/
/* and the number of elements in the type definition table.		*/
/*									*/
/* Assume the build tools have been initialized, use ASN.1 build tools	*/
/************************************************************************/

#ifndef MMS_LITE

ST_RET ms_locl_to_asn1 (ASN1_ENC_CTXT *aCtx, NAMED_TYPE *tptr, ST_CHAR *dptr)
  {
  if (!tptr->rt_num)			/* if len == 0			*/
    {
    MLOG_NERR0 ("Named type has no runtime elements");
    return (MVE_RT_TYPE);		/* 0 length typedef is error		*/
    }

  return (ms_local_to_asn1 (aCtx, tptr->rt_head,tptr->rt_num, dptr));
  }

#endif
       
/************************************************************************/
/*			ms_local_to_asn1 				*/
/* This function is most convenient when data is encoded in the		*/
/* middle of a larger encode.						*/
/*   If data is encoded by itself, ms_local_to_asn1_2 is more		*/
/* efficient and much easier to use.					*/
/************************************************************************/
//extern int  flag_jou_asn1_endian;//lnk编译删除，原前置程序未使用

//void jou_endian_2(char *pval);//lnk编译删除，原前置程序未使用
//void jou_endian_4(char *pval);//lnk编译删除，原前置程序未使用

ST_RET ms_local_to_asn1 (ASN1_ENC_CTXT *aCtx,
			SD_CONST RUNTIME_TYPE *rt_head,
			ST_INT rt_num,
			ST_CHAR *dptr)
  {
ST_INT done;
ST_RET   ret_val;
ST_INT arr_loop_buf[ASN1_MAX_LEVEL];
ST_CHAR *datptr;
SD_CONST RUNTIME_TYPE *rt_ptr;
SD_CONST RUNTIME_TYPE *rt_end;
ST_INT arr_loop_level;
ST_INT *arr_loops;

/* Make sure that "asn1r_strt_asn1_bld" was called for this context.	*/
  if (aCtx->asn1r_magic != ASN1_ENC_MAGIC_NUMBER)
    {
    MLOG_ERR0 ("ASN1_ENC_CTXT not initialized. MUST call 'asn1r_strt_asn1_bld' first.");
    return (MVE_ASN1_ENCODE_ERR);
    }

  arr_loop_level = 0;
  arr_loops = arr_loop_buf;

  rt_ptr = rt_head + rt_num -1; /* point to bottom rt element 		*/
  rt_end = rt_head;		/* head is end				*/

/* Set working data pointer to point below last data element		*/
  datptr =  dptr + rt_head->offset_to_last;

  done = SD_FALSE;
  ret_val = SD_SUCCESS;  
  while (!done && !ret_val && !aCtx->asn1r_encode_overrun)	/* while not done*/
    {
    if (ms_is_rt_prim (rt_ptr))		/* is this a primitive element?	*/
      {
      datptr -= rt_ptr->el_size;						/* Point to data for this element    */


	  //if(flag_jou_asn1_endian)
    if(0)//lnk编译修改，原前置程序未使用
	  {
			if(rt_ptr->el_tag==RT_BIT_STRING)
			{
				jou_endian_2((char *)&datptr[0]);
				jou_endian_2((char *)&datptr[2]);
			}
			if(rt_ptr->el_tag==RT_FLOATING_POINT)
			{
				jou_endian_4((char *)datptr);
			}
			if(rt_ptr->el_tag==RT_INTEGER)
			{
				if(rt_ptr -> u.p.el_len==2) jou_endian_2((char *)&datptr[0]);
				if(rt_ptr -> u.p.el_len==4) jou_endian_4((char *)&datptr[0]);
			}
			if(rt_ptr->el_tag==RT_UTC_TIME)
			{
				jou_endian_4((char *)&datptr[0]);
				jou_endian_4((char *)&datptr[4]);
			}
	  }
      ret_val = wr_prim_dat (aCtx, datptr, rt_ptr);	   /* Write the primitive data*/
      }
    else				/* not a primitive element	*/
      {
      switch (rt_ptr->el_tag)
	{
	case RT_ARR_END :		/* array end, start constructor */
					/* initialize loop count	*/
          ++arr_loop_level;
          arr_loops[arr_loop_level] = rt_ptr->u.arr.num_elmnts;
	  asn1r_strt_constr (aCtx);
          datptr -= rt_ptr->el_size; /* Point to data element above	*/
	break;

	case RT_ARR_START :     		/* array start			*/
					/* if more loops, move ptr back */
          if (--arr_loops[arr_loop_level] > 0) /* if need to do next ar elmnt	*/
	    {
	    rt_ptr += rt_ptr->u.arr.num_rt_blks;
	    continue;			/* Back to loop bottom		*/
	    }
	  else
	    {
            --arr_loop_level;
	    asn1r_fin_constr (aCtx,1,CTX,DEF);	/* array done, fin the cstr*/
            datptr -= rt_ptr->el_size;
	    }
	break;

	case RT_STR_END :			/* array end, start constructor */
	  asn1r_strt_constr (aCtx);
          datptr -= rt_ptr->el_size;
	break;

	case RT_STR_START :
	  asn1r_fin_constr (aCtx,2,CTX,DEF);  	/* struct done, fin the cstr*/
          datptr -= rt_ptr->el_size;
	break;

	default :			/* unknown typedef tag		*/
          MLOG_NERR0 ("Unknown RT type tag");
	  ret_val = MVE_RT_TYPE;
	}
      } /* end if not primitive element */

/* All tags (EXCEPT array start when loopback) come here. 		*/

/* Move the rt_ptr to the next element, check for done		       	*/
    if (rt_ptr == rt_end)		/* If this was last element 	*/
      done = SD_TRUE;	
    else
      --rt_ptr;				/* move pointer to next 	*/
    }


  if (ret_val == SD_SUCCESS)
    {
    if (aCtx->asn1r_encode_overrun)	/* Check for encode overrun	*/
      ret_val = ME_ASN1_ENCODE_OVERRUN;
    }

  /* If conversion failed, log the type used for the conversion.	*/
  if (ret_val)
    {
    MLOG_NERR1 ("Local to ASN.1 data conversion error = 0x%X", ret_val);
    _log_data_type (rt_head, rt_num);
    }

  return (ret_val);
  }

/************************************************************************/
/*			wr_prim_dat					*/
/* Write a primitive data element from the user data to the message	*/
/* under construction.							*/
/************************************************************************/

static ST_RET wr_prim_dat (ASN1_ENC_CTXT *aCtx, ST_CHAR *datptr, SD_CONST RUNTIME_TYPE *rt_ptr)
  {
ST_RET ret_val;
ST_INT16 len;
MMS_BTOD btod_data;
ST_INT32 *i32_ptr;

  ret_val = SD_SUCCESS;

/* use the runtime type def table element and type to select storage	*/

  switch (rt_ptr->el_tag)
    {
    case RT_BOOL :				/* boolean			*/
      asn1r_wr_bool (aCtx,*((ST_UCHAR *)datptr));	/* write a single byte*/
    break;

    case RT_BIT_STRING : 
#if defined(_S_TEST_PROBES)
      if (_sTestProbeEnabledS("MmsConstructedBitstrings"))
        {
        ret_val = _wr_constructed_bitstring (aCtx, datptr, rt_ptr);
	goto _CONSTRUCTED_BSOS_WRITTEN;
        }
#endif

      if (rt_ptr->u.p.el_len >= 0)
        asn1r_wr_bitstr (aCtx,(ST_UCHAR *)datptr,rt_ptr->u.p.el_len); /* bits */
      else
        {	/* variable length bitstring	*/
        len = *((ST_INT16 *)datptr);
        if (len < 0 || len > abs(rt_ptr->u.p.el_len))
          {
          MLOG_NERR1 ("Invalid variable length bitstring length: %d", 
						(ST_INT) len);
          ret_val = MVE_RT_TYPE;
	  }
        else
          asn1r_wr_bitstr (aCtx,(ST_UCHAR *) (datptr + sizeof(ST_INT16)), len);
	}
    break;

    case RT_INTEGER :
      switch (rt_ptr -> u.p.el_len)	/* determine length		*/
	{
	case 1 :			/* one byte int 		*/
	  asn1r_wr_i8 (aCtx,*datptr);		/* write a single byte	*/
	break;

	case 2 :			/* two byte int 		*/
	  asn1r_wr_i16 (aCtx,*((ST_INT16 *)datptr));
	break;

	case 4 :			/* four byte integer		*/
	  asn1r_wr_i32 (aCtx,*((ST_INT32 *) datptr));
	break;

#ifdef INT64_SUPPORT
	case 8 :			/* eight byte integer		*/
	  asn1r_wr_i64 (aCtx,*((ST_INT64 *) datptr));
	break;
#endif

	default :
          MLOG_NERR0 ("Invalid integer length");
          ret_val = MVE_RT_TYPE;
	}
    break;

    case RT_UNSIGNED :
      switch (rt_ptr -> u.p.el_len)	/* determine length		*/
	{
	case 1 :			/* one byte unsigned int	*/
	  asn1r_wr_u8 (aCtx,*((ST_UCHAR *)datptr));
	break;

	case 2 :			/* two byte unsigned int	*/
	  asn1r_wr_u16 (aCtx,*((ST_UINT16 *) datptr));
	break;

	case 4 :			/* four byte unsigned integer	*/
	  asn1r_wr_u32 (aCtx,*((ST_UINT32 *) datptr));
	break;

#ifdef INT64_SUPPORT
	case 8 :			/* eight byte unsigned integer	*/
	  asn1r_wr_u64 (aCtx,*((ST_UINT64 *) datptr));
	break;
#endif

	default :
          MLOG_NERR0 ("Invalid integer length");
          ret_val = MVE_RT_TYPE;
	}
    break;

#ifdef FLOAT_DATA_SUPPORT
    case RT_FLOATING_POINT :
      if (rt_ptr -> u.p.el_len != sizeof (ST_FLOAT))
	asn1r_wr_double (aCtx,*((ST_DOUBLE *)datptr));
      else
	asn1r_wr_float (aCtx,*((ST_FLOAT *)datptr));
    break;
#endif

    case RT_OCTET_STRING :	
#if defined(_S_TEST_PROBES)
      if (_sTestProbeEnabledS("MmsConstructedOctetstrings"))
        {
        ret_val = _wr_constructed_octetstring (aCtx, datptr, rt_ptr);
	goto _CONSTRUCTED_BSOS_WRITTEN;
        }
#endif

      if (rt_ptr->u.p.el_len >= 0)
        asn1r_wr_octstr (aCtx,(ST_UCHAR *)datptr, rt_ptr->u.p.el_len);
      else
        {	/* variable length octetstring	*/
        len = *((ST_INT16 *)datptr);
        if (len < 0 || len > abs(rt_ptr->u.p.el_len))
          {
          MLOG_NERR1 ("Invalid variable length octetstring length: %d", 
						(ST_INT) len);
          ret_val = MVE_RT_TYPE;
	  }
        else
          asn1r_wr_octstr (aCtx,(ST_UCHAR *) (datptr + sizeof(ST_INT16)), len);
	}
    break;

    case RT_VISIBLE_STRING :
      if (((rt_ptr -> u.p.el_len > 0) && 
            (strlen (datptr) != (ST_UINT) rt_ptr->u.p.el_len)) ||
            (strlen (datptr) >  (ST_UINT) abs (rt_ptr->u.p.el_len)))
        {
        MLOG_ENC0 ("Data is illegal for VISIBLE_STRING type.");
        ret_val = MVE_ASN1_ENCODE_ERR;		/* say data is illegal for type	*/
        }
      else
        asn1r_wr_vstr (aCtx,datptr);
    break;

#ifdef TIME_DATA_SUPPORT
    case RT_GENERAL_TIME :
      asn1r_wr_time (aCtx,*((time_t *)datptr));
    break;
#endif

#ifdef BTOD_DATA_SUPPORT
    case RT_BINARY_TIME :
      i32_ptr = (ST_INT32 *) datptr;
      btod_data.ms = *i32_ptr;
      if (rt_ptr->u.p.el_len == 6)
        {
        btod_data.form = MMS_BTOD6;
        ++i32_ptr;
        btod_data.day = *i32_ptr;
        }
      else
        btod_data.form = MMS_BTOD4;

      asn1r_wr_btod (aCtx,&btod_data);
    break;
#endif

/* The u.p.el_len for BCD indicates the number of digits in the value.  */
/* Digits are represented as [0..9] requiring one nibble of storage     */
/* each.  Because all BCD values are sent over the wire as integers and */
/* the C programming language has no native BCD type, BCD values are    */
/* handled by MMS-EASE as integers.                                     */

    case RT_BCD:
      if (rt_ptr->u.p.el_len <= 2)
	asn1r_wr_i8 (aCtx,*datptr);		        /* write a single byte	        */
      else if (rt_ptr->u.p.el_len <= 4)
        asn1r_wr_i16 (aCtx,*((ST_INT16 *)datptr));
      else 
        asn1r_wr_i32 (aCtx,*((ST_INT32 *) datptr));
    break;

    case RT_UTC_TIME :
      {
      MMS_UTC_TIME *utc_time = (MMS_UTC_TIME *) datptr;
      asn1r_wr_utc_time (aCtx,utc_time);
      }
    break;

    case RT_UTF8_STRING :
      /* asn1r_wr_utf8 returns SD_SUCCESS or error code, so chk return	*/
      if (asn1r_wr_utf8 (aCtx,datptr,rt_ptr->u.p.el_len))
        {
        MLOG_NERR1 ("Data or len is illegal for UTF8(V)string%d.",
                    abs(rt_ptr->u.p.el_len));
        ret_val = MVE_ASN1_ENCODE_ERR;	/* say data is illegal for type	*/
        }
    break;

    default :
      MLOG_NERR0 ("Bad RT tag");
      ret_val = MVE_RT_TYPE;
    }

  asn1r_fin_prim (aCtx,rt_ptr->el_tag,CTX);	/* finish the primitive */

#if defined(_S_TEST_PROBES)
_CONSTRUCTED_BSOS_WRITTEN:
#endif

  if (ret_val)
    {
    ST_CHAR tmp_tdl [MAX_IDENT_LEN+1];
    MLOG_ERR0 ("Local data could not be converted to ASN.1");
    if (ms_runtime_to_tdl (rt_ptr, 1, tmp_tdl, MAX_IDENT_LEN) > 0)
      MLOG_CERR1 ("Data type TDL=%s", tmp_tdl);
    else
      MLOG_CERR1 ("Data type tag=%d", rt_ptr->el_tag);
    MLOG_CERR0 ("Local Data:");
    MLOG_ERRH (rt_ptr->el_size, datptr);
    }
  return (ret_val);
  }

/************************************************************************/
/************************************************************************/

#if defined(_S_TEST_PROBES)

static ST_RET _wr_constructed_bitstring (ASN1_ENC_CTXT *aCtx, ST_CHAR *datptr, 
					 SD_CONST RUNTIME_TYPE *rt_ptr)
  {
ST_INT16 len;
ST_INT16 el_len;
ST_INT j;
ST_INT extra_bits;
ST_INT numbytes;
ST_UCHAR *bitstr_data;
static ST_BOOLEAN firstTime = SD_TRUE;

  if (firstTime)
    {
    SLOGALWAYS0 ("TEST: Using constructed bitstrings");
    firstTime = SD_FALSE;
    }


  el_len = rt_ptr->u.p.el_len;
  if (el_len > 8 || (el_len < 0 && *(ST_INT16*)datptr > 8))
    {	/* bitstring longer than 8 bits	*/
    if (el_len < 0)
      {
      bitstr_data = datptr + 2;	/* point after ST_INT16 len	*/
      len = *(ST_INT16 *)datptr;
      }
    else
      {
      bitstr_data = datptr;
      len = el_len;
      }
    extra_bits = len % 8;
    numbytes   = len / 8;

    asn1r_strt_constr (aCtx);
    asn1r_strt_constr (aCtx);	/* nested constr. Should be ignored.*/
#if 0	/* DEBUG: enable this to send 1 garbage bit after last real segment.*/
        /* Should cause truncation for "variable length" bitstr		*/
	/* (error for "fixed length" bitstr). 				*/
    asn1r_wr_bitstr (aCtx, bitstr_data, 1);	/* write 1 bit bitstr*/
    asn1r_fin_prim (aCtx,BITS_CODE,UNI);
#endif
    /* encoding backward, so loop backward through bits.*/
    if (extra_bits)
      {
      asn1r_wr_bitstr (aCtx, bitstr_data+numbytes, extra_bits);
      /* NOTE: Tag is UNI class.*/
      asn1r_fin_prim (aCtx,BITS_CODE,UNI);
      }
    for (j = numbytes-1; j >= 0; j--)
      {
      asn1r_wr_bitstr (aCtx, bitstr_data+j, 8);	/* write 8 bit bitstr*/
      asn1r_fin_prim (aCtx,BITS_CODE,UNI);	/* finish the primitive */
      }
#if 0	/* DEBUG: enable this to send 1 garbage bit before first real segment.*/
	/* Should cause decode error. First segment must be multiple of 8 bits*/
    asn1r_wr_bitstr (aCtx, &onebit, 1);	/* write 1 bit bitstr*/
    asn1r_fin_prim (aCtx,BITS_CODE,UNI);
#endif
    asn1r_fin_constr (aCtx, BITS_CODE, UNI,DEF);	/* nested constr. Should be ignored.*/
    asn1r_fin_constr (aCtx, RT_BIT_STRING, CTX,DEF);	/* finish the constructor*/
    }
  else
    {
    asn1r_wr_bitstr (aCtx,(ST_UCHAR *)datptr,rt_ptr->u.p.el_len); /* bits */
    asn1r_fin_prim (aCtx, RT_BIT_STRING, CTX);	/* finish the primitive */
    }
  return (SD_SUCCESS);
  }

/************************************************************************/

static ST_RET _wr_constructed_octetstring (ASN1_ENC_CTXT *aCtx, ST_CHAR *datptr, 
					 SD_CONST RUNTIME_TYPE *rt_ptr)
  {
ST_INT16 len;
ST_INT j;
static ST_BOOLEAN firstTime = SD_TRUE;

  if (firstTime)
    {
    SLOGALWAYS0 ("TEST: Using constructed octetstrings");
    firstTime = SD_FALSE;
    }

  len = rt_ptr->u.p.el_len;
  if (len < 0)
    {
    len = *(ST_INT16 *)datptr;
    datptr += 2;	/* point after ST_INT16 len	*/
    }

  asn1r_strt_constr (aCtx);
  asn1r_strt_constr (aCtx);	/* nested constr. Should be ignored.*/
  /* encoding backward, so loop backward through bytes.*/
  for (j = len-1; j >= 0; j--)
    {
    asn1r_wr_octstr (aCtx, &datptr[j], 1);	/* write 1 byte*/
    /* NOTE: all prim octstr inside constructed octstr, must be UNI.*/
    asn1r_fin_prim (aCtx,OCT_CODE,UNI);	/* finish the primitive */
    }
  asn1r_fin_constr (aCtx,OCT_CODE, UNI,DEF);	/* nested constr. Should be ignored.*/
  asn1r_fin_constr (aCtx,RT_OCTET_STRING,CTX,DEF);	/* finish the constructor*/
  return (SD_SUCCESS);
  }

#endif

/************************************************************************/
/*			ms_local_to_asn1_easy				*/
/* If a data encode is NOT part of a bigger encode, 			*/
/* this function is more efficient and easier to use.			*/
/* NOTE: ms_local_to_asn1_2 is almost the same but its arguments are	*/
/*       more consistent with other encoding functions.			*/
/************************************************************************/
ST_UCHAR *ms_local_to_asn1_easy (SD_CONST RUNTIME_TYPE *rt_head, ST_INT rt_num,
			ST_CHAR *dptr,
                        ST_UCHAR *asn1Buf,
                        ST_INT asn1BufLen,
                        ST_INT *asn1LenOut)
  {
ST_RET ret_val;
ASN1_ENC_CTXT aCtx;
ST_UCHAR *asn1Start = NULL;	/* ptr to start of ASN1 encoded data	*/
				/* init to NULL (i.e. failure)		*/

  asn1r_strt_asn1_bld (&aCtx, asn1Buf, asn1BufLen);

  /* encode everything using new context.	*/
  ret_val = ms_local_to_asn1 (&aCtx, rt_head, rt_num, dptr);

  /* When the ASN.1 encode is complete, 'asn1_field_ptr' points 1 byte	*/
  /* ahead of the start of the message. The ASN.1 message is built from	*/
  /* back to front, so the length = (ptr to end) - (ptr to start)	*/
  if (ret_val == SD_SUCCESS)
    {
    asn1Start = aCtx.asn1r_field_ptr+1;
    *asn1LenOut = (asn1Buf + asn1BufLen) - asn1Start;
    }
  return (asn1Start);		/* ptr to start (or NULL on error)	*/
  }

/************************************************************************/
/*			ms_local_to_asn1_2				*/
/* If a data encode is NOT part of a bigger encode, 			*/
/* this function is easier to use.					*/
/************************************************************************/
ST_RET ms_local_to_asn1_2 (SD_CONST RUNTIME_TYPE *rt_head, ST_INT rt_num,
	ST_CHAR *dptr,			/* local data to encode		*/
	ST_UCHAR *buf_ptr,		/* buffer in which to encode	*/
	ST_INT buf_len,			/* buffer length		*/
	ST_UCHAR **asn1_ptr_out,	/* ptr to ptr to encoded data	*/
	ST_INT *asn1_len_out)		/* ptr to encoded length	*/
  {
ST_RET ret_val;
ASN1_ENC_CTXT aCtx;

  asn1r_strt_asn1_bld (&aCtx, buf_ptr, buf_len);

  /* encode everything using new context.	*/
  ret_val = ms_local_to_asn1 (&aCtx, rt_head, rt_num, dptr);

  if (ret_val == SD_SUCCESS)
    {
    /* Set output parameters (ptr & len).	*/
    *asn1_ptr_out = ASN1_ENC_PTR(&aCtx);
    *asn1_len_out = ASN1_ENC_LEN(&aCtx);
    }
  return (ret_val);
  }

/************************************************************************/
/*			_log_data_type					*/
/* Log the data type (as TDL so average user can read it).		*/
/************************************************************************/
static ST_VOID _log_data_type (SD_CONST RUNTIME_TYPE *rt_head, ST_INT rt_num)
  {
/*ST_CHAR tdl_buf [500];*/
ST_CHAR tdl_buf [500];
ST_INT tdl_len;

  tdl_len = sizeof (tdl_buf);		/* init to max allowed tdl len	*/
  tdl_len = ms_runtime_to_tdl (rt_head, rt_num, tdl_buf, tdl_len);

  if (tdl_len != 0)	/* conversion to tdl succeeded	*/
    {
    MLOG_CALWAYS1 ("Local Data Type TDL: %s", tdl_buf);	/* should be CERR1?*/
    }
  else
    {		/* conversion failed. Just log what we can.	*/
    MLOG_CALWAYS2 ("Local Runtime Type Array ptr = " S_FMT_PTR ", Num Entries = %d",
                   rt_head, rt_num);
    }
  }

