#ifndef __ucf_h
#define __ucf_h

#include <stdio.h>
#include <setjmp.h>
#include <limits.h>

#include "gci.h"

typedef struct sCoder tCoder;
typedef tCoder* tBuffer;

/* EMS */

#define CODER_PATH_DEEP 64

typedef struct
{
  void*          Fields[CODER_PATH_DEEP];
  unsigned long  NumOfFields;
} tErrorPath;

typedef struct
{
  int           ErrorCode;
  jmp_buf       ReturnPoint;
  unsigned char IsAssigned;
  tErrorPath    ErrorPath;
} tEMS;

enum
{
  ec_SUCCESS,

  /* Memory errors */
  ec_MEM_NotEnoughMemory,

  /* Buffer errors */
  ec_BUF_DifferentBufferTypes,
  ec_BUF_WrongBufferType,
  ec_BUF_CloseNotInitialized,
  ec_BUF_WorkWithNotInitialized,
  ec_BUF_NullPtrToUserMemory,
  ec_BUF_NotEnoughUserMemory,
  ec_BUF_OpenOpened,
  ec_BUF_IllegalClose,
  ec_BUF_CloseWrongMode,
  ec_BUF_OperationWrongMode,
  ec_BUF_NoMoreDataForRead,
  ec_BUF_TooBigNumberOfBits,
  ec_BUF_InvalidEncodingRules,

  /* Internal errors */
  ec_INT_InternalError,
  ec_INT_UnsupportedType,

  /* Value errors */
  ec_VAL_IllegalRealBase,
  ec_VAL_WrongConstrainedValue,
  ec_VAL_WrongConstrainedLength,
  ec_VAL_WrongConstrainedAlphabet,
  ec_VAL_WrongEnumeratedValue,

/* Decode errors */
  ec_DEC_NoMoreDataForRead,
  ec_DEC_WrongIdentifierOctet,
  ec_DEC_WrongLength,
  ec_DEC_TooBigTagNumber,
  ec_DEC_WrongConstructedLengthPrefix,
  ec_DEC_WrongUnusedBits,
  ec_DEC_TooBigSubIdent,
  ec_DEC_WrongRealPrefix,
  ec_DEC_UnsupportedRealBase,
  ec_DEC_UnsupportedRealDecimalEncoding,
  ec_DEC_RequiredComponentIsAbsent,
  ec_DEC_ExtRequiredComponentIsAbsent,
  ec_DEC_AbsentComponentIsPresent,
  ec_DEC_AbsentAlternativeIsPresent,
  ec_DEC_UnknownComponent,
  ec_DEC_UnknownAlternative,
  ec_DEC_NoOpenId,
  ec_DEC_UnknownObject
};

/* Error output configuration */
extern char* CUCFGetErrorMessage(int ErrorCode);
extern void CUCFErrorOutput(FILE *File, int ErrorCode, ...);


/* MMS */

struct sMMSItem;
typedef struct sMMSItem tMMSItem;

struct sMMSItem
{
  void*     MemPtr;
  size_t    MemSize;
  tMMSItem* Next;
};

typedef struct
{
  tMMSItem* MMSFirst;
} tMMS;



/* BMS */

typedef unsigned long tBMSLength;

enum
{
  bms_NoMode,
  bms_ReadMode,
  bms_WriteMode
};
typedef unsigned char tBMSMode;

typedef struct tBMSUserMemory
{
  void*       MemPtr;
  tBMSLength  MemSize;
  tBMSLength  DataLength;
} tBMSUserMemory;


typedef enum tBMSBufType
{
  bms_SmallBuffer,
  bms_UserBuffer
} tBMSBufType;

typedef enum
{
  bms_DataLength,
  bms_DataBitLength,
  bms_ReadDataLength,
  bms_ReadDataBitLength,
  bms_ValueLength,
  bms_ValueBitLength
} tBMSLengthType;

typedef struct
{
  unsigned char* MemStart;
  unsigned char* MemEnd;
  unsigned char* DataStart;
  unsigned char* DataEnd;
  unsigned char* DataCurr;
  unsigned char  BitStart;
  unsigned char  BitEnd;
  unsigned char  BitCurr;
  unsigned char  IsAssigned;
} tBMSSmallBuffer;

typedef void (*tBufAppendBufFunc)(tCoder* Coder, unsigned int len);

typedef int  (*tBufInitBufFunc)(tCoder** Coder);
typedef int  (*tBufCloseBufFunc)(tCoder** Coder);

typedef int  (*tBufInitBufWithMemoryFunc)(tCoder** Coder, tBMSUserMemory* UserMemory);
typedef int  (*tBufCloseBufToMemoryFunc)(tCoder** Coder, tBMSUserMemory* UserMemory);

typedef tBMSLength (*tBufGetLengthFunc)(tCoder* Coder, tBMSLengthType LengthType);

typedef unsigned char* (*tBufGetMemoryFunc)(tCoder* Coder, tBMSLength* rLength);
typedef unsigned char* (*tBufAppendMemoryFunc)(tCoder* Coder, tBMSLength Length);

typedef void           (*tBufErrInitFunc)(tCoder* Coder);

typedef unsigned char* (*tBufGetDataCurr)(tCoder* Coder, unsigned char* rBitCurr);
typedef void           (*tBufSetDataCurr)  (tCoder* Coder, tBMSLength Length, unsigned char BitCurr);
typedef unsigned char* (*tBufGetDataEnd)(tCoder* Coder, unsigned char* rBitEnd);
typedef void           (*tBufSetDataEnd)  (tCoder* Coder, tBMSLength Length, unsigned char BitEnd);

typedef int  (*tBufCopyBufFunc)(tCoder* Dst, tCoder* Src);

typedef int  (*tBufInitWriteModeFunc)(tCoder* Coder);
typedef int  (*tBufCloseWriteModeFunc)(tCoder* Coder);

typedef int  (*tBufInitReadModeFunc)(tCoder* Coder);
typedef int  (*tBufCloseReadModeFunc)(tCoder* Coder);
typedef int  (*tBufCloseDeleteReadModeFunc)(tCoder* Coder);

typedef unsigned char (*tBufGetByteFunc)(tCoder* Coder);
typedef unsigned char (*tBufPeekByteFunc)(tCoder* Coder);
typedef void (*tBufPutByteFunc)(tCoder* Coder, unsigned char byte);

typedef unsigned char* (*tBufGetSegFunc)(tCoder* Coder, tBMSLength lenPtr);
typedef void (*tBufSkipSegFunc)(tCoder* Coder, tBMSLength lenPtr);
typedef unsigned char* (*tBufPeekSegFunc)(tCoder* Coder, tBMSLength lenPtr);
typedef void (*tBufPutSegFunc)(tCoder* Coder, unsigned char* data, tBMSLength len);

typedef unsigned char (*tBufGetBitFunc)(tCoder* Coder);
typedef void (*tBufPutBitFunc)(tCoder* Coder, unsigned char bit);
typedef unsigned long (*tBufGetBitsFunc)(tCoder* Coder, unsigned char num);
typedef void (*tBufPutBitsFunc)(tCoder* Coder, unsigned long bits, unsigned char num);

typedef void (*tBufAlignFunc)(tCoder* Coder);

#define BUFFER_STRUCT_SIZE sizeof(tBMSSmallBuffer)

