/* static char szModuleName__[] = "c:/unix/newer/comp.c"; jmh 29 May 2001*/
/* static char szLastVersion[] = "Version 0.9"; jmh 29 May 2001 */
/* static char szLastSave[] = "1994-11-17*11:15"; jmy 29 May 2001 */

/************************************************************
Abstract
compress.c - Nordrad API pack and unpack routines

(C) Copyright AU-System Communication AB 1994.

Change activity
990125		ARG, Modified entry names to avoid collision w. filep
1994-11-03      Arg  Corrected calls to pckBuff8Copy
1994-11-01      Arg  Always release memory and close files when error
1994-10-02      Arg  Fpopen modified
1994-02-25 1.00 BBN  Initial version by Björn Brodin.

Part of  Nordrad.

Description
************************************************************                */

#ifdef   VMS
#include <types.h>
#include <stdio.h>
#include <string.h>
#include <stat.h>
#include <netdb.h>
#else
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <malloc.h>
#include <netdb.h>
#endif
#include "netdef.h"
#include "api.h"
#include "net.h"
#include "fil.h"
#include "rr_fil.h"
#include "comp.h"
#include "nradutil.h"

static INT32 iTmpRc;    /* used as temp err storage  */
/*----------------------------------------------------------
*       Macros
*---------------------------------------------------------                  */

#define  READ_MODE     0
#define  WRITE_MODE    1
#define  MAX_INDEX     0xFFFFF
#define  LONG_DATA_SIZE 16383

/*----------------------------------------------------------
*       Functions
*---------------------------------------------------------                  */
/*----------------------------------------------------------
*       Structures
*---------------------------------------------------------                  */
/* -------------------------------------------------------                  */
/* ***************<  COMPRESS  >**************************                  */
/* -------------------------------------------------------                  */
/*----------------------------------------------------------
*  call pckCompressNradProd - 
*---------------------------------------------------------                  */

INT32 pckCompressNradProd(char *SourceFileStr,char *DestFileStr)
{
  INT32 iRc = OK;
  Fil_t InFile;
  Fil_t OutFile;
  Bitmap_t BitmapInfoIn;
  Bitmap_t *pBitmapAttrIn;
  Pixel_t PixelInfoIn;
  Pixel_t *pPixelAttrIn;
  INT32 iAttrLen = 0/*,iTest*/;

  /*  iTest = sizeof(Fil_t); */
  /*  iTest = sizeof(InFile); */
  memset(&InFile, 
         0, 
         sizeof(InFile));
  memset(&OutFile, 
         0, 
         sizeof(OutFile));
  pPixelAttrIn = (Pixel_t *)&PixelInfoIn;
  pBitmapAttrIn = (Bitmap_t *)&BitmapInfoIn;
  strcpy(OutFile.Name, 
         DestFileStr);
  strcpy(InFile.Name, 
         SourceFileStr);
  fiOpen(&InFile, 
         InputMode, 
         &iRc);
  if ((InFile.fp == NULL) || (iRc != OK))
    {
      if (iRc == -1)
        return  PGFFILNOTFND;
      else
        if (iRc == -3)
          return  PGFILLFILE;
        else
          return  APIILLPAR;
    } 

  fiReadAttr(&InFile, 
             (Attr_t *)pPixelAttrIn, 
             Pixel_Attr, 
             &iAttrLen, 
             &iRc);
  if (iRc != OK)
    {
      fiClose(&InFile, 
              &iTmpRc);
      return  iRc;
    } 

  if (pPixelAttrIn->Compressed == TRUE)
    {
      fiClose(&InFile, 
              &iTmpRc);
      return  PGFALRCNV;
    } 

  fiCreate(&OutFile, 
           OutFile.Name, 
           ATTR_SIZE, 
           pPixelAttrIn->RowCnt *pPixelAttrIn->ColCnt, 
           &iRc);

  if (iRc == OK)
    {
      fiOpen(&OutFile, 
             UpdateMode, 
             &iRc);
      if ((OutFile.fp == NULL) || (iRc != OK))
        {
          fiClose(&InFile, 
                  &iTmpRc);
          if (iRc == -1)
            return  APIDESTFIL;
          else
            if (iRc == -3)
              return  PGFILLFILE;
            else
              return  APIILLPAR;
        } 

      fiCopy_Header(&InFile, 
                    &OutFile, 
                    &iRc);
      if (iRc == OK)
        {
          if ((iRc = pckCompressData(&InFile, 
                                     &OutFile)) == OK)
            {
              fiReadAttr(&InFile, 
                         (Attr_t *)pBitmapAttrIn, 
                         Bitmap_Attr, 
                         &iAttrLen, 
                         &iRc);
              if (iRc == OK)
                iRc = pckCompressBitmap(&InFile, 
                                        &OutFile);
              if (iRc == -2)           /* NotFound, is OK in this case      */
                iRc = OK;
            } 
        } 
      fiClose(&OutFile, 
              &iTmpRc);
    } 
  else
    {
      if (iRc == -1)
        iRc = APIDESTFIL;
      else
        if (iRc == -3)

          iRc = PGFILLFILE;
        else
          iRc = APIILLPAR;
    } 
  fiClose(&InFile, 
          &iTmpRc);
  return  iRc;
} 


/*----------------------------------------------------------
*  call CompressData - 
*---------------------------------------------------------                  */

