#ifndef AuCode_H
#define AuCode_H
/* -------------------------------------------------------------------------- **
 * AuCode.h - Amiga uuencode/uudecode toolkit.
 *
 *  Written by Christopher R. Hertel; December, 1992
 *  email: crh@bubble.mooses.affinity.mn.org
 * -------------------------------------------------------------------------- **
 *  Copyright (C) 1993 Christopher R. Hertel
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * -------------------------------------------------------------------------- **
 *
 * $Log:	AuCode.h,v $
 * Revision 1.3  94/02/06  14:09:39  CRH
 * With this revision I rewrote the comments for functions Cleanln() and 
 * Decodeln().  I fixed some bugs with the checksum calculations (I was
 * getting negative values), and I added an internal function to calculate
 * checksums on bytes triples (au_cdChecksum3()).  CRH
 * 
 * Revision 1.2  93/09/15  21:29:22  CRH
 * Fixed a small bug in the decoding functions.  Plus some general
 * cleanup.
 *
 * Revision 1.1  93/03/25  11:31:56  CRH
 * Cleaned up comments.  Clarified License and Copyright.
 *
 * Revision 1.0  93/03/04  00:29:07  CRH
 * Initial revision
 *
 * -------------------------------------------------------------------------- **
 * My understanding of uuencoding/decoding is based on the knowledge that I
 * gained by reading the uuencode source provided with AmigaUUCP V1.16.
 * Many thanks to the authors of that software!  The following are comments
 * from their code, which are included as my way of giving credit where
 * credit is due.
 *
 * /begin/
 * [uuencode.c:]
 * Written by Mark Horton
 * Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums
 * Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for
 * compatibility
 * Modified by bcn (Bryce Nesbitt,ucbvax!hoser!bryce) to enable CTRL-C for
 * Amiga Lattice C.  Added a transparent file size trailer for later check.
 * Changed fopen from "r" to "rb" for Messy-dos machines (thanks to Andrew
 * Wylie)
 *
 * [uudecode.c:]
 * Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a misleading
 * error message on the Amiga port, to fix a bug that prevented decoding
 * certain files, to work even if trailing spaces have been removed from a
 * file, to check the filesize (if present), to add some error checking, to
 * loop for multiple decodes from a single file, and to handle common
 * BITNET mangling.  Kludged around a missing string function in Aztec
 * C. Changed "r" to "rb" and "w" to "wb" for Messy-dos machines
 * (Thanks to Andrew Wylie).
 * /end/
 *
 * -------------------------------------------------------------------------- **
 *  Initial comments:  This module implements the basic uuencode/decode
 *  functionality.  The functions are designed to be reentrant, so you may
 *  use them as part of either a link library or a run-time library.
 *  Also, no attempt is made to support any hardware platform other than the
 *  Commodore Amiga.  In particular, this module is written to compile under
 *  SAS C 5.10 or above on an Amiga running OS 2.04 or above.  The code is,
 *  however, written in a fairly generic style, and should be highly porable.
 *
 *  Notes regarding style:  I am a Pascal programmer at heart, and most of
 *  my style choices are based on my preference for that language and its
 *  derivatives.  The result is a hybrid format with a few odd quirks of
 *  its own.  In any case, I intend to produce several modules, so my
 *  function, macro, constant, variable, and type naming conventions serve
 *  to associate identifiers with modules, and to prevent duplicate names
 *  (after all, who else would use such awkward identifiers?).
 *
 *  As mentioned above, these modules are designed to work within the
 *  multitasking environment of the Commodore Amiga.  The code is (should
 *  be) reentrant and self contained (I've even avoided ANSI standard
 *  functions, because the available libraries are not necessarily
 *  reentrant).  I have, however, been careful to avoid Amiga-specific
 *  functions.  It should, therefore, be very easy to port the code to other
 *  platforms.  (I'm hoping for a microVAX for Christmas. ;-) )
 *
 * Christopher R. Hertel; December, 1992
 * -------------------------------------------------------------------------- **
 */

