/* 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. */

#include "cucf.h"

#ifdef CODER_USE_USERBUF

#ifndef CODER_BMS_USERBUF

const tBMSBaseBuffer UserBuffer = {
  bms_UserBuffer,                                           /* BufType */
  "",                                                        /* Buffer */

  /* Functions */
  (tBufInitBufFunc)              UserBufInitBuf,            /* initBuf */
  (tBufCloseBufFunc)             UserBufCloseBuf,           /* closeBuf */

  (tBufInitBufWithMemoryFunc)    UserBufInitBufWithMemory,  /* initBufWithMemory */
  (tBufCloseBufToMemoryFunc)     UserBufCloseBufToMemory,   /* closeBufToMemory */ 

  (tBufGetLengthFunc)            UserBufGetLength,          /* getLength */

  (tBufGetMemoryFunc)            UserBufGetMemory,          /* getMemory */
  (tBufAppendMemoryFunc)         UserBufAppendMemory,       /* appendMemory */

  (tBufGetDataCurr)              UserBufGetDataCurr,        /* getDataCurr */
  (tBufSetDataCurr)              UserBufSetDataCurr,        /* setDataCurr */
  (tBufGetDataEnd)               UserBufGetDataEnd,         /* getDataEnd */
  (tBufSetDataEnd)               UserBufSetDataEnd,         /* setDataEnd */

#ifndef CODER_BMS_TINY
  (tBufCopyBufFunc)              UserBufCopyBuf,            /* copyBuf */

  (tBufInitWriteModeFunc)        UserBufInitWriteMode,      /* initWriteMode */
  (tBufCloseWriteModeFunc)       UserBufCloseWriteMode,     /* closeWriteMode */

  (tBufInitReadModeFunc)         UserBufInitReadMode,       /* initReadMode */
  (tBufCloseReadModeFunc)        UserBufCloseReadMode,      /* closeReadMode */
  (tBufCloseDeleteReadModeFunc)  UserBufCloseDeleteReadMode,/* closeDeleteReadMode */

  /* Read/Write functions */
  (tBufGetByteFunc)              UserBufGetByte,            /* getByte */
  (tBufPeekByteFunc)             UserBufPeekByte,           /* peekByte */
  (tBufPutByteFunc)              UserBufPutByte,            /* putByte */

  (tBufGetSegFunc)               UserBufGetSeg,             /* getSeg */
  (tBufSkipSegFunc)              UserBufSkipSeg,            /* skipSeg */
  (tBufPeekSegFunc)              UserBufPeekSeg,            /* peekSeg */
  (tBufPutSegFunc)               UserBufPutSeg,             /* putSeg */

  (tBufPutBitFunc)               UserBufPutBit,             /* putBit */
  (tBufGetBitFunc)               UserBufGetBit,             /* getBit */

  (tBufPutBitsFunc)              UserBufPutBits,            /* putBits */
  (tBufGetBitsFunc)              UserBufGetBits,            /* getBits */

  (tBufAlignFunc)                UserBufAlign               /* bufAlign */
#endif /* CODER_BMS_TINY */
};

#endif /* CODER_BMS_USERBUF */

const tBMSUserBuffer UserInit = {
  NULL,            /* MemStart */
  NULL,            /* MemEnd */
  NULL,            /* DataStart */
  NULL,            /* DataEnd */
  NULL,            /* DataCurr */
  7,               /* BitStart */
  7,               /* BitEnd */
  7,               /* BitCurr */
  0                /* IsAssigned */
};


/**************************************************
 * 
 * NAME: UserBufInitBuf
 *
 *
 */

int
UserBufInitBuf(tCoder** Coder)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufInitBuf\n");
#endif

#ifdef CODER_BMS_USERBUF
#ifdef CODER_BMS_TINY
  if (*Coder == NULL) {
    *Coder = (tCoder*)BMS_ALLOC(*Coder, sizeof(tCoder), 0);
    MEMORY_ERROR_HANDLER_EXP(*Coder == NULL, *Coder, return ec_MEM_NotEnoughMemory, ec_MEM_NotEnoughMemory, NO_ARGS);
    (*Coder)->IsAssigned = 0;
  } else {
    (*Coder)->IsAssigned = 1;
  }
#else
  *Coder = (tCoder*)BMS_ALLOC(*Coder, sizeof(tCoder), 0);
  MEMORY_ERROR_HANDLER_EXP(*Coder == NULL, *Coder, return ec_MEM_NotEnoughMemory, ec_MEM_NotEnoughMemory, NO_ARGS);
#endif
#endif

  EMSInit(*Coder);
  MMSInit(*Coder);
  BMSInit(*Coder);
  ERInit(*Coder);

