/******************************************************************************
* Module    :   UUdecode --- Test for and decode a uuencoded text.
*
* Author    :   John W. M. Stevens
******************************************************************************/

#include    "compiler.h"

#include    "unpost.h"
#include    "regexp.h"
#include    "parse.h"
#include    "uudec.h"

#define     DEC_CHAR(c)     (((c) - ' ') & 0x3f)
#define     CHK_SUM_MASK    0x3f

static  int     FixBitNetTwiddleFlag = 0;

/*-----------------------------------------------------------------------------
| Routine   :   UULnDec() --- UU decode a line.
|
| Inputs    :   LnLen   - Length of line.
|               Line    - Pointer to the line buffer.
| Outputs   :   Bfr     - Points to buffer for decoded output.
-----------------------------------------------------------------------------*/

static
int     UULnDec(int     LnLen,
                char    *Line,
                BYTE    *Bfr)
{
    register    int     i;
    register    int     j;
    auto        int     RecLen;
    auto        int     tmp;
    auto        int     Shift;

    /*  Zero out buffer.    */
    RecLen = DEC_CHAR( *Line );
    memset(Bfr, 0, RecLen);

    /*  Do actual line decoding.  Skip first character, as it is line
    *   length.
    */
    for (i = 1, j = 0, Shift = 2;
         i <= LnLen;
         i++)
    {
        /*  Get six bits.   */
        tmp = DEC_CHAR( Line[i] );

        /*  Put into buffer.    */
        Bfr[j] |= tmp << Shift;
        if (Shift > 2)
            Bfr[j - 1] |= tmp >> (8 - Shift);

        /*  Increment byte pointer if neccesary.    */
        if (Shift < 6)
            j++;

        /*  Adjust shift size.  */
        Shift = (Shift + 2) & 0x7;
    }

    /*  Return size of buffer.  */
    return( RecLen );
}

/*-----------------------------------------------------------------------------
| Routine   :   ChkUUChars() --- Check that a line of the proper length has
|               the proper characters.
|
| Inputs    :   LnLen   - Length of line.
|               Line    - Pointer to the line buffer.
| Outputs   :   Line    - Pointer to the line buffer with fixes.
|
| Returns   :   Returns TRUE    - This is a uuencoded line.
|                       FALSE   - This is not a uudecoded line.
-----------------------------------------------------------------------------*/

static
int     ChkUUChars(int  LnLen,
                   char *Line)
{
    register    int     i;

    /*  Loop through line, checking that all characters are in proper
    *   range.
    */
    for (i = 0; i < LnLen; i++)
        if (Line[i] == '~' && FixBitNetTwiddleFlag)
            Line[i] = '^';
        else if (Line[i] < ' ' || Line[i] > '`')
            return( NOT_UU_LINE );

    /*  Return that this is an encoded line.    */
    return( IS_UU_LINE );
}

/*-----------------------------------------------------------------------------
| Routine   :   ChkUULine() --- Check to see if this is a UUencoded line.
|
| Inputs    :   Line    - Pointer to line buffer.
| Outputs   :   RetStrs - Pointer to array of sub strings.
|               EncLen  - Length of unencoded line in bytes.
|
| Returns   :   Returns IS_UU_LINE  - This is a uuencoded line.
|                       NOT_UU_LINE - This is not a uuencoded line.
|                       UU_SPACE    - This is a valid uuencoded empty line.
|                       UU_BEGIN    - This is a uuencode begin line.
|                       UU_END      - This is a uuencode end line.
-----------------------------------------------------------------------------*/

