
/*
 * encdec.c,v 1.1 1994/01/28 17:22:03 franktor Exp
 *
 * encdec.c
 *
 * Copyright (c) 1992, 1993 Nordic SR-NET
 * Geir Pedersen, Geir.Pedersen@usit.uio.no
 *
 * Encoder and decoder for SR/Z39.50
 *
 *
*/

#include <sys/types.h>
/*#include <isode/tsap.h>*/
#include "SR.h"
#include "ISO10163-SR-1-types.h"
#include <sr-api.h>
#include <sr-general.h>
#include <sr-util.h>
#include <sr-low.h>

struct _RPNQuery *	encode_RPNQuery ( RPNQuery *req );
RPNQuery *		decode_RPNQuery ( struct _RPNQuery *req );
struct _RPNStructure *	encode_RPNStructure ( RPNStructure *req );
RPNStructure *		decode_RPNStructure ( struct _RPNStructure *req );
struct _Operator *	encode_Operator ( Operator req );
Operator		decode_Operator ( struct _Operator *req );

int	purify_assert_is_readable(const void *src, int n);
#define PURIFY_CHECKVAR(v)	(purify_assert_is_readable((v),sizeof(*(v))))
#define IF_PURIFY(stmt)		stmt

struct Extern *encode_EXTERN ( EXTERN *e )
{
   struct Extern		*res	= (struct Extern *) NULL;

   if ( !e )
      return res;

   res = (struct Extern *) smalloc ( sizeof ( struct Extern ) );

   if ( OID_contents ( e->directReference ) )
      res->directReference = oid_cpy ( OID_GET ( e->directReference ) );
   else
      res->directReference = NULLOID;

   if ( e->indirectReference )
   {
      res->indirectReference = *(e->indirectReference);
      SRBITSET ( res->optionals, OPT_EXTERN_INDIRECTREFERENCE );
   }
   else
      res->indirectReference = 0;

   if ( e->dataValueDescriptor )
   {
      octetString		*os	= osdup ( e->dataValueDescriptor );

      res->dataValueDescriptor.len = os->len;
      res->dataValueDescriptor.value = os->value;
      free ( os );
/*      SRBITSET ( res->optionals, OPT_EXTERN_DATAVALUEDESCRIPTOR ); */
   }
   else
      bzero ( &res->dataValueDescriptor, sizeof ( octetString ) );

   switch ( e->externEncoding )
   {
      octetString		*os;
      
    case extEncANY:
      res->offset = 1;
      res->singleASN1Type = NULLPE;
      break;

    case extEncOctetString:
      res->offset = 2;
      os = osdup ( e->octStr );
      res->octetAligned.len = os->len;
      res->octetAligned.value = os->value;
      free ( os );
      break;

    case extEncBitString:
      res->offset = 3;
      bzero ( &res->arbitrary, sizeof ( octetString ) );
      break;
   }

   (void)(PURIFY_CHECKVAR(e) && PURIFY_CHECKVAR(res));
   return res;
}

EXTERN *decode_EXTERN ( struct Extern *e )
{
   EXTERN			*res		= (EXTERN *) NULL;

   if ( !e )
      return res;

   res = (EXTERN *) smalloc ( sizeof ( EXTERN ) );
   
   if ( e->directReference )
      res->directReference = OID_str2Oid ( sprintoid ( e->directReference ) );
   else
      res->directReference = OID_NULLPTR;
   if ( SRBITTEST ( e->optionals, OPT_EXTERN_INDIRECTREFERENCE ) )
   {
      res->indirectReference = (int *) smalloc ( sizeof ( int ) );
      *(res->indirectReference) = e->indirectReference;
   }
   IF_PURIFY(else res->indirectReference = NULL);
/* if ( SRBITTEST ( e->optionals, OPT_EXTERN_DATAVALUEDESCRIPTOR ) ) */
   if ( e->dataValueDescriptor.value && e->dataValueDescriptor.len )
      res->dataValueDescriptor = osdup ( &e->dataValueDescriptor );
   IF_PURIFY(else res->dataValueDescriptor = NULL);
   IF_PURIFY(res->octStr = NULL);

   switch ( e->offset )
   {
    case 1:
      res->externEncoding = extEncANY;
      break;

    case 2:
      res->externEncoding = extEncOctetString;
      res->octStr = osdup ( &e->octetAligned );
      break;

    case 3:
      res->externEncoding = extEncBitString;
      break;

    default:
      res->externEncoding = -1;		/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "decode_EXTERN: bad offset %d", e->offset);
      break;
   }

   (void)(PURIFY_CHECKVAR(res));
   return res;
}


/* Initialise
*/

