/*******************************************************************************
* *
* JAC.C May 1992 *
* *
* Written in Borland C++ 2.0 under MS-DOS 5.0 *
* Memory model = medium *
* *
*******************************************************************************/
#include <stdio.h>
typedef struct chardata {
short charnum; // which character to be encoded
short frequency; // frequency of occurance,
};
#define input fgetc(infile)
#define output(i) fputc(i,outfile)
#define FALSE 0
#define TRUE !FALSE
struct chardata *table[256];
struct chardata *temp;
FILE *infile; // file ptr to original file (uncompressed)
FILE *outfile; // file ptr to output fiel (compressed)
char *infile_name; // ptr to name of input file
char *outfile_name; // ptr to name of output file
int n=0,S=0;
int sort(short);
int frequency_16_char(short);
int timeout(void);
int main(int argc, char **argv)
{
enum { QUAD, NO_QUAD } encode_state = NO_QUAD;
register short c,quad_high,X; // a character
if (argc < 3) { // check command line arguments
puts("'jac file1 file2 [S] ' encode_s file1 into file2.");
return 1;
}
puts("Jac by TT, 1992");
infile_name = argv[1];
outfile_name = argv[2];
if (argc == 3) S=atoi(argv[3]);
for (c=0; c < 256; c++) // initialize decode table
{
if ((table[c] = (struct chardata *)malloc(sizeof (struct chardata)))== NULL)
{
printf("Unable to allocate space for %dth table node.",c);
return 1;
}
table[c]->charnum = c; // need to know who we are after sort
table[c]->frequency = 1;
}
if ((infile=fopen(infile_name, "rb")) == NULL) // open the input file
{
printf("Unable to open %s.\n", infile_name);
return 1;
}
outfile=fopen(outfile_name,"wb");
while (!timeout()) // get character distribution data
{
c = input;
if (!timeout())
{
X=0;
while(table[X]->charnum != c || X==256) X++;
switch (encode_state)
{
case NO_QUAD: {
if (X < S) // check if quad is 4-bit character
{
quad_high=(X << 4); // save character
S=sort(X); // sort table
encode_state=QUAD;
break;
}
else
if (X > 255 - 16 * S)
{
output(0xf0+(X>>4));
S=sort(X);
quad_high=X<<4;
encode_state=QUAD;
break;
}
else
{
output(X+15*S);
encode_state=NO_QUAD;
S=sort(X);
break;
}
}
case QUAD: {
if (X<S)
{
output(quad_high+X);
S=sort(X);
encode_state=NO_QUAD;
break;
}
else
if (X > 255 - 16*S)
{
output(quad_high+0x0f);
output(X);
S=sort(X);
encode_state=NO_QUAD;
break;
}
else
{
output(quad_high+((X+15*S)>>4));
quad_high=(X+15*S)<<4;
S=sort(X);
encode_state=QUAD;
break;
}
}
default: break;
} // switch (deco....
}
if (timeout() && encode_state==QUAD) // fill end of file with quad + 1111
{
printf("filling");
output(quad_high+0x0f);
}
}
fclose(infile); // Close files
fclose(outfile); // close files
return 0;
}
// Function makes limited short
// if function has been called 128 times
// it calcultes new value for S
int sort(short x)
{
int c,b;
table[x]->frequency++; // update frequency
// printf("%c",table[x]->charnum);
if (x<16) c=0; else c=x-16;
while((table[c]->frequency >= table[x]->frequency) || c==x) c++;
// printf("c=%d\n",c);
// If new frequency greater than value(s) above change places
if (c<x)
{
temp=table[c]; // Store old value
table[c]=table[x]; // Move value to new place
for(b=c+1;b<x;b++)
{
if (temp->frequency >= table[b]->frequency)
{
table[x]=table[b]; // store original value to X place
table[b]=temp; // replace new value to b
temp=table[x]; // restore original value to temp
}
}
table[x]=temp;
}
// Check is it time to calculate S set
n++; // increment counter
if (n==128) // Time to check SET S
{
// calculate best S value
S=0;
for (c=0;c<16;c++)
if ((table[c]->frequency) > frequency_16_char(256-(c+1)*16)) S=c;
printf("S=%d \t",S);
// divide by two the original character count
for (c=0;c<256;c++) table[c]->frequency >>=1;
// set n to zero for next calculation
n=0;
}
return S;
}
// Calculates total frequency of 16 characters starting from charcter c
int frequency_16_char(short c)
{
int v,val=0;
for(v=c;v<c+16;v++) val+=table[v]->frequency;
return val;
}
// Returns TRUE if timeout occurs
// In this case timeout is only true if end of file infile
int timeout(void)
{
if(!feof(infile)) return FALSE; else return TRUE;
}