"zambak" <> wrote:
> Thank you.....That seems to work just fine....
I'm glad you managed to get it working... it took me some
debugging to get all the shifts and masks correct.
This basically works; it doesn't know exactly when the input
has ended so you get a variable number (0 to 7) of extra
'a' characters (code value zero) at the end of the decoded
file.
It loses capitalisation as there's not room in 5 bits to
store both uppercase and lowercase letters.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
const char *set = "abcdefghijklmnopqrstuvwxyz .,?!\n"; /* 32 chars */
unsigned char encodechar(unsigned char c)
{
char *p = strchr(set, tolower(c));
if(p == NULL) /* Not in code set */
{
if(isprint(c))
fprintf(stderr, "Error: Cannot encode character '%c'\n", (int)c);
else
fprintf(stderr, "Error: Cannot encode character %u\n", (unsigned int)c);
return 0;
}
return p - set;
}
unsigned char decodechar(unsigned char c)
{
if(c > 31)
{
fprintf(stderr, "Error: Got code %d\n", c);
return 0;
}
return set[c];
}
/*
Encode n characters (n <=

from inbuf (up to 8 characters)
to outbuf (5 8-bit bytes)
Bit packing:
where '(' is most significant bit and
')' is least significant bit.
from (---)(---)(---)(---)(---)(---)(---)(---)
to (------)(------)(------)(------)(------)
*/
void encodebuf(unsigned char *outbuf, unsigned char *inbuf, size_t n)
{
memset(outbuf, 0, 5);
for(size_t i = 0; i < n; i++) inbuf[i] = encodechar(inbuf[i]);
if(n >= 1) outbuf[0] |= inbuf[0] << 3;
if(n >= 2) outbuf[0] |= inbuf[1] >> 2, outbuf[1] |= (inbuf[1] & 3) << 6;
if(n >= 3) outbuf[1] |= inbuf[2] << 1;
if(n >= 4) outbuf[1] |= inbuf[3] >> 4, outbuf[2] |= (inbuf[3] & 15) << 4;
if(n >= 5) outbuf[2] |= inbuf[4] >> 1, outbuf[3] |= (inbuf[4] & 1) << 7;
if(n >= 6) outbuf[3] |= inbuf[5] << 2;
if(n >= 7) outbuf[3] |= inbuf[6] >> 3, outbuf[4] |= (inbuf[6] & 7) << 5;
if(n >=

outbuf[4] |= inbuf[7];
}
/* Decode 8 characters from inbuf (5 8-bit bytes) to 8-byte outbuf
from (------)(------)(------)(------)(------)
to (---)(---)(---)(---)(---)(---)(---)(---)
*/
void decodebuf(unsigned char *outbuf, unsigned char *inbuf)
{
memset(outbuf, 0,

;
outbuf[0] = decodechar( inbuf[0] >> 3);
outbuf[1] = decodechar((inbuf[0] & 7) << 2 | inbuf[1] >> 6);
outbuf[2] = decodechar((inbuf[1] >> 1) & 31);
outbuf[3] = decodechar((inbuf[1] & 1) << 4 | inbuf[2] >> 4);
outbuf[4] = decodechar((inbuf[2] & 15) << 1 | inbuf[3] >> 7);
outbuf[5] = decodechar((inbuf[3] >> 2) & 31);
outbuf[6] = decodechar((inbuf[3] & 3) << 3 | inbuf[4] >> 5);
outbuf[7] = decodechar( inbuf[4] & 31);
}
void encode(FILE *fpin, FILE *fpout)
{
unsigned char inbuf[8] = {0};
unsigned char outbuf[5] = {0};
size_t n;
while((n = fread(inbuf, 1, 8, fpin)) != 0)
{
encodebuf(outbuf, inbuf, n);
fwrite(outbuf, 1, 5, fpout);
}
}
void decode(FILE *fpin, FILE *fpout)
{
unsigned char inbuf[5] = {0};
unsigned char outbuf[8] = {0};
size_t n;
while((n = fread(inbuf, 1, 5, fpin)) != 0)
{
decodebuf(outbuf, inbuf);
fwrite(outbuf, 1, 8, fpout);
}
}
int main(int argc, char **argv)
{
if(argc != 4)
{
fprintf(stderr, "Usage: requires three arguments:\n");
fprintf(stderr, " encode or decode\n");
fprintf(stderr, " input filename\n");
fprintf(stderr, " output filename\n");
}
else
{
if(strcmp(argv[1], "encode") == 0)
{
FILE *fpin = fopen(argv[2], "r");
if(fpin == NULL)
{
fprintf(stderr, "Error opening file %s for text reading\n", argv[2]);
exit(EXIT_FAILURE);
}
FILE *fpout = fopen(argv[3], "wb");
if(fpout == NULL)
{
fprintf(stderr, "Error opening file %s for binary writing\n", argv[3]);
exit(EXIT_FAILURE);
}
encode(fpin, fpout);
fclose(fpin);
fclose(fpout);
}
else if(strcmp(argv[1], "decode") == 0)
{
FILE *fpin = fopen(argv[2], "rb");
if(fpin == NULL)
{
fprintf(stderr, "Error opening file %s for binary reading\n", argv[2]);
exit(EXIT_FAILURE);
}
FILE *fpout = fopen(argv[3], "w");
if(fpout == NULL)
{
fprintf(stderr, "Error opening file %s for text writing\n", argv[3]);
exit(EXIT_FAILURE);
}
decode(fpin, fpout);
fclose(fpin);
fclose(fpout);
}
else
{
fprintf(stderr, "Incorrect argument.\n");
}
}
return 0;
}
--
Simon.