typedef struct
{
  tBMSBufType                    BufType;
  char                           Buffer[BUFFER_STRUCT_SIZE];

  /* Functions */
  tBufInitBufFunc                initBuf;
  tBufCloseBufFunc               closeBuf;

  tBufInitBufWithMemoryFunc      initBufWithMemory;
  tBufCloseBufToMemoryFunc       closeBufToMemory;

  tBufGetLengthFunc              getLength;

  tBufGetMemoryFunc              getMemory;
  tBufAppendMemoryFunc           appendMemory;

  tBufGetDataCurr                getDataCurr;
  tBufSetDataCurr                setDataCurr;
  tBufGetDataEnd                 getDataEnd;
  tBufSetDataEnd                 setDataEnd;

  tBufCopyBufFunc                copyBuf;

  tBufInitWriteModeFunc          initWriteMode;
  tBufCloseWriteModeFunc         closeWriteMode;

  tBufInitReadModeFunc           initReadMode;
  tBufCloseReadModeFunc          closeReadMode;
  tBufCloseDeleteReadModeFunc    closeDeleteReadMode;

  /* Read/Write functions */
  tBufGetByteFunc                getByte;
  tBufPeekByteFunc               peekByte;
  tBufPutByteFunc                putByte;

  tBufGetSegFunc                 getSeg;
  tBufSkipSegFunc                skipSeg;
  tBufPeekSegFunc                peekSeg;
  tBufPutSegFunc                 putSeg;

  tBufPutBitFunc                 putBit;
  tBufGetBitFunc                 getBit;
  tBufPutBitsFunc                putBits;
  tBufGetBitsFunc                getBits;

  tBufAlignFunc                  bufAlign;
} tBMSBaseBuffer;

/* BMS interfaces */

int BaseBufInitBuf(tCoder** Coder, tBMSBufType BufType);
int BaseBufInitBufWithMemory(tCoder** Coder, tBMSBufType BufType, tBMSUserMemory* UserMemory);

#define BufGetRule(c)                                 (c)->ER.Rule
#define BufSetRule(c, rule)                           ERSetRule(c, rule)

#define BufGetUserData(c)                             (&((c)->UserData))

#define BufSetAppendBufFunc(c, f)                     (c)->BMS.AppendFunc = f;
#define BufGetAppendBufFunc(c)                        (c)->BMS.AppendFunc

#define BufSetErrInitFunc(c, f)                       (c)->BMS.ErrInitFunc = f
#define BufGetErrInitFunc(c)                          (c)->BMS.ErrInitFunc
#define BufErrInit(c)                                 (c)->BMS.ErrInitFunc(c)
#define BufGetErrorPath(c)                            (&((c)->EMS.ErrorPath))
#define BufGetMainVal(c)                              (c)->VMS.Value

#define BufSetErrorCode(c, errorcode)                 (c)->EMS.ErrorCode = errorcode
#define BufGetErrorCode(c)                            (c)->EMS.ErrorCode

#define BufGetMode(c)                                 (c)->BMS.Mode
#define BufInNoMode(c)                                ((c)->BMS.Mode == bms_NoMode)
#define BufInReadMode(c)                              ((c)->BMS.Mode == bms_ReadMode)
#define BufInWriteMode(c)                             ((c)->BMS.Mode == bms_WriteMode)

#define BufInitBuf(c, buftype)                        BaseBufInitBuf(&c, buftype)
#define BufCloseBuf(c)                                (c)->BMS.BMSBuffer.closeBuf(&c);

#define BufInitBufWithMemory(c, buftype, usermemory)  BaseBufInitBufWithMemory(&c, buftype, usermemory)
#define BufCloseBufToMemory(c, usermemory)            (c)->BMS.BMSBuffer.closeBufToMemory(&c, usermemory)

#define BufGetBufType(c)                              (c)->BMS.BMSBuffer.BufType

#define BufGetDataLen(c)                              (c)->BMS.BMSBuffer.getLength(c, bms_DataLength)
#define BufGetDataBitLen(c)                           (c)->BMS.BMSBuffer.getLength(c, bms_DataBitLength)
#define BufGetReadDataLen(c)                          (c)->BMS.BMSBuffer.getLength(c, bms_ReadDataLength)
#define BufGetReadDataBitLen(c)                       (c)->BMS.BMSBuffer.getLength(c, bms_ReadDataBitLength)
#define BufGetValueLen(c)                             (c)->BMS.BMSBuffer.getLength(c, bms_ValueLength)
#define BufGetValueBitLen(c)                          (c)->BMS.BMSBuffer.getLength(c, bms_ValueBitLength)

#define BufGetMemory(c, rlen)                         (c)->BMS.BMSBuffer.getMemory(c, rlen)
#define BufAppendMemory(c, len)                       (c)->BMS.BMSBuffer.appendMemory(c, len)

#define BufGetDataCurr(c, rbitcurr)                   (c)->BMS.BMSBuffer.getDataCurr(c, rbitcurr)
#define BufSetDataCurr(c, len, bitcurr)               (c)->BMS.BMSBuffer.setDataCurr(c, len, bitcurr)
#define BufGetDataEnd(c, rbitend)                     (c)->BMS.BMSBuffer.getDataEnd(c, rbitend)
#define BufSetDataEnd(c, len, bitend)                 (c)->BMS.BMSBuffer.setDataEnd(c, len, bitend)

#define BufCopyBuf(dst, srs)                          (srs)->BMS.BMSBuffer.copyBuf(dst, srs)

#define BufInitWriteMode(c)                           (c)->BMS.BMSBuffer.initWriteMode(c)
#define BufCloseWriteMode(c)                          (c)->BMS.BMSBuffer.closeWriteMode(c)

#define BufInitReadMode(c)                            (c)->BMS.BMSBuffer.initReadMode(c)
#define BufCloseReadMode(c)                           (c)->BMS.BMSBuffer.closeReadMode(c)
#define BufCloseDeleteReadMode(c)                     (c)->BMS.BMSBuffer.closeDeleteReadMode(c)

#define BufGetByte(c)                                 (c)->BMS.BMSBuffer.getByte(c)
#define BufPeekByte(c)                                (c)->BMS.BMSBuffer.peekByte(c)
#define BufPutByte(c, byte)                           (c)->BMS.BMSBuffer.putByte(c, byte)

#define BufGetSeg(c, lenPtr)                          (c)->BMS.BMSBuffer.getSeg(c, lenPtr)
#define BufSkipSeg(c,lenPtr)                          (c)->BMS.BMSBuffer.skipSeg(c, lenPtr)
#define BufPeekSeg(c,lenPtr)                          (c)->BMS.BMSBuffer.peekSeg(c, lenPtr)
#define BufPutSeg(c, data, len)                       (c)->BMS.BMSBuffer.putSeg(c, data, len)

#define BufPutBit(c, bit)                             (c)->BMS.BMSBuffer.putBit(c, bit)
#define BufGetBit(c)                                  (c)->BMS.BMSBuffer.getBit(c)
#define BufPutBits(c, bits, num)                      (c)->BMS.BMSBuffer.putBits(c, bits, num)
#define BufGetBits(c, num)                            (c)->BMS.BMSBuffer.getBits(c, num)

#define BufAlign(c)                                   (c)->BMS.BMSBuffer.bufAlign(c)

typedef tBMSBaseBuffer tBMSBuffer;