#ifdef CODER_BMS_USERBUF
  Buf = &((*Coder)->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)(*Coder)->BMS.BMSBuffer.Buffer;
#endif
  
  *Buf = UserInit;
  Buf->MemStart = (unsigned char*)BMS_ALLOC(*Coder, CODER_USERBUF_SIZE, 0);
  MEMORY_ERROR_HANDLER_EXP(Buf->MemStart == NULL, *Coder, return ec_MEM_NotEnoughMemory, ec_MEM_NotEnoughMemory, NO_ARGS);
  Buf->MemEnd = Buf->MemStart + CODER_USERBUF_SIZE;
  Buf->DataStart = Buf->DataEnd = Buf->DataCurr = Buf->MemStart;
  return ec_SUCCESS; 
}

/**************************************************
 * 
 * NAME: UserBufCloseBuf
 *
 *
 */

int
UserBufCloseBuf(tCoder** Coder)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufCloseBuf\n");
#endif

#ifdef CODER_BMS_USERBUF
  Buf = &((*Coder)->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)(*Coder)->BMS.BMSBuffer.Buffer;
#endif

  USERBUF_ERROR_HANDLER_EXP((*Coder)->BMS.Mode != bms_NoMode, *Coder, return ec_BUF_IllegalClose, ec_BUF_IllegalClose, NO_ARGS);
  if (!Buf->IsAssigned)
    {
      BMS_FREE(*Coder, Buf->MemStart, Buf->MemEnd - Buf->MemStart, 0);
    }
#ifdef CODER_BMS_TINY
  if (!(*Coder)->IsAssigned)
    {
      BMS_FREE(*Coder, *Coder, sizeof(tCoder), 0);
      *Coder = NULL;
    }
#else
  BMS_FREE(*Coder, *Coder, sizeof(tCoder), 0);
  *Coder = NULL;
#endif
  return ec_SUCCESS;
}

/**************************************************
 * 
 * NAME: UserBufInitBufWithMemory
 *
 *
 */

int
UserBufInitBufWithMemory(tCoder** Coder, tBMSUserMemory* UserMemory)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufInitBufWithMemory\n");
#endif

#ifdef CODER_BMS_USERBUF
  if (UserMemory == NULL)
    return ec_BUF_NullPtrToUserMemory;

#ifdef CODER_BMS_TINY
  if (*Coder == NULL) {
    *Coder = (tCoder*)BMS_ALLOC(*Coder, sizeof(tCoder), 0);
    MEMORY_ERROR_HANDLER_EXP(*Coder == NULL, *Coder, return ec_MEM_NotEnoughMemory, ec_MEM_NotEnoughMemory, NO_ARGS);
    (*Coder)->IsAssigned = 0;
  } else {
    (*Coder)->IsAssigned = 1;
  }
#else
  *Coder = (tCoder*)BMS_ALLOC(*Coder, sizeof(tCoder), 0);
  MEMORY_ERROR_HANDLER_EXP(*Coder == NULL, *Coder, return ec_MEM_NotEnoughMemory, ec_MEM_NotEnoughMemory, NO_ARGS);
#endif
#endif

  EMSInit(*Coder);
  MMSInit(*Coder);
  BMSInit(*Coder);
  ERInit(*Coder);

#ifdef CODER_BMS_USERBUF
  Buf = &((*Coder)->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)(*Coder)->BMS.BMSBuffer.Buffer;
#endif

  *Buf = UserInit;
  Buf->MemStart = (unsigned char*)(UserMemory->MemPtr);
  Buf->MemEnd = (unsigned char*)(UserMemory->MemPtr) + UserMemory->MemSize;
  Buf->DataStart = Buf->DataCurr = Buf->MemStart;
  Buf->DataEnd = Buf->DataStart + UserMemory->DataLength;
  Buf->IsAssigned = 1;
  return ec_SUCCESS; 
}

/**************************************************
 * 
 * NAME: UserBufCloseBufToMemory
 *
 *
 */

int
UserBufCloseBufToMemory(tCoder** Coder, tBMSUserMemory* UserMemory)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufCloseBufWithMemory\n");
#endif

  if (UserMemory == NULL)
    return ec_BUF_NullPtrToUserMemory;

#ifdef CODER_BMS_USERBUF
  Buf = &((*Coder)->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)(*Coder)->BMS.BMSBuffer.Buffer;
#endif

  USERBUF_ERROR_HANDLER_EXP((*Coder)->BMS.Mode != bms_NoMode, *Coder, return ec_BUF_IllegalClose, ec_BUF_IllegalClose, NO_ARGS);
  (*UserMemory).MemPtr = Buf->MemStart;
  (*UserMemory).MemSize = Buf->MemEnd - Buf->MemStart;
  (*UserMemory).DataLength = (Buf->DataEnd - Buf->DataStart) + ((Buf->BitStart > Buf->BitEnd) ? 1 : 0);