PE encode_Authentication ( Authentication *req )
{
   struct _Authentication	a;
   PE				pe		= NULLPE;

   if ( !req )
      return NULLPE;
   
   bzero ( (char *) &a, sizeof ( struct _Authentication ) );

   if ( req->user )
   {
      a.user.len = req->user->len;
      a.user.value = safe_strdup ( req->user->value );

      a.password.len = req->password->len;
      a.password.value = safe_strdup ( req->password->value );

      a.account.len = req->account->len;
      a.account.value = safe_strdup ( req->account->value );
   }

   (void)(PURIFY_CHECKVAR(req));
   if ( encode_ISO10163__SR__1_Authentication ( &pe, 1, 0, NULLCP, &a ) == NOTOK )
      return NULLPE;

   (void)(PURIFY_CHECKVAR(pe));
   return pe;
}

struct Authentication *decode_Authentication ( PE pe )
{
   struct _Authentication	*a;
   Authentication		*res	= (struct Authentication *) NULL;
   
   if ( pe == NULLPE )
      return res;

   if ( decode_ISO10163__SR__1_Authentication ( pe, 1, 0, NULLCP, &a ) == NOTOK )
      return res;

   res = (Authentication *) smalloc ( sizeof ( Authentication ) );
   res->user = osdup ( &a->user );
   res->password = osdup ( &a->password );
   res->account = osdup ( &a->account );

   (void)(PURIFY_CHECKVAR(res));
   return res;
}

struct _InitialiseRequest *encode_InitialiseRequest ( SRInitialiseRequest *req )
{
   char				*cp;
   struct _InitialiseRequest	*res	= (struct _InitialiseRequest *) smalloc ( sizeof ( struct _InitialiseRequest ) );

   res->referenceId = NULLOS;

   cp = int2strb(req->protocolVersion, sizeof req->protocolVersion * 8 );
   res->protocolVersion = strb2bitstr ( cp, sizeof req->protocolVersion * 8, PE_CLASS_UNIV, PE_PRIM_BITS );

   cp = int2strb(req->options, sizeof req->options * 8 );
   res->options = strb2bitstr ( cp, sizeof req->options * 8, PE_CLASS_UNIV, PE_PRIM_BITS );

   res->preferredMessageSize = req->preferredMessageSize;
   res->maximumMessageSize = req->maximumMessageSize;

   res->authentication = encode_Authentication ( req->authentication );

   res->implementationId = safe_strdup ( req->implementationId );
   res->implementationName = safe_strdup ( req->implementationName );
   res->implementationVersion = safe_strdup ( req->implementationVersion );