typedef struct {
  tBufAppendBufFunc AppendFunc;
  tBufErrInitFunc   ErrInitFunc;
  tBMSMode          Mode;
  tBMSBuffer        BMSBuffer;
} tBMS;



/* VMS */

#define CODER_ENUMERATED_TYPE      long
#define CODER_TagNumber_TYPE       unsigned long
#define CODER_NumOf_TYPE           unsigned long
#define CODER_INTEGER_LBOUND_TYPE  long
#define CODER_INTEGER_UBOUND_TYPE  long
#define CODER_SIZE_LBOUND_TYPE     unsigned long
#define CODER_SIZE_UBOUND_TYPE     unsigned long

typedef void*         tVMSPointer;
typedef unsigned long tVMSULong;
typedef unsigned char tVMSBoolean;
typedef long          tVMSInteger;
typedef char*         tVMSString_Value;
typedef unsigned char tVMSIsAssigned;
typedef CODER_ENUMERATED_TYPE tVMSEnumerated_Value;
typedef unsigned long tVMSEnumerated_Index;

typedef struct 
{
  tVMSString_Value Value;
  tVMSULong        Length;
  tVMSIsAssigned   IsAssigned;
} tVMSString;

typedef enum
{
  rk_Zero,
  rk_MINUS_INFINITY,
  rk_PLUS_INFINITY,
  rk_Value
} tVMSReal_Kind;

enum
{
  type_ASN1_BOOLEAN           = 1,
  type_ASN1_NULL              = 5,
  type_ASN1_OBJECT_IDENTIFIER = 6,
  type_ASN1_REAL              = 9,
  type_ASN1_INTEGER           = 2,
  type_ASN1_BIT_STRING        = 3,
  type_ASN1_OCTET_STRING      = 4,
  type_ASN1_NumericString     = 18,
  type_ASN1_PrintableString   = 19,
  type_ASN1_IA5String         = 22,
  type_ASN1_VisibleString     = 26,
  type_ASN1_UTCTime           = 23,
  type_ASN1_GeneralizedTime   = 24,
  type_ASN1_ENUMERATED        = 10,
  type_ASN1_SEQUENCE          = 16,
  type_ASN1_SET               = 17,
  type_ASN1_SEQUENCE_OF       = 48,  /* Internal */
  type_ASN1_SET_OF            = 49,  /* Internal */
  type_ASN1_CHOICE            = 101, /* Internal */
  type_ASN1_DEFINED           = 51,  /* Internal */
  type_ASN1_TAGGED            = 103, /* Internal */
  type_ASN1_OPEN_ID           = 52,  /* Internal */
  type_ASN1_OPEN              = 102  /* Internal */
};

typedef unsigned char tCUCFTypeClass;

enum
{
  em_Absent = 0,
  em_Present = 1
};
typedef unsigned char tASN1ExtMarker;

enum 
{
  ct_Required = 0,
  ct_Present  = 1,
  ct_Optional = 2,
  ct_Default  = 3,
  ct_Group    = 4,
  ct_Absent   = 5
};
typedef unsigned char tASN1ComponentType;

enum
{
  rs_NonRoot = 0,
  rs_Root = 1
};
typedef unsigned char tASN1RootStruct;

enum
{
  tc_UT = 0,
  tc_AP = (1 << 6),
  tc_CS = (2 << 6),
  tc_PR = (3 << 6)
};
typedef unsigned char tASN1TagClass;

typedef CODER_TagNumber_TYPE tASN1TagClassNumber;

struct sASN1TypeInfo;
typedef const struct sASN1TypeInfo tASN1TypeInfo;

struct sASN1TypeInfo
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
};

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
} tASN1Predefined;

typedef tASN1Predefined tASN1Boolean;
typedef tASN1Predefined tASN1Null;
typedef tASN1Predefined tASN1ObjectIdentifier;
typedef tASN1Predefined tASN1Real;

typedef struct
{
  CODER_INTEGER_LBOUND_TYPE pLBound;
  CODER_INTEGER_UBOUND_TYPE pUBound;
  tASN1ExtMarker                  ExtMarker;
} tASN1IntegerConstraint;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  unsigned char          ConstraintMask;
  tASN1IntegerConstraint IntegerConstraint;
} tASN1Integer;

typedef struct
{
  CODER_SIZE_LBOUND_TYPE  LBound;
  CODER_SIZE_UBOUND_TYPE  pUBound;
  tASN1ExtMarker          ExtMarker;
} tASN1SizeConstraint;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  unsigned char         ConstraintMask;
  tASN1SizeConstraint   SizeConstraint;
} tASN1String;

typedef tASN1String tASN1BitString;
typedef tASN1String tASN1OctetString;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  unsigned char         ConstraintMask;
  tASN1SizeConstraint   SizeConstraint;
  unsigned char*        Alphabet;
  tVMSULong             AlphabetLen;
} tASN1CharString;

typedef tASN1CharString tASN1NumericString;
typedef tASN1CharString tASN1PrintableString;
typedef tASN1CharString tASN1IA5String;
typedef tASN1CharString tASN1VisibleString;

typedef tASN1VisibleString tASN1UTCTime;
typedef tASN1VisibleString tASN1GeneralizedTime;

typedef const struct
{
  char*                 Name;
  tVMSEnumerated_Value  Value;
} tASN1Item;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  tASN1Item*            Items;
  CODER_NumOf_TYPE      NumOfItems;
  long                  ExtMarker;
} tASN1Enumerated;

typedef const struct
{
  tASN1TypeInfo*        TypeInfo;
  char*                 Name;
  tASN1ComponentType    Type;
  CODER_NumOf_TYPE      Index;
} tASN1Component;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  tASN1Component*       RootComps1;
  tASN1Component*       ExtAddComps;
  tASN1Component*       RootComps2;
  unsigned char         RootExtFlags;
  CODER_NumOf_TYPE      NumOfRC1;
  CODER_NumOf_TYPE      NumOfEAC;
  CODER_NumOf_TYPE      NumOfRC2;
  CODER_NumOf_TYPE      NumOfOptDef;
  CODER_NumOf_TYPE      NumOfExtAdd;
} tASN1Struct;

typedef tASN1Struct tASN1Sequence;
typedef tASN1Struct tASN1Set;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  tASN1TypeInfo*        BaseType;
  unsigned char         ConstraintMask;
  tASN1SizeConstraint   SizeConstraint;
} tASN1StructOf;

typedef tASN1StructOf tASN1SequenceOf;
typedef tASN1StructOf tASN1SetOf;

typedef const struct
{
  tASN1TypeInfo*        TypeInfo;
  char*                 Name;
  tASN1ComponentType    Type;
  tVMSULong             Index;
} tASN1Alternative;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  long                  ExtMarker;
  tASN1Alternative*     Alternatives;
  CODER_NumOf_TYPE      NumOfAlts;
} tASN1Choice;

typedef const struct 
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  tASN1TypeInfo*        BaseType;
} tASN1Defined;

typedef const struct
{
  tASN1TagClass         Class;
  tASN1TagClassNumber   Number;  
} tASN1Tag;

typedef const struct 
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  tASN1TypeInfo*        BaseType;
  tASN1Tag*             Tags;
  CODER_NumOf_TYPE      NumOfTags;
} tASN1Tagged;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  tASN1TypeInfo*        BaseType;
} tASN1OpenId;

typedef void* (*tCUCFObjectInitFunc)(tCoder* Coder);