#ifndef CODER_BMS_TINY
  if (Buf->BitStart != 7)
    {
      unsigned char* CurrByte = Buf->MemStart;
      *CurrByte = (unsigned char)(*(Buf->DataStart) << (7 - Buf->BitStart));
      if (Buf->DataStart != Buf->DataEnd)
        {
          Buf->DataStart++;
          while (Buf->DataStart != Buf->DataEnd)
            {
              *CurrByte |= (unsigned char)(*(Buf->DataStart) >> (Buf->BitStart + 1));
              CurrByte++;
              *CurrByte = (unsigned char)(*(Buf->DataStart) << (7 - Buf->BitStart));
              Buf->DataStart++;
           }
          if (Buf->BitEnd != 7)
            {
              *CurrByte |= (unsigned char)(*(Buf->DataStart) >> (Buf->BitStart + 1));
              if (Buf->BitStart > Buf->BitEnd)
                {
                  CurrByte++;
                  *CurrByte = (unsigned char)(*(Buf->DataStart) << (7 - Buf->BitStart));
                }
            }
        }
    }
  else
    {
      if (Buf->MemStart != Buf->DataStart)
        memcpy(Buf->MemStart, Buf->DataStart, (*UserMemory).DataLength);
    }
#endif

#ifdef CODER_BMS_TINY
  if (!(*Coder)->IsAssigned)
    {
      BMS_FREE(*Coder, *Coder, sizeof(tCoder), 0);
      *Coder = NULL;
    }
#else
  BMS_FREE(*Coder, *Coder, sizeof(tCoder), 0);
  *Coder = NULL;
#endif

  return ec_SUCCESS;
}

/**************************************************
 * 
 * NAME: UserBufGetLength
 *
 *
 */

tBMSLength
UserBufGetLength(tCoder* Coder, tBMSLengthType LengthType)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufGetLength\n");
#endif

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  switch (LengthType)
    {
    case bms_DataLength:
      return (Buf->DataEnd - Buf->DataStart) + ((Buf->BitStart > Buf->BitEnd) ? 1 : 0);
    case bms_DataBitLength:
      return ((Buf->DataEnd - Buf->DataStart) << 3) + (Buf->BitStart - Buf->BitEnd);
    case bms_ReadDataLength:
      return (Buf->DataCurr - Buf->DataStart) + ((Buf->BitStart > Buf->BitCurr) ? 1 : 0);
    case bms_ReadDataBitLength:
      return ((Buf->DataCurr - Buf->DataStart) << 3) + (Buf->BitStart - Buf->BitCurr);
    case bms_ValueLength:
      return (Coder->ER.ValueBitLength >> 3) + ((Coder->ER.ValueBitLength & 0x7) ? 1 : 0);
    default:
      break;
    }

  return Coder->ER.ValueBitLength;   /* bms_ValueBitLength */
}

/**************************************************
 *
 * NAME: UserBufGetMemory
 *
 *
 */

unsigned char*
UserBufGetMemory(tCoder* Coder, tBMSLength* rLength)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufGetMemory\n");
#endif

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  *rLength = Buf->MemEnd - Buf->MemStart;
  return Buf->MemStart;
}

/**************************************************
 * 
 * NAME: UserBufAppendMemory
 *
 *
 */

unsigned char*
UserBufAppendMemory(tCoder* Coder, tBMSLength AppendLen)
{
  tBMSUserBuffer* Buf;
  unsigned char* NewMemPtr;
  tBMSLength NewMemLength;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufAppendMemory\n");
#endif

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  USERBUF_ERROR_HANDLER_EXP(Buf->IsAssigned, Coder, return NULL, ec_BUF_NotEnoughUserMemory, NO_ARGS);
  NewMemLength = Buf->MemEnd - Buf->MemStart + AppendLen;
  NewMemPtr = (unsigned char*)BMS_ALLOC(Coder, NewMemLength, 0);
  MEMORY_ERROR_HANDLER_EXP(NewMemPtr == NULL, Coder, return NULL, ec_MEM_NotEnoughMemory, NO_ARGS);
  memcpy(NewMemPtr, Buf->MemStart, Buf->MemEnd - Buf->MemStart);
  Buf->DataStart = NewMemPtr + (Buf->DataStart - Buf->MemStart);
  Buf->DataEnd = NewMemPtr + (Buf->DataEnd - Buf->MemStart);
  Buf->DataCurr = NewMemPtr + (Buf->DataCurr - Buf->MemStart);
  BMS_FREE(Coder, Buf->MemStart, Buf->MemEnd - Buf->MemStart, 0);
  Buf->MemStart = NewMemPtr;
  Buf->MemEnd = Buf->MemStart + NewMemLength;
  return Buf->MemStart;
}

