


       /******************************************************
       *
       *       file d:\lsu\cujhuff4.c
       *
       *****************************************************/


#include "d:\lsu\cujhuff.h"


/* 
    decode_compressed_file(...

    This is the main function of the decompression
    portion of the program.

*/

decode_compressed_file(input_file_name, output_file_name, 
                       item_array, file_header)
   char   input_file_name[], output_file_name[];
   struct item_struct item_array[];
   struct header_struct *file_header;
{
   char r[80];
   int  in_file_desc,
        out_file_desc;

   open_files_for_decode(input_file_name, output_file_name,
                         &in_file_desc, &out_file_desc);

   input_file_header(file_header, in_file_desc);
   convert_short_to_long(item_array, file_header);

   decode_file_and_write_output(item_array, 
                                in_file_desc, 
                                out_file_desc);

   close_decode_files(in_file_desc, out_file_desc);


}  /* ends decode_compressed_file */



/*    
         open_files_for_decode(...

         Open the input and output file.
*/


open_files_for_decode(in_file_name, out_file_name, 
                      in_file_desc, out_file_desc)
   char in_file_name[], out_file_name[];
   int        *in_file_desc, *out_file_desc;

{
   int a ,b;

   *out_file_desc = open(out_file_name, O_RDWR | O_CREAT | O_BINARY,
                         S_IWRITE);
   *in_file_desc  = open(in_file_name, O_RDWR | O_CREAT | O_BINARY,
                         S_IWRITE);

}  /*  ends open_files_for_decode        */







/*  
           input_file_header(file_header, in_file_desc)

           This function reads in the short header from the
           front of the input file.
*/


input_file_header(file_header, in_file_desc)
   int    in_file_desc;
   struct header_struct *file_header;
{
        int     bytes_read,
                i;

        char    in_buffer[(sizeof(struct header_struct))],
                *charptr,
                name[80];

        long    position;


        position   = lseek(in_file_desc, 0L, 0);
        bytes_read = my_read(in_file_desc, in_buffer, 
                             sizeof(struct header_struct));
/*printf("\n\n> Read %d bytes using file header", bytes_read);*/

        charptr = (char *)file_header;
        for(i=0; i<((sizeof(struct header_struct))); i++)
           *charptr++ = in_buffer[i];

}       /* ends input_item_array  */
   





/* 
        decode_file_and_write_output(...

        This function takes in the packed bits, decodes them,
        and puts the decoded characters out to the output
        file.

*/


decode_file_and_write_output(item_array, in_file_desc, out_file_desc)
   int    in_file_desc, out_file_desc;
   struct item_struct item_array[];
{
   char  output_buffer[IB_LENGTH],
         r[80],
         stream_buffer[CODE_LENGTH],
         stream_of_bits[OB_LENGTH];

   int   bytes_read,
         counter,
         i,
         in_disp,
         not_finished,
         output_pointer,
         stream_pointer;
   counter        = 0;
   output_pointer = 0;
   stream_pointer = 0;
   bytes_read     = 0;
   not_finished   = 1;

   for(i=0; i<IB_LENGTH; i++)
      output_buffer[i] = OTHER;

   while(not_finished){

      read_in_buffer(in_file_desc, in_disp, 
                     stream_of_bits, &bytes_read);

/*printf("\n> read %d bytes into stream of bits", bytes_read);*/
      stream_pointer = 0;

      if(bytes_read < OB_LENGTH)
         not_finished = 0;

         /* work through the stream_of_bits
            you're finished when the stream_pointer
            equals bytes_read * 8 bits per byte. */

      while(stream_pointer < bytes_read*8){
         convert_bits_to_char(stream_of_bits, stream_pointer, 
                                 stream_buffer);
   
         decode_bits(stream_buffer, item_array, 
                     output_buffer, &output_pointer,
                     &stream_pointer);

/*printf("\n> stream pointer = %d", stream_pointer);*/
            /* if output_buffer fills up write it to disk */
         if(output_pointer >= IB_LENGTH-10){
            counter++;
            printf("\n> Writing to output file-%d", counter);
            write_out_buffer(out_file_desc, 
                             output_buffer, 
                             output_pointer);
            output_pointer = 0;

         }  /* ends if output_pointer is too big */
      }     /* ends while stream_pointer < bytes_read*8 */

   }  /* ends while not_finished */

   if(output_pointer > 0){
         printf("\n> Writing to output file");
         write_out_buffer(out_file_desc, output_buffer, output_pointer);
   }

}  /* ends decode_file_and_write_output */
   




/* 
          read_in_buffer(...

          This function reads the input file and puts the packed
          bits into the stream_of_bits.
*/

read_in_buffer(in_file_desc, in_disp, stream_of_bits, 
               bytes_read)
   int   *bytes_read, in_file_desc, in_disp;
   char  stream_of_bits[];
{
   int b;

   for(b=0; b<OB_LENGTH; b++)
      stream_of_bits[b] = 0x00;

   *bytes_read = read(in_file_desc, stream_of_bits, OB_LENGTH);

}  /* ends read_in_buffer */