   res->userInformationField = encode_EXTERN ( req->userInformationField );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

SRInitialiseRequest *decode_InitialiseRequest ( struct _InitialiseRequest *req )
{
   char				*cp;
   int				len;
   struct SRInitialiseRequest 	*res	= (struct SRInitialiseRequest *) smalloc ( sizeof ( struct SRInitialiseRequest ) );

   if ( req->protocolVersion )
   {
      cp = bitstr2strb ( req->protocolVersion, &len );
      if ( len > sizeof res->protocolVersion )
	 len = sizeof res->protocolVersion;
      res->protocolVersion = strb2int ( cp, len );
   }
   else
      res->protocolVersion = 0;
   
   if ( req->options )
   {
      cp = bitstr2strb ( req->options, &len );
      if ( len > sizeof res->options )
	 len = sizeof res->options;
      res->options = strb2int ( cp, len );
   }
   else
      res->options = 0;
   
   res->preferredMessageSize = req->preferredMessageSize;
   res->maximumMessageSize = req->maximumMessageSize;

   res->authentication = decode_Authentication ( req->authentication );

   res->implementationId = safe_strdup ( req->implementationId );
   res->implementationName = safe_strdup ( req->implementationName );
   res->implementationVersion = safe_strdup ( req->implementationVersion );

   res->userInformationField = decode_EXTERN ( req->userInformationField );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _InitialiseResponse *encode_InitialiseResponse ( SRInitialiseResponse *req )
{
   struct _InitialiseResponse	*res 	= (struct _InitialiseResponse *) smalloc ( sizeof ( struct _InitialiseResponse ) );
   char				*cp;
   
   res->referenceId = NULLOS;

   cp = int2strb ( req->protocolVersion, sizeof req->protocolVersion * 8 );
   res->protocolVersion = strb2bitstr ( cp, sizeof req->protocolVersion * 8, PE_CLASS_UNIV, PE_PRIM_BITS );

   cp = int2strb ( req->options, sizeof req->options * 8 );
   res->options = strb2bitstr ( cp, PE_CLASS_UNIV, PE_PRIM_BITS );
   
   res->preferredMessageSize = req->preferredMessageSize;
   res->maximumMessageSize = req->maximumMessageSize;

   res->initializationStatus = req->initializationStatus ? 1 : 0;

   res->implementationId = safe_strdup ( req->implementationId );
   res->implementationName = safe_strdup ( req->implementationName );
   res->implementationVersion = safe_strdup ( req->implementationVersion );

   res->userInformationField = encode_EXTERN ( req->userInformationField );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

SRInitialiseResponse *decode_InitialiseResponse ( struct _InitialiseResponse *req )
{
   char				*cp;
   int				len;
   struct SRInitialiseResponse	*res	= (struct SRInitialiseResponse *) smalloc ( sizeof ( struct SRInitialiseResponse ) );

   if ( req->protocolVersion )
   {
      cp = bitstr2strb ( req->protocolVersion, &len );
      if ( len > sizeof res->protocolVersion )
	 len = sizeof res->protocolVersion;
      res->protocolVersion = strb2int ( cp, len );
   }
   else
      res->protocolVersion = 0;
   
   if ( req->options )
   {
      cp = bitstr2strb ( req->options, &len );
      if ( len > sizeof res->options )
	 len = sizeof res->options;
      res->options = strb2int ( cp, len );
   }
   else
      res->options = 0;
   
   res->preferredMessageSize = req->preferredMessageSize;
   res->maximumMessageSize = req->maximumMessageSize;

   res->initializationStatus = req->initializationStatus ? True : False;

   res->implementationId = safe_strdup ( req->implementationId );
   res->implementationName = safe_strdup ( req->implementationName );
   res->implementationVersion = safe_strdup ( req->implementationVersion );

   res->userInformationField = decode_EXTERN ( req->userInformationField );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}
   



/* SEARCH
*/

struct _Query *encode_Query ( Query *req )
{
   struct _Query	*res	= (struct _Query *) smalloc ( sizeof ( struct _Query ) );
   octetString		*tmp;
   
   switch ( req->kind )
   {
    case queryPrivate:
      IF_PURIFY(bzero(res,sizeof(*res)));
      res->offset = 1;
      res->privateQuery = NULLPE;
      break;

    case queryRpnQuery:
      IF_PURIFY(bzero(res,sizeof(*res)));
      res->offset = 2;
      res->rpnQuery = encode_RPNQuery ( req->q.rpnQuery );
      break;

    case queryIso8777Query:
      IF_PURIFY(bzero(res,sizeof(*res)));
      res->offset = 3;
      if ( (res->iso8777Query.len = req->q.iso8777Query->len) != 0 )
      {
	 tmp = osdup ( req->q.iso8777Query );
	 res->iso8777Query.value = tmp->value;
	 free ( tmp );
      }
      else
	 res->iso8777Query.value = (char *) NULL;
      break;

    default:
      res->offset = 0;			/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "encode_Query: bad record kind %d", (int)req->kind);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

   
struct Query *decode_Query ( struct _Query *req )   
{
   Query		*res	= (Query *) smalloc ( sizeof ( Query ) );

   switch ( req->offset )
   {
    case 1:
      res->kind = queryPrivate;
      break;

    case 2:
      res->kind = queryRpnQuery;
      res->q.rpnQuery = decode_RPNQuery ( req->rpnQuery );
      break;

    case 3:
      res->kind = queryIso8777Query;
      res->q.iso8777Query = osdup ( &req->iso8777Query );
      break;

    default:
      res->kind = -1;			/* Handle unexpected value.  --hbf */
      LOG (facLow, llevExceptions, "decode_Query: bad offset %d", req->offset);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _RPNQuery *encode_RPNQuery ( RPNQuery *req )
{
   struct _RPNQuery	*res	= (struct _RPNQuery *) smalloc ( sizeof ( struct _RPNQuery ) );

   res->attributeSetId = oid_cpy ( OID_GET ( req->attributeSetId ) );
   res->rpnStructure = encode_RPNStructure ( req->rpnStructure );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

RPNQuery *decode_RPNQuery ( struct _RPNQuery *req )
{
   RPNQuery		*res	= (RPNQuery *) smalloc ( sizeof ( RPNQuery ) );

   res->attributeSetId = OID_str2Oid ( sprintoid ( req->attributeSetId ) );
   res->rpnStructure = decode_RPNStructure ( req->rpnStructure );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _AttributeElement *encode_AttributeElement ( AttributeElement *req )
{
   struct _AttributeElement *res = (struct _AttributeElement *) smalloc ( sizeof (struct _AttributeElement) );

   res->attributeType = req->attributeType;
   res->attributeValue = req->attributeValue;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

AttributeElement *decode_AttributeElement ( struct _AttributeElement *req )
{
   struct AttributeElement *res = (AttributeElement *) smalloc ( sizeof ( AttributeElement ) );

   res->attributeType = req->attributeType;
   res->attributeValue = req->attributeValue;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _AttributeList *encode_AttributeList ( AttributeList *req )
{
   struct _AttributeList	*res = (struct _AttributeList *) smalloc ( sizeof ( struct _AttributeList ) );

   res->attributeElement = encode_AttributeElement ( req->attrElem );
   if ( req->next )
      res->next = encode_AttributeList ( req->next );
   else
      res->next = (struct _AttributeList *) NULL;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

AttributeList *decode_AttributeList ( struct _AttributeList *req )
{
   AttributeList 	*res 	= (AttributeList *) smalloc ( sizeof ( AttributeList ) );

   res->attrElem = decode_AttributeElement ( req->attributeElement );
   if ( req->next )
      res->next = decode_AttributeList ( req->next );
   else
      res->next = (AttributeList *) NULL;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _AttributesPlusTerm *encode_AttributesPlusTerm ( AttributesPlusTerm *req )
{
   struct _AttributesPlusTerm *res = (struct _AttributesPlusTerm *) smalloc ( sizeof ( struct _AttributesPlusTerm ) );

   res->attributeList = encode_AttributeList ( req->attributeList );
   res->term = osdup ( req->term );
   if ( req->next )
      res->next = encode_AttributesPlusTerm ( req->next );
   else
      res->next = (struct _AttributesPlusTerm *) NULL;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

AttributesPlusTerm *decode_AttributesPlusTerm ( struct _AttributesPlusTerm *req )
{
   AttributesPlusTerm	*res 	= (AttributesPlusTerm *) smalloc ( sizeof ( AttributesPlusTerm ) );

   res->attributeList = decode_AttributeList ( req->attributeList );
   res->term = osdup ( req->term );
   if ( req->next )
      res->next = decode_AttributesPlusTerm ( req->next );
   else
      res->next = (struct AttributesPlusTerm *) NULL;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _Operand *encode_Operand ( Operand *req ) 
{
   struct _Operand	*res	= (struct _Operand *) smalloc ( sizeof ( struct _Operand ) );

   switch ( req->kind )
   {
    case operandAttrsPlusTerm:
      res->offset = 1;
      res->attributesPlusTerm = encode_AttributesPlusTerm ( req->attrsPlusTerm );
      break;

    case operandResultSet:
      res->offset = 2;
      res->resultSetId = safe_strdup ( req->resultSetId );
      break;

    default:
      res->offset = 0;			/* Handle unexpected value.  --hbf */
      LOG (facLow, llevExceptions, "encode_Operand: bad record kind %d", (int)req->kind);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

Operand *decode_Operand ( struct _Operand *req )
{
   Operand		*res 	= (Operand *) smalloc ( sizeof ( Operand ) );

   switch ( req->offset )
   {
    case 1:
      res->kind = operandAttrsPlusTerm;
      res->attrsPlusTerm = decode_AttributesPlusTerm ( req->attributesPlusTerm );
      break;

    case 2:
      res->kind = operandResultSet;
      res->resultSetId = safe_strdup ( req->resultSetId );
      break;

    default:
      res->kind = -1;			/* Handle unexpected value.  --hbf */
      LOG (facLow, llevExceptions, "decode_Operand: bad offset %d", req->offset);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _RPNStructure *encode_RPNStructure ( RPNStructure *req )
{
   struct _RPNStructure	*res	= (struct _RPNStructure *) smalloc ( sizeof ( struct _RPNStructure ) );

   switch ( req->kind )
   {
    case rpnOpr:
      res->offset = 1;
      res->operand = encode_Operand ( req->u.operand );
      break;

    case rpnSeq:
      res->offset = 2;
      res->compound.rpnStructure1 = encode_RPNStructure ( req->u.s.rpnStructure1 );
      res->compound.rpnStructure2 = encode_RPNStructure ( req->u.s.rpnStructure2 );
      res->compound.operator = encode_Operator ( req->u.s.operator );
      break;

    default:
      res->offset = 0;			/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "encode_RPNStructure: bad record kind %d", (int)req->kind);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

RPNStructure *decode_RPNStructure ( struct _RPNStructure *req )
{
   RPNStructure		*res	= (RPNStructure *) smalloc ( sizeof ( RPNStructure ) );

   switch ( req->offset )
   {
    case 1:
      res->kind = rpnOpr;
      res->u.operand = decode_Operand ( req->operand );
      break;

    case 2:
      res->kind = rpnSeq;
      res->u.s.rpnStructure1 = decode_RPNStructure ( req->compound.rpnStructure1 );
      res->u.s.rpnStructure2 = decode_RPNStructure ( req->compound.rpnStructure2 );
      res->u.s.operator = decode_Operator ( req->compound.operator );
      break;
      
    default:
      res->kind = -1;			/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "decode_RPNStructure: bad offset %d", req->offset);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _Operator *encode_Operator ( Operator req )
{
   struct _Operator	*res 	= (struct _Operator *) smalloc ( sizeof ( struct _Operator ) );

   switch ( req )
   {
    case operatorAnd:
      res->offset = 1;
      break;

    case operatorOr:
      res->offset = 2;
      break;

    case operatorAndNot:
      res->offset = 3;
      break;

    default:
      res->offset = 1;
      break;
   }

   (void)(PURIFY_CHECKVAR(&req) && PURIFY_CHECKVAR(res));
   return res;
}

Operator decode_Operator ( struct _Operator *req )
{
   (void)(PURIFY_CHECKVAR(req));
   switch ( req->offset )
   {
    case 1:
      return operatorAnd;

    case 2:
      return operatorOr;

    default:
    case 3:
      return operatorAndNot;
   }
   /*NOTREACHED*/
}

struct _DiagRec *encode_DiagRec ( DiagRec *req )
{
   struct _DiagRec 	*res	= (struct _DiagRec *) smalloc ( sizeof ( struct _DiagRec ) );

   res->diagnosticSetId = oid_cpy ( OID_GET ( req->diagnosticSetId ) );
   res->condition = req->condition;
   res->addinfo = safe_strdup ( req->addinfo );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

DiagRec *decode_DiagRec ( struct _DiagRec *req )
{
   DiagRec		*res 	= (DiagRec *) smalloc ( sizeof ( DiagRec ) );

   res->diagnosticSetId = OID_str2Oid ( sprintoid ( req->diagnosticSetId ) );
   res->condition = req->condition;
   res->addinfo = safe_strdup ( req->addinfo );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _NamePlusRecord *encode_NamePlusRecord ( NamePlusRecord *req )
{
   struct _NamePlusRecord *res;

   if ( !req )
      return ( struct _NamePlusRecord * ) NULL;
   
   res = (struct _NamePlusRecord *) smalloc ( sizeof ( struct _NamePlusRecord ) );

   res->databaseName = safe_strdup ( req->databaseName );

   switch ( req->nprKind )
   {
    case nprRecord:
      res->offset = 1;
      res->databaseRecord = encode_EXTERN ( req->u.databaseRecord );
      break;

    case nprDiag:
      res->offset = 2;
      res->surrogateDiagnostic = encode_DiagRec ( req->u.surrogateDiagnostic );
      break;

    default:
      res->offset = 0;			/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "encode_NamePlusRecord: bad record kind %d", (int)req->nprKind);
      break;
   }

   res->next = encode_NamePlusRecord ( req->next );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

NamePlusRecord *decode_NamePlusRecord ( struct _NamePlusRecord *req )
{
   NamePlusRecord	*res;

   if ( !req )
      return (NamePlusRecord *) NULL;

   res = (NamePlusRecord *) smalloc ( sizeof ( NamePlusRecord ) );

   res->databaseName = safe_strdup ( req->databaseName );

   switch ( req->offset )
   {
    case 1:
      res->nprKind = nprRecord;
      res->u.databaseRecord = decode_EXTERN ( req->databaseRecord );
      break;

    case 2:
      res->nprKind = nprDiag;
      res->u.surrogateDiagnostic = decode_DiagRec ( req->surrogateDiagnostic );
      break;

    default:
      res->nprKind = -1;		/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "decode_NamePlusRecord: bad offset %d", req->offset);
      break;
   }

   res->next = decode_NamePlusRecord ( req->next );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _Records *encode_Records ( Records *req )
{
   struct _Records	*res;

   if ( !req )
      return (struct _Records *) NULL;

   res = (struct _Records *) smalloc ( sizeof ( struct _Records ) );

   switch ( req->recKind )
   {
    case recNamePlusRecord:
      res->offset = 1;
      res->databaseOrSurDiagnostics = encode_NamePlusRecord ( req->u.databaseOrSurDiagnostics );
      break;

    case recDiagRec:
      res->offset = 2;
      res->nonSurrogateDiagnostic = encode_DiagRec ( req->u.nonSurrogateDiagnostic );
      break;

    default:
      res->offset = 0;			/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "encode_Records: bad record kind %d", (int)req->recKind);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

Records *decode_Records ( struct _Records *req )
{
   Records		*res;

   if ( !req )
      return (Records *) NULL;
   
   res 	= (Records *) smalloc ( sizeof ( Records ) );

   switch ( req->offset )
   {
    case recNamePlusRecord:
      res->recKind = recNamePlusRecord;
      res->u.databaseOrSurDiagnostics = decode_NamePlusRecord ( req->databaseOrSurDiagnostics );
      break;

    case recDiagRec:
      res->recKind = recDiagRec;
      res->u.nonSurrogateDiagnostic = decode_DiagRec ( req->nonSurrogateDiagnostic );
      break;

    default:
      res->recKind = -1;		/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "decode_Records: bad offset %d", req->offset);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}


struct _SeqOf_DatabaseName *encode_SeqOfDatabaseName ( char **req, int size )
{
   struct _SeqOf_DatabaseName	*res 	= (struct _SeqOf_DatabaseName *) smalloc ( sizeof ( struct _SeqOf_DatabaseName ) );

   res->name = safe_strdup ( req[0] );
   if ( size > 1 )
      res->next = encode_SeqOfDatabaseName ( &req[1], size-1 );
   else
      res->next = (struct _SeqOf_DatabaseName *) NULL;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

char **decode_SeqOfDatabaseName ( struct _SeqOf_DatabaseName *req, int *size )
{
   int				s;
   char				**res;
   struct _SeqOf_DatabaseName	*x;
   
   for ( s = 0, x = req; x; x = x->next, s++ );

   *size = s;
   res = (char **) smalloc ( sizeof (char *) * s );

   for ( s = 0, x = req; x; x = x->next, s++ )
      res[s] = safe_strdup ( x->name );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _RCDatabaseSpecific *encode_RCDatabaseSpecific ( RCNameAndId *sr_rc )
{
   struct _RCDatabaseSpecific *res	= (struct _RCDatabaseSpecific *) smalloc ( sizeof ( struct _RCDatabaseSpecific ) );

   res->databaseName = safe_strdup ( sr_rc->databaseName );
   res->recordCompositionId = safe_strdup ( sr_rc->recordCompositionId );
   if ( sr_rc->next )
      res->next = encode_RCDatabaseSpecific ( sr_rc->next );
   else
      res->next = (struct _RCDatabaseSpecific *) NULL;

   (void)(PURIFY_CHECKVAR(sr_rc) && PURIFY_CHECKVAR(res));
   return res;
}

RCNameAndId *decode_RCDatabaseSpecific ( struct _RCDatabaseSpecific *req )
{
   struct _RCDatabaseSpecific	*rc;
   struct RCNameAndId *sr_rc = NULL, *prev_sr_rc = NULL;
   
   for ( rc = req; rc; rc = rc->next, prev_sr_rc = sr_rc )
   {
      sr_rc = (RCNameAndId *) malloc(sizeof(RCNameAndId));
      sr_rc->databaseName = safe_strdup(rc->databaseName);
      sr_rc->recordCompositionId = safe_strdup(rc->recordCompositionId);
      sr_rc->next = NULL;
      if (prev_sr_rc)
	 prev_sr_rc->next = sr_rc;
   }
   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(sr_rc));
   return sr_rc;
}

struct _RecordComposition *encode_RecordComposition ( RecordComposition *req )
{
   struct _RecordComposition		*res;

   if ( !req )
      return (struct _RecordComposition *) NULL;

   res = (struct _RecordComposition *) smalloc ( sizeof ( struct _RecordComposition ));
   
   switch ( req->genericRecordComposition )
   {
    case True:
      res->offset = 1;
      res->generic = safe_strdup ( req->u.generic );
      IF_PURIFY(res->databaseSpecific = NULL);
      break;
    case False:
      res->offset = 2;
      IF_PURIFY(res->generic = NULL);
      res->databaseSpecific = encode_RCDatabaseSpecific ( req->u.databaseSpecific );
      break;
    default:
      res->offset = 0;			/* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "encode_RecordComposition: bad record composition %d", (int)req->genericRecordComposition);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

RecordComposition *decode_RecordComposition ( struct _RecordComposition *req )
{
   RecordComposition 	*res;
   
   if ( !req )
      return ( RecordComposition * ) NULL;

   res = (RecordComposition *) smalloc ( sizeof ( RecordComposition ) );

   switch ( req->offset )
   {
    case 1:
      res->genericRecordComposition = True;
      res->u.generic = safe_strdup ( req->generic );
      break;

    case 2:
      res->genericRecordComposition = False;
      res->u.databaseSpecific = decode_RCDatabaseSpecific ( req->databaseSpecific );
      break;

    default:
      res->genericRecordComposition = -1; /* Handle unexpected value.  -hbf */
      LOG (facLow, llevExceptions, "decode_RecordComposition: bad offset %d", req->offset);
      break;
   }

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}
   
struct _SearchRequest *encode_SearchRequest ( SRSearchRequest *req )
{
   struct _SearchRequest 	*res 	= (struct _SearchRequest *) smalloc ( sizeof ( struct _SearchRequest ) );

   res->referenceId = NULLOS;
   res->smallSetUpperBound = req->smallSetUpperBound;
   res->largeSetLowerBound = req->largeSetLowerBound;
   res->mediumSetPresentNumber = req->mediumSetPresentNumber;
   res->replaceIndicator = (req->replaceIndicator ? 1 : 0);
   res->proposedResultSetId = safe_strdup ( req->proposedResultSetId );
   res->databaseId = encode_SeqOfDatabaseName ( req->databaseId, req->noDatabaseIds );
   res->smallSetRecordComposition = encode_RecordComposition ( req->smallSetRecordComposition );
   res->mediumSetRecordComposition = encode_RecordComposition ( req->mediumSetRecordComposition );
   res->preferredRecordSyntax = oid_cpy ( OID_GET ( req->preferredRecordSyntax ) );
   res->query = encode_Query ( req->query );

   IF_PURIFY(bzero(&res->replaceIndicator+1, (char*)&res->proposedResultSetId - (&res->replaceIndicator+1)));
   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

SRSearchRequest *decode_SearchRequest ( struct _SearchRequest *req )
{
   SRSearchRequest	*res 	= (SRSearchRequest *) smalloc ( sizeof ( SRSearchRequest ) );

   res->smallSetUpperBound = req->smallSetUpperBound;
   res->largeSetLowerBound = req->largeSetLowerBound;
   res->mediumSetPresentNumber = req->mediumSetPresentNumber;
   if ( req->replaceIndicator )
      res->replaceIndicator = True;
   else
      res->replaceIndicator = False;
   res->proposedResultSetId = safe_strdup ( req->proposedResultSetId );
   res->databaseId = decode_SeqOfDatabaseName ( req->databaseId, &res->noDatabaseIds );
   res->smallSetRecordComposition = decode_RecordComposition ( req->smallSetRecordComposition );
   res->mediumSetRecordComposition = decode_RecordComposition ( req->mediumSetRecordComposition );
   res->preferredRecordSyntax = OID_str2Oid ( sprintoid ( req->preferredRecordSyntax ) );
   res->query = decode_Query ( req->query );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _SearchResponse *encode_SearchResponse ( SRSearchResponse *req )
{
   struct _SearchResponse	*res	= (struct _SearchResponse *) smalloc ( sizeof ( struct _SearchResponse ) );

   res->referenceId = NULLOS;
   res->numberOfRecordsFound = req->numberOfRecordsFound;
   res->numberOfRecordsReturned = req->numberOfRecordsReturned;
   res->nextResultSetPosition = req->nextResultSetPosition;
   res->searchStatus = req->searchStatus ? 1 : 0;

   if ( req->resultSetStatus == resultSetStatus_ignore )
      res->resultSetStatus = 0;
   else
   {
      SRBITSET ( res->optionals, OPT_SEARCHRESP_RESULTSETSTATUS );
      
      switch ( req->resultSetStatus )
      {
       case resultSetStatus_subset:
	 res->resultSetStatus = 1;
	 break;

       case resultSetStatus_interim:
	 res->resultSetStatus = 2;
	 break;

       case resultSetStatus_none:
	 res->resultSetStatus = 3;
	 break;

       default:
	 res->resultSetStatus = 0;	/* Handle unexpected value.  -hbf */
	 LOG (facLow, llevExceptions, "encode_SearchResponse: bad status %d", (int)req->resultSetStatus);
	 break;
      }
   }

   if ( req->presentStatus != presentStatus_ignore )
   {
      res->presentStatus = (int) req->presentStatus;
      SRBITSET ( res->optionals, OPT_SEARCHRESP_PRESENTSTATUS );
   }

   res->records = encode_Records ( req->records );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

SRSearchResponse *decode_SearchResponse ( struct _SearchResponse *req )
{
   SRSearchResponse	*res	= (SRSearchResponse *) smalloc ( sizeof ( SRSearchResponse ) );

   res->numberOfRecordsFound = req->numberOfRecordsFound;
   res->numberOfRecordsReturned = req->numberOfRecordsReturned;
   res->nextResultSetPosition = req->nextResultSetPosition;
   res->searchStatus = req->searchStatus ? True : False;

   if ( SRBITTEST ( req->optionals, OPT_SEARCHRESP_RESULTSETSTATUS ) )
      switch ( req->resultSetStatus )
      {
       case 1:
	 res->resultSetStatus = resultSetStatus_subset;
	 break;

       case 2:
	 res->resultSetStatus = resultSetStatus_interim;
	 break;

       case 3:
	 res->resultSetStatus = resultSetStatus_none;
	 break;

       default:
	 res->resultSetStatus = resultSetStatus_ignore;	/* Handle unexpected value.  -hbf */
	 LOG (facLow, llevExceptions, "encode_SearchResponse: bad status %d", (int)req->resultSetStatus);
	 break;
      }
   else
      res->resultSetStatus = resultSetStatus_ignore;

   if ( SRBITTEST ( req->optionals, OPT_SEARCHRESP_PRESENTSTATUS ) )
      res->presentStatus = (PresentStatus) req->presentStatus;
   else
      res->presentStatus = presentStatus_ignore;

   res->records = decode_Records ( req->records );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}


/* PRESENT
*/

struct _PresentRequest *encode_PresentRequest ( SRPresentRequest *req )
{
   struct _PresentRequest	*res	= (struct _PresentRequest *) smalloc ( sizeof ( struct _PresentRequest ) );

   res->referenceId = NULLOS;
   res->resultSetId = safe_strdup ( req->resultSetId );
   res->resultSetStartPoint = req->resultSetStartPoint;
   res->numberOfRecordsRequested = req->numberOfRecordsRequested;
   res->recordComposition = encode_RecordComposition ( req->recordComposition );
   res->preferredRecordSyntax = oid_cpy ( OID_GET ( req->preferredRecordSyntax ) );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

SRPresentRequest *decode_PresentRequest ( struct _PresentRequest *req )
{
   SRPresentRequest	*res	= (SRPresentRequest *) smalloc ( sizeof ( SRPresentRequest ) );

   res->resultSetId = safe_strdup ( req->resultSetId );
   res->resultSetStartPoint = req->resultSetStartPoint;
   res->numberOfRecordsRequested = req->numberOfRecordsRequested;
   res->recordComposition = decode_RecordComposition ( req->recordComposition );
   res->preferredRecordSyntax = OID_str2Oid ( sprintoid ( req->preferredRecordSyntax ) );
   
   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _PresentResponse *encode_PresentResponse ( SRPresentResponse *req )
{
   struct _PresentResponse	*res	= (struct _PresentResponse *) smalloc ( sizeof ( struct _PresentResponse ) );

   res->referenceId = NULLOS;
   res->numberOfRecordsReturned = req->numberOfRecordsReturned;
   res->nextResultSetPosition = req->nextResultSetPosition;
   res->presentStatus = req->presentStatus;
   res->records = encode_Records ( req->records );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

SRPresentResponse *decode_PresentResponse ( struct _PresentResponse *req )
{
   SRPresentResponse	*res	= (SRPresentResponse *) smalloc ( sizeof ( SRPresentResponse ) );

   res->numberOfRecordsReturned = req->numberOfRecordsReturned;
   res->nextResultSetPosition = req->nextResultSetPosition;
   res->presentStatus = req->presentStatus;
   res->records = decode_Records ( req->records );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}


/* DELETE RESULT SET
*/

struct _ResultSetList *encode_ResultSetList ( ResultSetList *req )
{
   struct _ResultSetList	*res;

   if ( !req )
      return (struct _ResultSetList *) NULL;
   
   res	= (struct _ResultSetList *) smalloc ( sizeof ( struct _ResultSetList ) );

   res->resultSetId = safe_strdup ( req->resultSetId );
   if ( req->next )
      res->next = encode_ResultSetList ( req->next );
   else
      res->next = (struct _ResultSetList *) NULL;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

ResultSetList *decode_ResultSetList ( struct _ResultSetList *req )
{
   ResultSetList		*res;

   if ( !req )
      return (ResultSetList *) NULL;

   res 	= (ResultSetList *) smalloc ( sizeof ( ResultSetList ) );
   
   res->resultSetId = safe_strdup ( req->resultSetId );
   if ( req->next )
      res->next = decode_ResultSetList ( req->next );
   else
      res->next = (ResultSetList *) NULL;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

struct _ListStatuses *encode_ListStatuses ( ListStatuses *req )
{
   struct _ListStatuses		*res;

   if ( !req )
      return (struct _ListStatuses *) NULL;
   
   res	= (struct _ListStatuses *) smalloc ( sizeof ( ListStatuses ) );

   res->resultSetId = safe_strdup ( req->resultSetId );
   res->deleteSetStatus = (int) req->deleteSetStatus;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

ListStatuses *decode_ListStatuses ( struct _ListStatuses *req )
{
   ListStatuses			*res;

   if ( !req )
      return (ListStatuses *) NULL;
   
   res	= (ListStatuses *) smalloc ( sizeof ( ListStatuses ) );

   res->resultSetId = safe_strdup ( req->resultSetId );
   res->deleteSetStatus = (DeleteSetStatus) req->deleteSetStatus;

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}
   
struct _DeleteResultSetRequest *encode_DeleteResultSetRequest ( SRDeleteResultSetRequest *req )
{
   struct _DeleteResultSetRequest	*res	= (struct _DeleteResultSetRequest *) smalloc ( sizeof ( struct _DeleteResultSetRequest ) );

   res->referenceId = NULLOS;
   res->deleteSetFunction = (int) req->deleteSetFunction;
   res->resultSetList = encode_ResultSetList ( req->resultSetList );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

SRDeleteResultSetRequest *decode_DeleteResultSetRequest ( struct _DeleteResultSetRequest *req )
{	
   SRDeleteResultSetRequest	*res	= (SRDeleteResultSetRequest *) smalloc ( sizeof ( SRDeleteResultSetRequest ) );

   res->deleteSetFunction = (int) req->deleteSetFunction;
   res->resultSetList = decode_ResultSetList ( req->resultSetList );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}
   
struct _DeleteResultSetResponse *encode_DeleteResultSetResponse ( SRDeleteResultSetResponse *req )
{
   struct _DeleteResultSetResponse 	*res	= (struct _DeleteResultSetResponse *) smalloc ( sizeof ( struct _DeleteResultSetResponse ) );

   res->referenceId = NULLOS;
   res->deleteOperationStatus = (int) req->deleteOperationStatus;
   res->deleteListStatuses = encode_ListStatuses ( req->deleteListStatuses );
   if (req->numberNotDeleted != -1 )
   {
      res->numberNotDeleted = req->numberNotDeleted;
      SRBITSET ( res->optionals, OPT_DELRESULTSETRESP_NUMBERNOTDELETED );
   }
   res->bulkStatuses = encode_ListStatuses ( req->bulkStatuses );
   res->deleteMessage = safe_strdup ( req->deleteMessage );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}

SRDeleteResultSetResponse *decode_DeleteResultSetResponse ( struct _DeleteResultSetResponse *req )
{
   SRDeleteResultSetResponse 	*res	= (SRDeleteResultSetResponse *) smalloc ( sizeof ( SRDeleteResultSetResponse ) );
   
   res->deleteOperationStatus = (int) req->deleteOperationStatus;
   res->deleteListStatuses = decode_ListStatuses ( req->deleteListStatuses );
   if ( SRBITTEST ( req->optionals, OPT_DELRESULTSETRESP_NUMBERNOTDELETED ) )
      res->numberNotDeleted = req->numberNotDeleted;
   else
      res->numberNotDeleted = -1;
   res->bulkStatuses = decode_ListStatuses ( req->bulkStatuses );
   res->deleteMessage = safe_strdup ( req->deleteMessage );

   (void)(PURIFY_CHECKVAR(req) && PURIFY_CHECKVAR(res));
   return res;
}