/**************************************************
 *
 * NAME: UserBufGetDataCurr
 *
 *
 */

unsigned char*
UserBufGetDataCurr(tCoder* Coder, unsigned char* rBitCurr)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufGetDataCurr\n");
#endif
  
#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  *rBitCurr = Buf->BitCurr;
  return Buf->DataCurr;
}

/**************************************************
 *
 * NAME: UserBufSetDataCurr
 *
 *
 */

void
UserBufSetDataCurr(tCoder* Coder, tBMSLength Length, unsigned char BitCurr)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufSetDataCurr\n");
#endif

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  Buf->DataCurr += Length;
  Buf->BitCurr = BitCurr;
}

/**************************************************
 *
 * NAME: UserBufGetDataEnd
 *
 *
 */

unsigned char*
UserBufGetDataEnd(tCoder* Coder, unsigned char* rBitEnd)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufGetDataEnd\n");
#endif

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  *rBitEnd = Buf->BitEnd;
  return Buf->DataEnd;
}

/**************************************************
 *
 * NAME: UserBufSetDataEnd
 *
 *
 */

void
UserBufSetDataEnd(tCoder* Coder, tBMSLength Length, unsigned char BitEnd)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufSetDataEnd\n");
#endif

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  Buf->DataEnd += Length;
  Buf->BitEnd = BitEnd;
}

#ifndef CODER_BMS_TINY
/**************************************************
 * 
 * NAME: UserBufCopyBuf
 *
 *
 */

int
UserBufCopyBuf(tCoder* Dst, tCoder* Src)
{
  tBMSUserBuffer* DstBuf;
  tBMSUserBuffer* SrcBuf;
  tBMSLength DataLength;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufCopyBuf\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Dst == NULL || Src == NULL,
                             Src, return ec_BUF_WorkWithNotInitialized, ec_BUF_WorkWithNotInitialized, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  DstBuf = &(Dst->BMS.BMSBuffer);
  SrcBuf = &(Src->BMS.BMSBuffer);
#else
  USERBUF_ERROR_HANDLER_EXP(Dst->BMS.BMSBuffer.BufType != Src->BMS.BMSBuffer.BufType,
                             Src, return ec_BUF_DifferentBufferTypes, ec_BUF_DifferentBufferTypes, NO_ARGS);
  DstBuf = (tBMSUserBuffer*)Dst->BMS.BMSBuffer.Buffer;
  SrcBuf = (tBMSUserBuffer*)Src->BMS.BMSBuffer.Buffer;
#endif

  DataLength = (SrcBuf->DataEnd - SrcBuf->DataStart) + ((SrcBuf->BitEnd != 7) ? 1 : 0);
  if (DataLength > (tBMSLength)(DstBuf->MemEnd - DstBuf->MemStart))
    {
      unsigned char* NewMemPtr;

      USERBUF_ERROR_HANDLER_EXP(DstBuf->IsAssigned, Src, return ec_BUF_NotEnoughUserMemory, ec_BUF_NotEnoughUserMemory, NO_ARGS);
      NewMemPtr = (unsigned char*)BMS_ALLOC(Dst, DataLength, 0);
      MEMORY_ERROR_HANDLER_EXP(NewMemPtr == NULL, Src, return ec_MEM_NotEnoughMemory, ec_MEM_NotEnoughMemory, NO_ARGS);
      BMS_FREE(Dst, DstBuf->MemStart, DstBuf->MemEnd - DstBuf->MemStart, 0);
      DstBuf->MemStart = NewMemPtr;
      DstBuf->MemEnd = DstBuf->MemStart + DataLength;
    }
  DstBuf->DataEnd = DstBuf->MemStart + (SrcBuf->DataEnd - SrcBuf->DataStart);
  DstBuf->DataCurr = DstBuf->MemStart + (SrcBuf->DataCurr - SrcBuf->DataStart);
  DstBuf->DataStart = DstBuf->MemStart;
  memcpy(DstBuf->DataStart, SrcBuf->DataStart, DataLength);
  DstBuf->BitStart = SrcBuf->BitStart;
  DstBuf->BitEnd = SrcBuf->BitEnd;
  DstBuf->BitCurr = SrcBuf->BitCurr;
  return ec_SUCCESS;
}

/**************************************************
 * 
 * NAME: UserBufInitWriteMode
 *
 *
 */