/* -------------------------------------------------------------------------- **
 * Defines...
 *  au_cdMAXPhrase -  a "phrase" of input becomes one line of output.  In
 *                    other words, function AuEncode() will encode at most
 *                    MAXphrase characters at a time, and write them to the
 *                    output buffer. The output line length will be 8/6ths
 *                    (or 1 and 1/3 times) the original input, plus three
 *                    extra bytes per line (length, checksum, and newline).
 *                    This value should ALWAYS be a multiple of three!
 *                    Encoding is performed three bytes at a time.  Other
 *                    values will cause a reducion in performance and some
 *                    oddly encoded (yet correct) translations. This value
 *                    should also ALWAYS be less than 64, because it will
 *                    be encoded in six bits just like everything else.
 *
 *  au_cdCHKSUMsize - Checksum size, in decimal.  A checksum of n indicates
 *                    that the checksum should be in the range 0..(n-1), so
 *                    if n = 64, then the checksum would be in the range
 *                    0..63 (i.e., six bits).
 *
 *  au_cdMAX_LINE   - This is, roughly, the maximum length (in bytes) of a
 *                    "line".  A line being a single uuencode "record", so
 *                    to speak.  The value is calculated as follows:  The
 *                    number of source bytes must be <=63 (since only six
 *                    bits are used to store this value).  63 bytes encodes
 *                    to (63 * (4 / 3)) == 84 bytes.
 *
 *                    Add:
 *                        + one byte for the encoded length
 *                        + one for the encoded checksum
 *                        + one for the eoln character
 *                        + one more, for a nul terminator
 *
 *                    Total 88.  Add 2 for good luck for a total of 90.
 *                    (I was once told that infinity was "as much as you'll
 *                    ever need plus one".)
 *
 */

#define au_cdMAXPhrase  45
#define au_cdCHKSUMsize 64
#define au_cdMAX_LINE   90

/* -------------------------------------------------------------------------- **
 * Defined Error Codes...
 *
 *          au_cdErr_NoError  - No error.
 *
 *          au_cdErr_Cramped  - Output buffer does not contain enough space.
 *
 *          au_cdErr_Checksum - The checksum comparison failed.
 */
#define au_cdErr_NoError  0x00
#define au_cdErr_Cramped  0x01
#define au_cdErr_Checksum 0x02

/* -------------------------------------------------------------------------- **
 * Macros...
 *  au_cdENCD - encode a character.  The character, c, is encoded in a six
 *              bit field as follows:  If c is not nul, the lower six bits
 *              arithmatically added to the value of the space character
 *              (ascii 32).  If c *is* nul, then the value of the `
 *              character is returned.  (Note: octal 77 = hex 3F = binary
 *              00111111.)
 *
 *  au_cdDECD - decode a character.  Subtract the value of the space
 *              character, then make sure that you have only the lower six
 *              bits.
 *
 *  au_cdExpPhrLen-Given the length of a source phrase, calculate the
 *              number of bytes required for the encoded line.  This macro
 *              converts the number of source bytes into bits, then figures
 *              out how many bytes are required to store the encoded
 *              version (rounding up any fractional part to a whole
 *              number).  Three bytes are then added to the count (for
 *              length, checksum, and newline).  Note that the entire
 *              calculation is performed using integers.
 *
 *  au_cdCleanSixel-A potential error exists because BITNET converts the
 *              "^" to a "~".  Technically, the "~" (tilde) can't be part
 *              of the code, so it's safe to convert it back to "^" (carat)
 *              using this macro.
 *
 */

#define au_cdENCD(c) ((c) ? (((c) & 077) + ' ') : '`')  /* single char encode */

#define au_cdDECD(c) (((c) - ' ') & 077)           /* single character decode */

#define au_cdExpPhrLen(pl) (((((pl) * 80) / 6)+9)/10 +3)

#define au_cdCleanSixel(c) (('~'==(c))?'^':(c))

/* -------------------------------------------------------------------------- **
 * Functions Prototypes...
 */

int au_cdCvt3to4( char *S, char *T );
  /* ------------------------------------------------------------------------ **
   * Uuencode a three-byte value.  The result is a four-byte value.  The
   * function returns the checksum of the three source bytes.
   *
   *  Input:
   *    S - A pointer to an array of three bytes.  These are the source data.
   *    T - A pointer to the four byte target array.
   *
   *  Output: a checksum value calculated from the three source bytes.
   * ------------------------------------------------------------------------ **
   */

int au_cdCvt4to3( char *S, char *T );
  /* ------------------------------------------------------------------------ **
   * Uudecode a four-byte value.  The result is a three-byte value.  The
   * function returns the checksum of the three target bytes.
   *
   *  Input:
   *    S - A pointer to an array of four bytes.  These are the source data.
   *    T - A pointer to the three byte target array.
   *
   *  Output: a checksum value calculated from the three target bytes.
   * ------------------------------------------------------------------------ **
   */

int au_cdEncode( char *sBufr, int sbSize, char *tBufr, int tbSize );
  /* ------------------------------------------------------------------------ **
   * Encode a block of characters using the UUENCODE coding scheme.
   *
   *  Input:
   *    sBufr   - A pointer to a buffer containing the bytes to be encoded.
   *    sbSize  - The number of bytes in sBufr to be encoded.
   *    tBufr   - A pointer to the target buffer.
   *    tbSize  - The number of bytes available in tBufr.
   *
   *  Output:   The number of source bytes that were actually converted.  If
   *            this number is less than sbSize, an error occured during the
   *            encoding process (ran out of room in tBufr).  The best way to
   *            recover is to write out the contents of tBufr (which, if they
   *            exist, are valid) and call this function again, passing in a
   *            pointer to the remainder of the source bytes.
   *         -> However, if zero bytes were processed (i.e., this function
   *            returns zero), then tBufr is simply not large enough.
   *
   *  Note:     This function will not write the terminating line.
   * ------------------------------------------------------------------------ **
   */