typedef const struct
{
  tASN1TypeInfo*        TypeInfo;
  char*                 Name;
  tCUCFObjectInitFunc   InitFunc;
  CODER_NumOf_TYPE      Index;
} tASN1Object;

typedef const struct
{
  tCUCFTypeClass        TypeClass;
  char*                 TypeName;
  tASN1TypeInfo*        OpenIdType;
  tASN1Object*          Objects;
  CODER_NumOf_TYPE      NumOfObjects;
} tASN1Open;

#define TYPE_REF(typename) (tASN1TypeInfo*)&typename

#define BOOLEAN_TYPE_DECL(specifier, typename) \
  specifier tASN1Boolean typename

#define NULL_TYPE_DECL(specifier, typename) \
  specifier tASN1Null typename

#define OBJECT_IDENTIFIER_TYPE_DECL(specifier, typename) \
  specifier tASN1ObjectIdentifier typename

#define REAL_TYPE_DECL(specifier, typename) \
  specifier tASN1Real typename

#define INTEGER_TYPE_DECL(specifier, typename) \
  specifier tASN1Integer typename

#define CONSTRAINED_INTEGER_TYPE_DECL(specifier, typename) \
  specifier tASN1Integer typename

#define BIT_STRING_TYPE_DECL(specifier, typename) \
  specifier tASN1BitString typename

#define CONSTRAINED_BIT_STRING_TYPE_DECL(specifier, typename) \
  specifier tASN1BitString typename

#define OCTET_STRING_TYPE_DECL(specifier, typename) \
  specifier tASN1OctetString typename

#define CONSTRAINED_OCTET_STRING_TYPE_DECL(specifier, typename) \
  specifier tASN1OctetString typename

#define NumericString_TYPE_DECL(specifier, typename) \
  specifier tASN1NumericString typename

#define CONSTRAINED_NumericString_TYPE_DECL(specifier, typename) \
  specifier tASN1NumericString typename

#define PrintableString_TYPE_DECL(specifier, typename) \
  specifier tASN1PrintableString typename

#define CONSTRAINED_PrintableString_TYPE_DECL(specifier, typename) \
  specifier tASN1PrintableString typename

#define IA5String_TYPE_DECL(specifier, typename) \
  specifier tASN1IA5String typename

#define CONSTRAINED_IA5String_TYPE_DECL(specifier, typename) \
  specifier tASN1IA5String typename

#define VisibleString_TYPE_DECL(specifier, typename) \
  specifier tASN1VisibleString typename

#define CONSTRAINED_VisibleString_TYPE_DECL(specifier, typename) \
  specifier tASN1VisibleString typename

#define UTCTime_TYPE_DECL(specifier, typename) \
  specifier tASN1UTCTime typename

#define GeneralizedTime_TYPE_DECL(specifier, typename) \
  specifier tASN1GeneralizedTime typename

#define ENUMERATED_TYPE_DECL(specifier, typename) \
  specifier tASN1Enumerated typename

#define SEQUENCE_TYPE_DECL(specifier, typename) \
  specifier tASN1Sequence typename

#define SET_TYPE_DECL(specifier, typename) \
  specifier tASN1Sequence typename

#define SEQUENCE_OF_TYPE_DECL(specifier, typename) \
  specifier tASN1SequenceOf typename

#define CONSTRAINED_SEQUENCE_OF_TYPE_DECL(specifier, typename) \
  specifier tASN1SequenceOf typename

#define SET_OF_TYPE_DECL(specifier, typename) \
  specifier tASN1SetOf typename

#define CONSTRAINED_SET_OF_TYPE_DECL(specifier, typename) \
  specifier tASN1SetOf typename

#define CHOICE_TYPE_DECL(specifier, typename) \
  specifier tASN1Choice typename

#define DEFINED_TYPE_DECL(specifier, typename) \
  specifier tASN1Defined typename

#define TAGGED_TYPE_DECL(specifier, typename) \
  specifier tASN1Tagged typename

#define OPEN_ID_DECL(specifier, typename) \
  specifier tASN1OpenId typename

#define OPEN_TYPE_DECL(specifier, typename) \
  specifier tASN1Open typename

#define INLINE_BOOLEAN_TYPE_DECL(specifier, typename) \
        BOOLEAN_TYPE_DECL(specifier, typename)

#define INLINE_NULL_TYPE_DECL(specifier, typename) \
        NULL_TYPE_DECL(specifier, typename)

#define INLINE_OBJECT_IDENTIFIER_TYPE_DECL(specifier, typename) \
        OBJECT_IDENTIFIER_TYPE_DECL(specifier, typename)

#define INLINE_REAL_TYPE_DECL(specifier, typename) \
        REAL_TYPE_DECL(specifier, typename)

#define INLINE_INTEGER_TYPE_DECL(specifier, typename) \
        INTEGER_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_INTEGER_TYPE_DECL(specifier, typename) \
        CONSTRAINED_INTEGER_TYPE_DECL(specifier, typename)

#define INLINE_BIT_STRING_TYPE_DECL(specifier, typename) \
        BIT_STRING_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_BIT_STRING_TYPE_DECL(specifier, typename) \
        CONSTRAINED_BIT_STRING_TYPE_DECL(specifier, typename)

#define INLINE_OCTET_STRING_TYPE_DECL(specifier, typename) \
        OCTET_STRING_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_OCTET_STRING_TYPE_DECL(specifier, typename) \
        CONSTRAINED_OCTET_STRING_TYPE_DECL(specifier, typename)

#define INLINE_NumericString_TYPE_DECL(specifier, typename) \
        NumericString_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_NumericString_TYPE_DECL(specifier, typename) \
        CONSTRAINED_NumericString_TYPE_DECL(specifier, typename)

#define INLINE_PrintableString_TYPE_DECL(specifier, typename) \
        PrintableString_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_PrintableString_TYPE_DECL(specifier, typename) \
        CONSTRAINED_PrintableString_TYPE_DECL(specifier, typename)

#define INLINE_IA5String_TYPE_DECL(specifier, typename) \
        IA5String_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_IA5String_TYPE_DECL(specifier, typename) \
        CONSTRAINED_IA5String_TYPE_DECL(specifier, typename)

#define INLINE_VisibleString_TYPE_DECL(specifier, typename) \
        VisibleString_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_VisibleString_TYPE_DECL(specifier, typename) \
        CONSTRAINED_VisibleString_TYPE_DECL(specifier, typename)

#define INLINE_UTCTime_TYPE_DECL(specifier, typename) \
        UTCTime_TYPE_DECL(specifier, typename)

#define INLINE_GeneralizedTime_TYPE_DECL(specifier, typename) \
        GeneralizedTime_TYPE_DECL(specifier, typename)

#define INLINE_ENUMERATED_TYPE_DECL(specifier, typename) \
        ENUMERATED_TYPE_DECL(specifier, typename)

#define INLINE_SEQUENCE_TYPE_DECL(specifier, typename) \
        SEQUENCE_TYPE_DECL(specifier, typename)

#define INLINE_SET_TYPE_DECL(specifier, typename) \
        SET_TYPE_DECL(specifier, typename)

#define INLINE_SEQUENCE_OF_TYPE_DECL(specifier, typename) \
        SEQUENCE_OF_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_SEQUENCE_OF_TYPE_DECL(specifier, typename) \
        CONSTRAINED_SEQUENCE_OF_TYPE_DECL(specifier, typename)

