/*----------------------------------------------------------------------------
                           U U B U F F E R
                           
                           
     A function for encoding a given buffer with the uuencode algorithm.
     Derived form a uuencoder for files written by Don Kneller:
     kneller@ucsfcgl.bitnet.

     Mark Koennecke, April 1998
-----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "fortify.h"
#include <string.h>
#include <assert.h>
#include "uubuffer.h"

/*--------------------------------------------------------------------------*/
  typedef struct _ReadBuf {
                   char *pPtr;
                   char *pCurrent;
                   int iBufPtr;
                   int iBufLen;
                  } ReadBuf, *pReadBuf;
                  
/*--------------------------------------------------------------------------*/
  static int ReadBytes(pReadBuf self, char *pBuffer, int iLen)
  {
     int iLeft;
     
     if(self->iBufPtr+iLen < self->iBufLen)
     {
        memcpy(pBuffer,&self->pPtr[self->iBufPtr],iLen);
        self->iBufPtr += iLen;
        self->pCurrent += iLen;
        return iLen;
     }
     else
     {
        iLeft = self->iBufLen - self->iBufPtr;
        if(iLeft == 0)
        {
          return 0;
        }
        memcpy(pBuffer,&self->pPtr[self->iBufPtr],iLeft);
        self->iBufPtr = self->iBufLen;
        self->pCurrent += iLeft;
        return iLeft;
     }
  }   
/*-------------------------------------------------------------------------*/
  static int ReadPut(pReadBuf self, char c)
  {
      *(self->pCurrent)= c;
      self->iBufPtr++;
      self->pCurrent++;
      return 1;
  }   
/*--------------------------------------------------------------------------*/
  static int ReadWrite(pReadBuf self, char *pText)
  {
     int i;
     
     for(i = 0; i < strlen(pText); i++)
     {
       ReadPut(self,pText[i]);
     }
     return 1;
  }       
/*-------------------------------------------------------------------------*/
/* ENC is the basic 1 character encoding function to make a char printing */

#define ENC(c) (((c) & 077) + ' ')

  static void OutDec(char *p, pReadBuf self)
  {
      int c1, c2, c3, c4;
      
      c1 = *p >> 2;
      c2 = ((p[0] << 4) & 060) | ((p[1] >> 4) & 017);
      c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
      c4 = p[2] & 077;
      /* original, replaced by code below for efficiency.
         Saves a couple of function call overhead. The profiler
         showed this as a bottleneck.
      ReadPut(self,ENC(c1));
      ReadPut(self,ENC(c2));
      ReadPut(self,ENC(c3));
      ReadPut(self,ENC(c4));
      */
      *(self->pCurrent) = ENC(c1);
      self->pCurrent++;
      *(self->pCurrent) = ENC(c2);
      self->pCurrent++;
      *(self->pCurrent) = ENC(c3);
      self->pCurrent++;
      *(self->pCurrent) = ENC(c4);
      self->pCurrent++;
      self->iBufPtr += 4;
                                                        
  }            
/*--------------------------------------------------------------------------*/
                     
  int UUencodeBuffer(void *pBuffer, int iBufLen, char *pName, 
                     void **pEncoded, int *iLength)
  {
      char pBuffel[80];
      ReadBuf sRead, sWrite;
      int i, n;
      
      assert(pBuffer);
      assert(iBufLen > 0);
      
      /* set up read buffer */
      sRead.pPtr = pBuffer;
      sRead.iBufPtr = 0;
      sRead.iBufLen = iBufLen;
      sRead.pCurrent = pBuffer; 
      
      /* set up write buffer. uuencode increases size by 33%, we do 50%
         + a bit for newlines etc.
      */
      iBufLen += iBufLen/2;
      sWrite.pPtr = NULL;
      sWrite.pPtr = (char *)malloc((512 + iBufLen)*sizeof(char));
      if(!sWrite.pPtr)
      {
        return 0;
      }
      memset(sWrite.pPtr,0,(512+iBufLen)*sizeof(char));
      sWrite.iBufPtr = 0;
      sWrite.iBufLen = iBufLen + 512;
      sWrite.pCurrent = sWrite.pPtr;
      
      /* do the header */
      ReadWrite(&sWrite,"begin 622 ");
      ReadWrite(&sWrite,pName);
      ReadWrite(&sWrite,"\r\n");
      
      /* well, do it */
      for( ; ;)
      {
          n = ReadBytes(&sRead,pBuffel,45);
          if(n > 0)
          {
            ReadPut(&sWrite,ENC(n));
          
            for(i = 0; i < n; i += 3)
            {
              OutDec(&pBuffel[i],&sWrite);
            }
            ReadWrite(&sWrite,"\r\n");
          }
          else
          {
            break;
          }    
      }

      /* finish the game */
      ReadWrite(&sWrite,"end\r\n");
      *pEncoded = sWrite.pPtr;
      *iLength  = sWrite.iBufPtr;
      return 1;         
  }  
                           