CHK_UU_ENC  ChkUULine(char  *Line,
                      char  ***RetStrs,
                      int   *EncLen)
{
    auto        int     RecLen;
    auto        int     BfrLen;

    /*  Check for a character in the range of 0x20 to 0x60 inclusive.   */
    if ((*Line >= ' ' && *Line <= 'M') || *Line == '`')
    {
        /*  Get record length.  */
        RecLen = DEC_CHAR( *Line );

        /*  Get line length.    */
        BfrLen = strlen( Line );

        /*  Calculate the line length based on the record size character.   */
        if (*Line == 'M')
            *EncLen = 60;
        else if (*Line == ' ' || *Line == '`')
            *EncLen = 0;
        else
        {
            /*  This is a short line, so calculate the lenght that it's
            *   record length character says it should have.
            *
            *   The first calculation assumes that for any number of
            *   bytes between 1 and 3 inclusive, that the UU encoder
            *   always spits out four characters.
            */
            if (RecLen % 3)
                *EncLen = 4 * (RecLen / 3 + 1);
            else
                *EncLen = 4 * (RecLen / 3);

            /*  If the UU encoder spits out less than four characters
            *   for 1 or 2 bytes, then we need a different calculation.
            */
            if (BfrLen != *EncLen + 1 && BfrLen != *EncLen + 2)
                *EncLen = 4 * (RecLen / 3) + (RecLen % 3 + 1);
        }

        /*  Check for short or long buffer. */
        if (BfrLen != *EncLen + 1 && BfrLen != *EncLen + 2)
            return( NOT_UU_LINE );

        /*  Check for the expected UU characters.   */
        if (ChkUUChars(BfrLen, Line) == NOT_UU_LINE)
            return( NOT_UU_LINE );

        /*  Return one of two different flags.    */
        if (RecLen == 0)
            return( UU_SPACE );
        return( IS_UU_LINE );
    }
    else
    {
        /*  Test for a begin line.  */
        if ( MatchBegin(Line, RetStrs) )
            return( UU_BEGIN );

        /*  Test for end line.  */
        if ( MatchEnd( Line ) )
            return( UU_END );
    }

    /*  This is not a UUencoded line.   */
    return( NOT_UU_LINE );
}

/*-----------------------------------------------------------------------------
| Routine   :   DecUULine() --- Decode a UU encoded line.
|
| Inputs    :   Line    - Pointer to line buffer.
| Outputs   :   Len     - Number of bytes in the buffer.
|               Bfr     - Points to buffer for decoded output.
|
| Returns   :   Returns IS_UU_LINE  - This is a uuencoded line.
|                       NOT_UU_LINE - This is not a uuencoded line.
|                       UU_SPACE    - This is a valid uuencoded empty line.
|                       UU_BEGIN    - This is a uuencode begin line.
|                       UU_END      - This is a uuencode end line.
-----------------------------------------------------------------------------*/

CHK_UU_ENC  DecUULine(char  *Line,
                      int   *Len,
                      BYTE  *Bfr)
{
    auto        int         EncLen;
    auto        CHK_UU_ENC  UULnType;
    auto        char        **RetStrs;

    /*  If this is not a uuencoded line, then it cannot be decoded.
    *   Check it first.
    */
    *Len = 0;
    UULnType = ChkUULine(Line, &RetStrs, &EncLen);
    if (UULnType != IS_UU_LINE)
        return( UULnType );

    /*  Do actual UU decode.    */
    *Len = UULnDec(EncLen, Line, Bfr);

    /*  Return the type of line this is.    */
    return( IS_UU_LINE );
}

/*-----------------------------------------------------------------------------
| Routine   :   DecTruncUULn() --- Decode a possibly truncated UU encoded
|               line.
|
| Inputs    :   Line    - Pointer to line buffer.
| Outputs   :   Len     - Number of bytes in the buffer.
|               Bfr     - Points to buffer for decoded output.
-----------------------------------------------------------------------------*/

void        DecTruncUULn(char   *Line,
                         int    *Len,
                         BYTE   *Bfr)
{
    register    int         i;
    auto        int         RecLen;
    auto        int         BfrLen;
    auto        int         EncLen;

    /*  Get line length.    */
    BfrLen = strlen( Line );

    /*  Calculate the line length.  */
    RecLen = DEC_CHAR( *Line );
    if (RecLen % 3)
        EncLen = 4 * (RecLen / 3 + 1);
    else
        EncLen = 4 * (RecLen / 3);

    /*  If the actual line is shorter than the record length indicates
    *   it ought to be, then pad with spaces.
    */
    if (BfrLen <= EncLen)
    {
        /*  Loop, putting spaces at end.    */
        for (i = BfrLen; i <= EncLen; i++)
            Line[i] = '`';
        Line[i] = '\0';
    }

    /*  Do actual UU line decode.   */
    *Len = UULnDec(EncLen, Line, Bfr);
}


syntax highlighted by Code2HTML, v. 0.9.1