#define INLINE_SET_OF_TYPE_DECL(specifier, typename) \
        SET_OF_TYPE_DECL(specifier, typename)

#define INLINE_CONSTRAINED_SET_OF_TYPE_DECL(specifier, typename) \
        CONSTRAINED_SET_OF_TYPE_DECL(specifier, typename)

#define INLINE_CHOICE_TYPE_DECL(specifier, typename) \
        CHOICE_TYPE_DECL(specifier, typename)

#define INLINE_DEFINED_TYPE_DECL(specifier, typename) \
        DEFINED_TYPE_DECL(specifier, typename)

#define INLINE_TAGGED_TYPE_DECL(specifier, typename) \
        TAGGED_TYPE_DECL(specifier, typename)

#define INLINE_OPEN_ID_DECL(specifier, typename) \
        OPEN_ID_DECL(specifier, typename)

#define INLINE_OPEN_TYPE_DECL(specifier, typename) \
        OPEN_TYPE_DECL(specifier, typename)

#define BOOLEAN_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1Boolean typename = \
    { \
      type_ASN1_BOOLEAN \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
    }

#define NULL_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1Null typename = \
    { \
      type_ASN1_NULL \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
    }

#define OBJECT_IDENTIFIER_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1ObjectIdentifier typename = \
    { \
      type_ASN1_OBJECT_IDENTIFIER \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
    }

#define REAL_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1Real typename = \
    { \
      type_ASN1_REAL \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
    }

#define INTEGER_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1Integer typename = \
    { \
      type_ASN1_INTEGER \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CONSTRAINT(0, 0, 0, em_Absent) \
    }

#define CONSTRAINED_INTEGER_TYPE_DEF(specifier, typename, \
                                     islbound, lbound, isubound, ubound, \
                                     isextmarker, \
                                     vrtype) \
  specifier tASN1Integer typename = \
    { \
      type_ASN1_INTEGER \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CONSTRAINT(((islbound << 4) | isubound), lbound, ubound, \
                                     ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent)) \
    }

#define BIT_STRING_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1BitString typename = \
    { \
      type_ASN1_BIT_STRING \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CONSTRAINT(0, 0, 0, em_Absent) \
    }

#define CONSTRAINED_BIT_STRING_TYPE_DEF(specifier, typename, \
                                        islbound, lbound, isubound, ubound, \
                                        isextmarker, \
                                        vrtype) \
  specifier tASN1BitString typename = \
    { \
      type_ASN1_BIT_STRING \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CONSTRAINT(isubound, \
                                     ((islbound == BOUND_PRESENT) ? lbound : 0), \
                                     ((isubound == BOUND_PRESENT) ? ubound : 0), \
                                     ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent)) \
    }

#define OCTET_STRING_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1OctetString typename = \
    { \
      type_ASN1_OCTET_STRING \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CONSTRAINT(0, 0, 0, em_Absent) \
    }

#define CONSTRAINED_OCTET_STRING_TYPE_DEF(specifier, typename, \
                                          islbound, lbound, isubound, ubound, \
                                          isextmarker, \
                                          vrtype) \
  specifier tASN1OctetString typename = \
    { \
      type_ASN1_OCTET_STRING \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CONSTRAINT(isubound,\
                                     ((islbound == BOUND_PRESENT) ? lbound : 0), \
                                     ((isubound == BOUND_PRESENT) ? ubound : 0), \
                                     ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent)) \
    }

#define NumericString_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1NumericString typename = \
    { \
      type_ASN1_NumericString \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT(0, 0, 0, em_Absent, NULL, 0) \
    }

#define CONSTRAINED_NumericString_TYPE_DEF(specifier, typename, \
                                           islbound, lbound, isubound, ubound, \
                                           isextmarker, \
                                           alphabet, alphabetlen, \
                                           vrtype) \
  specifier tASN1NumericString typename = \
    { \
      type_ASN1_NumericString \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT ( \
      isubound,\
      ((islbound == BOUND_PRESENT) ? lbound : 0), \
      ((isubound == BOUND_PRESENT) ? ubound : 0), \
      ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent), \
      alphabet, \
      alphabetlen ) \
    }

#define PrintableString_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1PrintableString typename = \
    { \
      type_ASN1_PrintableString \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT(0, 0, 0, em_Absent, NULL, 0) \
    }

#define CONSTRAINED_PrintableString_TYPE_DEF(specifier, typename, \
                                             islbound, lbound, isubound, ubound, \
                                             isextmarker, \
                                             alphabet, alphabetlen, \
                                             vrtype) \
  specifier tASN1PrintableString typename = \
    { \
      type_ASN1_PrintableString \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT ( \
      isubound,\
      ((islbound == BOUND_PRESENT) ? lbound : 0), \
      ((isubound == BOUND_PRESENT) ? ubound : 0), \
      ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent), \
      alphabet, \
      alphabetlen )\
    }

#define IA5String_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1IA5String typename = \
    { \
      type_ASN1_IA5String \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT(0, 0, 0, em_Absent, NULL, 0) \
    }

#define CONSTRAINED_IA5String_TYPE_DEF(specifier, typename, \
                                       islbound, lbound, isubound, ubound, \
                                       isextmarker, \
                                       alphabet, alphabetlen, \
                                       vrtype) \
  specifier tASN1IA5String typename = \
    { \
      type_ASN1_IA5String \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT ( \
      isubound,\
      ((islbound == BOUND_PRESENT) ? lbound : 0), \
      ((isubound == BOUND_PRESENT) ? ubound : 0), \
      ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent), \
      alphabet, \
      alphabetlen )\
    }

#define VisibleString_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1VisibleString typename = \
    { \
      type_ASN1_VisibleString \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT(0, 0, 0, em_Absent, NULL, 0) \
    }

#define CONSTRAINED_VisibleString_TYPE_DEF(specifier, typename, \
                                           islbound, lbound, isubound, ubound, \
                                           isextmarker, \
                                           alphabet, alphabetlen, \
                                           vrtype) \
  specifier tASN1VisibleString typename = \
    { \
      type_ASN1_VisibleString \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT ( \
      isubound,\
      ((islbound == BOUND_PRESENT) ? lbound : 0), \
      ((isubound == BOUND_PRESENT) ? ubound : 0), \
      ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent), \
      alphabet, \
      alphabetlen )\
    }

#define UTCTime_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1UTCTime typename = \
    { \
      type_ASN1_UTCTime \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT(0, 0, 0, em_Absent, NULL, 0) \
    }

#define GeneralizedTime_TYPE_DEF(specifier, typename, vrtype) \
  specifier tASN1GeneralizedTime typename = \
    { \
      type_ASN1_GeneralizedTime \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      VMS_CONSTRAINTC VMS_CHARSTRING_CONSTRAINT(0, 0, 0, em_Absent, NULL, 0) \
    }

#define ENUMERATED_TYPE_DEF(specifier, typename, \
                            isextmarker, extmarker, \
                            numofitems,items, \
                            vrtype) \
  static tASN1Item typename##Items[] = items; \
  specifier tASN1Enumerated typename = \
    { \
      type_ASN1_ENUMERATED \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      typename##Items, \
      numofitems, \
      (isextmarker == EXTMARKER_PRESENT) ? extmarker : -1 \
    }

#define ITEMS(items) { items }

#define ITEM(name, number) { VMS_TYPENAME((char*)#name) VMS_TYPENAMEC number }

