#include #ifdef SCCSID static char *SccsId = "@(#)encode.c 1.3 5/15/85"; #endif /* SCCSID */ /* * Produce a 7 bit printable encoding of stdin on stdout. * * Encoding uses acsii chars from ' ' .. 'z' * (040 .. 0172) (0x20 - 0x7a) inclusive * * Method is to expand 3 chars -> 4 6 bit ones. * Then collect 13 6 bit chars, and spread the 13th over * the preceding 12, so that each of the 12 chars is now * 6.5 bits. These 2 6.5 bit chars are a little hard * to represent on most common machines (one of these days * sane hosts will have 1/2 bits just for this program) * so we take a pair of them, and represent that in 13 bits. * 13 bits (max value 8191) can be represented as * A * 91 + B * where A < 91, B < 91 (91^2 == 8281, so it fits!) * * Each of A and B is encoded as a character by adding 32 * to make it printable (ie: 0x20). * * The termination conditions are foul beyond belief. Don't * monkey with them! * * If you think its a fluke that 040 .. 0171 just happen to * be the chars that Piet Beertema's uucp 'f' protocol transmits * as single bytes, you're insane. 0172 chars are produced * with lower frequency than any other (given random data) * so the doubling that occurs with that we will just suffer. * (A newer 'f' proto, sometime, will probably not use 0172) */ /* * the following pair of characters cannot legally occur * in normal output (since 90*91 + 90 == 8280, which > 2^13) * so we use them to indicate that the data that follows is the * terminator. The character immediately following this * pair is the length of the (expanded) terminator (which * otherwise might be indeterminable) */ #define ENDMARK1 ((90*91 + 90) / 91 + ' ') #define ENDMARK2 ((90*91 + 90) % 91 + ' ') main() { register char *p; register char *e; register c; char b3[3]; p = b3; e = b3 + 3; while ((c = getchar()) != EOF) { *p++ = c; if (p == e) { encode(b3, 3); p = b3; } } encode(b3, p - b3); flushout(); exit(0); } static char b13[13]; static int cnt = 0; encode(c, n) register char *c; int n; { register char *p; register i = cnt; register j; char b4[4]; p = b4; p[0] = (c[0] >> 2) & 0x3f; p[1] = ((c[0] & 0x3) << 4) | ((c[1] >> 4) & 0xf); p[2] = ((c[1] & 0xF) << 2) | ((c[2] >> 6) & 0x3); if (n == 3) p[3] = c[2] & 0x3f; else p[3] = n; c = &b13[i]; for (j = 4; --j >= 0; i++) { if (i == 13) { dumpcode(b13, 13); c = b13; i = 0; } *c++ = *p++; } cnt = i; } flushout() { putchar(ENDMARK1); putchar(ENDMARK2); putchar(cnt + ' '); dumpcode(b13, cnt); } dumpcode(p, n) register char *p; register int n; { register last; register c; if (n == 13) n--, last = p[12]; else if (n & 1) last = (1 << (6-1)); else last = 0; for ( ; n > 0; n -= 2) { c = *p++ << 6; c |= *p++; if (last & (1 << (6-1))) c |= (1 << 12); last <<= 1; /* * note: 91^2 > 2^13, 90^2 < 2^13, (91 + ' ') is printable */ /* oh for a compiler that would only do one division... */ putchar((c / 91) + ' '); putchar((c % 91) + ' '); } }