/* ********************************************* */
/* PROGRAM            RLE.C                      */
/* WRITTEN BY         CHAROENPORN ANCHLITAM      */
/* Proved by 	      Pichaya Tandayya		 */
/* ********************************************* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#define ErrREAD  1
#define ErrWRITE 2
#define BlockLength 2048

unsigned int compress(unsigned char *, int);
int process_comp(unsigned char *, int, int);
int process_uncomp(unsigned char *, int ,int);

#include <mem.h>

FILE *f1,*f2;
unsigned char screen[BlockLength];

void set_array(void)
{
   unsigned int i;
   for   (i=0; i<BlockLength; i++)    {
     screen[i] = NULL;
   }
} /* set_array */

void errexit(s1,s2)
char	*s1,*s2;
{
	printf(s1,s2);	exit(-1);
}                /* errexit */

RLEcomp(filein,fileout)
char *filein,*fileout;
{
  unsigned int i;
  unsigned int byte_count,comp_count;
  unsigned long int total_byte=0,total_comp=0;

  if ((f1=fopen(filein,"r"))==NULL)
	return(ErrREAD);
  if ((f2=fopen(fileout,"w"))==NULL)
	return(ErrWRITE);
  setvbuf(f1,NULL,_IOFBF,BlockLength);
  setvbuf(f2,NULL,_IOFBF,BlockLength);
  do {
	i = 0;
	while (!feof(f1) && (i < BlockLength)) {
		screen[i] = getc(f1); i++;
	} /* while */
    byte_count = i-1;   /* Error Correction: read data length  */
	total_byte = total_byte + byte_count;
	comp_count = compress(screen,byte_count);
	total_comp = total_comp + comp_count;
	i =0;
	while (i<comp_count) {
		putc(screen[i],f2); i++;
	}
  } while (!feof(f1));
  fclose(f1); fclose(f2);

  printf("Original string %d compressed to %d bytes\n",total_byte,total_comp);
  return(0);
}

RLEdecomp(filein,fileout)
char *filein,*fileout;
{
  unsigned long i=0,k=0;
  register int j;
  register int l;

  if ( (f1=fopen(filein,"r"))==NULL)
	return(ErrREAD);
  setvbuf(f1,NULL,_IOFBF,BlockLength);
  if ( (f2=fopen(fileout,"w"))==NULL)
	return(ErrWRITE);
  setvbuf(f2,NULL,_IOFBF,BlockLength);
/* ---------------- */
  while(!feof(f1)) {
     j = getc(f1); i++;
     if (j>128 && !feof(f1)) { /* uncompress the compressed char */
	l = getc(f1);  i++;
	for (j -= 128; j > 0 ; j--,k++)
		putc(l,f2);
     }
     else  /* if j : normal char */
	for (l=0;l<j && !feof(f1);l++,i++,k++)
	    putc(getc(f1),f2);
  } /* while */
  /* ---------------- */
  fclose(f1); fclose(f2);
  printf("And back to the original (%d) length from (%d).\n",k,i-1);
  return(0);
}

int main(argc,argv)         /* main program */
int argc; char **argv;
{
  int i,j;
  int retval;
#ifdef	O_BINARY
	_fmode=O_BINARY;
#endif

  if (argc<4) errexit("Usage : rle [-c] [-d] filein fileout\n",(char *)NULL);
  set_array();
  if (strncmp(argv[1],"-c",2)==NULL)
	retval=RLEcomp(argv[2],argv[3]);
  else	if (strncmp(argv[1],"-d",2)==NULL)
		retval=RLEdecomp(argv[2],argv[3]);
	else	errexit("rle: option must be '-c' or '-d'.\n",NULL);
  switch(retval)	{
	case	ErrREAD: printf("rle: error read %s.\n",argv[2]); break;
	case	ErrWRITE: printf("rle: error write %s.\n",argv[3]); break;
  } /* switch */
  return(retval);
} /* of main program */

unsigned int compress(in_array, in_size)
unsigned char *in_array;
int 		in_size;
{
   unsigned char *out_array;
   register int i = 0;
   register int j = 0; /* Number of New Compressed Block */
   register int k;
   register int l;

   out_array=(unsigned char *)malloc(BlockLength*sizeof(unsigned char));
   while (i<in_size) {
	 if (in_array[i] == in_array[i+1] && in_array[i+1] == in_array[i+2])
	 {  k = process_comp(in_array,i,in_size);
	    out_array[j++] = (unsigned char)k | 0x80; /* compress them */
	    out_array[j++] = in_array[i];
	    i +=k;
	    }                /* of if */
	  else { k = process_uncomp(in_array,i,in_size);
		 out_array[j++] = (unsigned char)k;  /* do not compress */
		 for (l = 0; l < k ; l++)
		     out_array[j++] = in_array[i++];
		     } /* of else */
	} /* of while */
    in_array = strncpy(in_array,out_array,j*sizeof(char));
    return(j);                  
}                      /* of compress */



process_comp(in_array,i,in_size)
unsigned char *in_array;
int i;
int in_size;
{
 register int len = 0;

 while (in_array[i] == in_array[i+1] && i < in_size) {
       len++;
       i++;   /* count for the same char */
       if (len >= 126)
	  break;
     } /* of while */

 return(len+1);
} /* of process_comp */

process_uncomp(in_array,i,in_size)
unsigned char *in_array;
int i;
int in_size;
{
 register int len = 0;

 while ((in_array[i] != in_array[i+1] || in_array[i] != in_array[i+2])
                    && i < in_size) {
                       len++;
                       i++;                    /* count char */
		       if (len >= 127)
			  break;
	  }  /* of while */

	return(len);
} /* of process_uncomp */