INT32 pckCompressData(Fil_t *pInFile,Fil_t *pOutFile)
{
  INT32 iRc = OK;
  PixBuffer_t *pInData;
  PixBuffer_t *pOutData;
  Pixel_t PixelInfoIn;
  Pixel_t PixelInfoOut;
  Pixel_t *pPixelAttrIn;
  Pixel_t *pPixelAttrOut;
  INT32 iNoBytes;
  INT32 iAttrLen = 0;
  size_t mallocSize;

  pPixelAttrIn = (Pixel_t *)&PixelInfoIn;
  pPixelAttrOut = (Pixel_t *)&PixelInfoOut;
  fiOpen(pInFile, 
         InputMode, 
         &iRc);
  if ((pInFile->fp == NULL) || (iRc != OK))
    {
      if (iRc == -1)
        return  PGFFILNOTFND;
      else
        if (iRc == -3)
          return  PGFILLFILE;
        else
          return  APIILLPAR;
    } 

  fiOpen(pOutFile, 
         UpdateMode, 
         &iRc);
  if ((pOutFile->fp == NULL) || (iRc != OK))
    return  APIDESTFIL;

  fiReadAttr(pInFile, 
             (Attr_t *)pPixelAttrIn, 
             Pixel_Attr, 
             &iAttrLen, 
             &iRc);
  if (iRc == OK)
    {
      mallocSize = (size_t)(pPixelAttrIn->StorePixels+sizeof(PixBuffer_t));
      pInData = (PixBuffer_t *)malloc(mallocSize);
      if (pInData == NULL)
        return  APINOMEM;

      pInData->Compressed = FALSE;
      pInData->iMaxSize = pPixelAttrIn->StorePixels+sizeof(PixBuffer_t);
      pInData->Data.iMaxSize = pPixelAttrIn->StorePixels;
      mallocSize = (size_t)((pPixelAttrIn->StorePixels *2)+sizeof
         (PixBuffer_t));
      pOutData = (PixBuffer_t *)malloc(mallocSize);
      if (pOutData == NULL)
        {
          free(pInData);
          return  APINOMEM;
        } 

      pOutData->Compressed = TRUE;
      pOutData->iMaxSize = ((pPixelAttrIn->StorePixels *2)+sizeof
         (PixBuffer_t));
      pOutData->Data.iMaxSize = (pPixelAttrIn->StorePixels *2);
      fseek(pInFile->fp, 
            pPixelAttrIn->FileOffset-1, 
            SEEK_SET);
      iNoBytes = fread(&pInData->Data.ByteData[0], 
                       sizeof(char), 
                       pPixelAttrIn->StorePixels, 
                       pInFile->fp);
      if (iNoBytes != pPixelAttrIn->StorePixels)
        {
          free(pInData);
          free(pOutData);
          return  BUFNRDERROR;
        } 

      if ((iRc = pckPixReset(READ_MODE, 
                             pInData)) == OK)
        if ((iRc = pckPixReset(WRITE_MODE, 
                               pOutData)) == OK)
          iRc = pckPixCopy(pInData, 
                           pOutData, 
                           pPixelAttrIn->StorePixels);
      if (iRc == OK)
        {
          fiOpen(pOutFile, 
                 UpdateMode, 
                 &iRc);
          if ((pOutFile->fp == NULL) || (iRc != OK))
            {
              free(pInData);
              free(pOutData);
              return  APIDESTFIL;
            } 

          fiAllocate(pOutFile, 
                     pOutData->Data.iLen, 
                     &pPixelAttrOut->FileOffset, 
                     &iRc);
          if (iRc == OK)
            {
              pPixelAttrOut->RowCnt = pPixelAttrIn->RowCnt;
              pPixelAttrOut->ColCnt = pPixelAttrIn->ColCnt;
              pPixelAttrOut->StorePixels = pOutData->Data.iLen;
              pPixelAttrOut->FileOffset += 1;
              pPixelAttrOut->StoreBits = 8;
              pPixelAttrOut->StoreMax = 255;
              pPixelAttrOut->Compressed = TRUE;
              iAttrLen = sizeof(Pixel_t);
              fiWriteAttr(pOutFile, 
                          (Attr_t *)pPixelAttrOut, 
                          Pixel_Attr, 
                          iAttrLen, 
                          &iRc);
              if (iRc != OK)
                {
                  free(pInData);
                  free(pOutData);
                  return  BUFNRDERROR;
                } 

              iNoBytes = fseek(pOutFile->fp, 
                               pPixelAttrOut->FileOffset-1, 
                               SEEK_SET);
              iNoBytes = fwrite(&pOutData->Data.ByteData[0], 
                                sizeof(char), 
                                pPixelAttrOut->StorePixels, 
                                pOutFile->fp);
              if (iNoBytes != pPixelAttrOut->StorePixels)
                {
                  free(pInData);
                  free(pOutData);
                  return  BUFNRDERROR;
                } 
            } 
        } 
    } 

  free(pInData);
  free(pOutData);
  return  iRc;
} 


/*----------------------------------------------------------
*  call CompressBitmap - 
*---------------------------------------------------------                  */

INT32 pckCompressBitmap(Fil_t *pInFile,Fil_t *pOutFile)
{
  INT32 iRc = OK;
  INT32 iDataSize = 0;
  INT32 iBytesWri = 0;
  char *pInData;
  char *pOutData;
  Bitmap_t BitmapInfoIn;
  Pixel_t PixelInfoIn;
  Bitmap_t BitmapInfoOut;
  Pixel_t *pPixelAttrIn;
  Bitmap_t *pBitmapAttrIn;
  Bitmap_t *pBitmapAttrOut;
  INT32 iAttrLen = 0;
  int iNoBytes;

  pPixelAttrIn = (Pixel_t *)&PixelInfoIn;
  pBitmapAttrIn = (Bitmap_t *)&BitmapInfoIn;
  pBitmapAttrOut = (Bitmap_t *)&BitmapInfoOut;
  fiOpen(pInFile, 
         InputMode, 
         &iRc);
  if ((pInFile->fp == NULL) || (iRc != OK))
    {
      if (iRc == -1)
        return  PGFFILNOTFND;
      else
        if (iRc == -3)
          return  PGFILLFILE;
        else
          return  APIILLPAR;
    } 

  fiReadAttr(pInFile, 
             (Attr_t *)pBitmapAttrIn, 
             Bitmap_Attr, 
             &iAttrLen, 
             &iRc);
  if (iRc == OK)
    fiReadAttr(pInFile, 
               (Attr_t *)pPixelAttrIn, 
               Pixel_Attr, 
               &iAttrLen, 
               &iRc);
  pInData = malloc(pBitmapAttrIn->StorePixels);
  if (pInData == NULL)
    {
      fiClose(pInFile, 
              &iTmpRc);
      return  APINOMEM;
    } 

  iDataSize = pPixelAttrIn->RowCnt *pPixelAttrIn->ColCnt;
  pOutData = malloc(iDataSize+8);
  if (pOutData == NULL)
    {
      free(pInData);
      fiClose(pInFile, 
              &iTmpRc);
      return  APINOMEM;
    } 

  fseek(pInFile->fp, 
        pBitmapAttrIn->FileOffset-1, 
        SEEK_SET);
  iNoBytes = fread(pInData, 
                   sizeof(char), 
                   pBitmapAttrIn->StorePixels, 
                   pInFile->fp);
  if (iNoBytes != pBitmapAttrIn->StorePixels)
    {
      free(pInData);
      free(pOutData);
      fiClose(pInFile, 
              &iTmpRc);
      return  BUFNRDERROR;
    } 

  if ((iRc = pckRleCompressData(pInData, 
                                pBitmapAttrIn->StorePixels, 
                                pOutData, 
                                &pBitmapAttrOut->StorePixels)) != OK)
    {
      free(pInData);
      free(pOutData);
      fiClose(pInFile, 
              &iTmpRc);
      return  iRc;
    } 

  pBitmapAttrOut->Compressed = TRUE;
  fiAllocate(pOutFile, 
             pBitmapAttrOut->StorePixels, 
             &pBitmapAttrOut->FileOffset, 
             &iRc);
  if (iRc == OK)
    {
      pBitmapAttrOut->FileOffset += 1;
      iAttrLen = sizeof(Bitmap_t);
      fiWriteAttr(pOutFile, 
                  (Attr_t *)pBitmapAttrOut, 
                  Bitmap_Attr, 
                  iAttrLen, 
                  &iRc);
      if (iRc != OK)
        {
          free(pInData);
          free(pOutData);
          return  BUFNRDERROR;
        } 

      fseek(pOutFile->fp, 
            pBitmapAttrOut->FileOffset-1, 
            SEEK_SET);
      iBytesWri = fwrite(pOutData, 
                         sizeof(char), 
                         pBitmapAttrOut->StorePixels, 
                         pOutFile->fp);
      if (iBytesWri != pBitmapAttrOut->StorePixels)
        iRc = NOK;
    } 
  free(pInData);
  free(pOutData);
  return  iRc;
} 