int 
UserBufInitWriteMode(tCoder* Coder)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufInitWriteMode\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_NoMode, Coder, return ec_BUF_OpenOpened, ec_BUF_OpenOpened, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  Buf->DataStart = Buf->MemStart;
  Buf->DataEnd   = Buf->MemStart;
  Buf->DataCurr  = Buf->MemStart;
  Buf->BitStart  = 7;
  Buf->BitEnd    = 7;
  Buf->BitCurr   = 7;
  Coder->EMS.ErrorCode = 0;
  Coder->BMS.Mode = bms_WriteMode;
  return ec_SUCCESS;
}

/**************************************************
 * 
 * NAME: UserBufCloseWriteMode
 *
 *
 */

int 
UserBufCloseWriteMode(tCoder* Coder)
{
#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufCloseWriteMode\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_WriteMode, Coder, return ec_BUF_CloseWrongMode, ec_BUF_CloseWrongMode, NO_ARGS);
  Coder->BMS.Mode = bms_NoMode;
  return ec_SUCCESS;
}

/**************************************************
 * 
 * NAME: UserBufInitReadMode
 *
 *
 */

int 
UserBufInitReadMode(tCoder* Coder)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufInitReadMode\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_NoMode, Coder, return ec_BUF_OpenOpened, ec_BUF_OpenOpened, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  Buf->DataCurr = Buf->DataStart;
  Buf->BitCurr  = Buf->BitStart;
  Coder->EMS.ErrorCode = 0;
  Coder->BMS.Mode = bms_ReadMode;
  return ec_SUCCESS;
}

/**************************************************
 * 
 * NAME: UserBufCloseReadMode
 *
 *
 */

int 
UserBufCloseReadMode(tCoder* Coder)
{

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufCloseReadMode\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return ec_BUF_CloseWrongMode, ec_BUF_CloseWrongMode, NO_ARGS);
  Coder->BMS.Mode = bms_NoMode;
  return ec_SUCCESS;
}

/**************************************************
 * 
 * NAME: UserBufCloseDeleteReadMode
 *
 *
 */

int 
UserBufCloseDeleteReadMode(tCoder* Coder)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufCloseDeleteReadMode\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return ec_BUF_CloseWrongMode, ec_BUF_CloseWrongMode, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  Buf->DataStart = Buf->DataCurr;
  Buf->BitStart = Buf->BitCurr;
  Coder->BMS.Mode = bms_NoMode;
  return ec_SUCCESS;
}

/**************************************************
 * 
 * NAME: UserBufGetByte
 *
 *
 */

unsigned char
UserBufGetByte(tCoder* Coder)
{
  tBMSUserBuffer* Buf;
  unsigned char Byte;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufGetByte\n");
#endif
  
  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return 0, ec_BUF_OperationWrongMode, NO_ARGS);
  
#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  if (((Buf->DataEnd - Buf->DataCurr) << 3) + (Buf->BitCurr - Buf->BitEnd) < 8)
    {
      if (Coder->BMS.AppendFunc)
        Coder->BMS.AppendFunc(Coder, 1);
      /* Aka, 7 JAN 2002 */
      USERBUF_ERROR_HANDLER_EXP(((Buf->DataEnd - Buf->DataCurr) << 3) + (Buf->BitCurr - Buf->BitEnd) < 8,
                                 Coder, return 0, ec_BUF_NoMoreDataForRead, NO_ARGS);
    }
  if (Buf->BitCurr != 7)
    {
      Byte = (unsigned char)(*(Buf->DataCurr) << (7 - Buf->BitCurr));
      Byte |= (unsigned char)(*(Buf->DataCurr + 1) >> (Buf->BitCurr + 1));      
    }
  else
    {
      Byte = *(Buf->DataCurr);
    }
  Buf->DataCurr++;
  return Byte;
}

/**************************************************
 * 
 * NAME: UserBufPeekByte
 *
 *
 */

unsigned char
UserBufPeekByte(tCoder* Coder)
{
  tBMSUserBuffer* Buf;
  unsigned char Byte;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufPeekByte\n");
#endif
  
  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return 0, ec_BUF_OperationWrongMode, NO_ARGS);
  
#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  if (((Buf->DataEnd - Buf->DataCurr) << 3) + (Buf->BitCurr - Buf->BitEnd) < 8)
    {
      if (Coder->BMS.AppendFunc)
        Coder->BMS.AppendFunc(Coder, 1);
      /* Aka, 7 JAN 2002 */
      USERBUF_ERROR_HANDLER_EXP(((Buf->DataEnd - Buf->DataCurr) << 3) + (Buf->BitCurr - Buf->BitEnd) < 8,
                                 Coder, return 0, ec_BUF_NoMoreDataForRead, NO_ARGS);
    }
  if (Buf->BitCurr != 7)
    {
      Byte = (unsigned char)(*(Buf->DataCurr) << (7 - Buf->BitCurr));
      Byte |= (unsigned char)(*(Buf->DataCurr + 1) >> (Buf->BitCurr + 1));      
    }
  else
    {
      Byte = *(Buf->DataCurr);
    }
  return Byte;
}

