/*****************************************************************************/
/*          Copyright (c) 1987 - 1988, Future Soft Engineering, Inc.         */
/*                              Houston, Texas                               */
/*****************************************************************************/

#define NOLSTRING    TRUE  /* jtf win3 mod */
#include <windows.h>
#include "port1632.h"
#include "dcrc.h"
#include "dynacomm.h"


/*---------------------------------------------------------------------------*/

#define XM_ABORT                    0x8000
#define XM_COMPLETE                 0x4000
#define XM_BLKREPEAT                0x2000
#define XM_CRC                      0x0800
#define YM_1KBLK                    0x0400
#define YM_GOPTION                  0x0200
#define XM_RETRYMASK                0x001F   /* mbbx 1.04: relax 15 -> 31 */

#define XM_RETRIES                  0x0014   /* mbbx 1.04: relax 10 -> 20 */
#define XM_RETRYINITCRC             4
#define XM_RETRYINITCKS             10

#define XM_WAITRCVINIT              50       /* mbbx 1.04: relax... */
#define XM_WAITNEXTBLK              100
#define XM_WAITNEXTCHAR 	    50	     //sdj: was 20 to get rid of xmodem
					     //sdj: retries when moused moved..move to 50
#define XM_WAITSNDINIT              600


BOOL YM_RcvBatch(WORD);
BOOL NEAR YM_RcvFileInfo(WORD *, WORD *);

BOOL XM_RcvFile(WORD);
BOOL NEAR XM_RcvInit(WORD *, WORD *);
BOOL NEAR XM_RcvData(WORD *, WORD *);
BOOL NEAR XM_RcvBlockHeader(WORD *, WORD *);
BOOL NEAR XM_RcvBlockData(WORD *blockNumber, WORD blockSize,WORD *rcvStatus);
VOID NEAR XM_RcvBlockAbort(WORD *);
BOOL NEAR XM_RcvEnd();
VOID NEAR XM_RcvAbort();

BOOL YM_SndBatch(WORD);
BOOL NEAR YM_SndFileInfo(WORD *, BOOL);

BOOL XM_SndFile(WORD sndStatus);
BOOL NEAR XM_SndInit(WORD *);
BOOL NEAR XM_SndData(WORD *);
BOOL NEAR XM_SndBlockData(WORD *, WORD *, WORD *);
BOOL NEAR XM_SndEnd();
VOID NEAR XM_SndAbort();

BYTE XM_CheckSum(BYTE *dataBlock, WORD blockSize);              /* mbbx 2.00: NEAR -> FAR */
WORD XM_CalcCRC(BYTE *, INT);                /* mbbx 2.00: NEAR -> FAR */


/*---------------------------------------------------------------------------*/
/* UTILITIES --> RCVBFILE.C */

BOOL initXfrBuffer(WORD wBufSize);
VOID fillXfrBuffer(BYTE *, WORD);
WORD readXfrBuffer(BYTE *dataBlock,WORD  blockSize,BOOL bBlkRepeat);
BOOL writeXfrBuffer(BYTE *dataBlock, WORD blockSize,BOOL bBlkRepeat);
VOID grabXfrBuffer(BYTE *, WORD);
BOOL clearXfrBuffer();
VOID freeXfrBuffer();


/*---------------------------------------------------------------------------*/
/* XM_RcvFile() -                                                      [mbb] */
/*---------------------------------------------------------------------------*/

