"zambak" <za****@comcast.net> 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 <= 8)
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 >= 8) 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, 8);
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.