/* Copyright (C) 1994 - 2001 by Telelogic AB.
Copyright (C) 1991, 1992, 1993, 1994 by Telelogic Malmoe AB.
Copyright (C) 1990, 1991, 1999 by Telesoft Europe AB.
This Program is owned by Telelogic and is protected by national
copyright laws and international copyright treaties. Telelogic
grants you the right to use this Program on one computer or in
one local computer network at any one time.
Under this License you may only modify the source code for the purpose
of adapting it to your environment. You must reproduce and include
any copyright and trademark notices on all copies of the source code.
You may not use, copy, merge, modify or transfer the Program except as
provided in this License.
Telelogic does not warrant that the Program will meet your
requirements or that the operation of the Program will be
uninterrupted and error free. You are solely responsible that the
selection of the Program and the modification of the source code
will achieve your intended result and that the results are actually
obtained. */

#ifndef __bms_h
#define __bms_h

typedef unsigned long tBMSLength;

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

typedef enum tBMSBufType
{
  bms_SmallBuffer,
  bms_UserBuffer
} tBMSBufType;

enum
{
  bms_NoMode,
  bms_ReadMode,
  bms_WriteMode
};

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



#ifndef CODER_REMOVE_SMALLBUF
#include "bms/bms_small.h"
#define SMALLBUF_STRUCT_SIZE  sizeof(tBMSSmallBuffer)
#else
#define SMALLBUF_STRUCT_SIZE  0
#endif

#ifdef CODER_USE_USERBUF
#include "bms_user.h"
#define USERBUF_STRUCT_SIZE  sizeof(tBMSUserBuffer)
#else
#define USERBUF_STRUCT_SIZE  0
#endif

#define BUFFER_STRUCT_SIZE \
  (SMALLBUF_STRUCT_SIZE > USERBUF_STRUCT_SIZE) ? SMALLBUF_STRUCT_SIZE : USERBUF_STRUCT_SIZE



/* Common BMS interfaces */

#define BufGetRule(c)                                 ERGetRule(c)
#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

#ifndef CODER_REMOVE_PATH
#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
#endif

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

#define BufSetExternalError(c, errorcode)             BufSetErrorCode(c, errorcode)
#define BufExternalError(c)                           BufGetErrorCode(c)

#define BufReadError(c)                               BufGetErrorCode(c)
#define BufWriteError(c)                              BufGetErrorCode(c)

#ifndef CODER_BMS_TINY
#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)
#endif

#if !defined(CODER_BMS_SMALLBUF) && !defined(CODER_BMS_USERBUF)

#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)

#ifndef CODER_BMS_TINY
#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)
#endif

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);

#ifndef CODER_REMOVE_PATH
typedef void (*tBufErrInitFunc)(tCoder* Coder);
#endif

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);

#ifndef CODER_BMS_TINY
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);
#endif

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;

#ifndef CODER_BMS_TINY
  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;
#endif
} tBMSBaseBuffer;

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

#ifndef CODER_REMOVE_SMALLBUF
extern const tBMSBaseBuffer SmallBuffer;
#endif

#ifdef CODER_USE_USERBUF
extern const tBMSBaseBuffer UserBuffer;
#endif

#endif /* !CODER_BMS_SMALLBUF && !CODER_BMS_USERBUF */

#endif /* __bms_h */