BOOL XM_RcvFile(WORD rcvStatus)
{
   WORD  blockSize;

   if(XM_RcvInit(&blockSize, &rcvStatus))
      if(XM_RcvData(&blockSize, &rcvStatus))
         if(XM_RcvEnd())
            return(TRUE);

   XM_RcvAbort();
   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_RcvInit() -                                                      [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_RcvInit(WORD  *blockSize, WORD  *rcvStatus)
{
   BYTE  work[3];
   WORD  retry;

   LoadString(hInst, STR_RI, (LPSTR) work, 4);  /* mbbx 1.04: REZ... */
   bSetup(work);

   *blockSize = 128;
   *rcvStatus |= XM_RETRIES;

   if(*rcvStatus & (YM_1KBLK | YM_GOPTION))
      *rcvStatus |= XM_CRC;

   while(*rcvStatus & XM_CRC)
   {
      for(retry = XM_RETRYINITCRC; retry > 0; retry -= 1)
      {
         modemWr('C');

         if(xferPSChar)                      /* mbbx 1.02: packet switching */
            modemWr(xferPSChar);

         if(waitRcvChar(work, XM_WAITRCVINIT, 0, CHSTX, CHSOH, CHEOT, CHCAN, NULL))
         {
            switch(work[0])
            {
            case CHSTX:
               *blockSize = 1024;
                                             /* then fall thru... */
            case CHSOH:
               return(TRUE);

            case CHEOT:
               *rcvStatus |= XM_COMPLETE;
               return(TRUE);

            case CHCAN:
               return(FALSE);
            }
         }

         if(xferStopped)
            return(FALSE);
      }

      *rcvStatus &= ((*rcvStatus & YM_GOPTION) ? ~YM_GOPTION : ~XM_CRC);
   }

   for(retry = XM_RETRYINITCKS; retry > 0; retry -= 1)   /* mbbx 1.04: relax */
   {
      modemWr(CHNAK);
      if(xferPSChar)                         /* mbbx 1.02: packet switching */
         modemWr(xferPSChar);

      if(waitRcvChar(work, XM_WAITRCVINIT, 0, CHSTX, CHSOH, CHEOT, CHCAN, NULL))
      {
         switch(work[0])
         {
         case CHSTX:
            *blockSize = 1024;
                                             /* then fall thru... */
         case CHSOH:
            return(TRUE);

         case CHEOT:
            *rcvStatus |= XM_COMPLETE;
            return(TRUE);

         case CHCAN:
            return(FALSE);
         }
      }

      if(xferStopped)
         break;

      showBErrors(++xferErrors);
   }

   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_RcvData() -                                                      [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_RcvData(WORD  *blockSize, WORD  *rcvStatus)
{
   BYTE  work[3];
   WORD  blockNumber = 1;

   if(*rcvStatus & XM_COMPLETE)
      return(TRUE);

   LoadString(hInst, STR_DF, (LPSTR) work, 4);  /* mbbx 1.04: REZ... */
   bSetup(work);

   if(initXfrBuffer(12 * 1024))
   {
      XM_RcvBlockData(&blockNumber, *blockSize, rcvStatus);

      while(!(*rcvStatus & (XM_COMPLETE | XM_ABORT)))
      {
         if(XM_RcvBlockHeader(blockSize, rcvStatus))
            XM_RcvBlockData(&blockNumber, *blockSize, rcvStatus);
      }

      if(!(*rcvStatus & XM_ABORT))
         if(!clearXfrBuffer())
            *rcvStatus |= XM_ABORT;

      freeXfrBuffer();
   }

   return(!(*rcvStatus & XM_ABORT));
}


/*---------------------------------------------------------------------------*/
/* XM_RcvBlockHeader() -                                               [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_RcvBlockHeader(WORD  *blockSize, WORD  *rcvStatus)
{
   BYTE  work[1];

   if(waitRcvChar(work, XM_WAITNEXTBLK, 0, CHSTX, CHSOH, CHEOT, CHCAN, NULL))
   {
      switch(work[0])
      {
      case CHSTX:
         *blockSize = 1024;
         return(TRUE);

      case CHSOH:
         *blockSize = 128;
         return(TRUE);

      case CHEOT:
         *rcvStatus |= XM_COMPLETE;
         return(FALSE);

      case CHCAN:
         xferStopped = TRUE;
         break;
      }
   }

   XM_RcvBlockAbort(rcvStatus);
   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_RcvBlockData() -                                                 [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_RcvBlockData(WORD *blockNumber, WORD blockSize,WORD *rcvStatus)
{
   BYTE  work[2];
   BOOL  bBlkRepeat;
   WORD  ndx;
   BYTE  dataBlock[1024];
   signed char i,j;

   while(waitRcvChar(work, XM_WAITNEXTCHAR, 0, 0) &&
         waitRcvChar(work+1, XM_WAITNEXTCHAR, 0, 0) &&
	 ( (j=(signed char)work[0]) == ~(i = (signed char)work[1])	) )

   //sdj: on mips xmodem rcv was broken due to (BYTE)~work[1]

   {
      if(bBlkRepeat = (work[0] != (BYTE) *blockNumber))
         if(work[0] != (BYTE) (*blockNumber-1))
            break;

      for(ndx = 0; ndx < blockSize; ndx += 1)
         if(!waitRcvChar(dataBlock+ndx, XM_WAITNEXTCHAR, 0, 0))
            break;
      if(ndx < blockSize)
         break;

      if(!waitRcvChar(work, XM_WAITNEXTCHAR, 0, 0))
         break;
      if(!(*rcvStatus & XM_CRC))
      {
         if(XM_CheckSum(dataBlock, blockSize) != work[0])
            break;
      }
      else
      {
         if(!waitRcvChar(work+1, XM_WAITNEXTCHAR, 0, 0) || (XM_CalcCRC(dataBlock, blockSize) != ((work[0] << 8) | work[1])))
            break;
      }

      if(!writeXfrBuffer(dataBlock, blockSize, bBlkRepeat))
      {
         xferStopped = TRUE;
         break;
      }

      if(!bBlkRepeat)                        /* mbb: reset retry counter */
      {
         *blockNumber += 1;
         *rcvStatus = (*rcvStatus & ~XM_RETRYMASK) | XM_RETRIES;

         if(*blockNumber > 1)                /* mbb: skip block 0 */
         {
            if(xferOrig > 0)
            {
               xferBytes -= blockSize;
               updateProgress(FALSE);
            }
            else
               showBBytes(xferLength += blockSize, FALSE);  /* mbbx 2.00: xfer ctrls */
         }
      }

      if(!(*rcvStatus & YM_GOPTION))
      {
         modemWr(CHACK);
         if(xferPSChar)                      /* mbbx 1.02: packet switching */
            modemWr(xferPSChar);
      }

      return(TRUE);
   }

   XM_RcvBlockAbort(rcvStatus);
   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_RcvBlockAbort() -                                                [mbb] */
/*---------------------------------------------------------------------------*/

VOID NEAR XM_RcvBlockAbort(WORD  *rcvStatus)
{
   BYTE  work[1];

   if(xferStopped || (((*rcvStatus -= 1) & XM_RETRYMASK) == 0))
      *rcvStatus |= XM_ABORT;
   else
   {
      while(waitRcvChar(work, XM_WAITNEXTCHAR, 0, 0));
      modemWr(CHNAK);
      if(xferPSChar)                         /* mbbx 1.02: packet switching */
         modemWr(xferPSChar);
   }

   if(!xferStopped)
      showBErrors(++xferErrors);
}


/*---------------------------------------------------------------------------*/
/* XM_RcvEnd() -                                                       [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_RcvEnd()
{
   BYTE  work[3];
   WORD  retry;

   LoadString(hInst, STR_RE, (LPSTR) work, 4);  /* mbbx 1.04: REZ... */
   bSetup(work);

   modemWr(CHACK);
   if(xferPSChar)                            /* mbbx 1.02: packet switching */
      modemWr(xferPSChar);

   for(retry = XM_RETRIES; retry > 0; retry -= 1)     /* mbbx 1.04: relax */
   {
      if(waitRcvChar(work, XM_WAITNEXTBLK / 2, 0, CHEOT, CHCAN, NULL))
      {
         switch(work[0])
         {
         case CHEOT:
            modemWr(CHACK);
            if(xferPSChar)                   /* mbbx 1.02: packet switching */
               modemWr(xferPSChar);
            showBErrors(++xferErrors);
            continue;

         case CHCAN:
            xferStopped = TRUE;
            break;
         }
      }

      if(xferStopped)
         break;

      return(TRUE);
   }

   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_RcvAbort() -                                                     [mbb] */
/*---------------------------------------------------------------------------*/

VOID NEAR XM_RcvAbort()
{
   BYTE  work[1];

   rcvAbort();

   while(waitRcvChar(work, XM_WAITNEXTCHAR, 0, 0));
   modemWr(CHCAN);
   modemWr(CHCAN);
   modemWr(CHCAN);
   modemWr(CHCAN);
   modemWr(CHCAN);
   modemWr(BS);
   modemWr(BS);
   modemWr(BS);
   modemWr(BS);
   modemWr(BS);
   if(xferPSChar)                            /* mbbx 1.02: packet switching */
      modemWr(xferPSChar);
}


/*---------------------------------------------------------------------------*/
/* XM_SndFile() -                                                      [mbb] */
/*---------------------------------------------------------------------------*/

BOOL XM_SndFile(WORD sndStatus)
{
   if(XM_SndInit(&sndStatus))
      if(XM_SndData(&sndStatus))
         if(XM_SndEnd())
            return(TRUE);

   XM_SndAbort();
   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_SndInit() -                                                      [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_SndInit(WORD  *sndStatus)
{
   BYTE  work[3];

   LoadString(hInst, STR_SI, (LPSTR) work, 4);  /* mbbx 1.04: REZ... */
   bSetup(work);

   *sndStatus |= XM_RETRIES;

   if(waitRcvChar(work, XM_WAITSNDINIT, 0, 'C', CHNAK, CHCAN, 0))
   {
      switch(work[0])
      {
      case 'C':
         *sndStatus |= XM_CRC;
         if(!(*sndStatus & YM_1KBLK) && waitRcvChar(work, XM_WAITNEXTCHAR / 2, 0, 'K', 0))
            *sndStatus |= YM_1KBLK;
         return(TRUE);

      case CHNAK:
         *sndStatus &= ~(XM_CRC | YM_1KBLK);
         return(TRUE);

      case CHCAN:
         break;
      }
   }

   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_SndData() -                                                      [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_SndData(WORD  *sndStatus)
{
   BYTE  work[3];
   WORD  blockNumber = 1;
   WORD  blockSize;

   LoadString(hInst, STR_DF, (LPSTR) work, 4);  /* mbbx 1.04: REZ... */
   bSetup(work);

   if(initXfrBuffer(12 * 1024))
   {
      blockSize = (!(*sndStatus & YM_1KBLK) ? 128 : 1024);

      while(!(*sndStatus & (XM_COMPLETE | XM_ABORT)))
         XM_SndBlockData(&blockNumber, &blockSize, sndStatus);

      freeXfrBuffer();
   }

   return(!(*sndStatus & XM_ABORT));
}


/*---------------------------------------------------------------------------*/
/* XM_SndBlockData() -                                                 [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_SndBlockData(WORD *blockNumber, WORD *blockSize, WORD *sndStatus)
{
   BYTE  dataBlock[1024];
   WORD  dataBytes;
   WORD  wCRC;
   BYTE  work[1];
   BOOL  writeGood;

   switch(dataBytes = readXfrBuffer(dataBlock, *blockSize, (*sndStatus & XM_BLKREPEAT)))
   {
   case (WORD)-1:
      xferStopped = TRUE;
      break;

   case 0:
      *sndStatus |= XM_COMPLETE;
      return(TRUE);

   default:
      if((*blockSize == 1024) && (dataBytes <= (5 * 128)) && !(*sndStatus & XM_BLKREPEAT))
         readXfrBuffer(dataBlock, *blockSize = 128, TRUE);

      modemWr((*blockSize == 128) ? CHSOH : CHSTX);
      modemWr((BYTE) *blockNumber);
      modemWr((BYTE) ~*blockNumber);

      writeGood = modemWrite((LPSTR) dataBlock, (INT)(*blockSize));

      if(!writeGood)
      {
         wCRC = 0;
         break;
      }

      if(!(*sndStatus & XM_CRC))
         modemWr(XM_CheckSum(dataBlock, *blockSize));
      else
      {
         wCRC = XM_CalcCRC(dataBlock, *blockSize);
         modemWr(HIBYTE(wCRC));
         modemWr(LOBYTE(wCRC));
      }
      if(xferPSChar)                         /* mbbx 1.02: packet switching */
         modemWr(xferPSChar);

      if(!waitRcvChar(work, XM_WAITSNDINIT, 0, CHACK, CHNAK, CHCAN, (*blockNumber <= 1) ? 'C' : 0, 0))
      {
         xferStopped = TRUE;
         break;
      }

      switch(work[0])
      {
      case CHACK:
         *blockNumber += 1;
         *sndStatus = (*sndStatus & ~(XM_BLKREPEAT | XM_RETRYMASK)) | XM_RETRIES;

         if(*blockNumber > 1)
         {
            xferBytes -= *blockSize;
            updateProgress(FALSE);
         }
         return(TRUE);

      case CHNAK:
         break;

      case CHCAN:
         xferStopped = TRUE;
         break;
      }
      break;
   }

   if(xferStopped || (((*sndStatus -= 1) & XM_RETRYMASK) == 0))
      *sndStatus |= XM_ABORT;
   else
      *sndStatus |= XM_BLKREPEAT;

   if(!xferStopped)
      showBErrors(++xferErrors);

   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_SndEnd() -                                                       [mbb] */
/*---------------------------------------------------------------------------*/

BOOL NEAR XM_SndEnd()
{
   BYTE  work[3];
   WORD  retry;

   LoadString(hInst, STR_SE, (LPSTR) work, 4);  /* mbbx 1.04: REZ... */
   bSetup(work);

   for(retry = XM_RETRIES; retry > 0; retry -= 1)     /* mbbx 1.04: relax */
   {
      modemWr(CHEOT);
      if(xferPSChar)                         /* mbbx 1.02: packet switching... */
         modemWr(xferPSChar);

      if(waitRcvChar(work, XM_WAITNEXTBLK, 0, CHACK, CHCAN, 0))   /* mbbx 1.04: relax 15 -> 60 */
      {
         switch(work[0])
         {
         case CHACK:
            return(TRUE);

         case CHCAN:
            xferStopped = TRUE;
            break;
         }
      }

      if(xferStopped)
         break;

      showBErrors(++xferErrors);
   }

   return(FALSE);
}


/*---------------------------------------------------------------------------*/
/* XM_SndAbort() -                                                     [mbb] */
/*---------------------------------------------------------------------------*/

VOID NEAR XM_SndAbort()
{
   BYTE  work[1];

   sndAbort();

   modemWr(CHCAN);
   modemWr(CHCAN);
   modemWr(CHCAN);
   modemWr(CHCAN);
   modemWr(CHCAN);
   modemWr(BS);
   modemWr(BS);
   modemWr(BS);
   modemWr(BS);
   modemWr(BS);
   if(xferPSChar)                            /* mbbx 1.02: packet switching */
      modemWr(xferPSChar);
}


/*---------------------------------------------------------------------------*/
/* XM_CheckSum() -                                                     [mbb] */
/*---------------------------------------------------------------------------*/

BYTE XM_CheckSum(BYTE *dataBlock, WORD blockSize)       /* mbbx 2.00: NEAR -> FAR */
{
   BYTE  XM_CheckSum = 0;

   while(blockSize > 0)
      XM_CheckSum += dataBlock[--blockSize];

   return(XM_CheckSum);
}


/*---------------------------------------------------------------------------*/
/* XM_CalcCRC() -                                                      [mbb] */
/*---------------------------------------------------------------------------*/

WORD XM_CalcCRC(BYTE  *dataBlock, INT   blockSize)
{
   WORD  XM_CalcCRC = 0;
   INT   ndx;

   while(--blockSize >= 0)
   {
      XM_CalcCRC = XM_CalcCRC ^ (((WORD) *dataBlock++) << 8);
      for(ndx = 0; ndx < 8; ndx += 1)
      {
         if(XM_CalcCRC & 0x8000)
            XM_CalcCRC = (XM_CalcCRC << 1) ^ 0x1021;
         else
            XM_CalcCRC = (XM_CalcCRC << 1);
      }
   }

   return(XM_CalcCRC & 0xFFFF);
}


/*---------------------------------------------------------------------------*/
/* UTILITIES --> file buffering to be used by all RCV protocols !!!    [mbb] */
/*---------------------------------------------------------------------------*/

HANDLE   hXfrBuf;
LPSTR    lpXfrBuf;
WORD     wXfrBufSize;
WORD     wXfrBufBytes;
WORD     wXfrBufIndex;
WORD     wXfrBufExtend;


BOOL initXfrBuffer(WORD wBufSize)
{
   wXfrBufSize = wBufSize;
   if((hXfrBuf = GlobalAlloc(GMEM_MOVEABLE, (DWORD) wXfrBufSize)) != NULL)
   {
#ifdef ORGCODE
      if((lpXfrBuf = GlobalWire(hXfrBuf)) != NULL)
#else
      if((lpXfrBuf = GlobalLock(hXfrBuf)) != NULL)
#endif

      {
         wXfrBufBytes  = 0;
         wXfrBufIndex  = 0;
         wXfrBufExtend = 0;
         return(TRUE);
      }

      GlobalFree(hXfrBuf);
   }

   rcvFileErr();
   return(FALSE);
}



WORD readXfrBuffer(BYTE *dataBlock, WORD blockSize, BOOL bBlkRepeat)
{
   if(!bBlkRepeat)
      wXfrBufIndex += wXfrBufExtend;

   if((wXfrBufIndex+blockSize) > wXfrBufBytes)
   {
      if((wXfrBufBytes -= wXfrBufIndex) > 0)
         lmovmem(lpXfrBuf+wXfrBufIndex, lpXfrBuf, wXfrBufBytes);

      if((wXfrBufIndex = (WORD)_lread(xferRefNo, lpXfrBuf, wXfrBufSize-wXfrBufBytes)) == (WORD)-1)
      {
         return((WORD)-1);
      }

      wXfrBufBytes += wXfrBufIndex;
      wXfrBufIndex  = 0;
   }

   if((wXfrBufExtend = (wXfrBufBytes-wXfrBufIndex)) > 0)
   {
      if(wXfrBufExtend > blockSize)
         wXfrBufExtend = blockSize;
      lmovmem(lpXfrBuf+wXfrBufIndex, (LPSTR) dataBlock, wXfrBufExtend);
      if(wXfrBufExtend < blockSize)
         memset(dataBlock+wXfrBufExtend, CNTRLZ, blockSize-wXfrBufExtend);
   }

   return(wXfrBufExtend);
}


BOOL writeXfrBuffer(BYTE *dataBlock, WORD blockSize,BOOL bBlkRepeat)
{
   if(!bBlkRepeat)
      wXfrBufBytes += wXfrBufExtend;

   if((wXfrBufBytes+blockSize) > wXfrBufSize)
   {
      if(_lwrite(xferRefNo, lpXfrBuf, wXfrBufBytes) != wXfrBufBytes)
      {
         rcvFileErr();
         return(FALSE);
      }
      wXfrBufBytes = 0;
   }

   lmovmem((LPSTR) dataBlock, lpXfrBuf+wXfrBufBytes, wXfrBufExtend = blockSize);
   return(TRUE);
}


BOOL clearXfrBuffer()
{
   if(wXfrBufExtend > 0)
   {
      while(wXfrBufExtend > 0)               /* mbbx 1.04 ... */
      {
         if(*(lpXfrBuf+(wXfrBufBytes+wXfrBufExtend-1)) != CNTRLZ)
            break;
         wXfrBufExtend -= 1;
      }
      wXfrBufBytes += wXfrBufExtend;
      wXfrBufExtend = 0;
   }

   if(wXfrBufBytes > 0)
   {
      if(_lwrite(xferRefNo, lpXfrBuf, wXfrBufBytes) != wXfrBufBytes)
      {
         rcvFileErr();
         return(FALSE);
      }
      wXfrBufBytes = 0;
   }

   return(TRUE);
}


VOID freeXfrBuffer()
{
#ifdef ORGCODE
   GlobalUnWire(hXfrBuf);
#else
   GlobalUnlock(hXfrBuf);
#endif

   GlobalFree(hXfrBuf);
}
