/* File: dcodrle2.c
   Author: David Bourgin
   Creation date: 1/2/94
   Last update: 22/9/94
   Purpose: Example of RLE type 1 decoding with a file source to decompress.
*/

#include <stdio.h>
/* For routines printf,fgetc and fputc */
#include <stdlib.h>
/* For routine exit */

/* Error codes sent to the caller */
#define NO_ERROR      0
#define BAD_FILE_NAME 1
#define BAD_ARGUMENT  2

/* Useful constants */
#define FALSE 0
#define TRUE  1

/* Global variables */
FILE *source_file,*dest_file;

                             /* Being that fgetc=EOF only after an access
                                then 'byte_stored_status' is 'TRUE' if a byte has been stored by 'fgetc'
                                or 'FALSE' if there's no valid byte not already read and not handled in 'val_byte_stored' */
int byte_stored_status=FALSE;
int val_byte_stored;

/* Pseudo procedures */
#define end_of_data()  (byte_stored_status?FALSE:!(byte_stored_status=((val_byte_stored=fgetc(source_file))!=EOF)))
#define read_byte()  (byte_stored_status?byte_stored_status=FALSE,(unsigned char)val_byte_stored:(unsigned char)fgetc(source_file))
#define write_byte(byte)  ((void)fputc((byte),dest_file))

void rle2decoding()
/* Returned parameters: None
   Action: Decompresses with RLE type 2 method all bytes read by the function read_byte
   Errors: An input/output error could disturb the running of the program
*/
{ unsigned char header_byte,byte_read,byte_to_repeat;
  register unsigned int i;

  if (!end_of_data())
     { header_byte=read_byte();
       do {                  /* Being that header byte is present, then there are bytes to decompress */
            if ((byte_read=read_byte())==header_byte)
               { byte_read=read_byte();
                 if (byte_read<3)
                    for (i=0;i<=byte_read;i++)
                        write_byte(header_byte);
                 else { byte_to_repeat=read_byte();
                        for (i=0;i<=byte_read;i++)
                            write_byte(byte_to_repeat);
                      }
               }
            else write_byte(byte_read);
          }
       while (!end_of_data());
     }
}

void help()
/* Returned parameters: None
   Action: Displays the help of the program and then stops its running
   Errors: None
*/
{ printf("This utility enables you to decompress a file by using RLE type 2 method\n");
  printf("as given in 'La Video et Les Imprimantes sur PC'\n");
  printf("\nUse: dcodrle2 source target\n");
  printf("source: Name of the file to decompress\n");
  printf("target: Name of the restored file\n");
}

int main(argc,argv)
/* Returned parameters: Returns an error code (0=None)
   Action: Main procedure
   Errors: Detected, handled and an error code is returned, if any
*/
int argc;
char *argv[];
{ if (argc!=3)
     { help();
       exit(BAD_ARGUMENT);
     }
  else if ((source_file=fopen(argv[1],"rb"))==NULL)
          { help();
            exit(BAD_FILE_NAME);
          }
       else if ((dest_file=fopen(argv[2],"wb"))==NULL)
               { help();
                 exit(BAD_FILE_NAME);
               }
            else { rle2decoding();
                   fclose(source_file);
                   fclose(dest_file);
                 }
  printf("Execution of dcodrle2 completed.\n");
  return (NO_ERROR);
}