int au_cdCleanln( char *sBufr, int sbSize, char *tBufr, int tbSize );
  /* ------------------------------------------------------------------------ **
   * Clean a line of input to ensure that it can be decoded properly.
   *
   *  Input:  sBufr   - A pointer to an array of encoded bytes.  The
   *                    contents of sBufr[] (the "source") are assumed to
   *                    be a single line of uuencoded text.  The line is
   *                    considered to be terminated by ascii value less
   *                    than 32.
   *
   *          sbSize  - The number of significant bytes in sBufr[].  That
   *                    is, the maximum number of bytes that you wish to
   *                    have cleaned.  Cleanln() will process no more than
   *                    min( tbSize, sbSize ) bytes.
   *
   *          tBufr   - A pointer to the target buffer.  The target buffer
   *                    will receive the "cleaned" copy of the source line.
   *                    Note that, in general, tBufr should be at least
   *                    sbSize bytes long, and possibly longer.  It should
   *                    always be safe to create a tBufr that is
   *                    au_cdMAX_LINE bytes long (unless you are using in
   *                    this module in some new and interesting way that is
   *                    beyond my ability to extrapolate).
   *
   *          tbSize  - The number of bytes available in tBufr.  Cleanln()
   *                    will process no more than min( tbSize, sbSize )
   *                    bytes.
   *
   *  Output: The number of characters in sBufr[] that were copied to
   *          tBufr[].  This value does not include any spaces that were
   *          added to the end of tBufr[] as padding.
   *
   *  Notes:  The input line is "cleaned" as follows:
   *
   *          This function copies the input line to a new buffer.  During
   *          the copy the function repairs damage that *may* have occurred
   *          during transmission.
   *
   *          In particular, some UUENCODErs encode a nul sixel as a space
   *          (this module encodes a nul as a "`" character, both decode
   *          to the same thing).  Some editors (and other text utilites)
   *          will trim trailing spaces from the ends of lines.  This
   *          function pads the end of the target buffer with spaces to
   *          avoid the problem of lost sixles.
   *
   *          Another potential error exists because BITNET converts the
   *          "^" to a "~".  Technically, the "~" can't be part of the code,
   *          so it's safe to convert it back using the au_cdCleanSixel()
   *          macro.
   *
   *          This function always places a nul byte in the last position
   *          in tBufr[].  That is:
   *              tBufr[tbSize-1] = '\0';
   *          be certain that your tBufr[] is big enough to handle all the
   *          valid characters in sBufr[] plus the nul!
   * ------------------------------------------------------------------------ **
   */

int au_cdDecodeln( char *sBufr, char *tBufr, int tbSize, int *ErrCD );
  /* ------------------------------------------------------------------------ **
   * This function will decode one "line" of encoded input.
   *
   *  Input:  sBufr   - A pointer to a buffer containing the encoded data
   *                    that is to be decoded.  The data should be in the
   *                    form of a "line" of uuencoded text.  The line is
   *                    assumed to be "clean" (see au_cdCleanln()).
   *          tBufr   - A pointer to the target buffer.  tBufr[] will
   *                    receive the decoded data.
   *          tbSize  - Number of bytes available in tBufr[].
   *          ErrCD   - A pointer to an integer that will receive an
   *                    error code.  Check *ErrCD for one of the following
   *                    values:
   *
   *                    au_cdErr_NoError  - No error.  If the function
   *                      return value is zero *and* the error code is
   *                      _NoError, then an empty (i.e., terminating) line
   *                      has been found, indicating end of the (encoded)
   *                      file.
   *
   *                    au_cdErr_Cramped  - tBufr[] does not contain enough
   *                      space to receive the decoded information.  A
   *                      single encoded line may contain, at most, 63
   *                      encoded (source) bytes.
   *
   *                    au_cdErr_Checksum - the checksum comparison failed.
   *                      Either the source line is mangled, or the
   *                      checksum was not written properly by the encoding
   *                      program.
   *
   *  Output: The number of bytes that were generated as a result of
   *          decoding the input line.
   *
   *  Notes: sBufr[] is assumed to be "clean".  See the notes associated
   *  with function au_cdCleanln() for an explanation of the term "clean",
   *  as used in this context.
   * ------------------------------------------------------------------------ **
   */

/* ========================================================================== */
#endif /* AuCode_H */
