Metropoli BBS
VIEWER: jac.c MODE: TEXT (ASCII)
/*******************************************************************************
*                                                                              *
* 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;
}

[ RETURN TO DIRECTORY ]