INT32 pckPixReset(INT32 iMode,PixBuffer_t *pBuff)
{
  if (iMode == READ_MODE)
    {
      pBuff->Data.iLen = pBuff->Data.iMaxSize;
      pBuff->Data.iPos = 0;
      if (pBuff->Compressed == TRUE)
        {
          pBuff->Sequence.iStart = 0;
          pBuff->Sequence.iPackType = SHORT_DIFF;
          pBuff->Sequence.iDataLen = 0;
          pBuff->Sequence.iDataPos = 0;
          pckPixGetSequence(pBuff);
        } 
    } 
  else
    {
      pBuff->Data.iLen = 0;
      pBuff->Data.iPos = 0;
    } 
  return  OK;
} 

INT32 pckPixSkip(PixBuffer_t *pBuffer,INT32 iCount)
{
  INT32 iRc = OK;
  INT32 iMovedItems = 0;
  INT32 iThisMove = 0;

  if (pBuffer->Compressed)
    {
      while ((iMovedItems < iCount) && (iRc == OK))
        {
          if (pBuffer->Sequence.iDataPos > pBuffer->Sequence.iDataLen)
            iRc = pckPixGetSequence(pBuffer);
          iThisMove = pBuffer->Sequence.iDataLen-pBuffer->Sequence.iDataPos+
             1;
          if (iThisMove > iCount-iMovedItems)
            iThisMove = iCount-iMovedItems;
          iMovedItems += iThisMove;
          pBuffer->Sequence.iDataPos = pBuffer->Sequence.iDataPos+iThisMove;
          switch (pBuffer->Sequence.iPackType)
            {
              case  SHORT_DIFF :
              case  LONG_DIFF :
                pBuffer->Data.iPos += iThisMove;
                break;
              case  SHORT_SAME :
              case  LONG_SAME :

                /************************************************************/
                /* Don't move the pointer. We're processing packed data     */
                /************************************************************/

                break;
            } 
        } 
    } 
  else                                 /* none compressed                   */
    {
      if (pBuffer->Data.iPos > pBuffer->Data.iLen-iCount)
        {
          pBuffer->Data.iPos = pBuffer->Data.iLen;
          return  iRc;
        } 
      else

        pBuffer->Data.iPos += iCount;
    } 
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckPixGetSequence - 
*---------------------------------------------------------                  */

INT32 pckPixGetSequence(PixBuffer_t *pBuffer)
{
  struct LongHeaderStruc LongHeader;
  struct ShortHeaderStruc ShortHeader;
  unsigned char bDataByte;
  INT32 iRc = OK;
  INT32 iTmp = 0;

  *((char *)&ShortHeader) = 0;

  /**************************************************************************/
  /* skip ahead of data from the previous sequence                          */
  /**************************************************************************/

  if ((pBuffer->Sequence.iPackType == SHORT_SAME) || 
     (pBuffer->Sequence.iPackType == LONG_SAME))
    Buff8Get(&pBuffer->Data, 
             (char *)&bDataByte);
  while (((ShortHeader.HeaderType != SHORT_SAME) || (ShortHeader.Len > 0)) 
     && (iRc == OK))                   /* NOT EOD                           */
    {
      iRc = Buff8Get(&pBuffer->Data, 
                     (char *)&bDataByte);
      ShortHeader.HeaderType = bDataByte&0x03;/* get type from low nibble   */
      ShortHeader.Len = bDataByte>>0x02;/* get len from rest of nibble      */

/*    *((char *)&ShortHeader) = bDataByte;                                  */

      if ((ShortHeader.HeaderType != SHORT_SAME) || (ShortHeader.Len > 0))
        {
          if (*((char *)&ShortHeader) != 0 )
            {
              pBuffer->Sequence.iStart = pBuffer->Data.iPos-1;
              pBuffer->Sequence.iPackType = ShortHeader.HeaderType;
              pBuffer->Sequence.iDataPos = 0;
              switch (ShortHeader.HeaderType)
                {
                  case  SHORT_DIFF :
                  case  SHORT_SAME :
                    pBuffer->Sequence.iDataLen = ShortHeader.Len;
                    break;
                  case  LONG_DIFF :
                  case  LONG_SAME :
                    LongHeader.HeaderType = bDataByte&0x03;/* get type from 
                                          low nibble                        */
                    LongHeader.Len = bDataByte>>0x02;/* get len from rest of
                                          nibble                            */
                    iRc = Buff8Get(&pBuffer->Data, 
                                   (char *)&bDataByte);
                    iTmp = bDataByte;
                    LongHeader.Len += iTmp<<6;/* get rest of lenght         */

                    /********************************************************/
                    /* Mask.Low = bDataByte; iRc =                          */
                    /* Buff8Get(&pBuffer->Data,&Mask.High);                 */
                    /* memcpy(&LongHeader,&Mask,sizeof(LongHeader));        */
                    /********************************************************/

                    pBuffer->Sequence.iDataLen = LongHeader.Len;
                    break;
                } 
              return  OK;
            } 
        } 
      else
        return  EOD;
    } 
  return  NOK;
} 


/*----------------------------------------------------------
*  call pckPixCopy - 
*---------------------------------------------------------                  */

INT32 pckPixCopy(PixBuffer_t *pFrom,PixBuffer_t *pTo,INT32 iCount)
{
  INT32 iRc = OK;

  if ((pFrom->Compressed == TRUE) && (pTo->Compressed == TRUE))
    iRc = pckComprToCompr(pFrom, 
                          pTo, 
                          iCount);
  else
    if ((pFrom->Compressed == TRUE) && (pTo->Compressed == FALSE))

      iRc = pckComprToExp(pFrom, 
                          pTo, 
                          iCount);
    else
      if ((pFrom->Compressed == FALSE) && (pTo->Compressed == TRUE))

        iRc = pckExpToCompr(pFrom, 
                            pTo);
      else
        iRc = pckExpToExp(pFrom, 
                          pTo, 
                          iCount);
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckComprToCompr - 
*---------------------------------------------------------                  */

INT32 pckComprToCompr(PixBuffer_t *pFrom,PixBuffer_t *pTo,INT32 iCount)
{
  INT32 iRc = OK;
  INT32 iMovedItems = 0;
  INT32 iMiddlePartStart = 0;
  INT32 iCopyBytes = 0;
  INT32 iSaveLen = 0;
  INT32 iSavePos = 0;

  /**************************************************************************/
  /* First part : process the current sequence in the pixel data            */
  /**************************************************************************/

  iMovedItems = pFrom->Sequence.iDataLen-pFrom->Sequence.iDataPos+1;
  if (iMovedItems > iCount)
    iMovedItems = iCount;
  pckPixComprToComprSeq(pFrom, 
                        pTo, 
                        iCount);
  pFrom->Sequence.iDataPos = pFrom->Sequence.iDataPos+iMovedItems;
  if (iMovedItems == iCount)
    return  iRc;

  /**************************************************************************/
  /* We're done with the current sequence. Position at the next one. and    */
  /* process the middle part                                                */
  /**************************************************************************/

  pckPixGetSequence(pFrom);
  iMiddlePartStart = pFrom->Sequence.iStart;
  pckPixSkip(pFrom, 
             (iCount-iMovedItems));
  iCopyBytes = pFrom->Sequence.iStart-iMiddlePartStart;
  if (iCopyBytes > 0)
    {
      iSaveLen = pFrom->Data.iLen;
      iSavePos = pFrom->Data.iPos;
      pFrom->Data.iPos = iMiddlePartStart-1;
      pckBuff8Copy((struct Buff8Struc *)&pFrom->Data, 
                   (struct Buff8Struc *)&pTo->Data, 
                   iCopyBytes);
      pFrom->Data.iLen = iSaveLen;
      pFrom->Data.iPos = iSavePos;
    } 

  /**************************************************************************/
  /* Last part : Do last sequence                                           */
  /**************************************************************************/

  iMovedItems = iCount+

  /**************************************************************************/
  /* - iCopyItems seems unneccesary                                         */
  /**************************************************************************/

     pFrom->Sequence.iDataPos-1;
  if (iMovedItems == iCount)
    return  iRc;

  pckPixGetSequence(pFrom);
  pckPixComprToComprSeq(pFrom, 
                        pTo, 
                        (iCount-iMovedItems));
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckPixComprToComprSeq - Copies a compressed sequence
*                               from one buffer to another.
*                               The destination buffer might
*                               be either compressed or not.
*---------------------------------------------------------                  */

INT32 pckPixComprToComprSeq(PixBuffer_t *pFrom,PixBuffer_t *pTo,INT32 iCount
)
{
  INT32 iRc = OK;
  struct LongHeaderStruc LongHeader;
  struct ShortHeaderStruc ShortHeader;
  struct MaskStruc Mask;

  if (iCount > pFrom->Sequence.iDataLen-pFrom->Sequence.iDataPos+1)
    return  iRc;

  switch (pFrom->Sequence.iPackType)
    {
      case  SHORT_DIFF :
        ShortHeader.HeaderType = SHORT_DIFF;
        ShortHeader.Len = iCount;
        pckBuff8Put((struct Buff8Struc *)&pTo->Data, 
                    (char *)&ShortHeader, 
                    (INT32)sizeof(ShortHeader));
        pckBuff8Copy(&pFrom->Data, 
                     &pTo->Data, 
                     iCount);
        break;
      case  SHORT_SAME :
        ShortHeader.HeaderType = SHORT_SAME;
        ShortHeader.Len = iCount;
        pckBuff8Put((struct Buff8Struc *)&pTo->Data, 
                    (char *)&ShortHeader, 
                    (INT32)sizeof(ShortHeader));
        pckBuff8Put((struct Buff8Struc *)&pTo->Data, 
                    (char *)&pFrom->Data.ByteData[pFrom->Data.iPos], 
                    (INT32)sizeof(unsigned char));
        break;
      case  LONG_DIFF :
        LongHeader.HeaderType = LONG_DIFF;
        LongHeader.Len = iCount;
        Mask.Low = LongHeader.Len&0X3F;
        Mask.Low = (Mask.Low<<2)+LongHeader.HeaderType;
        pckBuff8Put(&pTo->Data, 
                    (char *)&Mask.Low, 
                    sizeof(Mask.Low));
        Mask.High = LongHeader.Len>>6;
        pckBuff8Put(&pTo->Data, 
                    (char *)&Mask.High, 
                    sizeof(Mask.High));
        pckBuff8Copy(&pFrom->Data, 
                     &pTo->Data, 
                     iCount);
        break;
      case  LONG_SAME :
        LongHeader.HeaderType = LONG_SAME;
        LongHeader.Len = iCount;
        Mask.Low = LongHeader.Len&0X3F;
        Mask.Low = (Mask.Low<<2)+LongHeader.HeaderType;
        pckBuff8Put(&pTo->Data, 
                    (char *)&Mask.Low, 
                    sizeof(Mask.Low));
        Mask.High = LongHeader.Len>>6;
        pckBuff8Put(&pTo->Data, 
                    (char *)&Mask.High, 
                    sizeof(Mask.High));
        pckBuff8Put(&pTo->Data, 
                    &pFrom->Data.ByteData[pFrom->Data.iPos], 
                    sizeof(unsigned char));
        break;
      default  :
        iRc = NOK;
    } 
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckComprToExp - 
*---------------------------------------------------------                  */

INT32 pckComprToExp(PixBuffer_t *pFrom,PixBuffer_t *pTo,INT32 iCount)
{
  INT32 iRc = OK;
  INT32 iMovedItems = 0;
  INT32 iMiddlePartStart;
  INT32 iSaveLen = 0;
  INT32 iSavePos = 0;
  INT32 iSaveSeqPos = 0;
  INT32 iToBefore = 0;

  iToBefore = pTo->Data.iPos;

  /**************************************************************************/
  /* First part : process the current sequence in the pixel data            */
  /**************************************************************************/

  iMovedItems = pFrom->Sequence.iDataLen-pFrom->Sequence.iDataPos;
  if (iMovedItems > iCount)
    iMovedItems = iCount;
  if ((iRc = pckPixComprToExpSeq(pFrom, 
                                 pTo, 
                                 iMovedItems)) != OK)
    return  iRc;

  pFrom->Sequence.iDataPos = pFrom->Sequence.iDataPos+iMovedItems;
  if (iMovedItems == iCount)
    return  iRc;

  /**************************************************************************/
  /* We're done with the current sequence. Position at the next one. and    */
  /* process the middle part                                                */
  /**************************************************************************/

  if ((iRc = pckPixGetSequence(pFrom)) != OK)
    return  iRc;

  iMiddlePartStart = pFrom->Sequence.iStart;
  pckPixSkip(pFrom, 
             (iCount-iMovedItems));
  if (pFrom->Sequence.iStart-iMiddlePartStart > 0)
    {
      iSaveLen = pFrom->Data.iLen;
      iSavePos = pFrom->Data.iPos;
      pFrom->Data.iPos = iMiddlePartStart;
      pFrom->Data.iLen = pFrom->Sequence.iStart-1;
      pckBuff8ExpandData(&pFrom->Data, 
                         &pTo->Data, 
                         pFrom->iMaxSize);
      pFrom->Data.iLen = iSaveLen;
      pFrom->Data.iPos = iSavePos;
    } 

  /**************************************************************************/
  /* Last part : Do last sequence                                           */
  /**************************************************************************/

  iMovedItems = pTo->Data.iPos-iToBefore;
  if (iMovedItems == iCount)
    return  iRc;

  iSaveSeqPos = pFrom->Sequence.iDataPos;
  iSavePos = pFrom->Data.iPos;

  /**************************************************************************/
  /* Reset sequence pointer. We're going to copy from the beginning of the  */
  /* sequence to the last in the sequence requested for copying             */
  /**************************************************************************/

  pFrom->Sequence.iDataPos = 0;

  /**************************************************************************/
  /* Set buffer pointer to the first item in the sequence                   */
  /**************************************************************************/

  switch (pFrom->Sequence.iPackType)
    {
      case  SHORT_SAME :
      case  SHORT_DIFF :
        pFrom->Data.iPos = pFrom->Sequence.iStart+1;
        break;
      case  LONG_SAME :
      case  LONG_DIFF :
        pFrom->Data.iPos = pFrom->Sequence.iStart+2;
        break;
    } 
  pckPixComprToExpSeq(pFrom, 
                      pTo, 
                      (iCount-iMovedItems));
  pFrom->Sequence.iDataPos = iSaveSeqPos;
  pFrom->Data.iPos = iSavePos;
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckPixComprToExpSeq - 
*---------------------------------------------------------                  */

INT32 pckPixComprToExpSeq(PixBuffer_t *pFrom,PixBuffer_t *pTo,INT32 iCount)
{
  INT32 iRc = OK;

  if (iCount > (pFrom->Sequence.iDataLen-pFrom->Sequence.iDataPos+1))
    return  iRc;

  switch (pFrom->Sequence.iPackType)
    {
      case  SHORT_DIFF :
      case  LONG_DIFF :
        if ((iRc = pckBuff8Copy(&pFrom->Data, 
                                &pTo->Data, 
                                iCount)) != OK)
          return  iRc;
        break;
      case  LONG_SAME :

      case  SHORT_SAME :
        if ((iRc = pckBuff8Fill(&pTo->Data, 
                                iCount, 
                                pFrom->Data.ByteData[pFrom->Data.iPos])) != 
                                   OK)
          return  iRc;
        break;
      default  :
        return  NOK;
    } 
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckExpToCompr - 
*---------------------------------------------------------                  */

INT32 pckExpToCompr(PixBuffer_t *pFrom,PixBuffer_t *pTo)
{
  INT32 iRc = OK;

  iRc = Buff8CompressData(&pFrom->Data, 
                          &pTo->Data, 
                          pFrom->Data.iMaxSize);
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckExpToExp - Copies expanded buffer to an expanded
*                     buffer.
*---------------------------------------------------------                  */

INT32 pckExpToExp(PixBuffer_t *pFrom,PixBuffer_t *pTo,INT32 iCount)
{
  INT32 iRc = OK;

  iRc = pckBuff8Copy(&pFrom->Data, 
                     &pTo->Data, 
                     iCount);
  return  iRc;
} 


/*----------------------------------------------------------
*  call Buff8CompressData - 
*---------------------------------------------------------                  */

INT32 Buff8CompressData(struct Buff8Struc *pInBuffer,struct Buff8Struc 
                        *pOutBuffer,INT32 iSourceDataSize)
{
  INT32 iRc = OK;
  INT32 iCompressedLen = 0;

  iRc = pckRleCompressData(&pInBuffer->ByteData[pInBuffer->iPos], 
                           iSourceDataSize, 

                           /*************************************************/
                           /* (pInBuffer->iLen-pInBuffer->iPos)             */
                           /*************************************************/

                           &pOutBuffer->ByteData[pOutBuffer->iPos], 
                           &iCompressedLen);
  pInBuffer->iPos = pInBuffer->iLen+1;
  pOutBuffer->iPos += iCompressedLen;
  pOutBuffer->iLen += iCompressedLen;
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckBuff8Fill - 
*---------------------------------------------------------                  */

INT32 pckBuff8Fill(struct Buff8Struc *pBuffer,INT32 iCount,char Item)
{
  INT32 iRc = OK;
  INT32 iLocCount = 0;
  INT32 wStoreCount = 0;

  iLocCount = iCount;
  if (iCount > (pBuffer->iMaxSize-pBuffer->iPos+1))
    iRc = NOK;
  else
    {
      if (iCount > 0)
        {
          while (iLocCount > 0)
            {
              if (iLocCount > MAX_INDEX)
                wStoreCount = MAX_INDEX;
              else
                wStoreCount = iLocCount;
              iLocCount -= wStoreCount;
              memset(&pBuffer->ByteData[pBuffer->iPos], 
                     Item, 
                     wStoreCount);
              pBuffer->iPos += wStoreCount;
              pBuffer->iLen += wStoreCount;
            } 
        } 
    } 
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckBuff8Copy - 
*---------------------------------------------------------                  */

INT32 pckBuff8Copy(struct Buff8Struc *pFrom,struct Buff8Struc *pTo,INT32 
                   iCount)
{
  INT32 iLocCnt = 0;
  INT32 iStoreCnt = 0;

  if (iCount > (pFrom->iLen-pFrom->iPos+1))
    return  NOK;

  if (iCount > (pTo->iMaxSize-pTo->iPos+1))
    return  NOK;

  iLocCnt = iCount;
  while (iLocCnt > 0)
    {
      if (iLocCnt > MAX_INDEX)
        iStoreCnt = MAX_INDEX;
      else
        iStoreCnt = iLocCnt;
      iLocCnt = iLocCnt-iStoreCnt;
      memcpy(pTo->ByteData, 
             pFrom->ByteData, 
             iStoreCnt);
      pTo->iPos += iStoreCnt;
      pTo->iLen += iStoreCnt;
      pFrom->iPos += iStoreCnt;
    } 
  return  OK;
} 


/*----------------------------------------------------------
*  call pckBuff8Put - 
*---------------------------------------------------------                  */

INT32 pckBuff8Put(struct Buff8Struc *pBuffer,char *pItem,INT32 iItemSize)
{
  INT32 iRc = OK;

  if (pBuffer->iLen == pBuffer->iMaxSize)
    iRc = NOK;
  else
    {
      memcpy((char *)((int)pBuffer->ByteData+pBuffer->iPos), 
             pItem, 
             iItemSize);
      pBuffer->iPos += iItemSize;
      pBuffer->iLen += iItemSize;
    } 
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckBuff8ExpandData - 
*---------------------------------------------------------                  */

INT32 pckBuff8ExpandData(struct Buff8Struc *pInBuffer,struct Buff8Struc 
                         *pOutBuffer,INT32 iSourceDataSize)
{
  INT32 iRc = OK;
  INT32 iExpandLen = 0;

  iRc = pckRleExpandData(&pInBuffer->ByteData[pInBuffer->iPos], 
                         iSourceDataSize, 
                         &pOutBuffer->ByteData[pOutBuffer->iPos], 
                         &iExpandLen);
  pInBuffer->iPos = pOutBuffer->iLen+1;
  pOutBuffer->iPos += iExpandLen;
  pOutBuffer->iLen += iExpandLen;
  return  iRc;
} 


/*----------------------------------------------------------
*  call PckRleCompressData - 
*---------------------------------------------------------                  */

INT32 pckRleCompressData(char *InData,INT32 iInSize,char *OutData,INT32 
                         *iOutSize)
{
  INT32 iRc = OK;
  INT32 iPos = 0;
  INT32 iOutPos = 0;
  INT32 iSequence = 0;

  while (iPos < iInSize)
    {
      iSequence = pckCountEqual(InData, 
                                iPos, 
                                iInSize);
      if (iSequence >= 2)
        {
          if (iSequence > LONG_DATA_SIZE)
            iSequence = LONG_DATA_SIZE;
          pckSameByteOutput(OutData, 
                            &iOutPos, 
                            iSequence, 
                            InData[iPos]);
          iPos += iSequence;
        } 
      if (iPos < iInSize)
        {
          iSequence = pckCountDifferent(InData, 
                                        iPos, 
                                        iInSize);
          if (iSequence > 0)
            {
              if (iSequence > LONG_DATA_SIZE)
                iSequence = LONG_DATA_SIZE;
              pckDiffByteOutput(InData, 
                                &iPos, 
                                OutData, 
                                &iOutPos, 
                                iSequence);
            } 
        } 
    } 
  OutData[iOutPos] = EOD;
  *iOutSize = iOutPos+1;
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckCountEqual  - Find a sequence of different bytes
*                     in the data
*---------------------------------------------------------                  */

INT32 pckCountEqual(char *InData,INT32 iPos,INT32 iMaxPos)
{
  INT32 iLocPos = 0;
  char cFirstValue;
  char cSecondValue;
  INT32 iSameCount = 1;

  iLocPos = iPos;
  cFirstValue = InData[iLocPos];
  iLocPos++;
  while (iLocPos <= iMaxPos)
    {
      cSecondValue = InData[iLocPos];
      iLocPos++;
      if (cFirstValue != cSecondValue)
        return  iSameCount;

      iSameCount++;
    } 
  return  iSameCount;
} 


/*----------------------------------------------------------
*  call pckCountDifferent - Find a sequence of different bytes
*                        in the data
*---------------------------------------------------------                  */

INT32 pckCountDifferent(char *InData,INT32 iPos,INT32 iMaxSize)
{
  INT32 iLocPos = 0;
  char cFirstValue;
  char cSecondValue;
  INT32 iSameCount = 0;

  iLocPos = iPos;
  cFirstValue = InData[iLocPos];
  iLocPos++;
  while (iLocPos < iMaxSize)
    {
      cSecondValue = InData[iLocPos];
      iLocPos++;
      if (cFirstValue == cSecondValue)
        {
          iSameCount = 2;
          return ((iLocPos-iSameCount)-iPos);
        } 
      cFirstValue = cSecondValue;
    } 
  return ((iLocPos-iSameCount)-iPos);
} 


/*----------------------------------------------------------
*  call pckDiffByteOutput - Outputs a sequence of different bytes
*                        from the input buffer to the output
*                        buffer.
*                 NOTE:  If the requested data could not fit
*                        into the output buffer as much as
*                        possible wil be stored there.
*                 NOTE   The position pointers to the two data
*                        buffers are updated herein.                          
*---------------------------------------------------------                  */

void pckDiffByteOutput(char *pFrom,INT32 *iFromPos,char *pTo,INT32 *iToPos,
                       INT32 iCount)
{
  struct LongHeaderStruc LongHeader;
  struct MaskStruc Mask;
  unsigned char bOutByte;

  if (iCount < 63)
    {
      bOutByte = (iCount<<2)+SHORT_DIFF;
      pTo[*iToPos] = bOutByte;
      (*iToPos)++;
    } 
  else
    {
      LongHeader.Len = iCount;
      LongHeader.HeaderType = LONG_DIFF;
      Mask.Low = LongHeader.Len&0X3F;
      Mask.Low = (Mask.Low<<2)+LongHeader.HeaderType;
      pTo[*iToPos] = Mask.Low;
      (*iToPos)++;
      Mask.High = LongHeader.Len>>6;
      pTo[*iToPos] = Mask.High;
      (*iToPos)++;
    } 
  memcpy(&pTo[*iToPos], 
         &pFrom[*iFromPos], 
         iCount);
  *iFromPos += iCount;
  *iToPos += iCount;
} 


/*----------------------------------------------------------
*  call pckSameByteOutput - Writes compressed data to the
*                        compressed buffer.
*---------------------------------------------------------                  */

void pckSameByteOutput(char *pTo,INT32 *iToPos,INT32 iCount,unsigned char 
                       bValue)
{
  struct LongHeaderStruc LongHeader;
  struct MaskStruc Mask;
  unsigned char bOutByte;

  if (iCount <= 63)
    {
      bOutByte = (iCount<<2)+SHORT_SAME;
      pTo[*iToPos] = bOutByte;
      (*iToPos)++;
      pTo[*iToPos] = bValue;
      (*iToPos)++;
    } 
  else
    {
      LongHeader.Len = iCount;
      LongHeader.HeaderType = LONG_SAME;
      Mask.Low = LongHeader.Len&0X3F;
      Mask.Low = (Mask.Low<<2)+LongHeader.HeaderType;
      Mask.High = LongHeader.Len>>6;
      pTo[*iToPos] = Mask.Low;
      (*iToPos)++;
      pTo[*iToPos] = Mask.High;
      (*iToPos)++;
      pTo[*iToPos] = bValue;
      (*iToPos)++;
    } 
} 

INT32 Buff8Get(struct Buff8Struc *pBuffer,char *pItem)
{
  if (pBuffer->iPos > pBuffer->iLen)
    return  NOK;

  *pItem = pBuffer->ByteData[pBuffer->iPos];
  pBuffer->iPos++;
  return  OK;
} 


/* -------------------------------------------------------                  */
/* *****************<  DECOMPRESS  >**********************                  */
/* -------------------------------------------------------                  */
/*----------------------------------------------------------
*  call pckExpandDataNradProd  - Expands the data from the given
*                     compressed data string.
*---------------------------------------------------------                  */

INT32 pckExpandNradProd(char *pSourceFileStr,char *pDestFileStr)
{
  Fil_t InFile;
  Fil_t OutFile;
  Bitmap_t BitmapInfoIn;
  Bitmap_t *pBitmapAttrIn;
  Pixel_t PixelInfoIn;
  Pixel_t *pPixelAttrIn;
  INT32 iRc = OK;
  INT32 iAttrLen = 0;

  memset(&InFile, 
         0, 
         sizeof(InFile));
  memset(&OutFile, 
         0, 
         sizeof(OutFile));
  memset(&BitmapInfoIn, 
         0, 
         sizeof(BitmapInfoIn));
  pPixelAttrIn = (Pixel_t *)&PixelInfoIn;
  pBitmapAttrIn = (Bitmap_t *)&BitmapInfoIn;
  strcpy(OutFile.Name, 
         pDestFileStr);
  strcpy(InFile.Name, 
         pSourceFileStr);
  fiOpen(&InFile, 
         InputMode, 
         &iRc);
  if ((InFile.fp == NULL) || (iRc != OK))
    {
      if (iRc == -1)
        return  PGFFILNOTFND;
      else
        if (iRc == -3)
          return  PGFILLFILE;
        else
          return  APIILLPAR;
    } 

  fiReadAttr(&InFile, 
             (Attr_t *)pPixelAttrIn, 
             Pixel_Attr, 
             &iAttrLen, 
             &iRc);
  if (iRc != OK)
    return  iRc;

  if (pPixelAttrIn->Compressed == FALSE)
    {
      fiClose(&InFile, 
              &iTmpRc);
      return  PGFALRCNV;
    } 

  fiCreate(&OutFile, 
           OutFile.Name, 
           ATTR_SIZE, 
           pPixelAttrIn->RowCnt *pPixelAttrIn->ColCnt, 
           &iRc);

  if (iRc == OK)
    {
      fiOpen(&OutFile, 
             UpdateMode, 
             &iRc);
      if ((OutFile.fp == NULL) || (iRc != OK))
        return  APIDESTFIL;

      fiCopy_Header(&InFile, 
                    &OutFile, 
                    &iRc);
      if (iRc == OK)
        {
          if ((iRc = pckExpandData(&InFile, 
                                   &OutFile)) == OK)
            {
              fiReadAttr(&InFile, 
                         (Attr_t *)pBitmapAttrIn, 
                         Bitmap_Attr, 
                         &iAttrLen, 
                         &iRc);
              if (iRc == OK)
                iRc = pckExpandBitmap(&InFile, 
                                      &OutFile);
              else
                if (iRc == -2)

                  iRc = OK;            /* bitmap missing but we can accesp  
                                          that                              */
            } 
        } 
      fiClose(&OutFile, 
              &iTmpRc);
    } 
  fiClose(&InFile, 
          &iTmpRc);
  return  iRc;
} 


/*----------------------------------------------------------
*  call pckExpandData  - Expands the data from the given
*                     compressed data string.
*---------------------------------------------------------                  */

INT32 pckExpandData(Fil_t *pInFile,Fil_t *pOutFile)
{
  INT32 iRc = OK;
  PixBuffer_t *pInData;
  PixBuffer_t *pOutData;
  Pixel_t PixelInfoIn;
  Pixel_t PixelInfoOut;
  Pixel_t *pPixelAttrIn;
  Pixel_t *pPixelAttrOut;
  INT32 iAttrLen = 0;
  INT32 iNoBytes = 0;

  memset(&PixelInfoOut, 
         0, 
         sizeof(PixelInfoOut));
  memset(&PixelInfoIn, 
         0, 
         sizeof(PixelInfoIn));
  pPixelAttrIn = (Pixel_t *)&PixelInfoIn;
  pPixelAttrOut = (Pixel_t *)&PixelInfoOut;
  fiOpen(pInFile, 
         InputMode, 
         &iRc);
  if ((pInFile->fp == NULL) || (iRc != OK))
    {
      if (iRc == -1)
        return  PGFFILNOTFND;
      else
        if (iRc == -3)
          return  PGFILLFILE;
        else
          return  APIILLPAR;
    } 

  fiOpen(pOutFile, 
         UpdateMode, 
         &iRc);
  if ((pOutFile->fp == NULL) || (iRc != OK))
    return  APIDESTFIL;

  fiReadAttr(pInFile, 
             (Attr_t *)pPixelAttrIn, 
             Pixel_Attr, 
             &iAttrLen, 
             &iRc);
  if (iRc == OK)
    {
      /* pInData = malloc(pPixelAttrIn->StorePixels+sizeof(PixBuffer_t));  ARG 950530 */
      pInData = malloc(pPixelAttrIn->StorePixels+sizeof(PixBuffer_t)+10);
      if (pInData == NULL)
        return  APINOMEM;

      /* Quick and dirty try to avoid the loop ARG 950530 */

      memset(pInData, 
	     0, 
	     (pPixelAttrIn->StorePixels+sizeof(PixBuffer_t)+10));

      pInData->iMaxSize = pPixelAttrIn->StorePixels+sizeof(PixBuffer_t);
      pInData->Data.iMaxSize = pPixelAttrIn->StorePixels;
      pInData->Compressed = TRUE;
      pOutData = malloc((pPixelAttrIn->RowCnt *pPixelAttrIn->ColCnt)+sizeof
         (PixBuffer_t));
      if (pOutData == NULL)
        {
          free(pInData);
          return  APINOMEM;
        } 

      pOutData->iMaxSize = (pPixelAttrIn->RowCnt *pPixelAttrIn->ColCnt)+
         sizeof(PixBuffer_t);
      pOutData->Data.iMaxSize = (pPixelAttrIn->RowCnt *pPixelAttrIn->ColCnt)
         ;
      pOutData->Compressed = FALSE;
      fseek(pInFile->fp, 
            pPixelAttrIn->FileOffset-1, 
            SEEK_SET);
      iNoBytes = fread(&pInData->Data.ByteData[0], 
                       sizeof(char), 
                       pInData->Data.iMaxSize, 
                       pInFile->fp);
      if (iNoBytes != pInData->Data.iMaxSize)
        {
          free(pInData);
          free(pOutData);
          return  BUFNRDERROR;
        } 

      iRc = pckPixReset(READ_MODE, 
                        pInData);
      if (iRc == OK)
        iRc = pckPixReset(WRITE_MODE, 
                          pOutData);
      if (iRc == OK)
        iRc = pckPixCopy(pInData, 
                         pOutData, 
                         pPixelAttrIn->RowCnt *pPixelAttrIn->ColCnt);

      if (iRc == OK)
        {
          fiOpen(pOutFile, 
                 UpdateMode, 
                 &iRc);
          if ((pOutFile->fp == NULL) || (iRc != OK))
            {
              free(pInData);
              free(pOutData);
              return  APIDESTFIL;
            } 

          fiAllocate(pOutFile, 
                     pOutData->Data.iLen, 
                     &pPixelAttrOut->FileOffset, 
                     &iRc);
          pPixelAttrOut->RowCnt = pPixelAttrIn->RowCnt;
          pPixelAttrOut->ColCnt = pPixelAttrIn->ColCnt;
          pPixelAttrOut->StorePixels = pOutData->Data.iLen;
          pPixelAttrOut->FileOffset += 1;
          pPixelAttrOut->StoreBits = 8;
          pPixelAttrOut->StoreMax = 255;
          pPixelAttrOut->Compressed = FALSE;
          iAttrLen = sizeof(Pixel_t);
          fiWriteAttr(pOutFile, 
                      (Attr_t *)pPixelAttrOut, 
                      Pixel_Attr, 
                      iAttrLen, 
                      &iRc);
          if (iRc != OK)
            {
              free(pInData);
              free(pOutData);
              return  BUFNRDERROR;
            } 

          fseek(pOutFile->fp, 
                pPixelAttrOut->FileOffset-1, 
                SEEK_SET);
          iNoBytes = fwrite(&pOutData->Data.ByteData[0], 
                            sizeof(char), 
                            pPixelAttrOut->StorePixels, 
                            pOutFile->fp);
          if (iNoBytes != pPixelAttrOut->StorePixels)
            {
              free(pInData);
              free(pOutData);
              return  BUFNRDERROR;
            } 
        } 

      free(pInData);
      free(pOutData);
    } 
  return  iRc;
} 


/*----------------------------------------------------------
*  call ExpandBitmap - 
*---------------------------------------------------------                  */

INT32 pckExpandBitmap(Fil_t *pInFile,Fil_t *pOutFile)
{
  INT32 iRc = OK;
  INT32 iDataSize = 0;
  INT32 iBytesWri = 0;
  char *InData;
  char *OutData;
  Bitmap_t BitmapInfoIn;
  Pixel_t PixelInfoIn;
  Bitmap_t BitmapInfoOut;
  Pixel_t PixelInfoOut;
  Pixel_t *pPixelAttrIn;
  Bitmap_t *pBitmapAttrIn;
  Bitmap_t *pBitmapAttrOut;
  INT32 iAttrLen = 0;
  INT32 iNoBytes = 0;

  memset(&PixelInfoOut, 
         0, 
         sizeof(PixelInfoOut));
  memset(&PixelInfoIn, 
         0, 
         sizeof(PixelInfoIn));
  memset(&BitmapInfoOut, 
         0, 
         sizeof(BitmapInfoOut));
  memset(&BitmapInfoIn, 
         0, 
         sizeof(BitmapInfoIn));
  pPixelAttrIn = (Pixel_t *)&PixelInfoIn;
  pBitmapAttrIn = (Bitmap_t *)&BitmapInfoIn;
  pBitmapAttrOut = (Bitmap_t *)&BitmapInfoOut;
  fiOpen(pInFile, 
         InputMode, 
         &iRc);
  if ((pInFile->fp == NULL) || (iRc != OK))
    {
      if (iRc == -1)
        return  PGFFILNOTFND;
      else
        if (iRc == -3)
          return  PGFILLFILE;
        else
          return  APIILLPAR;
    } 

  fiReadAttr(pInFile, 
             (Attr_t *)pBitmapAttrIn, 
             Bitmap_Attr, 
             &iAttrLen, 
             &iRc);
  fiReadAttr(pInFile, 
             (Attr_t *)pPixelAttrIn, 
             Pixel_Attr, 
             &iAttrLen, 
             &iRc);
  InData = malloc((pBitmapAttrIn->StorePixels)+8);
  if (InData == NULL)
    return  APINOMEM;

  iDataSize = (pPixelAttrIn->RowCnt *pPixelAttrIn->ColCnt)/8;
  OutData = malloc(iDataSize+8);
  if (OutData == NULL)
    {
      free(InData);
      fiClose(pInFile, 
              &iTmpRc);
      return  APINOMEM;
    } 

  fseek(pInFile->fp, 
        pBitmapAttrIn->FileOffset-1, 
        SEEK_SET);
  iNoBytes = fread(InData, 
                   sizeof(char), 
                   pBitmapAttrIn->StorePixels, 
                   pInFile->fp);
  if (iNoBytes != pBitmapAttrIn->StorePixels)
    {
      free(InData);
      free(OutData);
      fiClose(pInFile, 
              &iTmpRc);
      return  BUFNRDERROR;
    } 

  pckRleExpandData(InData, 
                   pBitmapAttrIn->StorePixels, 
                   OutData, 
                   &pBitmapAttrOut->StorePixels);
  pBitmapAttrOut->Compressed = FALSE;
  fiOpen(pOutFile, 
         UpdateMode, 
         &iRc);
  if ((pOutFile->fp == NULL) || (iRc != OK))
    {
      free(InData);
      free(OutData);
      fiClose(pInFile, 
              &iTmpRc);
      return  APIDESTFIL;
    } 

  fiAllocate(pOutFile, 
             pBitmapAttrOut->StorePixels, 
             &pBitmapAttrOut->FileOffset, 
             &iRc);
  iAttrLen = sizeof(Bitmap_t);
  pBitmapAttrOut->FileOffset += 1;
  fiWriteAttr(pOutFile, 
              (Attr_t *)pBitmapAttrOut, 
              Bitmap_Attr, 
              iAttrLen, 
              &iRc);
  if (iRc != OK)
    {
      free(InData);
      free(OutData);
      return  BUFNRDERROR;
    } 

  fseek(pOutFile->fp, 
        pBitmapAttrOut->FileOffset-1, 
        SEEK_SET);
  iBytesWri = fwrite(OutData, 
                     sizeof(char), 
                     pBitmapAttrOut->StorePixels, 
                     pOutFile->fp);
  if (iBytesWri != pBitmapAttrOut->StorePixels)
    iRc = NOK;
  free(InData);
  free(OutData);
  return  iRc;
} 

INT32 pckRleExpandData(char *pInBuffer,INT32 iInSize,char *pOutBuffer,INT32 
                       *iOutSize)
{
  INT32 iRc = OK;
  struct LongHeaderStruc LongHeader;
  struct ShortHeaderStruc ShortHeader;
  INT32 iInPos = 0;
  INT32 iOutPos = 0;
  INT32 iTmp = 0;
  unsigned char bValue;

  *((char *)&ShortHeader) = 0;
  while ((iInPos < iInSize) && ((ShortHeader.HeaderType != SHORT_SAME) || 
     (ShortHeader.Len > 0)))           /* NOT EOD                           */
    {
      bValue = pInBuffer[iInPos];
      ShortHeader.HeaderType = bValue&0x03;/* get type from low nibble      */
      ShortHeader.Len = bValue>>0x02;  /* get len from rest of nibble       */
      iInPos++;
      switch (ShortHeader.HeaderType)
        {
          case  SHORT_DIFF :
            if (ShortHeader.Len > 0)
              {
                memcpy(&pOutBuffer[iOutPos], 
                       &pInBuffer[iInPos], 
                       ShortHeader.Len);
                iInPos += ShortHeader.Len;
                iOutPos += ShortHeader.Len;
              } 
            break;
          case  LONG_DIFF :
            LongHeader.HeaderType = bValue&0x03;/* get type from low nibble */
            LongHeader.Len = bValue>>0x02;/* get len from rest of nibble    */
            iTmp = pInBuffer[iInPos];
            LongHeader.Len += iTmp<<6; /* get rest of lenght                */
            iInPos++;
            memcpy(&pOutBuffer[iOutPos], 
                   &pInBuffer[iInPos], 
                   LongHeader.Len);
            iInPos += LongHeader.Len;
            iOutPos += LongHeader.Len;
            break;
          case  SHORT_SAME :
            if ((ShortHeader.HeaderType != SHORT_SAME) || (ShortHeader.Len >
               0))                     /* NOT EOD                           */
              {
                bValue = pInBuffer[iInPos];
                iInPos++;
                memset(&pOutBuffer[iOutPos], 
                       bValue, 
                       ShortHeader.Len);
                iOutPos += ShortHeader.Len;
              } 
            break;
          case  LONG_SAME :
            LongHeader.HeaderType = bValue&0x03;/* get type from low nibble */
            LongHeader.Len = bValue>>0x02;/* get len from rest of nibble    */
            iTmp = pInBuffer[iInPos];
            LongHeader.Len += iTmp<<6;
            iInPos++;
            bValue = pInBuffer[iInPos];
            iInPos++;
            memset(&pOutBuffer[iOutPos], 
                   bValue, 
                   LongHeader.Len);
            iOutPos += LongHeader.Len;
            break;
        } 
    } 
  *(iOutSize) = iOutPos;
  return  iRc;
} 