/**************************************************
 * 
 * NAME: UserBufPutByte
 *
 *
 */

void
UserBufPutByte(tCoder* Coder, unsigned char Byte)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufPutByte\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode == bms_NoMode, Coder, return, ec_BUF_OperationWrongMode, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  if (Buf->BitEnd != 7)
    {
      if (Buf->DataEnd + 1 == Buf->MemEnd)
        if (UserBufAppendMemory(Coder, CODER_USERBUF_SIZE) == NULL) return;
      *(Buf->DataEnd) |= (unsigned char)(Byte >> (7 - Buf->BitEnd));
      *(Buf->DataEnd + 1) = (unsigned char)(Byte << (Buf->BitEnd + 1));
    }
  else
    {
      if (Buf->DataEnd == Buf->MemEnd)
        if (UserBufAppendMemory(Coder, CODER_USERBUF_SIZE) == NULL) return;
      *(Buf->DataEnd) = Byte;
    }
  Buf->DataEnd++;
}

/**************************************************
 * 
 * NAME: UserBufGetSeg
 *
 *
 */

unsigned char*
UserBufGetSeg(tCoder* Coder, tBMSLength SegLen)
{
  tBMSUserBuffer* Buf;
  unsigned char* Seg;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufGetSeg\n");
#endif
  
  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return NULL, ec_BUF_OperationWrongMode, NO_ARGS);
  if (SegLen == 0) return NULL;

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  INTERNAL_ERROR_HANDLER_EXP(Buf->BitCurr != 7,
                             Coder, ec_INT_InternalError,
                             ERR_ARG(__FILE__) ERR_ARG(__LINE__));
  if (Buf->DataEnd - Buf->DataCurr < (long)SegLen)
    {
      if (Coder->BMS.AppendFunc)
        Coder->BMS.AppendFunc(Coder, SegLen - (Buf->DataEnd - Buf->DataCurr));
      USERBUF_ERROR_HANDLER_EXP(Buf->DataEnd - Buf->DataCurr + ((Buf->BitEnd != 7) ? 1 : 0) < (long)SegLen,
                                 Coder, return NULL, ec_BUF_NoMoreDataForRead, NO_ARGS);
    }
  Seg = Buf->DataCurr;
  Buf->DataCurr += SegLen;
  return Seg;
}

/**************************************************
 * 
 * NAME: UserBufSkipSeg
 *
 *
 */

void
UserBufSkipSeg(tCoder* Coder, tBMSLength SegLen)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufSkipSeg\n");
#endif
  
  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return, ec_BUF_OperationWrongMode, NO_ARGS);
  if (SegLen == 0) return;

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  INTERNAL_ERROR_HANDLER_EXP(Buf->BitCurr != 7,
                             Coder, ec_INT_InternalError,
                             ERR_ARG(__FILE__) ERR_ARG(__LINE__));
  if (Buf->DataEnd - Buf->DataCurr < (long)SegLen)
    {
      if (Coder->BMS.AppendFunc)
        Coder->BMS.AppendFunc(Coder, SegLen - (Buf->DataEnd - Buf->DataCurr));
      USERBUF_ERROR_HANDLER_EXP(Buf->DataEnd - Buf->DataCurr + ((Buf->BitEnd != 7) ? 1 : 0) < (long)SegLen,
                                 Coder, return, ec_BUF_NoMoreDataForRead, NO_ARGS);
    }
  Buf->DataCurr += SegLen;
}

/**************************************************
 * 
 * NAME: UserBufPeekSeg
 *
 *
 */

unsigned char*
UserBufPeekSeg(tCoder* Coder, tBMSLength SegLen)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufPeekSeg\n");
#endif
  
  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return NULL, ec_BUF_OperationWrongMode, NO_ARGS);
  if (SegLen == 0) return NULL;

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  INTERNAL_ERROR_HANDLER_EXP((Buf->BitCurr != 7),
                             Coder, ec_INT_InternalError,
                             ERR_ARG(__FILE__) ERR_ARG(__LINE__));
  if (Buf->DataEnd - Buf->DataCurr < (long)SegLen)
    {
      if (Coder->BMS.AppendFunc)
        Coder->BMS.AppendFunc(Coder, SegLen - (Buf->DataEnd - Buf->DataCurr));
      USERBUF_ERROR_HANDLER_EXP(Buf->DataEnd - Buf->DataCurr + ((Buf->BitEnd != 7) ? 1 : 0) < (long)SegLen,
                                 Coder, return NULL, ec_BUF_NoMoreDataForRead, NO_ARGS);
    }
  return Buf->DataCurr;
}