#define SEQUENCE_TYPE_DEF(specifier, typename, isextmarker, root, noptdef, nextadd, \
                          m_root1, root1, m_extadd, extadd, m_root2, root2, \
                          vrtype) \
  m_root1(typename, ##root1, 1) \
  m_extadd(typename, ##extadd, 2) \
  m_root2(typename, ##root2, 3) \
  specifier tASN1Sequence typename = \
    { \
      type_ASN1_SEQUENCE \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      m_root1##_REF(typename, 1), \
      m_extadd##_REF(typename, 2), \
      m_root2##_REF(typename, 3), \
      (root << 4) | isextmarker, \
      (sizeof(m_root1##_REF(typename, 1)) / sizeof(tASN1Component)), \
      (sizeof(m_extadd##_REF(typename, 2)) / sizeof(tASN1Component)), \
      (sizeof(m_root2##_REF(typename, 3)) / sizeof(tASN1Component)) \
      VMS_PERC VMS_PER(noptdef) \
      VMS_PERC VMS_PER(nextadd) \
      }

#define SET_TYPE_DEF(specifier, typename, isextmarker, root, noptdef, nextadd, \
                     m_root1, root1, m_extadd, extadd, m_root2, root2, \
                     vrtype) \
  m_root1(typename, ##root1, 1) \
  m_extadd(typename, ##extadd, 2) \
  m_root2(typename, ##root2, 3) \
  specifier tASN1Sequence typename = \
    { \
      type_ASN1_SET \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      m_root1##_REF(typename, 1), \
      m_extadd##_REF(typename, 2), \
      m_root2##_REF(typename, 3), \
      (root << 4) | isextmarker, \
      (sizeof(m_root1##_REF(typename, 1)) / sizeof(tASN1Component)), \
      (sizeof(m_extadd##_REF(typename, 2)) / sizeof(tASN1Component)), \
      (sizeof(m_root2##_REF(typename, 3)) / sizeof(tASN1Component)) \
      VMS_PERC VMS_PER(noptdef) \
      VMS_PERC VMS_PER(nextadd) \
      }

#define PRESENT_LIST(typename, components, num) \
static tASN1Component typename##Comps##num [] = components;

#define ABSENT_LIST(typename, components, num)

#define PRESENT_LIST_REF(typename, num) \
typename##Comps##num

#define ABSENT_LIST_REF(typename, num) \
NULL

#define EMPTY_LIST

#define ROOT_COMPONENTS(components) { components }
#define EXTADD_COMPONENTS(components) { components }

#define REQUIRED_COMPONENT(typename, componentname, typenameref, index) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#componentname) \
    , \
    ct_Required, \
    index \
  }

#define OPTIONAL_COMPONENT(typename, componentname, typenameref, index) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#componentname) \
    , \
    ct_Optional, \
    index \
  }

#define DEFAULT_COMPONENT(typename, componentname, typenameref, index) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#componentname) \
    , \
    ct_Default, \
    index \
  }

#define PRESENT_COMPONENT(typename, componentname, typenameref, index) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#componentname) \
    , \
    ct_Present, \
    index \
  }

#define ABSENT_COMPONENT(typename, componentname, typenameref) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#componentname) \
    , \
    ct_Absent, \
    0 \
  }

#define ADDITION_GROUP(numofcomps, components) \
  { \
    NULL \
    VMS_TYPENAMEC VMS_TYPENAME((char*)"") \
    , \
    ct_Group, \
    numofcomps \
  }, \
  components


#define SEQUENCE_OF_TYPE_DEF(specifier, typename, typenameref, \
                             vrtype) \
  specifier tASN1SequenceOf typename = \
    { \
      type_ASN1_SEQUENCE_OF \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref \
      VMS_CONSTRAINTC VMS_CONSTRAINT(0, 0, 0, em_Absent) \
    }

#define CONSTRAINED_SEQUENCE_OF_TYPE_DEF(specifier, typename, typenameref, \
                                         islbound, lbound, isubound, ubound, \
                                         isextmarker, \
                                         vrtype) \
  specifier tASN1SequenceOf typename = \
    { \
      type_ASN1_SEQUENCE_OF \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref \
      VMS_CONSTRAINTC VMS_CONSTRAINT( \
      isubound,\
      ((islbound == BOUND_PRESENT) ? lbound : 0), \
      ((isubound == BOUND_PRESENT) ? ubound : 0), \
      ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent)) \
    }

#define SET_OF_TYPE_DEF(specifier, typename, typenameref, \
                        vrtype) \
  specifier tASN1SetOf typename = \
    { \
      type_ASN1_SET_OF \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref \
      VMS_CONSTRAINTC VMS_CONSTRAINT(0, 0, 0, em_Absent) \
    }

#define CONSTRAINED_SET_OF_TYPE_DEF(specifier, typename, typenameref, \
                                    islbound, lbound, isubound, ubound, \
                                    isextmarker, \
                                    vrtype) \
  specifier tASN1SetOf typename = \
    { \
      type_ASN1_SET_OF \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref \
      VMS_CONSTRAINTC VMS_CONSTRAINT( \
      isubound, \
      ((islbound == BOUND_PRESENT) ? lbound : 0), \
      ((isubound == BOUND_PRESENT) ? ubound : 0), \
      ((isextmarker == EXTMARKER_PRESENT) ? em_Present : em_Absent)) \
    }

#define CHOICE_TYPE_DEF(specifier, typename, \
                        isextmarker, extmarker, \
                        alternatives, \
                        vrtype) \
  static tASN1Alternative typename##Alternatives[] = alternatives; \
  specifier tASN1Choice typename = \
    { \
      type_ASN1_CHOICE \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (isextmarker == EXTMARKER_PRESENT) ? extmarker : -1, \
      typename##Alternatives, \
      (sizeof(typename##Alternatives) / sizeof(tASN1Alternative)) \
    }

#define ALTERNATIVES(alternatives) { alternatives }

#define REQUIRED_ALTERNATIVE(typename, alternativename, typenameref, index) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#alternativename) \
    , \
    ct_Required, \
    index \
  }

#define ABSENT_ALTERNATIVE(typename, alternativename, typenameref) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#alternativename) \
    , \
    ct_Absent, \
    0 \
  }

#define DEFINED_TYPE_DEF(specifier, typename, typenameref, vrtype) \
  specifier tASN1Defined typename = \
    { \
      type_ASN1_DEFINED \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref \
    }

#define TAGGED_OR_DIRECT_REF(tagged_typeref, direct_typeref) \
  tagged_typeref
#define TAGGED_TYPE_DEF(specifier, typename, tags, typenameref, vrtype) \
  VMS_BER(static tASN1Tag typename##Tags[] = ) tags VMS_BER(;) \
  specifier tASN1Tagged typename = \
    { \
      type_ASN1_TAGGED \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref \
      VMS_BERC VMS_BER( \
      typename##Tags VMS_BERC \
      (sizeof(typename##Tags) / sizeof(tASN1Tag)) \
      ) \
    }

#define OPEN_ID_DEF(specifier, typename, typenameref, vrtype) \
  specifier tASN1OpenId typename = \
    { \
      type_ASN1_OPEN_ID \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref \
    }

#define EMPTY_OPEN_TYPE_DEF(specifier, typename, typenameref, vrtype) \
  specifier tASN1Open typename = \
    { \
      type_ASN1_OPEN \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref, \
      NULL, \
      0 \
    }

#define OPEN_TYPE_DEF(specifier, typename, typenameref, \
                      initobjects, objects, \
                      vrtype) \
  initobjects \
  static tASN1Object typename##Objects[] = objects; \
  specifier tASN1Open typename = \
    { \
      type_ASN1_OPEN \
      VMS_VRTYPEC VMS_VRTYPE((const tVMSPointer)&vrtype) \
      VMS_TYPENAMEC VMS_TYPENAME((char*)#typename) \
      , \
      (tASN1TypeInfo*)&typenameref, \
      typename##Objects, \
      (sizeof(typename##Objects) / sizeof(tASN1Object)) \
    }

#define INIT_OBJECTS(initobjects) initobjects

#define INIT_OBJECT(typename, objectname, ident, initobjectbody) \
  static void* typename##objectname##ident##InitFunc(tCoder* Coder) \
    { \
      return initobjectbody; \
    }

#define BOOLEAN_VALUE(Boolean) \
  CUCFInitObjectBOOLEAN(Coder, Boolean)

#define NULL_VALUE

#define OBJECT_IDENTIFIER_VALUE(NumberOfComponents, Components) \
  CUCFInitObjectOBJECT_IDENTIFIER(Coder, NumberOfComponents, Components)

#define SUB_IDENT(subident) \
  subident

#define REAL_ZERO_VALUE \
  CUCFInitObjectREAL(Coder, rk_Zero)

#define REAL_MINUS_INFINITY_VALUE \
  CUCFInitObjectREAL(Coder, rk_MINUS_INFINITY)

#define REAL_PLUS_INFINITY_VALUE \
  CUCFInitObjectREAL(Coder, rk_PLUS_INFINITY)

#define REAL_VALUE(Mantissa, Base, Exponent) \
  CUCFInitObjectREAL(Coder, rk_Value, Mantissa, Base, Exponent)

#define INTEGER_VALUE(Integer) \
  CUCFInitObjectINTEGER(Coder, Integer)

#define BIT_STRING_VALUE(BitString, Length) \
  CUCFInitObjectBIT_STRING(Coder, NULL, BitString, Length)

#define OCTET_STRING_VALUE(OctetString, Length) \
  CUCFInitObjectOCTET_STRING(Coder, NULL, OctetString, Length)

#define STRING_VALUE(String, Length) \
  CUCFInitObjectCHARACTER_STRING(Coder, String, Length)

#define ENUMERATED_VALUE(Enumerated_Index) \
  CUCFInitObjectENUMERATED(Coder, Enumerated_Index)

#define SEQUENCE_VALUE(NumberOfComponents, Components) \
  CUCFInitObjectStruct(Coder, NumberOfComponents, Components)

#define SET_VALUE(NumberOfComponents, Components) \
  CUCFInitObjectStruct(Coder, NumberOfComponents, Components)

#define COMPONENT_VALUE(component) \
  component

#define NONE_VALUE NULL

#define SEQUENCE_OF_VALUE(NumberOfComponents, Components) \
  CUCFInitObjectStruct(Coder, NumberOfComponents, Components)

#define SET_OF_VALUE(NumberOfComponents, Components) \
  CUCFInitObjectStruct(Coder, NumberOfComponents, Components)

#define CHOICE_VALUE(Index, Alternative) \
  CUCFInitObjectCHOICE(Coder, Index, Alternative)

#define OPEN_VALUE(Index, Object) \
  CUCFInitObjectOPEN(Coder, Index, Object)

#define OBJECTS(objects) { objects }

#define OBJECT(typename, objectname, ident, typenameref, index) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#objectname) \
    , \
    (tCUCFObjectInitFunc)typename##objectname##ident##InitFunc, \
    index \
  }

#define SIMPLE_OBJECT(objectname, typenameref, index, value) \
  { \
    (tASN1TypeInfo*)&typenameref \
    VMS_TYPENAMEC VMS_TYPENAME((char*)#objectname) \
    , \
    (tCUCFObjectInitFunc)value, \
    index \
  }

#define VMS_VRTYPE(arg)
#define VMS_VRTYPEC

#define VMS_TYPENAME(arg) arg
#define VMS_TYPENAMEC ,

#define VMS_CONSTRAINT(mask, lbound, ubound, extmarker) \
mask, \
{ \
  lbound, \
  ubound, \
  extmarker \
}

#define VMS_CHARSTRING_CONSTRAINT(mask, lbound, ubound, extmarker, alphabet, alphabetlen) \
VMS_CONSTRAINT(mask, lbound, ubound, extmarker), \
  (unsigned char*)alphabet,\
  alphabetlen

#define VMS_CONSTRAINTC ,

#define VMS_BER(arg) arg
#define VMS_BERC ,
#define TAGS(tags) { tags }
#define TAG(class, number) { class, number }, 

#define VMS_PER(arg) arg
#define VMS_PERC ,

#define GLOBAL_INFO
#define STATIC_INFO static
#define EXTERN_INFO extern

#define VMS_COMMA ,

#define NO_TAG

#define UNIVERSAL                  tc_UT
#define APPLICATION                tc_AP
#define CONTEXT_SPECIFIC           tc_CS
#define PRIVATE                    tc_PR

#define NOTHING

#define EXTMARKER_ABSENT           em_Absent
#define EXTMARKER_PRESENT          em_Present

#define EXTMARKER(number)          number
#define NONE_EXTMARKER             0

#define BOUND_ABSENT               0
#define BOUND_PRESENT              1

#define BOUND(number)              number
#define NONE_BOUND                 0
#define MIN_BOUND                  LONG_MIN
#define MAX_BOUND                  LONG_MAX

#define NONE_ALPHABET              NULL
#define ALPHABET(alphabet)         alphabet
#define NONE_ALPHABET_LEN          0
#define ALPHABET_LEN(alphabetsize) alphabetsize

#define NONE_ROOT                  rs_NonRoot
#define ROOT                       rs_Root

BOOLEAN_TYPE_DECL(EXTERN_INFO, yASN1_BOOLEAN);
NULL_TYPE_DECL(EXTERN_INFO, yASN1_NULL);
OBJECT_IDENTIFIER_TYPE_DECL(EXTERN_INFO, yASN1_OBJECT_IDENTIFIER);
REAL_TYPE_DECL(EXTERN_INFO, yASN1_REAL);
INTEGER_TYPE_DECL(EXTERN_INFO, yASN1_INTEGER);
BIT_STRING_TYPE_DECL(EXTERN_INFO, yASN1_BIT_STRING);
OCTET_STRING_TYPE_DECL(EXTERN_INFO, yASN1_OCTET_STRING);
NumericString_TYPE_DECL(EXTERN_INFO, yASN1_NumericString);
PrintableString_TYPE_DECL(EXTERN_INFO, yASN1_PrintableString);
IA5String_TYPE_DECL(EXTERN_INFO, yASN1_IA5String);
VisibleString_TYPE_DECL(EXTERN_INFO, yASN1_VisibleString);
UTCTime_TYPE_DECL(EXTERN_INFO, yASN1_UTCTime);
GeneralizedTime_TYPE_DECL(EXTERN_INFO, yASN1_GeneralizedTime);

void* CUCFInitObjectBOOLEAN(tCoder* Coder, tVMSBoolean Boolean);
void* CUCFInitObjectOBJECT_IDENTIFIER(tCoder* Coder, tVMSULong NumberOfComponents, ...);
void* CUCFInitObjectREAL(tCoder* Coder, tVMSReal_Kind Kind, ...);
void* CUCFInitObjectINTEGER(tCoder* Coder, tVMSInteger Integer);
void* CUCFInitObjectBIT_STRING(tCoder* Coder, tVMSString* vString, tVMSString_Value Value, tVMSULong Length);
void* CUCFInitObjectOCTET_STRING(tCoder* Coder, tVMSString* vString, tVMSString_Value Value, tVMSULong Length);
void* CUCFInitObjectCHARACTER_STRING(tCoder* Coder, tVMSString_Value Value, tVMSULong Length);
void* CUCFInitObjectENUMERATED(tCoder* Coder, tVMSEnumerated_Index Enumerated_Index);
void* CUCFInitObjectStruct(tCoder* Coder, tVMSULong NumberOfComponents, ...);
void* CUCFInitObjectCHOICE(tCoder* Coder, tVMSULong Index, void* Alternative);
#define CUCFInitObjectOPEN(Info, Index, Object) CUCFInitObjectCHOICE(Info, Index, Object)

typedef struct {
  tASN1TypeInfo* Type;
  void*          Value;
} tVMS;


/* ER */

enum {
  er_NoRule        = 0x0000,
/*er_Basic         = 0x0001,*/
/*er_Canonical     = 0x0002,*/
  er_Indefinite    = 0x0004,
  er_Definite      = 0x0008,
  er_NoEndPad      = 0x0010,
  er_Unaligned     = 0x0020,
  er_Aligned       = 0x0040,
  er_UER           = 0x0080,
  er_BER           = 0x0100,
/*er_CER           = 0x0200,*/
/*er_DER           = 0x0400,*/
  er_PER           = 0x0800
};

typedef unsigned long tERRule;

typedef struct
{
  tERRule        Rule;
  unsigned long  ValueLength;
  unsigned char* MemStart;
  unsigned char* MemEnd;
  unsigned char* DataEnd;
  unsigned char* DataCurr;
  unsigned char  BitEnd;
  unsigned char  BitCurr;
} tER;



/* Coder */

typedef void* tUserData;

struct sCoder {
  tEMS          EMS;
  tMMS          MMS;
  tBMS          BMS;
  tVMS          VMS;
  tER           ER;
  tUserData     UserData;
  unsigned char IsAssigned;
};

#define ASN1_ENCODE(c, type, val) ASN1Encode(c, type, val)
#define ASN1_DECODE(c, type, val) ASN1Decode(c, type, val)

extern void ERSetRule(tCoder* Coder, unsigned long Rule);

extern int ASN1Encode(tCoder* Coder, tASN1TypeInfo* Type, void* Val);
extern int ASN1Decode(tCoder* Coder, tASN1TypeInfo* Type, void* Val);

/* Backwards compatibility */
#ifndef TRUE
#define TRUE 255
#endif

#ifndef FALSE
#define FALSE 0
#endif

typedef enum
{
  UCF_Align,
  UCF_Unalign,
  UCF_NoEndPad
} UCFEncVariant;

typedef enum
{
  dt_Direct,
  dt_Reverse
} tDirectionType;

typedef enum
{
  bem_Off,
  bem_On
} tBufferErrorMode;

#define DIRECT
#define REVERSE

#undef BufInitBuf
#define BufInitBuf(b, dirtype, status) \
if (BaseBufInitBuf(&b, bms_SmallBuffer) == 0) \
  status = UCF_Ok; \
else \
  status = UCF_DYN_NoEnoughMemory;

#define BufGetDirType(b)          dt_Direct
#define BufNotInitialized(b)      BufInNoMode(b)
#define BufSetEncVar(b, enc_var)  BufSetRule(b, (enc_var == UCF_ALign) ? (er_PER | er_Aligned) : (enc_var == UCF_Unaligned) ? \
                                             (er_PER | er_Unaligned) : (er_PER | er_NoEndPad))
#define BufGetEncVar(b)           ((BufGetRule(b) & er_Aligned) ? UCF_Align : (BufGetRule(b) & er_Unaligned) ? UCF_Unalign : UCF_NoEndPad)
#define BufSetCatcher(b)          0
#define BufGetErrorMode(b)        bem_Off

#define BufPutAlign(b)            BufAlign(b)
#define BufGetAlign(b)            BufAlign(b)

typedef int UCFStatus;

#define UCF_Ok                                  ec_SUCCESS

/* Dynamic errors */
#define UCF_DYN_NoEnoughMemory                  ec_MEM_NotEnoughMemory

/* Buffer errors */
#define UCF_BUF_ClosingWrongMode                ec_BUF_CloseWrongMode
#define UCF_BUF_EndOfBuffer                     ec_BUF_EndOfBuffer

/* Internal errors*/
#define UCF_INTERNAL_ERROR                      ec_INT_InternalError
#define UCF_ENC_TypeNotSupported                ec_INT_UnsupportedType

/* Decoding errors */
#define UCF_DEC_WrongTypeLength                 ec_DEC_WrongLength
#define UCF_DEC_WrongTagNumberLength            ec_DEC_TooBigTagNumber
#define UCF_DEC_RequiredComponentAbsent         ec_DEC_RequiredComponentIsAbsent
#define UCF_DEC_UnknownAlternative              ec_DEC_UnknownAlternative
#define UCF_DEC_BigNumberSubident               ec_DEC_TooBigSubIdent
#define UCF_DEC_WrongRealValue                  ec_DEC_WrongRealPrefix
#define UCF_DEC_UnsupportedRealBase             ec_DEC_UnsupportedRealBase
#define UCF_DEC_UnsupportedRealDecimalEncoding  ec_DEC_UnsupportedRealDecimalEncoding
#define UCF_DEC_IllegalValueOfLength            ec_DEC_WrongConstructedLengthPrefix

/* Error outputting backward compability */
#define UCFPrintErrorMessage CUCFErrorOutput

/* Encode/decode macros backward compability */
typedef tVMSULong tLength;

extern UCFStatus TTCN_BEREncode(tBuffer Buf, tASN1TypeInfo *Type, GciValue* Val);
extern UCFStatus TTCN_BERDecode(tBuffer Buf, tASN1TypeInfo *Type, tLength* DecLength, GciValue** Val);

#define BER_ENCODE(b, type, val) TTCN_BEREncode(b, type, val)
#define BER_DECODE(b, type, dec_length, val) TTCN_BERDecode(b, type, dec_length, val)

#ifndef UCF_PER_DEFAULT_ENCODING_VARIANT
#define UCF_PER_DEFAULT_ENCODING_VARIANT UCF_Unalign
#endif

extern UCFStatus TTCN_PEREncode(tBuffer Buf, tASN1TypeInfo *Type, unsigned char EncVar, GciValue* Val);
extern UCFStatus TTCN_PERDecode(tBuffer Buf, tASN1TypeInfo *Type, unsigned char EncVar, tVMSULong* DecLength, GciValue** Val);

#define PER_ENCODE(b, type, enc_var, val) TTCN_PEREncode(b, type, enc_var, val)
#define PER_DECODE(b, type, enc_var, dec_length, val) TTCN_PERDecode(b, type, enc_var, dec_length, val)

#endif /* __ucf.h */
