Contributor: RAPHAEL VANNEY

{
Some time ago, I posted here an uuencoder with the following comment :

8<--------------------------------------------------------------
This is the fastest I could come up with ; I suspect it's fairly
faster than the one that was posted earlier. Going still faster
would require some change in the algorithm, which I'm much to
lazy to go through .
8<--------------------------------------------------------------

I was recently toying with this UU matter, and came onto that piece of
code in the SWAGS ; I found it amazingly slow, which it actually is, so
here's the new release (about 10 times faster ; I've given up lazyness
for that one).

Please note that the warning still applies :

Beware, this program does not check before overwritting an existing .uue
file. Generally speaking, the error checking is quite light.

{$r-,s-,q-}    { for the sake of speed only }
{$v-}

Uses DOS ;

Const
     BytesPerLine   = 45 ;         { maximum bytes per encoded line }
     Masque6bits    = $3f ;        { mask for six lower bits }

Procedure EncodeBuffer(Var Buf ; Len : Integer ; Var Res : String) ;
{ UUEncodes Len bytes from Buf into Res }
Assembler ;
Asm
     Push DS
     ClD
     LDS  SI, Buf        { source buffer }
     LES  DI, Res        { destination buffer }
     Mov  CX, Len        { source length }
     Inc  DI             { ES:DI points to first char of Res }
     Mov  AL, CL
     Add  AL, ' '
     StoSB               { store coded number of bytes in line }
     Mov  DL, 1          { DL will hold the actual length of Res }
@1:
     { This loops process 3 input bytes to make 4 output characters }
     LodSB               { 1st byte }
     Mov  BL, AL         { save it }
     ShR  AL, 2          { keep 6 most significant bits (msb) }
     Add  AL, ' '        { encode }
     StoSB               { store in Res }
     ShL  BL, 4          { BL's 4 msb contains 1st byte's 4 lsb }
     LodSB               { load 2nd byte }
     Mov  BH, AL         { save it }
     ShR  AL, 4          { AL's 4 lsb contains 2nd byte's 4 msb }
     Or   AL, BL
     And  AL, Masque6bits{ clear out 2 msb }
     Add  AL, ' '        { encode }
     StoSB               { store 2nd char }
     LodSB               { load 3rd byte }
     Mov  BL, AL         { save it }
     And  BH, $0f        { BH now holds 4 lsb of 2nd byte }
     ShL  AL, 1          { rotate BH:AL... }
     RCL  BH, 1          { ...left 2 bits so that... }
     ShL  AL, 1          { ...6 lsb of BH contains 4 lsb of 2nd byte... }
     RCL  BH, 1          { ...and 2 msb of 3rd byte (clear ?) }
     Mov  AL, BH
     Add  AL, ' '        { encode 3rd char }
     StoSB               { store it }
     Mov  AL, BL         { BL contains 3rd byte }
     And  AL, Masque6bits{ keep only 6 lsb }
     Add  AL, ' '        { encode }
     StoSB               { store 4th char }
     Add  DL, 4          { add 4 to resulting string's length }
     Sub  CX, 3          { 3 bytes processed }
     JA   @1             { if more to process, loop }
     Mov  DI, Word Ptr Res
     Mov  ES:[DI], DL    { store resulting string's length }
     Pop  DS
End ;

Procedure ReplaceSpaceWithBackQuote(Var Str : String) ;
{ Replaces ' ' with '`' in Str }
Assembler ;
Asm
     LES  DI, Str
     Mov  CL, ES:[DI]
     XOr  CH, CH
     ClD
     Inc  DI
     Mov  AX, '`'*256+' '
#1:
     JCXZ @2
     RepNE ScaSB
     JNE  @2
     Mov  ES:[DI-1], AH
     Jmp  #1
@2:
End ;

Var  { buffers for input and output files }
     InBuf     : Array[1..100*BytesPerLine] Of Byte ;
     OutBuf    : Array[1..8192] Of Char ;

Procedure EncodeFile(FName : String) ;
Var  InF  : File ;            { input file }
     OutF : Text ;            { output file }
     OutB : String[BytesPerLine*4 Div 3+4] ; { output buffer }
     Lus  : Word ;            { # of bytes read from input file }
     InP  : Word ;            { current pos in input buffer }
     Nb   : Word ;            { # of bytes to process }

     Rep  : PathStr ;
     Nom  : NameStr ;
     Ext  : ExtStr ;
Begin
     { Open input file }

     Assign(InF, FName) ;
     {$i-}
     ReSet(InF, 1) ;
     {$i+}
     If IOResult<>0 Then
     Begin
          WriteLn('Can''t open ', FName) ;
          Exit ;
     End ;

     FSplit(FName, Rep, Nom, Ext) ;

     { Create (erase) output file in current directory }

     Assign(OutF, Nom+'.UUE') ;
     ReWrite(OutF) ;
     SetTextBuf(OutF, OutBuf, SizeOf(OutBuf)) ;
     WriteLn(OutF, 'begin 644 ', Nom, Ext) ;

     While Not EOF(InF) Do
     Begin
          { Fill the input buffer }

          BlockRead(InF, InBuf, SizeOf(InBuf), Lus) ;
          InP:=1 ;
          If LusBytesPerLine Then Nb:=BytesPerLine ;
               EncodeBuffer(InBuf[InP], Nb, OutB) ;
               ReplaceSpaceWithBackQuote(OutB) ;
               WriteLn(OutF, OutB) ;
               Inc(InP, Nb) ;
          End ;
     End ;

     Close(InF) ;

     { write UUE footer }

     WriteLn(OutF, '`') ;
     WriteLn(OutF, 'end') ;
     Close(OutF) ;
End ;

Begin
     If ParamCount<>1 Then
     Begin
          WriteLn('UUE2 ') ;
          Halt(1) ;
     End ;
     EncodeFile(ParamStr(1)) ;
End.