/**************************************************
 * 
 * NAME: UserBufPutSeg
 *
 *
 */

void
UserBufPutSeg(tCoder* Coder, unsigned char* Seg, tBMSLength SegLen)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufPutSeg\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode == bms_NoMode, Coder, return, ec_BUF_OperationWrongMode, NO_ARGS);
  if (SegLen == 0) return;

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  if (Buf->BitEnd != 7)
    {
      unsigned char* Byte = Seg;
      if (Buf->DataEnd + SegLen + 1 > Buf->MemEnd)
        if (UserBufAppendMemory(Coder, CODER_USERBUF_SIZE) == NULL) return;
      for(; SegLen > 0; SegLen--, Byte++)
        {
          *(Buf->DataEnd) |= (unsigned char)(*Byte >> (7 - Buf->BitEnd));
          Buf->DataEnd++;
          *(Buf->DataEnd) = (unsigned char)(*Byte << (Buf->BitEnd + 1));
        }
    }
  else
    {
      if (Buf->DataEnd + SegLen > Buf->MemEnd)
        if (UserBufAppendMemory(Coder, CODER_USERBUF_SIZE) == NULL) return;
      memcpy(Buf->DataEnd, Seg, SegLen);
      Buf->DataEnd += SegLen;
    }
}

/**************************************************
 * 
 * NAME: UserBufGetBit
 *
 *
 */

unsigned char
UserBufGetBit(tCoder* Coder)
{
  tBMSUserBuffer* Buf;
  unsigned char Bit;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufGetBit\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return 0, ec_BUF_OperationWrongMode, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  if (Buf->DataCurr == Buf->DataEnd && Buf->BitCurr == Buf->BitEnd)
    {
      if (Coder->BMS.AppendFunc)
        Coder->BMS.AppendFunc(Coder, 1);
      USERBUF_ERROR_HANDLER_EXP(Buf->DataCurr == Buf->DataEnd, Coder, return 0, ec_BUF_NoMoreDataForRead, NO_ARGS);
    }
  if (Buf->BitCurr != 7)
    {
      Bit = (unsigned char)((*(Buf->DataCurr) >> Buf->BitCurr) & 0x01);
      if (Buf->BitCurr == 0)
        {
          Buf->DataCurr++;
          Buf->BitCurr = 7;
        }
      else
        Buf->BitCurr--;
    }
  else
    {
      Bit = (unsigned char)((*(Buf->DataCurr) >> Buf->BitCurr) & 0x01);
      Buf->BitCurr = 6;
    }
  return Bit;
}

/**************************************************
 * 
 * NAME: UserBufPutBit
 *
 *
 */

void
UserBufPutBit(tCoder* Coder, unsigned char Bit)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufPutBit\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode == bms_NoMode, Coder, return, ec_BUF_OperationWrongMode, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  if (Buf->BitEnd != 7)
    {
      *(Buf->DataEnd) |= (unsigned char)(Bit << Buf->BitEnd);
      if (Buf->BitEnd == 0)
        {
          Buf->DataEnd++;
          Buf->BitEnd = 7;
        }
      else
        Buf->BitEnd--;
    }
  else
    {
      if (Buf->DataEnd == Buf->MemEnd)
        if (UserBufAppendMemory(Coder, CODER_USERBUF_SIZE) == NULL) return;
      *(Buf->DataEnd) = (unsigned char)(Bit << 7);
      Buf->BitEnd = 6;
    }
}

/**************************************************
 * 
 * NAME: UserBufGetBits
 *
 *
 */

