[comp.sys.atari.st] Info-Atari16 Digest V87 #58

jhs@mitre-bedford.ARPA.UUCP (02/07/87)

For the folks at Michigan Tech, and anyone else who needs it, here is the
definition of uuencode/decode, plus a c program to do it.

There are several pitfalls which may or may not be handled correctly by this
program.  I will post another message summarizing what people have said about
the problems encountered.

-John Sangster / jhs@mitre-bedford.arpa
------------------------------------------------------------------------------
From: randy@NLM-VAX.arpa (Rand Huntzinger)
Organization: National Library of Medicine, Bethesda, Md
------------
Uudecode reads a file of the following format:

header line(1)->begin <mode> <filename>
data lines(many)-><length> <data>
trailer line(1)->end

where:
The header line fields contain:

<mode> is a three digit number specifying a Unix file mode (specifies
who can read and write the file.  You can ignore this on a
non-Unix machine.

<filename> is the name of the file encoded below.  You can use this
if it is compatable with file names on your system.


The data lines contain:

<length> is one character generated by adding the number of bytes
encoded on this line to 32 (ASCII space).

<data> is the <length>-32 bytes of binary data encoded into text
to produce 4 bytes of text for every 3 bytes of binary
data as follows:

Input:    Byte 1      Byte 2      Byte 3

    7  6  5  4  3  2  1  0    7  6  5  4  3  2  1  0    7  6  5  4  3  2  1  0
    \              /  \                /  \                /  \              /
     \            /    \              /    \              /    \            /
      ----- + ----      ----- + ------      ------ + -----      ----- + ----
    |                 |                    |                  |

  + 32               + 32                 + 32               + 32

    |                 |                    |                  |
    V                 V                    V                  V

Output:  Byte 1    Byte 2               Byte 3             Byte 4


In other words, encoding involves taking 3 bytes, breaking it
into 4 six bit chunks, adding 32 to each six bit value to make
it an ascii character, and output them.

To decode, you reverse this.  Strip the parity bit, subtract
32 from each byte and repack into three words by shifting and
or'ing the pieces.  I don't think I'll spell this out, since
it is an obvious reversal of the above steps.


The last line in the section simply says 'end'.

The file may contain junk before the begin statement and after the end
statement.  So the decoder usually skips until it sees begin, extracts
the file name and decodes until it sees the end line.  Be sure when you
implement it that you use the length byte to determine the length of the
decoded text, since stuff going though news sometimes gets padding added
to the text.  Also, you need to do this is you want to get the file
length correct.

**** NOTE (jhs):  VAX implementations seem to always include a last line of
data containing zero bytes just before the "end" line.  This comes out as a
line containing a single space before the <RETURN>, when uuencoded.
****

I've included a posted uudecode source for the Atari 520 ST below.  I've
never used it, but it does give you something to look at.  I don't know
whether you read C, but it might still be of help.  There is nothing which
says it's copyrighted, so I assume it's public domain.  If not, the
copyright was removed before I saw it.  Some of the cruft in it indicates
it was originally written for Unix.  I seem to have lost the credits on
this one, I don't see who posted it.

===========================================================================


/*
 * uudecode input
 * Modified for the ST - cannot use putc because of CR/LF problems
 *
 * create the specified file, decoding as you go.
 * used with uuencode.
 */
#include <stdio.h>
#include <osbind.h>

int_isconio;
#define NULL 0

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

intoutfile;/* File descriptor of output file */

charoutbuf[BUFSIZ];/* Output buffer for my character out code */
char*nextc= outbuf;/* Pointer to the next character */
#define lputc(outchar){*nextc++ = outchar;if (nextc >= &outbuf[BUFSIZ])do_write();}

main(argc, argv)
char **argv;
{
FILE *in;
FILE *fopen();
int mode;
char dest[128];
char buf[80];
_isconio = 1;
/* mandatory input arg */
if (argc != 2) {
printf("Usage: uudec filename\n");
exit(1);
}
if ((in = fopen(argv[1], "r")) == NULL) {
printf("Cannot open: %s\n", argv[1]);
exit(1);
}
_isconio = 0;
/* search for header line */
for (;;) {
if (fgets(buf, sizeof buf, in) == NULL) {
printf("No begin line\n");
exit(3);
}
if (strncmp(buf, "begin ", 6) == 0)
break;
}
sscanf(buf, "begin %o %s", &mode, dest);

/* handle ~user/file format */
if (dest[0] == '~') {
printf("Cannot handle user formats\n");
exit(1);
}
/* create output file */
if ((outfile = Fcreate(dest, 0)) < 0)
{printf("Cannot create: %s\n", argv[2]);
exit(1);
}

decode(in);

if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) {
printf("No end line\n");
exit(5);
}
exit(0);
}

/*
 * copy from in to outfile, decoding as you go along.
 */
decode(in)
FILE *in;
{
char buf[80];
char *bp;
int n;

for (;;) {
/* for each input line */
if (fgets(buf, sizeof buf, in) == NULL) {
printf("Short file\n");
exit(10);
}
n = DEC(buf[0]);
if (n <= 0)
break;

bp = &buf[1];
while (n > 0) {
outdec(bp, n);
bp += 4;
n -= 3;
}
}
do_write();
}

/*
 * output a group of 3 bytes (4 input characters).
 * the input chars are pointed to by p, they are to
 * be output to file f.  n is used to tell us not to
 * output all of them at the end of the file.
 */
outdec(p, n)
char *p;
{
int c1, c2, c3;

c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
c3 = DEC(p[2]) << 6 | DEC(p[3]);
if (n >= 1)
lputc(c1);
if (n >= 2)
lputc(c2);
if (n >= 3)
lputc(c3);
}

do_write()
{longbytect;
if (nextc != &outbuf[0])
{bytect = nextc - &outbuf[0];
if (Fwrite(outfile, bytect, outbuf) < 0)
{printf("Write error on output file\n");
exit(1);
}
nextc = outbuf;
}
}