/* 
          convert_bits_to_char(...

          This function takes the next CODE_LENGTH # of bits
          from the stream_of_bits and converts them to bytes
          having the value ONE or ZERO.  These bytes are placed
          into the stream_buffer.  This makes it easier for
          the decode_bits function to compare coded with the
          packed bits.
*/


convert_bits_to_char(stream_of_bits, stream_pointer, stream_buffer)
   char  stream_of_bits[], stream_buffer[];
   int   stream_pointer;
{
   char temp;


   int bit_in_byte, 
       byte_in_buffer, 
       i,
       j;


   for(i=0; i<CODE_LENGTH; i++)
      stream_buffer[i] = OTHER;

   j = -1;

   for(i=stream_pointer; i<stream_pointer+CODE_LENGTH; i++){

      j++;
      bit_in_byte    = i % 8;
      byte_in_buffer = i/8;

         /* Test the bit by shifting it to the left
            by the number bit_in_byte and then ANDing
            it with 1000 0000 (128).
            For this routine bit zero is the left most
            or most significant bit of temp */

      temp = stream_of_bits[byte_in_buffer];
      temp = temp << bit_in_byte;
      if((temp & SET_BIT_ZERO) != 0)
         stream_buffer[j] = ONE;
      else
         stream_buffer[j] = ZERO;

   }  /* ends loop over i */

}  /* ends convert_bits_to_char */



/* 
          decode_bits(...

          Look at the converted bits from the packed file
          compare them to the item_array.coded (start looking
          at the top of the item_array since those occur most
          frequently) and put the original character in the 
          output buffer
*/

decode_bits(stream_buffer, item_array, 
            output_buffer, output_pointer,
            stream_pointer)
   char output_buffer[], stream_buffer[];
   int  *output_pointer, *stream_pointer;
   struct item_struct item_array[];
{
   int   found,
         i,
         j,
         length_of_code,
         not_finished;


   char  compare_string[CODE_LENGTH], r[80];

   found        = 0;
   not_finished = 1;
   j            = 0;

      /* search through the item_array looking for a coded array that
         matches the characters in the stream_buffer 
         If you find it, increase the stream_pointer by
         adding length_of_code to it. */

   while(not_finished){

      extract_code(item_array[j].coded, compare_string, &length_of_code);

      if(strncmp(compare_string, 
                 stream_buffer,       
                 length_of_code) == 0){
         found        = 1;
         not_finished = 0;
         *stream_pointer = *stream_pointer + length_of_code;
      }  /* ends if strncmp */

      else{   /* did not find the code so keep looking */
         j++;
         if(j > LENGTH){
            not_finished = 0;
            printf("\n\n\t> FAILURE - did not find code\n\n");
         }
      }  /* ends else */

   }  /* ends while not_finished */

      /* now put the decoded character in to the output_buffer */

   if(found == 1){
      output_buffer[*output_pointer] = item_array[j].character;
      *output_pointer = *output_pointer + 1;
   }  /* ends if found == 1 */

}  /* ends decode_bits */





/* 
            extract_code(...

            Pull the code out of item_array[x].coded,
            put it into compare_string, and put the
            length of the code into length.
*/

extract_code(coded, compare_string, length_of_code)
   char coded[], compare_string[];
   int  *length_of_code;
{
   int  i, j, k, m, not_finished;


      /* clear the compare_string */
   for(k=0; k<CODE_LENGTH; k++)
      compare_string[k] = OTHER;

   not_finished    = 1;
   *length_of_code = 0;
   i               = CODE_LENGTH-1;
   j               = 0;

      /* Start at the end of coded and search back until you
         run out of code i.e. you hit a OTHER. */

   while(not_finished){
      if(coded[i] != OTHER){
         i--;
         j++;
      }
      else
         not_finished = 0;
   }  /* ends while not_finished */

      /* adjust value of i */
   i++;

      /* Copy the coded to the compare_string */
   *length_of_code = j;
   m       = 0;
   for(k=i; k<CODE_LENGTH; k++){
      compare_string[m] = coded[k];
      m++;
   }

}  /* ends extract_code */




/* 
          write_out_buffer(...

          Write the output_buffer to file.
*/

write_out_buffer(out_file_desc, output_buffer, output_pointer)
   char output_buffer[];
   int  out_file_desc, output_pointer;
{
   int bytes_written;

   bytes_written = 
     my_write(out_file_desc, output_buffer, output_pointer);
}  /* ends write_out_buffer */



/* 
          close_decode_files(...

          Close the files.
*/


close_decode_files(in_file_desc, out_file_desc)
   int in_file_desc, out_file_desc;
{

   close(in_file_desc);
   close(out_file_desc);

} /* ends close_decode_files */
/* End of File */