unsigned long
UserBufGetBits(tCoder* Coder, unsigned char Num)
{
  tBMSUserBuffer* Buf;
  unsigned long Bits = 0;
  unsigned char NOB, RB;
  tBMSLength Length;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufGetBits\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode != bms_ReadMode, Coder, return 0, ec_BUF_OperationWrongMode, NO_ARGS);
  if (Num == 0) return 0;
  USERBUF_ERROR_HANDLER_EXP(Num > 32, Coder, return 0, ec_BUF_TooBigNumberOfBits, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  Length = ((Buf->DataEnd - Buf->DataCurr) << 3) + (Buf->BitCurr - Buf->BitEnd);
  if (Length < Num)
    {
      if (Coder->BMS.AppendFunc)
        Coder->BMS.AppendFunc(Coder, ((Num - Length) >> 3) + (((Num - Length) & 0x7) ? 1 : 0));
      USERBUF_ERROR_HANDLER_EXP(Num > ((Buf->DataEnd - Buf->DataCurr) << 3) + (Buf->BitCurr - Buf->BitEnd),
                                 Coder, return 0, ec_BUF_NoMoreDataForRead, NO_ARGS);
    }
  if (Buf->BitCurr != 7)
    {
      const static unsigned char UserBufBitMask[8] = { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
      char newNum = (char)(Num - Buf->BitCurr - 1);

      Bits = *(Buf->DataCurr) & UserBufBitMask[Buf->BitCurr];
      if (newNum < 0)
        {
          Bits >>= -newNum;
          /* Aka, 04 JAN 2002 */
          /* Buf->BitCurr = (unsigned char)(Buf->BitCurr + newNum);*/
          Buf->BitCurr -= Num;
          /**/
          return Bits;
        }
      Num = (unsigned char)newNum;
      Buf->DataCurr++;
      Buf->BitCurr = 7;
    }
  RB = (unsigned char)(Num & 0x7);
  NOB = (unsigned char)(Num >> 3);
  for (; NOB > 0; NOB--, Buf->DataCurr++)
    {
      Bits <<= 8;
      Bits |= *(Buf->DataCurr);
    }
  if (RB > 0)
    {
      Bits <<= RB;
      Buf->BitCurr = (unsigned char)(7 - RB);
      Bits |= *(Buf->DataCurr) >> (Buf->BitCurr + 1);
    }
  return Bits;
}

/**************************************************
 * 
 * NAME: UserBufPutBits
 *
 *
 */

void
UserBufPutBits(tCoder* Coder, unsigned long Bits, unsigned char Num)
{
  tBMSUserBuffer* Buf;
  unsigned char NOB, RB;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufPutBits\n");
#endif

  USERBUF_ERROR_HANDLER_EXP(Coder->BMS.Mode == bms_NoMode, Coder, return, ec_BUF_OperationWrongMode, NO_ARGS);
  if (Num == 0) return;  
  USERBUF_ERROR_HANDLER_EXP(Num > 32, Coder, return, ec_BUF_TooBigNumberOfBits, NO_ARGS);

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  NOB = (unsigned char)(Num + (7 - Buf->BitEnd));
  RB = (unsigned char)(NOB & 0x7);
  NOB >>= 3;
  if (Buf->DataEnd + NOB + (RB > 0 ? 1 : 0) > Buf->MemEnd)
    if (UserBufAppendMemory(Coder, CODER_USERBUF_SIZE) == NULL) return;
  if (Buf->BitEnd == 7) *(Buf->DataEnd) = 0;
  if (NOB > 0)
    {
      unsigned char *CurrByte;

      Buf->DataEnd += NOB;
      Buf->BitEnd = (unsigned char)(7 - RB);
      if (RB > 0)
        {
          *(Buf->DataEnd) = (unsigned char)(Bits << (8 - RB));
          Bits >>= RB;
        }
      CurrByte = Buf->DataEnd - 1;
      for (; NOB > 1; NOB--, CurrByte--, Bits >>= 8)
        {
          *CurrByte = (unsigned char)Bits;
        }
      *CurrByte |= (unsigned char)Bits;
    }
  else
    {
      *(Buf->DataEnd) |= (unsigned char)(Bits << (Buf->BitEnd + 1 - Num));
      Buf->BitEnd = (unsigned char)(Buf->BitEnd - Num);
    }
}

/**************************************************
 * 
 * NAME: UserBufAlign
 * NOTE: User will have incorrect results if he will use this 
 *       function in AppendFunc
 */

void
UserBufAlign(tCoder* Coder)
{
  tBMSUserBuffer* Buf;

#ifdef CODER_DEBUG_BMS
  fprintf(stdout, "UserBufAlign\n");
#endif

#ifdef CODER_BMS_USERBUF
  Buf = &(Coder->BMS.BMSBuffer);
#else
  Buf = (tBMSUserBuffer*)Coder->BMS.BMSBuffer.Buffer;
#endif

  switch (Coder->BMS.Mode)
    {
    case bms_ReadMode:
      if(Buf->BitCurr != 7)
        {
          Buf->DataCurr++;
          Buf->BitCurr = 7;
        }
      return;
    case bms_WriteMode:
      if (Buf->BitEnd != 7)
        {
          Buf->DataEnd++;
          Buf->BitEnd = 7;          
        }
      return;
    default:
      USERBUF_ERROR_HANDLER(Coder, return, ec_BUF_OperationWrongMode, NO_ARGS);
    }
}

#endif /* CODER_BMS_TINY */

#endif /* CODER_USE_USERBUF */
